一:拦截器
拦截全局请求HandlerInterceptor
public interface HandlerInterceptor {
/**
* 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller
* 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
*/
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
/**
* 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
*/
void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
/**
* 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中
*/
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
用途:
拦截非法请求,日志记录等。
用法:
1.直接实现HandlerInterceptor接口,实现三个方法
/**
* HandlerInterceptor 拦截请求,过滤掉非法请求
*/
public class CheckTokenGetHandler implements HandlerInterceptor {
@Autowired
private CheckTokenRequest checkTokenRequest;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
String token = httpServletRequest.getParameter("cookieid");
//根据token,校验token是否存在合法
if (checkTokenRequest.tokenIsExist(token)){
return true;
}else {
//返回false之前,设置response相应前台
checkTokenRequest.returnJson(httpServletResponse);
return false;
}
//return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
2.继承HandlerInterceptorAdapter适配器
有时候我们的业务需求只需要实现三个回调函数之间的一个,所以不需要实现所有的方法,Spring提供了一个HandlerInterceptor的适配器HandlerInterceptorAdapter,继承这个类,重写需要用到的回调方法即可。
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
public 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 {
}
//这个方法是AsyncHandlerInterceptor独有的方法
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
}
}
拦截器HandlerInterceptor的装载
写一个配置类,继承WebMvcConfigurerAdapter,重写addInterceptors添加拦截器(可同时加载多个拦截器)
/**
* web MVC配置类,加载拦截器
*/
@Configuration
public class DeveloperWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {
@Bean
public CheckTokenGetHandler getCheckTokenGetHandler(){
return new CheckTokenGetHandler();
}
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getCheckTokenGetHandler()).addPathPatterns("/**");
}
}
有一点需要注意!spring在启动时,@Configuration注解的类生产出让Spring IoC容器管理的Bean实例的工厂。@Bean注解的方法产生一个对象,注册到容器中,这里联合使用@Bean和@Configuration注解使得在实体类中使用的@Autowired注解能够顺利将实体类注入,如果不提前声明Bean,拦截器将在SpringContext(加载Bean)之前注册,从而导致拦截器中的@Autowired注解的变量将为null。顺便提一下@PostConstruct这个注解在@Autowired注解修饰的变量或者方法之后执行,可以用来做一些初始化方法的加载。
二:请求的过滤及处理
RequestBodyAdvice
仅支持post请求,数据以body的形式发送
实现RequestBodyAdvice类或者继承RequestBodyAdviceAdapter(RequestBodyAdvice适配器)
在实现类上加注解@ControllerAdvice
import java.io.IOException;
import java.lang.reflect.Type;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
public interface RequestBodyAdvice {
//这里是一个前置拦截匹配操作,其实就是告诉你满足为true的才会执行下面的beforeBodyRead方法,这里可以定义自己业务相关的拦截匹配
boolean supports(MethodParameter var1, Type var2, Class<? extends HttpMessageConverter<?>> var3);
//当请求体为空时调用(可拦截body为空的请求)
Object handleEmptyBody(Object var1, HttpInputMessage var2, MethodParameter var3, Type var4, Class<? extends HttpMessageConverter<?>> var5);
//在请求体未读取(转换)时调用(可对数据进行处理,解密数据,过滤非法数据,重新序列化等)
HttpInputMessage beforeBodyRead(HttpInputMessage var1, MethodParameter var2, Type var3, Class<? extends HttpMessageConverter<?>> var4) throws IOException;
//在请求体完成读取后调用(可针对读取后的对象做转换,此处不做处理)
Object afterBodyRead(Object var1, HttpInputMessage var2, MethodParameter var3, Type var4, Class<? extends HttpMessageConverter<?>> var5);
}
ResponseBodyAdvice
ResponseBodyAdvice 的用途在于对返回内容做拦截处理:
public interface ResponseBodyAdvice<T> {
// 返回true,启动拦截,false,不启动拦截
boolean supports(MethodParameter var1, Class<? extends HttpMessageConverter<?>> var2);
//在返回数据之前启动拦截,比如做数据的加密处理等
T beforeBodyWrite(T var1, MethodParameter var2, MediaType var3, Class<? extends HttpMessageConverter<?>> var4, ServerHttpRequest var5, ServerHttpResponse var6);
}