一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的
而在Spring中,基于Filter这种方式可以实现Bean预处理、后处理。 比如注入FilterRegistrationBean,然后在这个Bean上传递自己继承Filter实现的自定义Filter进入即可。
而Spring MVC也有拦截器,不仅可实现Filter的所有功能,还可以更精确的控制拦截精度。
Spring MVC提供的org.springframework.web.servlet.handler.HandlerInterceptorAdapter这个适配器,继承此类,可以非常方便的实现自己的拦截器。
它有三个方法:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception {
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
}
preHandle在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制等处理;
postHandle在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView;
afterCompletion在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面),可以根据ex是否为null判断是否发生了异常,进行日志记录;
如果基于XML配置使用Spring MVC,可以利用SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping进行Url映射(相当于struts的path映射)和拦截请求(注入interceptors)。
如果基于注解使用Spring MVC,可以使用DefaultAnnotationHandlerMapping注入interceptors。
注意无论基于XML还是基于注解,HandlerMapping Bean都是需要在XML中配置的。
示例一:
在这个例子中,我们假设UserController中的注册操作只在9:00-12:00开放,那么就可以使用拦截器实现这个功能。
@Component
public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
private int openingTime;
private int closingTime;
private String mappingURL;//利用正则映射到需要拦截的路径
public void setOpeningTime(int openingTime) {
this.openingTime = openingTime;
}
public void setClosingTime(int closingTime) {
this.closingTime = closingTime;
}
public void setMappingURL(String mappingURL) {
this.mappingURL = mappingURL;
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
String url=request.getRequestURL().toString();
if(mappingURL==null || url.matches(mappingURL)){
Calendar c=Calendar.getInstance();
c.setTime(new Date());
int now=c.get(Calendar.HOUR_OF_DAY);
if(now<openingTime || now>closingTime){
request.setAttribute("msg", "注册开放时间:9:00-12:00");
request.getRequestDispatcher("/msg.jsp").forward(request, response);
return false;
}
return true;
}
return true;
}
}
将该类在启动的时候,通过注解(@Component)交给spring托管,
在WebMvcConfigurer类的子类中的注册你配置的拦截器上面
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private TimeBasedAccessInterceptor timeBasedAccessInterceptor ;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(timeBasedAccessInterceptor).addPathPatterns("/api/**");
}
}
主要做的事情就是:1,继承HandlerInterceptorAdapter,2,继承WebMvcConfigurer 并注册拦截器,这里注册的时候,HandlerInterceptorAdapter子类必须是交给spring托管后的子类。