• springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j


    导言

    Swagger2、Knife4j 都是后端API接口文档。
    knife4j swagger2 官方文档:https://doc.xiaominfo.com/docs/quick-start

    一、swagger2介绍

    其实无论是前端调用后端,还是后端调用后端,都期望有一个好的接口文档。但是这个接口文档对于程序员来说,就跟注释一样,经常会抱怨别人写的代码没有写注释,然而自己写起代码起来,最讨厌的,也是写注释。所以仅仅只通过强制来规范大家是不够的,随着时间推移,版本迭代,接口文档往往很容易就跟不上代码了。

    ​ 使用Swagger你只需要按照它的规范去定义接口及接口相关的信息。再通过Swagger衍生出来的一系列项目和工具,就可以做到生成各种格式的接口文档,生成多种语言的客户端和服务端的代码,以及在线接口调试页面等等。

    ​ 这样,如果按照新的开发模式,在开发新版本或者迭代版本的时候,只需要更新Swagger描述文件,就可以自动生成接口文档和客户端服务端代码,做到调用端代码、服务端代码以及接口文档的一致性。

    为了简化swagger的使用,Spring框架对swagger进行了整合,建立了Spring-swagger项目,后面改成了现在的Springfox。通过在项目中引入Springfox,可以扫描相关的代码,生成描述文件,进而生成与代码一致的接口文档和客户端代码。

    二、springBoot-swagger2实战演练

    1. 快速创建项目

    创建springboot项目细节请看博文:
    这里只放出来主要的内容

    1. 描述
      在这里插入图片描述
    2. 插件,选择web和Lombok(上一篇博文讲的)(这里的版本,创建完项目后,我手动改成了2.7.2)
      在这里插入图片描述
    3. 项目结构
      在这里插入图片描述

    2. 引入是swagger2 依赖

            
            <dependency>
                <groupId>io.springfoxgroupId>
                <artifactId>springfox-swagger2artifactId>
                <version>2.9.2version>
            dependency>
            <dependency>
                <groupId>io.springfoxgroupId>
                <artifactId>springfox-swagger-uiartifactId>
                <version>2.9.2version>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3. swagger2 常用注解

    注解说明
    @Api用在请求的类上,例如Controller,表示对类的说明
    @ApiModel用在类上,通常是实体类,表示一个返回响应数据的信息
    @ApiModelProperty用在属性上,描述响应类的属性
    @ApiOperation用在请求的方法上,说明方法的用途、作用
    @ApiImplicitParams用在请求的方法上,表示一组参数说明
    @ApiImplicitParam用在@ApiImplicitParams注解中,指定一个请求参数的各个方面

    4. 配置 application.yml(重要)

    1. 修改配置文件后缀为 application.yml
    2. 配置内容如下
      server:
        port: 9000
      # 配置 swagger2 knife4j
      spring:
        mvc:
          pathmatch:
            # 配置策略
            matching-strategy: ant-path-matcher
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    3. 官网指出:
      在这里插入图片描述
      如果不配置spring.mvc.pathmatch.matching-strategy,会爆下面错误:
      Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException

    5. 创建 swagger 配置类:SwaggerConfig

    创建 config/SwaggerConfig.java

    package com.feng.springboot_swagger2.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.service.Contact;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    // 启用swagger
    @EnableSwagger2
    @Configuration
    public class SwaggerConfig {
        // 用户接口组
        // Docket表示接口文档,用于封装接口文档相关信息(如记录扫描哪些包、文档名字、文档信息等)
        @Bean
        public Docket createRestApi1() {
            Docket docket = new Docket(DocumentationType.SWAGGER_2)
                    // groupName : 接口文档组名字
                    .apiInfo(apiInfo()).groupName("用户接口组")//创建该Api的基本信息(这些基本信息会展现在文档页面中)
                    .select() //函数返回一个ApiSelectorBuilder实例用来控制哪些接口暴露给Swagger ui来展现
                    // basePackage 表示扫描那个包
                    .apis(RequestHandlerSelectors.basePackage("com.feng.springboot_swagger2.controller")) //指定需要扫描的包路路径
                    .paths(PathSelectors.any()) //
                    .build();
            return docket;
        }
    
        //构建 api文档的详细信息
        private ApiInfo apiInfo() {
            return new ApiInfoBuilder()
                    //页面标题
                    .title("API接口文档")
                    //创建人
                    .contact(new Contact("springBoot-swagger2", "https://blog.csdn.net/qq_40036754", ""))
                    //版本号
                    .version("1.0")
                    //描述
                    .description("API 描述")
                    .build();
        }
    
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    6. 创建请求类:UserReqVO

    创建/vo/req/UserReqVO.java

    package com.feng.springboot_swagger2.vo.req;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    // @ApiModel用在类上,通常是实体类,表示一个返回响应数据的信息
    @ApiModel(description = "用户实体")
    public class UserReqVO {
        @ApiModelProperty(value = "名字")
        private String name;
    
        @ApiModelProperty(value = "年龄")
        private Integer age;
    
        @ApiModelProperty(value = "电话")
        private String phone;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    7. 创建控制器:UserController

    创建/controller/UserController.java

    package com.feng.springboot_swagger2.controller;
    
    import com.feng.springboot_swagger2.vo.req.UserReqVO;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @Api(tags = "测试 swagger User 模块")
    @RequestMapping("/api")
    public class UserController {
    
        @ApiOperation(value = "第一个swagger接口")
        @PostMapping("/swagger")
        public UserReqVO testSwagger(@RequestBody UserReqVO vo){
            return vo;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    8. 项目结构

    在这里插入图片描述

    9. 测试结构

    http://localhost:9000/swagger-ui.html

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    测试成功

    10. pom.xml(全)

    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0modelVersion>
    	<parent>
    		<groupId>org.springframework.bootgroupId>
    		<artifactId>spring-boot-starter-parentartifactId>
    		<version>2.7.2version>
    		<relativePath/> 
    	parent>
    	<groupId>com.fenggroupId>
    	<artifactId>springboot_swagger2artifactId>
    	<version>0.0.1-SNAPSHOTversion>
    	<name>springboot_swagger2name>
    	<description>springboot_swagger2 project for Spring Bootdescription>
    	<properties>
    		<java.version>1.8java.version>
    	properties>
    	<dependencies>
    
            
            <dependency>
                <groupId>io.springfoxgroupId>
                <artifactId>springfox-swagger2artifactId>
                <version>2.9.2version>
            dependency>
            <dependency>
                <groupId>io.springfoxgroupId>
                <artifactId>springfox-swagger-uiartifactId>
                <version>2.9.2version>
            dependency>
    
    		<dependency>
    			<groupId>org.springframework.bootgroupId>
    			<artifactId>spring-boot-starter-webartifactId>
    		dependency>
    
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
    
    		<dependency>
    			<groupId>org.springframework.bootgroupId>
    			<artifactId>spring-boot-starter-testartifactId>
    			<scope>testscope>
    		dependency>
    	dependencies>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.bootgroupId>
    				<artifactId>spring-boot-maven-pluginartifactId>
    			plugin>
    		plugins>
    	build>
    
    project>
    
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    三、knife4j介绍

    knife4j是为Java MVC框架 集成Swagger生成Api文档的增强解决方案 ,前身是swagger-bootstrap-ui,取名knife4j是希望它能像一把匕首一样小巧、轻量,并且功能强悍。其底层是对Springfox的封装,使用方式也和Springfox一致,只是对接口文档UI进行了优化。
    核心功能:

    • 文档说明:根据Swagger的规范说明,详细列出接口文档的说明,包括接口地址、类型、请求示例、请求参数、响应示例、响应参数、响应码等信息,对该接口的使用情况一目了然。

    • 在线调试:提供在线接口联调的强大功能,自动解析当前接口参数,同时包含表单验证,调用参数可返回接口响应内容、headers、响应时间、响应状态码等信息,帮助开发者在线调试。

    四、springboot-knife4j 实战演练

    1. 快速创建项目

    1. 项目细节
      在这里插入图片描述
    2. 插件,选择web和Lombok(上一篇博文讲的)(这里的版本,创建完项目后,我手动改成了2.7.2)
      在这里插入图片描述

    2. 引入依赖

    我们通过查看依赖关系发现,knife4j内部已经集成了 springfox-swagger2

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

    3. 创建实体类 UserReqVO 和 MenuReqVO

    a、UserReqVO.java

    package com.feng.springBoot_knife4j.vo.req;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ApiModel(description = "用户实体")
    public class UserReqVO {
    
        @ApiModelProperty(value = "名字")
        private String name;
    
        @ApiModelProperty(value = "年龄")
        private Integer age;
    
        @ApiModelProperty(value = "电话")
        private String phone;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    b、MenuReqVO.java

    package com.feng.springBoot_knife4j.vo.req;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ApiModel(description = "菜单实体")
    public class MenuReqVO {
        @ApiModelProperty(value = "主键")
        private int id;
        @ApiModelProperty(value = "菜单名称")
        private String name;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4. 创建user.controller

    a、user/UserController

    package com.feng.springBoot_knife4j.controller.user;
    
    import com.feng.springBoot_knife4j.vo.req.UserReqVO;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiImplicitParam;
    import io.swagger.annotations.ApiImplicitParams;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @RestController
    @RequestMapping("/api/user")
    @Api(tags = "用户模块")
    public class UserController {
    
        @GetMapping("/getUsers")
        @ApiOperation(value = "查询所有用户", notes = "查询所有用户信息")
        public List<UserReqVO> getUser(){
            UserReqVO user = new UserReqVO();
            user.setAge(23);
            user.setName("冯坚持");
            user.setPhone("15106757434");
            List<UserReqVO> list = new ArrayList<>();
            list.add(user);
            return list;
        }
    
        @PostMapping("/user/list")
        @ApiOperation(value = "查询用户", notes = "查询用户信息")
        public UserReqVO getUser(@RequestBody UserReqVO user){
            return user;
        }
    
        @PutMapping("/update")
        @ApiOperation(value = "修改用户", notes = "修改用户信息")
        public String update(@RequestBody UserReqVO user){
            return "OK";
        }
    
        @DeleteMapping("/delete")
        @ApiOperation(value = "删除用户", notes = "删除用户信息")
        public String delete(int id){
            return "OK";
        }
    
        @ApiImplicitParams({
                @ApiImplicitParam(name = "pageNum", value = "页码",
                        required = true, type = "Integer"),
                @ApiImplicitParam(name = "pageSize", value = "每页条数",
                        required = true, type = "Integer"),
        })
        @ApiOperation(value = "分页查询用户信息")
        @GetMapping(value = "page/{pageNum}/{pageSize}")
        public String findByPage(@PathVariable Integer pageNum,
                                 @PathVariable Integer pageSize) {
            return "OK";
        }
    }
    
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    b、menu/MenuController

    package com.feng.springBoot_knife4j.controller.menu;
    
    import com.feng.springBoot_knife4j.vo.req.MenuReqVO;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiImplicitParam;
    import io.swagger.annotations.ApiImplicitParams;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @RestController
    @RequestMapping("/api/menu")
    @Api(tags = "菜单模块")
    public class MenuController {
    
        @GetMapping("/getMenus")
        @ApiOperation(value = "查询所有菜单", notes = "查询所有菜单信息")
        public List<MenuReqVO> getMenus(){
            MenuReqVO menu = new MenuReqVO();
            menu.setId(100);
            menu.setName("feng");
            List<MenuReqVO> list = new ArrayList<>();
            list.add(menu);
            return list;
        }
    
        @PostMapping("/save")
        @ApiOperation(value = "新增菜单", notes = "新增菜单信息")
        public String save(@RequestBody MenuReqVO menu){
            return "OK";
        }
    
        @PutMapping("/update")
        @ApiOperation(value = "修改菜单", notes = "修改菜单信息")
        public String update(@RequestBody MenuReqVO menu){
            return "OK";
        }
    
        @DeleteMapping("/delete")
        @ApiOperation(value = "删除菜单", notes = "删除菜单信息")
        public String delete(int id){
            return "OK";
        }
    
        @ApiImplicitParams({
                @ApiImplicitParam(name = "pageNum", value = "页码", required = true, type = "Integer"),
                @ApiImplicitParam(name = "pageSize", value = "每页条数", required = true, type = "Integer"),
        })
        @ApiOperation(value = "分页查询菜单信息")
        @GetMapping(value = "page/{pageNum}/{pageSize}")
        public String findByPage(@PathVariable Integer pageNum, @PathVariable Integer pageSize) {
            return "OK";
        }
    }
    
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    5. 创建属性配置类SwaggerProperties

    创建配置属性类SwaggerProperties,相比于之前我们对swagger的直接在配置文件中写死,这样可以对接口文档进行灵活的配置,这样我们直接可以通过在application.yml中进行接口文档的配置分组以及不分组。

    package com.feng.springBoot_knife4j.config;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    import java.util.ArrayList;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    
    /*
     * 配置属性类,用于封装接口文档相关属性,从配置文件读取信息封装成当前对象
     */
    @Data
    @ConfigurationProperties(prefix = "feng.swagger")
    public class SwaggerProperties {
        private String title;            // 标题 interface document
        private String group = "";       // 自定义组名
        private String description;      // 描述 this is a interface document
        private String version;          // 版本 1.0
        private Contact contact = new Contact(); //联系人
        private String basePackage;      // swagger会解析的包路径: com.feng.springBoot_knife4j
        private Map<String, DocketInfo> docket = new HashMap<>(); //分组文档
        private List<String> basePath = new ArrayList<>(); // swagger 会解析的url规则
        private List<String> excludePath = new ArrayList<>();//在basePath基础上需要排除的url规则
    
        public String getGroup() {
            if (group == null || "".equals(group)) {
                return title;
            }
            return group;
        }
        @Data
        public static class DocketInfo {
            // 下面这三个走的时配置文件
            private String title;       //标题
            private String group;       //自定义组名
            private String basePackage; //swagger会解析的包路径
    
            // 下面的是默认的,多出来的字段
            private String description = "在线文档"; //描述
            private String version = "1.0"; //版本
            private Contact contact = new Contact(); //联系人
            private List<String> basePath = new ArrayList<>(); //swagger会解析的url规则
            private List<String> excludePath = new ArrayList<>();//在basePath基础上需要排除的url
            public String getGroup() {
                if (group == null || "".equals(group)) {
                    return title;
                }
                return group;
            }
        }
        @Data
        public static class Contact {
            private String name = "FengJianChi"; //联系人
            private String url = ""; //联系人url
            private String email = ""; //联系人email
        }
    }
    
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    6. application.yml

    server:
      port: 7788
    
    # 配置 swagger2 knife4j
    spring:
      mvc:
        pathmatch:
          # 配置策略
          matching-strategy: ant-path-matcher
    
    # swagger 配置
    feng:
      swagger:
        title: interface document   # 接口文档
        description: this is a interface document # 这是接口文档
        version: 1.0
        basePackage: com.feng.springBoot_knife4j
        enabled: true   # 是否启用 swagger
        docket:         # 对接口文档进行分组,不写则不进行分组,我们在 SwaggerProperties 定义 docket 为 Map
          user:         # user接口文档组
            title: user_module #  用户模块
            group: user_module_group # 用户模块组
            base-package: com.feng.springBoot_knife4j.controller.user
          menu:         # menu接口文档组
            title: menu_module # 菜单模块
            group: menu_module_group # 菜单模块组
            base-package: com.feng.springBoot_knife4j.controller.menu
    
    • 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

    7. 创建配置类SwaggerAutoConfiguration(认真读)

    package com.feng.springBoot_knife4j.config;
    
    import com.google.common.base.Predicate;
    import com.google.common.base.Predicates;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.config.ConfigurableBeanFactory;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.service.Contact;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    import java.util.ArrayList;
    import java.util.LinkedList;
    import java.util.List;
    
    @Configuration
    // swagger开关,这里表示 feng.swagger.enabled为true,即我们在 application.yml 中配置 feng.swagger.enabled: true才会启用,
    // matchIfMissing = true 表示不写则默认为true
    @ConditionalOnProperty(name = "feng.swagger.enabled", havingValue = "true",
            matchIfMissing = true)
    // 启用swagger
    @EnableSwagger2
    // 指定配置属性类
    @EnableConfigurationProperties(SwaggerProperties.class)
    public class SwaggerAutoConfiguration implements BeanFactoryAware {
    
        @Autowired
        private SwaggerProperties swaggerProperties;
    
        private BeanFactory beanFactory;
    
        @Bean
        @ConditionalOnMissingBean
        // 接口文档不分组则list为1个,分组则为多个
        public List<Docket> createRestApi(){
            // 强转为可配置的bean工厂
            ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;
            // 创建一个容器
            List<Docket> docketList = new LinkedList<>();
    
            // 如果:没有分组,则走 默认接口文档
            if (swaggerProperties.getDocket().isEmpty()) {
                Docket docket = createDocket(swaggerProperties);
                // 注册为单例对象,通过bean工厂来进行管理,使用 title 作为key,value 为 docket 接口文档对象
                configurableBeanFactory.registerSingleton(swaggerProperties.getTitle(), docket);
                docketList.add(docket);
                return docketList;
            }
    
            // 否则:分组创建,遍历
            for (String groupName : swaggerProperties.getDocket().keySet()){
                SwaggerProperties.DocketInfo docketInfo = swaggerProperties.getDocket().get(groupName);
                ApiInfo apiInfo = new ApiInfoBuilder()
                        //页面标题
                        .title(docketInfo.getTitle())
                        //创建人
                        .contact(new Contact(docketInfo.getContact().getName(),
                                docketInfo.getContact().getUrl(),
                                docketInfo.getContact().getEmail()))
                        //版本号
                        .version(docketInfo.getVersion())
                        //描述
                        .description(docketInfo.getDescription())
                        .build();
    
                // base-path处理
                // 当没有配置任何path的时候,解析/**
                if (docketInfo.getBasePath().isEmpty()) {
                    docketInfo.getBasePath().add("/**");
                }
    
                List<Predicate<String>> basePath = new ArrayList<>();
                for (String path : docketInfo.getBasePath()) {
                    basePath.add(PathSelectors.ant(path));
                }
    
                // exclude-path处理,
                List<Predicate<String>> excludePath = new ArrayList<>();
                for (String path : docketInfo.getExcludePath()) {
                    excludePath.add(PathSelectors.ant(path));
                }
    
                Docket docket = new Docket(DocumentationType.SWAGGER_2)
                        .apiInfo(apiInfo)
                        .groupName(docketInfo.getGroup())
                        .select()
                        //为当前包路径
                        .apis(RequestHandlerSelectors.basePackage(docketInfo.getBasePackage()))
                        .paths(Predicates.and(Predicates.not(Predicates.or(excludePath)),Predicates.or(basePath)))
                        .build();
                // 注册为单例对象,通过bean工厂来进行管理,使用title作为key,value为docket接口文档对象
                configurableBeanFactory.registerSingleton(groupName, docket);
                // 添加
                docketList.add(docket);
            }
            return docketList;
        }
    
        //构建 api文档的详细信息
        private ApiInfo apiInfo(SwaggerProperties swaggerProperties) {
            return new ApiInfoBuilder()
                    //页面标题
                    .title(swaggerProperties.getTitle())
                    //创建人
                    .contact(new Contact(swaggerProperties.getContact().getName(),
                            swaggerProperties.getContact().getUrl(),
                            swaggerProperties.getContact().getEmail()))
                    //版本号
                    .version(swaggerProperties.getVersion())
                    //描述
                    .description(swaggerProperties.getDescription())
                    .build();
        }
    
        //创建 默认接口文档 对象
        private Docket createDocket(SwaggerProperties swaggerProperties) {
            //API 基础信息
            ApiInfo apiInfo = apiInfo(swaggerProperties);
    
            // base-path处理
            // 当没有配置任何path的时候,解析/**
            if (swaggerProperties.getBasePath().isEmpty()) {
                swaggerProperties.getBasePath().add("/**");
            }
            List<Predicate<String>> basePath = new ArrayList<>();
            for (String path : swaggerProperties.getBasePath()) {
                basePath.add(PathSelectors.ant(path));
            }
    
            // exclude-path处理
            List<Predicate<String>> excludePath = new ArrayList<>();
            for (String path : swaggerProperties.getExcludePath()) {
                excludePath.add(PathSelectors.ant(path));
            }
    
            return new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(apiInfo)
                    .groupName(swaggerProperties.getGroup())
                    .select()
                    .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
                    .paths(Predicates.and(Predicates.not(Predicates.or(excludePath)),Predicates.or(basePath)))
                    .build();
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            // 获取bean工厂对象
            this.beanFactory = beanFactory;
        }
    }
    
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163

    8. 启动项目/测试

    1. 执行启动类main方法启动项目
    2. 访问地址:http://localhost:7788/doc.html
      在这里插入图片描述
    3. 之后我们可以对api接口进行调试,如删除用户调试,
      在这里插入图片描述

    9. 不分组,修改 application.yml

    server:
      port: 7788
    pinda:
      swagger:
        enabled: true #是否启用swagger
        title: test模块
        base-package: cn.itcast.controller
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    再次访问地址:http://localhost:7788/doc.html
    在这里插入图片描述
    可以看到所有的接口在一个分组中。

    4. 定制starter(一个小的技术点)

    这里就不讲了,送上博文,最下面就是定制start
    https://blog.csdn.net/qq_45745964/article/details/122525640

    项目结构

  • 相关阅读:
    【博客489】prometheus-----PromQL数据类型与Metrics数据类型
    第三章 队列
    mybatis查询PostgreSQL报错:无法确定参数 $1 的数据类型
    各省GDP可视化案列,附带csv Metabase处理
    node-sass安装报错
    消除注释C++
    Day711. 档案类-Java8后最重要新特性
    Spring Security(3)
    RabbitMQ学习笔记(二)SpringAMQP的使用、消息转换器
    linux 系统安装 or-tools 并在c++ 项目中使用
  • 原文地址:https://blog.csdn.net/qq_40036754/article/details/126437823