在一个分布式服务中,有多个服务,每个服务定义的拦截器和路径都不相同,为了解决以下问题:
1、每个服务定义的拦截器不一致
2、每个拦截器定义的拦截和非拦截的路径不能定制化
十多年成都创新互联公司网站建设,由一走到现在,当中离不开团队顽强的创业精神,离不开伴随我们同行的客户与专业的合作伙伴,创力信息一直秉承以“见一个客户,了解一个行业,交一个朋友”的方式为经营理念,提出“让每一个客户成为我们的终身客户”为目标,以为用户提供精细化服务,全面满足用户需求为宗旨,诚信经营,更大限度为用户创造价值。期待迈向下一个更好的十多年。
为了解决上面2个问题,采用注解+自定义配置,即可实现统一风格的自定义拦截器。
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;
/**
* 1、对拦截器排序
* 2、把对应的配置路径,分别添加到拦截和过滤的规则里
*/
@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 handlerInterceptors;
@Autowired
private Environment environment;
@Override
public void configureMessageConverters(List> 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 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 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) {
}
}
访问拦截的路径:会异常
http://127.0.0.1:9098/test/ok
可以通过Header添加Authorization来,则可以满足不被拦截。
设置过滤的路径:通过postman访问,允许访问
http://127.0.0.1:9098/client/ok