签入版本

This commit is contained in:
2026-09-10 21:41:50 +08:00
commit 717116a605
2693 changed files with 355025 additions and 0 deletions
+74
View File
@@ -0,0 +1,74 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xiaomayi</groupId>
<artifactId>xiaomayi-common</artifactId>
<version>${revision}</version>
</parent>
<artifactId>xiaomayi-mybatis</artifactId>
<!-- 依赖声明 -->
<dependencies>
<!-- 核心依赖模块 -->
<dependency>
<groupId>com.xiaomayi</groupId>
<artifactId>xiaomayi-core</artifactId>
</dependency>
<!-- 多租户模块 -->
<dependency>
<groupId>com.xiaomayi</groupId>
<artifactId>xiaomayi-tenant</artifactId>
</dependency>
<!-- 文档依赖模块 -->
<dependency>
<groupId>com.xiaomayi</groupId>
<artifactId>xiaomayi-springdoc</artifactId>
</dependency>
<!-- Druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
</dependency>
<!-- 动态数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
</dependency>
<!-- MySQL 依赖 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Postgresql 依赖 -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<!-- SqlServer 依赖 -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<!-- Sqlite 依赖 -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
</dependency>
<!--mybatis-plus 起始依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<!-- mybatis-plus代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,473 @@
// +======================================================================
// | 小蚂蚁云·企业数字化开发平台 [ 加速数字化转型,构建智能未来 ]
// +----------------------------------------------------------------------
// | 核心价值:赋能开发者 · 服务企业 · 共建生态
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2026 小蚂蚁云团队 版权所有
// +----------------------------------------------------------------------
// | 官方平台: https://www.xiaomayicloud.com
// +======================================================================
// | 【知识产权声明】
// | 1. 权属声明:本软件是受《中华人民共和国著作权法》
// | 保护的专有财产,完整版权归小蚂蚁云团队所有
// | 2. 权利范围:所有知识产权(商标、专利、著作权、
// | 商业秘密等)均归小蚂蚁云团队所有,受法律保护
// | 3. 授权性质:用户仅可获得有限的、非独占的使用许可
// | 4. 禁止行为:未经书面授权,禁止对本软件本身
// | 申请任何知识产权
// | 5. 权利保留:未在本协议中明示授予的一切权利
// | 均由小蚂蚁云团队保留
// +======================================================================
// | 【授权状态说明】
// | 1. 未授权状态:用户未购买有效的商业许可证
// | 2. 商业授权:已购买正式商业许可证的用户
// +======================================================================
// | 【绝对禁止条款】
// | 无论授权状态如何,任何用户均严格禁止以下行为:
// | 1. 逆向工程:对软件进行反编译、反汇编、技术破解或任何形式的逆向分析
// | 2. 版权破坏:移除、修改、遮挡软件中的版权标识、许可控制或技术保护措施
// | 3. 非法传播:复制、分发、出租、出借、转售、再许可本软件或其许可权利
// | 4. 竞争性使用:利用本软件的代码、架构、设计开发直接竞争的产品或服务
// | 5. 侵权使用:将软件用于侵犯第三方知识产权或其他合法权益的用途
// +======================================================================
// | 【商业授权许可范围】
// | 购买有效商业许可证的用户,在遵守上述禁止条款的前提下,获得:
// | 1. 使用权利:在许可证约定的项目数量、开发者数量范围内使用本软件
// | 2. 技术支持:商业授权用户可以获取本地开发部署的技术支持服务
// | 3. 版本更新:在许可证有效期内获取软件更新、安全补丁和功能增强
// | 4. 商业部署:将基于本软件开发的应用程序用于商业运营和生产环境
// +======================================================================
// | 【许可证获取】
// | 1. 获取途径:仅通过小蚂蚁云官方渠道购买(官网、授权代理商),购买记录凭证
// | 2. 转让限制:许可证与购买主体绑定,未经书面同意不得转让
// | 3. 终止情形:许可证到期、违反协议、破产清算等情况下自动终止
// +======================================================================
// | 【合法使用要求】
// | 1. 仅限用于合法合规的软件研发
// | 2. 严禁用于任何违法、侵权或恶意行为
// | 3. 严禁违反我国法律法规和政策
// +======================================================================
// | 【免责声明】
// | 因使用本框架导致的以下情况,我们概不负责:
// | 1. 项目研发中的意外、疏忽、违约等风险
// | 2. 侵犯第三方知识产权或其他合法权益
// | 3. 任何直接、间接、附带或衍生一切损失
// | 4. 用户违规违法行为的一切法律后果
// +======================================================================
// | 【协议重要提示】
// | 1. 本声明是《小蚂蚁云最终用户许可协议》的摘要版本
// | 2. 下载、安装或使用本软件即表示您接受全部协议条款
// | 3. 我们保留单方面修改本声明的权利,修改后的版本在官网公布即生效
// | 4. 用户有义务定期查看最新版本,继续使用视为接受修改
// +======================================================================
// | 【侵权举报与合规】
// | 1. 知识产权侵权举报:请联系官方客服
// | 2. 许可证合规咨询:xiaomayicloud@163.com
// | 3. 违规使用将终止授权并追究责任
// | 4. 无条件配合司法机关调查取证
// | 5. 保留一切法律追诉权利
// | 6. 对有效举报和合规建议,我们将给予感谢和奖励
// +======================================================================
package com.xiaomayi.mybatis.config;
import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.xiaomayi.core.utils.SpringUtils;
import com.xiaomayi.mybatis.exception.MybatisPlusException;
import com.xiaomayi.mybatis.handler.MybatisMetaObjectHandler;
import com.xiaomayi.mybatis.interceptor.MybatisPlusSqlInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
/**
* <p>
* MybatisPlus配置类
* <p>
* 核心功能:
* 1. 配置MybatisPlus的各种插件和拦截器
* 2. 配置SqlSessionFactory,集成Spring Boot
* 3. 启用Spring事务管理
* 4. 配置自动填充、分页、乐观锁等功能
* <p>
*
* @author 小蚂蚁云团队
* @since 2024-05-21
*/
@Slf4j
@Configuration
@EnableTransactionManagement(proxyTargetClass = true) // 启用注解式事务管理,使用CGLIB代理
public class MybatisPlusConfig {
/**
* Spring环境配置
* 用于读取application.yml中的MybatisPlus相关配置
*/
private final Environment environment;
/**
* 单页分页条数限制
* 防止恶意的大数据量查询,保护数据库性能
* 默认值:1000条,可通过配置覆盖
*/
private static final Long DEFAULT_MAX_LIMIT = 1000L;
/**
* 多租户功能开关
* 从配置文件中读取tenant.enable,默认值为false
* 启用后会自动添加多租户拦截器
*/
@Value("${tenant.enable:false}")
private boolean tenantEnabled;
/**
* 构造函数注入
* <p>
* 优势:
* - 不可变性:environment字段为final,线程安全
* - 明确的依赖:所有必需依赖在构造时明确指定
* - 易于测试:可以通过构造函数传入mock对象
*
* @param environment Spring环境配置
*/
@Autowired
public MybatisPlusConfig(Environment environment) {
this.environment = environment;
log.info("MybatisPlusConfig初始化完成");
}
/**
* MybatisPlus核心拦截器配置
* <p>
* 功能:配置MybatisPlus的各种功能插件,按顺序执行
* <p>
* 拦截器执行顺序(重要):
* 1. 多租户拦截器(如果启用)
* 2. 乐观锁拦截器
* 3. 分页拦截器
* 4. 防全表操作拦截器
* <p>
* 设计原则:
* - 多租户插件必须最先执行,确保数据隔离
* - 分页插件应该放在较后位置,避免影响其他插件
* - 防全表操作插件放在最后,作为安全防护
*
* @return MybatisPlusInterceptor 配置完成的拦截器链
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
log.info("配置MybatisPlus拦截器链...");
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 1. 多租户拦截器(条件化添加)
if (tenantEnabled) {
log.info("多租户功能已启用,添加多租户拦截器");
TenantLineInnerInterceptor tenantInterceptor = SpringUtils.getBean(TenantLineInnerInterceptor.class);
interceptor.addInnerInterceptor(tenantInterceptor);
} else {
log.debug("多租户功能未启用,跳过多租户拦截器");
}
// 2. 乐观锁拦截器
interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
log.debug("添加乐观锁拦截器");
// 3. 分页拦截器(放在乐观锁之后)
interceptor.addInnerInterceptor(paginationInnerInterceptor());
log.debug("添加分页拦截器");
// 4. 防全表操作拦截器(放在最后,安全防护)
interceptor.addInnerInterceptor(blockAttackInnerInterceptor());
log.debug("添加防全表操作拦截器");
log.info("MybatisPlus拦截器链配置完成,共配置 {} 个拦截器",
interceptor.getInterceptors().size());
return interceptor;
}
/**
* 乐观锁拦截器配置
* <p>
* 功能:实现乐观锁机制,防止并发更新冲突
* <p>
* 使用方式:
* 1. 在实体类字段上添加@Version注解
* 2. 数据库表中添加version字段
* 3. 更新时会自动检查version值,不一致则抛出异常
* <p>
* 适用场景:
* - 高并发更新操作
* - 需要防止数据覆盖的场景
* - 读多写少的业务场景
*
* @return OptimisticLockerInnerInterceptor 乐观锁拦截器
*/
@Bean
public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
log.debug("创建乐观锁拦截器");
return new OptimisticLockerInnerInterceptor();
}
/**
* 分页拦截器配置
* <p>
* 功能:提供自动分页功能,支持多种数据库
* <p>
* 配置说明:
* - setOverflow(true): 分页合理化,当页码超出范围时返回最后一页
* - setMaxLimit(MAX_LIMIT): 限制单页最大记录数,防止恶意查询
* <p>
* 数据库支持:
* - MySQL、PostgreSQL、Oracle等主流数据库
* - 自动识别数据库类型,生成对应的分页SQL
*
* @return PaginationInnerInterceptor 分页拦截器
*/
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor() {
log.debug("创建分页拦截器");
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
// 分页合理化:当请求的页码大于总页数时,返回最后一页的数据
paginationInterceptor.setOverflow(true);
// 设置单页分页条数限制,防止恶意的大数据量查询
paginationInterceptor.setMaxLimit(DEFAULT_MAX_LIMIT);
log.debug("分页拦截器配置完成:overflow={}, maxLimit={}",
true, DEFAULT_MAX_LIMIT);
return paginationInterceptor;
}
/**
* 防全表操作拦截器配置
* <p>
* 功能:防止恶意的全表更新和删除操作
* <p>
* 防护范围:
* - 没有WHERE条件的UPDATE语句
* - 没有WHERE条件的DELETE语句
* <p>
* 安全意义:
* - 防止误操作导致数据丢失
* - 增强系统数据安全性
* - 符合数据库操作最佳实践
*
* @return BlockAttackInnerInterceptor 防全表操作拦截器
*/
@Bean
public BlockAttackInnerInterceptor blockAttackInnerInterceptor() {
log.debug("创建防全表操作拦截器");
return new BlockAttackInnerInterceptor();
}
/**
* MybatisPlus异常处理器
* <p>
* 功能:统一处理MybatisPlus相关的异常
* <p>
* 处理范围:
* - 乐观锁冲突异常
* - 分页参数异常
* - 防全表操作拦截异常
* - 其他MybatisPlus特定异常
*
* @return MybatisPlusException 异常处理器
*/
@Bean
public MybatisPlusException mybatisException() {
log.debug("注册MybatisPlus异常处理器");
return new MybatisPlusException();
}
/**
* 元对象字段填充处理器
* <p>
* 功能:自动填充实体类的公共字段
* <p>
* 典型应用:
* - 创建时间(createTime)
* - 更新时间(updateTime)
* - 创建人(createBy)
* - 更新人(updateBy)
* - 逻辑删除标志(deleted)
* <p>
* 使用方式:
* 在实体类字段上添加@TableField(fill = FieldFill.INSERT)等注解
*
* @return MetaObjectHandler 元对象处理器
*/
@Bean
public MetaObjectHandler metaObjectHandler() {
log.debug("注册元对象字段填充处理器");
return new MybatisMetaObjectHandler();
}
/**
* SqlSessionFactory配置
* <p>
* 功能:创建并配置Mybatis的SqlSessionFactory
* <p>
* 配置内容:
* 1. 数据源配置
* 2. 类型别名包扫描
* 3. Mapper文件位置
* 4. Mybatis全局配置
* 5. 插件拦截器
* 6. 自动填充处理器
* <p>
* 注意:这里使用MybatisSqlSessionFactoryBean而不是原生的SqlSessionFactoryBean
* 以便更好地集成MybatisPlus功能
*
* @param dataSource 数据源,由Spring自动注入(使用@Primary的动态数据源)
* @return SqlSessionFactory SqlSession工厂
* @throws Exception 配置过程中可能出现的异常
*/
@Primary
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
log.info("开始配置SqlSessionFactory...");
// 从环境配置中读取MybatisPlus相关参数
String typeAliasesPackage = getRequiredProperty("mybatis-plus.typeAliasesPackage");
String mapperLocations = getRequiredProperty("mybatis-plus.mapperLocations");
log.debug("MybatisPlus配置参数:typeAliasesPackage={}, mapperLocations={}",
typeAliasesPackage, mapperLocations);
// 注册Spring Boot VFS,解决Mybatis在Spring Boot中的资源加载问题
VFS.addImplClass(SpringBootVFS.class);
MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
// 1. 设置数据源
sessionFactory.setDataSource(dataSource);
log.debug("设置数据源完成");
// 2. 设置类型别名包扫描路径
sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
log.debug("设置类型别名包扫描路径: {}", typeAliasesPackage);
// 3. 设置Mapper XML文件位置
sessionFactory.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources(mapperLocations)
);
log.debug("设置Mapper文件位置: {}", mapperLocations);
// 4. 配置Mybatis全局设置
MybatisConfiguration configuration = createMybatisConfiguration();
sessionFactory.setConfiguration(configuration);
log.debug("Mybatis全局配置完成");
// 5. 设置插件拦截器
Interceptor[] plugins = {
mybatisPlusInterceptor(), // MybatisPlus核心插件
new MybatisPlusSqlInterceptor() // SQL打印拦截器
};
sessionFactory.setPlugins(plugins);
log.debug("设置插件拦截器完成,共 {} 个插件", plugins.length);
// 6. 设置全局配置(自动填充处理器)
GlobalConfig globalConfig = new GlobalConfig()
.setMetaObjectHandler(metaObjectHandler());
sessionFactory.setGlobalConfig(globalConfig);
log.debug("设置全局配置完成");
SqlSessionFactory sqlSessionFactory = sessionFactory.getObject();
log.info("SqlSessionFactory配置完成");
return sqlSessionFactory;
}
// @Primary
// @Bean(name = "transactionManager")
// public DataSourceTransactionManager transactionManager(DataSource dataSource) {
// return new DataSourceTransactionManager(dataSource);
// }
/**
* 创建Mybatis全局配置
* <p>
* 功能:配置Mybatis的核心行为
* <p>
* 配置项说明:
* - 默认脚本语言:MybatisXMLLanguageDriver
* - 空值处理:JdbcType.NULL
* - 驼峰命名映射:自动将user_id映射到userId
* - 缓存启用:false(通常由业务层控制)
* - 自增主键:使用JDBC的getGeneratedKeys
*
* @return MybatisConfiguration Mybatis配置对象
*/
private MybatisConfiguration createMybatisConfiguration() {
MybatisConfiguration configuration = new MybatisConfiguration();
// 设置默认脚本语言驱动
configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
// 设置JDBC空值处理类型
configuration.setJdbcTypeForNull(JdbcType.NULL);
// 启用驼峰命名自动映射:数据库字段名 user_id → 实体类属性名 userId
configuration.setMapUnderscoreToCamelCase(true);
// 禁用二级缓存(通常由业务层控制缓存策略)
configuration.setCacheEnabled(false);
// 使用JDBC的getGeneratedKeys获取数据库自增主键值
configuration.setUseGeneratedKeys(true);
log.debug("Mybatis全局配置创建完成:驼峰映射={}, 自增主键={}", true, true);
return configuration;
}
/**
* 安全获取配置属性值
* <p>
* 功能:从环境配置中获取属性值,如果不存在则抛出明确异常
* <p>
* 设计考虑:
* - 避免在配置缺失时出现难以排查的NullPointerException
* - 提供清晰的错误信息,便于快速定位问题
* - 在应用启动时尽早发现配置问题
*
* @param key 配置属性键
* @return 配置属性值
* @throws IllegalStateException 如果配置属性不存在
*/
private String getRequiredProperty(String key) {
String value = environment.getProperty(key);
if (value == null || value.trim().isEmpty()) {
throw new IllegalStateException("必需的MybatisPlus配置缺失: " + key);
}
return value;
}
}
@@ -0,0 +1,100 @@
// +======================================================================
// | 小蚂蚁云·企业数字化开发平台 [ 加速数字化转型,构建智能未来 ]
// +----------------------------------------------------------------------
// | 核心价值:赋能开发者 · 服务企业 · 共建生态
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2026 小蚂蚁云团队 版权所有
// +----------------------------------------------------------------------
// | 官方平台: https://www.xiaomayicloud.com
// +======================================================================
// | 【知识产权声明】
// | 1. 权属声明:本软件是受《中华人民共和国著作权法》
// | 保护的专有财产,完整版权归小蚂蚁云团队所有
// | 2. 权利范围:所有知识产权(商标、专利、著作权、
// | 商业秘密等)均归小蚂蚁云团队所有,受法律保护
// | 3. 授权性质:用户仅可获得有限的、非独占的使用许可
// | 4. 禁止行为:未经书面授权,禁止对本软件本身
// | 申请任何知识产权
// | 5. 权利保留:未在本协议中明示授予的一切权利
// | 均由小蚂蚁云团队保留
// +======================================================================
// | 【授权状态说明】
// | 1. 未授权状态:用户未购买有效的商业许可证
// | 2. 商业授权:已购买正式商业许可证的用户
// +======================================================================
// | 【绝对禁止条款】
// | 无论授权状态如何,任何用户均严格禁止以下行为:
// | 1. 逆向工程:对软件进行反编译、反汇编、技术破解或任何形式的逆向分析
// | 2. 版权破坏:移除、修改、遮挡软件中的版权标识、许可控制或技术保护措施
// | 3. 非法传播:复制、分发、出租、出借、转售、再许可本软件或其许可权利
// | 4. 竞争性使用:利用本软件的代码、架构、设计开发直接竞争的产品或服务
// | 5. 侵权使用:将软件用于侵犯第三方知识产权或其他合法权益的用途
// +======================================================================
// | 【商业授权许可范围】
// | 购买有效商业许可证的用户,在遵守上述禁止条款的前提下,获得:
// | 1. 使用权利:在许可证约定的项目数量、开发者数量范围内使用本软件
// | 2. 技术支持:商业授权用户可以获取本地开发部署的技术支持服务
// | 3. 版本更新:在许可证有效期内获取软件更新、安全补丁和功能增强
// | 4. 商业部署:将基于本软件开发的应用程序用于商业运营和生产环境
// +======================================================================
// | 【许可证获取】
// | 1. 获取途径:仅通过小蚂蚁云官方渠道购买(官网、授权代理商),购买记录凭证
// | 2. 转让限制:许可证与购买主体绑定,未经书面同意不得转让
// | 3. 终止情形:许可证到期、违反协议、破产清算等情况下自动终止
// +======================================================================
// | 【合法使用要求】
// | 1. 仅限用于合法合规的软件研发
// | 2. 严禁用于任何违法、侵权或恶意行为
// | 3. 严禁违反我国法律法规和政策
// +======================================================================
// | 【免责声明】
// | 因使用本框架导致的以下情况,我们概不负责:
// | 1. 项目研发中的意外、疏忽、违约等风险
// | 2. 侵犯第三方知识产权或其他合法权益
// | 3. 任何直接、间接、附带或衍生一切损失
// | 4. 用户违规违法行为的一切法律后果
// +======================================================================
// | 【协议重要提示】
// | 1. 本声明是《小蚂蚁云最终用户许可协议》的摘要版本
// | 2. 下载、安装或使用本软件即表示您接受全部协议条款
// | 3. 我们保留单方面修改本声明的权利,修改后的版本在官网公布即生效
// | 4. 用户有义务定期查看最新版本,继续使用视为接受修改
// +======================================================================
// | 【侵权举报与合规】
// | 1. 知识产权侵权举报:请联系官方客服
// | 2. 许可证合规咨询:xiaomayicloud@163.com
// | 3. 违规使用将终止授权并追究责任
// | 4. 无条件配合司法机关调查取证
// | 5. 保留一切法律追诉权利
// | 6. 对有效举报和合规建议,我们将给予感谢和奖励
// +======================================================================
package com.xiaomayi.mybatis.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* <p>
* 数据分页设置
* </p>
*
* @author 小蚂蚁云团队
* @since 2024-05-21
*/
@Data
public class PageDTO {
/**
* 页码
*/
@Schema(description = "页码")
private Integer pageNo = 1;
/**
* 每页数
*/
@Schema(description = "每页数")
private Integer pageSize = 20;
}
@@ -0,0 +1,129 @@
// +======================================================================
// | 小蚂蚁云·企业数字化开发平台 [ 加速数字化转型,构建智能未来 ]
// +----------------------------------------------------------------------
// | 核心价值:赋能开发者 · 服务企业 · 共建生态
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2026 小蚂蚁云团队 版权所有
// +----------------------------------------------------------------------
// | 官方平台: https://www.xiaomayicloud.com
// +======================================================================
// | 【知识产权声明】
// | 1. 权属声明:本软件是受《中华人民共和国著作权法》
// | 保护的专有财产,完整版权归小蚂蚁云团队所有
// | 2. 权利范围:所有知识产权(商标、专利、著作权、
// | 商业秘密等)均归小蚂蚁云团队所有,受法律保护
// | 3. 授权性质:用户仅可获得有限的、非独占的使用许可
// | 4. 禁止行为:未经书面授权,禁止对本软件本身
// | 申请任何知识产权
// | 5. 权利保留:未在本协议中明示授予的一切权利
// | 均由小蚂蚁云团队保留
// +======================================================================
// | 【授权状态说明】
// | 1. 未授权状态:用户未购买有效的商业许可证
// | 2. 商业授权:已购买正式商业许可证的用户
// +======================================================================
// | 【绝对禁止条款】
// | 无论授权状态如何,任何用户均严格禁止以下行为:
// | 1. 逆向工程:对软件进行反编译、反汇编、技术破解或任何形式的逆向分析
// | 2. 版权破坏:移除、修改、遮挡软件中的版权标识、许可控制或技术保护措施
// | 3. 非法传播:复制、分发、出租、出借、转售、再许可本软件或其许可权利
// | 4. 竞争性使用:利用本软件的代码、架构、设计开发直接竞争的产品或服务
// | 5. 侵权使用:将软件用于侵犯第三方知识产权或其他合法权益的用途
// +======================================================================
// | 【商业授权许可范围】
// | 购买有效商业许可证的用户,在遵守上述禁止条款的前提下,获得:
// | 1. 使用权利:在许可证约定的项目数量、开发者数量范围内使用本软件
// | 2. 技术支持:商业授权用户可以获取本地开发部署的技术支持服务
// | 3. 版本更新:在许可证有效期内获取软件更新、安全补丁和功能增强
// | 4. 商业部署:将基于本软件开发的应用程序用于商业运营和生产环境
// +======================================================================
// | 【许可证获取】
// | 1. 获取途径:仅通过小蚂蚁云官方渠道购买(官网、授权代理商),购买记录凭证
// | 2. 转让限制:许可证与购买主体绑定,未经书面同意不得转让
// | 3. 终止情形:许可证到期、违反协议、破产清算等情况下自动终止
// +======================================================================
// | 【合法使用要求】
// | 1. 仅限用于合法合规的软件研发
// | 2. 严禁用于任何违法、侵权或恶意行为
// | 3. 严禁违反我国法律法规和政策
// +======================================================================
// | 【免责声明】
// | 因使用本框架导致的以下情况,我们概不负责:
// | 1. 项目研发中的意外、疏忽、违约等风险
// | 2. 侵犯第三方知识产权或其他合法权益
// | 3. 任何直接、间接、附带或衍生一切损失
// | 4. 用户违规违法行为的一切法律后果
// +======================================================================
// | 【协议重要提示】
// | 1. 本声明是《小蚂蚁云最终用户许可协议》的摘要版本
// | 2. 下载、安装或使用本软件即表示您接受全部协议条款
// | 3. 我们保留单方面修改本声明的权利,修改后的版本在官网公布即生效
// | 4. 用户有义务定期查看最新版本,继续使用视为接受修改
// +======================================================================
// | 【侵权举报与合规】
// | 1. 知识产权侵权举报:请联系官方客服
// | 2. 许可证合规咨询:xiaomayicloud@163.com
// | 3. 违规使用将终止授权并追究责任
// | 4. 无条件配合司法机关调查取证
// | 5. 保留一切法律追诉权利
// | 6. 对有效举报和合规建议,我们将给予感谢和奖励
// +======================================================================
package com.xiaomayi.mybatis.exception;
import com.xiaomayi.core.utils.R;
import com.xiaomayi.core.utils.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* <p>
* Mybatis异常处理
* </p>
*
* @author 小蚂蚁云团队
* @since 2023-06-16
*/
@Slf4j
@RestControllerAdvice
public class MybatisPlusException {
/**
* 主键或者UNIQUE索引,数据重复异常
*
* @param e 参数
* @param request 网络请求
* @return 返回结果
*/
@ExceptionHandler(DuplicateKeyException.class)
public R<Void> handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',数据库中已存在记录'{}'", requestURI, e.getMessage());
return R.failed("数据库中已存在该记录,请联系管理员确认");
}
/**
* Mybatis通用异常处理
*
* @param e 参数
* @param request 网络请求
* @return 返回结果
*/
@ExceptionHandler(MyBatisSystemException.class)
public R<Void> handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
String message = e.getMessage();
if (StringUtils.contains("CannotFindDataSourceException", message)) {
log.error("请求地址'{}', 未找到数据源", requestURI);
return R.failed("未找到数据源,请联系管理员确认");
}
log.error("请求地址'{}', Mybatis系统异常", requestURI, e);
return R.failed(message);
}
}
@@ -0,0 +1,181 @@
// +======================================================================
// | 小蚂蚁云·企业数字化开发平台 [ 加速数字化转型,构建智能未来 ]
// +----------------------------------------------------------------------
// | 核心价值:赋能开发者 · 服务企业 · 共建生态
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2026 小蚂蚁云团队 版权所有
// +----------------------------------------------------------------------
// | 官方平台: https://www.xiaomayicloud.com
// +======================================================================
// | 【知识产权声明】
// | 1. 权属声明:本软件是受《中华人民共和国著作权法》
// | 保护的专有财产,完整版权归小蚂蚁云团队所有
// | 2. 权利范围:所有知识产权(商标、专利、著作权、
// | 商业秘密等)均归小蚂蚁云团队所有,受法律保护
// | 3. 授权性质:用户仅可获得有限的、非独占的使用许可
// | 4. 禁止行为:未经书面授权,禁止对本软件本身
// | 申请任何知识产权
// | 5. 权利保留:未在本协议中明示授予的一切权利
// | 均由小蚂蚁云团队保留
// +======================================================================
// | 【授权状态说明】
// | 1. 未授权状态:用户未购买有效的商业许可证
// | 2. 商业授权:已购买正式商业许可证的用户
// +======================================================================
// | 【绝对禁止条款】
// | 无论授权状态如何,任何用户均严格禁止以下行为:
// | 1. 逆向工程:对软件进行反编译、反汇编、技术破解或任何形式的逆向分析
// | 2. 版权破坏:移除、修改、遮挡软件中的版权标识、许可控制或技术保护措施
// | 3. 非法传播:复制、分发、出租、出借、转售、再许可本软件或其许可权利
// | 4. 竞争性使用:利用本软件的代码、架构、设计开发直接竞争的产品或服务
// | 5. 侵权使用:将软件用于侵犯第三方知识产权或其他合法权益的用途
// +======================================================================
// | 【商业授权许可范围】
// | 购买有效商业许可证的用户,在遵守上述禁止条款的前提下,获得:
// | 1. 使用权利:在许可证约定的项目数量、开发者数量范围内使用本软件
// | 2. 技术支持:商业授权用户可以获取本地开发部署的技术支持服务
// | 3. 版本更新:在许可证有效期内获取软件更新、安全补丁和功能增强
// | 4. 商业部署:将基于本软件开发的应用程序用于商业运营和生产环境
// +======================================================================
// | 【许可证获取】
// | 1. 获取途径:仅通过小蚂蚁云官方渠道购买(官网、授权代理商),购买记录凭证
// | 2. 转让限制:许可证与购买主体绑定,未经书面同意不得转让
// | 3. 终止情形:许可证到期、违反协议、破产清算等情况下自动终止
// +======================================================================
// | 【合法使用要求】
// | 1. 仅限用于合法合规的软件研发
// | 2. 严禁用于任何违法、侵权或恶意行为
// | 3. 严禁违反我国法律法规和政策
// +======================================================================
// | 【免责声明】
// | 因使用本框架导致的以下情况,我们概不负责:
// | 1. 项目研发中的意外、疏忽、违约等风险
// | 2. 侵犯第三方知识产权或其他合法权益
// | 3. 任何直接、间接、附带或衍生一切损失
// | 4. 用户违规违法行为的一切法律后果
// +======================================================================
// | 【协议重要提示】
// | 1. 本声明是《小蚂蚁云最终用户许可协议》的摘要版本
// | 2. 下载、安装或使用本软件即表示您接受全部协议条款
// | 3. 我们保留单方面修改本声明的权利,修改后的版本在官网公布即生效
// | 4. 用户有义务定期查看最新版本,继续使用视为接受修改
// +======================================================================
// | 【侵权举报与合规】
// | 1. 知识产权侵权举报:请联系官方客服
// | 2. 许可证合规咨询:xiaomayicloud@163.com
// | 3. 违规使用将终止授权并追究责任
// | 4. 无条件配合司法机关调查取证
// | 5. 保留一切法律追诉权利
// | 6. 对有效举报和合规建议,我们将给予感谢和奖励
// +======================================================================
package com.xiaomayi.mybatis.handler;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.xiaomayi.core.config.AppConfig;
import com.xiaomayi.core.exception.BizException;
import com.xiaomayi.mybatis.model.BaseEntity;
import com.xiaomayi.mybatis.model.TenantEntity;
import com.xiaomayi.tenant.constant.TenantConstant;
import com.xiaomayi.core.utils.LoginUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Arrays;
/**
* <p>
* 自定义元对象数据填充处理
* </p>
*
* @author 小蚂蚁云团队
* @since 2024-03-23
*/
@Slf4j
@Component
public class MybatisMetaObjectHandler implements MetaObjectHandler {
/**
* 插入自动填充
*
* @param metaObject 元数据对象
*/
@Override
public void insertFill(MetaObject metaObject) {
try {
// ================================= 此处为演示环境专用,实际项目研发时可以删除《开始》 =============================
// 获取原始请求类对象
Class<?> classObj = metaObject.getOriginalObject().getClass();
// 设置忽略拦截的请求实体对象
String[] strings = new String[]{"LoginLog", "OperLog", "EmailLog", "FileLog", "SmsLog", "JobLog"};
// 演示环境设置非日志请求操作权限拦截
if (AppConfig.isDemo() && !Arrays.asList(strings).contains(classObj.getSimpleName())) {
throw new BizException("演示环境,禁止操作", HttpStatus.HTTP_FORBIDDEN);
}
// ================================= 此处为演示环境专用,实际项目研发时可以删除《结束》 =============================
if (ObjectUtil.isNotNull(metaObject)) {
// 基类基础字段数据填充处理
if (metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
// 获取当前时间
LocalDateTime localDateTime = ObjectUtil.isNotNull(baseEntity.getCreateTime())
? baseEntity.getCreateTime() : LocalDateTime.now();
// 设置创建时间
baseEntity.setCreateTime(localDateTime);
// 设置更新时间
baseEntity.setUpdateTime(localDateTime);
// 设置填充创建人、更新人
if (ObjectUtil.isNull(baseEntity.getCreateUser())) {
// 获取用户登录账号
String username = LoginUtils.getUsername();
if (ObjectUtil.isNotEmpty(username)) {
// 设置填充创建人
baseEntity.setCreateUser(username);
// 设置填充更新人
baseEntity.setUpdateUser(username);
}
}
}
// 租户ID字段数据填充处理
if (metaObject.getOriginalObject() instanceof TenantEntity tenantEntity) {
// 元对象自动填充租户ID
if (metaObject.hasGetter(TenantConstant.TENANT_ID_PARAM) && ObjectUtil.isNull(tenantEntity.getTenantId())) {
tenantEntity.setTenantId(LoginUtils.getTenantId());
}
}
}
} catch (Exception e) {
throw new BizException("填充处理异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
}
}
/**
* 更新自动填充
*
* @param metaObject 元数据对象
*/
@Override
public void updateFill(MetaObject metaObject) {
if (AppConfig.isDemo()) {
throw new BizException("演示环境,禁止操作", HttpStatus.HTTP_FORBIDDEN);
}
try {
if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
// 设置填充更新时间
baseEntity.setUpdateTime(LocalDateTime.now());
// 获取用户登录账号
String username = LoginUtils.getUsername();
// 设置填充更新人
if (ObjectUtil.isNotEmpty(username)) {
baseEntity.setUpdateUser(username);
}
}
} catch (Exception e) {
throw new BizException("填充处理异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
}
}
}
@@ -0,0 +1,642 @@
// +======================================================================
// | 小蚂蚁云·企业数字化开发平台 [ 加速数字化转型,构建智能未来 ]
// +----------------------------------------------------------------------
// | 核心价值:赋能开发者 · 服务企业 · 共建生态
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2026 小蚂蚁云团队 版权所有
// +----------------------------------------------------------------------
// | 官方平台: https://www.xiaomayicloud.com
// +======================================================================
// | 【知识产权声明】
// | 1. 权属声明:本软件是受《中华人民共和国著作权法》
// | 保护的专有财产,完整版权归小蚂蚁云团队所有
// | 2. 权利范围:所有知识产权(商标、专利、著作权、
// | 商业秘密等)均归小蚂蚁云团队所有,受法律保护
// | 3. 授权性质:用户仅可获得有限的、非独占的使用许可
// | 4. 禁止行为:未经书面授权,禁止对本软件本身
// | 申请任何知识产权
// | 5. 权利保留:未在本协议中明示授予的一切权利
// | 均由小蚂蚁云团队保留
// +======================================================================
// | 【授权状态说明】
// | 1. 未授权状态:用户未购买有效的商业许可证
// | 2. 商业授权:已购买正式商业许可证的用户
// +======================================================================
// | 【绝对禁止条款】
// | 无论授权状态如何,任何用户均严格禁止以下行为:
// | 1. 逆向工程:对软件进行反编译、反汇编、技术破解或任何形式的逆向分析
// | 2. 版权破坏:移除、修改、遮挡软件中的版权标识、许可控制或技术保护措施
// | 3. 非法传播:复制、分发、出租、出借、转售、再许可本软件或其许可权利
// | 4. 竞争性使用:利用本软件的代码、架构、设计开发直接竞争的产品或服务
// | 5. 侵权使用:将软件用于侵犯第三方知识产权或其他合法权益的用途
// +======================================================================
// | 【商业授权许可范围】
// | 购买有效商业许可证的用户,在遵守上述禁止条款的前提下,获得:
// | 1. 使用权利:在许可证约定的项目数量、开发者数量范围内使用本软件
// | 2. 技术支持:商业授权用户可以获取本地开发部署的技术支持服务
// | 3. 版本更新:在许可证有效期内获取软件更新、安全补丁和功能增强
// | 4. 商业部署:将基于本软件开发的应用程序用于商业运营和生产环境
// +======================================================================
// | 【许可证获取】
// | 1. 获取途径:仅通过小蚂蚁云官方渠道购买(官网、授权代理商),购买记录凭证
// | 2. 转让限制:许可证与购买主体绑定,未经书面同意不得转让
// | 3. 终止情形:许可证到期、违反协议、破产清算等情况下自动终止
// +======================================================================
// | 【合法使用要求】
// | 1. 仅限用于合法合规的软件研发
// | 2. 严禁用于任何违法、侵权或恶意行为
// | 3. 严禁违反我国法律法规和政策
// +======================================================================
// | 【免责声明】
// | 因使用本框架导致的以下情况,我们概不负责:
// | 1. 项目研发中的意外、疏忽、违约等风险
// | 2. 侵犯第三方知识产权或其他合法权益
// | 3. 任何直接、间接、附带或衍生一切损失
// | 4. 用户违规违法行为的一切法律后果
// +======================================================================
// | 【协议重要提示】
// | 1. 本声明是《小蚂蚁云最终用户许可协议》的摘要版本
// | 2. 下载、安装或使用本软件即表示您接受全部协议条款
// | 3. 我们保留单方面修改本声明的权利,修改后的版本在官网公布即生效
// | 4. 用户有义务定期查看最新版本,继续使用视为接受修改
// +======================================================================
// | 【侵权举报与合规】
// | 1. 知识产权侵权举报:请联系官方客服
// | 2. 许可证合规咨询:xiaomayicloud@163.com
// | 3. 违规使用将终止授权并追究责任
// | 4. 无条件配合司法机关调查取证
// | 5. 保留一切法律追诉权利
// | 6. 对有效举报和合规建议,我们将给予感谢和奖励
// +======================================================================
package com.xiaomayi.mybatis.interceptor;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.stereotype.Component;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.*;
/**
* <p>
* 执行SQL处理拦截器
* 功能:SQL执行日志打印,包含参数值和参数替换后的完整SQL语句
* 修复:避免参数值含有${}导致正则替换报错问题
* 特性:
* 1. 安全替换SQL占位符,避免参数值中的特殊字符影响
* 2. 支持多种数据类型格式化(字符串、数值、日期、集合、数组等)
* 3. 详细的参数信息输出
* 4. 完整的SQL语句还原
* 5. 执行耗时统计
* 6. 可配置的启用开关和慢SQL监控
* </p>
*
* @author 小蚂蚁云团队
* @since 2025-05-04
*/
@Intercepts(value = {
// 拦截Executor的update方法(插入、更新、删除操作)
@Signature(type = Executor.class, method = "update", args = {
MappedStatement.class, // SQL映射语句
Object.class // 参数对象
}),
// 拦截Executor的query方法(查询操作)- 两种重载形式
@Signature(type = Executor.class, method = "query", args = {
MappedStatement.class, // SQL映射语句
Object.class, // 参数对象
RowBounds.class, // 行边界(分页)
ResultHandler.class, // 结果处理器
CacheKey.class, // 缓存键
BoundSql.class // 绑定的SQL
}),
@Signature(type = Executor.class, method = "query", args = {
MappedStatement.class, // SQL映射语句
Object.class, // 参数对象
RowBounds.class, // 行边界(分页)
ResultHandler.class // 结果处理器
})
})
@Slf4j
@Component
public class MybatisPlusSqlInterceptor implements Interceptor {
/**
* 是否启用SQL日志打印
* 默认值:true(启用)
* 可通过配置文件修改:mybatis-plus.sql-interceptor.enabled=false
* -- GETTER --
* 获取是否启用SQL日志打印
* <p>
* <p>
* -- SETTER --
* 设置是否启用SQL日志打印
*/
private boolean enabled = true;
/**
* SQL执行超时阈值(毫秒),超过此时间会打印警告日志
* 默认值:5000毫秒(5秒)
* 可通过配置文件修改:mybatis-plus.sql-interceptor.slow-sql-threshold=3000
* -- GETTER --
* 获取慢SQL阈值(毫秒)
* <p>
* <p>
* -- SETTER --
* 设置慢SQL阈值(毫秒)
*/
private long slowSqlThreshold = 5000L;
/**
* 日期格式化器 - 使用ThreadLocal保证线程安全
* 每个线程拥有独立的DateFormat实例,避免多线程下的日期格式化问题
*/
private static final ThreadLocal<DateFormat> DATE_FORMATTER =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
/**
* 拦截器核心方法 - 增强SQL执行日志输出
* 在SQL执行前后进行拦截,记录执行耗时、参数信息、完整SQL等
*
* @param invocation 拦截器调用上下文,包含被拦截的方法信息
* @return 原始方法的执行结果
* @throws Throwable 可能抛出的异常
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 如果未启用SQL日志打印,直接执行原始方法并返回
if (!enabled) {
return invocation.proceed();
}
// 记录SQL执行开始时间,用于计算执行耗时
long startTime = System.currentTimeMillis();
// 执行原始方法(即实际的SQL执行)
Object result = invocation.proceed();
// 记录SQL执行结束时间
long endTime = System.currentTimeMillis();
// 计算SQL执行耗时(毫秒)
long executionTime = endTime - startTime;
try {
// 获取MappedStatement,它包含SQL语句的配置信息(如SQL ID、SQL类型等)
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
// 获取方法参数:对于update操作是第二个参数,对于query操作也是第二个参数
Object parameter = invocation.getArgs().length > 1 ? invocation.getArgs()[1] : null;
// 获取BoundSql,它包含实际的SQL语句和参数映射信息
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
// 获取MyBatis配置信息,用于后续的参数处理
Configuration configuration = mappedStatement.getConfiguration();
// 获取SQL语句ID(格式:包名.类名.方法名)
String sqlId = mappedStatement.getId();
// 获取原始SQL语句,并压缩连续空白字符为单个空格
String originalSql = boundSql.getSql().replaceAll("\\s+", " ");
// 获取参数映射列表,描述SQL中的每个占位符对应的参数信息
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
// 获取参数对象
Object parameterObject = boundSql.getParameterObject();
// 构建详细的参数信息映射(参数名 -> 参数值)
Map<String, Object> paramDetailMap = buildParameterDetails(configuration, boundSql, parameterMappings, parameterObject);
// 生成替换参数后的完整SQL语句(将?占位符替换为实际参数值)
String completeSql = generateCompleteSql(originalSql, paramDetailMap);
// 根据执行时间判断日志级别:超时SQL使用WARN级别,正常SQL使用INFO级别
if (executionTime > slowSqlThreshold) {
// 慢SQL警告日志:包含完整的SQL信息和执行时间
logSlowSqlWarning(sqlId, originalSql, completeSql, paramDetailMap, executionTime);
} else {
// 正常SQL信息日志
logSqlExecutionReport(sqlId, originalSql, completeSql, paramDetailMap, executionTime);
}
} catch (Exception e) {
// 日志处理异常不应影响主业务流程,仅记录警告日志
log.warn("SQL日志打印异常,但不影响业务执行: {}", e.getMessage());
}
// 返回原始方法的执行结果
return result;
}
/**
* 构建参数详细信息映射
* 从BoundSql中提取所有参数的名称和实际值,用于后续的SQL构造和日志输出
*
* @param configuration MyBatis配置信息,用于创建MetaObject
* @param boundSql BoundSql对象,包含SQL和参数信息
* @param parameterMappings 参数映射列表,描述SQL中的参数占位符
* @param parameterObject 原始参数对象
* @return 参数名到参数值的映射,保持参数顺序
*/
private Map<String, Object> buildParameterDetails(Configuration configuration,
BoundSql boundSql,
List<ParameterMapping> parameterMappings,
Object parameterObject) {
// 使用LinkedHashMap保持参数插入顺序,便于阅读和调试
Map<String, Object> paramMap = new LinkedHashMap<>();
// 如果没有参数映射,直接返回空Map
if (CollectionUtils.isEmpty(parameterMappings)) {
return paramMap;
}
// 获取类型处理器注册表,用于判断参数对象是否有对应的类型处理器
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
// 创建参数对象的元对象,用于反射获取属性值
MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject);
// 遍历所有参数映射,提取每个参数的名称和值
for (ParameterMapping parameterMapping : parameterMappings) {
String propertyName = parameterMapping.getProperty();
Object value = null;
try {
// 优先从BoundSql的附加参数中获取(如分页参数等)
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
}
// 其次从元对象中通过反射获取属性值
else if (metaObject != null && metaObject.hasGetter(propertyName)) {
value = metaObject.getValue(propertyName);
}
// 如果参数对象本身有类型处理器,直接使用整个参数对象
// 这种情况通常出现在参数是简单类型(如String、Integer等)
else if (parameterObject != null && typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
}
} catch (Exception e) {
// 获取参数值过程中发生异常,记录调试信息并使用提示文本
log.debug("获取参数值异常,参数名: {}, 异常信息: {}", propertyName, e.getMessage());
value = "【参数获取失败】";
}
// 将参数名和值放入映射中
paramMap.put(propertyName, value);
}
return paramMap;
}
/**
* 生成替换参数后的完整SQL语句
* 使用安全的方式逐个替换SQL中的?占位符,避免参数值中的特殊字符影响替换过程
*
* @param originalSql 原始SQL语句(包含?占位符)
* @param paramDetails 参数详情映射(参数名 -> 参数值)
* @return 替换参数后的完整SQL语句
*/
private String generateCompleteSql(String originalSql, Map<String, Object> paramDetails) {
// 如果没有参数,直接返回原始SQL
if (paramDetails.isEmpty()) {
return originalSql;
}
// 将SQL转换为字符数组进行安全处理,避免使用正则表达式替换
char[] sqlChars = originalSql.toCharArray();
StringBuilder completeSql = new StringBuilder();
int paramIndex = 0;
// 将参数值转换为列表,便于按顺序获取
List<Object> paramValues = new ArrayList<>(paramDetails.values());
// 遍历SQL字符数组,逐个字符处理
for (char sqlChar : sqlChars) {
// 遇到?占位符且还有参数值需要替换
if (sqlChar == '?' && paramIndex < paramValues.size()) {
// 安全替换占位符:将?替换为格式化后的参数值
completeSql.append(formatParameterValue(paramValues.get(paramIndex)));
paramIndex++;
} else {
// 非占位符字符,直接追加
completeSql.append(sqlChar);
}
}
return completeSql.toString();
}
/**
* 格式化参数值为SQL字符串
* 根据参数的实际类型进行适当的格式化处理,确保生成的SQL语法正确
* 安全处理各种数据类型,避免SQL注入和格式错误
*
* @param parameter 参数值
* @return 格式化后的SQL参数值,可直接嵌入SQL语句
*/
private String formatParameterValue(Object parameter) {
// 处理null值
if (parameter == null) {
return "NULL";
}
// 字符串类型 - 需要转义单引号,避免SQL语法错误
if (parameter instanceof String stringValue) {
// 转义单引号:将'替换为'',这是SQL标准转义方式
stringValue = stringValue.replace("'", "''");
return "'" + stringValue + "'";
}
// 数值类型(Integer、Long、Double等)- 直接转换为字符串
if (parameter instanceof Number) {
return parameter.toString();
}
// 布尔类型 - 转换为1或0(数据库通常用0/1表示布尔值)
if (parameter instanceof Boolean) {
return Boolean.TRUE.equals(parameter) ? "1" : "0";
}
// Java 8 日期时间类型(LocalDateTime、LocalDate、LocalTime)
if (parameter instanceof TemporalAccessor) {
return formatTemporalAccessor((TemporalAccessor) parameter);
}
// 传统Date类型
if (parameter instanceof Date) {
// 使用同步块确保线程安全
synchronized (DATE_FORMATTER) {
return "'" + DATE_FORMATTER.get().format((Date) parameter) + "'";
}
}
// 集合类型(如IN查询参数:WHERE id IN (1,2,3))
if (parameter instanceof Collection) {
return formatCollectionParameter((Collection<?>) parameter);
}
// 数组类型
if (parameter.getClass().isArray()) {
return formatArrayParameter(parameter);
}
// 其他类型默认处理:转换为字符串并转义单引号
return "'" + parameter.toString().replace("'", "''") + "'";
}
/**
* 处理Java 8日期时间类型参数
* 根据具体的时间类型使用合适的格式化模式
*
* @param temporal 时间对象(LocalDateTime、LocalDate、LocalTime)
* @return 格式化后的日期时间字符串,用单引号包围
*/
private String formatTemporalAccessor(TemporalAccessor temporal) {
// LocalDateTime类型:包含日期和时间
if (temporal instanceof LocalDateTime) {
return "'" + ((LocalDateTime) temporal).format(
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "'";
}
// LocalDate类型:仅包含日期
if (temporal instanceof LocalDate) {
return "'" + ((LocalDate) temporal).format(
DateTimeFormatter.ofPattern("yyyy-MM-dd")) + "'";
}
// LocalTime类型:仅包含时间
if (temporal instanceof LocalTime) {
return "'" + ((LocalTime) temporal).format(
DateTimeFormatter.ofPattern("HH:mm:ss")) + "'";
}
// 其他TemporalAccessor子类型:使用默认的toString方法
return "'" + temporal.toString() + "'";
}
/**
* 处理集合类型参数(主要用于IN查询)
* 将集合转换为逗号分隔的值列表,如:(1,2,3,4)
*
* @param collection 集合参数(List、Set等)
* @return 格式化后的IN查询参数列表
*/
private String formatCollectionParameter(Collection<?> collection) {
// 空集合处理
if (CollectionUtils.isEmpty(collection)) {
return "NULL";
}
StringBuilder sb = new StringBuilder();
// 遍历集合中的每个元素
for (Object item : collection) {
// 非第一个元素前添加逗号分隔符
if (!sb.isEmpty()) {
sb.append(",");
}
// 递归格式化集合中的元素
sb.append(formatParameterValue(item));
}
return sb.toString();
}
/**
* 处理数组类型参数
* 支持基本类型数组和对象数组的格式化
*
* @param array 数组参数
* @return 格式化后的数组参数列表
*/
private String formatArrayParameter(Object array) {
// 空数组处理
if (array == null) {
return "NULL";
}
// 基本类型数组处理:需要先装箱为对象数组
if (array instanceof int[]) {
// int[] 转 Integer[]
return formatPrimitiveArray(Arrays.stream((int[]) array).boxed().toArray());
} else if (array instanceof long[]) {
// long[] 转 Long[]
return formatPrimitiveArray(Arrays.stream((long[]) array).boxed().toArray());
} else if (array instanceof double[]) {
// double[] 转 Double[]
return formatPrimitiveArray(Arrays.stream((double[]) array).boxed().toArray());
} else if (array instanceof boolean[]) {
// boolean[] 转 Boolean[]
Boolean[] boxedArray = new Boolean[((boolean[]) array).length];
for (int i = 0; i < ((boolean[]) array).length; i++) {
boxedArray[i] = ((boolean[]) array)[i];
}
return formatPrimitiveArray(boxedArray);
}
// 对象数组处理:直接转换为集合处理
return formatCollectionParameter(Arrays.asList((Object[]) array));
}
/**
* 处理基本类型的装箱后数组
* 辅助方法,用于处理基本类型数组转换后的对象数组
*
* @param array 装箱后的对象数组
* @return 格式化后的数组参数列表
*/
private String formatPrimitiveArray(Object[] array) {
StringBuilder sb = new StringBuilder();
// 遍历数组中的每个元素
for (Object item : array) {
// 非第一个元素前添加逗号分隔符
if (!sb.isEmpty()) {
sb.append(",");
}
// 格式化数组元素
sb.append(formatParameterValue(item));
}
return sb.toString();
}
/**
* 格式化输出SQL执行报告 - 正常SQL
* 生成结构化的日志输出,包含SQL执行的完整信息,使用INFO级别
*
* @param sqlId SQL语句ID(Mapper方法全限定名)
* @param originalSql 原始SQL语句(带?占位符)
* @param completeSql 完整SQL语句(参数替换后)
* @param paramDetails 参数详情映射
* @param executionTime 执行耗时(毫秒)
*/
private void logSqlExecutionReport(String sqlId, String originalSql, String completeSql,
Map<String, Object> paramDetails, long executionTime) {
StringBuilder report = new StringBuilder();
// 构建格式化的日志输出
report.append("\n").append("=".repeat(50)); // 顶部装饰线
report.append("\n【SQL执行报告】"); // 标题
report.append("\n").append("-".repeat(50)); // 分隔线
// SQL ID信息
report.append("\n■ SQL ID : ").append(sqlId);
// 原始SQL语句(便于对比查看)
report.append("\n■ 原始SQL : ").append(originalSql);
// 完整SQL语句(可直接复制执行)
report.append("\n■ 完整SQL : ").append(completeSql);
// 参数详情输出(如果有参数)
if (!paramDetails.isEmpty()) {
report.append("\n■ 参数详情 : ");
// 遍历所有参数,格式化输出
paramDetails.forEach((key, value) ->
report.append("\n - ").append(key).append(" = ").append(value)
);
}
// 执行耗时信息
report.append("\n■ 执行耗时 : ").append(executionTime).append("ms");
report.append("\n").append("=".repeat(50)); // 底部装饰线
// 输出到日志系统,使用INFO级别
log.info(report.toString());
}
/**
* 格式化输出慢SQL警告日志
* 生成结构化的警告日志输出,包含慢SQL的完整信息,使用WARN级别
*
* @param sqlId SQL语句ID(Mapper方法全限定名)
* @param originalSql 原始SQL语句(带?占位符)
* @param completeSql 完整SQL语句(参数替换后)
* @param paramDetails 参数详情映射
* @param executionTime 执行耗时(毫秒)
*/
private void logSlowSqlWarning(String sqlId, String originalSql, String completeSql,
Map<String, Object> paramDetails, long executionTime) {
StringBuilder warning = new StringBuilder();
// 构建格式化的警告日志输出
warning.append("\n").append("!".repeat(60)); // 警告装饰线
warning.append("\n【慢SQL警告】执行时间: ").append(executionTime).append("ms (阈值: ").append(slowSqlThreshold).append("ms)");
warning.append("\n").append("-".repeat(60)); // 分隔线
// SQL ID信息
warning.append("\n■ SQL ID : ").append(sqlId);
// 原始SQL语句
warning.append("\n■ 原始SQL : ").append(originalSql);
// 完整SQL语句
warning.append("\n■ 完整SQL : ").append(completeSql);
// 参数详情输出(如果有参数)
if (!paramDetails.isEmpty()) {
warning.append("\n■ 参数详情 : ");
// 遍历所有参数,格式化输出
paramDetails.forEach((key, value) ->
warning.append("\n - ").append(key).append(" = ").append(value)
);
}
// 执行耗时和阈值信息
warning.append("\n■ 执行耗时 : ").append(executionTime).append("ms (超过阈值: ").append(slowSqlThreshold).append("ms)");
warning.append("\n").append("!".repeat(60)); // 底部警告装饰线
// 输出到日志系统,使用WARN级别
log.warn(warning.toString());
}
/**
* 插件包装方法
* MyBatis拦截器标准方法,用于包装目标对象
*
* @param target 被拦截的目标对象
* @return 包装后的对象
*/
@Override
public Object plugin(Object target) {
return Interceptor.super.plugin(target);
}
/**
* 设置拦截器属性
* MyBatis拦截器标准方法,用于接收配置参数
* 可以从MyBatis配置文件中读取属性值
*
* @param properties 配置属性
*/
@Override
public void setProperties(Properties properties) {
// 从配置中读取enabled属性,默认为true
if (properties.containsKey("enabled")) {
this.enabled = Boolean.parseBoolean(properties.getProperty("enabled"));
log.debug("SQL拦截器启用状态: {}", this.enabled);
}
// 从配置中读取slowSqlThreshold属性,默认为5000毫秒
if (properties.containsKey("slowSqlThreshold")) {
try {
this.slowSqlThreshold = Long.parseLong(properties.getProperty("slowSqlThreshold"));
log.debug("慢SQL阈值设置: {}ms", this.slowSqlThreshold);
} catch (NumberFormatException e) {
log.warn("慢SQL阈值配置格式错误,使用默认值: {}ms", this.slowSqlThreshold);
}
}
Interceptor.super.setProperties(properties);
}
}
@@ -0,0 +1,136 @@
// +======================================================================
// | 小蚂蚁云·企业数字化开发平台 [ 加速数字化转型,构建智能未来 ]
// +----------------------------------------------------------------------
// | 核心价值:赋能开发者 · 服务企业 · 共建生态
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2026 小蚂蚁云团队 版权所有
// +----------------------------------------------------------------------
// | 官方平台: https://www.xiaomayicloud.com
// +======================================================================
// | 【知识产权声明】
// | 1. 权属声明:本软件是受《中华人民共和国著作权法》
// | 保护的专有财产,完整版权归小蚂蚁云团队所有
// | 2. 权利范围:所有知识产权(商标、专利、著作权、
// | 商业秘密等)均归小蚂蚁云团队所有,受法律保护
// | 3. 授权性质:用户仅可获得有限的、非独占的使用许可
// | 4. 禁止行为:未经书面授权,禁止对本软件本身
// | 申请任何知识产权
// | 5. 权利保留:未在本协议中明示授予的一切权利
// | 均由小蚂蚁云团队保留
// +======================================================================
// | 【授权状态说明】
// | 1. 未授权状态:用户未购买有效的商业许可证
// | 2. 商业授权:已购买正式商业许可证的用户
// +======================================================================
// | 【绝对禁止条款】
// | 无论授权状态如何,任何用户均严格禁止以下行为:
// | 1. 逆向工程:对软件进行反编译、反汇编、技术破解或任何形式的逆向分析
// | 2. 版权破坏:移除、修改、遮挡软件中的版权标识、许可控制或技术保护措施
// | 3. 非法传播:复制、分发、出租、出借、转售、再许可本软件或其许可权利
// | 4. 竞争性使用:利用本软件的代码、架构、设计开发直接竞争的产品或服务
// | 5. 侵权使用:将软件用于侵犯第三方知识产权或其他合法权益的用途
// +======================================================================
// | 【商业授权许可范围】
// | 购买有效商业许可证的用户,在遵守上述禁止条款的前提下,获得:
// | 1. 使用权利:在许可证约定的项目数量、开发者数量范围内使用本软件
// | 2. 技术支持:商业授权用户可以获取本地开发部署的技术支持服务
// | 3. 版本更新:在许可证有效期内获取软件更新、安全补丁和功能增强
// | 4. 商业部署:将基于本软件开发的应用程序用于商业运营和生产环境
// +======================================================================
// | 【许可证获取】
// | 1. 获取途径:仅通过小蚂蚁云官方渠道购买(官网、授权代理商),购买记录凭证
// | 2. 转让限制:许可证与购买主体绑定,未经书面同意不得转让
// | 3. 终止情形:许可证到期、违反协议、破产清算等情况下自动终止
// +======================================================================
// | 【合法使用要求】
// | 1. 仅限用于合法合规的软件研发
// | 2. 严禁用于任何违法、侵权或恶意行为
// | 3. 严禁违反我国法律法规和政策
// +======================================================================
// | 【免责声明】
// | 因使用本框架导致的以下情况,我们概不负责:
// | 1. 项目研发中的意外、疏忽、违约等风险
// | 2. 侵犯第三方知识产权或其他合法权益
// | 3. 任何直接、间接、附带或衍生一切损失
// | 4. 用户违规违法行为的一切法律后果
// +======================================================================
// | 【协议重要提示】
// | 1. 本声明是《小蚂蚁云最终用户许可协议》的摘要版本
// | 2. 下载、安装或使用本软件即表示您接受全部协议条款
// | 3. 我们保留单方面修改本声明的权利,修改后的版本在官网公布即生效
// | 4. 用户有义务定期查看最新版本,继续使用视为接受修改
// +======================================================================
// | 【侵权举报与合规】
// | 1. 知识产权侵权举报:请联系官方客服
// | 2. 许可证合规咨询:xiaomayicloud@163.com
// | 3. 违规使用将终止授权并追究责任
// | 4. 无条件配合司法机关调查取证
// | 5. 保留一切法律追诉权利
// | 6. 对有效举报和合规建议,我们将给予感谢和奖励
// +======================================================================
package com.xiaomayi.mybatis.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 基类实体对象
* </p>
*
* @author 小蚂蚁云团队
* @since 2023-06-16
*/
@Data
public class BaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 创建人
*/
@TableField(fill = FieldFill.INSERT)
private String createUser;
/**
* 创建时间
*/
// @JSONField(format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* 更新人
*/
@TableField(fill = FieldFill.INSERT)
private String updateUser;
/**
* 更新时间
*/
// @JSONField(format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
/**
* 删除标识:0-有效 1-删除
*/
@TableLogic
private Integer delFlag;
}
@@ -0,0 +1,103 @@
// +======================================================================
// | 小蚂蚁云·企业数字化开发平台 [ 加速数字化转型,构建智能未来 ]
// +----------------------------------------------------------------------
// | 核心价值:赋能开发者 · 服务企业 · 共建生态
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2026 小蚂蚁云团队 版权所有
// +----------------------------------------------------------------------
// | 官方平台: https://www.xiaomayicloud.com
// +======================================================================
// | 【知识产权声明】
// | 1. 权属声明:本软件是受《中华人民共和国著作权法》
// | 保护的专有财产,完整版权归小蚂蚁云团队所有
// | 2. 权利范围:所有知识产权(商标、专利、著作权、
// | 商业秘密等)均归小蚂蚁云团队所有,受法律保护
// | 3. 授权性质:用户仅可获得有限的、非独占的使用许可
// | 4. 禁止行为:未经书面授权,禁止对本软件本身
// | 申请任何知识产权
// | 5. 权利保留:未在本协议中明示授予的一切权利
// | 均由小蚂蚁云团队保留
// +======================================================================
// | 【授权状态说明】
// | 1. 未授权状态:用户未购买有效的商业许可证
// | 2. 商业授权:已购买正式商业许可证的用户
// +======================================================================
// | 【绝对禁止条款】
// | 无论授权状态如何,任何用户均严格禁止以下行为:
// | 1. 逆向工程:对软件进行反编译、反汇编、技术破解或任何形式的逆向分析
// | 2. 版权破坏:移除、修改、遮挡软件中的版权标识、许可控制或技术保护措施
// | 3. 非法传播:复制、分发、出租、出借、转售、再许可本软件或其许可权利
// | 4. 竞争性使用:利用本软件的代码、架构、设计开发直接竞争的产品或服务
// | 5. 侵权使用:将软件用于侵犯第三方知识产权或其他合法权益的用途
// +======================================================================
// | 【商业授权许可范围】
// | 购买有效商业许可证的用户,在遵守上述禁止条款的前提下,获得:
// | 1. 使用权利:在许可证约定的项目数量、开发者数量范围内使用本软件
// | 2. 技术支持:商业授权用户可以获取本地开发部署的技术支持服务
// | 3. 版本更新:在许可证有效期内获取软件更新、安全补丁和功能增强
// | 4. 商业部署:将基于本软件开发的应用程序用于商业运营和生产环境
// +======================================================================
// | 【许可证获取】
// | 1. 获取途径:仅通过小蚂蚁云官方渠道购买(官网、授权代理商),购买记录凭证
// | 2. 转让限制:许可证与购买主体绑定,未经书面同意不得转让
// | 3. 终止情形:许可证到期、违反协议、破产清算等情况下自动终止
// +======================================================================
// | 【合法使用要求】
// | 1. 仅限用于合法合规的软件研发
// | 2. 严禁用于任何违法、侵权或恶意行为
// | 3. 严禁违反我国法律法规和政策
// +======================================================================
// | 【免责声明】
// | 因使用本框架导致的以下情况,我们概不负责:
// | 1. 项目研发中的意外、疏忽、违约等风险
// | 2. 侵犯第三方知识产权或其他合法权益
// | 3. 任何直接、间接、附带或衍生一切损失
// | 4. 用户违规违法行为的一切法律后果
// +======================================================================
// | 【协议重要提示】
// | 1. 本声明是《小蚂蚁云最终用户许可协议》的摘要版本
// | 2. 下载、安装或使用本软件即表示您接受全部协议条款
// | 3. 我们保留单方面修改本声明的权利,修改后的版本在官网公布即生效
// | 4. 用户有义务定期查看最新版本,继续使用视为接受修改
// +======================================================================
// | 【侵权举报与合规】
// | 1. 知识产权侵权举报:请联系官方客服
// | 2. 许可证合规咨询:xiaomayicloud@163.com
// | 3. 违规使用将终止授权并追究责任
// | 4. 无条件配合司法机关调查取证
// | 5. 保留一切法律追诉权利
// | 6. 对有效举报和合规建议,我们将给予感谢和奖励
// +======================================================================
package com.xiaomayi.mybatis.model;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* <p>
* 租户基类实体对象
* </p>
*
* @author 小蚂蚁云团队
* @since 2023-06-16
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TenantEntity extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 租户ID
*/
@TableField(value = "tenant_id", fill = FieldFill.INSERT)
private Integer tenantId;
}