在日常开发中,我们常用拦截器如HandlerInterceptor,ClientHttpRequestInterceptor,RequestInterceptor,AsyncClientHttpRequestInterceptor等,
这几种拦截器都是HTTP拦截器,在处理业务逻辑之前对http请求信息进行处理,比如获取请求头,请求参数,设置请求头,请求参数等;
HandlerInterceptor拦截器
HandlerInterceptor是SpringMVC中的拦截器,它拦截的目标是请求的地址,比MethodInterceptor先执行。
实现一个HandlerInterceptor拦截器可以实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter类。
java
public interface HandlerInterceptor {
/**前置处理:在业务处理器处理请求之前被调用*/
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
/**中置处理:在业务处理器处理请求执行完成后,生成视图之前执行。*/
void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
/**后置处理:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等*/
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
使用示例(HandlerInterceptorAdapter实现了HandlerInterceptor接口):
java
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("在Controller方法调用之前执行:" + request.getRequestURI());
//只有返回true才会继续向下执行,返回false取消当前请求
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
System.out.println("在Controller方法调用之后,视图被渲染之前执行:" + request.getRequestURI());
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("在视图被渲染之后执行:" + request.getRequestURI());
}
}
MethodInterceptor拦截器
MethodInterceptor是AOP项目中的拦截器,它拦截的目标是方法,即使不是Controller中的方法。
实现MethodInterceptor拦截器大致分为两种,一种是实现MethodInterceptor接口,另一种利用AspectJ的注解或配置。
使用示例(实现MethodInterceptor接口):
java
//自定义注解类
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Log {
}
//方法拦截器
public class CustomMethodInterceptor implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object object = invocation.proceed();
System.out.println("after...");
return object;
}
}
@Configuration
public class AspectjAutoConfig {
@Bean
public DefaultPointcutAdvisor getDefaultPointcutAdvisor() {
DefaultPointcutAdvisor pointcutAdvisor = new DefaultPointcutAdvisor();
pointcutAdvisor.setOrder(Ordered.HIGHEST_PRECEDENCE + 500);
//基于方法注解进行拦截
AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(null, Log.class);
CustomMethodInterceptor advice = new CustomMethodInterceptor();
pointcutAdvisor.setPointcut(pointcut);
pointcutAdvisor.setAdvice(advice);
return pointcutAdvisor;
}
}
public interface CountryMapper {
void show();
}
@Component
public class CountryMapperImpl implements CountryMapper {
//用自定义注解类标注方法,该方法会被自定义方法拦截器进行拦截处理
@Log
@Override
public void show(){
System.out.println("invoke show...");
}
}
@RestController
@SpringBootApplication
public class Main{
@Autowired
private CountryMapper countryMapper;
public static void main(String[] args){
SpringApplication.run(Main.class, args);
}
@GetMapping("/index")
public String index(){
countryMapper.show();
return LocalDateTime.now().toString();
}
}
ClientHttpRequestInterceptor拦截器
ClientHttpRequestInterceptor是对RestTemplate的请求进行拦截的,在项目中直接使用restTemplate.getForObject的时候,会对这种请求进行拦截,经常被称为:RestTemplate拦截器或者Ribbon拦截器。
java
public interface ClientHttpRequestInterceptor {
/**只有这一个方法,在项目中直接使用 restTemplate.getForObject 的时候,会对这种请求进行拦截*/
ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException;
}
使用示例(实现ClientHttpRequestInterceptor 接口):
java
public class RestClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpHeaders headers = request.getHeaders();
headers.add("Cookie","SESSIONID=b8dd5bd9-9fb7-48cb-a86b-e079cb554fb8");
log.info("拦截器已添加header");
return execution.execute(request,body);
}
}
RequestInterceptor拦截器
RequestInterceptor常被称为是Feign拦截器,由于Feign调用底层实际上还是http调用,因此也是一个http拦截器。
在项目中使用Feign调用的时候,可以使用此拦截器。
java
public interface RequestInterceptor {
/**在项目中使用Feign调用的时候,可以使用此拦截器*/
void apply(RequestTemplate template);
}
使用示例(实现RequestInterceptor接口):
java
public class FeignRequestInterceptor implements RequestInterceptor, Ordered {
private static final String SESSIONID = "SESSIONID";
private static final String SESSIONID_PREFIX = "SESSIONID=";
private static final String COOKIE = "Cookie";
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes servletAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest httpServletRequest = servletAttributes.getRequest();
Cookie[] cookies = httpServletRequest.getCookies();
for (Cookie cookie : cookies) {
if (SESSIONID.equals(cookie.getName())){
requestTemplate.header(COOKIE, SESSIONID_PREFIX+cookie.getValue());
break;
}
}
}
}
AsyncClientHttpRequestInterceptor拦截器
AsyncClientHttpRequestInterceptor从Spring 5.0开始,同样是处理http请求,主要是针对 AsyncRestTemplate的请求进行拦截,但目前标记为不推荐使用;
使用示例(实现AsyncClientHttpRequestInterceptor接口):
java
public class TestAsyncRestTemplateInterceptor implements AsyncClientHttpRequestInterceptor, Ordered {
public TestAsyncRestTemplateInterceptor() {
}
public int getOrder() {
return 10;
}
public ListenableFuture<ClientHttpResponse> intercept(HttpRequest request, byte[] body, AsyncClientHttpRequestExecution execution) throws IOException {
URI uri = request.getURI();
String serviceName = uri.getHost();
map.put("spring-application-name", serviceName);
String reqAttr = URLEncoder.encode(JacksonSerializer.serializer.serialize(map), StandardCharsets.UTF_8.name());
request.getHeaders().add("reqAttr", reqAttr);
return execution.executeAsync(request,body);
}
}