Spring Boot实战(四):Spring Boot配置拦截
拦截器功能强大,能够深入方法前后,常应用于日志记录、权限检查和性能检测等,几乎是项目中不可或缺的一部分,本文就来实现Spring Boot自定义拦截器的配置。
理论指导
问:Spring Boot怎么配置拦截器?
答:配置一个拦截器需要两步完成。
-
自定义拦截器,实现
HandlerInterceptor
这个接口。这个接口包括三个方法,preHandle
是请求执行前执行的,postHandler
是请求结束执行的,但只有preHandle
方法返回true的时候才会执行,afterCompletion
是视图渲染完成后才执行,同样需要preHandle
返回true,该方法通常用于清理资源等工作。 -
注册拦截器。 作用是确定拦截器和拦截的URL。需要继承
WebMvcConfigurationSupport
并重写addInterceptor
方法,WebMvcConfigureAdapter
已经过时了!!
代码实现
目录结构:
imageTimeCostInterceptor是一个功能齐全的拦截器,需要用到util里面的工具类,由于代码较多,感兴趣的可以到GitHub中查看源码。
具体代码:
MyInterceptor.java
public class MyInterceptor implements HandlerInterceptor {
/**
* preHandle在执行Controller之前执行,返回true,则继续执行Contorller
* 返回false则请求中断。
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o)
throws Exception {
//只有返回true才会继续向下执行,返回false取消当前请求
long startTime = System.currentTimeMillis();
httpServletRequest.setAttribute("startTime", startTime);
return true;
}
/**
* postHandle是在请求执行完,但渲染ModelAndView返回之前执行
*/
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
ModelAndView modelAndView) throws Exception {
long startTime = (Long) httpServletRequest.getAttribute("startTime");
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
StringBuilder sb = new StringBuilder(1000);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = simpleDateFormat.format(new Date());
sb.append("-----------------------").append(date).append("-------------------------------------\n");
sb.append("URI : ").append(httpServletRequest.getRequestURI()).append("\n");
sb.append("CostTime : ").append(executeTime).append("ms").append("\n");
sb.append("-------------------------------------------------------------------------------");
System.out.println(sb.toString());
}
/**
* afterCompletion是在整个请求执行完毕后执行
*/
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
}
}
RegisterInterceptor.java
/**
* 继承WebMvcConfigurationSupport继承并重写addInterceptor方法用于注册拦截器
* WebMvcConfigureAdapter已经过时了!!
*/
@Configuration
public class RegisterInterceptor extends WebMvcConfigurationSupport {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
拦截效果
image更新
跨域访问
由于JavaScript同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。具体的看下表(来源于javascript跨域资源总结与解决办法):
URL | 说明 | 是否允许通信 |
---|---|---|
http://www.a.com/a.jshttp://www.a.com/b.js | 同一域名下 | 允许 |
http://www.a.com/lab/a.jshttp://www.a.com/script/b.js | 同一域名下不同文件夹 | 允许 |
http://www.a.com:8000/a.jshttp://www.a.com/b.js | 同一域名,不同端口 | 不允许 |
http://www.a.com/a.jshttps://www.a.com/b.js | 同一域名,不同协议 | 不允许 |
http://www.a.com/a.jshttp://70.32.92.74/b.js | 域名和域名对应ip | 不允许 |
http://www.a.com/a.jshttp://script.a.com/b.js | 主域相同,子域不同 | 不允许 |
http://www.a.com/a.jshttp://a.com/b.js | 同一域名,不同二级域名(同上) | 不允许(cookie这种情况下也不允许访问) |
http://www.cnblogs.com/a.jshttp://www.a.com/b.js | 不同域名 | 不允许 |
上面代码是可以实现拦截器基本功能,但是这样是不可以跨域访问的,前端请求接口会有报错:XMLHttpRequest cannot loadhttp://xxx/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
解决方案是设置请求头Access-Control-Allow-Origin为“*”或者设置为和request相同的Origin。
①在拦截器中添加一个设置请求头的方法。
public void crossDomain(HttpServletRequest request, HttpServletResponse response) {
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
}
②在preHandle中调用这个方法。
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
crossDomain(request, response);
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
return true;
}
完整代码:GItHub地址