JAVA拦截器的三种实现方式
- 一、java原生过滤器Filter
- 二、springMVC拦截器
- 三、aop切面实现拦截器
一、java原生过滤器Filter
/*** 自定义Filter* 对请求的header 过滤token** 过滤器Filter可以拿到原始的HTTP请求和响应的信息,* 但是拿不到你真正处理请求方法的信息,也就是方法的信息** @Component 注解让拦截器注入Bean,从而让拦截器生效* @WebFilter 配置拦截规则** 拦截顺序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller**/
@Slf4j
@Component
@WebFilter(urlPatterns = {"/**"},filterName = "authFilter")
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {log.info("TokenFilter init {}",filterConfig.getFilterName());}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {String param = request.getParameter("param");response.setContentType("text/html;charset=UTF-8");//获取请求头tokenString token = "";HttpServletRequest httpServletRequest = (HttpServletRequest) request;Enumeration<String> headerNames = httpServletRequest.getHeaderNames();while(headerNames.hasMoreElements()) {//判断是否还有下一个元素String nextElement = headerNames.nextElement();//获取headerNames集合中的请求头if ("token".equals(nextElement)){token = httpServletRequest.getHeader(nextElement);log.info("请求头key[" + nextElement + "]:" + token);}}log.info("doFilter-我拦截到了请求:"+ param);if (null != param && "pass".equals(param)){//验证tokenif ("7758258xx".equals(token)){chain.doFilter(request,response);//到下一个链}else{response.getWriter().write("doFilter-请求头token不通过");}}else{log.info("doFilter-参数param不符合条件");response.getWriter().write("doFilter-参数param不通过");}}@Overridepublic void destroy() {log.info("destroy");}
}
二、springMVC拦截器
/*** 自定义拦截器* 自定义拦截器后,需要配置进Spring** 拦截器Interceptor可以拿到原始的HTTP请求和响应的信息,* 也可以拿到你真正处理请求方法的信息,但是拿不到传进参数的那个值。**拦截顺序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller*/
@Slf4j
@Component
public class MyInterceptor implements HandlerInterceptor {/*** 在访问Controller某个方法之前这个方法会被调用。* @param request* @param response* @param handler* @return false则表示不执行postHandle方法,true 表示执行postHandle方法* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("Interceptor preHandle {}","");String token = request.getHeader("token");log.info("Interceptor preHandle token :{}",token);log.info("Interceptor preHandle uri {}",request.getRequestURL().toString());response.setContentType("text/html;charset=UTF-8");//spring boot 2.0对静态资源也进行了拦截,当拦截器拦截到请求之后,// 但controller里并没有对应的请求时,该请求会被当成是对静态资源的请求。// 此时的handler就是 ResourceHttpRequestHandler,就会抛出上述错误。if (handler instanceof HandlerMethod){HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();log.info("Token Interceptor preHandle getMethod {}",method.getName());}else if(handler instanceof ResourceHttpRequestHandler){//静态资源ResourceHttpRequestHandler resourceHttpRequestHandler = (ResourceHttpRequestHandler) handler;log.info("Token Interceptor preHandle getMethod {}",resourceHttpRequestHandler.getMediaTypes());}if (!"7758258xx".equals(token)){response.getWriter().write("doInterceptor-请求头token不通过");return false;}//false则表示不执行postHandle方法,不执行下一步chain链,直接返回responsereturn true;}/*** 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)* preHandle方法处理之后这个方法会被调用,如果控制器Controller出现了异常,则不会执行此方法* @param request* @param response* @param handler* @param modelAndView* @throws Exception*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("Interceptor postHandle");}/*** 不管有没有异常,这个afterCompletion都会被调用* @param request* @param response* @param handler* @param ex* @throws Exception*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("Interceptor afterCompletion");}
三、aop切面实现拦截器
引入maven:
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version>
</dependency>
/*** @Description: 切面*/
@Slf4j
@Component //表示它是一个Spring的组件
@Aspect //表示它是一个切面
public class MyAspect {private static final Logger logger = LoggerFactory.getLogger(MyAspect.class);ThreadLocal<Long> startTime = new ThreadLocal<>();/*** 第一个*代表返回类型不限* 第二个*代表所有类* 第三个*代表所有方法* (..) 代表参数不限* com.zhangximing.springbootinterceptor.controller 测试的controller层*/@Pointcut("execution(public * com.zhangximing.springbootinterceptor.controller.*.*(..))")public void pointCut(){};@Before(value = "pointCut()")public void before(JoinPoint joinPoint){System.out.println("方法执行前执行......before");ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();logger.info("<=====================================================");logger.info("请求来源: =》" + request.getRemoteAddr());logger.info("请求URL:" + request.getRequestURL().toString());logger.info("请求方式:" + request.getMethod());logger.info("响应方法:" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());logger.info("请求参数:" + Arrays.toString(joinPoint.getArgs()));logger.info("连接点的方法签名对象:"+joinPoint.getSignature());logger.info("连接点所在的目标对象:"+joinPoint.getTarget());logger.info("代理对象:"+joinPoint. getThis());logger.info("------------------------------------------------------");startTime.set(System.currentTimeMillis());}// 定义需要匹配的切点表达式,同时需要匹配参数/*** @description 要拦截修改参数的值只有使用这个方法,Around相当于before+after* @param pjp* @param arg 类型可以根据pointCut指定切点类下的方法确定,也可以使用统一的Object,也可以不写参数* @return* @throws Throwable*/@Around("pointCut() && args(arg)")public Object around(ProceedingJoinPoint pjp, Object arg) throws Throwable{logger.info("入参:{}",arg);logger.info("方法环绕start...around");JSONObject param = JSONObject.parseObject(JSONObject.toJSONString(arg));if ("zxm".equals(param.getString("name"))){JSONObject result = new JSONObject();result.put("success",false);result.put("msg","error");return result;}param.put("exist",true);param.put("name","cml");//修改值Object[] objects = new Object[]{param};Object objectNew = pjp.proceed(objects);logger.info("方法环绕end...around");return objectNew;}@After("within(com.zhangximing.springbootinterceptor.controller.*)")public void after(){System.out.println("方法之后执行...after.");}/**** @param AjaxResult rst 该参数类型需要与测试的Controller层的返回值类型一致,否则不生效,也就是找不到* 该测试中的AjaxResult是测试项目中封装好的出参*/@AfterReturning(pointcut="pointCut()",returning = "rst")public void afterRunning(JSONObject rst){if(startTime.get() == null){startTime.set(System.currentTimeMillis());}System.out.println("方法执行完执行...afterRunning");logger.info("耗时(毫秒):" + (System.currentTimeMillis() - startTime.get()));logger.info("返回数据:{}", rst);logger.info("==========================================>");}@AfterThrowing("within(com.zhangximing.springbootinterceptor.controller.*)")public void afterThrowing(){System.out.println("异常出现之后...afterThrowing");}
}