初始化仓库
This commit is contained in:
20
xtools-boot-db/pom.xml
Normal file
20
xtools-boot-db/pom.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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>org.xujun</groupId>
|
||||
<artifactId>xtools-boot</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</parent>
|
||||
<packaging>pom</packaging>
|
||||
<artifactId>xtools-boot-db</artifactId>
|
||||
|
||||
<!-- 子模块 -->
|
||||
<modules>
|
||||
<module>xtools-boot-db-mybatis</module>
|
||||
<module>xtools-boot-db-mybatis-plus</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
37
xtools-boot-db/xtools-boot-db-mybatis-plus/pom.xml
Normal file
37
xtools-boot-db/xtools-boot-db-mybatis-plus/pom.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-db</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</parent>
|
||||
<artifactId>xtools-boot-db-mybatis-plus</artifactId>
|
||||
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<!-- xtools-boot begin -->
|
||||
<!-- xtools-boot-core -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-core</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-boot end -->
|
||||
|
||||
<!-- SpringBoot begin -->
|
||||
<!-- mybatis-plus begin -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-jsqlparser</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot4-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- mybatis-plus end -->
|
||||
<!-- SpringBoot end -->
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package xtools.boot.db.mybatisplus;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import xtools.boot.core.utils.ModuleLoadUtils;
|
||||
import xtools.boot.db.mybatisplus.selector.BootDbMybatisPlusImportSelector;
|
||||
|
||||
/**
|
||||
* <p>Title : BootCacheRedisConfiguration</p>
|
||||
* <p>Description : BootCacheRedisConfiguration</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/01/01 09:30
|
||||
*/
|
||||
@Import(BootDbMybatisPlusImportSelector.class)
|
||||
public class BootDbMybatisPlusConfiguration {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public BootDbMybatisPlusConfiguration() {
|
||||
ModuleLoadUtils.loadSuccess(BootDbMybatisPlusConfiguration.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package xtools.boot.db.mybatisplus.config;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* <p>Title : MybatisPlusConfig</p>
|
||||
* <p>Description : MybatisPlusConfig</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/1/5 10:15
|
||||
*/
|
||||
@Configuration
|
||||
public class MybatisPlusConfig {
|
||||
|
||||
/**
|
||||
* 配置 MybatisPlus 拦截器
|
||||
*
|
||||
* @return MybatisPlus 拦截器
|
||||
*/
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
// 添加分页插件
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package xtools.boot.db.mybatisplus.selector;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* <p>Title : BootDbMybatisPlusImportSelector</p>
|
||||
* <p>Description : BootDbMybatisPlusImportSelector</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/01/01 09:30
|
||||
*/
|
||||
public class BootDbMybatisPlusImportSelector implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
/**
|
||||
* 根据给定的注释元数据,根据需要注册bean
|
||||
*
|
||||
* @param importingClassMetadata AnnotationMetadata
|
||||
* @param registry BeanDefinitionRegistry
|
||||
*/
|
||||
@Override
|
||||
public void registerBeanDefinitions(@NonNull AnnotationMetadata importingClassMetadata, @NonNull BeanDefinitionRegistry registry) {
|
||||
// 构建扫描对象
|
||||
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, true);
|
||||
// 扫描包下路径
|
||||
scanner.scan("xtools.boot.db.mybatisplus");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package xtools.boot.db.mybatisplus.utils;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.core.ArrUtils;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : QueryUtils</p>
|
||||
* <p>Description : QueryUtils</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/1/17 19:16
|
||||
*/
|
||||
public class QueryUtils implements BaseParams {
|
||||
|
||||
/**
|
||||
* 添加时间范围查询
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param timeRange 时间范围
|
||||
* @param timeField 时间字段
|
||||
* @param <T> 泛型
|
||||
*/
|
||||
public static <T> void addTimeRange(LambdaQueryWrapper<T> query, Instant[] timeRange, SFunction<T, ?> timeField) {
|
||||
if (ArrUtils.isEmpty(timeRange) || timeRange.length != CP_NUM2) {
|
||||
return;
|
||||
}
|
||||
query.ge(Objects.nonNull(timeRange[CP_NUM0]), timeField, timeRange[CP_NUM0]);
|
||||
query.le(Objects.nonNull(timeRange[CP_NUM1]), timeField, timeRange[CP_NUM1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分页条件
|
||||
*
|
||||
* @param currentPage 当前页
|
||||
* @param pageSize 页面大小
|
||||
* @param <T> 泛型
|
||||
* @return 分页条件
|
||||
*/
|
||||
public static <T> Page<T> getPage(Integer currentPage, Integer pageSize) {
|
||||
if (Objects.isNull(currentPage) || currentPage < CP_NUM1) {
|
||||
currentPage = CP_NUM1;
|
||||
}
|
||||
if (Objects.isNull(pageSize) || pageSize < CP_NUM1) {
|
||||
pageSize = CP_NUM10;
|
||||
}
|
||||
return new Page<>(currentPage, pageSize);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
xtools.boot.db.mybatisplus.BootDbMybatisPlusConfiguration
|
||||
67
xtools-boot-db/xtools-boot-db-mybatis/pom.xml
Normal file
67
xtools-boot-db/xtools-boot-db-mybatis/pom.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-db</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</parent>
|
||||
<artifactId>xtools-boot-db-mybatis</artifactId>
|
||||
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<!-- xtools-boot begin -->
|
||||
<!-- xtools-boot-core -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-core</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-boot-log -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-log</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-boot-thread -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-thread</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-boot end -->
|
||||
|
||||
<!-- SpringBoot begin -->
|
||||
<!-- MyBatis -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- SpringBoot end -->
|
||||
|
||||
<!-- MySQL 驱动 -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Druid(数据库连接池) -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-4-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- fastjson2 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- servlet-api -->
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,30 @@
|
||||
package xtools.boot.db.mybatis;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import xtools.boot.core.utils.ModuleLoadUtils;
|
||||
import xtools.boot.db.mybatis.selector.BootDbMybatisImportSelector;
|
||||
|
||||
/**
|
||||
* <p>Title : BootDbMybatisConfiguration</p>
|
||||
* <p>Description : BootDbMybatisConfiguration</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/01/01 09:30
|
||||
*/
|
||||
@MapperScan({"xtools.boot.db.mybatis.mapper"})
|
||||
@Import(BootDbMybatisImportSelector.class)
|
||||
public class BootDbMybatisConfiguration {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public BootDbMybatisConfiguration() {
|
||||
ModuleLoadUtils.loadSuccess(BootDbMybatisConfiguration.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package xtools.boot.db.mybatis.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* <p>Title : MyBatisConfig</p>
|
||||
* <p>Description : MyBatisConfig</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/11 14:46
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "mybatis")
|
||||
public class MyBatisConfig {
|
||||
|
||||
/**
|
||||
* 是否开启MyBatis监控
|
||||
*/
|
||||
private Boolean monitor = true;
|
||||
|
||||
/**
|
||||
* 慢查询时间阈值
|
||||
*/
|
||||
private Integer slowTime = 3000;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package xtools.boot.db.mybatis.druid;
|
||||
|
||||
import com.alibaba.druid.spring.boot4.autoconfigure.properties.DruidStatProperties;
|
||||
import com.alibaba.druid.util.Utils;
|
||||
import jakarta.servlet.Filter;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.FilterConfig;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.core.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* <p>Title : DruidConf</p>
|
||||
* <p>Description : DruidConf</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2025年8月13日 上午8:06:06
|
||||
*/
|
||||
@Component
|
||||
@Configuration
|
||||
public class DruidConf {
|
||||
|
||||
/**
|
||||
* 广告过滤
|
||||
*
|
||||
* @param properties Druid配置信息
|
||||
* @return 广告过滤
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "spring.datasource.druid.web-stat-filter.enabled", havingValue = "true")
|
||||
public FilterRegistrationBean<Filter> removeDruidFilterRegistrationBean(DruidStatProperties properties) {
|
||||
DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
|
||||
String urlPattern = config.getUrlPattern();
|
||||
// 提取common.js的配置路径
|
||||
String pattern = StringUtils.isEmpty(urlPattern) ? "/druid/**" : urlPattern;
|
||||
String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
|
||||
final String filePath = "support/http/resources/js/common.js";
|
||||
// 创建filter进行过滤
|
||||
Filter filter = new Filter() {
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param filterConfig FilterConfig
|
||||
*/
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤器
|
||||
*
|
||||
* @param request ServletRequest
|
||||
* @param response ServletResponse
|
||||
* @param chain FilterChain
|
||||
*/
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
chain.doFilter(request, response);
|
||||
// 重置缓冲区,响应头不会被重置
|
||||
response.resetBuffer();
|
||||
// 获取common.js
|
||||
String text = Utils.readFromResource(filePath);
|
||||
// 正则替换banner, 除去底部的广告信息
|
||||
text = text.replaceAll("<a.*?banner\"></a><br/>", "");
|
||||
text = text.replaceAll("powered.*?shrek.wang</a>", "");
|
||||
response.getWriter().write(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
};
|
||||
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.addUrlPatterns(commonJsPattern);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package xtools.boot.db.mybatis.druid;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.boot.core.interfaces.FilterWhitelist;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>Title : DruidFilterWhitelist</p>
|
||||
* <p>Description : DruidFilterWhitelist</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/3/8 12:28
|
||||
*/
|
||||
@Component
|
||||
public class DruidFilterWhitelist implements FilterWhitelist {
|
||||
|
||||
/**
|
||||
* 添加过滤器白名单
|
||||
*
|
||||
* @return 过滤器白名单
|
||||
*/
|
||||
@Override
|
||||
public Set<String> add() {
|
||||
return Set.of(
|
||||
"/druid/**"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package xtools.boot.db.mybatis.enums;
|
||||
|
||||
import xtools.boot.api.enums.BaseEnum;
|
||||
|
||||
/**
|
||||
* <p>Title : MySqlMonitorEnums</p>
|
||||
* <p>Description : MySqlMonitorEnums</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/3 10:31
|
||||
*/
|
||||
public enum MySqlMonitorEnums implements BaseEnum {
|
||||
|
||||
// 进程列表
|
||||
PROCESSLIST(1, "进程列表", "SHOW FULL PROCESSLIST"),
|
||||
// 变量
|
||||
VARIABLES(2, "变量", "SHOW GLOBAL VARIABLES"),
|
||||
// 状态
|
||||
STATUS(3, "状态", "SHOW STATUS"),
|
||||
|
||||
// 需要权限
|
||||
// // 查看正在进行中的事务
|
||||
// INNODB_TRX(100, "查看正在进行中的事务", "SELECT * FROM information_schema.INNODB_TRX"),
|
||||
// // 查看正在锁的事务
|
||||
// INNODB_LOCKS(101, "查看正在锁的事务", "SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS"),
|
||||
// // 查看等待锁的事务
|
||||
// INNODB_LOCK_WAITS(102, "查看等待锁的事务", "SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS"),
|
||||
// // 查询是否锁表
|
||||
// LOCK_TABLES(103, "查询是否锁表", "SHOW OPEN TABLES where In_use > 0"),
|
||||
// // 查看最近死锁的日志
|
||||
// INNODB_STATUS(104, "查看最近死锁的日志", "show engine innodb status"),
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* SQL语句
|
||||
*/
|
||||
private final String sql;
|
||||
|
||||
/**
|
||||
* 初始化方法
|
||||
*
|
||||
* @param code Code
|
||||
* @param desc 说明
|
||||
* @param sql SQL
|
||||
*/
|
||||
MySqlMonitorEnums(int code, String desc, String sql) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断枚举值类型
|
||||
*
|
||||
* @param code 枚举值
|
||||
* @return 枚举值类型
|
||||
*/
|
||||
public static MySqlMonitorEnums valueOf(int code) {
|
||||
for (MySqlMonitorEnums type : values()) {
|
||||
if (type.code == code) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("unknown code, code=" + code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有枚举
|
||||
*
|
||||
* @return 所有枚举
|
||||
*/
|
||||
@Override
|
||||
public BaseEnum[] all() {
|
||||
return values();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举编码
|
||||
*
|
||||
* @return 枚举编码
|
||||
*/
|
||||
@Override
|
||||
public int code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举说明
|
||||
*
|
||||
* @return 枚举说明
|
||||
*/
|
||||
@Override
|
||||
public String desc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SQL
|
||||
*
|
||||
* @return SQL
|
||||
*/
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
package xtools.boot.db.mybatis.interceptor;
|
||||
|
||||
import com.alibaba.druid.pool.DruidPooledPreparedStatement;
|
||||
import com.alibaba.druid.proxy.jdbc.JdbcParameter;
|
||||
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.ibatis.executor.statement.StatementHandler;
|
||||
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.session.ResultHandler;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.boot.api.model.dto.log.LogTrack;
|
||||
import xtools.boot.db.mybatis.config.MyBatisConfig;
|
||||
import xtools.boot.log.LogBus;
|
||||
import xtools.boot.log.enums.LogBusBaseType;
|
||||
import xtools.boot.log.holder.LogTrackHolder;
|
||||
import xtools.boot.thread.utils.VirtualThreadTaskUtils;
|
||||
import xtools.core.CollectionUtils;
|
||||
import xtools.core.enums.LogLevel;
|
||||
import xtools.core.enums.TimePattern;
|
||||
import xtools.core.time.InstantUtils;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.Statement;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : MyBatisInterceptor</p>
|
||||
* <p>Description : MyBatisInterceptor</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/11 14:35
|
||||
*/
|
||||
@Component
|
||||
@Intercepts({
|
||||
@Signature(type = StatementHandler.class, method = MyBatisInterceptor.QUERY, args = {Statement.class, ResultHandler.class}),
|
||||
@Signature(type = StatementHandler.class, method = MyBatisInterceptor.UPDATE, args = {Statement.class})
|
||||
})
|
||||
public class MyBatisInterceptor implements Interceptor {
|
||||
|
||||
/**
|
||||
* 查询方法名
|
||||
**/
|
||||
public final static String QUERY = "query";
|
||||
/**
|
||||
* 更新方法名
|
||||
**/
|
||||
public final static String UPDATE = "update";
|
||||
|
||||
@Resource
|
||||
private MyBatisConfig conf;
|
||||
|
||||
/**
|
||||
* 拦截操作
|
||||
*
|
||||
* @param invocation 调用参数
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Object intercept(@NonNull Invocation invocation) throws Throwable {
|
||||
LogTrack log = LogTrackHolder.getDefNull();
|
||||
// 是否启动监控
|
||||
if (!conf.getMonitor() || Objects.isNull(log) || !log.save()) {
|
||||
return invocation.proceed();
|
||||
}
|
||||
// 执行结果
|
||||
Object result = null;
|
||||
// 异常信息
|
||||
Exception err = null;
|
||||
// 开始时间
|
||||
long startTime = System.currentTimeMillis();
|
||||
try {
|
||||
result = invocation.proceed();
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
err = e;
|
||||
throw e;
|
||||
} finally {
|
||||
// 获取当前线程日志信息
|
||||
LogTrack logTrack = LogTrackHolder.get();
|
||||
// 结束时间
|
||||
long endTime = System.currentTimeMillis();
|
||||
// 执行时间
|
||||
long execTime = endTime - startTime;
|
||||
// 执行结果信息
|
||||
final Object execResult = result;
|
||||
// 转换参数
|
||||
Throwable ft = err;
|
||||
// 处理SQL日志
|
||||
VirtualThreadTaskUtils.simple(() -> {
|
||||
// 获取运行参数
|
||||
Object runArg = invocation.getArgs()[0];
|
||||
// 读写标识
|
||||
String rw = QUERY.equals(invocation.getMethod().getName()) ? "读" : "写";
|
||||
// 日志信息
|
||||
JSONObject logData = JSONObject.of(
|
||||
"startTime", InstantUtils.format(InstantUtils.from(startTime), TimePattern.ALL),
|
||||
"execTime", execTime,
|
||||
"result", execResult,
|
||||
"rw", rw
|
||||
);
|
||||
// 是否为慢SQL
|
||||
logData.put("slowSql", execTime >= conf.getSlowTime());
|
||||
// 日志分析
|
||||
this.analysisLog(logTrack, logData, runArg, ft);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志分析
|
||||
*
|
||||
* @param logTrack 日志信息
|
||||
* @param log 日志信息
|
||||
* @param runArg 运行参数
|
||||
* @param t 异常
|
||||
*/
|
||||
private void analysisLog(LogTrack logTrack, JSONObject log, Object runArg, Throwable t) {
|
||||
try {
|
||||
// 获取sql信息
|
||||
JSONObject sqlInfo = this.getSqlInfo(runArg, logTrack, log);
|
||||
if (CollectionUtils.isNotEmpty(sqlInfo)) {
|
||||
log.putAll(sqlInfo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
t = e;
|
||||
} finally {
|
||||
this.execLog(logTrack, log, t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SQL信息
|
||||
*
|
||||
* @param runArg 运行参数
|
||||
* @param log 日志信息
|
||||
* @return SQL信息
|
||||
*/
|
||||
private JSONObject getSqlInfo(Object runArg, LogTrack logTrack, JSONObject log) {
|
||||
// 执行SQL
|
||||
String sql;
|
||||
// 参数
|
||||
JSONArray params = new JSONArray();
|
||||
|
||||
// 个性化参数获取方式
|
||||
if (DruidPooledPreparedStatement.class.equals(runArg.getClass())) {
|
||||
// 开启druid监控获取参数方式
|
||||
DruidPooledPreparedStatement statement = (DruidPooledPreparedStatement) runArg;
|
||||
sql = statement.getSql();
|
||||
try {
|
||||
JSONArray dp = this.getParams(statement);
|
||||
if (dp != null) {
|
||||
params = dp;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.execLog(logTrack, log, e);
|
||||
}
|
||||
} else {
|
||||
sql = runArg.toString();
|
||||
// 获取完整SQL
|
||||
sql = sql.substring(sql.indexOf(":") + 1);
|
||||
}
|
||||
// 格式化Sql
|
||||
sql = sql.replaceAll(",", ", ").replaceAll("\t+", " ").replaceAll("\n+", " ").replaceAll(" +", " ").trim();
|
||||
// 结果封装
|
||||
return JSONObject.of("sql", sql, "params", params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数
|
||||
*
|
||||
* @param statement DruidPooledPreparedStatement
|
||||
* @return 参数集合
|
||||
*/
|
||||
private JSONArray getParams(DruidPooledPreparedStatement statement) {
|
||||
if (statement == null) {
|
||||
return null;
|
||||
}
|
||||
PreparedStatement ps = statement.getRawStatement();
|
||||
if (ps == null) {
|
||||
return null;
|
||||
}
|
||||
if (!PreparedStatementProxyImpl.class.equals(ps.getClass())) {
|
||||
return null;
|
||||
}
|
||||
PreparedStatementProxyImpl psp = (PreparedStatementProxyImpl) ps;
|
||||
int parametersSize = psp.getParametersSize();
|
||||
if (parametersSize <= 0) {
|
||||
return null;
|
||||
}
|
||||
Map<Integer, JdbcParameter> paramMap = psp.getParameters();
|
||||
if (CollectionUtils.isEmpty(paramMap)) {
|
||||
return null;
|
||||
}
|
||||
// 参数
|
||||
JSONArray params = new JSONArray();
|
||||
paramMap.forEach((key, value) -> params.add(value.getValue()));
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理SQL日志
|
||||
*
|
||||
* @param logTrack 日志信息
|
||||
* @param log 日志信息
|
||||
* @param t 异常
|
||||
*/
|
||||
private void execLog(LogTrack logTrack, JSONObject log, Throwable t) {
|
||||
// 是否为慢SQL
|
||||
boolean slowSql = log.getBooleanValue("slowSql", false);
|
||||
// 日志级别
|
||||
LogLevel level = LogLevel.INFO;
|
||||
if (t != null) {
|
||||
level = LogLevel.ERROR;
|
||||
} else if (slowSql) {
|
||||
level = LogLevel.WARN;
|
||||
}
|
||||
// 获取读写
|
||||
String rw = log.getString("rw");
|
||||
log.remove("rw");
|
||||
LogBus.init(level, LogBusBaseType.MYBATIS, logTrack).title("SQL/" + rw).data(log).error(t).save();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package xtools.boot.db.mybatis.mapper;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : MonitorDatabasesMapper</p>
|
||||
* <p>Description : MonitorDatabasesMapper</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/14 11:49
|
||||
*/
|
||||
@Mapper
|
||||
public interface MonitorDatabasesMapper {
|
||||
|
||||
/**
|
||||
* 监控MySQL
|
||||
*
|
||||
* @param sql SQL语句
|
||||
* @return 监控数据
|
||||
*/
|
||||
@Select({
|
||||
"<script>",
|
||||
"${sql}",
|
||||
"</script>"
|
||||
})
|
||||
List<JSONObject> mysql(@Param("sql") String sql);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package xtools.boot.db.mybatis.monitor;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.boot.api.exection.BizError;
|
||||
import xtools.boot.db.mybatis.enums.MySqlMonitorEnums;
|
||||
import xtools.boot.db.mybatis.mapper.MonitorDatabasesMapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : MySqlMonitor</p>
|
||||
* <p>Description : MySqlMonitor</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/14 16:18
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class MySqlMonitor {
|
||||
|
||||
private final MonitorDatabasesMapper monitorDatabasesMapper;
|
||||
|
||||
/**
|
||||
* 获取MySQL监控信息
|
||||
*
|
||||
* @param type 枚举
|
||||
* @return MySQL监控信息
|
||||
*/
|
||||
public List<JSONObject> info(MySqlMonitorEnums type) {
|
||||
if (Objects.isNull(type)) {
|
||||
throw new BizError("类型参数不能为空");
|
||||
}
|
||||
return monitorDatabasesMapper.mysql(type.getSql());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package xtools.boot.db.mybatis.selector;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* <p>Title : BootDbMybatisImportSelector</p>
|
||||
* <p>Description : BootDbMybatisImportSelector</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/01/01 09:30
|
||||
*/
|
||||
public class BootDbMybatisImportSelector implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
/**
|
||||
* 根据给定的注释元数据,根据需要注册bean
|
||||
*
|
||||
* @param importingClassMetadata AnnotationMetadata
|
||||
* @param registry BeanDefinitionRegistry
|
||||
*/
|
||||
@Override
|
||||
public void registerBeanDefinitions(@NonNull AnnotationMetadata importingClassMetadata, @NonNull BeanDefinitionRegistry registry) {
|
||||
// 构建扫描对象
|
||||
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, true);
|
||||
// 扫描包下路径
|
||||
scanner.scan("xtools.boot.db.mybatis");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
xtools.boot.db.mybatis.BootDbMybatisConfiguration
|
||||
Reference in New Issue
Block a user