SpringBoot开发接口的生成—Swagger

256 阅读9分钟

1. Swagger与OpenAPI

1.1 Swagger介绍

Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务(swagger.io/)。 它的主要作用是:

  1. 使得前后端分离开发更加方便,有利于团队协作

  2. 接口的文档在线自动生成,降低后端开发人员编写接口文档的负担

  3. 功能测试

Spring已经将Swagger纳入自身的标准,建立了Spring-swagger项目,现在叫Springfox。通过在项目中引入Springfox,即可非常简单快捷的使用Swagger。

1.2 OpenAPI介绍

OpenAPISwagger的后继者。它是一种用于描述 RESTful API 的规范,以YAMLJSON格式编写。OpenAPI 提供了一些高级功能,如请求和响应的验证、参数传递方式等。它是由OpenAPI Initiative(OAI)开发和维护的。

OpenAPI 3.0是OpenAPI规范的第一个正式版本,因为它是由SmartBear Software捐赠给OpenAPI Initiative,并在2015年从Swagger规范重命名为OpenAPI规范。

那么SwaggerOpenApi到底有什么不同之处呢?

理解差异的最简单方法是: OpenAPI = 规范。 OpenAPI是规范的正式名称。 Swagger = 实现规范的工具。 Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。

2. Knife4j

官方描述:Knife4j是一个集Swagger2OpenAPI3为一体的增强解决方案

Knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui,它是一个纯swagger-uiui皮肤项目,后面取名knife4j是希望它能像一把匕首一样小巧,轻量,并且功能强悍,更名也是希望把它做成一个为Swagger接口文档服务的通用性解决方案,不仅仅只是专注于前端ui。现在。一般都使用knife4j框架来使用Swagger接口文档服务。

Knife4j官网:doc.xiaominfo.com/

2.1 Knife4j版本参考

knife4j目前主要支持以Java开发为主,并且支持Spring MVC、Spring Boot、Spring Cloud框架的集成使用。

Knife4j 的版本说明:

版本说明
1.0~1.9.6名称叫swagger-bootstrap-ui,蓝色风格Ui,从1.9.6开始更名,增加更多的后端模块
2.0~2.0.5Ui基于Vue2.0+AntdV重写,黑色风格,底层依赖的springfox框架版本是2.9.2
2.0.6~2.0.9底层springfox框架版本升级至2.10.5OpenAPI规范为v2,建议开发者不要使用
3.0~3.0.3底层依赖springfox框架版本升级至3.0.3OpenAPI规范是v3
4.0~4.0重要版本,提供OpenAPI2 和OpenAPI3两种规范供开发者自行选择,主版本统一

ps:虽然不建议使用3.0~3.0.3的版本,但目前在Maven仓库中并没有4.0~以后的版本。(查看下文)

image-20240319204549573

真以为没有4.0版本?其实改名字了,偶然一次机会发现的,现在叫做Knife4j OpenAPI3 Jakarta Spring Boot Starter

image-20240323193334686

Knife4j的依赖引入要和Spring-boot版本相匹配,所以得首先确保你项目中所使用的Spring-boot版本,以下是一些常见的Spring-boot版本及其对应的Knife4j版本兼容推荐:

Spring Boot版本Knife4j Swagger2规范Knife4j OpenAPI3规范
1.5.x~2.0.0<Knife4j 2.0.0>=Knife4j 4.0.0
2.0~2.2Knife4j 2.0.0 ~ 2.0.6>=Knife4j 4.0.0
2.2.x~2.4.0Knife4j 2.0.6 ~ 2.0.9>=Knife4j 4.0.0
2.4.0~2.7.x>=Knife4j 4.0.0>=Knife4j 4.0.0
>=3.0>=Knife4j 4.0.0>=Knife4j 4.0.0

如果你不考虑使用Knife4j提供的服务端增强功能,引入Knife4j的纯Ui版本没有任何限制。只需要考虑不同的规范即可。

规范说明:

针对Swagger2规范OpenAPI3规范的说明:

在Spring Boot框架中,Knife4j对于服务端将Spring的开放接口解析成Swagger2或者OpenAPI3规范的框架,也是依赖的第三方框架组件。说明如下:

  • Swagger2规范:依赖Springfox项目,该项目目前几乎处于停更状态,但很多老项目依然使用的是该规范,所以Knife4j在更新前端Ui的同时也继续保持了兼容
  • OpenAPI3规范:依赖Springdoc项目,更新发版频率非常快,建议开发者尽快迁移过来使用OpenAPI3规范,Knife4j后面的重心也会在这里。

