用Spring Doc代替Swagger

52 篇文章 4 订阅
33 篇文章 3 订阅

1 OpenApi

OpenApi 是一个业界的 API 文档标准,是一个规范,这个规范目前有两大实现,分别是:

  • SpringFox
  • SpringDoc

其中 SpringFox 其实也就是我们之前所说的 Swagger,SpringDoc 则是我们今天要说的内容。

OpenApi 就像 JDBC 一样,制定了各种各样的规范,而 Swagger 和 SpringDoc 则类似于各种各样的数据库驱动,是具体的实现。

所以可能很多小伙伴也发现了,Swagger 和 Spring Doc 有一些相似的地方,这就是因为他们都遵守了相同的规范。

不过呢,Swagger 更新有点慢吞吞的,为了能够和新版的 Spring Boot 整合,还是 SpringDoc 更值得体验一把。

SpringDoc 支持:

  • OpenAPI 3
  • Spring-boot,全版本都支持。
  • JSR-303 中提供的一些注解,例如 @NotNull、@Min、@Max 以及 @Size 等。
  • Swagger-ui:SpringDoc 提供的接口 JSON 也可以通过 Swagger-ui 展示出来。
  • OAuth 2

2 引入 SpringDoc

小伙伴们知道,这种生成接口文档的工具,一般来说都是两方面的功能:

  • 生成接口文档 JSON
  • 渲染接口文档 JSON

所以,当我们使用 SpringDoc 的时候,如果只是想要生成接口文档 JSON,那么只需要添加如下依赖即可:

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-webmvc-core</artifactId>
    <version>1.6.9</version>
</dependency>

此时,就会针对项目中的接口自动生成接口的 JSON 文档,类似下面这样:
在这里插入图片描述

这样的 JSON 信息开发者可以自行将之绘制出来,也可以使用网上一些现成的工具例如 Knife4j 之类的。当然你要是不想费事,也可以使用 SwaggerUI 将之绘制出来,如果想使用网页,那么就不要使用上面的依赖,用下面这个依赖,不仅可以生成 JSON 接口,还可以生成渲染后的网页:

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

网页效果如下图:

在这里插入图片描述

这个网页看着眼熟,其实就是 Swagger UI。

这个网页上有一个输入框,输入的内容是 /v3/api-docs,这个地址就是这个网页想要渲染的 JSON 的地址,如果开发者修改了生成的 JSON API 文档的地址,那么就需要手动在这个输入框中输入一下 JSON API 文档的地址。

默认的 JSON API 文档地址是:

  • /v3/api-docs

默认的网页 UI 地址是:

  • /swagger-ui/index.html

如果需要配置,则可以在 Spring Boot 的 application.properties 中直接进行配置:

springdoc.swagger-ui.path=/javaboy-ui
springdoc.api-docs.path=/javaboy-api

不过这两个配置并不是真的修改了访问路径,这两个相当于给访问路径取了一个别名,访问这两个时会自动重定向到对应的路径上。

3 结合 Spring Security

如果我们的项目中使用了 Spring Security,那么部分接口的参数可能会比较特殊,例如下面这个接口:

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(@AuthenticationPrincipal User user) {
        System.out.println("user = " + user);
        return "hello";
    }
}

这个接口的参数加上了一个 @AuthenticationPrincipal 注解表示当前登录成功的用户对象,这个参数在实际使用中,并不需要前端传递,服务端会自动注入该参数。

但是!如果使用了 SpringDoc,通过网页去调用这个接口的时候,这个参数就必须要要传递,对于这种问题,我们可以引入如下依赖自动帮我们解决:

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-security</artifactId>
    <version>1.6.9</version>
</dependency>

这个依赖会自动帮我们忽略掉接口中带有 @AuthenticationPrincipal 注解的参数,这样我们在通过 swagger-ui 去进行接口测试的时候就不需要传递这个参数了。

4 结合 Spring Data Rest

Spring Boot 中提供了 Spring Data Rest,结合 Jpa 可以非常方便的构建出 Restful 应用。但是这种 Restful 应用不需要开发者自己写接口,那么怎么生成接口文档呢(连接口在哪里都不知道)?针对于此,SpringDoc 也提供了相关的支持,我们一起来看下。

4.1 Spring Data Rest

4.1.1 创建工程

首先创建一个 Spring Boot 工程,引入 Web 、 Jpa 、 MySQL 、Rest Repositories 依赖:
在这里插入图片描述

4.1.2 配置数据库

主要配置两个,一个是数据库,另一个是 Jpa:

spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.url=jdbc:mysql:///test02?serverTimezone=Asia/Shanghai

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.database-platform=mysql
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect

这里的配置,和 Jpa 中的基本一致。

前面三行配置了数据库的基本信息,包括数据库连接池、数据库用户名、数据库密码、数据库连接地址以及数据库驱动名称。

接下来的五行配置了 JPA 的基本信息,分别表示生成 SQL 的方言、打印出生成的 SQL 、每次启动项目时根据实际情况选择是否更新表、数据库平台是 MySQL。

4.1.3 构建实体类和持久层类

@Entity(name = "t_book")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "book_name")
    private String name;
    private String author;
    //省略 getter/setter
}

public interface BookRepository extends JpaRepository<Book,Long> {
}

这里一个是配置了一个实体类 Book,另一个则是配置了一个 BookRepository ,项目启动成功后,框架会根据 Book 类的定义,在数据库中自动创建相应的表,BookRepository 接口则是继承自 JpaRepository ,JpaRepository 中自带了一些基本的增删改查方法。

好了,代码写完了。

啥?你好像啥都没写啊?是的,啥都没写,啥都不用写,一个 RESTful 风格的增删改查应用就有了,这就是 Spring Boot 的魅力!

4.1.4 测试

此时,我们就可以启动项目进行测试了,使用 POSTMAN 来测试(大家也可以自行选择趁手的 HTTP 请求工具)。

此时我们的项目已经默认具备了一些接口,我们分别来看:

4.1.5 根据 id 查询接口

url : http://127.0.0.1:8080/books/{id}

这个接口表示根据 id 查询某一本书:

在这里插入图片描述

4.1.6 分页查询

url : http://127.0.0.1:8080/books

这是一个批量查询接口,默认请求路径是类名首字母小写,并且再加一个 s 后缀。这个接口实际上是一个分页查询接口,没有传参数,表示查询第一页,每页 20 条数据。

在这里插入图片描述
查询结果中,除了该有的数据之外,也包含了分页数据:
在这里插入图片描述
分页数据中:

  1. size 表示每页查询记录数
  2. totalElements 表示总记录数
  3. totalPages 表示总页数
  4. number 表示当前页数,从0开始计

如果要分页或者排序查询,可以使用 _links 中的链接。http://127.0.0.1:8080/books?page=1&size=3&sort=id,desc 。
在这里插入图片描述

4.1.7 添加

也可以添加数据,添加是 POST 请求,数据通过 JSON 的形式传递,如下:

在这里插入图片描述
添加成功之后,默认会返回添加成功的数据。

4.1.8 修改

修改接口默认也是存在的,数据修改请求是一个 PUT 请求,修改的参数也是通过 JSON 的形式传递:
在这里插入图片描述
默认情况下,修改成功后,会返回修改成功的数据。

4.1.9 删除

当然也可以通过 DELETE 请求根据 id 删除数据:

在这里插入图片描述
删除成功后,是没有返回值的。

不需要几行代码,一个基本的增删改查就有了。

这些都是默认的配置,这些默认的配置实际上都是在 JpaRepository 的基础上实现的,实际项目中,我们还可以对这些功能进行定制。

4.1.10 查询定制

最广泛的定制,就是查询,因为增删改操作的变化不像查询这么丰富。对于查询的定制,非常容易,只需要提供相关的方法即可。例如根据作者查询书籍:

public interface BookRepository extends JpaRepository<Book,Long> {
    List<Book> findBookByAuthorContaining(@Param("author") String author);
}

注意,方法的定义,参数要有 @Param 注解。

定制完成后,重启项目,此时就多了一个查询接口,开发者可以通过 http://localhost:8080/books/search 来查看和 book 相关的自定义接口都有哪些:
在这里插入图片描述
查询结果表示,只有一个自定义接口,接口名就是方法名,而且查询结果还给出了接口调用的示例。我们来尝试调用一下自己定义的查询接口:
在这里插入图片描述
开发者可以根据实际情况,在 BookRepository 中定义任意多个查询方法,查询方法的定义规则和 Jpa 中一模一样。但是,这样有一个缺陷,就是 Jpa 中方法名太长,因此,如果不想使用方法名作为接口名,则可以自定义接口名:

