导读:在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;
}
启动类
@