溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

springCloud+自定義注解+自定義配置順序攔截器

發(fā)布時(shí)間:2020-10-02 19:41:57 來源:網(wǎng)絡(luò) 閱讀:803 作者:shayang88 欄目:編程語(yǔ)言

案例

在一個(gè)分布式服務(wù)中,有多個(gè)服務(wù),每個(gè)服務(wù)定義的攔截器和路徑都不相同,為了解決以下問題:
1、每個(gè)服務(wù)定義的攔截器不一致
2、每個(gè)攔截器定義的攔截和非攔截的路徑不能定制化

為了解決上面2個(gè)問題,采用注解+自定義配置,即可實(shí)現(xiàn)統(tǒng)一風(fēng)格的自定義攔截器。

方案

1、實(shí)現(xiàn)一個(gè)注解WebInterceptorPathPattern


import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface WebInterceptorPathPattern {
    String ALL_PATH_PATTERN = "/*/**";
    String EMPTY_PATH_PATTERN = "";

    /**
     * 默認(rèn)攔截路徑
     *
     * @return
     */
    String[] interceptorPath() default ALL_PATH_PATTERN;
    /**
     * 攔截路徑變量(如果配置了該屬性,覆蓋默認(rèn)攔截路徑)
     *
     * @return
     */
    String interceptorPathVariable();
    /**
     * 默認(rèn)過濾路徑
     *
     * @return
     */
    String[] excludeInterceptorPath() default EMPTY_PATH_PATTERN;
    /**
     * 過濾路徑變量(如果配置了該屬性,覆蓋默認(rèn)過濾路徑)
     *
     * @return
     */
    String excludeInterceptorPathVariable();
    /**
     * 關(guān)閉該攔截器變量,默認(rèn)攔截器是開啟,當(dāng)配置該變量為false之后,攔截器關(guān)閉
     *
     * @return
     */
    String openVariable();
}

2、將帶有注解的攔截器自動(dòng)排序,并解析攔截和過濾路徑

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、對(duì)攔截器排序
 * 2、把對(duì)應(yīng)的配置路徑,分別添加到攔截和過濾的規(guī)則里
 */
@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);
        //  初始化轉(zhuǎn)換器
        FastJsonHttpMessageConverter fastConvert = new FastJsonHttpMessageConverter();
        //  初始化一個(gè)轉(zhuǎn)換器配置
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        //  fastJson禁用循環(huán)引用
        fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
        //  將配置設(shè)置給轉(zhuǎn)換器并添加到HttpMessageConverter轉(zhuǎn)換器列表中
        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);
                // 判斷是否關(guān)閉了該攔截器,如果關(guān)閉,退出攔截器
                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 {
            //設(shè)置為默認(rèn)值
            interceptorPaths = paths;
        }

        if (interceptorPaths != null && interceptorPaths.length > 0) {
            if (interceptorPaths.length == 1 && StringUtils.isEmpty(interceptorPaths[0])) {
                return null;
            } else {
                return interceptorPaths;
            }
        } else {
            return null;
        }
    }
}

3、自定義攔截器

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("授權(quán)失?。。。。。。。?!");
                throw new DefaultException(ErrorEnum.GET_AUTH_ERROR.getCode(),ErrorEnum.GET_AUTH_ERROR.getMsg());
            }else{
                //解析Authorization屬性,把解析到數(shù)據(jù)放入session,后續(xù)使用!
            }
        }catch (Exception e){
            logger.error("api-攔截器攔截,請(qǐng)重試!");
            throw e;
        }
        return  true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

    }
}

5、自定義配置文件

springCloud+自定義注解+自定義配置順序攔截器

6、驗(yàn)證結(jié)果

訪問攔截的路徑:會(huì)異常

http://127.0.0.1:9098/test/ok

springCloud+自定義注解+自定義配置順序攔截器

可以通過Header添加Authorization來,則可以滿足不被攔截。

設(shè)置過濾的路徑:通過postman訪問,允許訪問

http://127.0.0.1:9098/client/ok

springCloud+自定義注解+自定義配置順序攔截器

springCloud+自定義注解+自定義配置順序攔截器

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI