一、拦截器简介
1.1 概念
在学习SpringMVC之前,我们学习过一个和拦截器很像的技术——过滤器Filter,过滤器属于Servlet技术,Filter对所有内容进行过滤。而拦截器Interceptor属于SpringMVC技术,仅针对SpringMVC的访问进行拦截。
1.2 作用
(1)在指定的方法调用前执行预先设定的代码(类似于AOP的事前通知@Before)
(2)阻止原控制方法的执行
二、拦截器入门案例
2.1 入门案例制作
(1)在controller下新建拦截器包和拦截器类,实现HandlerInterceptor接口并覆盖3个方法。
public class ProjectInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle ..."); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle ..."); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion ..."); } }
暂时先分别打印一句话,主要目的是查看拦截器的执行流程。
(2)使用@Component注解将这个类交给SpringMVC管理
(3)编写SpringMvcSupport类,并重写拦截器方法
/** * 资源拦截器 */ @Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Autowired private ProjectInterceptor interceptor; @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(interceptor).addPathPatterns("/books"); // 3.注入拦截器对象并设置当URL含有/books时执行拦截 } }
(4)在SpringMVC配置类中扫描controller包
@Configuration @ComponentScan({"controller", "config"}) @EnableWebMvc public class SpringMvcConfig { }
(5)重启服务器,使用Postman测试并查看BookController执行结果。
@RestController @RequestMapping("/books") public class BookController { /** * 通过书名模糊查询书籍 * * @param bookName * @return */ @GetMapping("/{bookName}") public List<Book> selectByBookName(@PathVariable String bookName) { System.out.println("bookName is " + bookName); List<Book> books = new ArrayList<>(); return books; } /** * 查询所有书籍 * @return */ @GetMapping public List<Book> selectAll() { System.out.println("book select all..."); Book book = new Book(1,"计算机","SpringMVC入门教程","小试牛刀"); Book book1 = new Book(2,"计算机","SpringMVC实战教程","一代宗师"); List<Book> books = new ArrayList<>(); books.add(book); books.add(book1); return books; } /** * 添加书籍 * * @param book * @return */ @PostMapping() public int addBook(@RequestBody Book book) { System.out.println("book add ... " + book); return 1; } /** * 修改书籍信息 * * @param book * @return */ @PutMapping() public int updateBook(@RequestBody Book book) { System.out.println("book update ..." + book); return 1; } /** * 通过id删除书籍 * @param id * @return */ @DeleteMapping("/{id}") public int deleteBookById(@PathVariable Integer id) { System.out.println("book delete by id..." + id); return 1; } }
(6)由此得出结论,Post请求和Put请求执行了拦截器,而Get请求和Delete请求没有。
原因:
一开始拦截的是以/books结尾的请求,现在要加上拦截。
最后再看一下拦截器类
/** * 1.在controller下新建拦截器包和拦截器类,实现HandlerInterceptor接口并覆盖3个方法 */ @Component /** * 2.使用@Component注解将这个类交给SpringMVC管理 */ public class ProjectInterceptor implements HandlerInterceptor { /** * controller方法前执行的方法 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle ..."); return true; // 如果改为false,原始控制器方法将不执行 } /** *控制方法后执行的方法 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle ..."); } /** *PostHandle()方法后执行的方法 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion ..."); } }
2.2 实现WebMvcConfigurer接口简化开发
在SpringMVC配置类中实现WebMvcConfigurer接口,重写解决Post请求乱码的方法和添加拦截器对象和拦截控制器的方法,从而SpringMVC配置类不用再扫描config包,但是这种方法侵入性较强。
@Configuration @ComponentScan({"controller"}) @EnableWebMvc public class SpringMvcConfig implements WebMvcConfigurer { @Autowired private ProjectInterceptor interceptor; @Override public void addInterceptors(InterceptorRegistry registry) { // 3.注入拦截器对象并设置当URL以/books结尾时执行拦截,再设置以/books/结尾的也拦截 registry.addInterceptor(interceptor).addPathPatterns("/books","/books/*"); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/pages/**").addResourceLocations("/pages/"); registry.addResourceHandler("/static/**").addResourceLocations("/static/"); // 放行static和pages目录下的资源 } }
2.3 拦截器执行流程图
三、参数和拦截器链
3.1 拦截器参数
3.2 拦截器链
(1)配置多个拦截器interceptor
使用Postman测试查看结果:
(2)拦截器执行顺序
拦截器链中,当拦截器中断,后面的拦截器和原始方法、postHandle方法全部不执行, 下一个执行点是是上一个拦截器的afterHandle方法,因为它不执行自己的postHandle方法和afterHandle方法