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

简介: 这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。

导言

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 依赖

        <!--swagger2 依赖-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

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
    

    ```

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

}

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;

}

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

8. 项目结构

在这里插入图片描述

9. 测试结构

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

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

10. pom.xml(全)

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.feng</groupId>
    <artifactId>springboot_swagger2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot_swagger2</name>
    <description>springboot_swagger2 project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>

        <!--swagger2 依赖-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

三、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

        <!-- API 文档,knife4j依赖 -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>2.0.4</version>
        </dependency>

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

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

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

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

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

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<String, DocketInfo>
      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

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

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

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

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

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

项目结构

相关文章
|
1天前
|
编解码 Java 程序员
写代码还有专业的编程显示器?
写代码已经十个年头了, 一直都是习惯直接用一台Mac电脑写代码 偶尔接一个显示器, 但是可能因为公司配的显示器不怎么样, 还要接转接头 搞得桌面杂乱无章,分辨率也低,感觉屏幕还是Mac自带的看着舒服
|
3天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1540 5
|
1月前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
7天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
577 22
|
3天前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
201 3
|
10天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
10天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
571 5
|
23天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
6天前
|
XML 安全 Java
【Maven】依赖管理,Maven仓库,Maven核心功能
【Maven】依赖管理,Maven仓库,Maven核心功能
233 3
|
9天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
327 2