在一个分布式服务中,有多个服务,每一个服务定义的拦截器和路径都不相同,为了解决如下问题:
一、每一个服务定义的拦截器不一致
二、每一个拦截器定义的拦截和非拦截的路径不能定制化java
为了解决上面2个问题,采用注解+自定义配置,便可实现统一风格的自定义拦截器。web
import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented public @interface WebInterceptorPathPattern { String ALL_PATH_PATTERN = "/*/**"; String EMPTY_PATH_PATTERN = ""; /** * 默认拦截路径 * * @return */ String[] interceptorPath() default ALL_PATH_PATTERN; /** * 拦截路径变量(若是配置了该属性,覆盖默认拦截路径) * * @return */ String interceptorPathVariable(); /** * 默认过滤路径 * * @return */ String[] excludeInterceptorPath() default EMPTY_PATH_PATTERN; /** * 过滤路径变量(若是配置了该属性,覆盖默认过滤路径) * * @return */ String excludeInterceptorPathVariable(); /** * 关闭该拦截器变量,默认拦截器是开启,当配置该变量为false以后,拦截器关闭 * * @return */ String openVariable(); }
package com.baiziwan.service; import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; import com.baiziwan.common.annotation.WebInterceptorPathPattern; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.jetbrains.annotations.Nullable; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.core.env.Environment; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.config.annotation.InterceptorRegistration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * 一、对拦截器排序 * 二、把对应的配置路径,分别添加到拦截和过滤的规则里 */ @Configuration public class WebMvcConfiguration extends WebMvcConfigurationSupport { private final static Logger logger = LoggerFactory.getLogger(WebMvcConfiguration.class); public static final String FALSE = "false"; @Autowired(required = false) private List<HandlerInterceptor> handlerInterceptors; @Autowired private Environment environment; @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { super.configureMessageConverters(converters); StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); converters.add(stringHttpMessageConverter); // 初始化转换器 FastJsonHttpMessageConverter fastConvert = new FastJsonHttpMessageConverter(); // 初始化一个转换器配置 FastJsonConfig fastJsonConfig = new FastJsonConfig(); fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat); // fastJson禁用循环引用 fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect); // 将配置设置给转换器并添加到HttpMessageConverter转换器列表中 fastConvert.setFastJsonConfig(fastJsonConfig); //处理中文乱码问题 List<MediaType> fastMediaTypes = new ArrayList<>(); fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); fastMediaTypes.add(MediaType.ALL); fastConvert.setSupportedMediaTypes(fastMediaTypes); fastConvert.setFastJsonConfig(fastJsonConfig); converters.add(fastConvert); } @Override public void addInterceptors(InterceptorRegistry registry) { //排序拦截器 List<HandlerInterceptor> sortHandlerInterceptors = handlerInterceptors.stream().sorted((handlerInterceptor1, handlerInterceptor2) -> { int order1 = -10000; int order2 = -10000; if (handlerInterceptor1.getClass().isAnnotationPresent(Order.class)) { Order order = handlerInterceptor1.getClass().getAnnotation(Order.class); order1 = order.value(); } if (handlerInterceptor2.getClass().isAnnotationPresent(Order.class)) { Order order = handlerInterceptor2.getClass().getAnnotation(Order.class); order2 = order.value(); } return order1 - order2; }).collect(Collectors.toList()); for (HandlerInterceptor sortHandlerInterceptor : sortHandlerInterceptors) { if (sortHandlerInterceptor.getClass().isAnnotationPresent(WebInterceptorPathPattern.class)) { WebInterceptorPathPattern webInterceptorPathPattern = sortHandlerInterceptor.getClass().getAnnotation(WebInterceptorPathPattern.class); // 判断是否关闭了该拦截器,若是关闭,退出拦截器 if (StringUtils.isNoneEmpty(webInterceptorPathPattern.openVariable())) { String open = environment.getProperty(webInterceptorPathPattern.openVariable()); if (FALSE.equals(open)) { continue; } } // 拦截路径 String[] interceptorPaths = getPath(webInterceptorPathPattern.interceptorPathVariable(), webInterceptorPathPattern.interceptorPath()); if (interceptorPaths == null || interceptorPaths.length == 0) { continue; } InterceptorRegistration interceptorRegistration = registry.addInterceptor(sortHandlerInterceptor); interceptorRegistration.addPathPatterns(interceptorPaths); // 过滤路径 String[] excludeInterceptorPaths = getPath(webInterceptorPathPattern.excludeInterceptorPathVariable(), webInterceptorPathPattern.excludeInterceptorPath()); if (excludeInterceptorPaths == null || excludeInterceptorPaths.length == 0) { continue; } interceptorRegistration.excludePathPatterns(excludeInterceptorPaths); } } } @Nullable private String[] getPath(String pathVariable, String[] paths) { String[] interceptorPaths = null; // 若是变量地址不为空,经过配置获取路径 if (StringUtils.isNoneEmpty(pathVariable)) { String interceptorPathValues = environment.getProperty(pathVariable); if (StringUtils.isEmpty(interceptorPathValues)) { interceptorPaths = paths; } else { interceptorPaths = interceptorPathValues.split(","); } } else { //设置为默认值 interceptorPaths = paths; } if (interceptorPaths != null && interceptorPaths.length > 0) { if (interceptorPaths.length == 1 && StringUtils.isEmpty(interceptorPaths[0])) { return null; } else { return interceptorPaths; } } else { return null; } } }
package com.baiziwan.api.config; import com.baiziwan.api.enums.ErrorEnum; import com.baiziwan.common.annotation.WebInterceptorPathPattern; import com.baiziwan.common.exception.DefaultException; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Service; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Service @WebInterceptorPathPattern(interceptorPathVariable = "api.interceptor.path.include", excludeInterceptorPathVariable = "api.interceptor.path.exclude", openVariable = "api.open") @Order(1) public class TestInterceptor implements HandlerInterceptor { private static final Logger logger = LoggerFactory.getLogger(TestInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { try{ String authorization = request.getHeader("Authorization"); if(StringUtils.isEmpty(authorization)) { logger.error("受权失败!!!!!!!!"); throw new DefaultException(ErrorEnum.GET_AUTH_ERROR.getCode(),ErrorEnum.GET_AUTH_ERROR.getMsg()); }else{ //解析Authorization属性,把解析到数据放入session,后续使用! } }catch (Exception e){ logger.error("api-拦截器拦截,请重试!"); throw e; } return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { } }
访问拦截的路径:会异常spring
http://127.0.0.1:9098/test/ok
能够经过Header添加Authorization来,则能够知足不被拦截。apache
设置过滤的路径:经过postman访问,容许访问json
http://127.0.0.1:9098/client/ok