3. Knife4j的使用

ps:这里讲的是4.0版本以前的,也就是Spring Boot版本要在3.0以前

3.1 相关配置

  1. 导入 knife4j 的maven坐标

    在pom.xml中添加依赖

    <dependency>
       <groupId>com.github.xiaoymin</groupId>
       <artifactId>knife4j-spring-boot-starter</artifactId>
       <version>3.0.3</version>
    </dependency>
    

    注意:使用 knife4j 时注意前文讲到的版本对应的问题,否则会报错

  2. 在配置类中加入 knife4j 相关配置

    WebMvcConfiguration.java

    @Configuration
    // 需要继承WebMvcConfigurationSupport,重写addResourceHandlers,配置静态资源路径
    public class WebMvcConfiguration extends WebMvcConfigurationSupport {
        /**
         * 创建Swagger的基本信息情况,生成接口文档
         * @return
         */
        @Bean
        public Docket docket() {
            // 对应的描述信息
            ApiInfo apiInfo = new ApiInfoBuilder()
                    .title("API文档")
                    .description("swagger的简单教程")
                    .contact(new Contact("大锅","https://xxx.xxx","12345678@163.com")) // 作者信息
                    .version("1.0")
                    .license("Swagger的使用教程")
                    .licenseUrl("https://xxx.xxx")
                    .termsOfServiceUrl("服务Url")
                    .build();
            // 文档类型
            return new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(apiInfo)
                    .groupName("测试分组")
                    .host("http://www.daguo.com")
                    .select()
                	/* 被扫描的包,可以获取该包类下的所有接口
                	若还有其他包,可以进行更换,如:com.example.controller.admin/com.example.controller.user
                	*/
                    .apis(RequestHandlerSelectors.basePackage("com.example.controller"))  
                    .paths(PathSelectors.any())
                    .build();
        }
    
        /**
         * 配置 knife4j 的静态资源请求映射地址
         * @param registry
         */
        @Override
        protected void addResourceHandlers(ResourceHandlerRegistry registry) { // 重写方法
            registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
            registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
        }
    }
    
  3. 访问测试

​ 接口文档访问路径为 http://ip:port/doc.html ---> http://localhost:8080/doc.html

image-20240323201147811

对应这里的可视化界面,对于上面的基本信息一一对应就好,这里就不再详细每一个的含义了。

提一点,其中关于groupName的使用,这里只建了一个分组,左上角处只能选择该分组。

image-20240323201452684

如果想要新建分组,只需要在新建一个同样的函数就可以,使用不同的组名,函数名可以任意定义,对于扫描的包也可以更换成其他controller包,然后就可以进行切换分组查看不同的api接口。

knife4j 的静态资源请求映射地址必须进行配置,否则不能加载,这里就需要将该类继承于WebMvcConfigurationSupport,然后重写addResourceHandlers方法,这里的配置是固定不变的。

3.2 常用注解

通过注解可以控制生成的接口文档,使接口文档拥有更好的可读性,这些注解都会在接口文档有所体现,常用注解如下:

注解说明
@Api用在类上,例如Controller,表示对类的说明
@ApiModel用在类上,例如entity、DTO、VO
@ApiModelProperty用在属性上,描述属性信息
@ApiOperation用在方法上,例如Controller的方法,说明方法的用途、作用
@Parameter用在请求参数上,描述参数相关信息

接下来,使用上述注解,生成可读性更好的接口文档

@RestController
// 表示对该类的说明
@Api(tags = "hello测试接口")
public class HelloControl {

    @GetMapping("hello")
    // 说明该方法的用途,作用
    @ApiOperation("test")
    public String hello() {
        System.out.println("Hello world");
        return "Hello world";
    }
    
    @GetMapping("/user/{id}")
    @ApiOperation("根据id获取用户信息")
    public User getUser(@Parameter(description = "用户id", required = true) @PathVariable Long id) {
        User user = new User();
        System.out.println("用户id:" + id);
        // 这里并没有相关数据,简单设置返回,模拟获取数据
        user.setName("大锅");
        user.setAge(18);
        return user;
    }
}
@Data
@ApiModel("用户")
public class User implements Serializable {
 
