新增:新增接口文档配置(基于 Spring Doc OpenAPI,使用 Knife4j 作为增强解决方案)

This commit is contained in:
Charles7c 2022-12-11 21:56:18 +08:00
parent 1e5eaab9d3
commit 79891e8b5a
13 changed files with 366 additions and 44 deletions
README.md
continew-admin-common
pom.xml
src/main/java/top/charles7c/cnadmin/common
continew-admin-system/src/main/java/top/charles7c/cnadmin/auth/model/vo
continew-admin-webapi/src/main
pom.xml

View File

@ -9,15 +9,16 @@ ContiNew-Admin (incubating) 中后台管理框架Continue New Admin持续
### 技术栈
| 名称 | 版本 | 简介 |
| :----------------------------------------------------------- | :----------- | :----------------------------------------------------------- |
| [Spring Boot](https://spring.io/projects/spring-boot) | 2.7.6 | 简化新 Spring 应用的初始搭建以及开发过程。 |
| [Undertow](https://undertow.io/) | 2.2.20.Final | 采用 Java 开发的灵活的高性能 Web 服务器,提供包括阻塞和基于 NIO 的非堵塞机制。 |
| [Redis](https://redis.io/) | 6.2.7 | 高性能的 key-value 数据库。 |
| [Redisson](https://github.com/redisson/redisson/wiki/Redisson%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D) | 3.18.1 | 不仅仅是一个 Redis Java 客户端,同其他 Redis Java 客户端有着很大的区别,相比之下其他客户端提供的功能还仅仅停留在作为数据库驱动层面上,比如仅针对 Redis 提供连接方式,发送命令和处理返回结果等。而 Redisson 充分的利用了 Redis 键值数据库提供的一系列优势,基于 Java 实用工具包中常用接口,为使用者提供了一系列具有分布式特性的常用工具类。使得原本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式系统的难度。同时结合各富特色的分布式服务,更进一步简化了分布式环境中程序相互之间的协作。 |
| Easy Captcha | 1.6.2 | Java 图形验证码,支持 gif、中文、算术等类型可用于 Java Web、JavaSE 等项目。 |
| [Hutool](https://www.hutool.cn/) | 5.8.10 | 小而全的 Java 工具类库,通过静态方法封装,降低相关 API 的学习成本,提高工作效率,使 Java 拥有函数式语言般的优雅,让 Java 语言也可以“甜甜的”。 |
| [Lombok](https://projectlombok.org/) | 1.18.24 | 在 Java 开发过程中用注解的方式,简化了 JavaBean 的编写,避免了冗余和样板式代码,让编写的类更加简洁。 |
| 名称 | 版本 | 简介 |
| :----------------------------------------------------------- | :------------- | :----------------------------------------------------------- |
| [Spring Boot](https://spring.io/projects/spring-boot) | 2.7.6 | 简化新 Spring 应用的初始搭建以及开发过程。 |
| [Undertow](https://undertow.io/) | 2.2.20.Final | 采用 Java 开发的灵活的高性能 Web 服务器,提供包括阻塞和基于 NIO 的非堵塞机制。 |
| [Redis](https://redis.io/) | 6.2.7 | 高性能的 key-value 数据库。 |
| [Redisson](https://github.com/redisson/redisson/wiki/Redisson%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D) | 3.18.1 | 不仅仅是一个 Redis Java 客户端,同其他 Redis Java 客户端有着很大的区别,相比之下其他客户端提供的功能还仅仅停留在作为数据库驱动层面上,比如仅针对 Redis 提供连接方式,发送命令和处理返回结果等。而 Redisson 充分的利用了 Redis 键值数据库提供的一系列优势,基于 Java 实用工具包中常用接口,为使用者提供了一系列具有分布式特性的常用工具类。使得原本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式系统的难度。同时结合各富特色的分布式服务,更进一步简化了分布式环境中程序相互之间的协作。 |
| Easy Captcha | 1.6.2 | Java 图形验证码,支持 gif、中文、算术等类型可用于 Java Web、JavaSE 等项目。 |
| [Knife4j](https://doc.xiaominfo.com/) | 4.0.0-SNAPSHOT | 前身是 swagger-bootstrap-ui集 Swagger2 和 OpenAPI3 为一体的增强解决方案。本项目使用的是 [knife4j-openapi3-spring-boot-starter](https://gitee.com/xiaoym/swagger-bootstrap-ui-demo/tree/master/knife4j-springdoc-openapi-demo) 基于 OpenAPI3 规范,在 Spring Boot < 3.0.0-M1 的单体架构下可以直接引用此 starter该模块包含了 UI 部分底层基于 springdoc-openapi 项目 |
| [Hutool](https://www.hutool.cn/) | 5.8.10 | 小而全的 Java 工具类库,通过静态方法封装,降低相关 API 的学习成本,提高工作效率,使 Java 拥有函数式语言般的优雅,让 Java 语言也可以“甜甜的”。 |
| [Lombok](https://projectlombok.org/) | 1.18.24 | 在 Java 开发过程中用注解的方式,简化了 JavaBean 的编写,避免了冗余和样板式代码,让编写的类更加简洁。 |
### 项目结构
@ -41,30 +42,31 @@ continew-admin 全局通用项目配置及依赖版本管理
│ │ │ │ └─ContinewAdminApplication.java 启动入口
│ │ │ ├─resources 工程配置目录
├─continew-admin-system 系统管理模块(存放系统管理模块相关功能,例如:部门管理、角色管理、用户管理等)
│ ├─src 工程源文件代码目录
│ ├─src
│ │ ├─main
│ │ │ ├─java
│ │ │ ├─java 工程源文件代码目录
│ │ │ │ └─top
│ │ │ │ └─charles7c
│ │ │ │ └─cnadmin
│ │ │ │ └─auth 认证相关业务及配置
│ │ │ │ └─config 认证相关配置
│ │ │ │ └─properties 配置属性
│ │ │ │ └─properties 认证相关配置属性
│ │ │ │ └─model 认证相关模型
│ │ │ │ └─vo 认证相关 VOView Object
├─continew-admin-common 公共模块(存放公共工具类,公共配置等)
│ ├─src 工程源文件代码目录
│ ├─src
│ │ ├─main
│ │ │ ├─java
│ │ │ ├─java 工程源文件代码目录
│ │ │ │ └─top
│ │ │ │ └─charles7c
│ │ │ │ └─cnadmin
│ │ │ │ └─common
│ │ │ │ └─config 公共配置
│ │ │ │ └─jackson Jackson 配置
│ │ │ │ └─model 公共模型
│ │ │ │ └─vo 公共 VOView Object
│ │ │ │ └─util 公共工具类
│ │ │ │ └─config 公共配置
│ │ │ │ └─jackson Jackson 配置
│ │ │ │ └─properties 公共配置属性
│ │ │ │ └─model 公共模型
│ │ │ │ └─vo 公共 VOView Object
│ │ │ │ └─util 公共工具类
```
### License

View File

@ -60,6 +60,17 @@ limitations under the License.
</dependency>
<!-- ################ 工具库相关 ################ -->
<!-- Knife4j前身是 swagger-bootstrap-ui集 Swagger2 和 OpenAPI3 为一体的增强解决方案) -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
</dependency>
<!-- Spring Doc OpenAPI可以结合 Spring Boot 使用的,基于 OpenAPI3 的 API 文档生成工具) -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
</dependency>
<!-- Redisson不仅仅是一个 Redis Java 客户端) -->
<dependency>
<groupId>org.redisson</groupId>

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.common.config;
import java.util.HashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import cn.hutool.core.util.RandomUtil;
import top.charles7c.cnadmin.common.config.properties.ContinewAdminProperties;
/**
* 接口文档配置
*
* @author Charles7c
* @since 2022/12/11 19:14
*/
@Configuration
@RequiredArgsConstructor
@ConditionalOnProperty(name = "springdoc.swagger-ui.enabled", havingValue = "true", matchIfMissing = true)
public class SwaggerConfiguration {
private final ContinewAdminProperties continewAdminProperties;
/**
* 接口文档配置
*/
@Bean
public OpenAPI openAPI() {
return new OpenAPI().info(
new Info().title(continewAdminProperties.getName() + " 接口文档").version(continewAdminProperties.getVersion())
.description(continewAdminProperties.getDescription()).termsOfService(continewAdminProperties.getUrl())
.contact(continewAdminProperties.getAuthor()).license(continewAdminProperties.getLicense()));
}
/**
* 根据 @Tag 上的排序写入 x-order
*
* @return the global open api customizer
*/
@Bean
public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() {
return openApi -> {
if (openApi.getTags() != null) {
openApi.getTags().forEach(tag -> {
Map<String, Object> map = new HashMap<>();
map.put("x-order", RandomUtil.randomInt(0, 100));
tag.setExtensions(map);
});
}
};
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.common.config;
import java.util.concurrent.TimeUnit;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Web MVC 配置
*
* @author Charles7c
* @since 2022/12/11 19:40
*/
@EnableWebMvc
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
/**
* 静态资源处理器配置
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCacheControl(CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic());
}
/**
* 跨域配置
*/
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setMaxAge(1800L);
// 允许跨域配置
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
// 添加映射路径拦截一切请求
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.charles7c.cnadmin.common.config.properties;
import lombok.Data;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.License;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.stereotype.Component;
/**
* 项目配置属性
*
* @author Charles7c
* @since 2022/12/11 19:26
*/
@Data
@Component
@ConfigurationProperties(prefix = "continew-admin")
public class ContinewAdminProperties {
/**
* 名称
*/
private String name;
/**
* 应用名称
*/
private String appName;
/**
* 版本
*/
private String version;
/**
* 描述
*/
private String description;
/**
* URL
*/
private String url;
/**
* 作者信息
*/
@NestedConfigurationProperty
private Contact author;
/**
* 许可协议信息
*/
@NestedConfigurationProperty
private License license;
}

View File

@ -23,6 +23,8 @@ import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.http.HttpStatus;
import com.fasterxml.jackson.annotation.JsonFormat;
@ -35,19 +37,29 @@ import com.fasterxml.jackson.annotation.JsonFormat;
*/
@Data
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Schema(description = "响应信息")
public class R<V extends Serializable> implements Serializable {
private static final long serialVersionUID = 1L;
/** 是否成功 */
@Schema(description = "是否成功")
private boolean success;
/** 状态码 */
@Schema(description = "状态码")
private int code;
/** 状态信息 */
@Schema(description = "状态信息")
private String msg;
/** 返回数据 */
@Schema(description = "返回数据")
private V data;
/** 时间戳 */
@Schema(description = "时间戳")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime timestamp = LocalDateTime.now();

View File

@ -21,6 +21,8 @@ import java.io.Serializable;
import lombok.Data;
import lombok.experimental.Accessors;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* 验证码信息
*
@ -29,6 +31,7 @@ import lombok.experimental.Accessors;
*/
@Data
@Accessors(chain = true)
@Schema(description = "验证码信息")
public class CaptchaVO implements Serializable {
private static final long serialVersionUID = 1L;
@ -36,10 +39,12 @@ public class CaptchaVO implements Serializable {
/**
* 验证码唯一标识
*/
@Schema(description = "验证码唯一标识")
private String uuid;
/**
* 验证码图片Base64编码带图片格式data:image/gif;base64
*/
@Schema(description = "验证码图片Base64编码带图片格式data:image/gif;base64")
private String img;
}

View File

@ -18,18 +18,23 @@ package top.charles7c.cnadmin;
import java.net.InetAddress;
import lombok.SneakyThrows;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import io.swagger.v3.oas.annotations.Hidden;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import top.charles7c.cnadmin.common.config.properties.ContinewAdminProperties;
/**
* 启动程序
*
@ -39,22 +44,16 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@SpringBootApplication
@RequiredArgsConstructor
@Import(cn.hutool.extra.spring.SpringUtil.class)
@ComponentScan(basePackages = {"top.charles7c.cnadmin", "cn.hutool.extra.spring"})
public class ContinewAdminApplication {
public class ContinewAdminApplication implements ApplicationRunner {
private static Environment env;
private final ContinewAdminProperties properties;
private final ServerProperties serverProperties;
@SneakyThrows
public static void main(String[] args) {
SpringApplication application = new SpringApplication(ContinewAdminApplication.class);
ConfigurableApplicationContext context = application.run(args);
env = context.getEnvironment();
log.info("------------------------------------------------------");
log.info("{} backend service started successfully.", env.getProperty("continew-admin.name"));
log.info("后端 API 地址http://{}:{}", InetAddress.getLocalHost().getHostAddress(), env.getProperty("server.port"));
log.info("------------------------------------------------------");
SpringApplication.run(ContinewAdminApplication.class, args);
}
/**
@ -62,8 +61,19 @@ public class ContinewAdminApplication {
*
* @return /
*/
@Hidden
@GetMapping("/")
public String index() {
return String.format("%s backend service started successfully.", env.getProperty("continew-admin.name"));
return String.format("%s backend service started successfully.", properties.getName());
}
@Override
public void run(ApplicationArguments args) throws Exception {
String hostAddress = InetAddress.getLocalHost().getHostAddress();
log.info("------------------------------------------------------");
log.info("{} backend service started successfully.", properties.getName());
log.info("后端 API 地址http://{}:{}", hostAddress, serverProperties.getPort());
log.info("后端 API 文档http://{}:{}/doc.html", hostAddress, serverProperties.getPort());
log.info("------------------------------------------------------");
}
}

View File

@ -20,6 +20,10 @@ import java.time.Duration;
import lombok.RequiredArgsConstructor;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -39,18 +43,15 @@ import top.charles7c.cnadmin.common.util.RedisUtils;
* @author Charles7c
* @since 2022/12/11 14:00
*/
@Tag(name = "验证码 API")
@RestController
@RequiredArgsConstructor
@RequestMapping("/captcha")
@RequestMapping(value = "/captcha", produces = MediaType.APPLICATION_JSON_VALUE)
public class CaptchaController {
private final CaptchaProperties captchaProperties;
/**
* 获取图片验证码
*
* @return 验证码信息
*/
@Operation(summary = "获取图片验证码", description = "获取图片验证码Base64编码带图片格式data:image/gif;base64")
@GetMapping("/img")
public R<CaptchaVO> getImageCaptcha() {
// 生成验证码

View File

@ -32,4 +32,9 @@ captcha:
# 宽度
width: 111
# 高度
height: 36
height: 36
--- ### 接口文档配置
springdoc:
swagger-ui:
enabled: true

View File

@ -32,4 +32,9 @@ captcha:
# 宽度
width: 111
# 高度
height: 36
height: 36
--- ### 接口文档配置
springdoc:
swagger-ui:
enabled: false

View File

@ -3,9 +3,22 @@ continew-admin:
# 名称
name: ContiNew-Admin
# 应用名称
appName: @project.name@
appName: @project.parent.name@
# 版本
version: @project.version@
# 描述
description: @project.parent.description@
# URL
url: @project.parent.url@
## 作者信息配置
author:
name: Charles7c
email: charles7c@126.com
url: https://blog.charles7c.top/about/me
## 许可协议信息配置
license:
name: Apache-2.0
url: https://github.com/Charles7c/continew-admin/blob/dev/LICENSE
--- ### 日志配置(重叠部分,优先级高于 logback-spring.xml 中的配置)
logging:
@ -15,6 +28,20 @@ logging:
path: @logging.file.path@
config: classpath:logback-spring.xml
--- ### 接口文档配置
springdoc:
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
operations-sorter: alpha
api-docs:
enabled: ${springdoc.swagger-ui.enabled}
path: /v3/api-docs
group-configs:
- group: 'default'
paths-to-match: '/**'
packages-to-scan: top.charles7c.cnadmin.webapi
--- ### 服务器配置
server:
servlet:

24
pom.xml
View File

@ -43,6 +43,7 @@ limitations under the License.
<properties>
<!-- ### 工具库相关 ### -->
<knife4j.version>4.0.0-SNAPSHOT</knife4j.version>
<redisson.version>3.18.1</redisson.version>
<easy-captcha.version>1.6.2</easy-captcha.version>
<hutool.version>5.8.10</hutool.version>
@ -60,6 +61,15 @@ limitations under the License.
<dependencyManagement>
<dependencies>
<!-- ################ 工具库相关 ################ -->
<!-- Knife4j前身是 swagger-bootstrap-ui集 Swagger2 和 OpenAPI3 为一体的增强解决方案) -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-dependencies</artifactId>
<version>${knife4j.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Redisson不仅仅是一个 Redis Java 客户端) -->
<dependency>
<groupId>org.redisson</groupId>
@ -151,7 +161,7 @@ limitations under the License.
<configuration>
<java>
<importOrder>
<order>java,javax,lombok,org,com,cn,top.charles7c,</order>
<order>java,javax,lombok,io,org,com,cn,top.charles7c,</order>
</importOrder>
<removeUnusedImports/>
<eclipse>
@ -203,4 +213,16 @@ limitations under the License.
</properties>
</profile>
</profiles>
<!-- 私服配置(待 Knife4j 正式发版后,移除该配置) -->
<repositories>
<repository>
<id>nexus-maven</id>
<name>nexus-maven</name>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>