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:

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;
    }

}
R.java

2.5、查看接口信息

访问 http://localhost:8080/doc.html,可以看到文档页面更加的美观好用:

 

posted @ 2021-04-03 16:22  且行且码  阅读(1846)  评论(0编辑  收藏  举报