JAVA三种拦截方式
最近面试有遇到拦截方式的场景,结合网上xdm的代码整理了下,分为以下三种:
java原生过滤器Filter、springMVC拦截器、aop切面
目录:
- 一、java原生过滤器Filter
- 二、springMVC拦截器
- 三、aop切面
一、java原生过滤器Filter
package com.zhangximing.springbootinterceptor.interceptor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Enumeration; /** * 自定义Filter * 对请求的header 过滤token * * 过滤器Filter可以拿到原始的HTTP请求和响应的信息, * 但是拿不到你真正处理请求方法的信息,也就是方法的信息 * * @Component 注解让拦截器注入Bean,从而让拦截器生效 * @WebFilter 配置拦截规则 * * 拦截顺序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller * */ @Slf4j @Component @WebFilter(urlPatterns = {"/**"},filterName = "authFilter") public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { log.info("TokenFilter init {}",filterConfig.getFilterName()); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String param = request.getParameter("param"); response.setContentType("text/html;charset=UTF-8"); //获取请求头token String token = ""; HttpServletRequest httpServletRequest = (HttpServletRequest) request; Enumeration 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)){ //验证token if ("7758258xx".equals(token)){ chain.doFilter(request,response);//到下一个链 }else{ response.getWriter().write("doFilter-请求头token不通过"); } }else{ log.info("doFilter-参数param不符合条件"); response.getWriter().write("doFilter-参数param不通过"); } } @Override public void destroy() { log.info("destroy"); } }
简单测试直接用的postman,参数是一个param和一个请求头token:
这里补充一下:
若非springboot的情况下,不使用@WebFilter则需要自己设置配置文件
你需要在web.xml文件中配置过滤器,指定要拦截的URL以及要使用的过滤器
MyFilter com.zhangximing.springbootinterceptor.interceptor.MyFilter MyFilter /example
二、springMVC拦截器
import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Method; /** * 自定义拦截器 * 自定义拦截器后,需要配置进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 */ @Override public 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链,直接返回response return true; } /** * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后) * preHandle方法处理之后这个方法会被调用,如果控制器Controller出现了异常,则不会执行此方法 * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ @Override public 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 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info("Interceptor afterCompletion"); }
这里注意下,需要将拦截器配置进spring
import com.zhangximing.springbootinterceptor.interceptor.MyInterceptor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * MyInterceptor 自定义拦截器后,需要配置进Spring * 也可以mapping,跨域设置 */ @Slf4j @Configuration public class MyInterceptorConfig implements WebMvcConfigurer { @Autowired MyInterceptor myInterceptor; /** * 添加拦截器 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { log.info("addInterceptors tokenInterceptor"); registry.addInterceptor(myInterceptor) .addPathPatterns("/**")//指定该类拦截的url .excludePathPatterns( "/static/**");//过滤静态资源 } /** * 如果实现了Filter跨域拦截,这个跨域无效 * 拦截器实现 跨域支持 * @param registry */ @Override public void addCorsMappings(CorsRegistry registry) { log.info("addInterceptors addCorsMappings"); registry.addMapping("/**") .allowedOriginPatterns("*") //本人测试时springboot2.7版本用的是这个 .allowCredentials(true) .allowedMethods("GET", "POST", "DELETE", "PUT","OPTIONS","HEAD") .allowedHeaders("*") .maxAge(3600); } }
测试同理:
三、aop切面
引入maven:
org.springframework.boot spring-boot-starter-aop
若出现无法解析aspectjweaver则需要手动加入其他版本maven解决问题
org.aspectj aspectjweaver 1.9.4
import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.Arrays; /** * @Author: zhangximing * @Email: 530659058@qq.com * @Date: 2023/8/18 10:15 * @Description: 切面 */ @Slf4j @Component //表示它是一个Spring的组件 @Aspect //表示它是一个切面 public class MyAspect { private static final Logger logger = LoggerFactory.getLogger(MyAspect.class); ThreadLocal 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("
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。