秒懂SpringBoot之如何集成SpringDoc(全网目前最新最系统最全面的springdoc教程)

[版权申明] 非商业目的注明出处可自由转载
出自:shusheng007

概述

近来颇为懈怠,博客竟两月有余未发一篇,惭愧惭愧。值此端午佳节(dragon boat festival)作为调包高手、API小王子的我就聊聊API文档的那些事吧,如果你也是API小王子,那我们就可以在一起欢度佳节了,哈哈…

我惯用Java,惯用Spring,所以这里谈论的是关于springboot中如何处理文档的内容

概念解释

谈到API文档,那就绕不开大名鼎鼎的Swagger,但是你是否还听说过:OpenAPISpringfoxSpringdoc?你第一次看到这些脑瓜子是不是嗡嗡的?

是一个组织(OpenAPI Initiative),他们指定了一个如何描述HTTP API的规范(OpenAPI Specification)。既然是规范,那么谁想实现都可以,只要符合规范即可。

它是SmartBear这个公司的一个开源项目,里面提供了一系列工具,包括著名的 swagger-uiswagger是早于OpenApi的,某一天swagger将自己的API设计贡献给了OpenApi,然后由其标准化了。

是Spring生态的一个开源库,是Swagger与OpenApi规范的具体实现。我们使用它就可以在spring中生成API文档。以前基本上是行业标准,目前最新版本可以支持 Swagger2, Swagger3 以及 OpenAPI3 三种格式。但是其从 2020年7月14号就不再更新了,不支持springboot3,所以业界都在不断的转向我们今天要谈论的另一个库Springdoc,新项目就不要用了。

算是后起之秀,带着继任Springfox的使命而来。其支持OpenApi规范,支持Springboot3,我们的新项目都应该使用这个。

SpringDoc使用

我们可以在springboot中使用SpringDoc来生成API文档,详情可以参考官网,下面我们来简单的实践一下。

简单集成

在springboot中使用springdoc起步非常容易,只需要引入其starter即可

<dependency>
   <groupId>org.springdoc</groupId>
   <artifactId>springdoc-openapi-ui</artifactId>
   <version>1.7.0</version>
</dependency>

运行后访问下面的链接即可

http://server:port/context-path/swagger-ui.html 

例如

http://localhost:8080/swagger-ui.html 

例如我们有如下代码:

@RestController
@RequestMapping("/api/programmer")
public class ProgrammerController {
    @PostMapping()
    public Programmer createProgrammer(@RequestBody CreateProgrammerRequest request) {
        return new Programmer(1, request.getAge(), request.getProgrammingLang());
    }

    @GetMapping("/{id}")
    public Programmer getProgrammer(@PathVariable Integer id) {
        return new Programmer(1, 35, List.of("Java,Python,SQL"));
    }
}

添加依赖运行后访问http://localhost:8080/swagger-ui.html后结果如下

在这里插入图片描述

是不是特牛逼?当然springdoc的集成不可能就这点东西,不然也没有这篇文章了,咱接着往下看。苦于网上的一些教程不直观,对初学者不友好,所以本文以代码和其效果的形式来展示,保你一看就会。

配置文档信息

得益于springboot的强大,我们只需添加一个依赖就可以使用API文档了,但是使用的都是默认值,我们当然也希望对其进行各种自定义的配置

  • 配置文档信息

创建一个OpenAPI 的bean,配置文档名称等信息

@Configuration
public class SpringDocConfig {
    @Bean
    public OpenAPI myOpenAPI() {
        return new OpenAPI()
                .info(new Info()
                        .title("程序员API")
                        .description("程序员的大本营")
                        .version("v1.0.0")
                        .license(new License()
                                .name("许可协议")
                                .url("https://shusheng007.top"))
                        .contact(new Contact()
                                .name("书生007")
                                .email("wangben850115@gmail.com")))
                .externalDocs(new ExternalDocumentation()
                        .description("ShuSheng007博客")
                        .url("https://shusheng007.top"));
    }
 }

效果:

在这里插入图片描述
里面的配置项很多,可以根据代码和截图对照一下,按照自己的需求配置即可

配置文档分组

用来配置分组的,假如你有两类controller一类以/api为前缀,一类以/admin为前缀,就可以将其配置为两个分组。很多时候我们只有一个分组,所以就不需要下面的配置。

@Configuration
public class SpringDocConfig {
   ...
    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
                .group("api")
                .pathsToMatch("/api/**")
                .build();
    }

    @Bean
    public GroupedOpenApi adminApi() {
        return GroupedOpenApi.builder()
                .group("admin")
                .pathsToMatch("/admin/**")
                .build();
    }
}

效果:

在这里插入图片描述
可以通过右上角的下拉框选择要展示的group。

使用注解

这个是咱们的重头戏,OpenApi 规范提供了很多注解,下面是一些常用的

