SpringBoot-拦截器

  1. 介绍

    1. 见名知意,用于拦截controller请求,在进入controller之前进行一些处理,如果可以,进入controller处理方法,如果不可以,则不会进入controller处理方法。基本原理是采用AOP面相切面编程,基于动态代理,在所执行的controller方法前后添加代码,这就是拦截器

    2. 拦截器不依赖任何Servlet容器
    3. 拦截器只能对controller处理方法的url进行拦截,这里提到过滤器则可以对所有的请求进行过滤
    4. 在controller的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
  2. 实列(IDEA)

    1. 创建简单的SpringBoot项目,原始的即可,不需要改动,就用内置的Tomcat就行
    2. 编写POJO类
       1 @Data
       2 @AllArgsConstructor
       3 @RequiredArgsConstructor
       4 @NoArgsConstructor
       5 public class User implements Serializable {
       6                 private Integer id;
       7     @NonNull    private String name;
       8     @NonNull    private String sex;
       9                 private Integer age;
      10
      11 /* 12 * 类上面的注解是使用的lombok插件,不知道的朋友可自行查阅资料 13 * */ 14 }
    3. 创建UserController处理器类
       1 import org.springframework.web.bind.annotation.RequestMapping;
       2 import org.springframework.web.bind.annotation.RestController;
       3  
       4 import javax.servlet.http.HttpSession;
       5 import java.util.List;
       6 
       7 @RestController
       8 @RequestMapping("/user/")
       9 public class UserController {
      10     //模拟user的增删改查操作,假设增删改必须有用户且已登录才可执行
      11     @RequestMapping("delete")
      12     public String delete(){
      13         return "delete操作";
      14     }
      15     @RequestMapping("insert")
      16     public String insert(){
      17         return "insert操作";
      18     }
      19     @RequestMapping("update")
      20     public String update(){
      21         return "update操作";
      22     }
      23     @RequestMapping("login")
      24     public String login(HttpSession session){
      25         //模拟登录效果,不查询数据库
      26         User user = new User("admin","男");
      27         session.setAttribute("user",user);
      28         return "登录成功";
      29     }
      30     @RequestMapping("logout")
      31     public String logout(HttpSession session){
      32         //登出
      33         session.removeAttribute("user");
      34         return "登出成功";
      35     }
      36 }
    4. 编写LoginInterceptor拦截器类
      1. 可以使用实现HandlerInterceptor接口,也可直接继承HandlerInterceptorAdapter抽象类,因为这个类就是对HandlerInterceptor接口的一个空实现,看这边源码,注意方法上面的文档注释,如果选择HandlerInterceptorAdapter,再次重写这三个方法即可
        /*
         * Copyright 2002-2017 the original author or authors.
         *
         * Licensed under the Apache License, Version 2.0 (the "License");
         * you may not use this file except in compliance with the License.
         * You may obtain a copy of the License at
         *
         *      https://www.apache.org/licenses/LICENSE-2.0
         *
         * Unless required by applicable law or agreed to in writing, software
         * distributed under the License is distributed on an "AS IS" BASIS,
         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         * See the License for the specific language governing permissions and
         * limitations under the License.
         */
        
        package org.springframework.web.servlet.handler;
        
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        
        import org.springframework.lang.Nullable;
        import org.springframework.web.servlet.AsyncHandlerInterceptor;
        import org.springframework.web.servlet.ModelAndView;
        
        /**
         * Abstract adapter class for the {@link AsyncHandlerInterceptor} interface,
         * for simplified implementation of pre-only/post-only interceptors.
         *
         * @author Juergen Hoeller
         * @since 05.12.2003
         */
        public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
        
            /**
             * This implementation always returns {@code true}.
             */
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                    throws Exception {
        
                return true;
            }
        
            /**
             * This implementation is empty.
             */
            @Override
            public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                    @Nullable ModelAndView modelAndView) throws Exception {
            }
        
            /**
             * This implementation is empty.
             */
            @Override
            public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                    @Nullable Exception ex) throws Exception {
            }
        
            /**
             * This implementation is empty.
             */
            @Override
            public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response,
                    Object handler) throws Exception {
            }
        
        }
      2. 此处我选择实现接口
         1 import org.springframework.web.servlet.HandlerInterceptor;
         2 import org.springframework.web.servlet.ModelAndView;
         3 
         4 import javax.servlet.http.HttpServletRequest;
         5 import javax.servlet.http.HttpServletResponse;
         6 import java.io.IOException;
         7 
         8 /**
         9  * 登录验证
        10  */
        11 public class LoginInterceptor implements HandlerInterceptor {
        12     @Override
        13     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        14         //从session中取出user,如果取出的对象对空,向响应流中给出信息,并且返回false,不再进入controller方法
        15         //                   如果取出的对象不为空,表示用户已经登录,则返回true,继续进入controller方法
        16         System.out.println("LoginInterceptor--preHandle");
        17         boolean hasAlready=false;
        18         Object user = request.getSession().getAttribute("user");
        19         if(user!=null) {
        20             hasAlready = true;
        21         }else {
        22             response.getWriter().write("<h1 style='color:red;'>not login</h1>");
        23         }
        24 
        25         return hasAlready;
        26     }
        27 
        28     @Override
        29     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        30         System.out.println("LoginInterceptor--postHandle");
        31     }
        32 
        33     @Override
        34     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        35         System.out.println("LoginInterceptor--afterCompletion");
        36     }
        37 }
    5. 编写MvcConfigurer类,代码如下
       1 import cn.bdqn.ylm.sssmc.interceptor.LoginInterceptor;
       2 import org.springframework.context.annotation.Configuration;
       3 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
       4 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
       5 
       6 import java.util.ArrayList;
       7 import java.util.List;
       8 
       9 @Configuration
      10 public class MvcConfigurer implements WebMvcConfigurer {
      11     @Override
      12     public void addInterceptors(InterceptorRegistry registry) {
      13         LoginInterceptor li=new LoginInterceptor();
      14         List<String> pathPatterns=new ArrayList<>();
      15         List<String> excludePathPatterns=new ArrayList<>();
      16         pathPatterns.add("/**");
      17         excludePathPatterns.add("/user/log**");
      18 
      19         //pathPatterns表示所有的信息需要拦截的请求,这里写了/**,全部拦截
      20         //excludePathPatterns表示不拦截的请求,这里除了用户退出和登录操作以外,其他的都需要由用户登录才可以操作
      21         registry.addInterceptor(li).addPathPatterns(pathPatterns).excludePathPatterns(excludePathPatterns);
      22 
      23     }
      24 }
    6. OK,可以在浏览器访问观察结果了
      1. 首先访问/user/logout,浏览器显示登出成功即为成功,因为拦截器中设置了不拦截/user/log**请求
      2. 浏览器访问/user/增删改,浏览器显示not login即可成功,表示用户没有登录,被拦截器拦下并且向响应流中写出内容
      3. 浏览器访问/user/login,浏览器显示登录成功,此时session已经存在user对象,再次访问/user/增删改,如果增删改操作正常执行,并且页面显示对应的操作的成功提示即为正常,表示拦截器正常获取session中的对象判断对象状态放行拦截器
    7. 推荐进一步学习
      1. 拦截器的三个方法的执行时机、特征等
      2. 拦截器链(简单提一下:多拦截器会形成拦截器链,比如可以先用一个拦截器验证用户是否登录,如果登录,下一个拦截器再次验证权限问题)
      3. 过滤器、监听器
      4. 拦截器与ServletAPI的过滤器、监听器的不同
      5. 那么这些知识点我在这里并没有详细讲,大家自己下去学习
点赞