    @ApiModelProperty("用户id")
    private Long id;
 
    @ApiModelProperty("用户名称")
    private String name;
 
    @ApiModelProperty("用户年龄")
    private Integer age;
}

这里写了两个方法,就扫描到了两个接口,接口统计信息是描述扫描的包下的GET、POST、DELETE、PUT四个接口方法的总数:

image-20240323204754851

详细描述:

image-20240323204637932

image-20240323205607454转存失败,建议直接上传图片文件

这里也可以像postman或apifox等工具一样进行请求调试:

image-20240323205524355

4. Knife4j 4.0版本以上使用

这里其实大致的用法跟上面的差不多,但有些地方做了一些优化。

Knife4j在实现OpenAPI3规范时,底层基础框架选择 springdoc-openapi 项目。

springdoc-openapi 官网

4.1 相关配置

  1. 导入依赖
<!-- knife4j-openapi3 -->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
    <version>4.5.0</version>
</dependency>
  1. 在配置类中加入 knife4j 相关配置

可以参考官网的相关配置

knife4j 增强配置 springdoc-openapi 属性配置

# springdoc-openapi的相关设置
springdoc:
  # 分组设置
  group-configs:
    - group: 服务端管理接口
      packages-to-scan: com.example.controller.admin
    - group: 用户相关接口
      packages-to-scan: com.example.controller.user

# knife4j的增强配置,不需要增强可以不配
knife4j:
  enable: true
  setting:
    language: zh-CN

Knife4jConfiguration.java

package com.example.config;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Knife4jConfiguration {
	// 设置 openapi 基础参数
	@Bean
	public OpenAPI customOpenAPI() {
		// 对应的描述信息
		Info APIInfo = new Info()
				.title("Knife4j 4.0~文档")
				.description("Knife4j 4.0~的简单教程")  // 支持markdown语法
				.contact(new Contact().name("大锅").url("https://xxx.xxx").email("12345678.@163.com")) // 作者信息
				.version("1.0")
				.termsOfService("服务Url")
				.license(new License().name("我是license").url("https://xxx.xxx"));
		return new OpenAPI().info(APIInfo);
	}
}

相比以前的版本,就不需要配置相关的静态地址了,其访问接口还是不变的。http://ip:port/doc.html

image-20240324102049083

这里设置了两个分组,并扫描不同的controller,就可以将不同的api接口进行分组管理。

4.2 常用注解变化

官网文档:springdoc.org/#migrating-…

image-20240324102530986

常用的几个注解:

注解说明部分参数
@Tag用于controller上的说明标签。name:名称 description:描述
@Schema用于实体类或类属性的描述name:名称 description:描述 format:属性的格式。如 @Schema(format = "email")
@Operation描述API的接口的元数据信息summary:简短描述
@Parameter用于描述 API 操作中的参数namee:指定的参数名 description:参数描述 in:参数来源(query、header、cookie等)

示例项目结构:

image-20240324103710035

User.java

@Data
@NoArgsConstructor
@AllArgsConstructor
@Schema(name = "用户", description = "用户")
public class User implements Serializable {

	@Schema(description = "用户id")
	private Long id;

	@Schema(description = "用户名称")
	private String name;

	@Schema(description = "用户年龄")
	private Integer age;

}

admin/UserController.java

@RestController("adminUserController")
@Tag(name = "服务端管理接口")
public class UserController {

	@GetMapping("/admin/user/{id}")
	@Operation(summary = "根据用户id查找用户信息")
	@Parameter(name = "id", description = "用户id", required = true )
	public User getById(@PathVariable Long id) {
		User user = new User();
		System.out.println("用户id:"+id);
		user.setName("大锅");
		user.setAge(18);
		return user;
	}
}

user/UserController.java

@RestController
@Tag(name = "用户端相关接口")
public class UserController {

	@GetMapping("/user/hello")
	@Operation(summary = "欢迎用户")
	@Parameter(name = "username",description = "用户姓名", in = ParameterIn.QUERY)
	public String sayHi(String username) {

		return "你好!" + username;
	}

}

image-20240324103743757

image-20240324103802362

image-20240324103830820

image-20240324103852004

image-20240324103907862