SpringCloud Alibaba 2021微服务实战十八 SpringCloud整合Swagger3

导读:在SpringCloud体系架构中,我们需要的每个服务都需要对外输出接口文档,本篇内容主要是给我们的微服务配上Swagger的接口文档,并在网关层完成接口聚合。

Swagger3简介

在当下很多项目都会采用前后端分离的模式,前端和后端的工作由不同的开发人员完成。在这种开发模式下,我们需要维护一份及时更新且完整的Rest API接口文档。传统意义上的文档都是后端人员在开发相关接口后手动更新到接口文档上,但是这种方式很难保证文档的及时性,而且由于一些原因后端开发人员可能会忘记更新,这样就会导致随着开发的进行接口文档会失去他本身的参考意义,反而会增加沟通成本。而 Swagger 给我们提供了一个全新的维护 API 文档的方式,他有以下几个有点:

  • 只需要后端开发人员给接口加上几个注解,Swagger就可以根据代码自动生成API文档,节省编写接口文档的工作量,而且对接口修改时只需要修改相应的注解,能保证接口的及时性;
  • SwaggerUI展现出来的是一份可交互式的API文档,我们可以直接在接口页面对功能测试,省去了大量接口联调的时间;

Swagger3有以下几个常见注解,大家在使用过程中会经常用到。

@Api

此注解可以用来标记 Controller 的功能,如:

@Api(tags = "product模块")
public class ProductController implements ProductFeign {
	
}

@ApiOperation

此注解用来标记一个方法的作用

@ApiOperation(value = "根据产品编码查找对应的产品")
public ResultData<ProductDTO> getByCode(@PathVariable String productCode){
	...
}

@ApilmplicitParam@ApilmplicitParams

这组注解用来对参数进行描述,@ApilmplicitParam 有几个重要的参数:
name:参数名
value:参数的汉字说明、解释
required:参数是否必须传
paramType:参数放在哪个地方(header: 对应@RequestHeader的参数;query :对应@RequestParam的参数;path :对应@PathVariable的参数;body:对应 @RequestBody 的参数;form(普通表单提交) )

@ApiImplicitParam(name = "productCode",value = "产品编码", required = true,paramType = "path")
public ResultData<ProductDTO> getByCode(@PathVariable String productCode){
	...
}
@ApiImplicitParam(name = "productCode" , value = "产品编码",required = true, paramType = "query")
public ResultData<String> delete(@RequestParam String productCode){
	...
}

如果有多个参数,则需要使用@ApilmplicitParams 注解。

@ApiModel ,@ApiModelProperty

如果参数是一个对象,则需要在对象所在的类上加上此注解。这种一般用在post创建的时候,使用 @RequestBody 这样的场景,请求参数无法使用 @ApiImplicitParam 注解进行描述的时候 。在具体字段上则使用@ApiModelProperty注解。如:

@Data
@ApiModel(value = "产品封装类ProductDTO",description = "产品相关信息封装,用于接口传参")
public class ProductDTO {
    @ApiModelProperty(value = "产品主键")
    private Integer id;
    @ApiModelProperty(value = "产品编码")
    private String productCode;
    @ApiModelProperty(value = "产品名称")
    private String productName;
    @ApiModelProperty(value = "数量")
    private Integer count;
    @ApiModelProperty(value = "单价")
    private BigDecimal price;
}

使用

在项目中要使用Swagger3很简单,按照以下几步即可:

我这整合的环境是SpringCloud+SpringCloudAlibaba+SpringCloudGateway+SpringSecurityOAuth2+Nacos+Swagger3,这些框架整合的时候版本适配是一个大问题,然后就是不同版本的细节问题,再就是加了安全框架后请求拦截问题,然后还有SpringCloudGateway做聚合文档的时候一些列问题,那么本文就给大家把这几个问题一一道来,整合的流程是这样的,想完成单服SpringBoot集成Swagger3,然后再在网关成做一次聚合即可!
在pom文件中引入jar包

  • 每个微服务都需要使用,我们直接将其放在在cloud-common服务中

cloud-common-public

<version>3.0.0</version>