注解含义
@Tag用在controller类上,描述此controller的信息
@Operation用在controller的方法里,描述此api的信息
@Parameter用在controller方法里的参数上,描述参数信息
@Parameters用在controller方法里的参数上
@Schema用于Entity,以及Entity的属性上
@ApiResponse用在controller方法的返回值上
@ApiResponses用在controller方法的返回值上
@Hidden用在各种地方,用于隐藏其api

下面我们一起来看看效果

@Tag

@Tag(name = "程序员", description = "程序员乐园")
@RestController
@RequestMapping("/api/programmer")
public class ProgrammerController {
...
}

效果

在这里插入图片描述

@Operation

@Operation(summary = "创建程序员", description = "用于创建一个闷骚的程序员")
@PostMapping()
public Programmer createProgrammer(@RequestBody CreateProgrammerRequest request) {
    return new Programmer(666, "王二狗", request.getAge(), request.getProgrammingLang());
}

效果
在这里插入图片描述
@Operation 其实很复杂的,我们可以将下面要将的@Parameter以及@ApiResponse都可以配置在它里面。

@Schema

@Schema 用于实体类和其属性,例如有如下代码:

@Schema(description = "创建程序员入参")
public class CreateProgrammerRequest {

    @Schema(description = "名称", example = "王二狗")
    private String name;

    @Schema(description = "年龄", example = "35")
    private Integer age;

    @Schema(description = "掌握的编程语言", type = "List", example = "[\"Java\",\"Sql\"]")
    private List<String> programmingLang;
}

效果:

在这里插入图片描述
还可以切换到 Schema选项进行查看

在这里插入图片描述
同时,Springdoc还支持 Java Bean Validation API 的注解,例如@NotNull

@Schema(description = "创建程序员入参")
public class CreateProgrammerRequest {

    @NotNull
    @Schema(description = "名称", example = "王二狗")
    private String name;

    @NotNull
    @Min(18)
    @Max(35)
    @Schema(description = "年龄", example = "35")
    private Integer age;
  ...
}

效果:

在这里插入图片描述
注意红框中的内容,name和age右上角都有出现了一个红色的星星,表示是必填的。age也被限制了范围。

@Parameter

用于添加接口参数信息

@GetMapping("/{id}")
public Programmer getProgrammer(@Parameter(description = "程序员id") @PathVariable Integer id) {
    ...
}

效果

在这里插入图片描述

@Parameters

@Parameter作用一样,但是可以批量添加,不用一个一个的写在参数前面

@Parameters(value = {
        @Parameter(name = "name", description = "姓名", in = ParameterIn.PATH),
        @Parameter(name = "age", description = "年龄", in = ParameterIn.QUERY)
})
@GetMapping("/{name}")
public List<Programmer> getProgrammers(@PathVariable("name") String name, @RequestParam("age") Integer age) { 
    ...
}

parameters里的parameter使用name来找到方法中的入参,这块要对应上。

效果:

在这里插入图片描述

@ApiResponses@ApiResponse

顾名思义,此注解用来描述返回值的。

    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功",
                    content = {@Content(mediaType = "application/json",
                            schema = @Schema(implementation = Programmer.class))}),
            @ApiResponse(responseCode = "405", description = "非法输入",
                    content = @Content)
    })
    @PostMapping()
    public Programmer createProgrammer(@RequestBody CreateProgrammerRequest request) {
       ...
    }

效果

在这里插入图片描述
可见,我们成功配置了两种情况的返回值。但是我们一般不会手动给每个API 写上一堆 @ApiResponse,那的多烦啊。业界通常会有一个统一的返回类型,例如

public class Result<T> implements Serializable {
    private int code;
    private String message;
    private T data;
    private String traceId;
}

还会有一个统一的异常处理类,使用@RestControllerAdvice标记,然后每个方法会捕捉对应的异常,只要我们使用@ResponseStatus来标记这些方法,springdoc就会自动生成相应的文档

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result handleException(HttpServletRequest httpServletRequest, Exception e) {
        return new Result(StatusCode.FAILED.getCode(), StatusCode.FAILED.getMessage(), null);
    }

    @ExceptionHandler(value = ApiException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result handleBusinessException(HttpServletRequest httpServletRequest, ApiException e) {
        return new Result(e.getCode(), e.getMessage(), null);
    }
}

例如我们有如下代码:

...
@RequestMapping(value = "/api/programmer",produces =  "application/json")
public class ProgrammerController {

    @GetMapping("/{id}")
    public Result<Programmer> getProgrammer(@Parameter(description = "程序员id") @PathVariable Integer id) {
        ...
    }
}

生成的api文档如下:

在这里插入图片描述
可见,多了400和500。

认证授权

我们知道swagger-ui不仅可以看API文档也可以直接调用API,这点很牛逼。但有时我们的服务需要认证,否则就调用不通,那怎么办?稍安勿躁,OpenApi规范也考虑到了这个问题。

