Spring Boot 入门实战(9)--使用 knife4j 构建 API 文档
Knife4j 是为 Java MVC 框架集成 Swagger 生成 Api 文档的增强解决方案,其提供的页面更符合国人的使用习惯,并提供了很多额外的功能特性,官网地址为:https://doc.xiaominfo.com。本文主要介绍 Spring Boot 与 Knife4j 的结合使用,文中所使用到的软件版本:Spring Boot 2.4.4、jdk1.8.0_181、Knife4j 3.0.2。
1、Swagger基本使用
Knife4j 是基于 Swagger 开发改造的,所以有必要先了解下 Swagger 的使用方法;具体可参考 Spring Boot 入门实战(8)--使用 Swagger 构建 API 文档。
2、Spring Boot 整合 Knife4j
Spring Boot 环境下 Knifie 和 Swagger 的使用基本差不多,除了引入的 jar 包及配置等少许地方不一样,其他方面基本都一样。
2.1、引入依赖
<dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>3.0.2</version> </dependency>
2.2、增加配置(application.yml)
knife4j: enable: true
2.3、Swagger 配置
package com.abc.demo.config; import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver; import io.swagger.annotations.ApiOperation; import io.swagger.models.auth.In; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.*; import springfox.documentation.oas.annotations.EnableOpenApi; import springfox.documentation.service.*; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spring.web.plugins.Docket; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @Configuration @EnableOpenApi public class SwaggerConfig { private static final String AUTH_HEADER_NAME = "token"; //Knife4j扩展对象 @Autowired private OpenApiExtensionResolver openApiExtensionResolver; @Bean public Docket docket() { return new Docket(DocumentationType.OAS_30) .apiInfo(apiInfo()) .select() //加了ApiOperation注解的方法,才生成接口文档 .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) //特定包下的类,才生成接口文档 //.apis(RequestHandlerSelectors.basePackage("com.abc.demo.controller")) .paths(PathSelectors.any()) .build() .extensions(openApiExtensionResolver.buildExtensions("default")) //设置全局token .securitySchemes(securitySchemes()) .securityContexts(securityContexts()); //每个接口传token //.globalRequestParameters(globalRequestParameters()); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("XXX系统") .description("XXX系统接口文档") .termsOfServiceUrl("https://www.abc.com") .contact(new Contact("Jack", "https://www.cnblogs.com/jack", "123456@qq.com")) .version("1.0.0") .build(); } private List<SecurityScheme> securitySchemes() { return Arrays.asList(new ApiKey(AUTH_HEADER_NAME, "auth", In.HEADER.name())); } private List<SecurityContext> securityContexts() { List<SecurityContext> securityContexts = new ArrayList<>(); securityContexts.add(SecurityContext .builder() .securityReferences(securityReferences()) .operationSelector(operationContext -> operationContext.requestMappingPattern().startsWith("/api/")) .build()); return securityContexts; } private List<SecurityReference> securityReferences() { AuthorizationScope[] authorizationScopes = new AuthorizationScope[] {new AuthorizationScope("global", "accessEverything")}; List<SecurityReference> securityReferences = new ArrayList<>(); securityReferences.add(new SecurityReference(AUTH_HEADER_NAME, authorizationScopes)); return securityReferences; } private List<RequestParameter> globalRequestParameters() { return Arrays.asList(new RequestParameterBuilder() .name(AUTH_HEADER_NAME) .description("access token") .in(ParameterType.HEADER) .required(false) .build()); } }
2.4、编写Controller
package com.abc.demo.controller; import com.abc.demo.annotation.Login; import com.abc.demo.entity.R; import com.abc.demo.entity.Student; import com.abc.demo.form.StudentForm; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.*; import java.util.*; @RestController @RequestMapping("/api/student") @Api(tags = "学生相关接口") public class StudentController { private static Logger logger = LoggerFactory.getLogger(StudentController.class); @PostMapping("add") @ApiOperation("增加学生(json方式提交)") public R<Long> add(@RequestBody StudentForm studentForm) { logger.info("studentForm={}", studentForm); //TODO: service调用 return R.ok(new Random().nextLong()); } @PostMapping("add2") @ApiOperation("增加学生(form方式提交)") public R<Long> add2(StudentForm studentForm) { logger.info("studentForm={}", studentForm); //TODO: service调用 return R.ok(new Random().nextLong()); } @GetMapping("get") @ApiOperation("根据姓名查询学生") @ApiImplicitParam(name = "name", value = "学生姓名", dataTypeClass = String.class, required = true) public R<Student> get(String name) { logger.info("name={}", name); //TODO: service调用 return R.ok(new Student(new Random().nextLong(), "杜甫", 21, 175)); } @Login @GetMapping("list") @ApiOperation("获取学生列表") public R<List<Student>> list() { //TODO: service调用 List<Student> students = new ArrayList(){{ add(new Student(new Random().nextLong(), "杜甫", 21, 175)); add(new Student(new Random().nextLong(), "李商隐", 22, 175)); }}; return R.ok(students); } }
Controller 用到的参数实体类 StudentForm:
package com.abc.demo.form; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.ToString; @Data @ToString @ApiModel(value = "学生表单") public class StudentForm { @ApiModelProperty(value = "姓名", example = "李白") private String name; @ApiModelProperty(value = "年龄", example = "20") private Integer age; @ApiModelProperty(value = "身高", example = "175") private Integer height; }
Controller用到的实体类Student:
package com.abc.demo.entity; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; @NoArgsConstructor @AllArgsConstructor @Data @ToString @ApiModel(value = "学生信息") public class Student { @ApiModelProperty(value = "学生id", example = "1234") private Long id; @ApiModelProperty(value = "学生姓名", example = "李白") private String name; @ApiModelProperty(value = "年龄", example = "20") private Integer age; @ApiModelProperty(value = "身高", example = "175") private Integer height; }
Controller 用到的返回对象R:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.abc.demo.entity; /** * 返回数据 */ public class R<T> { /** * 返回码 * 0 正常,其他异常 */ private int returnCode = 0; /** * 描述 */ private String description = "OK"; /** * 结果数据 */ private T result; public int getReturnCode() { return returnCode; } public String getDescription() { return description; } public T getResult() { return result; } public static R ok() { return new R(); } public static <T> R<T> ok(T result) { R<T> r = new R<>(); r.result = result; return r; } public static <T> R<T> error() { R<T> r = new R(); r.returnCode = -1; r.description = "未知异常,请联系管理员"; return r; } public static <T> R<T> error(String description) { R<T> r = new R(); r.returnCode = -1; r.description = description; return r; } public static <T> R<T> error(int returnCode, String description) { R<T> r = new R(); r.returnCode = returnCode; r.description = description; return r; } }
2.5、查看接口信息
访问 http://localhost:8080/doc.html,可以看到文档页面更加的美观好用: