哈喽,小伙伴们,晚上好,距离上一次更新文章已经是`2021年1月份`了,停更了3个月的时间,这么久实在是感到抱歉,尤其对于那些付费的朋友们更是心里过意不去,其实停更这一段时间我一直在准备换工作,复习面试题,现在也成功入职了一家新的互联网公司,前面一段时间稍微忙了一些,就没有精力去更新这些文章了,其实要写的还蛮多,准备后面持续的输出给大家,同时希望自己通过写一些技术文章能给一些朋友们带来一点点的帮助,其次也是对自己技术探索之路的一个总结与提升,相信一直沉淀下去大家都会有所收获的,加油!
# 一、前言
做架构一直是我的职业目标,我喜欢在探索一门技术解决某个问题后带给我的成就感,所以业余时间自己会花一些时间研究基本框架的搭建和封装,学习里面的思想,今天主要总结一下SpringBoot封装企业通用Swagger的一些配置,避免冗余的配置文件产生。
# 二、背景
不知道大家有没有遇到过这种场景,就是当你在公司需要开启一个新项目的时候,如果使用到了`API Swagger`工具,那么你肯定需要去整合`Swagger`,产生一个叫做`SwaggerConfig`的配置文件。如果一个微服务项目被划分为多个粒度的子服务,可能每个服务都会Copy一份这样的配置到具体的服务工程里,这样很冗余。这时候我们可以考虑将`Swagger`与`Spring`整合的常用配置封装成一个`Starter`,每次当我们新开启一个项目的时候,不需要再去做这些重复的工作了,我们只需要引入我们封装好的`Starter`依赖,然后在`application.yml`中配置一些参数和启用开关即可。
- **项目完整目录**
![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/20210419222000223.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1RoaW5raW5nY2Fv,size_16,color_FFFFFF,t_70)
# 三、环境搭建
## 1. pom.xml
```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.3.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.swagger</groupId>
<artifactId>swagger-spring-boot-strater</artifactId>
<version>0.0.5-SNAPSHOT</version>
<name>swagger-spring-boot-strater</name>
<description>swagger-spring-boot-strater project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- processor 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- swagger2依赖 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- swagger-ui依赖 -->
<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-autoconfigure</artifactId>
</dependency>
</dependencies>
</project>
```
# 四、封装swagger-spring-boot-starter
## 1. 封装SwaggerProperties属性
`@value`: 用于读取`applicatoon.yml`中的属性值,左侧为读取的值,这里的值需要我们在引入我们封装好的`Starter`依赖时在`aplication.yml`中配置对应的字段信息,右侧使用冒号隔开的为读取不到时的默认值。
```java
/**
* @desc: SwaggerProperties
* @author: cao_wencao
* @date: 2021-03-24 15:54
*/
@Slf4j
@Getter
@Setter
@ConfigurationProperties(prefix = SwaggerProperties.PREFIX)
public class SwaggerProperties {
public static final String PREFIX = "project.swagger";
//启用、禁用
@Value("${project.swagger.enable:true}")
private boolean enable;
//接口title文档
@Value("${project.swagger.title:XXX平台标准API接口Doc}")
private String title;
//接口desc介绍
@Value("${project.swagger.desc:标准restfull风格API接口文档}")
private String desc;
//版本号
@Value("${project.swagger.version:1.0}")
private String version;
//文档扫描包路径
@Value("${project.swagger.basePackage:com.thinkingcao}")
private String basePackage;
}
```
## 2. 编写SwaggerConfig配置
```java
/**
* @desc: swagger自动配置类
* @author: cao_wencao
* @date: 2021-03-24 15:54
*/
@Slf4j
@EnableSwagger2
@AllArgsConstructor
@Configuration
@EnableConfigurationProperties(SwaggerProperties.class)
@ConditionalOnClass({Docket.class, ApiInfo.class})
@ConditionalOnProperty(prefix = SwaggerProperties.PREFIX, name = "enable", havingValue = "true", matchIfMissing = true)
@Profile({"dev","test","uat","pro"}) //通过spring.active激活某个环境
public class SwaggerAutoConfiguration implements WebMvcConfigurer {
private final SwaggerProperties properties;
@Bean
public Docket apiConfig() {
return new Docket(DocumentationType.SWAGGER_2)
.enable(properties.isEnable())
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage(properties.getBasePackage()))
.paths(PathSelectors.any())
.build();
}
//构建api文档的详细信息
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(properties.getTitle()) //页面标题
.description(properties.getDesc()) //描述
.termsOfServiceUrl("") //url
.version(properties.getVersion()) //版本号
.build();
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(new String[]{"/static/**"}).addResourceLocations(new String[]{"classpath:/static/"});
registry.addResourceHandler(new String[]{"swagger-ui.html"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/"});
registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"});
}
}
```
## 3. 配置自动配置类的读取位置
这一步很重要,首先我们需要在`resources`下面新建`META-INF`文件夹,然后再`META-INF`文件夹下面新建一个叫做`spring.factories`的文件,在`spring.factories`中配置以下信息:
- **spring.factories**
```yaml
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.swagger.autoconfigure.SwaggerAutoConfiguration
```
`org.springframework.boot.autoconfigure.EnableAutoConfiguration`为`SpringBoot`提供给开发者读取封装的自动配置类的一个`Spring`类,在`=`后面写入`SwaggerAutoConfiguration`的完整类路径,如果有多个`xxxxAutoConfiguration`自动配置类,就使用逗号分隔,然后换行的话使用`\`表示即可。
## 4. 配置application.yml文件提示
同样的,想要实现在`application.yml`编写配置文件时候有我们封装的上述字段属性的一个提示信息,我们科室可以实现的,首先需要在`resources-META-INF`下面新建一个文件名为`spring-configuration-metadata.json`的文件,然后按照模板编辑以下信息:
- **spring-configuration-metadata.json**
```json
{"properties": [
{
"name": "project.swagger.enable",
"type": "java.lang.Boolean",
"description": "文档开关"
},
{
"name": "project.swagger.basePackage",
"type": "java.lang.String",
"description": "文档扫描包路径。"
},
{
"name": "project.swagger.title",
"type": "java.lang.String",
"defaultValue": "平台系统接口详情",
"description": "title 如: 用户模块系统接口详情。"
},
{
"name": "project.swagger.desc",
"type": "java.lang.String",
"defaultValue": "在线文档",
"description": "服务文件介绍。"
},
{
"name": "project.swagger.version",
"type": "java.lang.String",
"defaultValue": "V1.0",
"description": "版本。"
}
]}
```
## 5. application.yml(可选的)
```yaml
#端口号
server:
port: 8338
#Swagger配置信息
project:
swagger:
#启用、禁用
enable: false
#标题
title:
#描述
desc:
#版本
version:
#basePackage
basePackage:
```
# 五、打包到本地Maven仓库
上面步骤都完成后,接下来的一步就是需要将这个工程打包到`Maven`仓库了,如果你是封装给公司使用,直接打入公司内部搭建的`Maven`私服仓库即可,没有私服仓库也不要紧,打入我们自己的`Maven`本地仓库中也是可以的。
打包到本地仓库可以使用IDEA中的Maven插件,这里我选择命令行手敲: `mvn clean install`
![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/20210419222322939.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1RoaW5raW5nY2Fv,size_16,color_FFFFFF,t_70)
Jar包打到本地仓库的Jar包存储位置:
![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/2021041922272480.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1RoaW5raW5nY2Fv,size_16,color_FFFFFF,t_70)
# 六、验证swagger-spring-boot-starter可用性
上面封装完了Starter之后,我们需要新建一个demo项目来引入依赖验证封装的Swagger是否正确,依赖如下:
```xml
<!-- 自身封装的swagger -->
<dependency>
<groupId>com.swagger</groupId>
<artifactId>swagger-spring-boot-strater</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
```
## 1. 创建一个springboot-swagger-demo项目![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/20210419223311755.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1RoaW5raW5nY2Fv,size_16,color_FFFFFF,t_70)
- **pom.xml完整依赖信息**
```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>
<groupId>com.thinkingcao</groupId>
<artifactId>springboot-swagger-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-swagger-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties>
<dependencies>
<!-- 自身封装的swagger -->
<dependency>
<groupId>com.swagger</groupId>
<artifactId>swagger-spring-boot-strater</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>compile</scope>
</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>
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<configuration>
<mainClass>com.thinkingcao.SwaggerDemoApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
```
## 2. application.yml
```yaml
#应用程序名称
spring:
application:
name: springboot-swagger-demo
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/swagger-api-demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
profiles:
active: dev
#MyBatis-Plus配置
mybatis-plus:
configuration:
#是否开启自动驼峰命名规则(camel case)映射,# 该参数不能和mybatis-plus.config-location同时存在
map-underscore-to-camel-case: true
##全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为 true。
cache-enabled: false
auto-mapping-behavior: full
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#指定mapper对应xml文件位置
mapper-locations: classpath*:mapper/**/*Mapper.xml
#指定别名实体类扫描路径
type-aliases-package: com.thinkingcao.entity
#扫描枚举类 # 支持统配符 * 或者 ; 分割
type-enums-package: com.thinkingcao.enums
global-config:
# 逻辑删除配置
db-config:
#逻辑未删除值,默认为0
logic-not-delete-value: 0
#逻辑已删除值,默认为1
logic-delete-value: 1
#全局逻辑删除实体字段名
logic-delete-field: deleted
#设置全局主键生成策略
id-type: auto
#全局表名配置,前缀
table-prefix: t_
#Swagger配置信息
project:
swagger:
#启用、禁用
enable: true
#标题
title: SpringBoot整合Swagger构建Api文档
#描述
desc: 简单优雅的restfull风格接口文档
#版本
version: 1.0.0
#扫包配置
base-package: com.thinkingcao.controller
```
## 3. Controller
```java
package com.thinkingcao.controller;
import com.thinkingcao.enums.ErrorCode;
import com.thinkingcao.entity.User;
import com.thinkingcao.result.BaseResult;
import com.thinkingcao.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @desc:
* @author: cao_wencao
* @date: 2021-04-18 12:58
*/
@RequestMapping("/user/api")
@RestController
@Api(value = "用户信息API接口",tags="用户信息API接口实现")
@Slf4j
public class UserController {
@Autowired
private UserService userService;
/**
* 查询多个
* @return
*/
@GetMapping("/selectListUser")
@ApiOperation(value = "查询批量用户")
public BaseResult selectListUser(){
List<User> userList = userService.selectListUser();
return BaseResult.success(userList);
}
/**
* 查询单个
* @return
*/
@GetMapping("/selectOneUser/{id}")
@ApiOperation(value = "查询单个用户")
public BaseResult selectOneUser(@PathVariable("id") String id){
User user = userService.selectOneUser(id);
return BaseResult.success(user);
}
/**
* 增加
* @return
*/
@PostMapping("/insertUser")
@ApiOperation(value = "新增用户")
public BaseResult insertUser(@RequestBody User user){
Boolean result = userService.insertUser(user);
if (result){
return BaseResult.success(result);
}
return BaseResult.error(ErrorCode.DB_ERROR);
}
/**
* 修改
* @return
*/
@PostMapping("/updateUser")
@ApiOperation(value = "修改用户")
public BaseResult updateUser(@RequestBody User user){
Boolean result = userService.updateUser(user);
if (result){
return BaseResult.success(result);
}
return BaseResult.error(ErrorCode.DB_ERROR);
}
/**
* 删除
* @return
*/
@PostMapping("/deleteUser/{id}")
@ApiOperation(value = "删除用户")
public BaseResult deleteUser(@PathVariable("id") String id){
Boolean result = userService.deleteUser(id);
if (result){
return BaseResult.success(result);
}
return BaseResult.error(ErrorCode.DB_ERROR);
}
}
```
## 4. 查看依赖的swagger-spring-boot-strater
![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/2021041922372747.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1RoaW5raW5nY2Fv,size_16,color_FFFFFF,t_70)
# 七、访问Swagger接口地址
- **Swagger访问地址**
| 类型 | 地址 |
| ---- | ---- |
| Swagger Mapped URL | http://127.0.0.1:8080//v2/api-docs |
| swagger-ui | http://127.0.0.1:8080/swagger-ui.html#/ |
- **访问`swagger-ui | http://127.0.0.1:8080/swagger-ui.html#/`如下**
![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/20210419224042841.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1RoaW5raW5nY2Fv,size_16,color_FFFFFF,t_70)
# 八、坑点记录
问题1:
`java.lang.IllegalStateException: Unable to read meta-data for class com.swagger.autoconfigure.SwaggerAutoConfiguration`
和
`Caused by: java.io.FileNotFoundException: class path resource [com/swagger/autoconfigure/SwaggerAutoConfiguration.class] cannot be opened because it does not exist`
- 解决方式: [https://www.freesion.com/article/63921387453/](https://www.freesion.com/article/63921387453/)