Filter是Servlet的规范,它的定义如下:
public interface Filter {
public void init(FilterConfig filterConfig)throwsServletException;
public void doFilter(ServletRequest request,ServletResponse response, FilterChain chain)throwsIOException,ServletException;
public void destroy();
主要作用就是,对ServletRequest做预处理,执行过程中任何时候都可以打断,只要不执行chain.doFilter()就不会再执行后面的过滤器和请求的内容。而在实际使用时,就要特别注意过滤链的执行顺序问题
而Spring MVC是基于Servlet来响应用户请求对,所以,在Spring中可以可以用Filter来干预Http请求,解决诸如跨域、认证方面的要求。例子如下:
@Component
public classSimpleCORSFilterimplementsFilter {
public voiddoFilter(ServletRequest req,ServletResponse res,FilterChain chain)throwsIOException,
ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin","*");
response.setHeader("Access-Control-Allow-Methods","POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age","3600");
response.setHeader("Access-Control-Allow-Headers","Token,Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since");
chain.doFilter(req,res);
}
public voidinit(FilterConfig filterConfig) {}
public voiddestroy() {}
}
而拦截器,是基于Spring IOC的。可以在方法级别,对流程进行预处理、后处理、综合(前后同时)处理。我们需要做的就是:
1、创建自己的拦截器实现HandlerInterceptor接口
2. 加入到拦截器链条,继承WebMvcConfigurerAdapter类,重写addInterceptors方法
将拦截器加入到拦截链条(需要添加拦截规则),如下:
public class CustomInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object object, Exception exception)throwsException {
//在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
System.out.println("3. 整个请求结束之后被调用......CustomInterceptor1......");
}
@Override
publicvoidpostHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView view)
throwsException {
// 请求处理之后进行调用,但是在视图被渲染之前
System.out.println("2. 请求处理之后进行调用,但是在视图被渲染之前......CustomInterceptor1......");
}
@Override
publicbooleanpreHandle(HttpServletRequest request, HttpServletResponse response, Object object)throwsException {
// 在请求处理之前进行调用
System.out.println("1. 在请求处理之前进行调用......CustomInterceptor1......");
// 只有返回true才会继续向下执行,返回false取消当前请求
returntrue;
}
@Configuration
publicclassWebAdapterextendsWebMvcConfigurerAdapter{
@Override
publicvoidaddInterceptors(InterceptorRegistry registry) {
//众多的拦截器组成了一个拦截器链
/**
* 主要方法说明:
* addPathPatterns 用于添加拦截规则
* excludePathPatterns 用户排除拦截
*/
registry.addInterceptor(newCustomInterceptor()).addPathPatterns("/*");
registry.addInterceptor(newCustomInterceptor2()).addPathPatterns("/*");
super.addInterceptors(registry);
}
或者直接写一个完整的自定义拦截器
@Aspect
@Component
public classControllerInterceptor {
private static finalLoggerlogger= LoggerFactory.getLogger(ControllerInterceptor.class);
@Value("${spring.profiles}")
privateStringenv;
/**
* 定义拦截规则:拦截com.xjj.web.controller包下面的所有类中,有@RequestMapping注解的方法。
*/
@Pointcut("execution(* com.xjj.web.controller..*(..)) and @annotation(org.springframework.web.bind.annotation.RequestMapping)")
public voidcontrollerMethodPointcut(){}
/**
* 拦截器具体实现
*@parampjp
*@returnJsonResult(被拦截方法的执行结果,或需要登录的错误提示。)
*/
@Around("controllerMethodPointcut()")//指定拦截器规则;也可以直接把“execution(* com.xjj.........)”写进这里
public Object Interceptor(ProceedingJoinPoint pjp){
long beginTime = System.currentTimeMillis();
Method Signature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();//获取被拦截的方法
String methodName = method.getName();//获取被拦截的方法名
Set allParams =newLinkedHashSet<>();//保存所有请求参数,用于输出到日志中
logger.info("请求开始,方法:{}",methodName);
Object result =null;
Object[] args = pjp.getArgs();
for(Object arg : args){
//logger.debug("arg: {}", arg);
if(arginstanceofMap) {
//提取方法中的MAP参数,用于记录进日志中
@SuppressWarnings("unchecked")
Map map = (Map) arg;
allParams.add(map);
}else if(arginstanceofHttpServletRequest){
HttpServletRequest request = (HttpServletRequest) arg;
if(isLoginRequired(method)){
if(!isLogin(request)){
result =newJsonResult(ResultCode.NOT_LOGIN,"该操作需要登录!去登录吗?", null);
}
}
//获取query string 或 posted form data参数
Map paramMap = request.getParameterMap();
if(paramMap!=null&& paramMap.size()>0){
allParams.add(paramMap);
}
}else if(arginstanceofHttpServletResponse){
//do nothing...
}else{
//allParams.add(arg);
}
}
try{
if(result ==null){
// 一切正常的情况下,继续执行被拦截的方法
result = pjp.proceed();
}
}catch(Throwable e) {
logger.info("exception: ",e);
result =newJsonResult(ResultCode.EXCEPTION,"发生异常:"+e.getMessage());
}
if(resultinstanceofJsonResult){
longcostMs = System.currentTimeMillis() - beginTime;
logger.info("{}请求结束,耗时:{}ms",methodName,costMs);
}
returnresult;
}
/**
* 判断一个方法是否需要登录
*@parammethod
*@return
*/
private booleanisLoginRequired(Method method){
if(!env.equals("prod")){//只有生产环境才需要登录
return false;
}
booleanresult =true;
if(method.isAnnotationPresent(Permission.class)){
result = method.getAnnotation(Permission.class).loginReqired();
}
returnresult;
}
//判断是否已经登录
private booleanisLogin(HttpServletRequest request) {
return true;
/*String token = XWebUtils.getCookieByName(request, WebConstants.CookieName.AdminToken);
if("1".equals(redisOperator.get(RedisConstants.Prefix.ADMIN_TOKEN+token))){
return true;
}else {
return false;
}*/
}
}