SpringBoot-拦截器
-
介绍
-
见名知意,用于拦截controller请求,在进入controller之前进行一些处理,如果可以,进入controller处理方法,如果不可以,则不会进入controller处理方法。基本原理是采用AOP面相切面编程,基于动态代理,在所执行的controller方法前后添加代码,这就是拦截器
- 拦截器不依赖任何Servlet容器
- 拦截器只能对controller处理方法的url进行拦截,这里提到过滤器则可以对所有的请求进行过滤
- 在controller的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
-
-
实列(IDEA)
- 创建简单的SpringBoot项目,原始的即可,不需要改动,就用内置的Tomcat就行
- 编写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 } - 创建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 }
- 编写LoginInterceptor拦截器类
- 可以使用实现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 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 }
- 可以使用实现HandlerInterceptor接口,也可直接继承HandlerInterceptorAdapter抽象类,因为这个类就是对HandlerInterceptor接口的一个空实现,看这边源码,注意方法上面的文档注释,如果选择HandlerInterceptorAdapter,再次重写这三个方法即可
- 编写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 }
- OK,可以在浏览器访问观察结果了
- 首先访问/user/logout,浏览器显示登出成功即为成功,因为拦截器中设置了不拦截/user/log**请求
- 浏览器访问/user/增删改,浏览器显示not login即可成功,表示用户没有登录,被拦截器拦下并且向响应流中写出内容
- 浏览器访问/user/login,浏览器显示登录成功,此时session已经存在user对象,再次访问/user/增删改,如果增删改操作正常执行,并且页面显示对应的操作的成功提示即为正常,表示拦截器正常获取session中的对象判断对象状态放行拦截器
- 推荐进一步学习
- 拦截器的三个方法的执行时机、特征等
- 拦截器链(简单提一下:多拦截器会形成拦截器链,比如可以先用一个拦截器验证用户是否登录,如果登录,下一个拦截器再次验证权限问题)
- 过滤器、监听器
- 拦截器与ServletAPI的过滤器、监听器的不同
- 那么这些知识点我在这里并没有详细讲,大家自己下去学习
风萧萧兮易水寒,壮士一去兮不复还