初始化仓库
This commit is contained in:
43
.gitignore
vendored
43
.gitignore
vendored
@@ -1,20 +1,29 @@
|
||||
# ---> Actionscript
|
||||
# Build and Release Folders
|
||||
bin-debug/
|
||||
bin-release/
|
||||
[Oo]bj/
|
||||
[Bb]in/
|
||||
# ---> Project
|
||||
|
||||
# Other files and folders
|
||||
# logs
|
||||
**/logs/
|
||||
|
||||
# ai
|
||||
.claude
|
||||
|
||||
# ---> Maven
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
# ---> Eclipse
|
||||
.settings/
|
||||
.project
|
||||
.classpath
|
||||
|
||||
# Executables
|
||||
*.swf
|
||||
*.air
|
||||
*.ipa
|
||||
*.apk
|
||||
|
||||
# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties`
|
||||
# should NOT be excluded as they contain compiler settings and other important
|
||||
# information for Eclipse / Flash Builder.
|
||||
|
||||
# ---> Idea
|
||||
.idea/
|
||||
*.iml
|
||||
44
pom.xml
Normal file
44
pom.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>xtools-boot</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>xtools-boot</name>
|
||||
<description>低调大师工具箱,SpringBoot工具模块,适配JDK25</description>
|
||||
|
||||
<!-- 父pom -->
|
||||
<parent>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-parent-boot</artifactId>
|
||||
<version>5.0.0</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<!-- 子模块 -->
|
||||
<modules>
|
||||
<module>xtools-boot-api</module>
|
||||
<module>xtools-boot-core</module>
|
||||
|
||||
<module>xtools-boot-cache</module>
|
||||
<module>xtools-boot-db</module>
|
||||
<module>xtools-boot-elasticsearch</module>
|
||||
<module>xtools-boot-ip</module>
|
||||
<module>xtools-boot-job</module>
|
||||
<module>xtools-boot-knife4j</module>
|
||||
<module>xtools-boot-log</module>
|
||||
<module>xtools-boot-mask</module>
|
||||
<module>xtools-boot-mq</module>
|
||||
<module>xtools-boot-storage</module>
|
||||
<module>xtools-boot-task</module>
|
||||
<module>xtools-boot-thread</module>
|
||||
<module>xtools-boot-web</module>
|
||||
</modules>
|
||||
|
||||
<!-- 属性配置 -->
|
||||
<properties>
|
||||
<!-- JDK 版本 -->
|
||||
<java.version>25</java.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
27
xtools-boot-api/pom.xml
Normal file
27
xtools-boot-api/pom.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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>
|
||||
<artifactId>xtools-boot-api</artifactId>
|
||||
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<!-- jakarta.validation -->
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
</dependency>
|
||||
<!-- swagger annotations -->
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,22 @@
|
||||
package xtools.boot.api.anntation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Title : IgnoreXss</p>
|
||||
* <p>Description : IgnoreXss</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/9 10:07
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface IgnoreXss {
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package xtools.boot.api.constant;
|
||||
|
||||
/**
|
||||
* <p>Title : BootCommonConstant</p>
|
||||
* <p>Description : BootCommonConstant</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/27 15:53
|
||||
*/
|
||||
public interface BootCommonConstant {
|
||||
|
||||
/**
|
||||
* 认证
|
||||
*/
|
||||
String AUTHORIZATION = "Authorization";
|
||||
|
||||
/**
|
||||
* 日志追踪
|
||||
*/
|
||||
String LOG_TRACK = "x-log-track";
|
||||
|
||||
/**
|
||||
* 微服务
|
||||
*/
|
||||
String CLOUD = "x-cloud";
|
||||
|
||||
/**
|
||||
* 微服务Token
|
||||
*/
|
||||
String CLOUD_TOKEN = "x-cloud-token";
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
String UID = "x-uid";
|
||||
|
||||
/**
|
||||
* 认证信息
|
||||
*/
|
||||
String AUTH = "x-auth";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package xtools.boot.api.enums;
|
||||
|
||||
/**
|
||||
* <p>Title : BaseEnum</p>
|
||||
* <p>Description : BaseEnum</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 interface BaseEnum {
|
||||
|
||||
/**
|
||||
* 获取所有枚举
|
||||
*
|
||||
* @return 所有枚举
|
||||
*/
|
||||
default BaseEnum[] all() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举编码
|
||||
*
|
||||
* @return 枚举编码
|
||||
*/
|
||||
int code();
|
||||
|
||||
/**
|
||||
* 获取枚举说明
|
||||
*
|
||||
* @return 枚举说明
|
||||
*/
|
||||
String desc();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package xtools.boot.api.enums;
|
||||
|
||||
import xtools.base.exception.BaseError;
|
||||
import xtools.base.exception.BaseErrorModule;
|
||||
|
||||
/**
|
||||
* <p>Title : BootError</p>
|
||||
* <p>Description : BootError</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/12/23 16:53
|
||||
*/
|
||||
public enum BootError implements BaseError {
|
||||
|
||||
/* api begin */
|
||||
// 认证异常
|
||||
UNAUTHORIZED_ERROR(401, "UNAUTHORIZED_ERROR", BootErrorModule.BOOT_API, "{}"),
|
||||
// 公钥错误
|
||||
BIZ_PUBLIC_KEY_ERROR(9990, "BIZ_PUBLIC_KEY_ERROR", BootErrorModule.BOOT_API, "{}"),
|
||||
// 业务警告
|
||||
BIZ_WARNING(9998, "BIZ_WARNING", BootErrorModule.BOOT_API, "{}"),
|
||||
// 业务异常
|
||||
BIZ_ERROR(9999, "BIZ_ERROR", BootErrorModule.BOOT_API, "{}"),
|
||||
// 结果码异常
|
||||
RESULT_CODE(10000, "RESULT_CODE", BootErrorModule.BOOT_API, "结果码异常,业务错误码必须大于1000,code:{}"),
|
||||
/* api end */
|
||||
|
||||
/* core begin */
|
||||
// Spring 核心工具异常
|
||||
SPRING_BASE(10001, "SPRING_BASE", BootErrorModule.BOOT_CORE, "Spring基本工具异常,操作类型:[{}]"),
|
||||
// 时间转换异常
|
||||
TIME_CONVERT(10002, "TIME", BootErrorModule.BOOT_CORE, "时间转换异常,时间:{}"),
|
||||
/* core end */
|
||||
|
||||
/* log begin */
|
||||
// 日志Holder异常
|
||||
LOG_HOLDER(10100, "LOG", BootErrorModule.BOOT_LOG, "日志 Holder 异常"),
|
||||
/* log end */
|
||||
|
||||
/* mq begin */
|
||||
MQ(10200, "MQ", BootErrorModule.BOOT_MQ, "MQ异常,错误:{}"),
|
||||
/* mq end */;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
**/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 错误类型
|
||||
**/
|
||||
private final String type;
|
||||
|
||||
/**
|
||||
* 错误模块
|
||||
**/
|
||||
private final BaseErrorModule module;
|
||||
|
||||
/**
|
||||
* 错误消息模板
|
||||
**/
|
||||
private final String msgTmp;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*
|
||||
* @param code 错误码
|
||||
* @param type 错误类型
|
||||
* @param msgTmp 错误消息模板
|
||||
*/
|
||||
BootError(int code, String type, BaseErrorModule module, String msgTmp) {
|
||||
this.code = code;
|
||||
this.type = type;
|
||||
this.module = module;
|
||||
this.msgTmp = msgTmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*
|
||||
* @return 错误码
|
||||
*/
|
||||
@Override
|
||||
public int code() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误类型
|
||||
*
|
||||
* @return 错误类型
|
||||
*/
|
||||
@Override
|
||||
public String type() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误模块
|
||||
*
|
||||
* @return 错误模块
|
||||
*/
|
||||
@Override
|
||||
public BaseErrorModule module() {
|
||||
return this.module;
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误消息模板
|
||||
*
|
||||
* @return 错误消息模板
|
||||
*/
|
||||
@Override
|
||||
public String msgTmp() {
|
||||
return this.msgTmp;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package xtools.boot.api.enums;
|
||||
|
||||
import xtools.base.exception.BaseErrorModule;
|
||||
|
||||
/**
|
||||
* <p>Title : BootErrorModule</p>
|
||||
* <p>Description : BootErrorModule</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/12/23 16:53
|
||||
*/
|
||||
public enum BootErrorModule implements BaseErrorModule {
|
||||
// API模块
|
||||
BOOT_API("xtools-boot-api"),
|
||||
// 核心模块
|
||||
BOOT_CORE("xtools-boot-core"),
|
||||
// 日志模块
|
||||
BOOT_LOG("xtools-boot-log"),
|
||||
// MQ模块
|
||||
BOOT_MQ("xtools-boot-mq"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 错误模块
|
||||
**/
|
||||
private final String module;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*
|
||||
* @param module 错误模块
|
||||
*/
|
||||
BootErrorModule(String module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误模块
|
||||
*
|
||||
* @return 错误模块
|
||||
*/
|
||||
@Override
|
||||
public String module() {
|
||||
return this.module;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package xtools.boot.api.enums;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : DeleteEnum</p>
|
||||
* <p>Description : DeleteEnum</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/20 11:08
|
||||
*/
|
||||
public enum DeleteEnum implements BaseEnum {
|
||||
|
||||
// 正常
|
||||
NORMAL(0, "正常"),
|
||||
// 删除
|
||||
DELETE(1, "删除"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param code 编码
|
||||
* @param desc 说明
|
||||
*/
|
||||
DeleteEnum(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断枚举值类型
|
||||
*
|
||||
* @param code 枚举值
|
||||
* @return 枚举值类型
|
||||
*/
|
||||
public static DeleteEnum valueOf(int code) {
|
||||
for (DeleteEnum type : values()) {
|
||||
if (type.code == code) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("unknown code, code=" + code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举值类型
|
||||
*
|
||||
* @param desc 枚举说明
|
||||
* @return 枚举值类型
|
||||
*/
|
||||
public static DeleteEnum valueOfDesc(String desc) {
|
||||
for (DeleteEnum type : values()) {
|
||||
if (Objects.equals(type.desc, desc)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("unknown desc, desc=" + desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有枚举
|
||||
*
|
||||
* @return 所有枚举
|
||||
*/
|
||||
@Override
|
||||
public BaseEnum[] all() {
|
||||
return values();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举编码
|
||||
*
|
||||
* @return 枚举编码
|
||||
*/
|
||||
@Override
|
||||
public int code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举说明
|
||||
*
|
||||
* @return 枚举说明
|
||||
*/
|
||||
@Override
|
||||
public String desc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package xtools.boot.api.enums;
|
||||
|
||||
/**
|
||||
* <p>Title : FileDataType</p>
|
||||
* <p>Description : FileDataType</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/6 16:44
|
||||
*/
|
||||
public enum FileDataType implements BaseEnum {
|
||||
|
||||
// 正常
|
||||
OK(0, "正常"),
|
||||
// 临时
|
||||
TEMP(1, "临时"),
|
||||
// 待删除
|
||||
DELETE(2, "待删除");
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param code 编码
|
||||
* @param desc 说明
|
||||
*/
|
||||
FileDataType(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有枚举
|
||||
*
|
||||
* @return 所有枚举
|
||||
*/
|
||||
@Override
|
||||
public BaseEnum[] all() {
|
||||
return values();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举编码
|
||||
*
|
||||
* @return 枚举编码
|
||||
*/
|
||||
@Override
|
||||
public int code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举说明
|
||||
*
|
||||
* @return 枚举说明
|
||||
*/
|
||||
@Override
|
||||
public String desc() {
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package xtools.boot.api.enums;
|
||||
|
||||
/**
|
||||
* <p>Title : ResultType</p>
|
||||
* <p>Description : ResultType</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 14:10
|
||||
*/
|
||||
public enum ResultType {
|
||||
|
||||
|
||||
// 请求成功
|
||||
OK(true, 200, "ok", "请求成功"),
|
||||
// 服务器内部错误
|
||||
INTERNAL_SERVER_ERROR(false, 500, "internal_server_error", "服务器内部错误"),
|
||||
|
||||
// 请求参数缺失 | 参数格式错误(如:期望数字却传了字符串) | 参数类型不匹配 | JSON/XML格式错误 | 必填参数为空
|
||||
BAD_REQUEST(false, 400, "bad_request", "请求参数缺失 | 参数格式错误(如:期望数字却传了字符串) | 参数类型不匹配 | JSON/XML格式错误 | 必填参数为空"),
|
||||
// 认证失败
|
||||
UNAUTHORIZED(false, 401, "unauthorized", "认证失败"),
|
||||
// 权限不足
|
||||
FORBIDDEN(false, 403, "forbidden", "权限不足"),
|
||||
// 资源不存在
|
||||
NOT_FOUND(false, 404, "not_found", "资源不存在"),
|
||||
// 请求方法不被允许
|
||||
METHOD_NOT_ALLOWED(false, 405, "method_not_allowed", "请求方法不被允许"),
|
||||
// 请求过于频繁
|
||||
TOO_MANY_REQUESTS(false, 429, "too_many_requests", "请求过于频繁"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private final boolean success;
|
||||
|
||||
/**
|
||||
* 响应码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 响应信息
|
||||
*/
|
||||
private final String msg;
|
||||
|
||||
/**
|
||||
* 响应描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
ResultType(boolean success, int code, String msg, String desc) {
|
||||
this.success = success;
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public boolean success() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public int code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String msg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public String desc() {
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package xtools.boot.api.enums;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : StatusEnum</p>
|
||||
* <p>Description : StatusEnum</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/20 11:08
|
||||
*/
|
||||
public enum StatusEnum implements BaseEnum {
|
||||
|
||||
// 正常
|
||||
NORMAL(1, "正常"),
|
||||
// 停用
|
||||
DISABLED(0, "停用"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param code 编码
|
||||
* @param desc 说明
|
||||
*/
|
||||
StatusEnum(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断枚举值类型
|
||||
*
|
||||
* @param code 枚举值
|
||||
* @return 枚举值类型
|
||||
*/
|
||||
public static StatusEnum valueOf(int code) {
|
||||
for (StatusEnum type : values()) {
|
||||
if (type.code == code) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("unknown code, code=" + code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举值类型
|
||||
*
|
||||
* @param desc 枚举说明
|
||||
* @return 枚举值类型
|
||||
*/
|
||||
public static StatusEnum valueOfDesc(String desc) {
|
||||
for (StatusEnum type : values()) {
|
||||
if (Objects.equals(type.desc, desc)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("unknown desc, desc=" + desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有枚举
|
||||
*
|
||||
* @return 所有枚举
|
||||
*/
|
||||
@Override
|
||||
public BaseEnum[] all() {
|
||||
return values();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举编码
|
||||
*
|
||||
* @return 枚举编码
|
||||
*/
|
||||
@Override
|
||||
public int code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举说明
|
||||
*
|
||||
* @return 枚举说明
|
||||
*/
|
||||
@Override
|
||||
public String desc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package xtools.boot.api.enums;
|
||||
|
||||
/**
|
||||
* <p>Title : ThreadType</p>
|
||||
* <p>Description : ThreadType</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/6 16:44
|
||||
*/
|
||||
public enum ThreadType implements BaseEnum {
|
||||
|
||||
// 主线程
|
||||
MAIN(0, "主线程"),
|
||||
// 子线程
|
||||
THREAD(1, "子线程");
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param code 编码
|
||||
* @param desc 说明
|
||||
*/
|
||||
ThreadType(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有枚举
|
||||
*
|
||||
* @return 所有枚举
|
||||
*/
|
||||
@Override
|
||||
public BaseEnum[] all() {
|
||||
return values();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举编码
|
||||
*
|
||||
* @return 枚举编码
|
||||
*/
|
||||
@Override
|
||||
public int code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举说明
|
||||
*
|
||||
* @return 枚举说明
|
||||
*/
|
||||
@Override
|
||||
public String desc() {
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package xtools.boot.api.exection;
|
||||
|
||||
import xtools.base.exception.CommonException;
|
||||
import xtools.boot.api.enums.BootError;
|
||||
|
||||
/**
|
||||
* <p>Title : BizError</p>
|
||||
* <p>Description : BizError</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/29 11:08
|
||||
*/
|
||||
public class BizError extends CommonException {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*
|
||||
* @param message 错误消息
|
||||
*/
|
||||
public BizError(String message) {
|
||||
super(BootError.BIZ_ERROR, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package xtools.boot.api.exection;
|
||||
|
||||
import xtools.base.exception.CommonException;
|
||||
import xtools.boot.api.enums.BootError;
|
||||
|
||||
/**
|
||||
* <p>Title : BizPublicKeyError</p>
|
||||
* <p>Description : BizPublicKeyError</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/29 11:08
|
||||
*/
|
||||
public class BizPublicKeyError extends CommonException {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*
|
||||
* @param message 错误消息
|
||||
*/
|
||||
public BizPublicKeyError(String message) {
|
||||
super(BootError.BIZ_PUBLIC_KEY_ERROR, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package xtools.boot.api.exection;
|
||||
|
||||
import xtools.base.exception.CommonException;
|
||||
import xtools.boot.api.enums.BootError;
|
||||
|
||||
/**
|
||||
* <p>Title : BizWarning</p>
|
||||
* <p>Description : BizWarning</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/29 11:08
|
||||
*/
|
||||
public class BizWarning extends CommonException {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*
|
||||
* @param message 错误消息
|
||||
*/
|
||||
public BizWarning(String message) {
|
||||
super(BootError.BIZ_WARNING, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package xtools.boot.api.exection;
|
||||
|
||||
import xtools.base.exception.CommonException;
|
||||
import xtools.boot.api.enums.BootError;
|
||||
|
||||
/**
|
||||
* <p>Title : UnauthorizedError</p>
|
||||
* <p>Description : UnauthorizedError</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/29 11:08
|
||||
*/
|
||||
public class UnauthorizedError extends CommonException {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public UnauthorizedError() {
|
||||
super(BootError.UNAUTHORIZED_ERROR, "认证异常");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package xtools.boot.api.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>Title : EnumInfoDto</p>
|
||||
* <p>Description : EnumInfoDto</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:30
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class EnumInfoDto implements Serializable {
|
||||
|
||||
/**
|
||||
* 枚举值
|
||||
*/
|
||||
private int code;
|
||||
|
||||
/**
|
||||
* 枚举说明
|
||||
*/
|
||||
private String desc;
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package xtools.boot.api.model.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.base.exception.CommonException;
|
||||
import xtools.boot.api.enums.BootError;
|
||||
import xtools.boot.api.enums.ResultType;
|
||||
import xtools.boot.api.exection.BizError;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : Result</p>
|
||||
* <p>Description : Result</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/12/22 14:07
|
||||
*/
|
||||
@Data
|
||||
public final class Result<T> implements BaseParams {
|
||||
|
||||
@Schema(description = "是否成功")
|
||||
private boolean success;
|
||||
|
||||
@Schema(description = "响应代码")
|
||||
private int code;
|
||||
|
||||
@Schema(description = "提示信息")
|
||||
private Object msg;
|
||||
|
||||
@Schema(description = "响应数据")
|
||||
private T data;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
public Result() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param success 是否成功
|
||||
* @param code 响应代码
|
||||
* @param msg 提示信息
|
||||
* @param data 响应数据
|
||||
*/
|
||||
public Result(boolean success, int code, Object msg, T data) {
|
||||
this.success = success;
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param type 响应类型
|
||||
* @param data 数据
|
||||
*/
|
||||
public Result(ResultType type, T data) {
|
||||
this.success = type.success();
|
||||
this.code = type.code();
|
||||
this.msg = type.msg() + CP_COMMA + type.desc();
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求成功
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public static Result<Object> ok() {
|
||||
return new Result<>(ResultType.OK, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求成功
|
||||
*
|
||||
* @param data 数据
|
||||
* @param <T> 泛型
|
||||
* @return 结果
|
||||
*/
|
||||
public static <T> Result<T> ok(T data) {
|
||||
return new Result<>(ResultType.OK, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求成功,业务失败
|
||||
*
|
||||
* @param code 业务错误码
|
||||
* @param msg 业务错误信息
|
||||
* @return 响应结果
|
||||
*/
|
||||
public static Result<Object> fail(int code, Object msg) {
|
||||
if (code < CP_NUM1000) {
|
||||
throw CommonException.create(BootError.RESULT_CODE, code);
|
||||
}
|
||||
return new Result<>(true, code, msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求参数缺失 | 参数格式错误(如:期望数字却传了字符串) | 参数类型不匹配 | JSON/XML格式错误 | 必填参数为空
|
||||
*
|
||||
* @return 响应结果
|
||||
*/
|
||||
public static <T> Result<T> badRequest() {
|
||||
return new Result<>(ResultType.BAD_REQUEST, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求参数缺失 | 参数格式错误(如:期望数字却传了字符串) | 参数类型不匹配 | JSON/XML格式错误 | 必填参数为空
|
||||
*
|
||||
* @param msg 错误信息
|
||||
* @return 响应结果
|
||||
*/
|
||||
public static <T> Result<T> badRequest(Object msg) {
|
||||
ResultType type = ResultType.BAD_REQUEST;
|
||||
return new Result<>(type.success(), type.code(), msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据
|
||||
*
|
||||
* @return 数据
|
||||
*/
|
||||
public T data() {
|
||||
if (Objects.equals(success, false) || !Objects.equals(code, CP_NUM200)) {
|
||||
throw new BizError(Objects.isNull(msg) ? "业务处理失败" : String.valueOf(msg));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package xtools.boot.api.model.dto.log;
|
||||
|
||||
import lombok.Data;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.boot.api.enums.ThreadType;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* <p>Title : HolderLogTrack</p>
|
||||
* <p>Description : HolderLogTrack</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/6 16:44
|
||||
*/
|
||||
@Data
|
||||
public class HolderLogTrack implements BaseParams {
|
||||
|
||||
/**
|
||||
* 日志追踪 ID
|
||||
*/
|
||||
private final String traceId;
|
||||
/**
|
||||
* 父线日志 ID
|
||||
*/
|
||||
private final String parentId;
|
||||
/**
|
||||
* 线程类型
|
||||
*/
|
||||
private final ThreadType type;
|
||||
/**
|
||||
* 日志获取次数
|
||||
*/
|
||||
private final AtomicInteger count;
|
||||
/**
|
||||
* 是否保存日志
|
||||
*/
|
||||
private boolean save;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*
|
||||
* @param traceId 日志追踪 ID
|
||||
* @param parentId 父日志 ID
|
||||
* @param type 线程类型
|
||||
*/
|
||||
public HolderLogTrack(String traceId, String parentId, ThreadType type) {
|
||||
this.save = true;
|
||||
this.traceId = traceId;
|
||||
this.parentId = parentId;
|
||||
this.type = type;
|
||||
this.count = new AtomicInteger(CP_NUM0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*
|
||||
* @param traceId 日志追踪 ID
|
||||
* @param parentId 父日志 ID
|
||||
* @param type 线程类型
|
||||
* @param count 日志获取次数
|
||||
*/
|
||||
public HolderLogTrack(String traceId, String parentId, ThreadType type, int count) {
|
||||
this.save = true;
|
||||
this.traceId = traceId;
|
||||
this.parentId = parentId;
|
||||
this.type = type;
|
||||
this.count = new AtomicInteger(count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package xtools.boot.api.model.dto.log;
|
||||
|
||||
import xtools.boot.api.enums.ThreadType;
|
||||
|
||||
/**
|
||||
* <p>Title : LogTrack</p>
|
||||
* <p>Description : LogTrack</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @param id 日志 ID
|
||||
* @param time 日志时间
|
||||
* @param traceId 日志追踪 ID
|
||||
* @param parentId 父线日志 ID
|
||||
* @param type 线程类型
|
||||
* @param index 日志获取次数
|
||||
* @param save 是否保存日志
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/1/6 16:44
|
||||
*/
|
||||
public record LogTrack(String id, Long time, String traceId, String parentId, ThreadType type, Integer index,
|
||||
boolean save) {
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package xtools.boot.api.model.dto.page;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>Title : PageReq</p>
|
||||
* <p>Description : PageReq</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/12/22 14:58
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PageReq<T> implements Serializable {
|
||||
|
||||
/**
|
||||
* 当前页面
|
||||
*/
|
||||
@Schema(description = "当前页面", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer currentPage;
|
||||
|
||||
/**
|
||||
* 页面数据条数
|
||||
*/
|
||||
@Schema(description = "页面数据条数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer pageSize;
|
||||
|
||||
/**
|
||||
* 查询条件
|
||||
*/
|
||||
@Schema(description = "查询条件")
|
||||
private T query;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package xtools.boot.api.model.dto.page;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import xtools.core.extend.PagingUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : PageResp</p>
|
||||
* <p>Description : PageResp</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/12/22 14:58
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public final class PageResp<T> implements Serializable {
|
||||
|
||||
/**
|
||||
* 当前页面
|
||||
*/
|
||||
@Schema(description = "当前页面")
|
||||
private Integer currentPage;
|
||||
|
||||
/**
|
||||
* 页面数据条数
|
||||
*/
|
||||
@Schema(description = "页面数据条数")
|
||||
private Integer pageSize;
|
||||
|
||||
/**
|
||||
* 数据条数
|
||||
*/
|
||||
@Schema(description = "数据条数")
|
||||
private Long total;
|
||||
|
||||
/**
|
||||
* 总页数
|
||||
*/
|
||||
@Schema(description = "总页数")
|
||||
private Long pageCount;
|
||||
|
||||
/**
|
||||
* 结果数据集
|
||||
*/
|
||||
@Schema(description = "结果数据集")
|
||||
private List<T> data;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*
|
||||
* @param req 分页请求
|
||||
*/
|
||||
public PageResp(PageReq<?> req) {
|
||||
this.currentPage = req.getCurrentPage();
|
||||
this.pageSize = req.getPageSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*
|
||||
* @param req 分页请求
|
||||
*/
|
||||
public PageResp(PageReq<?> req, Long total, List<T> data) {
|
||||
this.currentPage = req.getCurrentPage();
|
||||
this.pageSize = req.getPageSize();
|
||||
this.total = total;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取总页数
|
||||
*
|
||||
* @return 总页数
|
||||
*/
|
||||
public Long getPageCount() {
|
||||
return PagingUtils.getLastPage(this.total, this.pageSize);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package xtools.boot.api.model.dto.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : IdListReq</p>
|
||||
* <p>Description : IdListReq</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/4 11:03
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IdListReq implements Serializable {
|
||||
|
||||
/**
|
||||
* idList
|
||||
*/
|
||||
@NotNull(message = "不能为空")
|
||||
@Schema(description = "Id列表")
|
||||
private List<Long> idList;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package xtools.boot.api.model.dto.resp;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : TreeResp</p>
|
||||
* <p>Description : TreeResp</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/30 09:39
|
||||
*/
|
||||
@Data
|
||||
public class TreeResp implements Serializable {
|
||||
|
||||
/**
|
||||
* 父id
|
||||
*/
|
||||
@Schema(description = "父id", example = "1")
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
@Schema(description = "值", example = "1")
|
||||
private Long value;
|
||||
|
||||
/**
|
||||
* 标签
|
||||
*/
|
||||
@Schema(description = "标签", example = "1")
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* 子项
|
||||
*/
|
||||
@Schema(description = "子项")
|
||||
private List<TreeResp> children;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package xtools.boot.api.model.entity;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* <p>Title : BaseEntity</p>
|
||||
* <p>Description : BaseEntity</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 18:50
|
||||
*/
|
||||
@Data
|
||||
public class BaseEntity implements Serializable {
|
||||
|
||||
@Schema(description = "创建时间", example = "2026-01-05 10:32:00")
|
||||
private Instant gmtCreate;
|
||||
|
||||
@Schema(description = "更新时间", example = "2026-01-05 10:32:00")
|
||||
private Instant gmtModified;
|
||||
}
|
||||
19
xtools-boot-cache/pom.xml
Normal file
19
xtools-boot-cache/pom.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?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-cache</artifactId>
|
||||
|
||||
<!-- 子模块 -->
|
||||
<modules>
|
||||
<module>xtools-boot-cache-redis</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
38
xtools-boot-cache/xtools-boot-cache-redis/pom.xml
Normal file
38
xtools-boot-cache/xtools-boot-cache-redis/pom.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?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-cache</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</parent>
|
||||
<artifactId>xtools-boot-cache-redis</artifactId>
|
||||
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<!-- xtools-boot begin -->
|
||||
<!-- xtools-boot-core -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-core</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-boot end -->
|
||||
|
||||
<!-- SpringBoot begin -->
|
||||
<!-- SpringBoot-Redis -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<!-- SpringBoot end -->
|
||||
|
||||
<!-- Fastjson2 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package xtools.boot.cache.redis;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import xtools.boot.cache.redis.selector.BootCacheRedisImportSelector;
|
||||
import xtools.boot.core.utils.ModuleLoadUtils;
|
||||
|
||||
/**
|
||||
* <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(BootCacheRedisImportSelector.class)
|
||||
public class BootCacheRedisConfiguration {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public BootCacheRedisConfiguration() {
|
||||
ModuleLoadUtils.loadSuccess(BootCacheRedisConfiguration.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,458 @@
|
||||
package xtools.boot.cache.redis.base;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.core.ArrUtils;
|
||||
import xtools.core.CollectionUtils;
|
||||
import xtools.core.StringUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* <p>Title : RedisService</p>
|
||||
* <p>Description : RedisService</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
|
||||
*/
|
||||
@Component
|
||||
public class RedisService implements BaseParams {
|
||||
|
||||
/**
|
||||
* RedisTemplate
|
||||
**/
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
/**
|
||||
* StringRedisTemplate
|
||||
**/
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
/**
|
||||
* 获取组合 Key
|
||||
*
|
||||
* @param keys 多个 Key
|
||||
* @return 组合 Key
|
||||
*/
|
||||
public String getKey(String... keys) {
|
||||
if (ArrUtils.isEmpty(keys)) {
|
||||
return null;
|
||||
}
|
||||
StringJoiner sj = new StringJoiner(CP_COLON);
|
||||
for (String key : keys) {
|
||||
sj.add(key);
|
||||
}
|
||||
return sj.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 整数 值递增一
|
||||
*
|
||||
* @param key Key
|
||||
* @return 递增后的值
|
||||
*/
|
||||
public Long incr(String key) {
|
||||
return stringRedisTemplate.opsForValue().increment(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据
|
||||
*
|
||||
* @param key Key
|
||||
* @param data 数据
|
||||
*/
|
||||
public void set(String key, Object data) {
|
||||
this.set(key, data, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据
|
||||
*
|
||||
* @param key Key
|
||||
* @param data 数据
|
||||
* @param timeout 过期时间
|
||||
*/
|
||||
public void set(String key, Object data, Long timeout) {
|
||||
this.set(key, data, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据
|
||||
*
|
||||
* @param key Key
|
||||
* @param data 数据
|
||||
* @param timeout 过期时间
|
||||
* @param unit 时间单位
|
||||
*/
|
||||
public void set(String key, Object data, Long timeout, TimeUnit unit) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(key) || data == null) {
|
||||
return;
|
||||
}
|
||||
// 序列化数据
|
||||
String serializeData;
|
||||
if (data instanceof String) {
|
||||
serializeData = data.toString();
|
||||
} else {
|
||||
serializeData = JSON.toJSONString(data);
|
||||
}
|
||||
if (StringUtils.isEmpty(serializeData)) {
|
||||
return;
|
||||
}
|
||||
if (unit == null) {
|
||||
unit = TimeUnit.SECONDS;
|
||||
}
|
||||
// 判断是否有过期时间
|
||||
if (timeout == null || timeout <= 0) {
|
||||
stringRedisTemplate.opsForValue().set(key, serializeData);
|
||||
} else {
|
||||
stringRedisTemplate.opsForValue().set(key, serializeData, timeout, unit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据(如果key存在则保存失败)
|
||||
*
|
||||
* @param key Key
|
||||
* @param data 数据
|
||||
* @return 保存结果
|
||||
*/
|
||||
public Boolean setNx(String key, Object data) {
|
||||
return this.setNx(key, data, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据(如果key存在则保存失败)
|
||||
*
|
||||
* @param key Key
|
||||
* @param data 数据
|
||||
* @param timeout 有效时间
|
||||
* @return 保存结果
|
||||
*/
|
||||
public Boolean setNx(String key, Object data, Long timeout) {
|
||||
return this.setNx(key, data, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据(如果key存在则保存失败)
|
||||
*
|
||||
* @param key Key
|
||||
* @param data 数据
|
||||
* @param timeout 有效时间
|
||||
* @param unit 时间单位
|
||||
* @return 保存结果
|
||||
*/
|
||||
public Boolean setNx(String key, Object data, Long timeout, TimeUnit unit) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(key) || data == null) {
|
||||
return false;
|
||||
}
|
||||
// 序列化数据
|
||||
String serializeData;
|
||||
if (data instanceof String) {
|
||||
serializeData = data.toString();
|
||||
} else {
|
||||
serializeData = JSON.toJSONString(data);
|
||||
}
|
||||
if (StringUtils.isEmpty(serializeData)) {
|
||||
return false;
|
||||
}
|
||||
if (unit == null) {
|
||||
unit = TimeUnit.SECONDS;
|
||||
}
|
||||
// 判断是否有过期时间
|
||||
if (timeout == null || timeout <= 0) {
|
||||
return stringRedisTemplate.opsForValue().setIfAbsent(key, serializeData);
|
||||
} else {
|
||||
return stringRedisTemplate.opsForValue().setIfAbsent(key, serializeData, timeout, unit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据
|
||||
*
|
||||
* @param <T> Class 类型
|
||||
* @param key Key
|
||||
* @param clazz Class
|
||||
* @return 数据
|
||||
*/
|
||||
public <T> T get(String key, Class<T> clazz) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
return null;
|
||||
}
|
||||
// 从缓存获取数据
|
||||
String data = stringRedisTemplate.opsForValue().get(key);
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
return null;
|
||||
}
|
||||
return JSON.to(clazz, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 key 对应的数据
|
||||
*
|
||||
* @param key Key
|
||||
* @return 删除结果
|
||||
*/
|
||||
public Boolean del(String key) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
return stringRedisTemplate.delete(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改 Key
|
||||
*
|
||||
* @param oldKey 旧Key
|
||||
* @param newKey 新Key
|
||||
*/
|
||||
public void rename(String oldKey, String newKey) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(oldKey) || StringUtils.isEmpty(newKey)) {
|
||||
return;
|
||||
}
|
||||
stringRedisTemplate.rename(oldKey, newKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置key的过期时间(秒)
|
||||
*
|
||||
* @param key Key
|
||||
* @param timeout 时间(秒)
|
||||
* @return 设置结果
|
||||
*/
|
||||
public Boolean expire(String key, long timeout) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(key) || timeout <= 0) {
|
||||
return false;
|
||||
}
|
||||
return stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消对 Key 过期时间的设置
|
||||
*
|
||||
* @param key Key
|
||||
* @return true or false
|
||||
*/
|
||||
public Boolean persist(String key) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
return stringRedisTemplate.persist(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找所有匹配给定的模式的键
|
||||
*
|
||||
* @param pattern key的表达式,*表示多个,?表示一个
|
||||
* @return 全部符合表达式记录
|
||||
*/
|
||||
public Set<String> getByPattern(String pattern) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(pattern)) {
|
||||
return null;
|
||||
}
|
||||
return stringRedisTemplate.keys(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取锁
|
||||
*
|
||||
* @param key 锁的key
|
||||
* @param value 请求标识(可用UUID)
|
||||
* @param expireTime 过期时间(秒)
|
||||
* @return 是否获取成功
|
||||
*/
|
||||
public boolean tryLock(String key, String value, long expireTime) {
|
||||
Boolean result = redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);
|
||||
return Boolean.TRUE.equals(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放锁(使用Lua脚本保证原子性)
|
||||
*
|
||||
* @param key 锁的key
|
||||
* @param value 请求标识
|
||||
* @return 是否释放成功
|
||||
*/
|
||||
public boolean releaseLock(String key, String value) {
|
||||
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
||||
|
||||
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
|
||||
redisScript.setScriptText(script);
|
||||
redisScript.setResultType(Long.class);
|
||||
|
||||
Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), value);
|
||||
return Long.valueOf(CP_NUM1).equals(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存 Hash 数据
|
||||
*
|
||||
* @param key Key
|
||||
* @param map Hash 数据
|
||||
* @return 保存结果
|
||||
*/
|
||||
public boolean hashPutAll(String key, Map<Object, String> map) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
if (CollectionUtils.isEmpty(map)) {
|
||||
return false;
|
||||
}
|
||||
stringRedisTemplate.opsForHash().putAll(key, map);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存 Hash 数据
|
||||
*
|
||||
* @param key key
|
||||
* @param hashKey hashKey
|
||||
* @param data 数据
|
||||
* @return 保存结果
|
||||
*/
|
||||
public boolean hashPut(String key, Object hashKey, Object data) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(key) || Objects.isNull(hashKey)) {
|
||||
return false;
|
||||
}
|
||||
// 序列化数据
|
||||
String serializeData;
|
||||
if (data instanceof String) {
|
||||
serializeData = data.toString();
|
||||
} else {
|
||||
serializeData = JSON.toJSONString(data);
|
||||
}
|
||||
if (StringUtils.isEmpty(serializeData)) {
|
||||
return false;
|
||||
}
|
||||
stringRedisTemplate.opsForHash().putIfAbsent(key, hashKey, serializeData);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存 Hash 数据
|
||||
*
|
||||
* @param key key
|
||||
* @param hashKey hashKey
|
||||
* @param data 数据
|
||||
* @param expireTime 过期时间(秒)
|
||||
* @return 保存结果
|
||||
*/
|
||||
public boolean hashPut(String key, Object hashKey, Object data, long expireTime) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(key) || Objects.isNull(hashKey)) {
|
||||
return false;
|
||||
}
|
||||
// 序列化数据
|
||||
String serializeData;
|
||||
if (data instanceof String) {
|
||||
serializeData = data.toString();
|
||||
} else {
|
||||
serializeData = JSON.toJSONString(data);
|
||||
}
|
||||
if (StringUtils.isEmpty(serializeData)) {
|
||||
return false;
|
||||
}
|
||||
String script =
|
||||
"redis.call('HSET', KEYS[1], ARGV[1], ARGV[2]) " +
|
||||
"redis.call('HEXPIRE', KEYS[1], ARGV[3], 'FIELDS', 1, ARGV[1]) " +
|
||||
"return 1";
|
||||
Long result = stringRedisTemplate.execute(
|
||||
new DefaultRedisScript<>(script, Long.class),
|
||||
Collections.singletonList(key),
|
||||
hashKey, serializeData, String.valueOf(expireTime)
|
||||
);
|
||||
return Long.valueOf(CP_NUM1).equals(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Hash 中所有数据
|
||||
*
|
||||
* @param <T> 结果类型
|
||||
* @param key key
|
||||
* @param clazz 结果类型
|
||||
* @return 数据集
|
||||
*/
|
||||
public <T> T hashEntries(String key, Class<T> clazz) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
return null;
|
||||
}
|
||||
Map<Object, Object> data = stringRedisTemplate.opsForHash().entries(key);
|
||||
if (CollectionUtils.isEmpty(data)) {
|
||||
return null;
|
||||
}
|
||||
return JSON.to(clazz, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Hash 中指定 Key 的数据
|
||||
*
|
||||
* @param <T> 结果类型
|
||||
* @param key key
|
||||
* @param hashKey hashKey
|
||||
* @param clazz 结果类型
|
||||
* @return 数据
|
||||
*/
|
||||
public <T> T hashGet(String key, Object hashKey, Class<T> clazz) {
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(key) || Objects.isNull(hashKey)) {
|
||||
return null;
|
||||
}
|
||||
Object data = stringRedisTemplate.opsForHash().get(key, hashKey);
|
||||
return JSON.to(clazz, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 Hash 中指定 Key 的数据
|
||||
*
|
||||
* @param key key
|
||||
* @param hashKeys hashKey数组
|
||||
* @return 删除结果
|
||||
*/
|
||||
public Long hashDelete(String key, Object... hashKeys) {
|
||||
if (StringUtils.isBlank(key) || ArrUtils.isEmpty(hashKeys)) {
|
||||
return 0L;
|
||||
}
|
||||
return stringRedisTemplate.opsForHash().delete(key, hashKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 Hash 中是否存在指定 Key 的数据
|
||||
*
|
||||
* @param key key
|
||||
* @param hashKey hashKey
|
||||
* @return 存在结果
|
||||
*/
|
||||
public boolean hashExists(String key, Object hashKey) {
|
||||
if (StringUtils.isBlank(key) || Objects.isNull(hashKey)) {
|
||||
return false;
|
||||
}
|
||||
return stringRedisTemplate.opsForHash().hasKey(key, hashKey);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package xtools.boot.cache.redis.enums;
|
||||
|
||||
/**
|
||||
* <p>Title : BaseCacheEnum</p>
|
||||
* <p>Description : BaseCacheEnum</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/25 14:57
|
||||
*/
|
||||
public interface BaseCacheEnum {
|
||||
|
||||
/**
|
||||
* 获取key
|
||||
*
|
||||
* @return key
|
||||
*/
|
||||
String key();
|
||||
|
||||
/**
|
||||
* 获取超时时间
|
||||
*
|
||||
* @return 超时时间
|
||||
*/
|
||||
Long expireTime();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package xtools.boot.cache.redis.monitor;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.data.redis.connection.RedisCommands;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.core.StringUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* <p>Title : RedisMonitor</p>
|
||||
* <p>Description : RedisMonitor</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
|
||||
*/
|
||||
@Component
|
||||
public class RedisMonitor {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* @return 状态数据
|
||||
*/
|
||||
public JSONObject stats() {
|
||||
RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
|
||||
if (Objects.isNull(factory)) {
|
||||
return null;
|
||||
}
|
||||
// 获取redis命令
|
||||
RedisCommands commands = factory.getConnection().commands();
|
||||
// 获取相对应信息
|
||||
Properties info = commands.info();
|
||||
Object dbSize = commands.dbSize();
|
||||
Properties commandStats = commands.info("commandstats");
|
||||
JSONArray cmd = new JSONArray();
|
||||
if (Objects.nonNull(commandStats)) {
|
||||
commandStats.stringPropertyNames().forEach(key -> {
|
||||
String property = commandStats.getProperty(key);
|
||||
JSONObject data = JSONObject.of(
|
||||
"name", StringUtils.removeStart(key, "cmdstat_"),
|
||||
"value", StringUtils.substringBetween(property, "calls=", ",usec")
|
||||
);
|
||||
cmd.add(data);
|
||||
});
|
||||
}
|
||||
// 封装数据
|
||||
return JSONObject.of("info", info, "dbSize", dbSize, "cmd", cmd);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package xtools.boot.cache.redis.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 : BootCacheRedisImportSelector</p>
|
||||
* <p>Description : BootCacheRedisImportSelector</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 BootCacheRedisImportSelector 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.cache.redis");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package xtools.boot.cache.redis.utils;
|
||||
|
||||
import xtools.boot.cache.redis.base.RedisService;
|
||||
import xtools.boot.core.utils.SpringContextUtils;
|
||||
|
||||
/**
|
||||
* <p>Title : RedisUtils</p>
|
||||
* <p>Description : RedisUtils</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/10 09:02
|
||||
*/
|
||||
public class RedisUtils {
|
||||
|
||||
/**
|
||||
* Redis 服务
|
||||
**/
|
||||
private static RedisService redisService;
|
||||
|
||||
/**
|
||||
* 获取 Redis 服务
|
||||
*
|
||||
* @return Redis 服务
|
||||
*/
|
||||
public static RedisService get() {
|
||||
if (redisService != null) {
|
||||
return redisService;
|
||||
}
|
||||
return SpringContextUtils.getBean(RedisService.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
xtools.boot.cache.redis.BootCacheRedisConfiguration
|
||||
31
xtools-boot-core/pom.xml
Normal file
31
xtools-boot-core/pom.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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>
|
||||
<artifactId>xtools-boot-core</artifactId>
|
||||
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<!-- xtools-boot begin -->
|
||||
<!-- xtools-boot-api -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-api</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-boot end -->
|
||||
|
||||
<!-- spring 依赖 begin -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<!-- spring 依赖 end -->
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package xtools.boot.core;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import xtools.boot.core.selector.BootCoreImportSelector;
|
||||
import xtools.boot.core.utils.ModuleLoadUtils;
|
||||
|
||||
/**
|
||||
* <p>Title : BootCoreConfiguration</p>
|
||||
* <p>Description : BootCoreConfiguration</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(BootCoreImportSelector.class)
|
||||
public class BootCoreConfiguration {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public BootCoreConfiguration() {
|
||||
ModuleLoadUtils.loadSuccess(BootCoreConfiguration.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package xtools.boot.core.holder;
|
||||
|
||||
import xtools.base.config.BaseParams;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : CommonHolder</p>
|
||||
* <p>Description : CommonHolder</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/31 21:20
|
||||
*/
|
||||
public class CommonHolder implements BaseParams {
|
||||
|
||||
/**
|
||||
* Mvc通用信息
|
||||
*/
|
||||
private static final ScopedValue<Map<String, Object>> COMMON_INFO = ScopedValue.newInstance();
|
||||
|
||||
/**
|
||||
* 获取通用信息 Holder
|
||||
*
|
||||
* @return 通用信息
|
||||
*/
|
||||
public static ScopedValue<Map<String, Object>> getScoped() {
|
||||
return COMMON_INFO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建通用信息
|
||||
*
|
||||
* @return 通用信息
|
||||
*/
|
||||
public static Map<String, Object> create() {
|
||||
return new HashMap<>(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通用信息
|
||||
*
|
||||
* @return 通用信息
|
||||
*/
|
||||
public static Map<String, Object> get() {
|
||||
if (!COMMON_INFO.isBound()) {
|
||||
return null;
|
||||
}
|
||||
return COMMON_INFO.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置通用信息
|
||||
*
|
||||
* @param key Key
|
||||
* @param value Value
|
||||
*/
|
||||
public static void set(String key, Object value) {
|
||||
Map<String, Object> map = get();
|
||||
if (Objects.nonNull(map)) {
|
||||
map.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通用信息
|
||||
*
|
||||
* @param key Key
|
||||
* @return Value
|
||||
*/
|
||||
public static Object get(String key) {
|
||||
Map<String, Object> map = get();
|
||||
if (Objects.nonNull(map)) {
|
||||
return map.get(key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通用信息
|
||||
*
|
||||
* @param key Key
|
||||
* @return Value
|
||||
*/
|
||||
public static boolean getBoolean(String key) {
|
||||
Map<String, Object> map = get();
|
||||
if (Objects.nonNull(map) && map.get(key) instanceof Boolean value) {
|
||||
return value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package xtools.boot.core.interfaces;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>Title : FilterWhitelist</p>
|
||||
* <p>Description : FilterWhitelist</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:23
|
||||
*/
|
||||
public interface FilterWhitelist {
|
||||
|
||||
/**
|
||||
* 添加过滤器白名单
|
||||
*
|
||||
* @return 过滤器白名单
|
||||
*/
|
||||
Set<String> add();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package xtools.boot.core.interfaces;
|
||||
|
||||
/**
|
||||
* <p>Title : JobInterface</p>
|
||||
* <p>Description : JobInterface</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/12 20:52
|
||||
*/
|
||||
public interface JobInterface {
|
||||
|
||||
/**
|
||||
* 执行任务
|
||||
*
|
||||
* @throws Exception 任务执行异常
|
||||
*/
|
||||
void execute() throws Exception;
|
||||
|
||||
/**
|
||||
* 初始化任务
|
||||
*/
|
||||
default void init() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁任务
|
||||
*/
|
||||
default void destroy() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package xtools.boot.core.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 : BootCoreImportSelector</p>
|
||||
* <p>Description : BootCoreImportSelector</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 BootCoreImportSelector 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.core");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package xtools.boot.core.utils;
|
||||
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.core.StringUtils;
|
||||
import xtools.core.encrypt.Md5Utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : AddrUtils</p>
|
||||
* <p>Description : AddrUtils</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/13 15:09
|
||||
*/
|
||||
public class AddrUtils implements BaseParams {
|
||||
|
||||
/**
|
||||
* 本地IP列表
|
||||
*/
|
||||
private static final List<String> LOCAL_IP_LIST;
|
||||
|
||||
// 初始化
|
||||
static {
|
||||
LOCAL_IP_LIST = List.of(
|
||||
"127.0.0.1",
|
||||
"localhost"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为本地IP
|
||||
*
|
||||
* @param ip IP
|
||||
* @return true or false
|
||||
*/
|
||||
public static boolean isLocalIp(String ip) {
|
||||
if (StringUtils.isEmpty(ip)) {
|
||||
return true;
|
||||
}
|
||||
return LOCAL_IP_LIST.contains(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据IP地址获取通用地址code
|
||||
*
|
||||
* @param country 国家
|
||||
* @param province 省份
|
||||
* @param city 城市
|
||||
* @return 通用地址code
|
||||
*/
|
||||
public static String getCode(String country, String province, String city) {
|
||||
String code = country;
|
||||
if (StringUtils.isNotBlank(province)) {
|
||||
code += CP_LINE + province;
|
||||
}
|
||||
if (StringUtils.isNotBlank(city)) {
|
||||
code += CP_LINE + city;
|
||||
}
|
||||
return Md5Utils.encryptToString(code);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package xtools.boot.core.utils;
|
||||
|
||||
import xtools.core.extend.TemplateUtils;
|
||||
|
||||
/**
|
||||
* <p>Title : AppUtils</p>
|
||||
* <p>Description : AppUtils</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/12/23 09:44
|
||||
*/
|
||||
public class AppUtils {
|
||||
|
||||
/**
|
||||
* 应用启动信息
|
||||
*/
|
||||
private static final String APP_START_INFO = "应用启动成功,总耗时{}毫秒";
|
||||
|
||||
/**
|
||||
* 获取启动信息
|
||||
*
|
||||
* @param startTime 启动时间
|
||||
* @return 启动信息
|
||||
*/
|
||||
public static String info(long startTime) {
|
||||
return TemplateUtils.format(APP_START_INFO, startTime);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package xtools.boot.core.utils;
|
||||
|
||||
import xtools.boot.api.enums.BaseEnum;
|
||||
import xtools.boot.api.model.EnumInfoDto;
|
||||
import xtools.core.ArrUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : EnumUtils</p>
|
||||
* <p>Description : EnumUtils</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:29
|
||||
*/
|
||||
public class EnumUtils implements Serializable {
|
||||
|
||||
/**
|
||||
* 获取枚举信息
|
||||
*
|
||||
* @param list 枚举值列表
|
||||
* @return 枚举的详细信息
|
||||
*/
|
||||
public static List<EnumInfoDto> getEnumInfos(BaseEnum... list) {
|
||||
if (ArrUtils.isEmpty(list)) {
|
||||
return null;
|
||||
}
|
||||
List<EnumInfoDto> dataList = new ArrayList<>();
|
||||
for (BaseEnum item : list) {
|
||||
dataList.add(new EnumInfoDto(item.code(), item.desc()));
|
||||
}
|
||||
return dataList;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package xtools.boot.core.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import xtools.core.CollectionUtils;
|
||||
import xtools.core.sys.SysBaseInfoUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : JarUtils</p>
|
||||
* <p>Description : JarUtils</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/18 20:57
|
||||
*/
|
||||
@Slf4j
|
||||
public class JarUtils implements Serializable {
|
||||
|
||||
/**
|
||||
* 获取所有jar名称
|
||||
*
|
||||
* @return jar名称
|
||||
*/
|
||||
public static List<String> getJarName() {
|
||||
String end = "jar";
|
||||
List<String> mfPath = null;
|
||||
try {
|
||||
mfPath = SysBaseInfoUtils.getMfPath();
|
||||
} catch (Exception e) {
|
||||
log.error("获取[MANIFEST.MF]文件路径失败", e);
|
||||
}
|
||||
if (CollectionUtils.isEmpty(mfPath)) {
|
||||
return null;
|
||||
}
|
||||
List<String> jarList = new ArrayList<>();
|
||||
mfPath.stream().filter(Objects::nonNull).forEach(item -> {
|
||||
item = item.replaceAll("!/META-INF/MANIFEST.MF", "");
|
||||
item = item.substring(item.lastIndexOf("/") + 1);
|
||||
if (item.endsWith(end)) {
|
||||
jarList.add(item);
|
||||
}
|
||||
});
|
||||
return jarList.stream().sorted().toList();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package xtools.boot.core.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* <p>Title : ModuleLoadUtils</p>
|
||||
* <p>Description : ModuleLoadUtils</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 09:20
|
||||
*/
|
||||
@Slf4j
|
||||
public class ModuleLoadUtils {
|
||||
|
||||
/**
|
||||
* 加载成功模版
|
||||
*/
|
||||
private static final String LOAD_TEMPLATE = "模块[{}]加载成功";
|
||||
|
||||
/**
|
||||
* 加载成功
|
||||
*/
|
||||
public static void loadSuccess(Class<?> clazz) {
|
||||
String packageName = clazz.getPackageName();
|
||||
log.info(LOAD_TEMPLATE, packageName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package xtools.boot.core.utils;
|
||||
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import xtools.core.ArrUtils;
|
||||
import xtools.core.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>Title : PathPatternUtils</p>
|
||||
* <p>Description : PathPatternUtils</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/8 09:05
|
||||
*/
|
||||
public class PathPatternUtils {
|
||||
|
||||
/**
|
||||
* 路径匹配
|
||||
*
|
||||
* @param pathPatterns 路径规则
|
||||
* @param path 路径
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean match(String[] pathPatterns, String path) {
|
||||
if (ArrUtils.isEmpty(pathPatterns)) {
|
||||
return false;
|
||||
}
|
||||
PathMatcher pm = new AntPathMatcher();
|
||||
for (String pathPattern : pathPatterns) {
|
||||
if (pm.match(pathPattern, path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 路径匹配
|
||||
*
|
||||
* @param pathPatterns 路径规则
|
||||
* @param path 路径
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean match(List<String> pathPatterns, String path) {
|
||||
if (CollectionUtils.isEmpty(pathPatterns)) {
|
||||
return false;
|
||||
}
|
||||
PathMatcher pm = new AntPathMatcher();
|
||||
for (String pathPattern : pathPatterns) {
|
||||
if (pm.match(pathPattern, path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 路径匹配
|
||||
*
|
||||
* @param pathPatterns 路径规则
|
||||
* @param path 路径
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean match(Set<String> pathPatterns, String path) {
|
||||
if (CollectionUtils.isEmpty(pathPatterns)) {
|
||||
return false;
|
||||
}
|
||||
PathMatcher pm = new AntPathMatcher();
|
||||
for (String pathPattern : pathPatterns) {
|
||||
if (pm.match(pathPattern, path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
package xtools.boot.core.utils;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.base.exception.CommonException;
|
||||
import xtools.boot.api.enums.BootError;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* <p>Title : SpringContextUtils</p>
|
||||
* <p>Description : SpringContextUtils</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
|
||||
*/
|
||||
@Order(-1)
|
||||
@Component
|
||||
public class SpringContextUtils implements BeanFactoryPostProcessor, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* "@PostConstruct"注解标记的类中,由于ApplicationContext还未加载,导致空指针
|
||||
* 因此实现BeanFactoryPostProcessor注入ConfigurableListableBeanFactory实现bean的操作
|
||||
*/
|
||||
private static ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Spring 应用上下文环境
|
||||
*/
|
||||
@Getter
|
||||
private static ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* 获取 ListableBeanFactory
|
||||
*
|
||||
* @return ListableBeanFactory
|
||||
*/
|
||||
public static ListableBeanFactory getBeanFactory() {
|
||||
return null == beanFactory ? applicationContext : beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ConfigurableListableBeanFactory
|
||||
*
|
||||
* @return ConfigurableListableBeanFactory
|
||||
*/
|
||||
public static ConfigurableListableBeanFactory getConfigurableBeanFactory() {
|
||||
ConfigurableListableBeanFactory factory = null;
|
||||
if (null != beanFactory) {
|
||||
factory = beanFactory;
|
||||
} else if (applicationContext instanceof ConfigurableApplicationContext) {
|
||||
factory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类的类型获取对应的 Bean
|
||||
*
|
||||
* @param <T> 类的类型
|
||||
* @param requiredType 类型
|
||||
* @return Bean
|
||||
*/
|
||||
public static <T> T getBean(Class<T> requiredType) {
|
||||
try {
|
||||
return getBeanFactory().getBean(requiredType);
|
||||
} catch (Exception e) {
|
||||
throw CommonException.create(BootError.SPRING_BASE, e, "根据类的类型获取对应的 Bean");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类的类型获取对应的 Bean
|
||||
*
|
||||
* @param <T> 类的类型
|
||||
* @param requiredType 类型
|
||||
* @return Bean
|
||||
*/
|
||||
public static <T> T getBeanDefNull(Class<T> requiredType) {
|
||||
try {
|
||||
return getBeanFactory().getBean(requiredType);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类的类型获取对应的 Bean 列表
|
||||
*
|
||||
* @param <T> 类的类型
|
||||
* @param requiredType 类型
|
||||
* @return Bean 列表
|
||||
*/
|
||||
public static <T> Collection<T> getBeanList(Class<T> requiredType) {
|
||||
try {
|
||||
return new LinkedList<>(getBeanFactory().getBeansOfType(requiredType).values());
|
||||
} catch (Exception e) {
|
||||
throw CommonException.create(BootError.SPRING_BASE, e, "根据类的类型获取对应的 Bean 列表");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 Bean 名称获取对象
|
||||
*
|
||||
* @param name Bean 名称
|
||||
* @return Bean
|
||||
*/
|
||||
public static Object getBean(String name) {
|
||||
try {
|
||||
return getBeanFactory().getBean(name);
|
||||
} catch (Exception e) {
|
||||
throw CommonException.create(BootError.SPRING_BASE, e, "根据 Bean 名称获取对象");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 Bean 名称获取对象
|
||||
*
|
||||
* @param name Bean 名称
|
||||
* @return Bean
|
||||
*/
|
||||
public static Object getBeanDefNull(String name) {
|
||||
try {
|
||||
return getBeanFactory().getBean(name);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态向 Spring 注册 Bean
|
||||
*
|
||||
* @param <T> Bean 类型
|
||||
* @param beanName 名称
|
||||
* @param bean Bean
|
||||
*/
|
||||
public static <T> void registerBean(String beanName, T bean) {
|
||||
final ConfigurableListableBeanFactory factory = getConfigurableBeanFactory();
|
||||
factory.autowireBean(bean);
|
||||
factory.registerSingleton(beanName, bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销bean(将Spring中的bean注销,请谨慎使用)
|
||||
*
|
||||
* @param beanName bean 名称
|
||||
*/
|
||||
public static void unregisterBean(String beanName) {
|
||||
final ConfigurableListableBeanFactory factory = getConfigurableBeanFactory();
|
||||
if (factory instanceof DefaultSingletonBeanRegistry registry) {
|
||||
registry.destroySingleton(beanName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布事件
|
||||
*
|
||||
* @param event 待发布的事件
|
||||
*/
|
||||
public static void publishAppEvent(ApplicationEvent event) {
|
||||
publishEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布事件
|
||||
*
|
||||
* @param event 待发布的事件
|
||||
*/
|
||||
public static void publishEvent(Object event) {
|
||||
if (null != applicationContext) {
|
||||
applicationContext.publishEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 Spring 应用上下文环境
|
||||
*
|
||||
* @param applicationContext ApplicationContext
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
|
||||
SpringContextUtils.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 beanFactory
|
||||
*
|
||||
* @param beanFactory ConfigurableListableBeanFactory
|
||||
*/
|
||||
@Override
|
||||
public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
SpringContextUtils.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package xtools.boot.core.utils;
|
||||
|
||||
import xtools.base.exception.CommonException;
|
||||
import xtools.boot.api.enums.BootError;
|
||||
import xtools.core.StringUtils;
|
||||
import xtools.core.enums.TimePattern;
|
||||
import xtools.core.extend.CheckUtils;
|
||||
import xtools.core.time.InstantUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* <p>Title : TimeUtils</p>
|
||||
* <p>Description : TimeUtils</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/6 14:20
|
||||
*/
|
||||
public class TimeUtils implements Serializable {
|
||||
|
||||
/**
|
||||
* 时间分隔符
|
||||
*/
|
||||
private static final String T = "T";
|
||||
|
||||
/**
|
||||
* 时间转换
|
||||
*
|
||||
* @param time 时间
|
||||
* @return 时间
|
||||
*/
|
||||
public static Instant toInstant(String time) {
|
||||
if (StringUtils.isBlank(time)) {
|
||||
return null;
|
||||
}
|
||||
if (time.contains(T)) {
|
||||
return Instant.parse(time);
|
||||
}
|
||||
if (CheckUtils.pattern(TimePattern.YMDHMS.regex(), time)) {
|
||||
return InstantUtils.parse(time, TimePattern.YMDHMS);
|
||||
} else if (CheckUtils.pattern(TimePattern.YMD.regex(), time)) {
|
||||
return InstantUtils.parse(time, TimePattern.YMD);
|
||||
} else {
|
||||
throw CommonException.create(BootError.TIME_CONVERT, time);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package xtools.boot.core.utils;
|
||||
|
||||
import xtools.boot.api.model.dto.resp.TreeResp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title : TreeUtils</p>
|
||||
* <p>Description : TreeUtils</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/30 09:41
|
||||
*/
|
||||
public class TreeUtils {
|
||||
|
||||
/**
|
||||
* 获取子节点
|
||||
*
|
||||
* @param id 父级 ID
|
||||
* @param list 数据级
|
||||
* @return 子级
|
||||
*/
|
||||
public static List<TreeResp> getChild(Long id, List<TreeResp> list) {
|
||||
List<TreeResp> childList = new ArrayList<>();
|
||||
list.stream().filter(item -> item.getParentId().equals(id)).forEach(item -> {
|
||||
List<TreeResp> child = getChild(item.getValue(), list);
|
||||
item.setChildren(child);
|
||||
childList.add(item);
|
||||
});
|
||||
return childList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
xtools.boot.core.BootCoreConfiguration
|
||||
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
|
||||
43
xtools-boot-elasticsearch/pom.xml
Normal file
43
xtools-boot-elasticsearch/pom.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?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>
|
||||
<artifactId>xtools-boot-elasticsearch</artifactId>
|
||||
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<!-- xtools begin -->
|
||||
<!-- xtools-extend 模块 -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-extend</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools end -->
|
||||
|
||||
<!-- 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 end -->
|
||||
|
||||
<!-- fastjson2 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package xtools.boot.elasticsearch;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import xtools.boot.core.utils.ModuleLoadUtils;
|
||||
import xtools.boot.elasticsearch.selector.BootElasticsearchImportSelector;
|
||||
|
||||
/**
|
||||
* <p>Title : BootElasticsearchConfiguration</p>
|
||||
* <p>Description : BootElasticsearchConfiguration</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(BootElasticsearchImportSelector.class)
|
||||
public class BootElasticsearchConfiguration {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public BootElasticsearchConfiguration() {
|
||||
ModuleLoadUtils.loadSuccess(BootElasticsearchConfiguration.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package xtools.boot.elasticsearch.enums;
|
||||
|
||||
import xtools.boot.api.enums.BaseEnum;
|
||||
|
||||
/**
|
||||
* <p>Title : ElasticsearchMonitorEnums</p>
|
||||
* <p>Description : ElasticsearchMonitorEnums</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 ElasticsearchMonitorEnums implements BaseEnum {
|
||||
|
||||
// 集群索引信息
|
||||
INDICES(1, "集群索引信息", "/_cat/indices?v"),
|
||||
// 集群健康信息
|
||||
HEALTH(2, "集群健康信息", "/_cat/health?v"),
|
||||
// 集群分片信息
|
||||
SHARDS(3, "集群分片信息", "/_cat/shards?v"),
|
||||
// 集群节点信息
|
||||
NODES(4, "集群节点信息", "/_cat/nodes?v"),
|
||||
// 集群任务
|
||||
TASKS(5, "集群任务", "/_cat/tasks?v"),
|
||||
// 集群段信息
|
||||
SEGMENTS(6, "集群段信息", "/_cat/segments?v"),
|
||||
// 集群文档总数
|
||||
COUNT(7, "集群文档总数", "/_cat/count?v"),
|
||||
// 集群shard的recovery过程
|
||||
RECOVERY(8, "集群shard的recovery过程", "/_cat/recovery?v"),
|
||||
// 集群别名组
|
||||
ALIASES(9, "集群别名组", "/_cat/aliases?v"),
|
||||
// 集群线程池任务
|
||||
THREAD_POOL(10, "集群线程池任务", "/_cat/thread_pool?v"),
|
||||
// 集群插件信息
|
||||
PLUGINS(11, "集群插件信息", "/_cat/plugins?v"),
|
||||
// 单节点的自定义属性
|
||||
NODEATTRS(12, "单节点的自定义属性", "/_cat/nodeattrs?v"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 命令
|
||||
*/
|
||||
private final String cmd;
|
||||
|
||||
/**
|
||||
* 初始化方法
|
||||
*
|
||||
* @param code Code
|
||||
* @param desc 说明
|
||||
* @param cmd 命令
|
||||
*/
|
||||
ElasticsearchMonitorEnums(int code, String desc, String cmd) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断枚举值类型
|
||||
*
|
||||
* @param code 枚举值
|
||||
* @return 枚举值类型
|
||||
*/
|
||||
public static ElasticsearchMonitorEnums valueOf(int code) {
|
||||
for (ElasticsearchMonitorEnums 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取命令
|
||||
*
|
||||
* @return 命令
|
||||
*/
|
||||
public String cmd() {
|
||||
return cmd;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package xtools.boot.elasticsearch.monitor;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.boot.api.exection.BizError;
|
||||
import xtools.boot.elasticsearch.enums.ElasticsearchMonitorEnums;
|
||||
import xtools.boot.elasticsearch.utils.EsUtils;
|
||||
import xtools.core.ArrUtils;
|
||||
import xtools.core.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : ElasticsearchMonitor</p>
|
||||
* <p>Description : ElasticsearchMonitor</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 17:58
|
||||
*/
|
||||
@Component
|
||||
public class ElasticsearchMonitor implements BaseParams {
|
||||
|
||||
/**
|
||||
* 获取Elasticsearch监控信息
|
||||
*
|
||||
* @param type 枚举
|
||||
* @return Elasticsearch监控信息
|
||||
*/
|
||||
public JSONObject info(ElasticsearchMonitorEnums type) {
|
||||
if (Objects.isNull(type)) {
|
||||
throw new BizError("类型参数不能为空");
|
||||
}
|
||||
// 查询
|
||||
String result;
|
||||
try {
|
||||
result = EsUtils.exec(type.cmd(), null, String.class, true);
|
||||
} catch (Exception e) {
|
||||
throw new BizError("查询异常");
|
||||
}
|
||||
// 处理数据
|
||||
result = result.replaceAll("\n", "###").replaceAll("\\s+", " ");
|
||||
List<String> arr = ArrUtils.toStringList(result, "###");
|
||||
if (CollectionUtils.isEmpty(arr)) {
|
||||
throw new BizError("类型参数不能为空");
|
||||
}
|
||||
// 封装表头
|
||||
List<String> titleList = ArrUtils.toStringList(arr.getFirst(), " ");
|
||||
// 处理主体数据
|
||||
List<JSONObject> dataList = new ArrayList<>();
|
||||
for (int i = CP_NUM1; i < arr.size(); i++) {
|
||||
String line = arr.get(i);
|
||||
List<String> data = ArrUtils.toStringList(line, " ");
|
||||
JSONObject lineData = new JSONObject();
|
||||
for (int j = CP_NUM0; j < data.size(); j++) {
|
||||
lineData.put(titleList.get(j), data.get(j));
|
||||
}
|
||||
dataList.add(lineData);
|
||||
}
|
||||
return JSONObject.of("title", titleList, "dataList", dataList);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package xtools.boot.elasticsearch.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 : BootElasticsearchImportSelector</p>
|
||||
* <p>Description : BootElasticsearchImportSelector</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 BootElasticsearchImportSelector 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.elasticsearch");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package xtools.boot.elasticsearch.utils;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.core.ArrUtils;
|
||||
import xtools.core.StringUtils;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : EsQueryUtils</p>
|
||||
* <p>Description : EsQueryUtils</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 08:58
|
||||
*/
|
||||
public class EsQueryUtils implements BaseParams {
|
||||
|
||||
/**
|
||||
* 设置精确查询
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param filedName 字段名称
|
||||
* @param params 参数
|
||||
*/
|
||||
public static void setMatchPhrase(JSONArray query, String filedName, Object params) {
|
||||
if (params instanceof String txt && StringUtils.isNotBlank(txt)) {
|
||||
query.add(JSONObject.of("match_phrase", JSONObject.of(filedName, txt)));
|
||||
} else if (Objects.nonNull(params)) {
|
||||
query.add(JSONObject.of("match_phrase", JSONObject.of(filedName, params)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 模糊查询
|
||||
*
|
||||
* @param query 模糊查询
|
||||
* @param filedName 字段名称
|
||||
* @param params 参数
|
||||
*/
|
||||
public static void setWildcard(JSONArray query, String filedName, String params) {
|
||||
if (StringUtils.isBlank(params)) {
|
||||
return;
|
||||
}
|
||||
query.add(JSONObject.of("wildcard", JSONObject.of(filedName, "*" + params + "*")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间范围查询
|
||||
*
|
||||
* @param query 时间范围查询
|
||||
* @param filedName 字段名称
|
||||
* @param params 参数
|
||||
*/
|
||||
public static void setTimeRange(JSONArray query, String filedName, Instant[] params) {
|
||||
if (ArrUtils.isEmpty(params)) {
|
||||
return;
|
||||
}
|
||||
long start = Long.MIN_VALUE;
|
||||
long end = Long.MAX_VALUE;
|
||||
Instant startTime = params[CP_NUM0];
|
||||
if (Objects.nonNull(startTime)) {
|
||||
start = startTime.toEpochMilli();
|
||||
}
|
||||
Instant endTime = params[CP_NUM1];
|
||||
if (Objects.nonNull(endTime)) {
|
||||
end = endTime.toEpochMilli();
|
||||
}
|
||||
query.add(JSONObject.of("range", JSONObject.of(filedName, JSONObject.of("gte", start, "lte", end))));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package xtools.boot.elasticsearch.utils;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.boot.api.exection.BizError;
|
||||
import xtools.boot.api.exection.BizWarning;
|
||||
import xtools.boot.core.utils.SpringContextUtils;
|
||||
import xtools.boot.log.LogBus;
|
||||
import xtools.boot.log.enums.LogBusBaseType;
|
||||
import xtools.core.BytesUtils;
|
||||
import xtools.core.CollectionUtils;
|
||||
import xtools.core.StringUtils;
|
||||
import xtools.core.encrypt.Base64Utils;
|
||||
import xtools.core.enums.LogLevel;
|
||||
import xtools.core.extend.HttpUtils;
|
||||
import xtools.extend.JsonUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : EsUtils</p>
|
||||
* <p>Description : EsUtils</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月17日 下午6:24:22
|
||||
*/
|
||||
@Component
|
||||
public class EsUtils {
|
||||
|
||||
/**
|
||||
* 超时时间
|
||||
*/
|
||||
private static final long TIMEOUT = 60 * 1000 * 5;
|
||||
|
||||
/**
|
||||
* 查询服务器地址
|
||||
*/
|
||||
private static String host;
|
||||
|
||||
/**
|
||||
* 授权信息
|
||||
*/
|
||||
private static String auth;
|
||||
|
||||
|
||||
@Value("${spring.elasticsearch.uris:#{null}}")
|
||||
private String uris;
|
||||
@Value("${spring.elasticsearch.username:#{null}}")
|
||||
private String username;
|
||||
@Value("${spring.elasticsearch.password:#{null}}")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 执行
|
||||
*
|
||||
* @param uri 执行的uri
|
||||
* @return 执行结果
|
||||
*/
|
||||
public static String exec(String uri) {
|
||||
return exec(uri, null, String.class, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行
|
||||
*
|
||||
* @param uri 执行的uri
|
||||
* @param req 请求参数
|
||||
* @return 执行结果
|
||||
*/
|
||||
public static JSONObject exec(String uri, JSONObject req) {
|
||||
return exec(uri, req, JSONObject.class, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行
|
||||
*
|
||||
* @param <T> 结果类型
|
||||
* @param uri 执行的uri
|
||||
* @param req 请求参数
|
||||
* @param clazz 结果类型
|
||||
* @param isGet 是否为get请求
|
||||
* @return 结果
|
||||
*/
|
||||
public static <T> T exec(String uri, JSONObject req, Class<T> clazz, boolean isGet) {
|
||||
// 参数校验
|
||||
if (StringUtils.isBlank(uri)) {
|
||||
throw new BizWarning("uri不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(host)) {
|
||||
// 初始化
|
||||
EsUtils bean = SpringContextUtils.getBean(EsUtils.class);
|
||||
bean.init();
|
||||
}
|
||||
HttpUtils http = HttpUtils.init(host + uri).addHeader("Content-Type", "application/json").timeOut(TIMEOUT);
|
||||
if (StringUtils.isNotBlank(auth)) {
|
||||
http.addHeader("Authorization", "Basic " + auth);
|
||||
}
|
||||
http.setLogCallBack(log -> {
|
||||
byte[] resp = log.resp();
|
||||
String respData = BytesUtils.isEmpty(resp) ? null : new String(resp);
|
||||
JSONObject logData = JSONObject.of(
|
||||
"req", log.reqParam(),
|
||||
"resp", JsonUtils.isJson(respData) ? JSONObject.parseObject(respData) : respData,
|
||||
"execTime", log.execTime()
|
||||
);
|
||||
Throwable error = log.error();
|
||||
// 保存日志
|
||||
LogBus.init(Objects.isNull(error) ? LogLevel.INFO : LogLevel.ERROR, LogBusBaseType.ELASTICSEARCH)
|
||||
.data(logData)
|
||||
.error(error)
|
||||
.save();
|
||||
});
|
||||
// 查询结果
|
||||
String result;
|
||||
if (isGet) {
|
||||
result = http.get();
|
||||
} else {
|
||||
result = http.post(CollectionUtils.isEmpty(req) ? null : req.toString());
|
||||
}
|
||||
if (StringUtils.isBlank(result)) {
|
||||
throw new BizWarning("ES执行结果为空");
|
||||
}
|
||||
return JSON.to(clazz, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取授权信息
|
||||
*
|
||||
* @param username 用户名
|
||||
* @param password 密码
|
||||
* @return 授权信息
|
||||
*/
|
||||
private static String getAuth(String username, String password) {
|
||||
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
|
||||
return null;
|
||||
}
|
||||
return Base64Utils.encodeToStr((username + ":" + password).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
public void init() {
|
||||
if (StringUtils.isNotBlank(host)) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isBlank(uris)) {
|
||||
throw new BizError("Es工具类初始化失败, spring.elasticsearch.uris 不能为空");
|
||||
}
|
||||
EsUtils.host = uris;
|
||||
EsUtils.auth = getAuth(username, password);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
xtools.boot.elasticsearch.BootElasticsearchConfiguration
|
||||
43
xtools-boot-ip/pom.xml
Normal file
43
xtools-boot-ip/pom.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?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>
|
||||
<artifactId>xtools-boot-ip</artifactId>
|
||||
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<!-- xtools begin -->
|
||||
<!-- xtools-extend 模块 -->
|
||||
<!-- ip2region(本地IP查询工具) -->
|
||||
<dependency>
|
||||
<groupId>org.lionsoul</groupId>
|
||||
<artifactId>ip2region</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-extend</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools end -->
|
||||
|
||||
<!-- xtools-boot begin -->
|
||||
<!-- xtools-boot-core -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-core</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-boot end -->
|
||||
|
||||
<!-- spring-boot -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package xtools.boot.ip;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import xtools.boot.core.utils.ModuleLoadUtils;
|
||||
import xtools.boot.ip.selector.BootIpImportSelector;
|
||||
|
||||
/**
|
||||
* <p>Title : BootIpConfiguration</p>
|
||||
* <p>Description : BootIpConfiguration</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(BootIpImportSelector.class)
|
||||
public class BootIpConfiguration {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public BootIpConfiguration() {
|
||||
ModuleLoadUtils.loadSuccess(BootIpConfiguration.class);
|
||||
}
|
||||
|
||||
}
|
||||
49
xtools-boot-ip/src/main/java/xtools/boot/ip/init/InitIp.java
Normal file
49
xtools-boot-ip/src/main/java/xtools/boot/ip/init/InitIp.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package xtools.boot.ip.init;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.lionsoul.ip2region.xdb.Version;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.boot.ip.utils.IpUtils;
|
||||
import xtools.extend.IpLocalUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* <p>Title : InitIp</p>
|
||||
* <p>Description : InitIp</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/16 10:21
|
||||
*/
|
||||
@Component
|
||||
@Order(BaseParams.CP_NUM50)
|
||||
public class InitIp implements ApplicationRunner {
|
||||
|
||||
private static final String IP_FILE = "ip/ip2region_v4.xdb";
|
||||
|
||||
@Override
|
||||
public void run(@NonNull ApplicationArguments args) throws Exception {
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化IP库
|
||||
*/
|
||||
private void init() throws IOException {
|
||||
ClassPathResource classPathResource = new ClassPathResource(IP_FILE);
|
||||
try (InputStream is = classPathResource.getInputStream()) {
|
||||
IpLocalUtils.init(is, Version.IPv4);
|
||||
IpUtils.init();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package xtools.boot.ip.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 : BootIpImportSelector</p>
|
||||
* <p>Description : BootIpImportSelector</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 BootIpImportSelector 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.ip");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package xtools.boot.ip.utils;
|
||||
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.boot.api.exection.BizError;
|
||||
import xtools.core.StringUtils;
|
||||
import xtools.extend.IpLocalUtils;
|
||||
import xtools.extend.dto.IpAddrDto;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* <p>Title : IpUtils</p>
|
||||
* <p>Description : IpUtils</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/16 10:41
|
||||
*/
|
||||
public class IpUtils implements BaseParams {
|
||||
|
||||
/**
|
||||
* 是否初始化
|
||||
*/
|
||||
private static boolean init = false;
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
public static void init() {
|
||||
init = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询IP对应地址
|
||||
*
|
||||
* @param ip IP
|
||||
* @return IP对应地址
|
||||
*/
|
||||
public static IpAddrDto search(String ip) {
|
||||
if (!init) {
|
||||
throw new BizError("请先初始化IpUtils");
|
||||
}
|
||||
return IpLocalUtils.search(ip, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取IP对应地址
|
||||
*
|
||||
* @param ip IP
|
||||
* @return IP对应地址
|
||||
*/
|
||||
public static String searchAddr(String ip) {
|
||||
return searchAddr(search(ip));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取IP对应地址
|
||||
*
|
||||
* @param addr 地址信息
|
||||
* @return IP对应地址
|
||||
*/
|
||||
public static String searchAddr(IpAddrDto addr) {
|
||||
if (Objects.isNull(addr)) {
|
||||
return "未知";
|
||||
}
|
||||
StringJoiner joiner = new StringJoiner(CP_COMMA);
|
||||
if (StringUtils.isNotBlank(addr.getCountry())) {
|
||||
joiner.add(addr.getCountry());
|
||||
}
|
||||
if (StringUtils.isNotBlank(addr.getProvince())) {
|
||||
joiner.add(addr.getProvince());
|
||||
}
|
||||
if (StringUtils.isNotBlank(addr.getCity())) {
|
||||
joiner.add(addr.getCity());
|
||||
}
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
xtools.boot.ip.BootIpConfiguration
|
||||
BIN
xtools-boot-ip/src/main/resources/ip/ip2region_v4.xdb
Normal file
BIN
xtools-boot-ip/src/main/resources/ip/ip2region_v4.xdb
Normal file
Binary file not shown.
19
xtools-boot-job/pom.xml
Normal file
19
xtools-boot-job/pom.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?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-job</artifactId>
|
||||
|
||||
<!-- 子模块 -->
|
||||
<modules>
|
||||
<module>xtools-boot-job-xxl</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
41
xtools-boot-job/xtools-boot-job-xxl/README.md
Normal file
41
xtools-boot-job/xtools-boot-job-xxl/README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# xxl-job使用
|
||||
|
||||
## 官网地址
|
||||
|
||||
[xxl-job官网](https://www.xuxueli.com/xxl-job)
|
||||
|
||||
## 操作说明
|
||||
|
||||
> 1.先安装xxl-job-admin
|
||||
> 2.配置application-boot-xxl-job.yaml文件,可以参考application-boot-xxl-job-demo.yaml
|
||||
> 3.运行项目,即可在admin配置定时任务了
|
||||
|
||||
## docker命令
|
||||
|
||||
```sh
|
||||
# docker命令启动
|
||||
docker run -d \
|
||||
-e PARAMS=" \
|
||||
--spring.datasource.url=jdbc:mysql://devmysql.xujun.org:11010/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai \
|
||||
--spring.datasource.username=demo \
|
||||
--spring.datasource.password=demo321 \
|
||||
--xxl.job.accessToken=xtools-app-xxl-job \
|
||||
" \
|
||||
-p 26000:8080 \
|
||||
-v /data1/xxl-job-admin/applogs:/data/applogs \
|
||||
--name xxl-job-admin \
|
||||
registry.cn-hangzhou.aliyuncs.com/xujun-public/xxl-job-admin:3.3.2
|
||||
```
|
||||
|
||||
## docker-compose
|
||||
|
||||
> 参考docker-compose目录
|
||||
|
||||
## 访问
|
||||
|
||||
```sh
|
||||
# 访问地址
|
||||
http://[ip]:[port]/xxl-job-admin
|
||||
# 账号/密码
|
||||
admin/123456
|
||||
```
|
||||
@@ -0,0 +1,23 @@
|
||||
services:
|
||||
xxl-job-admin:
|
||||
container_name: xxl-job-admin
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xujun-public/xxl-job-admin:3.3.2
|
||||
pull_policy: always
|
||||
ports:
|
||||
- "26000:8080"
|
||||
volumes:
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "/data1/xxl-job-admin/applogs:/data/applogs"
|
||||
env_file:
|
||||
- env/container.env
|
||||
restart: always
|
||||
networks:
|
||||
- xxl_job_net
|
||||
|
||||
networks:
|
||||
xxl_job_net:
|
||||
name: xxl_job_net
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.201.0.0/16
|
||||
@@ -0,0 +1,2 @@
|
||||
# xxl-job-admin配置
|
||||
PARAMS=--spring.datasource.url=jdbc:mysql://devmysql.xujun.org:11010/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai --spring.datasource.username=demo --spring.datasource.password=demo321 --xxl.job.accessToken=xtools-app-xxl-job
|
||||
36
xtools-boot-job/xtools-boot-job-xxl/pom.xml
Normal file
36
xtools-boot-job/xtools-boot-job-xxl/pom.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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-job</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</parent>
|
||||
<artifactId>xtools-boot-job-xxl</artifactId>
|
||||
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<!-- xtools-boot begin -->
|
||||
<!-- xtools-boot-core -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-core</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-boot end -->
|
||||
|
||||
<!-- xxl-job -->
|
||||
<dependency>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- spring-boot -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package xtools.boot.job.xxl;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import xtools.boot.core.utils.ModuleLoadUtils;
|
||||
import xtools.boot.job.xxl.selector.BootXxlJobImportSelector;
|
||||
|
||||
/**
|
||||
* <p>Title : BootXxlJobConfiguration</p>
|
||||
* <p>Description : BootXxlJobConfiguration</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(BootXxlJobImportSelector.class)
|
||||
public class BootXxlJobConfiguration {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public BootXxlJobConfiguration() {
|
||||
ModuleLoadUtils.loadSuccess(BootXxlJobConfiguration.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package xtools.boot.job.xxl.config;
|
||||
|
||||
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import xtools.core.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>Title : XxlJobConfig</p>
|
||||
* <p>Description : XxlJobConfig</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/10 14:06
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class XxlJobConfig {
|
||||
|
||||
/**
|
||||
* 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔.执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
|
||||
*/
|
||||
@Value("${xxl.job.admin.addresses}")
|
||||
private String adminAddresses;
|
||||
|
||||
/**
|
||||
* 调度中心通讯TOKEN [选填]:非空时启用;
|
||||
*/
|
||||
@Value("${xxl.job.admin.accessToken}")
|
||||
private String accessToken;
|
||||
|
||||
/**
|
||||
* 调度中心通讯超时时间[选填],单位秒;默认3s;
|
||||
*/
|
||||
@Value("${xxl.job.admin.timeout}")
|
||||
private int timeout;
|
||||
|
||||
/**
|
||||
* 执行器启用开关 [选填]:默认开启,关闭时不进行执行器初始化;
|
||||
*/
|
||||
@Getter
|
||||
@Value("${xxl.job.executor.enabled:false}")
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
|
||||
*/
|
||||
@Value("${xxl.job.executor.appName}")
|
||||
private String appName;
|
||||
|
||||
/**
|
||||
* 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址.从而更灵活支持容器类型执行器动态IP和动态映射端口问题.
|
||||
*/
|
||||
@Value("${xxl.job.executor.address}")
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯使用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
|
||||
*/
|
||||
@Value("${xxl.job.executor.ip}")
|
||||
private String ip;
|
||||
|
||||
/**
|
||||
* 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
|
||||
*/
|
||||
@Value("${xxl.job.executor.port}")
|
||||
private int port;
|
||||
|
||||
/**
|
||||
* 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
|
||||
*/
|
||||
@Value("${xxl.job.executor.logPath}")
|
||||
private String logPath;
|
||||
|
||||
/**
|
||||
* 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
|
||||
*/
|
||||
@Value("${xxl.job.executor.logRetentionDays}")
|
||||
private int logRetentionDays;
|
||||
|
||||
/**
|
||||
* 任务扫描排除路径 [选填] :任务扫描时忽略指定包路径下的Bean;支持配置包路径前缀,多个逗号分隔;
|
||||
*/
|
||||
@Value("${xxl.job.executor.excludedPackage}")
|
||||
private String excludedPackage;
|
||||
|
||||
/**
|
||||
* xxl-job 执行器
|
||||
*
|
||||
* @return xxl-job 执行器
|
||||
*/
|
||||
@Bean
|
||||
public XxlJobSpringExecutor xxlJobExecutor() {
|
||||
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
|
||||
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
|
||||
xxlJobSpringExecutor.setAccessToken(accessToken);
|
||||
xxlJobSpringExecutor.setTimeout(timeout);
|
||||
xxlJobSpringExecutor.setEnabled(enabled);
|
||||
xxlJobSpringExecutor.setAppname(appName);
|
||||
if (StringUtils.isNotBlank(address)) {
|
||||
xxlJobSpringExecutor.setAddress(address);
|
||||
}
|
||||
if (StringUtils.isNotBlank(ip)) {
|
||||
xxlJobSpringExecutor.setIp(ip);
|
||||
}
|
||||
if (port > 0) {
|
||||
xxlJobSpringExecutor.setPort(port);
|
||||
}
|
||||
if (StringUtils.isNotBlank(logPath)) {
|
||||
xxlJobSpringExecutor.setLogPath(logPath);
|
||||
}
|
||||
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
|
||||
if (StringUtils.isNotBlank(excludedPackage)) {
|
||||
xxlJobSpringExecutor.setExcludedPackage(excludedPackage);
|
||||
}
|
||||
return xxlJobSpringExecutor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package xtools.boot.job.xxl.init;
|
||||
|
||||
import com.xxl.job.core.executor.XxlJobExecutor;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.base.config.BaseParams;
|
||||
import xtools.boot.core.interfaces.JobInterface;
|
||||
import xtools.boot.core.utils.SpringContextUtils;
|
||||
import xtools.boot.job.xxl.config.XxlJobConfig;
|
||||
import xtools.core.CollectionUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : InitIp</p>
|
||||
* <p>Description : InitIp</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/16 10:21
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Order(BaseParams.CP_NUM90)
|
||||
public class InitXxlJob implements ApplicationRunner, BaseParams {
|
||||
|
||||
private final XxlJobConfig xxlJobConfig;
|
||||
|
||||
@Override
|
||||
public void run(@NonNull ApplicationArguments args) {
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
private void init() {
|
||||
Boolean enabled = xxlJobConfig.getEnabled();
|
||||
if (Objects.isNull(enabled) || !enabled) {
|
||||
log.info("xxl-job未启用");
|
||||
return;
|
||||
}
|
||||
Collection<JobInterface> beanList = SpringContextUtils.getBeanList(JobInterface.class);
|
||||
if (CollectionUtils.isEmpty(beanList)) {
|
||||
log.info("没有需要执行xxl-job的任务");
|
||||
return;
|
||||
}
|
||||
beanList.forEach(item -> {
|
||||
try {
|
||||
String name = item.getClass().getSimpleName();
|
||||
name = Character.toLowerCase(name.charAt(CP_NUM0)) + name.substring(CP_NUM1);
|
||||
registerXxlJob(name, item);
|
||||
log.info("注册xxl-job任务成功:{}", name);
|
||||
} catch (Exception e) {
|
||||
log.error("注册xxl-job任务异常", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册任务
|
||||
*
|
||||
* @param name 任务名称
|
||||
* @param job 任务
|
||||
*/
|
||||
private void registerXxlJob(String name, JobInterface job) {
|
||||
IJobHandler handler = new IJobHandler() {
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
job.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
job.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
job.destroy();
|
||||
}
|
||||
};
|
||||
// 注册到XXL-JOB
|
||||
XxlJobExecutor.registryJobHandler(name, handler);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package xtools.boot.job.xxl.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 : BootXxlJobImportSelector</p>
|
||||
* <p>Description : BootXxlJobImportSelector</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 BootXxlJobImportSelector 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.job.xxl");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
xtools.boot.job.xxl.BootXxlJobConfiguration
|
||||
@@ -0,0 +1,26 @@
|
||||
xxl:
|
||||
job:
|
||||
admin:
|
||||
# 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔.执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
|
||||
addresses: http://10.1.0.12:8080/xxl-job-admin
|
||||
# 调度中心通讯TOKEN [选填]:非空时启用;
|
||||
accessToken: xtools-app-xxl-job
|
||||
# 调度中心通讯超时时间[选填],单位秒;默认3s;
|
||||
timeout: 3
|
||||
executor:
|
||||
# 执行器启用开关 [选填]:默认开启,关闭时不进行执行器初始化;
|
||||
enabled: true
|
||||
# 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
|
||||
appName: xtools-cloud
|
||||
# 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址.从而更灵活支持容器类型执行器动态IP和动态映射端口问题.
|
||||
address: ""
|
||||
# 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯使用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
|
||||
ip: ""
|
||||
# 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
|
||||
port: 9999
|
||||
# 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
|
||||
logPath: /Users/xujun/Downloads/xtools
|
||||
# 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
|
||||
logRetentionDays: 30
|
||||
# 任务扫描排除路径 [选填] :任务扫描时忽略指定包路径下的Bean;支持配置包路径前缀,多个逗号分隔;
|
||||
excludedPackage: ""
|
||||
37
xtools-boot-knife4j/pom.xml
Normal file
37
xtools-boot-knife4j/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</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</parent>
|
||||
<artifactId>xtools-boot-knife4j</artifactId>
|
||||
|
||||
<!-- 项目依赖 -->
|
||||
<dependencies>
|
||||
<!-- xtools-boot begin -->
|
||||
<!-- xtools-boot-core -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-core</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-boot end -->
|
||||
|
||||
<!-- SpringBoot begin -->
|
||||
<!-- springdoc -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
</dependency>
|
||||
<!-- knife4j -->
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- SpringBoot end -->
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package xtools.boot.knife4j;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import xtools.boot.core.utils.ModuleLoadUtils;
|
||||
import xtools.boot.knife4j.selector.BootKnife4jImportSelector;
|
||||
|
||||
/**
|
||||
* <p>Title : BootKnife4jConfiguration</p>
|
||||
* <p>Description : BootKnife4jConfiguration</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(BootKnife4jImportSelector.class)
|
||||
public class BootKnife4jConfiguration {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public BootKnife4jConfiguration() {
|
||||
ModuleLoadUtils.loadSuccess(BootKnife4jConfiguration.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package xtools.boot.knife4j.config;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import xtools.boot.core.interfaces.FilterWhitelist;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>Title : Knife4jFilterWhitelist</p>
|
||||
* <p>Description : Knife4jFilterWhitelist</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 Knife4jFilterWhitelist implements FilterWhitelist {
|
||||
|
||||
/**
|
||||
* 添加过滤器白名单
|
||||
*
|
||||
* @return 过滤器白名单
|
||||
*/
|
||||
@Override
|
||||
public Set<String> add() {
|
||||
return Set.of(
|
||||
"/doc.html",
|
||||
"/webjars/**",
|
||||
"/v3/api-docs/**"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package xtools.boot.knife4j.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 : BootKnife4jImportSelector</p>
|
||||
* <p>Description : BootKnife4jImportSelector</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 BootKnife4jImportSelector 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.knife4j");
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user