介绍

  1. 见名知意,用于拦截controller请求,在进入controller之前进行一些处理,如果可以,进入controller处理方法,如果不可以,则不会进入controller处理方法。基本原理是采用AOP面相切面编程,基于动态代理,在所执行的controller方法前后添加代码,这就是拦截器
  2. 拦截器不依赖任何Servlet容器
  3. 拦截器只能对controller处理方法的url进行拦截,这里提到过滤器则可以对所有的请求进行过滤
  4. 在controller的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

实列(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 }
  1. 创建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 }
  1. 编写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 {
    }

}
  1. 此处我选择实现接口
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 }
  1. 编写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 }
  1. OK,可以在浏览器访问观察结果了
  1. 首先访问/user/logout,浏览器显示登出成功即为成功,因为拦截器中设置了不拦截/user/log**请求
  2. 浏览器访问/user/增删改,浏览器显示not login即可成功,表示用户没有登录,被拦截器拦下并且向响应流中写出内容
  3. 浏览器访问/user/login,浏览器显示登录成功,此时session已经存在user对象,再次访问/user/增删改,如果增删改操作正常执行,并且页面显示对应的操作的成功提示即为正常,表示拦截器正常获取session中的对象判断对象状态放行拦截器
  1. 推荐进一步学习
  1. 拦截器的三个方法的执行时机、特征等
  2. 拦截器链(简单提一下:多拦截器会形成拦截器链,比如可以先用一个拦截器验证用户是否登录,如果登录,下一个拦截器再次验证权限问题)
  3. 过滤器、监听器
  4. 拦截器与ServletAPI的过滤器、监听器的不同
  5. 那么这些知识点我在这里并没有详细讲,大家自己下去学习

风萧萧兮易水寒,壮士一去兮不复还