美文网首页springboot demo实战项目
springboot spring cloud gateway

springboot spring cloud gateway

作者: 灰色调诺言 | 来源:发表于2020-01-17 17:10 被阅读0次

    简介

    Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul网关。网关作为流量的,在微服务系统中有着非常作用,网关常见的功能有路由转发、权限校验、限流控制等作用

    Git地址

    https://gitee.com/wqrzsy/lp-demo/tree/master/lp-springboot-gateway

    更多demo请关注

    springboot demo实战项目
    java 脑洞
    java 面试宝典
    开源工具

    基础项目

    springboot spring cloud gateway demo实战项目

    聚合

    1. swagger

    效果图:


    image.png

    聚合后通过访问gateway的swagger-ui页面就能访问所有微服务的swagger了,是不是很方便

    先分享作者连接: https://blog.csdn.net/ttzommed/article/details/81103609

    思路:通过gateway获取注册到eureka上的服务列表,然后把服务的url封装成swagger资源,让swagger-ui页面能获取到

    关键类: swagger资源提供者

    @Component
    @Primary
    public class SwaggerProvider implements SwaggerResourcesProvider {
    
        public static final String API_URI = "/v2/api-docs";
    
        public static final String EUREKA_SUB_PRIX = "CompositeDiscoveryClient_";
    
        private final DiscoveryClientRouteDefinitionLocator routeLocator;
    
        public SwaggerProvider(DiscoveryClientRouteDefinitionLocator routeLocator) {
            this.routeLocator = routeLocator;
        }
    
        @Override
    
        public List<SwaggerResource> get() {
            List<SwaggerResource> resources = new ArrayList<>();
            List<String> routes = new ArrayList<>();
            //从DiscoveryClientRouteDefinitionLocator 中取出routes,构造成swaggerResource
            routeLocator.getRouteDefinitions().subscribe(routeDefinition -> {
                String resourceName = routeDefinition.getId().substring(EUREKA_SUB_PRIX.length());
                String location = routeDefinition.getPredicates().get(0).getArgs().get("pattern").replace("/**", API_URI);
                resources.add(swaggerResource(resourceName, location));
            });
            return resources;
        }
    
        private SwaggerResource swaggerResource(String name, String location) {
            SwaggerResource swaggerResource = new SwaggerResource();
            swaggerResource.setName(name);
            swaggerResource.setLocation(location);
            swaggerResource.setSwaggerVersion("2.0");
            return swaggerResource;
    
        }
    
    
    }
    

    关键类: swagger资源访问Api

    @RestController
    @RequestMapping("/swagger-resources")
    public class SwaggerHandler {
    
        @Autowired(required = false)
        private SecurityConfiguration securityConfiguration;
    
        @Autowired(required = false)
        private UiConfiguration uiConfiguration;
    
        private final SwaggerResourcesProvider swaggerResources;
    
        @Autowired
        public SwaggerHandler(SwaggerResourcesProvider swaggerResources) {
            this.swaggerResources = swaggerResources;
        }
    
        @GetMapping("/configuration/security")
        public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
            return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
    
        }
    
        @GetMapping("/configuration/ui")
        public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
            return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
        }
    
        @GetMapping("")
        public Mono<ResponseEntity> swaggerResources() {
            return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
        }
    }
    

    2. 接口版本化

    先分享作者连接: https://blog.mariojd.cn/how-to-design-spring-boot-api-version-number-elegantly.html

    效果图:


    image.png image.png

    思路:通过RequestMappingHandlerMapping在匹配路径的时候做版本号匹配

    关键类: 映射RequestCondition

    public class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    
        @Override
        protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
            // 扫描类上的 @ApiVersion
            ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
            return createRequestCondition(apiVersion);
        }
    
        @Override
        protected RequestCondition<?> getCustomMethodCondition(Method method) {
            // 扫描方法上的 @ApiVersion
            ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);
            return createRequestCondition(apiVersion);
        }
    
        private RequestCondition<ApiVersionCondition> createRequestCondition(ApiVersion apiVersion) {
            if (Objects.isNull(apiVersion)) {
                return null;
            }
            int value = apiVersion.value();
            Assert.isTrue(value >= 1, "Api Version Must be greater than or equal to 1");
            return new ApiVersionCondition(value);
        }
    
    }
    

    关键类: 路径匹配的逻辑

    public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {
    
        /**
         * 接口路径中的版本号前缀,如: api/v[1-n]/test
         */
        private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("/v(\\d+)/");
    
        private int apiVersion;
    
        ApiVersionCondition(int apiVersion) {
            this.apiVersion = apiVersion;
        }
    
        @Override
        public ApiVersionCondition combine(ApiVersionCondition other) {
            // 最近优先原则,方法定义的 @ApiVersion > 类定义的 @ApiVersion
            return new ApiVersionCondition(other.getApiVersion());
        }
    
        /**
         * 检查当前请求匹配条件和指定请求request是否匹配,如果不匹配返回null,
         * 如果匹配,生成一个新的请求匹配条件,该新的请求匹配条件是当前请求匹配条件
         * 针对指定请求request的剪裁。
         * 举个例子来讲,如果当前请求匹配条件是一个路径匹配条件,包含多个路径匹配模板,
         * 并且其中有些模板和指定请求request匹配,那么返回的新建的请求匹配条件将仅仅
         * 包含和指定请求request匹配的那些路径模板。
         * @param request
         * @return
         */
        @Override
        public ApiVersionCondition getMatchingCondition(HttpServletRequest request) {
            Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getRequestURI());
            if (m.find()) {
                // 获得符合匹配条件的ApiVersionCondition
                int version = Integer.valueOf(m.group(1));
                if (version >= getApiVersion()) {
                    return this;
                }
            }
            return null;
        }
    
        /**
         * 针对指定的请求对象request比较两个请求匹配条件。
         * 该方法假定被比较的两个请求匹配条件都是针对该请求对象request调用了
         * #getMatchingCondition方法得到的,这样才能确保对它们的比较
         * 是针对同一个请求对象request,这样的比较才有意义(最终用来确定谁是
         * 更匹配的条件)。
         *
         * @param other
         * @param request
         * @return
         */
        @Override
        public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
            // 当出现多个符合匹配条件的ApiVersionCondition,优先匹配版本号较大的
            return other.getApiVersion() - getApiVersion();
        }
    
        public int getApiVersion() {
            return apiVersion;
        }
    }
    
    

    demo项目导入

    PS :本项目使用了JDK11,主要导入的时候要先安装JDK11
    参考: https://www.jianshu.com/p/cd0275a2f5fb

    如果这篇文章对你有帮助请给个star


    image.png

    相关文章

      网友评论

        本文标题:springboot spring cloud gateway

        本文链接:https://www.haomeiwen.com/subject/caoczctx.html