微服务电商实战(三)gateway统一管理swagger

一、简介

本篇文章要实现的是给接口服务引入swagger来生成接口文档,并用gateway来聚合API。

 

ok,开始实战吧。

 

二、引入swagger

shop-service-api添加swagger依赖,pom如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>shop-parent</artifactId>
        <groupId>com.liazhan</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>shop-service-api</artifactId>
    <packaging>pom</packaging>
    <modules>
        <module>shop-service-api-member</module>
        <module>shop-service-api-weixin</module>
    </modules>

    <dependencies>
        <!-- swagger-spring-boot -->
        <dependency>
            <groupId>com.spring4all</groupId>
            <artifactId>swagger-spring-boot-starter</artifactId>
            <version>1.7.0.RELEASE</version>
        </dependency>
    </dependencies>
</project>

 

修改shop-service-api-weixin的实体类TestEntity和接口WeiXinService,如下

package com.liazhan.weixin.entity;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @version V1.0
 * @description: 测试用实体类
 * @author: Liazhan
 * @date: 2020/4/7 21:55
 */

@ApiModel(value = "测试实体类")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TestEntity {
    /**
     * 姓名
     */
    @ApiModelProperty(value = "姓名")
    String name;
    /**
     * 地址
     */
    @ApiModelProperty(value = "地址")
    String address;
}
package com.liazhan.weixin.service;

import com.liazhan.weixin.entity.TestEntity;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @version V1.0
 * @description: 微信服务接口
 * @author: Liazhan
 * @date: 2020/4/7 21:59
 */
@Api(tags = "微信服务接口")
public interface WeiXinService {
    /**
     * 测试接口
     * @return
     */
    @ApiOperation(value = "测试接口")
    @GetMapping("/test")
    public TestEntity test();
}

 

 

修改shop-service-impl-weixin的入口类AppWeiXin ,添加@EnableSwagger2Doc注释;修改application.yml文件,添加swagger相关配置,如下:

package com.liazhan.weixin;

import com.spring4all.swagger.EnableSwagger2Doc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @version V1.0
 * @description: 微信服务入口类
 * @author: Liazhan
 * @date: 2020/4/8 0:14
 */
@SpringBootApplication
@EnableSwagger2Doc
public class AppWeiXin {

    public static void main(String[] args) {
        SpringApplication.run(AppWeiXin.class,args);
    }
}
#服务端口号
server:
  port: 8200
#eureka信息配置
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8100/eureka
spring:
  application:
    name: liazhan-weixin

####swagger相关配置
swagger:
  base-package: com.liazhan.weixin.service
  title: 微服务电商项目-微信服务接口
  description: 微信服务
  version: 1.1
  terms-of-service-url: www.baidu.com
  contact:
    name: liazhan
    email: 33421352+liazhan@users.noreply.github.com

 

启动eureka和微信服务,访问http://localhost:8200/swagger-ui.html

 

如此微信服务就引入swagger成功了。

 

同理,我们对会员服务进行相似的修改,如下所示:

package com.liazhan.member.service;

import com.liazhan.weixin.entity.TestEntity;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @version V1.0
 * @description: 会员服务接口
 * @author: Liazhan
 * @date: 2020/4/7 23:54
 */
@Api(tags = "会员服务接口")
public interface MemberService {

    /**
     * 调用微信服务测试接口
     * @return
     */
    @ApiOperation(value = "调用微信服务测试接口")
    @GetMapping("/callWeiXin")
    public TestEntity callWeiXin();
}
package com.liazhan.member;

import com.spring4all.swagger.EnableSwagger2Doc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @version V1.0
 * @description: 会员服务入口类
 * @author: Liazhan
 * @date: 2020/4/8 0:13
 */
@SpringBootApplication
@EnableFeignClients
@EnableSwagger2Doc
public class AppMember {

    public static void main(String[] args) {
        SpringApplication.run(AppMember.class,args);
    }
}
#服务端口号
server:
  port: 8300
#eureka信息配置
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8100/eureka
spring:
  application:
    name: liazhan-member

####swagger相关配置
swagger:
  base-package: com.liazhan.member.service
  title: 微服务电商项目-会员服务接口
  description: 会员服务
  version: 1.1
  terms-of-service-url: www.baidu.com
  contact:
    name: liazhan
    email: 33421352+liazhan@users.noreply.github.com

 

启动会员服务,访问http://localhost:8300/swagger-ui.html

 

如此会员服务就引入swagger成功了

 

如此有一个问题是,

查看微信服务文档要访问http://localhost:8200/swagger-ui.html

查看会员服务文档要访问http://localhost:8300/swagger-ui.html

这不是很方便,因此我们引入网关gateway来聚合Api的同时,统一管理swagger文档。

 

 

三、在shop-basics基础上创建Module——shop-basics-cloud-gateway

项目目录如下:

 

跟创建eureka时一样,使用maven创建,jar类型。

 

pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>shop-basics</artifactId>
        <groupId>com.liazhan</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>shop-basics-cloud-gateway</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <!-- gateway -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!-- swagger-spring-boot -->
        <dependency>
            <groupId>com.spring4all</groupId>
            <artifactId>swagger-spring-boot-starter</artifactId>
            <version>1.7.0.RELEASE</version>
        </dependency>
    </dependencies>
