A biblioteca Swagger fornecida pelo SpringFox já foi usada no projeto SpringBoot. Fui ao site oficial e descobri que não há uma nova versão há quase dois anos! Eu atualizei a versão SpringBoot 2.6.x alguns dias atrás , e descobri que a compatibilidade desta biblioteca está cada vez pior.Alguns atributos de anotação comuns foram abandonados e nenhuma substituição é fornecida! Encontrei outra biblioteca Swagger por acaso
SpringDoc
, e foi muito bom experimentá-la, recomendo a todos!
Endereço real do projeto de e-commerce SpringBoot (50k + estrelas): github.com/macrozheng/…
Introdução ao SpringDoc
SpringDoc é uma ferramenta de geração de documentos da API que pode ser usada em conjunto com SpringBoot. Com base OpenAPI 3
nele, está atualmente disponível no Github. 1.7K+Star
É bastante diligente para atualizar e liberar a versão, e é uma biblioteca Swagger melhor! Vale ressaltar que SpringDoc não só suporta projetos Spring WebMvc, mas também projetos Spring WebFlux, e até mesmo projetos Spring Rest e Spring Native, enfim, é muito poderoso, segue um diagrama de arquitetura do SpringDoc.
usar
A seguir, vamos apresentar o uso do SpringDoc, usando o
mall-tiny-swagger
projeto que antes integrava o SpringFox, vou transformá-lo para usar o SpringDoc.
integrado
Em primeiro lugar, temos que integrar o SpringDoc e
pom.xml
adicionar suas dependências a ele. Ele funciona fora da caixa sem nenhuma configuração.
<!--springdoc 官方Starter-->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.6</version>
</dependency>
复制代码
Migrando do SpringFox
- Vamos primeiro dar uma olhada nas anotações Swagger usadas com frequência para ver a diferença entre SpringFox e SpringDoc. Afinal, devemos dominar novas tecnologias rapidamente comparando as tecnologias que aprendemos;
SpringFox | SpringDocName |
---|---|
@Api | @Marcação |
@ApiIgnore | @Parameter(hidden = true)or @Operation(hidden = true)or @Hidden |
@ApiImplicitParam | @Parameter |
@ApiImplicitParams | @Parameters |
@ApiModel | @Schema |
@ApiModelProperty | @Schema |
@ApiOperation(value = "foo", notes = "bar") | @Operation(summary = "foo", description = "bar") |
@ApiParam | @Parameter |
@ApiResponse(code = 404, message = "foo") | ApiResponse(responseCode = "404", description = "foo") |
- 接下来我们对之前Controller中使用的注解进行改造,对照上表即可,之前在
@Api
注解中被废弃了好久又没有替代的description
属性终于被支持了!
/**
* 品牌管理Controller
* Created by macro on 2019/4/19.
*/
@Tag(name = "PmsBrandController", description = "商品品牌管理")
@Controller
@RequestMapping("/brand")
public class PmsBrandController {
@Autowired
private PmsBrandService brandService;
private static final Logger LOGGER = LoggerFactory.getLogger(PmsBrandController.class);
@Operation(summary = "获取所有品牌列表",description = "需要登录后访问")
@RequestMapping(value = "listAll", method = RequestMethod.GET)
@ResponseBody
public CommonResult<List<PmsBrand>> getBrandList() {
return CommonResult.success(brandService.listAllBrand());
}
@Operation(summary = "添加品牌")
@RequestMapping(value = "/create", method = RequestMethod.POST)
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public CommonResult createBrand(@RequestBody PmsBrand pmsBrand) {
CommonResult commonResult;
int count = brandService.createBrand(pmsBrand);
if (count == 1) {
commonResult = CommonResult.success(pmsBrand);
LOGGER.debug("createBrand success:{}", pmsBrand);
} else {
commonResult = CommonResult.failed("操作失败");
LOGGER.debug("createBrand failed:{}", pmsBrand);
}
return commonResult;
}
@Operation(summary = "更新指定id品牌信息")
@RequestMapping(value = "/update/{id}", method = RequestMethod.POST)
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public CommonResult updateBrand(@PathVariable("id") Long id, @RequestBody PmsBrand pmsBrandDto, BindingResult result) {
CommonResult commonResult;
int count = brandService.updateBrand(id, pmsBrandDto);
if (count == 1) {
commonResult = CommonResult.success(pmsBrandDto);
LOGGER.debug("updateBrand success:{}", pmsBrandDto);
} else {
commonResult = CommonResult.failed("操作失败");
LOGGER.debug("updateBrand failed:{}", pmsBrandDto);
}
return commonResult;
}
@Operation(summary = "删除指定id的品牌")
@RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public CommonResult deleteBrand(@PathVariable("id") Long id) {
int count = brandService.deleteBrand(id);
if (count == 1) {
LOGGER.debug("deleteBrand success :id={}", id);
return CommonResult.success(null);
} else {
LOGGER.debug("deleteBrand failed :id={}", id);
return CommonResult.failed("操作失败");
}
}
@Operation(summary = "分页查询品牌列表")
@RequestMapping(value = "/list", method = RequestMethod.GET)
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public CommonResult<CommonPage<PmsBrand>> listBrand(@RequestParam(value = "pageNum", defaultValue = "1")
@Parameter(description = "页码") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "3")
@Parameter(description = "每页数量") Integer pageSize) {
List<PmsBrand> brandList = brandService.listBrand(pageNum, pageSize);
return CommonResult.success(CommonPage.restPage(brandList));
}
@Operation(summary = "获取指定id的品牌详情")
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public CommonResult<PmsBrand> brand(@PathVariable("id") Long id) {
return CommonResult.success(brandService.getBrand(id));
}
}
复制代码
- 接下来进行SpringDoc的配置,使用
OpenAPI
来配置基础的文档信息,通过GroupedOpenApi
配置分组的API文档,SpringDoc支持直接使用接口路径进行配置。
/**
* SpringDoc API文档相关配置
* Created by macro on 2022/3/4.
*/
@Configuration
public class SpringDocConfig {
@Bean
public OpenAPI mallTinyOpenAPI() {
return new OpenAPI()
.info(new Info().title("Mall-Tiny API")
.description("SpringDoc API 演示")
.version("v1.0.0")
.license(new License().name("Apache 2.0").url("https://github.com/macrozheng/mall-learning")))
.externalDocs(new ExternalDocumentation()
.description("SpringBoot实战电商项目mall(50K+Star)全套文档")
.url("http://www.macrozheng.com"));
}
@Bean
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.group("brand")
.pathsToMatch("/brand/**")
.build();
}
@Bean
public GroupedOpenApi adminApi() {
return GroupedOpenApi.builder()
.group("admin")
.pathsToMatch("/admin/**")
.build();
}
}
复制代码
结合SpringSecurity使用
- 由于我们的项目集成了SpringSecurity,需要通过JWT认证头进行访问,我们还需配置好SpringDoc的白名单路径,主要是Swagger的资源路径;
/**
* SpringSecurity的配置
* Created by macro on 2018/4/26.
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf()// 由于使用的是JWT,我们这里不需要csrf
.disable()
.sessionManagement()// 基于token,所以不需要session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, // Swagger的资源路径需要允许访问
"/",
"/swagger-ui.html",
"/swagger-ui/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/swagger-resources/**",
"/v3/api-docs/**"
)
.permitAll()
.antMatchers("/admin/login")// 对登录注册要允许匿名访问
.permitAll()
.antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求
.permitAll()
.anyRequest()// 除上面外的所有请求全部需要鉴权认证
.authenticated();
}
}
复制代码
- 然后在
OpenAPI
对象中通过addSecurityItem
方法和SecurityScheme
对象,启用基于JWT的认证功能。
/**
* SpringDoc API文档相关配置
* Created by macro on 2022/3/4.
*/
@Configuration
public class SpringDocConfig {
private static final String SECURITY_SCHEME_NAME = "BearerAuth";
@Bean
public OpenAPI mallTinyOpenAPI() {
return new OpenAPI()
.info(new Info().title("Mall-Tiny API")
.description("SpringDoc API 演示")
.version("v1.0.0")
.license(new License().name("Apache 2.0").url("https://github.com/macrozheng/mall-learning")))
.externalDocs(new ExternalDocumentation()
.description("SpringBoot实战电商项目mall(50K+Star)全套文档")
.url("http://www.macrozheng.com"))
.addSecurityItem(new SecurityRequirement().addList(SECURITY_SCHEME_NAME))
.components(new Components()
.addSecuritySchemes(SECURITY_SCHEME_NAME,
new SecurityScheme()
.name(SECURITY_SCHEME_NAME)
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")));
}
}
复制代码
测试
- Em seguida, inicie o projeto e você poderá acessar a interface Swagger. Endereço de acesso: http://localhost:8088/swagger-ui.html
- Nós primeiro efetuamos login através da interface de login e podemos descobrir que esta versão do Swagger retorna resultados que suportam realce, e a versão é obviamente mais recente que SpringFox;
- Em seguida, insira as informações de cabeçalho de autenticação obtidas através do botão de autenticação, observe que nenhum
bearer
prefixo é necessário aqui;
- Depois disso, podemos acessar a interface que requer autenticação de login;
- Dê uma olhada na documentação dos parâmetros de solicitação, o familiar estilo Swagger!
Colocação regular
SpringDoc também tem algumas configurações comuns que você pode aprender.Para mais configurações, você pode consultar a documentação oficial.
springdoc:
swagger-ui:
# 修改Swagger UI路径
path: /swagger-ui.html
# 开启Swagger UI界面
enabled: true
api-docs:
# 修改api-docs路径
path: /v3/api-docs
# 开启api-docs
enabled: true
# 配置需要生成接口文档的扫描包
packages-to-scan: com.macro.mall.tiny.controller
# 配置需要生成接口文档的接口路径
paths-to-match: /brand/**,/admin/**
复制代码
Resumir
Caso a biblioteca Swagger do SpringFox não seja lançada há muito tempo, migrar para o SpringDoc é realmente uma escolha melhor. Experimentei um SpringDoc hoje. É realmente fácil de usar. É semelhante ao uso familiar antes, e o custo de aprendizado é extremamente baixo. Além disso, SpringDoc pode suportar projetos como WebFlux, e suas funções são mais poderosas. Amigos que estão um pouco presos ao SpringFox podem migrar para ele e experimentar!
Se você quiser saber mais habilidades de combate do SpringBoot, experimente este projeto prático com um conjunto completo de tutoriais (50K+Star): github.com/macrozheng/…
Referências
- Endereço do projeto: github.com/springdoc/s…
- Documentação oficial: springdoc.org/