Swagger3整合
1.导入依赖
Swagger3这个版本的整合和Swagger2的整合是不一样的,首先引入的依赖就有变化,下面这个是常规Swagger3的导法
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>2.0.6</version>
</dependency>

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

spring-boot-configuration-processor说白了其实也就是为一个配置类定义一套规范,我们定义一个Properties类,用来映射配置文件,这里需要注意一下,需要使用一个配置文件处理器的依赖,如果不需要这个Properties类的话可以忽略 

  • 在微服务中编写swagger2的配置类SwaggerProperties
package com.liu.learn.handler;

import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * SwaggerProperties

 */
@Data
@Component
@ConfigurationProperties("swagger")
public class SwaggerProperties {

	/**
	 * 是否开启swagger
	 */
	private Boolean enabled = true;

	/**
	 * swagger会解析的包路径
	 **/
	private String basePackage = "";

	/**
	 * swagger会解析的url规则
	 **/
	private List<String> basePath = new ArrayList<>();

	/**
	 * 在basePath基础上需要排除的url规则
	 **/
	private List<String> excludePath = new ArrayList<>();

	/**
	 * 需要排除的服务
	 */
	private List<String> ignoreProviders = new ArrayList<>();

	/**
	 * 标题
	 **/
	private String title = "";

	/**
	 * 描述
	 **/
	private String description = "";

	/**
	 * 版本
	 **/
	private String version = "";

	/**
	 * 许可证
	 **/
	private String license = "";

	/**
	 * 许可证URL
	 **/
	private String licenseUrl = "";

	/**
	 * 服务条款URL
	 **/
	private String termsOfServiceUrl = "";

	/**
	 * host信息
	 **/
	private String host = "";

	/**
	 * 联系人信息
	 */
	private Contact contact = new Contact();

	/**
	 * 全局统一鉴权配置
	 **/
	private Authorization authorization = new Authorization();

	@Data
	@NoArgsConstructor
	public static class Contact {

		/**
		 * 联系人
		 **/
		private String name = "";

		/**
		 * 联系人url
		 **/
		private String url = "";

		/**
		 * 联系人email
		 **/
		private String email = "";

	}

	@Data
	@NoArgsConstructor
	public static class Authorization {

		/**
		 * 鉴权策略ID,需要和SecurityReferences ID保持一致
		 */
		private String name = "";

		/**
		 * 需要开启鉴权URL的正则
		 */
		private String authRegex = "^.*$";

		/**
		 * 鉴权作用域列表
		 */
		private List<AuthorizationScope> authorizationScopeList = new ArrayList<>();

		private List<String> tokenUrlList = new ArrayList<>();

	}

	@Data
	@NoArgsConstructor
	public static class AuthorizationScope {

		/**
		 * 作用域名称
		 */
		private String scope = "";

		/**
		 * 作用域描述
		 */
		private String description = "";

	}

}
SwaggerAutoConfig类

package com.liu.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.schema.ScalarType;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

@Slf4j
@Configuration
@EnableAutoConfiguration
@EnableOpenApi//开启swagger,当前版本为3 所以注解和2@EnableSwagger2的版本不同
//或者直接省略prefix,那么直接写为swagger.enabled,当配置中存在swagger.enabled生效,matchIfMissing = true默认生效
@ConditionalOnProperty(prefix = "swagger",name = "enabled", matchIfMissing = true)
public class SwaggerAutoConfig {

    //默认的排除路径,排除Spring Boot默认的错误处理路径和端点(在解析的url规则之上)  /*/error,由于服务通常加前缀,所以前面/*忽略前缀
    private static final List<String> DEFAULT_EXCLUDE_PATH = Arrays.asList("/error","/actuator/**","/*/error");

    //swagger会解析的url规则
    private static final String BASE_PATH = "/**";

    @Autowired
    private SwaggerProperties swaggerProperties;

