王柳 发表于 2024-12-8 21:26:18

SpringMVC-08-拦截器

1、拦截器概述

SpringMVC的处置惩罚器拦截器 类似于Servlet开发中的过滤器 Filter ,用于对 Handler 举行预处置惩罚和后处置惩罚。开发者可以本身定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:

[*]过滤器

[*]servlet规范中的一部分,任何JavaWeb工程都可以使用
[*]在url-pattern中配置了/*之后,可以对所有要访问的资源举行过滤

[*]拦截器

[*]拦截器是SpringMVC框架本身的,只有使用了SpringMVC框架的工程才气使用
[*]拦截器只会拦截进入Spring体系中的请求,即 进入DispatcherServlet中的请求
[*]像.jsp这种的资源请求,拦截器不会执行,因为它并没用进入DispatcherServlet,而是进到Tomcat内置的 JspServlet中

拦截器是AOP思想的详细应用!

2、拦截器使用

自定义拦截器

那如何实现拦截器呢?
想要自定义拦截器,必须实现 HandlerInterceptor 接口
public interface HandlerInterceptor {

        default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                        throws Exception {
                return true;
        }

        default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                        @Nullable ModelAndView modelAndView) throws Exception {
        }

        default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception {
        }

}

[*]preHandle

[*]在 Handler执行 之前执行
[*]返回true: 放行,执行下一个拦截器
[*]返回false: 拦截,终止此次请求后面的处置惩罚链,接下来需要本身处置惩罚request和response来控制网页

[*]postHandle

[*]在 Handler执行 之后,ViewResolver解析逻辑视图之前 执行
[*]可以修改ModelAndView 来控制 模型数据 和 接下来将要跳转的视图(仅限于返回逻辑视图名的Handler)

[*]afterCompletion

[*]一次请求 在Spring体系处置惩罚工作完成 之后的回调(即,ViewResolver渲染出物理视图之后)
[*]不管Handler是否正常执行(大概抛异常),此方法都会执行
[*]类似于try-catch语法中的finally,常用来做资源清算和根据异常的处置惩罚

自定义拦截器 MyInterceptor
public class MyInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
      System.out.println("------------preHandle------------");

      return !"false".equals(httpServletRequest.getParameter("status"));
    }

    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
      System.out.println("------------postHandle------------");
    }

    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
      System.out.println("------------afterCompletion------------");
      System.out.println(e);
      if (e != null)
            httpServletRequest.getRequestDispatcher("/").forward(httpServletRequest, httpServletResponse);
    }
}配置拦截器

在Spring的配置文件中定义
<mvc:interceptors>
    <mvc:interceptor>
      
      
      
      <mvc:mapping path="/**"/>
      <mvc:exclude-mapping path="/login"/>
      
      <bean />
    </mvc:interceptor>
</mvc:interceptors>

[*]mvc:mapping

[*]拦截器映射拦截的路径

[*]mvc:exclude-mapping

[*]在映射拦截路径中排除的路径

[*]bean

[*]要配置的拦截器类

测试

添加Controller
@RestController
public class TestController {

    @RequestMapping("test1")
    public String test1() {
      System.out.println("Handler执行");
//      int i = 1 / 0;
      return "hello";
    }

}

[*]拦截器拦截:后面的处置惩罚链不会执行
https://img2023.cnblogs.com/blog/3455982/202412/3455982-20241208210901949-1977171666.png
https://img2023.cnblogs.com/blog/3455982/202412/3455982-20241208210951333-1929986978.png
[*]拦截器放行:请求正常处置惩罚
https://img2023.cnblogs.com/blog/3455982/202412/3455982-20241208170337282-2060940463.png
https://img2023.cnblogs.com/blog/3455982/202412/3455982-20241208170358477-1370425161.png
[*]Handler 出现异常:postHandle不会执行,异常被afterCompletion捕获,并由afterCompletion处置惩罚请求
https://img2023.cnblogs.com/blog/3455982/202412/3455982-20241208171106313-1253946664.png
https://img2023.cnblogs.com/blog/3455982/202412/3455982-20241208171127653-1520188632.png

3、拦截器执行次序

添加 MyInterceptor2
public class MyInterceptor2 implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
      System.out.println("------------preHandle-2------------");
      return true;
    }

    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
      System.out.println("------------postHandle-2------------");
    }

    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
      System.out.println("------------afterCompletion-2------------");
    }
}<mvc:interceptors>
    <mvc:interceptor>
      
      
      
      <mvc:mapping path="/**"/>
      <mvc:exclude-mapping path="/login"/>
      
      <bean />
    </mvc:interceptor>
</mvc:interceptors><mvc:interceptors>
    <mvc:interceptor>
      <mvc:mapping path="/**"/>
      <bean id="loginInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>执行测试,观察控制台输出
https://img2023.cnblogs.com/blog/3455982/202412/3455982-20241208181702026-1266655245.png
由图可知,

[*]在 preHandle阶段,拦截器按注册次序执行
[*]在 postHandle阶段 和 afterCompletion阶段,拦截器逆序执行
这好比进入一个有多重门的院子,进去 要先开外门,再开内门,出去 要先开内门,再开外门。

4、验证用户是否登录 (项目案例)

实现思路

[*]有一个登陆页面,需要写一个controller访问页面。
[*]登陆页面有一提交表单的动作。需要在controller中处置惩罚。
[*]判断用户名密码是否正确。如果正确,向session中写入用户信息。返回登陆成功。
[*]拦截用户请求,判断用户是否登陆。
[*]如果用户已经登陆。放行, 如果用户未登陆,跳转到登陆页面。
编写一个登陆页面 login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
   
<h1>登录页面</h1>
<hr>
   
<body>
<form action="${pageContext.request.contextPath}/user/login">
    用户名:<input type="text" name="username">

    密码: <input type="password" name="pwd">

    <input type="submit" value="提交">
</form>
</body>
</html>编写一个Controller处置惩罚请求
@Controller
@RequestMapping("/user")
public class UserController {
    //跳转到登陆页面
    @RequestMapping("/jumplogin")
    public String jumpLogin() throws Exception {
      return "login";
    }
    //跳转到成功页面
    @RequestMapping("/jumpSuccess")
    public String jumpSuccess() throws Exception {
      return "success";
    }
    //登陆提交
    @RequestMapping("/login")
    public String login(HttpSession session, String username, String pwd) throws Exception {
      // 向session记录用户身份信息
      System.out.println("接收前端==="+username);
      session.setAttribute("user", username);
      return "success";
    }
    //退出登陆
    @RequestMapping("logout")
    public String logout(HttpSession session) throws Exception {
      // session 过期
      session.invalidate();
      return "login";
    }
}编写一个登陆成功的页面 success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
   
<h1>登录成功页面</h1>
<hr>
   
${user}
<a target="_blank" href="https://www.cnblogs.com/${pageContext.request.contextPath}/user/logout">注销</a>
</body>
</html>在 index 页面上测试跳转!启动Tomcat 测试,未登录也可以进入主页!
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>$Title$</title>
</head>
<body>
<h1>首页</h1>
<hr>
<%--登录--%>
<a target="_blank" href="https://www.cnblogs.com/${pageContext.request.contextPath}/user/jumplogin">登录</a>
<a target="_blank" href="https://www.cnblogs.com/${pageContext.request.contextPath}/user/jumpSuccess">成功页面</a>
</body>
</html>编写用户登录拦截器
public class LoginInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
      // 如果是登陆页面则放行
      System.out.println("uri: " + request.getRequestURI());
      if (request.getRequestURI().contains("login")) {
            return true;
      }
      HttpSession session = request.getSession();
      // 如果用户已登陆也放行
      if(session.getAttribute("user") != null) {
            return true;
      }
      // 用户没有登陆跳转到登陆页面
      request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
      return false;
    }
   
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    }
   
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    }
   
}在Spring的配置文件中注册拦截器
<mvc:interceptors>
    <mvc:interceptor>
      <mvc:mapping path="/**"/>
      <bean id="loginInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>再次重启Tomcat测试!
OK,测试登录拦截功能无误.

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: SpringMVC-08-拦截器