在一個分佈式服務中,有多個服務,每一個服務定義的攔截器和路徑都不相同,爲了解決如下問題:
一、每一個服務定義的攔截器不一致
二、每一個攔截器定義的攔截和非攔截的路徑不能定製化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