    @Bean
    public Docket createRestApi() {

        // base-path处理
        if (swaggerProperties.getBasePath().isEmpty()) {
            swaggerProperties.getBasePath().add(BASE_PATH);
        }

        // exclude-path处理
        if (swaggerProperties.getExcludePath().isEmpty()) {
            swaggerProperties.getExcludePath().addAll(DEFAULT_EXCLUDE_PATH);
        }

        //需要排除的url
        List<Predicate<String>> excludePath = new ArrayList<>();
        swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path)));

        // 版本请求头处理
        List<RequestParameter> pars = new ArrayList<>();

        RequestParameterBuilder versionPar = new RequestParameterBuilder().description("灰度路由版本信息")
                .in(ParameterType.HEADER).name("VERSION").required(false)
                .query(param -> param.model(model -> model.scalarModel(ScalarType.STRING)));

        pars.add(versionPar.build());
        ApiSelectorBuilder builder = new Docket(DocumentationType.OAS_30)
                .host(swaggerProperties.getHost())
                .apiInfo(apiInfo()).globalRequestParameters(pars)
                .select()
                .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()));

        swaggerProperties.getBasePath().forEach(p -> builder.paths(PathSelectors.ant(p)));

        swaggerProperties.getExcludePath().forEach(p -> builder.paths(PathSelectors.ant(p).negate()));

        return builder.build().securitySchemes(Collections.singletonList(securitySchema()))
                .securityContexts(Collections.singletonList(securityContext())).pathMapping("/");

    }

    /**
     * 配置默认的全局鉴权策略的开关,通过正则表达式进行匹配;默认匹配所有URL
     * @return
     */
    private SecurityContext securityContext() {
        return SecurityContext.builder().securityReferences(defaultAuth()).build();
    }

    /**
     * 默认的全局鉴权策略
     * @return
     */
    private List<SecurityReference> defaultAuth() {
        ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
        swaggerProperties.getAuthorization().getAuthorizationScopeList()
                .forEach(authorizationScope -> authorizationScopeList.add(
                        new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[authorizationScopeList.size()];
        return Collections
                .singletonList(SecurityReference.builder().reference(swaggerProperties.getAuthorization().getName())
                        .scopes(authorizationScopeList.toArray(authorizationScopes)).build());
    }


    private OAuth securitySchema() {
        ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
        swaggerProperties.getAuthorization().getAuthorizationScopeList()
                .forEach(authorizationScope -> authorizationScopeList.add(
                        new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
        ArrayList<GrantType> grantTypes = new ArrayList<>();
        swaggerProperties.getAuthorization().getTokenUrlList()
                .forEach(tokenUrl -> grantTypes.add(new ResourceOwnerPasswordCredentialsGrant(tokenUrl)));
        return new OAuth(swaggerProperties.getAuthorization().getName(), authorizationScopeList, grantTypes);
    }


    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title(swaggerProperties.getTitle())
                .description(swaggerProperties.getDescription())
                .version(swaggerProperties.getVersion())
                .license(swaggerProperties.getLicense())
                .licenseUrl(swaggerProperties.getLicenseUrl())
                .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
                .contact(new Contact(
                        swaggerProperties.getContact().getName(),
                        swaggerProperties.getContact().getUrl(),
                        swaggerProperties.getContact().getEmail()
                ))
                .build();
    }

}

 

 

这两个类编写完后,那么Swagger3就已经整合完成了!那么我们现在用业务服务使用一下Swagger3,

其他服务使用Swagger3

 

order服务进行引用

<dependency>
    <groupId>com.liu.learn</groupId>
    <artifactId>cloud_common_public</artifactId>
</dependency>

 

在controller类上加上

@Api(value = "pay", tags = "支付")
public class PaymentController {然后启动服务

 

yml添加如下配置

swagger:
  title: payment-api
  description: "支付服务"
  version: 1.0
  license: "www"
  licenseUrl: http://baidu.com
  terms-of-service-url: http://baidu.com
  contact:
    name: liu
    email: 11111
    url: http://baidu.com
  authorization:
    name:  OAuth
    auth-regex: ^.*$
    authorization-scope-list:
      - scope: server
        description: server all
    token-url-list:
      - http://${GATEWAY_HOST:localhost}:${GATEWAY-PORT:5000}/auth/oauth/token

访问地址和swagger相比也发生了变化

ip:端口/swagger-ui/index.html

 

单个服务整合文档完毕了下面看gateway聚合文档

聚合文档

做聚合的前提是确保单服的Swagger能正常使用,然后才能做网关的聚合,因为这里做聚合就是在上面没问题的基础之上的!下面这些代码是写在网关服里的注意

 网关不能有web环境一定要注意

首先引入以下jar

<dependency>
     <!--swagger 整合好的依赖,就是开头整合好的swagger依赖-->
            <groupId>com.liu.learn</groupId>
            <artifactId>cloud_common_public</artifactId>
        </dependency>
        

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>

        <!--webflux 相关包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webflux</artifactId>
        </dependency>
        <!--网关 swagger 聚合依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-gateway-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
        </dependency>

编写Gateway和Swagger的配置 仅在webflux 环境生效



import com.liu.learn.handler.SwaggerResourceHandler;
import com.liu.learn.handler.SwaggerSecurityHandler;
import com.liu.learn.handler.SwaggerUiHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;

@Slf4j
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)//当Spring为web服务时,才使注解的类生效;通常是配置类;
public class GatewaySwaggerAutoConfiguration {

    @Autowired
    private SwaggerResourceHandler swaggerResourceHandler;

    @Autowired
    private SwaggerSecurityHandler swaggerSecurityHandler;

    @Autowired
    private SwaggerUiHandler swaggerUiHandler;

    /**
     * 路由映射,将Swagger相关URL映射到相应处理器上
     */
    @Bean
    public RouterFunction swaggerRouterFunction() {
        return RouterFunctions
                .route(RequestPredicates.GET("/swagger-resources")
                        .and(RequestPredicates.accept(MediaType.ALL)), swaggerResourceHandler)
                .andRoute(RequestPredicates.GET("/swagger-resources/configuration/ui")
                        .and(RequestPredicates.accept(MediaType.ALL)), swaggerUiHandler)
                .andRoute(RequestPredicates.GET("/swagger-resources/configuration/security")
                        .and(RequestPredicates.accept(MediaType.ALL)), swaggerSecurityHandler);
    }

}


加全限的配置: 

/**
 * 网关swagger 配置类,仅在webflux 环境生效哦
 *
 
 */
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class GatewaySwaggerAutoConfiguration {

	@Bean
	public SwaggerProvider swaggerProvider(SwaggerProperties swaggerProperties, GatewayProperties gatewayProperties) {
		return new SwaggerProvider(swaggerProperties, gatewayProperties);
	}

	@Bean
	public SwaggerResourceHandler swaggerResourceHandler(SwaggerProvider swaggerProvider) {
		return new SwaggerResourceHandler(swaggerProvider);
	}

	@Bean
	public WebFluxSwaggerConfiguration fluxSwaggerConfiguration() {
		return new WebFluxSwaggerConfiguration();
	}

	@Bean
	public SwaggerSecurityHandler swaggerSecurityHandler(
			ObjectProvider<SecurityConfiguration> securityConfigurationObjectProvider) {
		SecurityConfiguration securityConfiguration = securityConfigurationObjectProvider
				.getIfAvailable(() -> SecurityConfigurationBuilder.builder().build());
		return new SwaggerSecurityHandler(securityConfiguration);
	}

	@Bean
	public SwaggerUiHandler swaggerUiHandler(ObjectProvider<UiConfiguration> uiConfigurationObjectProvider) {
		UiConfiguration uiConfiguration = uiConfigurationObjectProvider
				.getIfAvailable(() -> UiConfigurationBuilder.builder().build());
		return new SwaggerUiHandler(uiConfiguration);
	}

	@Bean
	public RouterFunction<ServerResponse> swaggerRouterFunction(SwaggerProperties swaggerProperties,
			SwaggerUiHandler swaggerUiHandler, SwaggerSecurityHandler swaggerSecurityHandler,
			SwaggerResourceHandler swaggerResourceHandler) {
		// 开启swagger 匹配路由
		if (swaggerProperties.getEnabled()) {
			return RouterFunctions
					.route(RequestPredicates.GET("/swagger-resources").and(RequestPredicates.accept(MediaType.ALL)),
							swaggerResourceHandler)
					.andRoute(RequestPredicates.GET("/swagger-resources/configuration/ui")
							.and(RequestPredicates.accept(MediaType.ALL)), swaggerUiHandler)
					.andRoute(RequestPredicates.GET("/swagger-resources/configuration/security")
							.and(RequestPredicates.accept(MediaType.ALL)), swaggerSecurityHandler);
		}
		else {
			// 关闭时,返回404
			return RouterFunctions.route(
					RequestPredicates.GET("/swagger-ui/**").and(RequestPredicates.accept(MediaType.ALL)),
					serverRequest -> ServerResponse.notFound().build());
		}
	}

}

 

新建几个handler类

package com.liu.learn.handler;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

/**
 * @description: 提供Swagger3 获取注册中心的服务资源  http://localhost:5000/swagger-resources
 
 */
@Slf4j
@Component
public class SwaggerResourceHandler implements HandlerFunction<ServerResponse> {

    @Autowired
    private SwaggerResourcesProvider swaggerResources;

    @Override
    public Mono<ServerResponse> handle(ServerRequest request) {
        return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(swaggerResources.get()));
    }

}



package com.liu.learn.handler;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.SecurityConfigurationBuilder;

import java.util.Optional;

/**
 提供Swagger3 安全相关处理器
 */
@Slf4j
@Component
public class SwaggerSecurityHandler implements HandlerFunction<ServerResponse> {

	@Autowired(required = false)
	private SecurityConfiguration securityConfiguration;

	/**
	 * Handle the given request.
	 * @param request the request to handler
	 * @return the response
	 */
	@Override
	public Mono<ServerResponse> handle(ServerRequest request) {
		return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
				.body(BodyInserters.fromValue(Optional.ofNullable(securityConfiguration)
						.orElse(SecurityConfigurationBuilder.builder().build())));
	}

}
/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */

package com.liu.learn.handler;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;

import java.util.Optional;

/**
 * @description: 提供Swagger3 UI层配置数据  http://localhost:5000/swagger-resources/configuration/ui
 */
@Slf4j
@Component
public class SwaggerUiHandler implements HandlerFunction<ServerResponse> {

	@Autowired(required = false)
	private UiConfiguration uiConfiguration;

	/**
	 * Handle the given request.
	 * @param request the request to handler
	 * @return the response
	 */
	@Override
	public Mono<ServerResponse> handle(ServerRequest request) {
		return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(BodyInserters
				.fromValue(Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build())));
	}

}

