---
title: SpringBoot Common
date: 2025-12-15
---
# 一、框架说明
本框架基于Spring Boot3框架二次开发,增加了依赖包管理和启动项配置等功能。
# 二、项目结构
| 项目模块 | 模块含义 | 主要功能 |
| :-----------: | :-------------------: | :---------------------------------: |
| starters | SpringBoot 启动项 | 主要包括web、jdbc和log启动项配置 |
| autoconfigure | staters具体启动配置类 | 主要包括web和jdbc具体的启动项配置类 |
| dependencies | 依赖项 | 主要包括本框架中的依赖包管理 |
| framework | 通用配置 | 主要包括web和data的一些通用工具方法 |
# 三、项目说明
## 3.1 common模块
该模块主要声明项目结构,包括autoconfigure、dependencies、framework、starter-parent和starters等模块。
```xml
dependencies
starters
framework
autoconfigure
starter-parent
```
## 3.2 dependencies模块
该模块为其他模块的父模块,声明了一些常用依赖包及版本,通过``管理,只声明依赖的版本,并不会实际引入依赖。
后续有新增依赖时,需要先在dependencies模块声明版本,然后在相应的starter模块中增加依赖。
```xml
17
${java.version}
${java.version}
3.5.0
2.7.0
1.8.8
2.7.0
3.0.4
3.5.12
1.43.0
5.8.26
2.19.0
4.4
3.14.0
3.9.0
31.1-jre
1.5.5.Final
1.0.6
1.18.30
0.2.0
3.11.0
0.41.0
0.10.2
org.springframework.boot
spring-boot-dependencies
${spring.boot.version}
pom
import
org.springdoc
springdoc-openapi-starter-webmvc-ui
${springdoc.version}
com.sndyuk
logback-more-appenders
${logback-more-appenders.version}
org.komamitsu
fluency-fluentd
${fluency-fluentd.version}
cn.dev33
sa-token-bom
${sa.token.version}
pom
import
cn.hutool
hutool-bom
${hutool.version}
pom
import
org.mybatis
mybatis-spring
${mybatis-spring.version}
com.baomidou
mybatis-plus-bom
${mybatis.plus.version}
pom
import
commons-io
commons-io
${commons.io.version}
org.apache.commons
commons-collections4
${commons.collections.version}
org.apache.commons
commons-lang3
${commons-lang3.version}
commons-net
commons-net
${commons.net.version}
com.google.guava
guava-bom
${guava.version}
pom
import
org.mapstruct
mapstruct
${mapstruct.version}
com.github.yitter
yitter-idgenerator
${yitter.idgenerator.version}
com.cxx
starter-logging
2.0.0
com.cxx
starter-web
2.0.0
com.cxx
starter-jdbc
2.0.0
org.springframework.boot
spring-boot-maven-plugin
${spring.boot.version}
org.apache.maven.plugins
maven-compiler-plugin
${maven-compiler-plugin.version}
io.fabric8
docker-maven-plugin
${docker-maven-plugin.version}
org.graalvm.buildtools
native-maven-plugin
${native-maven-plugin.version}
```
::: tip
dependencyManagement部分只声明依赖的版本,并不会实际引入依赖。
需要在具体的模块中显式声明依赖,才能让模块使用这些库
:::
## 3.3 framework模块
该模块主要是一些通用的配置。
### 3.3.1 data
主要提供了2个数据库实体类的基类。
::: code-group
```java [AbstractIdEntity]
@Getter
@Setter
public abstract class AbstractIdEntity {
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
}
```
```java [AbstractEntity]
@Getter
@Setter
public abstract class AbstractEntity extends AbstractIdEntity {
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(value = "create_by", fill = FieldFill.INSERT)
private String createBy;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
private String updateBy;
}
```
:::
### 3.3.2 web
主要提供了自定义异常处理类。
::: code-group
```java [ErrorResponse]
/**
* 错误响应
*/
public final class ErrorResponse {
/**
* 自定义code
*/
private final String code;
/**
* 自定义消息
*/
private final String message;
public ErrorResponse(String message) {
this.code = "Unspecified";
this.message = message;
}
public ErrorResponse(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public String getMessage() {
return message;
}
}
```
```java [CustomException]
/**
* 自定义异常类
*/
public class CustomException extends AbstractException {
public CustomException(String errorMessage) {
super(errorMessage);
}
public CustomException(String code, String errorMessage) {
super(code, errorMessage);
}
public CustomException(String errorMessage, Exception innerException) {
super(errorMessage, innerException);
}
public CustomException(String code, String errorMessage, Exception innerException) {
super(code, errorMessage, innerException);
}
}
```
```java [AbstractException]
/**
* 抽象异常类
*/
public abstract class AbstractException extends RuntimeException {
protected String code;
public AbstractException(String errorMessage) {
super(errorMessage);
}
public AbstractException(String code, String errorMessage) {
super(errorMessage);
this.code = code;
}
public AbstractException(String errorMessage, Exception innerException) {
super(errorMessage, innerException);
}
public AbstractException(String code, String errorMessage, Exception innerException) {
super(errorMessage, innerException);
this.code = code;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
```
:::
### 3.4 starters模块
该模块为整个项目的核心模块,在实际项目中,通过引入相应的starter模块,并配合autoconfigure模块中的功能,即可实现快速自动装配。
该模块的pom.xml声明的依赖会注入到实际的项目中。
::: danger
在SringBoot3中,自动配置的路径改成了**main->resources->META-INF->spring->org.springframework.boot.autoconfigure.AutoConfiguration.imports**路径,然后在该文件中声明需要自动执行的类。
之前的SringBoot2,是在**main->resources->META-INF**目录下新建spring.factories文件。
:::
#### 3.4.1 stater-jdbc
该模块主要提供数据库相关的配置功能。
目前实现的功能有:
1. 配置MybatisPlus拦截器,添加乐观锁和分页插件。
2. 自定义MybatisPlus ID生成器(雪花ID)。
3. 配置MybatisPlus自动填充字段(create_time、create_by、update_time和update_by)。
::: code-group
```java [JdbcAutoConfiguration]
/**
* jdbc自动配置
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SqlSessionFactory.class)
@Import({YitterGenerator.class, MybatisMetaObjectHandler.class})
public class JdbcAutoConfiguration {
/**
* MybatisPlus拦截器
* @return 拦截器
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
```
```java [YitterGenerator]
/**
* 雪花id生成器
*/
public class YitterGenerator implements IdentifierGenerator {
@Override
public Number nextId(Object entity) {
return YitIdHelper.nextId();
}
}
```
```java [MybatisMetaObjectHandler]
/**
* Mybatis Plus自动填充
*/
public class MybatisMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, Constants.CREATE_TIME_FLAG, LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, Constants.UPDATE_TIME_FLAG, LocalDateTime.class, LocalDateTime.now());
if (StpUtil.isLogin()) {
this.strictInsertFill(metaObject, Constants.CREATE_BY_FLAG, String.class, StpUtil.getLoginIdAsString());
this.strictInsertFill(metaObject, Constants.UPDATE_BY_FLAG, String.class, StpUtil.getLoginIdAsString());
}
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, Constants.UPDATE_TIME_FLAG, LocalDateTime.class, LocalDateTime.now());
if (StpUtil.isLogin()) {
this.strictUpdateFill(metaObject, Constants.UPDATE_BY_FLAG, String.class, StpUtil.getLoginIdAsString());
}
}
}
```
:::
`@ConditionalOnClass(SqlSessionFactory.class)`表示只有存在SqlSessionFactory类时,这个配置类才会生效。即如果没有 MyBatis 相关依赖,这个配置类会被 Spring 完全忽略。
`@Import`用于导入其他配置类或组件到当前配置类中。
#### 3.4.2 starter-web
该模块主要提供web相关的配置功能。
目前实现的功能有:
1. 注册审计拦截器
2. 注册Sa-Token拦截器
3. 注册安全拦截器
4. 配置CORS跨越
5. 全局异常处理器
::: code-group
```java [ServerAutoConfiguration]
@Configuration()
@Import({DefaultExceptionAdvice.class, AuditBodyAdvice.class, CustomProperties.class})
public class ServerAutoConfiguration implements WebMvcConfigurer {
@Resource
private CustomProperties customProperties;
/**
* 注册拦截器 需要实现 WebMvcConfigurer 接口
* @param registry 注册器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册安全拦截器
// registry.addInterceptor(new SecurityInterceptor());
// 注册审计拦截器
registry.addInterceptor(new AuditInterceptor(customProperties.getBasePackage()));
// 注册Sa-Token拦截器 登录校验
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
.excludePathPatterns("/error", "/swagger-ui/**", "/swagger-resources/**", "/v3/api-docs/**")
.excludePathPatterns("/files/**")
.excludePathPatterns("/doc.html", "/webjars/**");
}
/**
* 配置CORS跨越 需要实现 WebMvcConfigurer 接口
* @return 过滤器
*/
@Bean
@Order(-128)
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 允许所有来源
config.addAllowedOrigin("*");
// 允许所有请求头
config.addAllowedHeader("*");
// 允许所有请求方法
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
```
```java [AuditInterceptor]
public class AuditInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(AuditInterceptor.class);
private final String basePackage;
public AuditInterceptor(String basePackage) {
this.basePackage = basePackage;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 如果是Http请求
if (handler instanceof HandlerMethod hd) {
request.setAttribute(Constants.AUDIT_TIME_FLAG, System.currentTimeMillis());
// 判断该请求是否需要审计
if (WebUtils.checkIsAuditPackages(hd.getBeanType().getPackage(), basePackage)) {
handleAuditPackageRequest(request);
}
}
// true表示继续处理请求
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 这里我们不需要处理时间计算,所有的计算在 afterCompletion 中完成
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 获取开始时间
Long startTime = (Long) request.getAttribute(Constants.AUDIT_TIME_FLAG);
if (startTime != null) {
long duration = System.currentTimeMillis() - startTime;
logger.info(" Request URL {} | Time Taken {} ms", request.getRequestURI(), duration);
}
}
/**
* 处理审计包请求
* @param request 请求
*/
private void handleAuditPackageRequest(HttpServletRequest request) {
if (StringUtils.isEmpty(request.getQueryString())) {
logger.info(" {} {}", request.getMethod(), request.getRequestURI());
} else {
logger.info(" {} {}?{}", request.getMethod(), request.getRequestURI(), WebUtils.format2UTF8(request.getQueryString()));
}
}
}
```
```java [DefaultExceptionAdvice]
/**
* 全局异常处理器
*/
@RestControllerAdvice
public class DefaultExceptionAdvice {
private static final Logger logger = LoggerFactory.getLogger(DefaultExceptionAdvice.class);
/**
* 处理SaToken权限错误
* @param e 权限异常
* @return 错误响应
*/
@ExceptionHandler(SaTokenException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public ErrorResponse handleSaTokenException(SaTokenException e) {
ErrorResponse response = new ErrorResponse(String.valueOf(e.getCode()), e.getMessage());
logger.error("<{}> {}", response.getCode(), e.toString());
return response;
}
/**
* 处理参数校验错误
* @param e 校验异常
* @return 错误响应
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ErrorResponse handleValidationException(MethodArgumentNotValidException e) {
ErrorResponse response = new ErrorResponse(WebUtils.formatValidationException(e.getBindingResult().getFieldErrors()));
logger.error("<{}> {}", response.getCode(), response.getMessage());
return response;
}
/**
* 处理自定义异常错误
* @param e 自定义异常
* @return 错误响应
*/
@ExceptionHandler(AbstractException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleAbstractException(AbstractException e) {
ErrorResponse response;
if (e.getCode() == null || e.getCode().isEmpty()) {
response = new ErrorResponse(e.getMessage());
} else {
response = new ErrorResponse(e.getCode(), e.getMessage());
}
logger.error(String.format("<%s> ", response.getCode()), e);
return response;
}
/**
* 处理默认异常错误
* @param e 默认异常
* @return 错误响应
*/
@ExceptionHandler
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleDefaultException(Exception e) {
ErrorResponse response = new ErrorResponse(e.getMessage());
logger.error(String.format("<%s> ", response.getCode()), e);
return response;
}
}
```
```java [AuditBodyAdvice]
@ControllerAdvice
@Import({CustomProperties.class})
public class AuditBodyAdvice implements RequestBodyAdvice, ResponseBodyAdvice