OpenAPI 3.0 支持下面的认证模式:

  • HTTP authentication schemes (使用Authorization header):
    • Basic
    • Bearer
    • Other HTTP schemes as defined by RFC 7235 and HTTP Authentication Scheme Registry
  • API keys in headers, query string or cookies
    • Cookie authentication
  • OAuth 2
  • OpenID Connect Discovery

有的我也没用过,我们常用的就是Http Auth,以及OAuth2。本文以HTTP Bearer来作为我们服务的认证授权模式,如下图所示。

在这里插入图片描述

无需认证

当你的服务没有认证机制的话是可以直接调用的:

每个API 右上角都有一个try it out按钮,点击输入参数点击execute按钮即可,如下所示。

在这里插入图片描述

需要认证

如果你的服务需要认证后才能调用,那么默认情况下就不行了。例如你使用了Spring Security,或者你自己写了个Filter 来实现认证功能。

下面是demo服务用来做认证的Filter,采用HTTP Bearer 模式。所以需要在请求的Authentication Header 里 携带token 123才能通过认证。

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
   ...
    @Override
    protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
    ...

        // get token from header [Authorization: Bearer <token>]
        String authHeader = request.getHeader(AUTH_HEADER);
        ...

        String authToken = authHeader.split(" ")[1];
        if (!"123".equals(authToken)) {
            genUnauthResponse(response);
            return;
        }
        filterChain.doFilter(request, response);
    }

所以当从swagger-ui上调用API时,返回了401,如下图所示。那怎么才能正常调用API呢?接下来让我们看一下

在这里插入图片描述
Springdoc 使用@SecurityScheme 来定义一个安全模式,我们可以定义全局的,也可以针对某个controller定义类级别的,我们这里定义一个全局的。

  1. 在Application类上添加@SecurityScheme
@SecurityScheme(name = "api_token", type = SecuritySchemeType.HTTP, scheme ="bearer", in = SecuritySchemeIn.HEADER)
@SpringBootApplication
public class SpringdocIntegrateApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringdocIntegrateApplication.class, args);
    }
}

我们定义了一个名为api_token的安全模式,并指定了其使用HTTP Bearer的方式。

  1. 使此安全模式生效
@Configuration
public class SpringDocConfig {
    @Bean
    public OpenAPI myOpenAPI() {
        return new OpenAPI()
                 ...
                .security(List.of(new SecurityRequirement().addList("api_token")));
    }
}

注意api_token正是我们第一步定义的那个Security schema。

经过上面两步后查看生成的API文档,你会发现其右上角出现了一个Authorize的按钮, 而且每个API的右边也出现了一把小锁,如下图所示。
在这里插入图片描述

当点击Authorize按钮后会弹出一个让你提供认证信息的弹出,其根据不同的认证方式会有所区别。

在这里插入图片描述
我们这里需要输入一个token,然后点击Authorize按钮后关闭此弹窗。你会发现每个API右边的那把小锁从打开状态变为了关闭状态,颜色也从灰色变成了黑色,证明其生效了。

然后我们再来请求一下API,就会正常返回了。

  1. 声明是否需要认证

默认情况下按照上面两步设置后,整个应用程序的API生效,但是有的API是不需要认证的,例如登录。
对于这种情况,我们可以使用@SecurityRequirements()来设置。

@RestController
@RequestMapping(value = "/admin",produces =  "application/json")
public class AuthController {
    ...
    @SecurityRequirements()
    @PostMapping("/login")
    public Result<String> login(@RequestBody LoginRequest request){
        return Result.ok("123");
    }
}

@SecurityRequirements() 里面需要一个String数组,里面列出需要使用的@SecurityScheme,例如我们这里的api_token。如果不写就说明不需要任何的安全模式,这里就是这种情况。

在这里插入图片描述
从上图可以看出,/admin/login这个API右边没有小锁的标志,表示其不需要认证。针对本案例来说,不需要认证的意思就是:在发起这个请求的时候,不在Authentication header里面附加token。

这里只是展示了HTTP bearer 这种安全模式,其他的原理类似,小朋友们可以开动你们聪明的大脑研究一下,给补充到这里。

总结

终于写完了,要写一篇逻辑清晰,对初学者友好的博客可真不容易。当然我写博客主要是为了自己梳理知识,但是我一直秉承着解决自己初次接触时候的困难场景来写的,相信对其他小朋友会有很大的帮助。

本文只是对Springdoc常用功能做了介绍,更个性化的功能还是要去看 Springdoc官网

最后,这么好的文章不给点个赞你还是那个无私奉献,互帮互助,开源博爱的IT人吗?

此情此景我想诵诗一首:

        端阳采撷
         
玉粽袭香千舸竞,艾叶黄酒可驱邪。
骑父稚子香囊佩,粉俏媳妇把景撷。

祝小朋友们端午节快乐!

源码

一如既往,你可以点击文章首发后,文末找到本文源码。

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShuSheng007

亲爱的猿猿,难道你又要白嫖?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值