编写SwaggerProvider

 

/**
 * @author Sywd 聚合接口文档注册,和zuul实现类似
 */
@Primary
@RequiredArgsConstructor
public class SwaggerProvider implements SwaggerResourcesProvider {

	private static final String API_URI = "/v2/api-docs";

	private final SwaggerProperties swaggerProperties;

	private final GatewayProperties gatewayProperties;

	@Lazy
	@Autowired
	private RouteLocator routeLocator;

	@Override
	public List<SwaggerResource> get() {
		List<SwaggerResource> resources = new ArrayList<>();
		List<String> routes = new ArrayList<>();
		routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
		gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId()))
				.forEach(routeDefinition -> routeDefinition.getPredicates().stream()
						.filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
						.filter(predicateDefinition -> !swaggerProperties.getIgnoreProviders()
								.contains(routeDefinition.getId()))
						.forEach(predicateDefinition -> resources
								.add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs()
										.get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", API_URI)))));
		return resources;
	}

	private static SwaggerResource swaggerResource(String name, String location) {
		SwaggerResource swaggerResource = new SwaggerResource();
		swaggerResource.setName(name);
		swaggerResource.setLocation(location);
		swaggerResource.setSwaggerVersion("2.0");
		return swaggerResource;
	}

}

 

配置文件yml

