SpringBoot e-Commerce project mall (35K + STAR) address: github.com/macrozheng/…

Abstract

I remember that THERE is no API document aggregation in my mall-swarm microservice project. Accessing the API document of each service requires accessing a separate swagger-ui. HTML page. Since we use microservice, there should be a unified API document entry. This article will introduce its implementation in detail, I hope to help you!

Front knowledge

We will use Nacos as the registry, Gateway as the Gateway, and KNIfe4J to generate API documentation. Those who are not familiar with these technologies can read the following article.

  • Spring Cloud Gateway: a new generation of API Gateway services
  • Spring Cloud Alibaba: Nacos is used as a registry and configuration center
  • Give Swagger a new skin and instantly Swagger!

Application architecture

Our ideal solution would be for the gateway to act as a unified entry point for API documentation, aggregating all microservices’ documentation, and enabling access to other service API documentation by switching between gateways.

Related services:

  • Micro-knife4j-gateway: gateway service, as the access entrance of micro-service API documents, aggregates all API documents, and needs to introduce the document front-end UI package.
  • Micro-knife4j-user: user service, common API service, no need to introduce document front-end UI package;
  • Micro-knife4j-order: Order service, common API service, no need to introduce document front-end UI package.

The specific implementation

The following is a detailed introduction to the implementation of Spring Cloud Gateway + KNIfe4J aggregation API document, which successively builds user service, order service and Gateway service.

micro-knife4j-user

Let’s start by building a user service, a plain API service that integrates knife4J in three simple steps.

  • inpom.xmlTo add dependencies, a SpringBoot Web functionality dependency, knife4J microservices dependency (front-end UI package without API documentation);
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-micro-spring-boot-starter</artifactId>
    </dependency>
</dependencies>
Copy the code
  • inapplication.ymlAdd the configuration, just configure the Nacos registry;
server:
  port: 9501
spring:
  profiles:
    active: dev
  application:
    name: micro-knife4j-user
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
management:
  endpoints:
    web:
      exposure:
        include: "*"
Copy the code
  • Add Swagger related configuration, very general configuration, add@EnableKnife4jAnnotations turn on knife4J enhancements.
/** * Swagger API configuration */
@Configuration
@EnableSwagger2
@EnableKnife4j
public class Swagger2Config {
    @Bean
    public Docket createRestApi(a){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.macro.cloud.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo(a) {
        return new ApiInfoBuilder()
                .title("micro-knife4j-user")
                .description("User Service API Documentation")
                .contact("macro")
                .version("1.0") .build(); }}Copy the code

micro-knife4j-order

Next we set up the order service, a common API service, directly refer to the above user service set up.

micro-knife4j-gateway

Finally, we set up a gateway service as a unified entrance to the API documents of microservices and aggregate all the API documents of microservices.

  • inpom.xmlTo add dependencies, Gateway dependencies, and knife4J Starter (front-end UI package containing API documentation);
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-spring-boot-starter</artifactId>
    </dependency>
</dependencies>
Copy the code
  • inapplication.ymlAdd some configuration, such as configuring the Nacos registry, routing for user service and order service.
server:
  port: 9201
spring:
  profiles:
    active: dev
  application:
    name: micro-knife4j-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      routes: Configure the routing path
        - id: user-service
          uri: lb://micro-knife4j-user
          predicates:
            - Path=/user-service/**
          filters:
            - StripPrefix=1
        - id: order-service
          uri: lb://micro-knife4j-order
          predicates:
            - Path=/order-service/**
          filters:
            - StripPrefix=1
      discovery:
        locator:
          enabled: true # enable dynamic route creation from registry
          lower-case-service-id: true Use lowercase service names. Default is uppercase
Copy the code
  • Add Swagger resource configuration on the gateway to aggregate Swagger in other microservicesapi-docsAccess path;
/** * Created by macro on 2020/7/9. */
@Slf4j
@Component
@Primary
@AllArgsConstructor
public class SwaggerResourceConfig implements SwaggerResourcesProvider {