</project>

 

MySwaggerResourceProvider文件如下:

package com.liazhan.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.*;

/**
 * @version V1.0
 * @description: 聚合各个服务的swagger接口
 * @author: Liazhan
 * @date: 2020/4/10 14:25
 */
@Component
public class MySwaggerResourceProvider implements SwaggerResourcesProvider {
    /**
     * swagger2默认的url后缀
     */
    private static final String SWAGGER2URL = "/v2/api-docs";

    /**
     * 网关路由
     */
    private final RouteLocator routeLocator;

    /**
     * 网关应用名称
     */
    @Value("${spring.application.name}")
    private String self;

    @Autowired
    public MySwaggerResourceProvider(RouteLocator routeLocator) {
        this.routeLocator = routeLocator;
    }

    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routeHosts = new ArrayList<>();
        // 获取所有可用的host:serviceId
        routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null)
                .filter(route -> !self.equals(route.getUri().getHost()))
                .subscribe(route -> routeHosts.add(route.getUri().getHost()));

        // 记录已经添加过的server,存在同一个应用注册了多个服务在eureka上
        Set<String> dealed = new HashSet<>();
        routeHosts.forEach(instance -> {
            // 拼接url
            String url = "/" + instance.toLowerCase() + SWAGGER2URL;
            if (!dealed.contains(url)) {
                dealed.add(url);
                SwaggerResource swaggerResource = new SwaggerResource();
                swaggerResource.setUrl(url);
                swaggerResource.setName(instance);
                resources.add(swaggerResource);
            }
        });
        return resources;
    }
}

 

SwaggerResourceController文件如下:

package com.liazhan.controller;

import com.liazhan.config.MySwaggerResourceProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.swagger.web.*;

import java.util.List;

/**
 * @version V1.0
 * @description: swagger聚合接口,三个接口都是swagger-ui.html需要访问的接口
 * @author: Liazhan
 * @date: 2020/4/10 14:30
 */
@RestController
@RequestMapping("/swagger-resources")
public class SwaggerResourceController {
    private MySwaggerResourceProvider swaggerResourceProvider;

    @Autowired
    public SwaggerResourceController(MySwaggerResourceProvider swaggerResourceProvider) {
        this.swaggerResourceProvider = swaggerResourceProvider;
    }

    @RequestMapping(value = "/configuration/security")
    public ResponseEntity<SecurityConfiguration> securityConfiguration() {
        return new ResponseEntity<>(SecurityConfigurationBuilder.builder().build(), HttpStatus.OK);
    }

    @RequestMapping(value = "/configuration/ui")
    public ResponseEntity<UiConfiguration> uiConfiguration() {
        return new ResponseEntity<>(UiConfigurationBuilder.builder().build(), HttpStatus.OK);
    }

    @RequestMapping
    public ResponseEntity<List<SwaggerResource>> swaggerResources() {
        return new ResponseEntity<>(swaggerResourceProvider.get(), HttpStatus.OK);
    }
}

 

AppGateway文件如下:

package com.liazhan;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @version V1.0
 * @description: 网关入口类
 * @author: Liazhan
 * @date: 2020/4/10 14:35
 */
@SpringBootApplication
public class AppGateway {
    public static void main(String[] args) {
        SpringApplication.run(AppGateway.class,args);
    }
}

 

application.yml文件如下,网关的端口一般设置成80端口:

server:
  port: 80

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8100/eureka/

spring:
  application:
    name: liazhan-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: service_member
          uri: lb://LIAZHAN-MEMBER
          order: 0
          predicates:
            - Path=/liazhan-member/**
          filters:
            - StripPrefix=1

        - id: service_weixin
          uri: lb://LIAZHAN-WEIXIN
          order: 0
          predicates:
            - Path=/liazhan-weixin/**
          filters:
            - StripPrefix=1

logging:
  level:
    org.springframework.cloud.gateway: debug



 

启动网关入口类

 

发现报错了

Parameter 0 of method modifyRequestBodyGatewayFilterFactory in org.springframework.cloud.gateway.config.GatewayAutoConfiguration required a bean of type 'org.springframework.http.codec.ServerCodecConfigurer' that could not be found.

 

出现这个错误的原因是,gateway使用的是webflux

 

而我们在父项目shop-parent配置了web依赖,那么我们的网关项目也会继承依赖web

        <!-- web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

而web和webflux会出现冲突。

 

因此,我们通过将父项目shop-parent的web依赖,移动到shop-service-api就可以解决这个问题。

 

我们再次启动网关入口类,不会再出现之前的问题。

访问http://localhost/swagger-ui.html

 

 

通过图中红色方框圈住的那个下拉框,可以切换到微信服务的接口文档。

 

如此,便实现了gateway统一管理swagger文档。

并且,我们可以通过gateway聚合Api,

访问微信服务的test接口可以通过访问http://localhost/liazhan-weixin/test

访问会员服务的callWeiXin接口可以通过访问http://localhost/liazhan-member/callWeiXin

 

 

github项目地址https://github.com/liazhan/shop-project/tree/0a289f6b5f2d8f4cecabfbe89f149ea4576c3c42

版本号为0a289f6b5f2d8f4cecabfbe89f149ea4576c3c42

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值