swagger:
  title: gateway
  description: "网关"
  version: 1.0
  license: "www"
  licenseUrl: http://baidu.com
  terms-of-service-url: http://baidu.com
  contact:
    name: liu
    email: 11111
    url: http://baidu.com
  authorization:
    name:  OAuth
    auth-regex: ^.*$
    authorization-scope-list:
      - scope: server
        description: server all
    token-url-list:
      - http://${GATEWAY_HOST:localhost}:${GATEWAY-PORT:5000}/auth/oauth/token


 

@

启动测试

filters:
  - StripPrefix=1

swagger3路由配置对这种过滤一部分不是太支持

 

 

.apis方法用于指定生成注解的范围,有以下四种取值逻辑
RequestHandlerSelectors.any(),为所有接口都生成API文档,这种方式不必在接口上加任何注解,但是生成的文档没有任何注释,可读性不高;
RequestHandlerSelectors.basePackage(xx.xx),为指定包下的controller生成接口文档
RequestHandlerSelectors.withClassAnnotation(Api.class),为有@api注解的接口生成api文档
RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class),为有@ApiOperation注解的方法生成API文档。

  • 给相关接口加上Swagger的注解例子

@RestController
@RequiredArgsConstructor
@RequestMapping("/dept")
@Api(value = "dept", tags = "部门管理模块")
public class DeptController {