    private final RouteLocator routeLocator;
    private final GatewayProperties gatewayProperties;

    @Override
    public List<SwaggerResource> get(a) {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routes = new ArrayList<>();
        // Get the ids of all routes
        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
        // Filter out the routes defined in the configuration file -> Filter out the Path Route Predicate-> splices together the API -docs Path -> Generate SwaggerResourcegatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId())).forEach(route  -> { route.getPredicates().stream() .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                    .forEach(predicateDefinition -> resources.add(swaggerResource(route.getId(),
                            predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
                                    .replace("* *"."v2/api-docs"))));
        });

        return resources;
    }

    private SwaggerResource swaggerResource(String name, String location) {
        log.info("name:{},location:{}", name, location);
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("2.0");
        returnswaggerResource; }}Copy the code
  • What’s Swagger’sapi-docsAccess path? This path will return data in JSON format, from which all data of Swagger rendering API document page comes. For example, our user service will return the following information, access address:http://localhost:9201/user-service/v2/api-docs

  • Next, we need to customize the nodes of each configuration of Swagger. In simple terms, we need to customize the interfaces for acquiring data within Swagger.
/** * Created by macro on 2020/7/9. */
@RestController
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;
    }

    /** * Swagger security configuration, support oauth and apiKey Settings */
    @GetMapping("/swagger-resources/configuration/security")
    public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
    }

    /** * Swagger UI configuration */
    @GetMapping("/swagger-resources/configuration/ui")
    public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
    }

    /** * Swagger */ ** * Swagger */
    @GetMapping("/swagger-resources")
    public Mono<ResponseEntity> swaggerResources(a) {
        return Mono.just((newResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); }}Copy the code
  • For instanceswagger-resourcesThis interface can be used to retrieve all microservicesapi-docsAccess path, obtain the following information, access address:http://localhost:9201/swagger-resources

Function demonstration

Next, let’s demonstrate the function of microservice API document aggregation. You only need to visit the API document page of the gateway, and you can switch to the API document of the relevant service.

  • Start our Nacos registry first, and then in turnmicro-knife4j-user,micro-knife4j-orderandmicro-knife4j-gatewayService;

  • From the gateway access API documentation, access address: http://localhost:9201/doc.html

  • We can switch to the API document of the corresponding service through the switch component in the upper left corner.

  • Checking the API documentation, we can find that all interfaces have been added with the corresponding access prefix, and can be accessed normally.

Switch back to Swagger UI

If you don’t want to use Knife4J and want to use the original Swagger interface, it can also be supported, the switch method is very simple, let’s talk about it.

  • The first thing we need to do ispom.xmlKnife4j dependencies are removed from knife4j, mainly the following two dependencies;
<dependencies>
    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-micro-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-spring-boot-starter</artifactId>
    </dependency>
</dependencies>
Copy the code
  • inpom.xmlAdd Swagger related dependencies and remove the ones originally used@EnableKnife4jAnnotations;
<dependencies>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.9.2</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.9.2</version>
    </dependency>
    <dependency>
        <groupId>io.swagger</groupId>
        <artifactId>swagger-models</artifactId>
        <version>1.6.0</version>
    </dependency>
    <dependency>
        <groupId>io.swagger</groupId>
        <artifactId>swagger-annotations</artifactId>
        <version>1.6.0</version>
    </dependency>
</dependencies>
Copy the code
  • Restart all services, access to the gateway API documentation path to view: http://localhost:9201/swagger-ui.html

conclusion

Comparing knife4J microservice usage with native Swagger, knife4j is once again an enhanced UI implementation of Springfox-Swagger, which fully follows the usage of Springfox-Swagger.

The resources

The official document: doc.xiaominfo.com/guide/ui-fr…

Project source code address

Github.com/macrozheng/…

The public,

Mall project full set of learning tutorials serialized, attention to the public number the first time access.