mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-06 12:39:38 +00:00
ref 脚手架同步为最新版本
This commit is contained in:
61
bootx-platform/bootx-platform-core/pom.xml
Normal file
61
bootx-platform/bootx-platform-core/pom.xml
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform</artifactId>
|
||||
<version>3.0.0.beta1</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>bootx-platform-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!-- lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- swagger 依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-common</artifactId>
|
||||
<version>${springdoc.version}</version>
|
||||
</dependency>
|
||||
<!-- hutool工具类 核心包 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<!-- hutool工具类 json包 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-json</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<!-- hutool工具类 加解密 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<!-- 国密扩展-->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk18on</artifactId>
|
||||
<version>${bouncycastle.version}</version>
|
||||
</dependency>
|
||||
<!-- TTL容器 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>transmittable-thread-local</artifactId>
|
||||
<version>${ttl.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
@@ -0,0 +1,24 @@
|
||||
package cn.bootx.platform.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 大字段注解
|
||||
* 配合 {@linkplain cn.hutool.core.map.MapUtil} 中 excludeBigField 方法使用使用
|
||||
*
|
||||
* 使用Mp条件构造器器分页查询时样例
|
||||
* {@snippet :
|
||||
* wrapper.select(this.getEntityClass (), MpUtil::excludeBigField);
|
||||
* }
|
||||
*
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/10/24
|
||||
*/
|
||||
@Target({ ElementType.PARAMETER, ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface BigField {
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package cn.bootx.platform.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 忽略鉴权, 可以放在controller控制器类和方法上,同时使用时,以方法上的为准
|
||||
* @author xxm
|
||||
* @since 2024/6/25
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface IgnoreAuth {
|
||||
|
||||
/**
|
||||
* 只要登录就可以访问,忽略权限校验
|
||||
*/
|
||||
boolean login() default false;
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package cn.bootx.platform.core.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 组件忽略注解
|
||||
* @author xxm
|
||||
* @since 2024/6/25
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface IgnoreTenant {
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package cn.bootx.platform.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 内部请求接口, 只允许超级管理员访问
|
||||
* @author xxm
|
||||
* @since 2024/6/25
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface InternalPath {
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
package cn.bootx.platform.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 操作日志注解(支持重复注解)
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/8/13
|
||||
*/
|
||||
@Target({ ElementType.PARAMETER, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Repeatable(value = OperateLogs.class)
|
||||
@Inherited
|
||||
public @interface OperateLog {
|
||||
|
||||
/**
|
||||
* 模块
|
||||
*/
|
||||
String title() default "";
|
||||
|
||||
/**
|
||||
* 业务操作类型
|
||||
*/
|
||||
BusinessType businessType() default BusinessType.OTHER;
|
||||
|
||||
/**
|
||||
* 是否保存请求参数
|
||||
*/
|
||||
boolean saveParam() default false;
|
||||
|
||||
/**
|
||||
* 是否保存返回参数
|
||||
*/
|
||||
boolean saverReturn() default false;
|
||||
|
||||
/**
|
||||
* 业务操作类型
|
||||
* 字典: log_business_type
|
||||
*/
|
||||
enum BusinessType {
|
||||
|
||||
/**
|
||||
* 其它
|
||||
*/
|
||||
OTHER,
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
ADD,
|
||||
|
||||
/**
|
||||
* 修改
|
||||
*/
|
||||
UPDATE,
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
DELETE,
|
||||
|
||||
/**
|
||||
* 授权
|
||||
*/
|
||||
GRANT,
|
||||
|
||||
/**
|
||||
* 导出
|
||||
*/
|
||||
EXPORT,
|
||||
|
||||
/**
|
||||
* 导入
|
||||
*/
|
||||
IMPORT,
|
||||
|
||||
/**
|
||||
* 强退
|
||||
*/
|
||||
FORCE,
|
||||
|
||||
/**
|
||||
* 清空数据
|
||||
*/
|
||||
CLEAN,
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package cn.bootx.platform.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 操作日志注解组
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/12/20
|
||||
*/
|
||||
@Target({ ElementType.PARAMETER, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface OperateLogs {
|
||||
|
||||
/** 操作日志注解组 */
|
||||
OperateLog[] value();
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package cn.bootx.platform.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 权限码
|
||||
* @author xxm
|
||||
* @since 2024/7/7
|
||||
*/
|
||||
@Target({ ElementType.PARAMETER, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface PermCode {
|
||||
|
||||
/**
|
||||
* 权限码,支持配置多个
|
||||
*/
|
||||
String[] value();
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
package cn.bootx.platform.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 查询参数 生效顺序 QueryParams 查询参数字段 > Entity 数据库实体字段 > QueryParams 查询类 > Entity 数据库实体类
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/12/12
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface QueryParam {
|
||||
/**
|
||||
* 匹配条件类型
|
||||
*/
|
||||
CompareTypeEnum type() default CompareTypeEnum.EQ;
|
||||
|
||||
/**
|
||||
* 生成查询条件时是否忽略
|
||||
*/
|
||||
boolean ignore() default false;
|
||||
|
||||
/**
|
||||
* 名称转换类型, 默认为下划线
|
||||
*/
|
||||
NamingCaseEnum namingCase() default NamingCaseEnum.UNDER_LINE;
|
||||
|
||||
/**
|
||||
* 自定义查询字段对应的数据库字段名称. 只可以在字段上标注时使用,标注在类上不生效 配置后,namingCase配置将会无效,会以这项配置数据库字段名称为准
|
||||
*/
|
||||
String fieldName() default "";
|
||||
|
||||
/**
|
||||
* 匹配类型
|
||||
*/
|
||||
enum CompareTypeEnum {
|
||||
|
||||
/** 大于 */
|
||||
GT,
|
||||
|
||||
/** 大于等于 */
|
||||
GE,
|
||||
|
||||
/** 小于 */
|
||||
LT,
|
||||
|
||||
/** 小于等于 */
|
||||
LE,
|
||||
|
||||
/** 等于 */
|
||||
EQ,
|
||||
/** 范围查询, 需要放在对象上, */
|
||||
BETWEEN,
|
||||
|
||||
/** 模糊匹配 */
|
||||
LIKE,
|
||||
|
||||
/** 左模糊 */
|
||||
LIKE_LEFT,
|
||||
|
||||
/** 右模糊 */
|
||||
LIKE_RIGHT,
|
||||
|
||||
/** 是否为空, 只作用在布尔类型上, true 代表 is null, false 代表 not null */
|
||||
IS_NULL,
|
||||
|
||||
/** 排序 */
|
||||
SORT
|
||||
}
|
||||
|
||||
/**
|
||||
* 名称转换类型
|
||||
*/
|
||||
enum NamingCaseEnum {
|
||||
/** 转换为下划线 */
|
||||
UNDER_LINE,
|
||||
/** 不进行处理 */
|
||||
NONE
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
package cn.bootx.platform.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 请求分组注解
|
||||
* @see RequestPath
|
||||
*
|
||||
* <br/>
|
||||
* 分为三级: 模块-->分组-->路径
|
||||
* <br/>
|
||||
* 模块: 通常对应一个的功能模块, 如用户管理、认证服务、权限管理等
|
||||
* <br/>
|
||||
* 分组: 通常对应多个请求组成的一个功能点分组, 如用户管理下的用户管理、用户管理下的角色管理等,多数时候会对对应少数几个或者一个控制器(Controller)
|
||||
* <br/>
|
||||
* 路径: 对应具体的一个具体请求方式(GET/POST)的请求路径
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/7/4
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface RequestGroup {
|
||||
/**
|
||||
* 模块编码
|
||||
*/
|
||||
String moduleCode();
|
||||
|
||||
/**
|
||||
* 模块名称, 多次标注注解时, 同样的模块编码, 可以只写一个模块名称, 其他未写的会自动使用这个
|
||||
*/
|
||||
String moduleName() default "";
|
||||
|
||||
/**
|
||||
* 分组编码
|
||||
*/
|
||||
String groupCode();
|
||||
|
||||
/**
|
||||
* 分组名称, 多次标注注解时, 同样的分组编码, 可以只写一个分组名称, 其他未写的会自动使用这个
|
||||
*/
|
||||
String groupName() default "";
|
||||
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
package cn.bootx.platform.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 请求路径注解
|
||||
* @see RequestGroup
|
||||
* <br/>
|
||||
* 分为三级: 模块-->分组-->路径
|
||||
* <br/>
|
||||
* 模块: 通常对应一个的功能模块, 如用户管理、认证服务、权限管理等
|
||||
* <br/>
|
||||
* 分组: 通常对应多个请求组成的一个功能点分组, 如用户管理下的用户管理、用户管理下的角色管理等,多数时候会对对应少数几个或者一个控制器
|
||||
* <br/>
|
||||
* 路径: 对应具体的一个具体请求方式(GET/POST)的请求路径
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/7/4
|
||||
*/
|
||||
@Target({ ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface RequestPath {
|
||||
|
||||
/**
|
||||
* 请求路径名称
|
||||
*/
|
||||
String value();
|
||||
}
|
@@ -0,0 +1,83 @@
|
||||
package cn.bootx.platform.core.code;
|
||||
|
||||
/**
|
||||
* 公共常量
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2020/4/8 10:58
|
||||
*/
|
||||
public interface CommonCode {
|
||||
|
||||
/** 服务器地址 */
|
||||
String SERVER_URL = "ServerUrl";
|
||||
|
||||
/** 开发环境 */
|
||||
String ENV_DEV = "dev";
|
||||
|
||||
/** 测试环境 */
|
||||
String ENV_TEST = "test";
|
||||
|
||||
/** 生产环境 */
|
||||
String ENV_PROD = "prod";
|
||||
|
||||
/**
|
||||
* 实体类删除标记
|
||||
*/
|
||||
String DELETE_FLAG = "1";
|
||||
|
||||
/**
|
||||
* 实体类正常标记
|
||||
*/
|
||||
String NORMAL_FLAG = "0";
|
||||
|
||||
/**
|
||||
* 系统默认用户的 userId,便于定时任务和异步任务时使用
|
||||
*/
|
||||
Long SYSTEM_DEFAULT_USERID = 1L;
|
||||
|
||||
/**
|
||||
* 系统默认用户的 userId,便于定时任务和异步任务时使用
|
||||
*/
|
||||
String SYSTEM_DEFAULT_USERNAME = "系统";
|
||||
|
||||
/**
|
||||
* 响应成功码
|
||||
*/
|
||||
int SUCCESS_CODE = 0;
|
||||
|
||||
/**
|
||||
* 响应失败码
|
||||
*/
|
||||
int FAIL_CODE = 1;
|
||||
|
||||
/** 追踪Id */
|
||||
String TRACE_ID = "traceId";
|
||||
|
||||
/** 用户 */
|
||||
String USER = "user";
|
||||
|
||||
/** 用户id */
|
||||
String USER_ID = "userId";
|
||||
|
||||
/** 主键字段 */
|
||||
String ID = "id";
|
||||
|
||||
/** 创建人字段 */
|
||||
String CREATOR = "creator";
|
||||
|
||||
/** 创建时间字段 */
|
||||
String CREATE_TIME = "createTime";
|
||||
|
||||
/** 最后更新人字段 */
|
||||
String LAST_MODIFIER = "lastModifier";
|
||||
|
||||
/** 最后更新时间字段 */
|
||||
String LAST_MODIFIED_TIME = "lastModifiedTime";
|
||||
|
||||
/** 数据版本号字段 */
|
||||
String VERSION = "version";
|
||||
|
||||
/** 数据软删除标识字段 */
|
||||
String DELETED = "deleted";
|
||||
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
package cn.bootx.platform.core.code;
|
||||
|
||||
/**
|
||||
* 公用错误码常量 10000-19999
|
||||
*/
|
||||
public interface CommonErrorCode {
|
||||
|
||||
/** 系统错误 */
|
||||
int SYSTEM_ERROR = 10500;
|
||||
|
||||
/** 认证失败 */
|
||||
int AUTHENTICATION_FAIL = 10401;
|
||||
|
||||
/** 参数处理失败 */
|
||||
int PARSE_PARAMETERS_ERROR = 10505;
|
||||
|
||||
/** 参数验证失败 */
|
||||
int VALIDATE_PARAMETERS_ERROR = 10506;
|
||||
|
||||
/** 重复操作异常 */
|
||||
int REPETITIVE_OPERATION_ERROR = 10507;
|
||||
|
||||
/** 资源不存在 */
|
||||
int SOURCES_NOT_EXIST = 10404;
|
||||
|
||||
/** 数据不存在 */
|
||||
int DATA_NOT_EXIST = 10405;
|
||||
|
||||
/** 不支持的操作 */
|
||||
int UN_SUPPORTED_OPERATE = 10415;
|
||||
|
||||
/** 危险SQL异常, */
|
||||
int DANGER_SQL = 10512;
|
||||
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package cn.bootx.platform.core.code;
|
||||
|
||||
/**
|
||||
* Servlet常量
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/3/10
|
||||
*/
|
||||
public interface ServletCode {
|
||||
|
||||
String METHOD = "Method";
|
||||
|
||||
String CONTEXT_PATH = "ContextPath";
|
||||
|
||||
String REQUEST_URI = "RequestURI";
|
||||
|
||||
String REQUEST_URL = "RequestURL";
|
||||
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
package cn.bootx.platform.core.code;
|
||||
|
||||
/**
|
||||
* web请求头常量
|
||||
*
|
||||
* @author network
|
||||
*/
|
||||
public interface WebHeaderCode {
|
||||
|
||||
/** ip */
|
||||
String X_FORWARDED_FOR = "X-Forwarded-For";
|
||||
|
||||
/** 用户代理 */
|
||||
String USER_AGENT = "User-Agent";
|
||||
|
||||
/** 请求头中 operatorId 的参数名 */
|
||||
String OPERATOR_ID = "OperatorId";
|
||||
|
||||
/** 请求头中 ACCESS_TOKEN 的参数名 */
|
||||
String ACCESS_TOKEN = "AccessToken";
|
||||
|
||||
/** 请求头中 Jwt_Token 的参数名 */
|
||||
String JWT_TOKEN = "JwtToken";
|
||||
|
||||
/** 请求头中 Bearer 的参数名 */
|
||||
String BEARER = "Bearer";
|
||||
|
||||
/** 请求头中 Authorization 的参数名 */
|
||||
String AUTH = "Authorization";
|
||||
|
||||
/** 幂等请求token */
|
||||
String IDEMPOTENT_TOKEN = "IdempotentToken";
|
||||
|
||||
/** 请求头 tid 的参数名 */
|
||||
String TID = "Tid";
|
||||
|
||||
/** 请求头 channelId 的参数名 */
|
||||
String CHANNEL_ID = "ChannelId";
|
||||
|
||||
/** 请求头中 appId 的参数名 */
|
||||
String APP_ID = "AppId";
|
||||
|
||||
/** 请求头中 appName 的参数名 */
|
||||
String APP_NAME = "AppName";
|
||||
|
||||
/** 请求头中 timezone 的参数名 */
|
||||
String TIMEZONE_NAME = "Timezone";
|
||||
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
package cn.bootx.platform.core.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户信息类
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/7/30
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
public class UserDetail {
|
||||
|
||||
/** 用户id */
|
||||
private Long id;
|
||||
|
||||
/** 用户名称 */
|
||||
private String name;
|
||||
|
||||
/** 账号 */
|
||||
private String account;
|
||||
|
||||
/** 不进行持久化 */
|
||||
@JsonIgnore
|
||||
private transient String password;
|
||||
|
||||
/** 是否管理员 */
|
||||
private boolean admin;
|
||||
|
||||
/**
|
||||
* 账号状态
|
||||
* @see cn.bootx.platform.iam.code.UserStatusCode
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 扩展信息
|
||||
*/
|
||||
private Map<String,String> ext;
|
||||
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package cn.bootx.platform.core.exception;
|
||||
|
||||
/**
|
||||
* 致命异常
|
||||
* @author xxm
|
||||
* @since 2024/7/14
|
||||
*/
|
||||
public class BizErrorException extends BizException {
|
||||
public BizErrorException(int code, String message) {
|
||||
super(code,message);
|
||||
}
|
||||
|
||||
public BizErrorException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package cn.bootx.platform.core.exception;
|
||||
|
||||
import cn.bootx.platform.core.code.CommonCode;
|
||||
import lombok.Getter;
|
||||
|
||||
|
||||
/**
|
||||
* 业务异常基类
|
||||
* @see BizErrorException 致命异常 error级别警告
|
||||
* @see BizWarnException 业务异常 warn级别
|
||||
* @see BizInfoException 哦月异常 info级别
|
||||
*/
|
||||
@Getter
|
||||
public class BizException extends RuntimeException {
|
||||
|
||||
private int code = CommonCode.FAIL_CODE;
|
||||
|
||||
public BizException(int code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public BizException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public BizException() {
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package cn.bootx.platform.core.exception;
|
||||
|
||||
/**
|
||||
* 普通异常, 不需要显示异常栈
|
||||
* @author xxm
|
||||
* @since 2024/7/14
|
||||
*/
|
||||
public class BizInfoException extends BizException{
|
||||
public BizInfoException(int code, String message) {
|
||||
super(code,message);
|
||||
}
|
||||
|
||||
public BizInfoException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package cn.bootx.platform.core.exception;
|
||||
|
||||
/**
|
||||
* 警告异常
|
||||
* @author xxm
|
||||
* @since 2024/7/14
|
||||
*/
|
||||
public class BizWarnException extends BizException{
|
||||
|
||||
public BizWarnException(int code, String message) {
|
||||
super(code,message);
|
||||
}
|
||||
|
||||
public BizWarnException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package cn.bootx.platform.core.exception;
|
||||
|
||||
|
||||
import cn.bootx.platform.core.code.CommonErrorCode;
|
||||
|
||||
/**
|
||||
* SQL相关异常
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2023/3/9
|
||||
*/
|
||||
public class DangerSqlException extends BizException {
|
||||
|
||||
public DangerSqlException(String msg) {
|
||||
super(CommonErrorCode.DANGER_SQL, msg);
|
||||
}
|
||||
|
||||
public DangerSqlException() {
|
||||
super(CommonErrorCode.DANGER_SQL, "危险SQL异常");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package cn.bootx.platform.core.exception;
|
||||
|
||||
|
||||
import cn.bootx.platform.core.code.CommonErrorCode;
|
||||
|
||||
/**
|
||||
* 数据不存在异常
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/1/10
|
||||
*/
|
||||
public class DataNotExistException extends BizInfoException {
|
||||
|
||||
public DataNotExistException(String msg) {
|
||||
super(CommonErrorCode.DATA_NOT_EXIST, msg);
|
||||
}
|
||||
|
||||
public DataNotExistException() {
|
||||
super(CommonErrorCode.DATA_NOT_EXIST, "数据不存在");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package cn.bootx.platform.core.exception;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import static cn.bootx.platform.core.code.CommonErrorCode.REPETITIVE_OPERATION_ERROR;
|
||||
|
||||
|
||||
/**
|
||||
* 重复操作异常
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/1/2
|
||||
*/
|
||||
public class RepetitiveOperationException extends BizInfoException implements Serializable {
|
||||
|
||||
public RepetitiveOperationException() {
|
||||
super(REPETITIVE_OPERATION_ERROR, "重复操作异常");
|
||||
}
|
||||
|
||||
public RepetitiveOperationException(String msg) {
|
||||
super(REPETITIVE_OPERATION_ERROR, msg);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package cn.bootx.platform.core.exception;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import static cn.bootx.platform.core.code.CommonErrorCode.UN_SUPPORTED_OPERATE;
|
||||
|
||||
/**
|
||||
* 不支持的操作异常
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/7/27
|
||||
*/
|
||||
public class UnSupportOperateException extends BizInfoException implements Serializable {
|
||||
|
||||
public UnSupportOperateException(String message) {
|
||||
super(UN_SUPPORTED_OPERATE, message);
|
||||
}
|
||||
|
||||
public UnSupportOperateException() {
|
||||
super(UN_SUPPORTED_OPERATE, "不支持的操作异常");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package cn.bootx.platform.core.exception;
|
||||
|
||||
import cn.bootx.platform.core.code.CommonErrorCode;
|
||||
|
||||
/**
|
||||
* 验证失败异常
|
||||
*/
|
||||
public class ValidationFailedException extends BizInfoException {
|
||||
|
||||
public ValidationFailedException(String detail) {
|
||||
super(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "验证参数错误" + System.lineSeparator() + detail);
|
||||
}
|
||||
|
||||
public ValidationFailedException() {
|
||||
super(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,"验证参数错误");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
package cn.bootx.platform.core.rest;
|
||||
|
||||
import cn.bootx.platform.core.rest.result.ErrorResult;
|
||||
import cn.bootx.platform.core.rest.result.Result;
|
||||
|
||||
import static cn.bootx.platform.core.code.CommonCode.FAIL_CODE;
|
||||
import static cn.bootx.platform.core.code.CommonCode.SUCCESS_CODE;
|
||||
|
||||
/**
|
||||
* 返回工具类
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2020/1/22 15:29
|
||||
*/
|
||||
public class Res {
|
||||
|
||||
private final static String SUCCESS = "success";
|
||||
|
||||
private final static String FAILED = "failed";
|
||||
|
||||
public static <T> Result<T> ok() {
|
||||
return new Result<>(SUCCESS_CODE, SUCCESS);
|
||||
}
|
||||
|
||||
public static <T> Result<T> okAndMsg(String message) {
|
||||
return new Result<>(SUCCESS_CODE, message);
|
||||
}
|
||||
|
||||
public static <T> Result<T> ok(T data) {
|
||||
return new Result<>(SUCCESS_CODE, data, SUCCESS);
|
||||
}
|
||||
|
||||
public static <T> Result<T> error() {
|
||||
return new Result<>(FAIL_CODE, FAILED);
|
||||
}
|
||||
|
||||
public static <T> Result<T> error(String message) {
|
||||
return new Result<>(FAIL_CODE, message);
|
||||
}
|
||||
|
||||
public static <T> Result<T> response(int code, String msg) {
|
||||
return new Result<>(code, msg);
|
||||
}
|
||||
|
||||
public static <T> Result<T> response(int code, String msg, String traceId) {
|
||||
return new ErrorResult<>(code, msg, traceId);
|
||||
}
|
||||
|
||||
public static <T> Result<T> response(int code, String msg, T data) {
|
||||
return new Result<>(code, data, msg);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package cn.bootx.platform.core.rest.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
/**
|
||||
* kv键值对象
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/5/18
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "kv键值对象")
|
||||
public class KeyValue {
|
||||
|
||||
@Schema(description = "键")
|
||||
private String key;
|
||||
|
||||
@Schema(description = "值")
|
||||
private String value;
|
||||
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
package cn.bootx.platform.core.rest.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* LabelValue
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/5/4
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "LabelValue键值对象")
|
||||
public class LabelValue {
|
||||
|
||||
@Schema(description = "label")
|
||||
private String label;
|
||||
|
||||
@Schema(description = "值")
|
||||
private String value;
|
||||
|
||||
public LabelValue(String label, Number value) {
|
||||
this.label = label;
|
||||
this.value = String.valueOf(value);
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package cn.bootx.platform.core.rest.param;
|
||||
|
||||
import cn.hutool.core.util.PageUtil;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 分页查询参数
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Schema(title = "分页查询参数")
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PageParam {
|
||||
|
||||
/**
|
||||
* 当前页
|
||||
*/
|
||||
@Schema(description = "当前页", defaultValue = "1")
|
||||
private int current = 1;
|
||||
|
||||
/**
|
||||
* 每页显示条数,默认 10
|
||||
*/
|
||||
@Schema(description = "每页显示条数,默认 10", defaultValue = "10")
|
||||
private int size = 10;
|
||||
|
||||
/**
|
||||
* 开始条数
|
||||
*/
|
||||
public int start() {
|
||||
// hutool 的下标从0开始
|
||||
return PageUtil.transToStartEnd(current - 1, size)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束条数
|
||||
*/
|
||||
public int end() {
|
||||
// hutool 的下标从0开始
|
||||
return PageUtil.transToStartEnd(current - 1, size)[1];
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package cn.bootx.platform.core.rest.result;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 错误响应类,携带链路追踪标示 trackId
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/9/9
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Schema(title = "错误响应类,携带链路追踪标示 trackId")
|
||||
public class ErrorResult<T> extends Result<T> {
|
||||
|
||||
/** 链路追踪标示 */
|
||||
@Schema(description = "链路追踪标示")
|
||||
private String traceId;
|
||||
|
||||
public ErrorResult(int code, String msg, String traceId) {
|
||||
super(code, msg);
|
||||
this.traceId = traceId;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
package cn.bootx.platform.core.rest.result;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页包装类
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2020/4/21 14:37
|
||||
*/
|
||||
@Getter
|
||||
public class PageResult<T> {
|
||||
/**
|
||||
* 查询数据列表
|
||||
*/
|
||||
private List<T> records = Collections.emptyList();
|
||||
|
||||
/**
|
||||
* 总数
|
||||
*/
|
||||
private long total = 0;
|
||||
|
||||
/**
|
||||
* 每页显示条数,默认 10
|
||||
*/
|
||||
private long size = 10;
|
||||
|
||||
/**
|
||||
* 当前页
|
||||
*/
|
||||
private long current = 1;
|
||||
|
||||
public PageResult<T> setRecords(List<T> records) {
|
||||
this.records = records;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PageResult<T> setTotal(long total) {
|
||||
this.total = total;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PageResult<T> setSize(long size) {
|
||||
this.size = size;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PageResult<T> setCurrent(long current) {
|
||||
this.current = current;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
package cn.bootx.platform.core.rest.result;
|
||||
|
||||
import cn.bootx.platform.core.code.CommonCode;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 响应包装类
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2020/1/22 15:26
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class Result<T> {
|
||||
|
||||
@Schema(description = "响应提示")
|
||||
private String msg = "success";
|
||||
|
||||
@Schema(description = "响应码")
|
||||
private int code = CommonCode.SUCCESS_CODE;
|
||||
|
||||
@Schema(description = "响应数据")
|
||||
private T data;
|
||||
|
||||
public Result() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Result(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Result(int code, T data) {
|
||||
this(code);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Result(int code, String msg) {
|
||||
this(code);
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public Result(int code, T data, String msg) {
|
||||
this(code, msg);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package cn.bootx.platform.core.result;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 基础返回类
|
||||
* @author xxm
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class BaseResult {
|
||||
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
package cn.bootx.platform.core.util;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* BigDecimal相关的工具类
|
||||
*
|
||||
* @author network
|
||||
*/
|
||||
@UtilityClass
|
||||
public class BigDecimalUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 比较大小
|
||||
* @param first 数字1
|
||||
* @param last 数字2
|
||||
* @return first > last =1 / first == last = 0 / first < last = -1
|
||||
*/
|
||||
public int compareTo(BigDecimal first, BigDecimal last) {
|
||||
BigDecimal newFirst = BigDecimal.ZERO;
|
||||
BigDecimal newLast = BigDecimal.ZERO;
|
||||
if (first != null) {
|
||||
newFirst = first;
|
||||
}
|
||||
if (last != null) {
|
||||
newLast = last;
|
||||
}
|
||||
return newFirst.compareTo(newLast);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否大于
|
||||
*/
|
||||
public boolean isGreaterThan(BigDecimal first, BigDecimal last) {
|
||||
return compareTo(first, last) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否大于或等于
|
||||
*/
|
||||
public boolean isGreaterAndEqualThan(BigDecimal first, BigDecimal last) {
|
||||
return compareTo(first, last) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否小于
|
||||
*/
|
||||
public boolean isLessThan(BigDecimal first, BigDecimal last) {
|
||||
return compareTo(first, last) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否等于
|
||||
*/
|
||||
public boolean isEqual(BigDecimal first, BigDecimal last) {
|
||||
return compareTo(first, last) == 0;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
package cn.bootx.platform.core.util;
|
||||
|
||||
import cn.hutool.core.codec.Base64Encoder;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
|
||||
/**
|
||||
* 证书工具类
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/2/24
|
||||
*/
|
||||
@UtilityClass
|
||||
public class CertUtil {
|
||||
|
||||
/**
|
||||
* 根据证书文本获取证书
|
||||
* @param certContent 证书字符串
|
||||
*/
|
||||
@SneakyThrows
|
||||
public String getCertByContent(String certContent) {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
Certificate cert = cf.generateCertificate(new ByteArrayInputStream(certContent.getBytes(StandardCharsets.UTF_8)));
|
||||
PublicKey publicKey = cert.getPublicKey();
|
||||
return Base64Encoder.encode(publicKey.getEncoded());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
package cn.bootx.platform.core.util;
|
||||
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 类工具类
|
||||
* @author xxm
|
||||
* @since 2023/5/30
|
||||
*/
|
||||
@UtilityClass
|
||||
public class ClassUtils {
|
||||
|
||||
/**
|
||||
* 获取字段属性
|
||||
*/
|
||||
public Field getField(Class<?> clas, String fieldName){
|
||||
if (Objects.isNull(clas)){
|
||||
throw new IllegalArgumentException("类为空");
|
||||
}
|
||||
// 查询是否有该属性
|
||||
Field field = ClassUtil.getDeclaredField(clas, fieldName);
|
||||
if (Objects.nonNull(field)){
|
||||
return field;
|
||||
}
|
||||
// 递归查询父类中的字段值
|
||||
if (Objects.nonNull(clas.getSuperclass())){
|
||||
return getField(clas.getSuperclass(),fieldName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归扫描父类的fields
|
||||
* @param clas 类
|
||||
* @param fields 属性
|
||||
*/
|
||||
public Field[] recursionParents(Class<?> clas, Field[] fields) {
|
||||
if (Objects.nonNull(clas.getSuperclass())) {
|
||||
Class<?> clsSup = clas.getSuperclass();
|
||||
List<Field> fieldList = new ArrayList<>(List.of(fields));
|
||||
// 获取当前class的所有fields的name列表
|
||||
List<String> fdNames = fieldList.stream().map(Field::getName).toList();
|
||||
for (Field pfd : clsSup.getDeclaredFields()) {
|
||||
// 避免重载属性
|
||||
if (fdNames.contains(pfd.getName())) {
|
||||
continue;
|
||||
}
|
||||
fieldList.add(pfd);
|
||||
}
|
||||
fields = new Field[fieldList.size()];
|
||||
int i = 0;
|
||||
for (Object field : fieldList.toArray()) {
|
||||
fields[i] = (Field) field;
|
||||
i++;
|
||||
}
|
||||
fields = recursionParents(clsSup, fields);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
}
|
@@ -0,0 +1,85 @@
|
||||
package cn.bootx.platform.core.util;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
|
||||
/**
|
||||
* java8 时间工具类
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2020/11/10
|
||||
*/
|
||||
@UtilityClass
|
||||
public class DateTimeUtil {
|
||||
|
||||
/**
|
||||
* 大于
|
||||
*/
|
||||
public boolean gt(LocalDateTime now, LocalDateTime next) {
|
||||
long mills = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
long epochMilli = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
return mills > epochMilli;
|
||||
}
|
||||
|
||||
/**
|
||||
* 小于
|
||||
*/
|
||||
public boolean lt(LocalDateTime now, LocalDateTime next) {
|
||||
long mills = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
long epochMilli = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
return mills < epochMilli;
|
||||
}
|
||||
|
||||
/**
|
||||
* 大于等于
|
||||
*/
|
||||
public boolean ge(LocalDateTime now, LocalDateTime next) {
|
||||
long mills = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
long epochMilli = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
return mills >= epochMilli;
|
||||
}
|
||||
|
||||
/**
|
||||
* 小于等于
|
||||
*/
|
||||
public boolean le(LocalDateTime now, LocalDateTime next) {
|
||||
long mills = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
long epochMilli = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
return mills <= epochMilli;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将localDate转换成localDateTime
|
||||
*/
|
||||
public LocalDateTime date2DateTime(LocalDate localDate) {
|
||||
return localDate.atTime(0, 0);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 将long类型的timestamp转为LocalDateTime
|
||||
* @param timestamp 时间戳
|
||||
* @return LocalDateTime
|
||||
*/
|
||||
public LocalDateTime parse(long timestamp) {
|
||||
Instant instant = Instant.ofEpochMilli(timestamp);
|
||||
ZoneId zone = ZoneId.systemDefault();
|
||||
return LocalDateTime.ofInstant(instant, zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* LocalDateTime转为long类型的timestamp
|
||||
* @param localDateTime 日期时间
|
||||
* @return timestamp
|
||||
*/
|
||||
public long timestamp(LocalDateTime localDateTime) {
|
||||
ZoneId zone = ZoneId.systemDefault();
|
||||
Instant instant = localDateTime.atZone(zone).toInstant();
|
||||
return instant.toEpochMilli();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
package cn.bootx.platform.core.util;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.json.JSON;
|
||||
import cn.hutool.json.JSONConfig;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
/**
|
||||
* json工具类, 基于hutool的进行封装, 对java8的LocalDateTime时间格式进行转换, 但无法处理LocalDate, LocalTime格式, 需要使用JacksonUtil进行处理
|
||||
* @author xxm
|
||||
* @since 2024/6/28
|
||||
*/
|
||||
@UtilityClass
|
||||
public class JsonUtil {
|
||||
private final JSONConfig JSON_CONFIG = JSONConfig.create().setDateFormat(DatePattern.NORM_DATETIME_PATTERN);
|
||||
|
||||
/**
|
||||
* 转换为实体
|
||||
*/
|
||||
public <T> T toBean(String json, Class<T> clazz){
|
||||
JSONObject jsonObject = new JSONObject(json, JSON_CONFIG);
|
||||
return JSONUtil.toBean(jsonObject, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为实体
|
||||
*/
|
||||
public <T> T toBean(String json, TypeReference<T> reference){
|
||||
JSON parse = JSONUtil.parse(json, JSON_CONFIG);
|
||||
return parse.toBean(reference);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为实体
|
||||
*/
|
||||
public <T> T toBean(String json, TypeReference<T> reference, boolean ignoreError){
|
||||
JSONConfig jsonConfig = JSONConfig.create()
|
||||
.setDateFormat(DatePattern.NORM_DATETIME_PATTERN)
|
||||
.setIgnoreError(ignoreError);
|
||||
JSON parse = JSONUtil.parse(json, jsonConfig);
|
||||
return parse.toBean(reference);
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化为字符串
|
||||
*/
|
||||
public String toJsonStr(Object object){
|
||||
JSONObject jsonObject = new JSONObject(object, JSON_CONFIG);
|
||||
return JSONUtil.toJsonStr(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON字符串转JSONObject对象
|
||||
*/
|
||||
public JSONObject parseObj(String jsonStr){
|
||||
return JSONUtil.parseObj(jsonStr, JSON_CONFIG);
|
||||
}
|
||||
}
|
@@ -0,0 +1,137 @@
|
||||
package cn.bootx.platform.core.util;
|
||||
|
||||
import cn.bootx.platform.core.exception.DangerSqlException;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* sql注入处理工具类 参考自 Jeecg Boot
|
||||
*
|
||||
* @author zhoujf
|
||||
*/
|
||||
@Slf4j
|
||||
@UtilityClass
|
||||
public class SqlInjectionUtil {
|
||||
|
||||
private final String XSS_STR = "and |extractvalue|updatexml|geohash|gtid_subset|gtid_subtract|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+|user()";
|
||||
|
||||
/**
|
||||
* 正则 user() 匹配更严谨
|
||||
*/
|
||||
private final String REGULAR_EXPRE_USER = "user[\\s]*\\([\\s]*\\)";
|
||||
|
||||
/** 正则 show tables */
|
||||
private final String SHOW_TABLES = "show\\s+tables";
|
||||
|
||||
/**
|
||||
* sql注释的正则
|
||||
*/
|
||||
private final Pattern SQL_ANNOTATION = Pattern.compile("/\\*[\\s\\S]*\\*/");
|
||||
|
||||
/**
|
||||
* sql注入过滤处理,遇到注入关键字抛异常
|
||||
*/
|
||||
public void filterContent(String value) {
|
||||
filterContent(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* sql注入过滤处理,遇到注入关键字抛异常
|
||||
*
|
||||
*/
|
||||
public void filterContent(String value, String customXssString) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// 校验sql注释 不允许有sql注释
|
||||
checkSqlAnnotation(value);
|
||||
// 统一转为小写
|
||||
value = value.toLowerCase();
|
||||
// SQL注入检测存在绕过风险
|
||||
String[] xssArr = XSS_STR.split("\\|");
|
||||
for (String s : xssArr) {
|
||||
if (value.contains(s)) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", s);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
throw new DangerSqlException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
// 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||
if (customXssString != null) {
|
||||
String[] xssArr2 = customXssString.split("\\|");
|
||||
for (String s : xssArr2) {
|
||||
if (value.contains(s)) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", s);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
throw new DangerSqlException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||
if (Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)) {
|
||||
throw new DangerSqlException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sql注入过滤处理,遇到注入关键字抛异常
|
||||
*/
|
||||
public void filterContent(String[] values) {
|
||||
filterContent(values, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* sql注入过滤处理,遇到注入关键字抛异常
|
||||
*/
|
||||
public void filterContent(String[] values, String customXssString) {
|
||||
String[] xssArr = XSS_STR.split("\\|");
|
||||
for (String value : values) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// 校验sql注释 不允许有sql注释
|
||||
checkSqlAnnotation(value);
|
||||
// 统一转为小写
|
||||
value = value.toLowerCase();
|
||||
|
||||
for (String s : xssArr) {
|
||||
if (value.contains(s)) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", s);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
throw new DangerSqlException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
// 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||
if (customXssString != null) {
|
||||
String[] xssArr2 = customXssString.split("\\|");
|
||||
for (String s : xssArr2) {
|
||||
if (value.contains(s)) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", s);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
throw new DangerSqlException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||
if (Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)) {
|
||||
throw new DangerSqlException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验是否有sql注释
|
||||
*/
|
||||
public void checkSqlAnnotation(String str) {
|
||||
Matcher matcher = SQL_ANNOTATION.matcher(str);
|
||||
if (matcher.find()) {
|
||||
String error = "请注意,值可能存在SQL注入风险---> \\*.*\\";
|
||||
log.error(error);
|
||||
throw new DangerSqlException(error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
package cn.bootx.platform.core.util;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 构建数据树工具类
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/12/24
|
||||
*/
|
||||
@UtilityClass
|
||||
public class TreeBuildUtil {
|
||||
|
||||
/**
|
||||
* 构建成树
|
||||
* @param list 要进行转换的列表
|
||||
* @param pid 一级节点的父级id,通常为null
|
||||
* @param getId 获取主键的方法方法引用
|
||||
* @param getPid 获取关联父级节点主键的方法引用
|
||||
* @param setChildren 设置子节点列表的方法引用
|
||||
*/
|
||||
public <T> List<T> build(List<T> list, Object pid, Function<T, Object> getId, Function<T, Object> getPid,
|
||||
BiConsumer<T, List<T>> setChildren) {
|
||||
return build(list, pid, getId, getPid, setChildren, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建成树 (带排序)
|
||||
* @param list 要进行转换的列表
|
||||
* @param pid 一级节点的父级id,通常为null
|
||||
* @param getId 获取主键的方法方法引用
|
||||
* @param getPid 获取关联父级节点主键的方法引用
|
||||
* @param setChildren 设置子节点列表的方法引用
|
||||
* @param comparator 节点顺序的排序规则
|
||||
*/
|
||||
public <T> List<T> build(List<T> list, Object pid, Function<T, Object> getId, Function<T, Object> getPid,
|
||||
BiConsumer<T, List<T>> setChildren, Comparator<? super T> comparator) {
|
||||
List<T> children = list.stream().filter(m -> Objects.equals(getPid.apply(m), pid)).collect(Collectors.toList());
|
||||
if (CollectionUtil.isEmpty(children)) {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
for (T region : children) {
|
||||
List<T> childrenList = build(list, getId.apply(region), getId, getPid, setChildren,comparator);
|
||||
setChildren.accept(region, childrenList);
|
||||
}
|
||||
// 排序
|
||||
if (Objects.nonNull(comparator)) {
|
||||
children.sort(comparator);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* 展开树为list列表
|
||||
*
|
||||
* @param list 要进行展开的列表
|
||||
* @param getChildren 获取子节点列表的方法引用
|
||||
* @return 展开后的结果列表
|
||||
*/
|
||||
public <T> List<T> unfold(List<T> list, Function<T, List<T>> getChildren){
|
||||
return unfold(list,getChildren, new ArrayList<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 展开树为list列表
|
||||
*
|
||||
* @param list 要进行展开的列表
|
||||
* @param getChildren 获取子节点列表的方法引用
|
||||
* @param result 用于存储展开后的列表对象
|
||||
* @return 展开后的结果列表
|
||||
*/
|
||||
private <T> List<T> unfold(List<T> list, Function<T, List<T>> getChildren, List<T> result){
|
||||
if (CollectionUtil.isEmpty(list)) {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
for (T region : list) {
|
||||
unfold(getChildren.apply(region), getChildren, result);
|
||||
result.add(region);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
package cn.bootx.platform.core.util;
|
||||
|
||||
import cn.bootx.platform.core.exception.ValidationFailedException;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.Validation;
|
||||
import jakarta.validation.Validator;
|
||||
import jakarta.validation.ValidatorFactory;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* BeanValidation 校验工具类
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2020/5/26 18:14
|
||||
*/
|
||||
@UtilityClass
|
||||
public class ValidationUtil {
|
||||
|
||||
private static final ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
|
||||
|
||||
/**
|
||||
* 验证参数对象,如果验证失败则抛出异常
|
||||
*/
|
||||
public void validateParam(Object paramObject, Class<?>... groups) {
|
||||
Validator validator = validatorFactory.getValidator();
|
||||
Set<ConstraintViolation<Object>> violations = validator.validate(paramObject, groups);
|
||||
if (!violations.isEmpty()) {
|
||||
throw new ValidationFailedException(extractMessages(violations));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证参数对象,如果验证失败则返回所有失败信息
|
||||
*/
|
||||
public String validate(Object paramObject, Class<?>... groups) {
|
||||
Validator validator = validatorFactory.getValidator();
|
||||
Set<ConstraintViolation<Object>> violations = validator.validate(paramObject, groups);
|
||||
return extractMessages(violations);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取校验失败的消息
|
||||
*/
|
||||
private String extractMessages(Set<ConstraintViolation<Object>> violations) {
|
||||
StringBuilder message = new StringBuilder();
|
||||
for (ConstraintViolation<Object> violation : violations) {
|
||||
message.append(violation.getMessage()).append(System.lineSeparator());
|
||||
}
|
||||
return message.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package cn.bootx.platform.core.validation;
|
||||
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/6/11
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
// 标记由哪个类来执行校验逻辑,该类需要实现ConstraintValidator接口
|
||||
@Constraint(validatedBy = IpAddressValidator.class)
|
||||
public @interface IpAddress {
|
||||
|
||||
String message() default "IP地址不合法!";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package cn.bootx.platform.core.validation;
|
||||
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
/**
|
||||
* ip地址校验器
|
||||
* @author xxm
|
||||
* @since 2024/6/11
|
||||
*/
|
||||
public class IpAddressValidator implements ConstraintValidator<IpAddress, String> {
|
||||
|
||||
/**
|
||||
* 校验是否为IP地址。成功返回true,失败返回false
|
||||
*/
|
||||
@Override
|
||||
public boolean isValid(String str, ConstraintValidatorContext constraintValidatorContext) {
|
||||
if (StrUtil.isNotBlank(str)){
|
||||
return Validator.isIpv4(str) || Validator.isIpv6(str);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package cn.bootx.platform.core.validation;
|
||||
|
||||
/**
|
||||
* 校验分组
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/5/7
|
||||
*/
|
||||
public interface ValidationGroup {
|
||||
|
||||
/**
|
||||
* 参数校验分组:增加
|
||||
*/
|
||||
@interface add {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数校验分组:编辑
|
||||
*/
|
||||
@interface edit {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数校验分组:删除
|
||||
*/
|
||||
@interface delete {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数校验分组:查询
|
||||
*/
|
||||
@interface query {
|
||||
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user