拦截RESTful API并做相应处理的方式
⒈使用Filter(过滤器)
1 package cn.coreqi.security.filter; 2 3 import org.springframework.stereotype.Component; 4 5 import javax.servlet.*; 6 import java.io.IOException; 7 import java.util.Date; 8 9 @Component 10 public class TimeFilter implements Filter { 11 @Override 12 public void init(FilterConfig filterConfig) throws ServletException { 13 System.out.println("TimeFilterc初始化完成!"); 14 } 15 16 @Override 17 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 18 long start = new Date().getTime(); 19 filterChain.doFilter(servletRequest,servletResponse); 20 System.out.println("执行方法所用时间:" + (new Date().getTime() - start)); 21 } 22 23 @Override 24 public void destroy() { 25 System.out.println("TimeFilterc已释放!"); 26 } 27 }
当然,如果是你自己写的Filter一般都会这样,别人的Filter就没有办法使用@Component注解了,那么你可以使用Web.xml,当然SpringBoot没有这个,可以使用SpringBoot独有的方式。
1 package cn.coreqi.security.config; 2 3 import cn.coreqi.security.filter.TimeFilter; 4 import org.springframework.boot.web.servlet.FilterRegistrationBean; 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.Configuration; 7 8 import java.util.ArrayList; 9 import java.util.List; 10 11 @Configuration 12 public class WebConfig { 13 @Bean 14 public FilterRegistrationBean timeFilter(){ 15 FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); 16 filterRegistrationBean.setFilter(new TimeFilter()); 17 List<String> urls = new ArrayList<>(); 18 urls.add("/*"); 19 filterRegistrationBean.setUrlPatterns(urls); 20 return filterRegistrationBean; 21 } 22 }
遗憾的是,Filter是Servlet提供的,SpringMVC的一些信息没有办法全部拿到,只能拿到request和response,没有办法拿到是那个控制器,那个方法处理的。这种情况下可以考虑Spring提供的Interceptor(拦截器)。
⒉使用Interceptor(拦截器)
1 package cn.coreqi.security.interceptor; 2 3 import org.springframework.stereotype.Component; 4 import org.springframework.web.method.HandlerMethod; 5 import org.springframework.web.servlet.HandlerInterceptor; 6 import org.springframework.web.servlet.ModelAndView; 7 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 @Component 12 public class TimeInterceptor implements HandlerInterceptor { 13 /** 14 * 在控制器方法调用之前执行 15 * @param request 16 * @param response 17 * @param handler 当前控制器方法 18 * @return 19 * @throws Exception 20 */ 21 @Override 22 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 23 System.out.println(((HandlerMethod) handler).getBean().getClass().getName()); 24 System.out.println(((HandlerMethod) handler).getMethod().getName()); 25 return true; 26 } 27 28 /** 29 * 在控制器方法调用之后执行,如果控制器方法抛出了异常,那么该方法将不会被调用 30 * @param request 31 * @param response 32 * @param handler 33 * @param modelAndView 34 * @throws Exception 35 */ 36 @Override 37 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 38 39 } 40 41 /** 42 * 无论控制器方法是否抛出异常,该方法始终会被调用 43 * @param request 44 * @param response 45 * @param handler 46 * @param ex 47 * @throws Exception 48 */ 49 @Override 50 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 51 52 } 53 }
1 package cn.coreqi.security.config; 2 3 import cn.coreqi.security.filter.TimeFilter; 4 import cn.coreqi.security.interceptor.TimeInterceptor; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.boot.web.servlet.FilterRegistrationBean; 7 import org.springframework.context.annotation.Bean; 8 import org.springframework.context.annotation.Configuration; 9 import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 10 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 11 12 import java.util.ArrayList; 13 import java.util.List; 14 15 @Configuration 16 public class WebConfig implements WebMvcConfigurer { 17 18 @Autowired 19 private TimeInterceptor timeInterceptor; 20 21 @Bean 22 public FilterRegistrationBean timeFilter(){ 23 FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); 24 filterRegistrationBean.setFilter(new TimeFilter()); 25 List<String> urls = new ArrayList<>(); 26 urls.add("/*"); 27 filterRegistrationBean.setUrlPatterns(urls); 28 return filterRegistrationBean; 29 } 30 31 @Override 32 public void addInterceptors(InterceptorRegistry registry) { 33 registry.addInterceptor(timeInterceptor); 34 } 35 }
拦截器可以拿到请求、响应、处理请求控制器方法的对象,但没法拿到处理请求方法参数的值。如果想要更进一步的拿到具体参数的值,那么就需要用到切片。
⒊使用Aspect(切片)
1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-aop</artifactId> 4 </dependency>
1 package cn.coreqi.security.aspect; 2 3 import org.aspectj.lang.ProceedingJoinPoint; 4 import org.aspectj.lang.annotation.Around; 5 import org.aspectj.lang.annotation.Aspect; 6 import org.springframework.stereotype.Component; 7 8 @Aspect //声明当前类为切片类 9 @Component //让切片成为Spring容器中的一部分 10 public class TimeAspect { 11 12 /** 13 * 第一个*代表任何返回值 14 * cn.coreqi.security.controller.UserController.* 代表拦截该类(控制器)中的所有方法 15 * (..)代表该方法可以有任意参数 16 * @param pjp 表示当前所拦截的信息 17 * @return 18 */ 19 @Around("execution(* cn.coreqi.security.controller.UserController.*(..))") 20 public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable { 21 for (Object arg:pjp.getArgs()){ //遍历拦截方法的参数列表 22 System.out.println("arg is :" + arg); 23 } 24 Object object = pjp.proceed(); //调用真正的方法 25 return object; 26 } 27 }