• SpringBoot3整合Knife4j4.x版本(Swagger3、OpenApi3)


      😊 @ 作者: 一恍过去
      🎊 @ 社区: Java技术栈交流
      🎉 @ 主题: SpringBoot3整合Knife4j4.x版本(Swagger3、OpenApi3)
      ⏱️ @ 创作时间: 2024年03月14日

      前言

      适用于:SpringBoot 3.x版本

      1、为什么使用Knife4j

      前后端分离的开发模式下,后端人员开发完接口后,需要单独出一份文档,说明每个接口的作用以及接口的传入参数与响应参数;但是项目处于快速开发阶段时,就会出现文档更新不及时的情况,久而久之在对接接口时就会出现效率下降的情况,Knife4j提供一个可视化的UI界面,通过Knife4j只需要注解就可以向前端暴漏出所有的接口信息,便于前端对接以及对系统的测试。页面访问方式为:ip:prot/context-path/doc.html

      2、基本使用

      2.1 pom

              <dependency>
                  <groupId>com.github.xiaoymingroupId>
                  <artifactId>knife4j-openapi3-jakarta-spring-boot-starterartifactId>
                  <version>4.4.0version>
              dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5

      2.2 配置Knife4j

      创建配置文件:Knife4jConfig

      @Configuration
      public class SwaggerConfig {
          @Bean
          public OpenAPI customOpenAPI() {
              return new OpenAPI()
                      .info(new Info()
                              .title("XXX系统API")
                              .version("1.0")
                              .description("Knife4j集成接口文档")
                              .termsOfService("http://www.lhz.com")
                              .license(new License().name("Apache 2.0")));
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      yaml

      # springdoc-openapi项目配置
      springdoc:
        swagger-ui:
          path: /swagger-ui.html
          # 排序方式为首字母
          tags-sorter: alpha
          # 使用增强order属性进行排序,或者不设置该参数( @ApiOperationSupport(order = n)直接生效)
          operations-sorter: order
        api-docs:
          path: /v3/api-docs
        group-configs:
          - group: '测试'
            paths-to-match: '/**'
            # controller所在包
            packages-to-scan: com.lhz.demo.controller.swagger3
      
      # knife4j的增强配置,不需要增强可以不配
      knife4j:
        enable: true
        setting:
          language: zh_cn
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21

      2.3 拦截器放行

      如果项目中配置了拦截器,那么会拦截Knife4j的请求的资源,需要进行放行处理,放行的url如下:

      • “/swagger-resources/**”
      • “/doc.html”
      • “/swagger-ui.html”
      • “/v2/**”
      • “/v3/**”
      • “/webjars/**”

      2.4 实体类

      创建一个实体类

      @Data
      @Schema(description = "测试实体类")
      public class TestEntity {
      
          @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED)
          private String name;
      
          @Schema(description = "手机号")
          private String phone;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

      2.5 SpringBoot整合基础使用

      2.5.1 基础配置

      通过@Tag注解,为当前Controller进行命名,通过@OperationController中的方法设置名称

      @Tag(name = "XX接口管理")
      @RestController
      public class TestController {
      
          @Operation(summary = "测试方法", description = "测试方法")
          @GetMapping("/test")
          public void test() {
              System.out.println("进入了test接口");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

      2.5.2 Post(实体)请求

      和传统的Post请求写法一致参数加上@RequestBody注解,通过@Operation为接口命名

      Controller:

      @Tag(name = "XX接口管理")
      @RestController
      public class TestController {
      
          @Operation(summary = "测试方法", description = "测试")
          @PostMapping("/test")
          public void test(@RequestBody TestEntity test) {
              System.out.println("test = " + test);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

      文档页面:
      在这里插入图片描述

      调试页面:
      在这里插入图片描述

      2.5.3 Get(实体)请求

      对于Get请求时,需要加一个由springdoc提供的注解@ParameterObject

      @Tag(name = "XX接口管理")
      @RestController
      public class TestController {
      
          @Operation(summary = "测试Get请求", description = "测试")
          @GetMapping("/testGet")
          public void testGet(@ParameterObject TestEntity test) {
              System.out.println("test = " + test);
          }
          
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      文档页面:
      在这里插入图片描述

      调试页面:
      可以看到Get请求的请求参数形式是以列表的形式进行呈现,而Post的请求参数是json形式
      在这里插入图片描述

      2.5.4 响应参数配置

      对于返回对象,我们通常可以为某个具体的Object或者List针对这两类情况有不同的处理方式,
      需要使用到swagger3提供的@ApiResponse注解

      1. 响应对象
      @Tag(name = "XX接口管理")
      @RestController
      public class TestController {
      
          @Operation(summary = "测试响应对象", description = "测试")
          @GetMapping("/responseObject")
          @ApiResponse(content = @Content(schema = @Schema(implementation = TestEntityRes.class)))
          public TestEntityRes testGet2() {
              return new TestEntityRes();
          }
          
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      文档页面:
      在这里插入图片描述

      2.响应List集合
      @Tag(name = "XX接口管理")
      @RestController
      public class TestController {
      
          @Operation(summary = "测试响应List集合", description = "测试")
          @GetMapping("/responseList")
          @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = TestEntityRes.class))))
          public List<TestEntityRes> testGetList() {
              return new ArrayList<>();
          }
          
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      文档页面:
      在这里插入图片描述

      2.5.5 Header参数请求

      在项目开发中,存在接口需要传入在header中传递token获取其他参数的情况,通过GlobalOpenApiCustomizer进行全局的配置,此处需要进行配置类的修改,其中HttpHeaders.AUTHORIZATION表示header的名称 该参数可以按照自己系统的header名称进行设置。

      Tips:配置后所有的接口,都会在调试请求时,RequestHeader中都会默认加上HttpHeaders.AUTHORIZATION

      配置如下:

      @Configuration
      public class SwaggerConfig {
          @Bean
          public OpenAPI customOpenAPI() {
              return new OpenAPI()
                      .info(new Info()
                              .title("XXX系统API")
                              .version("1.0")
                              .description("Knife4j集成接口文档")
                              .termsOfService("http://www.lhz.com")
                              .license(new License().name("Apache 2.0")))
                      .addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION))
                      .components(new Components().addSecuritySchemes(HttpHeaders.AUTHORIZATION, new SecurityScheme()
                              .name(HttpHeaders.AUTHORIZATION).type(SecurityScheme.Type.HTTP)));
          }
      
          @Bean
          public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() {
              return openApi -> {
                  // 全局添加鉴权参数(HttpHeaders.AUTHORIZATION)
                  if (openApi.getPaths() != null) {
                      openApi.getPaths().forEach((s, pathItem) -> {
                          // 为所有接口添加鉴权
                          pathItem.readOperations().forEach(operation -> {
                              operation.addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION));
                          });
                      });
                  }
              };
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31

      效果:
      在这里插入图片描述

      2.5.6 非实体参数请求

      对于传入请求参数,没有进行实体类封装时,那么可以进行单独的参数配置,可能会将参数在path上进行传递,也可以提供query方式进行传递,通过@Parameters@Parameter来实现

      @Tag(name = "XX接口管理")
      @RestController
      public class TestController {
      
          @Operation(summary = "测试响应List集合", description = "测试")
          @GetMapping("/responseList")
          @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = TestEntityRes.class))))
          public List<TestEntityRes> testGetList() {
              return new ArrayList<>();
          }
          
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      Tips:如果只有一个请求参数的情况下,直接使用@Parameter注解即可

      文档页面:
      外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

      调试页面:
      在这里插入图片描述

      2.5.7 文件类型的请求

      1. 文件上传
      @Tag(name = "XX接口管理")
      @RestController
      public class TestController {
          
          @Operation(summary = "单文件上传", description = "单文件上传")
          @Parameter(name = "file", description = "文件", required = true, schema = @Schema(name = "file", format = "binary"))
          @PostMapping("/upload")
          public void upload(@RequestParam("file") MultipartFile file) {
              System.out.println("file = " + file.getOriginalFilename());
          }
          
              @Operation(summary = "多文件上传", description = "多文件上传")
          @Parameter(name = "files", description = "文件", required = true, schema = @Schema(name = "files", format = "binary"))
          @PostMapping("/uploadBatch")
          public void uploadBatch(@RequestParam("files") List<MultipartFile> files) {
              for (MultipartFile file : files) {
                  System.out.println("file = " + file.getOriginalFilename());
              }
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

      文档页面:

      在这里插入图片描述

      2. 文件上传带参数
      @Tag(name = "XX接口管理")
      @RestController
      public class TestController {
          
          @Operation(summary = "文件上传带参数", description = "文件上传带参数")
          @Parameters({
                  @Parameter(name = "id", description = "文件id", in = ParameterIn.PATH),
                  @Parameter(name = "file", description = "文件", required = true, schema = @Schema(name = "file", format = "binary")),
                  @Parameter(name = "name", description = "文件名称", in = ParameterIn.QUERY, required = true),
          })
          @PostMapping("/uploadParam/{id}")
          public void uploadParamPath(@PathVariable("id") String id, @RequestParam("file") MultipartFile file, @RequestParam("name") String name) {
              System.out.println("id = " + id);
              System.out.println("file = " + file.getOriginalFilename());
              System.out.println("name = " + name);
          }
          
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

      文档页面:
      在这里插入图片描述

      4、接口排序

      接口排序的目的是,我们可以将一些新写的接口按照自定义的序号进行从上到下的顺序排序;

      接口排序要生效,需要在yaml配置中operations-sorter属性需要设置为order,并且配合ApiOperationSupport注解使用

      Yaml配置:

      # springdoc-openapi项目配置
      springdoc:
        swagger-ui:
          # 使用增强order属性进行排序,或者不设置该参数( @ApiOperationSupport(order = n)直接生效)
          operations-sorter: order
      
      • 1
      • 2
      • 3
      • 4
      • 5

      注解使用:

      @Tag(name = "XX接口管理")
      @RestController
      public class TestController {
      
          @Operation(summary = "测试排序-一", description = "测试")
          @ApiOperationSupport(order = 1)
          @PostMapping("/testSort1")
          public void test(@RequestBody TestEntity test) {
              System.out.println("test = " + test);
          }
      
          @Operation(summary = "测试排序-二", description = "测试")
          @ApiOperationSupport(order = 2)
          @GetMapping("/testSort2")
          public void testGet(@ParameterObject TestEntity test) {
              System.out.println("test = " + test);
          }
          
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

      5、访问页面权限控制

      通过开启页面权限控制 使得访问Knife4j接口地址时需要进行账户密码验证,通过Knife4j提供的增强功能实现,用法如下:

      yml配置:

      knife4j:
        # 开启增强配置
        enable: true
        basic:
          enable: true
          # Basic认证用户名
          username: admin
          # Basic认证密码
          password: 123456
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      效果:
      在这里插入图片描述

      6、生产环境屏蔽

      我们在开发阶段时,是可以任意访问Knife4j文档的,当项目上线以后,我们为了保证不被外部系统访问,在不大量修改代码的情况下,可以使用Knife4j提供的生产环境屏蔽功能,用法如下:

      knife4j:
        # 开启增强配置
        enable: true
       # 开启生产环境屏蔽
        production: true
      
      • 1
      • 2
      • 3
      • 4
      • 5

      效果:
      在这里插入图片描述

      7、多个Controller分组

      实际开发项目中,我们可以存在多个页面模块,每个模块的controller路径不同,那么可以在yaml中配置,多个不同的分组,如下:

      # springdoc-openapi项目配置
      springdoc:
        group-configs:
          - group: '测试组'
            paths-to-match: '/**'
            packages-to-scan: com.lhz.demo.a
          - group: '应用组'
            paths-to-match: '/**'
            packages-to-scan: com.lhz.demo.b
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      效果:
      在这里插入图片描述

      8、对比Swagger2

      8.1 实体类注解对比

      在Swagger2中通过@ApiModel@ApiModelProperty两个注解进行实现,使用required = true来表示必填标识;

      @ApiModel("测试实体类")
      public class TestEntity {
          @ApiModelProperty(value = "名称", required = true)
          private String name;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5

      在Swagger3中通过一个@Schema注解进行实现,使用requiredMode = Schema.RequiredMode.REQUIRED来表示必填标识;

      @Schema(description = "测试实体类")
      public class TestEntity {
      
          @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED)
          private String name;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      8.2 分组类注解对比

      在Swagger2中通过@Api注解进行实现;

      @Api(tags = "测试管理")
      @RestController
      @RequestMapping("test")
      public class TestController {
          
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      在Swagger3中通过一个@Tag注解进行实现;

      @Tag(name = "测试管理")
      @RestController
      @RequestMapping("test")
      public class TestController {
          
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      8.3 方法注解对比

      在Swagger2中通过@Api注解进行实现;

      @Api(tags = "测试管理")
      @RestController
      @RequestMapping("test")
      public class TestController {
          
          @ApiOperation(value = "根据Id查询", notes = "根据Id查询")
          @PostMapping("/test")
          public void test() {
              System.out.println("test");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      在Swagger3中通过一个@Operation注解进行实现;

      @Tag(name = "测试管理")
      @RestController
      @RequestMapping("test")
      public class TestController {    
      	@Operation(summary = "测试方法", description = "测试")
          @PostMapping("/test")
          public void test() {
              System.out.println("test");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

      8.4 请求参数注解对比

      在Swagger2中通过@ApiImplicitParams@ApiImplicitParam注解进行实现,并且通过dataType指定数据类型,通过paramType指定参数类型;

      @Api(tags = "测试管理")
      @RestController
      @RequestMapping("test")
      public class TestController {
          
          @ApiOperation(value = "测试非实体参数请求", notes = "测试非实体参数请求"")
          @GetMapping("/testParam/{id}")
          @ApiImplicitParams({
                  @ApiImplicitParam(name = "id", value = "Id字段", paramType = "path", required = true, dataType = "integer"),
                  @ApiImplicitParam(name = "name", value = "名称", paramType = "query", required = true, dataType = "string")
          })
          public void test(@PathVariable Integer id, @RequestParam String name) {
              System.out.println("id = " + id + ",name = " + name);
          }
          
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

      在Swagger3中通过一个@Parameters@Parameter注解进行实现,并且通过schema指定数据类型,通过in指定参数类型;

      @Tag(name = "测试管理")
      @RestController
      @RequestMapping("test")
      public class TestController {    
      
          @Operation(summary = "测试非实体参数请求", description = "测试非实体参数请求")
          @GetMapping("/testParam/{id}")
          @Parameters({
                  @Parameter(name = "id", description = "Id字段", required = true, in = ParameterIn.PATH, schema = @Schema(type = "integer")),
                  @Parameter(name = "name", description = "名称", required = true, in = ParameterIn.QUERY, schema = @Schema(type = "string"))
          })
          public void test(@PathVariable Integer id, @RequestParam String name) {
              System.out.println("id = " + id + ",name = " + name);
          }
          
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

      Tips:如果是Get请求,并且参数为实体时,需要使用@ParameterObject注解,比如:

      @Operation(summary = "测试Get请求", description = "测试")
      @ApiOperationSupport(order = 2)
      @GetMapping("/testGet")
      public void testGet(@ParameterObject TestEntity test) {
        System.out.println("test = " + test);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      8.5 响应参数注解对比

      在Swagger2中通过@ApiOperation注解的responseresponseContainer进行实现;

      @Api(tags = "测试管理")
      @RestController
      @RequestMapping("test")
      public class TestController {
          
          @ApiOperation(value = "返回对象", notes = "返回对象",response = TestEntityRes.class)
          @GetMapping("/responseObject")
      	public TestEntityRes responseObject() {
              return new TestEntityRes();
          }
          
      	@ApiOperation(value = "返回List集合", notes = "返回List集合", response = TestEntityRes.class, responseContainer = "List")
          @GetMapping("/responseList")
          public List<TestEntityRes> responseList() {
              return new ArrayList<>();
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17

      在Swagger3中通过一个@ApiResponse注解进行实现,通过@Schema注解实现返回对象,通过ArraySchema注解实现返回List集合

      @Tag(name = "测试管理")
      @RestController
      @RequestMapping("test")
      public class TestController {    
      
          @Operation(summary = "返回对象", description = "返回对象")
          @GetMapping("/responseObject")
          @ApiResponse(content = @Content(schema = @Schema(implementation = TestEntityRes.class)))
          public TestEntityRes responseObject() {
              return new TestEntityRes();
          }
      
          @Operation(summary = "返回List集合", description = "返回List集合")
          @GetMapping("/responseList")
          @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = TestEntityRes.class))))
          public List<TestEntityRes> responseList() {
              return new ArrayList<>();
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

        在这里插入图片描述

      • 相关阅读:
        [Handbook] 一行shell命令进入VENV环境并执行Python源文件
        FAT32文件系统---第4章 分区挂载
        合并零之间非零节点
        全国高校软件测试开发教学师资培训会圆满落幕
        Cortex-M3异常
        前端面试基础面试题——9
        ubuntu 22.04 卸载不常用软件,安装常用软件两行解决
        《量化投资以Python为工具》目录
        Netty心跳机制和客户端重连的实现
        负载均衡加权轮询算法
      • 原文地址:https://blog.csdn.net/zhuocailing3390/article/details/136696092