Servlet实现用户登录拦截功能

目录

1.创建一个Servlet项目

2.准备好Tomcat,用于启动Servlet项目 

3.检查Servlet项目的起始目录是否准备齐全

4.准备用户登录所需创建文件夹和文件

5.编写Jsp文件

login.jsp

error.jsp

Content.jsp

6.测试

7.题外:会话(session)功能


1.创建一个Servlet项目

在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>

2.准备好Tomcat,用于启动Servlet项目

创建本地(local)Tomacat,在菜单Server中选择对应的可使用的tomcat程序,此处用的版本为Tomcat.9.0.62,接着在Http port中设置服务器端口(默认为8080),配置完成后点击Apply

接着在菜单Deployment中添加要部署的项目,点击+号作添加,选择以war为后缀的项目文件,此处我的项目名称为ServletReview1,因此显示为ServletReview1:war;下面的Application context指的是基于8080端口下的映射路径,这里可以自定义作选择,我这里直接默认以/作为起始映射点

3.检查Servlet项目的起始目录是否准备齐全

一个基本的Servlet项目,包含蓝色的java文件(注:蓝色是表示该文件是源代码文件夹,用于存放所有与Java相关的代码文件,若不是蓝色,则需点击右键-Mark directory as-Source-root)、resource资源文件(可以用于存放静态资源,如图片、视频、图标等)、webapp目录(注:该文件是有蓝色小圆点的,表示Tomcat启动后会默认被扫描到的地方)

注:如果你想手动配置一个webapp(带蓝点)的文件,则需要点击File-Project Structure-Modules-点击+号,然后用一个已有的web.xml的路径,将两者关联

4.准备用户登录所需创建文件夹和文件

此处根据自己的创建习惯,在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应用程序的安全性

5.编写Jsp文件

此处是我的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页面

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>

error.jsp

<%@ 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>

Content.jsp

<%@ 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>

至此,一个基本的用户登录(带过滤)的代码工作基本完成

6.测试

登录:

倘若登录失败:

倘若想跳过登录,直接访问路径:

则会响应过滤器,发现session中没有username,就跳转到error.jsp页面

7.题外:会话(session)功能

其中无论是在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请求之间的状态。

其工作原理如下:

  1. 当用户首次访问Web应用程序时,服务器会为该用户创建一个唯一的会话标识,通常是一个会话ID。这个会话ID会被发送到用户的浏览器,并保存在cookie或URL参数中。

  2. 用户的每次请求都会携带会话ID,服务器通过会话ID来识别用户并检索与之关联的会话数据。

  3. 服务器可以在会话中存储用户的相关信息,例如登录状态、购物车内容等。这些信息可以在不同的页面和请求之间进行共享和传递,从而实现用户状态的保持。

  4. 会话的有效期可以根据需要进行设置,可以是固定的时间段,也可以是用户关闭浏览器时结束。

通过会话,Web应用程序可以实现以下功能:

  1. 用户认证和授权:会话可以跟踪用户的登录状态,确保只有经过身份验证的用户才能访问受限资源。
  2. 数据持久化:可以在会话中存储和获取用户的数据,以便在不同页面和请求之间进行传递和共享。
  3. 购物车管理:会话可以用于存储用户的购物车内容,并在用户提交订单时进行处理。
  4. 记录用户行为:可以通过会话来记录用户在网站上的操作和浏览历史,用于统计和个性化推荐等。

需要注意的是,由于会话是在服务器端进行管理的,因此需要在跨页面和跨请求之间正确传递会话ID。一般情况下,浏览器会自动处理这些细节,但在某些特殊情况下,可能需要手动管理会话ID的传递和处理。

我们也可以在web.xml中设置session的超时时间:

<session-config>
    <session-timeout>30</session-timeout> <!-- 以分钟为单位 -->
</session-config>