	private final SysDeptService sysDeptService;

	/**
	 * 通过ID查询
	 * @param id ID
	 * @return SysDept
	 */
	@GetMapping("/{id}")
	public R getById(@PathVariable Integer id) {
		return R.ok(sysDeptService.getById(id));
	}

	/**
	 * 返回树形菜单集合
	 * @return 树形菜单
	 */
	@GetMapping(value = "/tree")
	public R listDeptTrees() {
		return R.ok(sysDeptService.listDeptTrees());
	}

	/**
	 * 返回当前用户树形菜单集合
	 * @return 树形菜单
	 */
	@GetMapping(value = "/user-tree")
	public R listCurrentUserDeptTrees() {
		return R.ok(sysDeptService.listCurrentUserDeptTrees());
	}

	/**
	 * 添加
	 * @param sysDept 实体
	 * @return success/false
	 */
	@SysLog("添加部门")
	@PostMapping
	@PreAuthorize("@pms.hasPermission('sys_dept_add')")
	public R save(@Valid @RequestBody SysDept sysDept) {
		return R.ok(sysDeptService.saveDept(sysDept));
	}

	/**
	 * 删除
	 * @param id ID
	 * @return success/false
	 */
	@SysLog("删除部门")
	@DeleteMapping("/{id}")
	@PreAuthorize("@pms.hasPermission('sys_dept_del')")
	public R removeById(@PathVariable Integer id) {
		return R.ok(sysDeptService.removeDeptById(id));
	}

	/**
	 * 编辑
	 * @param sysDept 实体
	 * @return success/false
	 */
	@SysLog("编辑部门")
	@PutMapping
	@PreAuthorize("@pms.hasPermission('sys_dept_edit')")
	public R update(@Valid @RequestBody SysDept sysDept) {
		sysDept.setUpdateTime(LocalDateTime.now());
		return R.ok(sysDeptService.updateDeptById(sysDept));
	}

	/**
	 * 根据部门名查询部门信息
	 * @param deptname 部门名
	 * @return
	 */
	@GetMapping("/details/{deptname}")
	public R user(@PathVariable String deptname) {
		SysDept condition = new SysDept();
		condition.setName(deptname);
		return R.ok(sysDeptService.getOne(new QueryWrapper<>(condition)));
	}

}
@Data
@EqualsAndHashCode(callSuper = true)
public class SysDept extends Model<SysDept> {

	private static final long serialVersionUID = 1L;

	@TableId(value = "dept_id", type = IdType.AUTO)
	@ApiModelProperty(value = "部门id")
	private Integer deptId;

	/**
	 * 部门名称
	 */
	@NotBlank(message = "部门名称不能为空")
	@ApiModelProperty(value = "部门名称")
	private String name;

	/**
	 * 排序
	 */
	@ApiModelProperty(value = "排序值")
	private Integer sort;

	/**
	 * 创建时间
	 */
	@ApiModelProperty(value = "创建时间")
	private LocalDateTime createTime;

	/**
	 * 修改时间
	 */
	@ApiModelProperty(value = "修改时间")
	private LocalDateTime updateTime;

	/**
	 * 父级部门id
	 */
	@ApiModelProperty(value = "父级部门id")
	private Integer parentId;

	/**
	 * 是否删除 -1:已删除 0:正常
	 */
	@TableLogic
	private String delFlag;

}

 

启动类

@

 

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值