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:

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,可以看到文檔頁面更加的美觀好用: