关于swagger:不用Swagger那我用啥

65次阅读

共计 9472 个字符,预计需要花费 24 分钟才能阅读完成。

@[toc]
上周松哥写了一篇文章和小伙伴们分享 Swagger3 在 Spring Boot 中的用法,评论中有不少小伙伴举荐 Spring Doc,松哥趁着休息时间抽空看了下,这个货色的确不错,不存在和 Spring Boot 之间的兼容问题,于是就撸了这篇文章和小伙伴们分享。一起来看看这个好玩的文档生成工具吧!

1. OpenApi

在正式学习 Spring Doc 之前,先给大家介绍一下 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

创立工程

首先创立一个 Spring Boot 工程,引入 WebJpaMySQLRest Repositories 依赖:

配置数据库

次要配置两个,一个是数据库,另一个是 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。

这两段配置是对于 MySQL + JPA 的配置,没用过 JPA 的小伙伴能够参考松哥之前的 JPA 文章:http://www.javaboy.org/2019/0407/springboot-jpa.html

构建实体类

@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 的魅力!

测试

此时,咱们就能够启动我的项目进行测试了,应用 POSTMAN 来测试(大家也能够自行抉择趁手的 HTTP 申请工具)。

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

依据 id 查问接口
  • http://127.0.0.1:8080/books/{id}

这个接口示意依据 id 查问某一本书:

分页查问
  • 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

增加

也能够增加数据,增加是 POST 申请,数据通过 JSON 的模式传递,如下:

增加胜利之后,默认会返回增加胜利的数据。

批改

批改接口默认也是存在的,数据批改申请是一个 PUT 申请,批改的参数也是通过 JSON 的模式传递:

默认状况下,批改胜利后,会返回批改胜利的数据。

删除

当然也能够通过 DELETE 申请依据 id 删除数据:

删除胜利后,是没有返回值的。

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

这些都是默认的配置,这些默认的配置实际上都是在 JpaRepository 的根底上实现的,理论我的项目中,咱们还能够对这些性能进行定制。

查问定制

最宽泛的定制,就是查问,因为增删改操作的变动不像查问这么丰盛。对于查问的定制,非常容易,只须要提供相干的办法即可。例如依据作者查问书籍:

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

留神,办法的定义,参数要有 @Param 注解。

定制实现后,重启我的项目,此时就多了一个查问接口,开发者能够通过 http://localhost:8080/books/s… 来查看和 book 相干的自定义接口都有哪些:

查问后果示意,只有一个自定义接口,接口名就是办法名,而且查问后果还给出了接口调用的示例。咱们来尝试调用一下本人定义的查问接口:

开发者能够依据理论状况,在 BookRepository 中定义任意多个查询方法,查询方法的定义规定和 Jpa 中截然不同(不懂 Jpa 的小伙伴,能够参考干货 | 一文读懂 Spring Data Jpa!,或者在松哥集体网站 www.javaboy.org 上搜寻 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,重启我的项目,持续查问接口:

除了 relpath 两个属性之外,@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,能够在这里本人从新定义。

其余配置

最初,也能够在 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

6. 切换到 Swagger

如果你在我的项目中曾经应用了 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。

正文完
 0