Spring Boot2 学习笔记之集成 Interceptor(七)
过滤器 Filter 和 拦截器 Interceptor 的区别
Filter 是依赖于 Servlet 容器,属于 Servlet 规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用。
Filter 的执行由 Servlet 容器回调完成,而拦截器通常通过动态代理的方式来执行。
Filter 的生命周期由 Servlet 容器管理,而拦截器则可以通过 IoC 容器来管理,因此可以通过注入等方式来获取其他 Bean 的实例,因此使用会更方便。
过滤器在 spring boot 调用的外层进行拦截,而拦截器则在 spring boot 加载 bean 之后进行拦截操作
编写一个拦截器
spring boot 中拦截器很简单,只要实现HandlerInterceptor
接口就可以
以下是一个计算请求执行时间的拦截器
public class LogCostInterceptor implements HandlerInterceptor { long start = System.currentTimeMillis(); @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { start = System.currentTimeMillis(); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("Interceptor cost="+(System.currentTimeMillis()-start)); } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
这里我们需要实现 HandlerInterceptor 这个接口,这个接口包括三个方法,preHandle 是请求执行前执行的,postHandler 是请求结束执行的,但只有 preHandle 方法返回 true 的时候才会执行,afterCompletion 是视图渲染完成后才执行,同样需要 preHandle 返回 true,该方法通常用于清理资源等工作。除了实现上面的接口外,我们还需对其进行配置:
@Configuration public class InterceptorConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogCostInterceptor()).addPathPatterns("/**"); super.addInterceptors(registry); } }
使用拦截器解析 Basic token 信息
我们开发网络应用中免不了要开发与授权相关的功能,授权的操作就非常适合放入拦截器.
以下是我编写的拦截器,用来解析 Basic token 信息,并将用户名放入请求参数中
@Slf4j public class FirstInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { String token = httpServletRequest.getHeader("Authorization"); String regex = "^Basic\\s.+$"; if(token != null && token.matches(regex)){ //获取 basic token log.info("token:{}",token); token = new String(Base64.getDecoder().decode(token.substring(6)),"UTF-8"); log.info("获取的 Authorization token: {}",token); //basic token 格式为 username:password String[] res = token.split(":"); if(res[0].equals("admin") && res[1].equals("111111")){ //将用户名放入 req 中 httpServletRequest.setAttribute("username",res[0]); return true; }else{ JSONObject json = new JSONObject(); //向 json 中添加数据 json.put("code", 401); json.put("message", "用户名密码错误"); String jsonStr = json.toString(); httpServletResponse.setStatus(401); this.returnJson(httpServletResponse,jsonStr); return false; } } JSONObject json = new JSONObject(); //向 json 中添加数据 json.put("code", 403); json.put("message", "未授权"); String jsonStr = json.toString(); httpServletResponse.setStatus(403); this.returnJson(httpServletResponse,jsonStr); return false; } private void returnJson(HttpServletResponse response, String json) throws Exception{ response.setCharacterEncoding("UTF-8"); response.setHeader("Content-type","application/json;charset=UTF-8"); System.out.println("Default charset: " + response.getCharacterEncoding()); log.info("返回值:{}",json); PrintWriter writer = response.getWriter(); writer.write(json); writer.flush(); writer.close(); } @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 { } }
再编写一个controller
进行测试
@RestController @Slf4j public class TestController { @GetMapping("testInterceptor") public Map<String,Object> testInterceptor(HttpServletRequest req){ Map res = new HashMap<String,Object>(); res.put("用户名",req.getAttribute("username")); return res; } }
接下来我们再PostMan
中进行测试:
用户名为admin
,密码为111111
才能通过拦截器