public interface BookRepository extends JpaRepository<Book, Long> {
    @RestResource(rel = "byauthor",path = "byauthor")
    List<Book> findBookByAuthorContaining(@Param("author") String author);
}

@RestResource 注解中,两个参数的含义:

  • rel 表示接口查询中,这个方法的 key
  • path 表示请求路径

这样定义完成后,表示接口名为 byauthor ,重启项目,继续查询接口:
在这里插入图片描述
除了 rel 和 path 两个属性之外,@RestResource 中还有一个属性,exported 表示是否暴露接口,默认为 true ,表示暴露接口,即方法可以在前端调用,如果仅仅只是想定义一个方法,不需要在前端调用这个方法,可以设置 exported 属性为 false 。

如果不想暴露官方定义好的方法,例如根据 id 删除数据,只需要在自定义接口中重写该方法,然后在该方法上加 @RestResource 注解并且配置相关属性即可。

public interface BookRepository extends JpaRepository<Book, Long> {
    @RestResource(rel = "byauthor",path = "byauthor")
    List<Book> findBookByAuthorContaining(@Param("author") String author);
    @Override
    @RestResource(exported = false)
    void deleteById(Long aLong);
}

另外生成的 JSON 字符串中的集合名和单个 item 的名字都是可以自定义的:

@RepositoryRestResource(collectionResourceRel = "bs",itemResourceRel = "b",path = "bs")
public interface BookRepository extends JpaRepository<Book, Long> {
    @RestResource(rel = "byauthor",path = "byauthor")
    List<Book> findBookByAuthorContaining(@Param("author") String author);
    @Override
    @RestResource(exported = false)
    void deleteById(Long aLong);
}

path 属性表示请求路径,请求路径默认是类名首字母小写+s,可以在这里自己重新定义。

4.1.11 其他配置

最后,也可以在 application.properties 中配置 REST 基本参数:

spring.data.rest.base-path=/api
spring.data.rest.sort-param-name=sort
spring.data.rest.page-param-name=page
spring.data.rest.limit-param-name=size
spring.data.rest.max-page-size=20
spring.data.rest.default-page-size=0
spring.data.rest.return-body-on-update=true
spring.data.rest.return-body-on-create=true

配置含义,从上往下,依次是:

  1. 给所有的接口添加统一的前缀
  2. 配置排序参数的 key ,默认是 sort
  3. 配置分页查询时页码的 key,默认是 page
  4. 配置分页查询时每页查询页数的 key,默认是size
  5. 配置每页最大查询记录数,默认是 20 条
  6. 分页查询时默认的页码
  7. 更新成功时是否返回更新记录
  8. 添加成功时是否返回添加记录

这是 Spring Data Rest 的一个简单用法,接下来我们来看如何给这个生成的文档。

4.2 生成接口文档

对于这种你都没看到接口的,我们只需要添加如下依赖,就可以自动生成 API 文档了,如下:

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-data-rest</artifactId>
    <version>1.6.9</version>
</dependency>
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.6.9</version>
</dependency>

生成的接口文档如下:
在这里插入图片描述

5 结合 Actuator

在之前的 Spring Boot 教程中,松哥还和大家介绍过 Spring Boot 中的 actuator,这个工具可以自行生成项目运行数据的端点(endpoints),如果想把这些端点也纳入到 SpringDoc 中来,那么只需要添加如下配置即可:

springdoc.show-actuator=true

至于 SpringDoc 会显示多少个 Actuator 端点出来,那就要看 Actuator 暴露出来多少端点了,最终显示效果如下:
在这里插入图片描述
不过这里还有一个玩法!

SpringDoc 扮演的角色毕竟不是业务功能,而是项目的辅助功能,所以,我们可以将之从业务中剥离,放到 Actuator 中,毕竟 Actuator 专干这种事。那么只需要增加如下两个配置即可:

springdoc.use-management-port=true
management.endpoints.web.exposure.include=openapi, swagger-ui
management.server.port=9090

配置完成后,将来就可以在 Actuator 中去查看接口文档和对应的页面了,访问地址是:

  • http://localhost:9090/actuator/swagger-ui/index.html
    在这里插入图片描述
    如果你在项目中已经使用了 Swagger 了,那么也可以非常方便的切换到 SpringDoc 上面来,切换的时候,首先引入 SpringDoc 依赖:
