目录
在Idea中选择maven-archetype-webapp,点击创建(create)
注:此处Idea版本为2023,若是以往版本,页面会有不同,但找到maven项目一样可以找到
Servlet项目所需依赖
<!-- servlet所需依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
创建本地(local)Tomacat,在菜单Server中选择对应的可使用的tomcat程序,此处用的版本为Tomcat.9.0.62,接着在Http port中设置服务器端口(默认为8080),配置完成后点击Apply
接着在菜单Deployment中添加要部署的项目,点击+号作添加,选择以war为后缀的项目文件,此处我的项目名称为ServletReview1,因此显示为ServletReview1:war;下面的Application context指的是基于8080端口下的映射路径,这里可以自定义作选择,我这里直接默认以/作为起始映射点
一个基本的Servlet项目,包含蓝色的java文件(注:蓝色是表示该文件是源代码文件夹,用于存放所有与Java相关的代码文件,若不是蓝色,则需点击右键-Mark directory as-Source-root)、resource资源文件(可以用于存放静态资源,如图片、视频、图标等)、webapp目录(注:该文件是有蓝色小圆点的,表示Tomcat启动后会默认被扫描到的地方)
注:如果你想手动配置一个webapp(带蓝点)的文件,则需要点击File-Project Structure-Modules-点击+号,然后用一个已有的web.xml的路径,将两者关联
此处根据自己的创建习惯,在java文件夹下自定义文件夹,一般我的习惯是Controller文件夹+Filter文件夹,分别用来编写Servlet和过滤器代码
写登录的逻辑代码,存在controller中(此处不添加数据库,模拟一套用户名和密码)
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
// 获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
if ("admin".equals(username) && "123456".equals(password)) {
System.out.println("登陆成功");
// 倘若校验成功 则将其存在session中,便于到时在过滤器代码中取出作筛选
HttpSession httpSession = req.getSession();
httpSession.setAttribute("username",username);
resp.sendRedirect("/jsp/Content.jsp");
} else {
String message = "登录失败,请检查用户名和密码";
resp.getWriter().write("<script>alert('" + message + "');location.href='login.jsp';</script>");
}
}
}
写完一个Servlet后,马上在web.xml中作映射(避免遗忘的好习惯)
<!--xml是一个配置文件,属于一种标记语言,通过标签定义内容-->
<!--声明Servlet-->
<servlet>
<!--servlet命名-->
<servlet-name>LoginServlet</servlet-name>
<!--servlet类的全限定名(路径+文件名)-->
<servlet-class>zhan.controller.LoginServlet</servlet-class>
</servlet>
<!--定义Servlet的请求映射-->
<servlet-mapping>
<!--要映射的servlet名,与上方定义的servlet-name一致-->
<servlet-name>LoginServlet</servlet-name>
<!--请求映射url,必须以/开头-->
<!--之后通过项目上下文路径+该路径,就能访问FirstServlet类-->
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
写过滤器代码
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class AuthenticationFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 根据您的登录验证逻辑判断用户是否已登录
boolean isLoggedIn = checkLoginStatus(request);
if (isLoggedIn) {
// 用户已登录,继续执行下一个过滤器或请求(放行)
filterChain.doFilter(request, response);
} else {
response.sendRedirect("/jsp/error.jsp");
}
}
@Override
public void destroy() {
}
private boolean checkLoginStatus(HttpServletRequest request) {
// 在这里编写您的登录验证逻辑
// 返回 true 表示已登录,返回 false 表示未登录
// 这里只是一个示例,您需要根据您的实际情况进行修改
HttpSession session = request.getSession(false);
if (session != null) {
// 获取session中的用户名,并打印检查
System.out.println(session.getAttribute("username"));
System.out.println(session);
}
return session != null && session.getAttribute("username") != null;
}
}
然后跟Servlet一样的,Filter类也要在web.xml中作映射
<!-- 定义一个名为"AuthenticationFilter"的过滤器 -->
<filter>
<filter-name>AuthenticationFilter</filter-name>
<!-- 过滤器类 -->
<filter-class>zhan.Filter.AuthenticationFilter</filter-class>
</filter>
<!-- 配置"AuthenticationFilter"过滤器映射 -->
<filter-mapping>
<!-- 过滤器名称 -->
<filter-name>AuthenticationFilter</filter-name>
<!-- URL模式,表示所有以"/jsp/"开头的URL路径都会被该过滤器拦截 -->
<url-pattern>/jsp/*</url-pattern>
</filter-mapping>
这个过滤器的作用是对所有以"/jsp/"开头的URL进行身份认证,如果用户未登录或登录信息不正确,则重定向到登录页面。可以看出,这个过滤器是在保护Web应用程序的安全方面起作用的。
注:这是一段典型的web.xml配置文件中的过滤器(filter)代码段,其中定义了名字为“AuthenticationFilter”的过滤器,该过滤器由“zhan.Filter.AuthenticationFilter”类实现。通过filter-mapping元素将此过滤器映射到所有以“/jsp/”开头的请求路径上。当请求的URL路径被匹配时,容器就会先调用该过滤器来进行身份认证,保障Web应用程序的安全性。
此处是我的webapp目录,其中web.xml是必须要在WEB-INF下的
我个人习惯是创建jsp文件夹,用于存放不同模块下的不同jsp页面,然后在webapp目录下直接创建一个登陆页面和错误页面(login.jsp和error.jsp),当然用index作登陆首页也没问题
由于我此处选择了用login作为首页,因此跟以往Servlet启动时,自动跳转到index.jsp不同的是,我需要在web.xml中额外作首页配置:
<!--设置首页-->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
配置完后,每次运行Servlet项目时,会先跳转到login.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<title>登录</title>
<body>
<form action="LoginServlet" method="post" onsubmit="return checkStringFormat()">
用户名:<input type="text" name="username" id="username" >
<br>
密码:<input type="password" name="password" id="password">
<button type="submit">提交</button>
</form>
</body>
<script>
function checkStringFormat() {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
if (username.length===0||password.length===0) {
alert("用户名或密码不能为空");
return false;
}
return true;
}
</script>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>无权限</title>
</head>
<body>
<p>
请登录后再访问该页面!<a href="login.jsp" style="color: #0cde28" >返回</a>
</p>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--<%= session.getAttribute("username") %>--%>
<html>
<head>
<title>首页</title>
</head>
<body>
<h1><%= session.getAttribute("username")%></h1>
<h1>hello world!</h1>
</body>
</html>
至此,一个基本的用户登录(带过滤)的代码工作基本完成
登录:
倘若登录失败:
倘若想跳过登录,直接访问路径:
则会响应过滤器,发现session中没有username,就跳转到error.jsp页面
其中无论是在LoginServlet还是filter类中,都离不开会话session的功劳,在前者代码里,登录成功后将username存进了session里:
if ("admin".equals(username) && "123456".equals(password)) {
System.out.println("登陆成功");
// 倘若校验成功 则将其存在session中
HttpSession httpSession = req.getSession();
httpSession.setAttribute("username",username);
resp.sendRedirect("/jsp/Content.jsp");
}
然后又在Filter类中,检查session里是否有username进而作筛选:
private boolean checkLoginStatus(HttpServletRequest request) {
// 在这里编写您的登录验证逻辑
// 返回 true 表示已登录,返回 false 表示未登录
// 这里只是一个示例,您需要根据您的实际情况进行修改
HttpSession session = request.getSession(false);
if (session != null) {
// 获取session中的用户名,并打印检查
System.out.println(session.getAttribute("username"));
System.out.println(session);
}
return session != null && session.getAttribute("username") != null;
}
基本上,一个Servlet项目往往离不开session:
Session(会话)是一种在Web应用程序中用于跟踪用户状态和存储用户相关信息的机制。在HTTP协议的无状态特性下,为了实现用户的连续性和数据的持久化,可以使用会话来跟踪用户在多个HTTP请求之间的状态。
其工作原理如下:
当用户首次访问Web应用程序时,服务器会为该用户创建一个唯一的会话标识,通常是一个会话ID。这个会话ID会被发送到用户的浏览器,并保存在cookie或URL参数中。
用户的每次请求都会携带会话ID,服务器通过会话ID来识别用户并检索与之关联的会话数据。
服务器可以在会话中存储用户的相关信息,例如登录状态、购物车内容等。这些信息可以在不同的页面和请求之间进行共享和传递,从而实现用户状态的保持。
会话的有效期可以根据需要进行设置,可以是固定的时间段,也可以是用户关闭浏览器时结束。
通过会话,Web应用程序可以实现以下功能:
需要注意的是,由于会话是在服务器端进行管理的,因此需要在跨页面和跨请求之间正确传递会话ID。一般情况下,浏览器会自动处理这些细节,但在某些特殊情况下,可能需要手动管理会话ID的传递和处理。
我们也可以在web.xml中设置session的超时时间:
<session-config>
<session-timeout>30</session-timeout> <!-- 以分钟为单位 -->
</session-config>