SpringMVC拦截器
什么是拦截器?
拦截器是指通过统一拦截从浏览器发往服务器的请求来完成功能的增强。通常用来处理请求中的共性问题。比如
- 编码问题
- 权限验证问题
可以减少重复代码,便于维护。
编写拦截器
自定义类实现HandlerInterceptor,并重写方法即可。
package com.shy.springmvcbingding.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Haiyu
* @date 2018/10/9 13:25
*/
public class MyInterceptor implements HandlerInterceptor {
/**
*
* @param request request
* @param response response
* @param handler 被拦截的目标对象
* @return true表示被拦截后请求不会被终止;false表示被拦截后请求被终止
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Pre");
System.out.println(handler.toString());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("post");
modelAndView.addObject("username", "被拦截并修改的用户名");
// 拦截原视图,直接替换成新视图
// modelAndView.setViewName("hello2");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 一般用来处理资源关闭等操作
System.out.println("after");
}
}
- preHandle:在请求被处理前进行调用
- postHandle:在请求被处理后进行调用
- afterCompletion:在请求结束之后才进行调用
preHandle方法的返回值如果是false,那么Controller中被拦截的方法以及postHandle、afterCompletion方法都不会执行。方法参数中,有两个参数需要提一下:
- Object handler:指的是被拦截的目标对象,在这里就是被拦截的请求路径对应的方法;
- ModelAndView modelAndView:通过该参数,可以改变被拦截请求的视图属性甚至替换视图。
然后在xml中配置拦截器,将我们定义的拦截器注入到Spring环境中。
标签中
表示这个Interceptor只拦截该路径。如果不配置这个标签,将默认拦截所有路径。使用该标签可以使得针对不同的路径使用不同的拦截器。下面是路径请求路径为/hello
的方法,根据上面的配置,MyInterceptor会拦截该请求。
@RequestMapping("/hello")
public String hell0(Model model,
@RequestParam("username") String username,
@RequestParam("password") String password) {
System.out.println(username);
model.addAttribute("username", username);
model.addAttribute("password", password);
return "hello";
}
再看hello视图,以jsp为例
<%@ page contentType="text/html;charset=UTF-8" %>
Title
${username} and ${password}
控制台打印
Pre
public java.lang.String com.shy.springmvcbingding.controller.JspController.hello(org.springframework.ui.Model,java.lang.String,java.lang.String)
admin
post
after
jsp页面显示
被拦截并修改的用户名 and 1234
可以看到hello方法中打印的username还是admin,经postHandle拦截后,视图的username属性已经被修改了。
Spring Boot中配置拦截器
在Spring Boot中可以基于Java Config来注册拦截器,这样就可以抛弃xml配置了。我们只需自定义类实现WebMvcConfigurer,并重写addInterceptors方法即可,当然也可以重写addFormatters注册一个全局的Formatter用于转换日期。注意,该类要加上@Configuration注解,以便被Spring Boot扫描到并加载配置到上下文中。
package com.shy.springmvcbingding.config;
import com.shy.springmvcbingding.interceptor.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author Haiyu
* @date 2018/10/9 14:35
*/
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/hello");
}
/**
* 注册一个日期转换器
* @param registry
*/
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new DateFormatter());
}
}
多个拦截器的执行顺序
看下图,如果配置的拦截器1在拦截器2之前,拦截顺序如下
Request -> 拦截器1 -> 拦截器2 -> SpringMVC控制器
从图中可以看出:
- preHandel:请求先被拦截器1拦截,然后被拦截器2拦截;
- postHandle:请求先被拦截器2拦截,然后被拦截器1拦截;
- afterCompletion:请求先被拦截器2拦截,然后被拦截器1拦截。
by @sunhaiyu
2018.10.9