<dependency>
   <groupId>org.springdoc</groupId>
   <artifactId>springdoc-openapi-ui</artifactId>
   <version>1.6.9</version>
</dependency>

Swagger 和 SpringDoc 注解的对应关系如下:

  • @Api → @Tag
  • @ApiIgnore → @Parameter(hidden = true) or @Operation(hidden = true)
    or @Hidden
  • @ApiImplicitParam → @Parameter
  • @ApiImplicitParams → @Parameters
  • @ApiModel → @Schema
  • @ApiModelProperty(hidden = true) → @Schema(accessMode = READ_ONLY)
  • @ApiModelProperty → @Schema
  • @ApiOperation(value = “foo”, notes = “bar”) → @Operation(summary =
    “foo”, description = “bar”)
  • @ApiParam → @Parameter
  • @ApiResponse(code = 404, message = “foo”) → @ApiResponse(responseCode
    = “404”, description = “foo”)

以前我们在 Swagger 中配置接口扫描的方式如下:

@Bean
public Docket publicApi() {
    return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.public"))
            .paths(PathSelectors.regex("/public.*"))
            .build()
            .groupName("springshop-public")
            .apiInfo(apiInfo());
}

@Bean
public Docket adminApi() {
    return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.admin"))
            .paths(PathSelectors.regex("/admin.*"))
            .apis(RequestHandlerSelectors.withMethodAnnotation(Admin.class))
            .build()
            .groupName("springshop-admin")
            .apiInfo(apiInfo());
}

现在在 SpringDoc 中则按照如下方式进行配置即可(还可以按照注解去标记需要生成接口文档的方法):

@Configuration
public class SpringDocConfig {
    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
                .group("springshop-public")
                .pathsToMatch("/public/**")
                .build();
    }
    @Bean
    public GroupedOpenApi adminApi() {
        return GroupedOpenApi.builder()
                .group("springshop-admin")
                .pathsToMatch("/admin/**")
                .addOpenApiMethodFilter(method -> method.isAnnotationPresent(RequestMapping.class))
                .build();
    }
}

当然,如果你并不需要对接口文档进行分组,那么也可以不使用 Java 配置,直接在 application.properties 中进行配置即可:

springdoc.packages-to-scan=org.javaboy.spring_doc.controller
springdoc.paths-to-match=/**

在 SpringDoc 中,如果你想配置 Swagger UI,则可以通过如下方式进行配置:

@Bean
OpenAPI springShopOpenAPI() {
    return new OpenAPI()
            .info(new Info().title("江南一点雨")
                    .description("Spring Boot 教程")
                    .version("v0.0.1")
                    .license(new License().name("Apache 2.0").url("http://www.javaboy.org")))
            .externalDocs(new ExternalDocumentation()
                    .description("一些描述信息")
                    .url("https://github.com/lenve/vhr"));
}

好啦,常见用法大概就是这样,感兴趣的小伙伴可以去试试哦~关于 SpringDoc 的更多玩法,大家也可以参考官方文档:springdoc.org。

Spring Security整合Swagger的过程中,我们需要进行以下几个步骤: 1. 配置Spring Security:在Spring Security配置类中,我们可以使用`WebSecurityConfigurerAdapter`来配置权限过滤和访问控制。可以在`configure(HttpSecurity http)`方法中添加`.antMatchers("/swagger-ui.html").permitAll()`来允许Swagger UI页面的访问。这样,Swagger UI页面将不会被Spring Security拦截。 2. 配置静态资源:Swagger UI页面需要访问一些静态资源,例如Swagger API文档和UI配置文件。我们可以在Spring Security配置类中使用`WebSecurity.configure(WebSecurity web)`方法来配置这些静态资源的访问权限。可以使用`web.ignoring().antMatchers("/v2/api-docs", "/swagger-resources/configuration/ui", "/swagger-resources", "/swagger-resources/configuration/security", "/swagger-ui.html")`来允许这些静态资源的访问。 3. 添加相关依赖:在项目的pom.xml文件中,我们需要添加Spring Security和Swagger的相关依赖。可以添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <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> ``` 这些依赖将帮助我们实现Spring Security和Swagger的整合。 综上所述,以上是实现Spring Security整合Swagger的方法。通过配置Spring Security和静态资源,以及添加相关依赖,我们可以实现在Spring Boot项目中使用Spring Security保护接口并允许Swagger UI的访问[1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

吴名氏.

你的鼓励是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值