Java Web 系列文章:
前言
上篇进入了Java Web的世界,本篇将使用Servlet/JSP来实现简单的注册登录功能,当然我们需要与AI结对编程,AI输出框架代码,我们修缮细节即可。
通过本篇文章,你将了解到:
- Servlet 注解请求路径
- Servlet 过滤请求
- Servlet/JSP 转发和重定向
- Servlet Session保持登录态
- 小结
1. Servlet 注解请求路径
在上一篇里,请求路径与Servlet之间的映射是通过在web.xml编写映射关系体现的,此种方式比较麻烦,更简洁的方式是通过注解的方式建立映射。
比如,我们创建一个处理登录的Servlet,当浏览器访问登录页面时通过该Servlet处理。
如下:
java
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
}
使用@WebServlet注解访问路径,当在浏览器里访问:
请求将会分发给LoginServlet处理。
同样的,登录后跳转首页:
java
@WebServlet("/main")
public class MainServlet extends HttpServlet {
}
对应的访问路径:
当然访问的路径不是永久不变的,之前访问的是"main",后面访问变为"home",但处理逻辑又是一样的,想要同时兼容"main"和"home"路径的访问,此时注解也是支持多路径:
java
@WebServlet(urlPatterns = {"/main", "/home"})
public class LoginServlet extends HttpServlet {
}
2. Servlet 过滤请求
现在有个需求:
用户先登录后才能进入主页查看学校列表信息,点击列表的item,进入具体学校的详情页
我们不能预判和控制用户在浏览器输入的地址,但可以对用户的请求进行过滤。比如用户在未登录的场景下直接访问了主页和详情页,此时应该将用户的访问路径重定向到登录页,登录完成后再跳转到主页/详情页。
于是我们需要对访问主页和详情页的请求进行过滤。
java
@WebFilter(urlPatterns = {"/main", "/school_detail"}) // 过滤请求
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
}
}
如上,先定义一个认证Filter类AuthFilter,实现了Filter接口,主要实现doFilter方法。

在该方法里对请求路径进行处理和分发。
过滤类建立好之后,需要指定其需过滤的路径。
如上,我们需要过滤首页和详情页的地址,则添加@WebFilter注解,并表明对应的路径。
此时当访问如下地址时:
http://localhost:8080/java_web_war_exploded/main http://localhost:8080/java_web_war_exploded/school_detail
请求将被优先分发到AuthFilter过滤器。
当然现在只有两个页面需要先登录再访问,若后续有N个页面需要先登录呢?我们也不可能穷举所有的页面,当然有更好的处理方式:
java
@WebFilter("/*") // 过滤所有请求
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String path = httpRequest.getRequestURI();
// 1. 白名单路径放行(避免循环重定向)
if (path.endsWith("/login") || path.endsWith("/register") || path.endsWith(".css") || path.endsWith(".js")) {
chain.doFilter(request, response);
return;
}
}
}
使用"/*"过滤所有请求,当然有些页面确实不需要登录就可以访问,可以设置白名单进行放过。
3. Servlet/JSP 转发和重定向
当过滤器发现用户未登录但访问了其它页面时如何处理呢?
java
@WebFilter("/*") // 拦截所有请求
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String path = httpRequest.getRequestURI();
// 1. 白名单路径放行(避免循环重定向)
if (path.endsWith("/login") || path.endsWith("/register")|| path.endsWith(".css") || path.endsWith(".js")) {
chain.doFilter(request, response);
return;
}
// 2. 检查登录态
HttpSession session = httpRequest.getSession(false);
if (session == null || session.getAttribute("user") == null) {
//未登录,重定向到登录页
httpResponse.sendRedirect(httpRequest.getContextPath() + "/login");
} else {
//不处理,继续处理后续过滤器或目标资源
chain.doFilter(request, response);
}
}
}
处理步骤:
- 先从session里获取登录状态,判断当前用户是否登录
- 若未登录,则将请求转发到登录页面
- 若已登录,则不做额外处理
httpResponse.sendRedirect(xx),表示将请求重定向,httpResponse是发给浏览器的,因此当浏览器收到sendRedirect(xx)动作后,将取出参数xx,并重新向服务端发起请求。
此处重定向到servlet。
来看看实际表现,浏览器访问地址:http://localhost:8080/java_web_war_exploded/main 浏览器F12查看请求:

实际产生了两个请求:main和login。
我们请求了main,此时过滤器发现未登录,将请求重定向到login。

对于浏览器来说,它收到http的响应,状态码为302,于是取出响应头里的Location(/java_web_war_exploded/login)字段进行访问。
当浏览器访问:http://localhost:8080/java_web_war_exploded/login
交由LoginServlet处理:
java
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getRequestDispatcher("/school/login.jsp").forward(req, resp);
}
}
此处是将请求转发到了JSP页面,最终展示:

以上涉及到两个概念:请求重定向和请求转发。
重定向:HttpServletResponse.sendRedirect(xx),通知浏览器重新请求xx路径,此时地址栏上的地址将发生变化 请求转发:RequestDispatcher.forward(req, resp),在服务器内部将请求转发到另一个Servlet或JSP,与浏览器没有交互,地址栏上的地址未发生变化。
4. Servlet Session保持登录态
用户被重定向到登录页面,输入信息进行登录后,第二次请求还会被重定向吗?当然不需要,因此我们需要记录用户的登录态。
通过Session记录用户的状态。
当用户通过form表单提交登录信息时:

向login发起了post请求,对应的是LoginServlet:
java
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String phone = request.getParameter("phone");
String captcha = request.getParameter("captcha");
// 记录用户的登录态
HttpSession session = request.getSession();
session.setAttribute("user", phone);
response.sendRedirect("main");
}
}
LoginServlet 处理Post请求:
- 取出session
- 往session里存储登录信息
如此,服务端就记录了用户的登录信息。
当用户再次访问main页面时,在过滤器里判断session里是否有对应的登录信息从而判定用户是否处于登录态。
session存放在cookie里。

演示gif如下:

完整的工程请查看登录/注册模块
如果觉得有些许帮助,不要忘了一键三连哦~
下篇我们将对接数据库,进行传说中的CRUD。