修改 common 模块名.

This commit is contained in:
lijiahang
2023-10-09 17:35:36 +08:00
parent 890afa093c
commit 8f626d278c
58 changed files with 70 additions and 21 deletions

View File

@@ -0,0 +1,90 @@
<?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>com.orion.ops</groupId>
<artifactId>orion-ops-framework</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>orion-ops-framework-common</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<description>项目公共基准包</description>
<url>https://github.com/lijiahangmax/orion-ops-pro</url>
<dependencies>
<dependency>
<groupId>io.github.lijiahangmax</groupId>
<artifactId>orion-all</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- aspectj -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!-- mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
</dependency>
<!-- transmittable -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
</dependency>
<!-- validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- configuration -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>provided</scope>
</dependency>
<!-- security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- doc -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,26 @@
package com.orion.ops.framework.common.annotation;
import com.orion.ops.framework.common.constant.IgnoreLogMode;
import java.lang.annotation.*;
/**
* 不执行统一日志打印
*
* @author Jiahang Li
* @version 1.0.0
* @since 2022/4/20 10:33
*/
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreLog {
/**
* 日志忽略模式
*
* @return 日志忽略模式
*/
IgnoreLogMode value() default IgnoreLogMode.ALL;
}

View File

@@ -0,0 +1,16 @@
package com.orion.ops.framework.common.annotation;
import java.lang.annotation.*;
/**
* 无需包装返回
*
* @author Jiahang Li
* @version 1.0.0
* @since 2021/4/2 10:36
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreWrapper {
}

View File

@@ -0,0 +1,19 @@
package com.orion.ops.framework.common.annotation;
import java.lang.annotation.*;
/**
* 统一返回包装
*
* @author Jiahang Li
* @version 1.0.0
* @see Void#TYPE
* @see IgnoreWrapper
* @since 2021/4/2 12:34
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RestWrapper {
}

View File

@@ -0,0 +1,44 @@
package com.orion.ops.framework.common.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 线程池配置类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/10 15:49
*/
@Data
@ConfigurationProperties(prefix = "orion.async.executor")
public class AsyncExecutorConfig {
/**
* 核心线程数量
*/
private int corePoolSize;
/**
* 最大线程数量
*/
private int maxPoolSize;
/**
* 队列容量
*/
private int queueCapacity;
/**
* 活跃时间
*/
private int keepAliveSeconds;
public AsyncExecutorConfig() {
this.corePoolSize = 8;
this.maxPoolSize = 16;
this.queueCapacity = 200;
this.keepAliveSeconds = 300;
}
}

View File

@@ -0,0 +1,64 @@
package com.orion.ops.framework.common.config;
import com.orion.ops.framework.common.constant.AutoConfigureOrderConst;
import com.orion.ops.framework.common.thread.ThreadPoolMdcTaskExecutor;
import com.orion.spring.SpringHolder;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 应用配置类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/20 10:34
*/
@EnableAsync
@AutoConfiguration
@AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_COMMON)
@EnableConfigurationProperties(AsyncExecutorConfig.class)
public class OrionCommonAutoConfiguration {
/**
* @return spring 容器工具类
*/
@Bean
public SpringHolder.ApplicationContextAwareStore springHolderAware() {
return new SpringHolder.ApplicationContextAwareStore();
}
/**
* 支持 MDC 的异步线程池
* <p>
* {@code @Async("asyncExecutor")}
*
* @return 异步线程池
*/
@Primary
@Bean(name = "asyncExecutor")
public TaskExecutor asyncExecutor(AsyncExecutorConfig config) {
ThreadPoolMdcTaskExecutor executor = new ThreadPoolMdcTaskExecutor();
executor.setCorePoolSize(config.getCorePoolSize());
executor.setMaxPoolSize(config.getMaxPoolSize());
executor.setQueueCapacity(config.getQueueCapacity());
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
executor.setAllowCoreThreadTimeOut(true);
executor.setThreadNamePrefix("async-task-");
// 设置等待所有任务执行结束再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 以确保应用最后能够被关闭
executor.setAwaitTerminationSeconds(60);
// 调用者调用拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}

View File

@@ -0,0 +1,46 @@
package com.orion.ops.framework.common.constant;
/**
* 自动装配排序常量
* <p>
* 实际遵循 DependsOn
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/11 17:55
*/
public interface AutoConfigureOrderConst {
int FRAMEWORK_COMMON = Integer.MIN_VALUE + 1000;
int FRAMEWORK_WEB = Integer.MIN_VALUE + 1100;
int FRAMEWORK_SECURITY = Integer.MIN_VALUE + 1200;
int FRAMEWORK_SECURITY_CRYPTO = Integer.MIN_VALUE + 1250;
int FRAMEWORK_WEBSOCKET = Integer.MIN_VALUE + 1300;
int FRAMEWORK_DESENSITIZE = Integer.MIN_VALUE + 1400;
int FRAMEWORK_LOG = Integer.MIN_VALUE + 1500;
int FRAMEWORK_JOB = Integer.MIN_VALUE + 1600;
int FRAMEWORK_SWAGGER = Integer.MIN_VALUE + 1700;
int FRAMEWORK_DATASOURCE = Integer.MIN_VALUE + 1800;
int FRAMEWORK_MYBATIS = Integer.MIN_VALUE + 1900;
int FRAMEWORK_REDIS = Integer.MIN_VALUE + 2000;
int FRAMEWORK_REDIS_CACHE = Integer.MIN_VALUE + 2050;
int FRAMEWORK_STORAGE = Integer.MIN_VALUE + 2100;
int FRAMEWORK_MONITOR = Integer.MIN_VALUE + 2200;
int FRAMEWORK_BANNER = Integer.MIN_VALUE + 2300;
}

View File

@@ -0,0 +1,35 @@
package com.orion.ops.framework.common.constant;
/**
* 常量
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/23 18:49
*/
public class Const implements com.orion.lang.constant.Const {
private Const() {
}
public static final Integer NOT_DELETE = 0;
public static final Integer IS_DELETED = 1;
public static final int BEARER_PREFIX_LEN = 7;
public static final int MD5_LEN = 32;
public static final String UNKNOWN = "未知";
public static final String INTRANET_IP = "内网IP";
public static final Long ROOT_MENU_ID = 0L;
public static final Integer DEFAULT_SORT = 10;
public static final Long NONE_ID = -1L;
public static final Integer DEFAULT_VERSION = 1;
}

View File

@@ -0,0 +1,164 @@
package com.orion.ops.framework.common.constant;
import com.orion.lang.define.wrapper.CodeInfo;
import com.orion.lang.define.wrapper.HttpWrapper;
import com.orion.lang.utils.Exceptions;
import com.orion.lang.utils.Strings;
/**
* 用于定义错误码
* <p>
* 1. http 通用 status
* 2. 前端需要特殊处理
* 3. @ExceptionHandler 全局异常
* 其他情况可以定义在 ExceprionMessage 中
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/6 16:14
*/
@SuppressWarnings("ALL")
public enum ErrorCode implements CodeInfo {
// -------------------- http message --------------------
BAD_REQUEST(400, "参数验证失败"),
UNAUTHORIZED(401, "当前认证信息已失效, 请重新登录"),
FORBIDDEN(403, "无操作权限"),
NOT_FOUND(404, "未找到该资源"),
METHOD_NOT_ALLOWED(405, "不支持此方法"),
REQUEST_TIMEOUT(408, "处理超时"),
CONFLICT(409, "数据状态发生改变, 请刷新后重试"),
PAYLOAD_TOO_LARGE(413, "请求过大"),
LOCKED(423, "当前已被锁定"),
TOO_MANY_REQUESTS(429, "请求过快"),
INTERNAL_SERVER_ERROR(500, "系统异常"),
// -------------------- 自定义 - 业务 --------------------
OTHER_DEVICE_LOGIN(700, "该账号于 {} 已在其他设备登陆 {}({})"),
USER_DISABLED(701, "当前用户已禁用"),
USER_LOCKED(702, "当前用户已被锁定"),
// -------------------- 自定义 - 通用 --------------------
NETWORK_FLUCTUATION(900, "当前环境网路波动"),
HTTP_API_REQUEST_ERROR(901, "api 调用异常"),
IO_EXCEPTION(902, "网络异常"),
SQL_EXCEPTION(903, "数据异常"),
SFTP_EXCEPTION(904, "操作失败"),
EXCEL_PASSWORD_ERROR(905, "文档密码错误"),
PASER_FAILED(906, "解析失败"),
ENCRYPT_ERROR(907, "数据加密异常"),
DECRYPT_ERROR(908, "数据解密异常"),
EXPRESSION_ERROR(909, "表达式错误"),
TASK_EXECUTE_ERROR(910, "任务执行异常"),
CONNECT_ERROR(911, "建立连接失败"),
INTERRUPT_ERROR(912, "操作中断"),
UNSAFE_OPERATOR(913, "不安全的操作"),
VCS_OPETATOR_ERROR(914, "仓库操作执行失败"),
DIABLED_ERROR(915, "数据已被禁用"),
UNSUPPOETED(916, "不支持此操作"),
;
ErrorCode(int code, String message) {
this.code = code;
this.message = message;
this.wrapper = HttpWrapper.of(this);
}
/**
* 错误码
*/
private final int code;
/**
* 错误信息
*/
private final String message;
private final HttpWrapper<?> wrapper;
/**
* 获取 wapper
*
* @param data data
* @return HttpWrapper
*/
public HttpWrapper<?> wrapper() {
return HttpWrapper.of(this);
}
/**
* 获取 wapper
*
* @param data data
* @param <T> T
* @return HttpWrapper
*/
public <T> HttpWrapper<T> wrapper(T data) {
return HttpWrapper.of(this, data);
}
@Override
public int code() {
return code;
}
@Override
public String message() {
return message;
}
/**
* @return 获取单例 wapper
*/
public HttpWrapper<?> getWrapper() {
return wrapper;
}
/**
* @return 获取异常
*/
public RuntimeException exception() {
return Exceptions.httpWrapper(this);
}
/**
* @param params 错误信息参数
* @return 获取异常
*/
public RuntimeException exception(Object... params) {
return Exceptions.httpWrapper(this.toHttpWrapper().msg(Strings.format(this.message, params)));
}
}

View File

@@ -0,0 +1,60 @@
package com.orion.ops.framework.common.constant;
/**
* 错误信息
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/7 18:51
*/
public interface ErrorMessage {
String MISSING = "{} 不能为空";
String PARAM_MISSING = "参数不能为空";
String ID_MISSING = "id 不能为空";
String INVALID_PARAM = "参数验证失败";
String DATA_MODIFIED = "数据发生变更, 请刷新后重试";
String DATA_ABSENT = "数据不存在";
String KEY_ABSENT = "主机秘钥不存在";
String IDENTITY_ABSENT = "主机身份不存在";
String CONFIG_ABSENT = "配置不存在";
String DATA_PRESENT = "数据已存在";
String NAME_PRESENT = "名称已存在";
String CODE_PRESENT = "编码已存在";
String NICKNAME_PRESENT = "花名已存在";
String USERNAME_PRESENT = "用户名已存在";
String ROLE_ABSENT = "角色不存在";
String ROLE_CODE_ABSENT = "角色 [{}] 不存在";
String INVALID_PARENT_MENU = "所选父菜单不合法";
String PARENT_MENU_ABSENT = "父菜单不存在";
String USERNAME_PASSWORD_ERROR = "用户名或密码错误";
String MAX_LOGIN_FAILED = "登陆失败次数已上限";
String USER_ABSENT = "用户不存在";
String UNABLE_OPERATE_ADMIN_ROLE = "无法操作管理员账号";
String UNSUPPORTED_CHARSET = "不支持的编码 [{}]";
String PASSWORD_MISSING = "请输入密码";
}

View File

@@ -0,0 +1,18 @@
package com.orion.ops.framework.common.constant;
/**
* 过滤器排序常量
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/16 17:04
*/
public interface FilterOrderConst {
int TRICE_ID_FILTER = Integer.MIN_VALUE + 1000;
int CORS_FILTER = Integer.MIN_VALUE + 2000;
int MYBATIS_CACHE_CLEAR_FILTER = Integer.MIN_VALUE + 100000;
}

View File

@@ -0,0 +1,34 @@
package com.orion.ops.framework.common.constant;
/**
* 日志忽略模式
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/21 9:54
*/
public enum IgnoreLogMode {
/**
* 不打印任何日志
*/
ALL,
/**
* 不打印参数
*/
ARGS,
/**
* 不打印返回值
*/
RET,
/**
* 不打印参数以及返回值
*/
ARGS_RET,
;
}

View File

@@ -0,0 +1,14 @@
package com.orion.ops.framework.common.constant;
/**
* 拦截器排序常量
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/16 18:15
*/
public interface InterceptorOrderConst {
int LOG_FILTER = Integer.MIN_VALUE;
}

View File

@@ -0,0 +1,23 @@
package com.orion.ops.framework.common.constant;
/**
* 项目常量
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/19 18:56
*/
public interface OrionOpsProConst {
/**
* 同 ${orion.version} 迭代时候需要手动更改
*/
String VERSION = "1.0.0";
String GITHUB = "https://github.com/lijiahangmax/orion-ops-pro";
String GITEE = "https://gitee.com/lijiahangmax/orion-ops-pro";
String ISSUES = "https://gitee.com/lijiahangmax/orion-ops-pro/issues";
}

View File

@@ -0,0 +1,14 @@
package com.orion.ops.framework.common.constant;
/**
* 结果增强器 排序常量
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/29 16:09
*/
public interface ResponseAdviceOrderConst {
int WRAPPER = Integer.MIN_VALUE + 1000;
}

View File

@@ -0,0 +1,40 @@
package com.orion.ops.framework.common.crypto;
import com.orion.lang.utils.codec.Base62s;
import com.orion.lang.utils.crypto.symmetric.SymmetricCrypto;
/**
* 数据加密器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/8 0:20
*/
public interface ValueCrypto extends SymmetricCrypto {
/**
* 初始化
*/
void init();
/**
* 加密后 base62 编码
*
* @param plain 明文
* @return 密文
*/
default String encryptBase62(String plain) {
return new String(Base62s.encode(this.encrypt(plain)));
}
/**
* base62 解码后解密
*
* @param text 密文
* @return 明文
*/
default String decryptBase62(String text) {
return new String(this.decrypt(Base62s.decode(text)));
}
}

View File

@@ -0,0 +1,27 @@
package com.orion.ops.framework.common.entity;
import com.orion.lang.define.wrapper.IPageRequest;
import com.orion.ops.framework.common.valid.group.Page;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
/**
* 公共页码请求
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/12 23:14
*/
@Data
public class PageRequest implements IPageRequest {
@Range(min = 1, max = 10000, groups = Page.class)
@Schema(description = "页码")
private int page;
@Range(min = 1, max = 100, groups = Page.class)
@Schema(description = "大小")
private int limit;
}

View File

@@ -0,0 +1,43 @@
package com.orion.ops.framework.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* boolean 枚举
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/19 10:32
*/
@Getter
@AllArgsConstructor
public enum BooleanBit {
/**
* 假
*/
FALSE(0),
/**
* 真
*/
TRUE(1),
;
private final Integer value;
public static BooleanBit of(Integer value) {
if (value == null) {
return null;
}
for (BooleanBit e : values()) {
if (e.value.equals(value)) {
return e;
}
}
return null;
}
}

View File

@@ -0,0 +1,105 @@
package com.orion.ops.framework.common.file;
import java.io.InputStream;
/**
* 文件客户端
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/30 16:51
*/
public interface FileClient {
/**
* 上传文件
*
* @param path 文件路径
* @param content 文件内容
* @return 路径
* @throws Exception Exception
*/
String upload(String path, byte[] content) throws Exception;
/**
* 上传文件
*
* @param path 文件路径
* @param content 文件内容
* @param overrideIfExist 文件存在是否覆盖
* @return 路径
* @throws Exception Exception
*/
String upload(String path, byte[] content, boolean overrideIfExist) throws Exception;
/**
* 上传文件
*
* @param path 文件路径
* @param in in
* @return 路径
* @throws Exception Exception
*/
String upload(String path, InputStream in) throws Exception;
/**
* 上传文件
*
* @param path 文件路径
* @param in in
* @param autoClose autoClose
* @return 路径
* @throws Exception Exception
*/
String upload(String path, InputStream in, boolean autoClose) throws Exception;
/**
* 上传文件
*
* @param path 文件路径
* @param in in
* @param autoClose autoClose
* @param overrideIfExist 文件存在是否覆盖
* @return 路径
* @throws Exception Exception
*/
String upload(String path, InputStream in, boolean autoClose, boolean overrideIfExist) throws Exception;
// TODO getOutputStream
/**
* 检查文件是否存在
*
* @param path path
* @return 是否存在
*/
boolean isExists(String path);
/**
* 删除文件
*
* @param path 路径
* @return 是否删除
* @throws Exception Exception
*/
boolean delete(String path) throws Exception;
/**
* 获取文件内容
*
* @param path path
* @return bytes
* @throws Exception Exception
*/
byte[] getContent(String path) throws Exception;
/**
* 获取文件输入流
*
* @param path path
* @return stream
* @throws Exception Exception
*/
InputStream getContentInputStream(String path) throws Exception;
}

View File

@@ -0,0 +1,33 @@
package com.orion.ops.framework.common.filter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import javax.servlet.Filter;
/**
* 过滤器构造器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/25 15:05
*/
public class FilterCreator {
private FilterCreator() {
}
/**
* 创建过滤器
*
* @param filter filter
* @param order order
* @param <T> type
* @return filter bean
*/
public static <T extends Filter> FilterRegistrationBean<T> create(T filter, Integer order) {
FilterRegistrationBean<T> bean = new FilterRegistrationBean<>(filter);
bean.setOrder(order);
return bean;
}
}

View File

@@ -0,0 +1,38 @@
package com.orion.ops.framework.common.meta;
import com.alibaba.ttl.TransmittableThreadLocal;
/**
* traceId 持有者
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/16 17:35
*/
public class TraceIdHolder {
public static final String TRACE_ID_HEADER = "trace-id";
public static final String TRACE_ID_MDC = "tid";
private TraceIdHolder() {
}
/**
* 请求序列
*/
private static final ThreadLocal<String> HOLDER = new TransmittableThreadLocal<>();
public static String get() {
return HOLDER.get();
}
public static void set(String traceId) {
HOLDER.set(traceId);
}
public static void remove() {
HOLDER.remove();
}
}

View File

@@ -0,0 +1,37 @@
package com.orion.ops.framework.common.security;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 当前登录用户
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/6 18:36
*/
@Data
@Schema(name = "LoginUser", description = "当前登录用户对象")
public class LoginUser {
@Schema(description = "id")
private Long id;
@Schema(description = "用户名")
private String username;
@Schema(description = "花名")
private String nickname;
@Schema(description = "用户状态")
private Integer status;
@Schema(description = "头像地址")
private String avatar;
@Schema(description = "角色")
private List<String> roles;
}

View File

@@ -0,0 +1,40 @@
package com.orion.ops.framework.common.security;
import com.orion.lang.utils.Booleans;
import com.orion.lang.utils.Strings;
import com.orion.ops.framework.common.constant.Const;
import com.orion.ops.framework.common.utils.CryptoUtils;
/**
* 密码修改器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/21 11:35
*/
public class PasswordModifier {
private PasswordModifier() {
}
/**
* 获取新密码
*
* @param action action
* @return password
*/
public static String getEncryptNewPassword(UpdatePasswordAction action) {
if (Booleans.isTrue(action.getUseNewPassword())) {
// 使用新密码
String password = action.getPassword();
if (Strings.isBlank(password)) {
return Const.EMPTY;
} else {
return CryptoUtils.encryptAsString(password);
}
} else {
return null;
}
}
}

View File

@@ -0,0 +1,26 @@
package com.orion.ops.framework.common.security;
/**
* SecurityUtils 的 bean 对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/7 15:20
*/
public interface SecurityHolder {
/**
* 获取当前用户
*
* @return 当前用户
*/
LoginUser getLoginUser();
/**
* 获取当前用户id
*
* @return id
*/
Long getLoginUserId();
}

View File

@@ -0,0 +1,28 @@
package com.orion.ops.framework.common.security;
import java.io.Serializable;
/**
* 更新密码操作
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/21 11:32
*/
public interface UpdatePasswordAction extends Serializable {
/**
* 是否使用新密码
*
* @return use
*/
Boolean getUseNewPassword();
/**
* 获取密码
*
* @return password
*/
String getPassword();
}

View File

@@ -0,0 +1,33 @@
package com.orion.ops.framework.common.thread;
import com.orion.ops.framework.common.utils.ThreadMdcUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
/**
* 自动注入 MDC 异步线程池
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/10 15:16
*/
public class ThreadPoolMdcTaskExecutor extends ThreadPoolTaskExecutor {
@Override
public void execute(Runnable task) {
super.execute(ThreadMdcUtils.wrap(task));
}
@Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(ThreadMdcUtils.wrap(task));
}
@Override
public Future<?> submit(Runnable task) {
return super.submit(ThreadMdcUtils.wrap(task));
}
}

View File

@@ -0,0 +1,46 @@
package com.orion.ops.framework.common.utils;
import com.orion.lang.constant.Const;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 工具类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/28 23:21
*/
public class ConfigUtils {
private ConfigUtils() {
}
public static List<String> parseStringList(List<String> list) {
return parseStringList(list, Function.identity());
}
/**
* 解析配置 List<String:String[,]>
*
* @param list list
* @param mapper mapper
* @return config
*/
public static List<String> parseStringList(List<String> list, Function<String, String> mapper) {
return Optional.ofNullable(list)
.map(List::stream)
.orElseGet(Stream::empty)
.map(s -> s.split(Const.COMMA))
.flatMap(Arrays::stream)
.map(String::trim)
.map(mapper)
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,147 @@
package com.orion.ops.framework.common.utils;
import com.orion.ops.framework.common.crypto.ValueCrypto;
/**
* 加密工具类
* <p>
* PrimaryValueCrypto 代理类工具
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/8 0:05
*/
public class CryptoUtils {
private static ValueCrypto delegate;
private CryptoUtils() {
}
/**
* 加密
*
* @param plain 明文
* @return 密文
*/
public static byte[] encrypt(byte[] plain) {
return delegate.encrypt(plain);
}
/**
* 加密
*
* @param plain 明文
* @return 密文
*/
public static byte[] encrypt(String plain) {
return delegate.encrypt(plain);
}
/**
* 加密
*
* @param plain 明文
* @return 密文
*/
public static String encryptAsString(String plain) {
return delegate.encryptAsString(plain);
}
/**
* 加密
*
* @param plain 明文
* @return 密文
*/
public static String encryptAsString(byte[] plain) {
return delegate.encryptAsString(plain);
}
/**
* 解密
*
* @param text 密文
* @return 明文
*/
public static byte[] decrypt(byte[] text) {
return delegate.decrypt(text);
}
/**
* 解密
*
* @param text 密文
* @return 明文
*/
public static byte[] decrypt(String text) {
return delegate.decrypt(text);
}
/**
* 解密
*
* @param text 密文
* @return 明文
*/
public static String decryptAsString(String text) {
return delegate.decryptAsString(text);
}
/**
* 解密
*
* @param text 密文
* @return 明文
*/
public static String decryptAsString(byte[] text) {
return delegate.decryptAsString(text);
}
/**
* 验证加密结果
*
* @param plain 明文
* @param text 密文
* @return 是否成功
*/
public static boolean verify(String plain, String text) {
return delegate.verify(plain, text);
}
/**
* 验证加密结果
*
* @param plain 明文
* @param text 密文
* @return 是否成功
*/
public static boolean verify(byte[] plain, byte[] text) {
return delegate.verify(plain, text);
}
/**
* 加密后 base62 编码
*
* @param plain 明文
* @return 密文
*/
public static String encryptBase62(String plain) {
return delegate.encryptBase62(plain);
}
/**
* base62 解码后解密
*
* @param text 密文
* @return 明文
*/
public static String decryptBase62(String text) {
return delegate.decryptBase62(text);
}
public static void setDelegate(ValueCrypto delegate) {
CryptoUtils.delegate = delegate;
}
}

View File

@@ -0,0 +1,136 @@
package com.orion.ops.framework.common.utils;
import com.orion.ops.framework.common.file.FileClient;
import java.io.InputStream;
/**
* 文件客户端工具
* <p>
* PrimaryFileClient 代理类工具
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/21 12:05
*/
public class FileClientUtils {
private static FileClient delegate;
private FileClientUtils() {
}
/**
* 上传文件
*
* @param path 文件路径
* @param content 文件内容
* @return 路径
* @throws Exception Exception
*/
public static String upload(String path, byte[] content) throws Exception {
return delegate.upload(path, content);
}
/**
* 上传文件
*
* @param path 文件路径
* @param content 文件内容
* @param overrideIfExist 文件存在是否覆盖
* @return 路径
* @throws Exception Exception
*/
public static String upload(String path, byte[] content, boolean overrideIfExist) throws Exception {
return delegate.upload(path, content, overrideIfExist);
}
/**
* 上传文件
*
* @param path 文件路径
* @param in in
* @return 路径
* @throws Exception Exception
*/
public static String upload(String path, InputStream in) throws Exception {
return delegate.upload(path, in);
}
/**
* 上传文件
*
* @param path 文件路径
* @param in in
* @param autoClose autoClose
* @return 路径
* @throws Exception Exception
*/
public static String upload(String path, InputStream in, boolean autoClose) throws Exception {
return delegate.upload(path, in, autoClose);
}
/**
* 上传文件
*
* @param path 文件路径
* @param in in
* @param autoClose autoClose
* @param overrideIfExist 文件存在是否覆盖
* @return 路径
* @throws Exception Exception
*/
public static String upload(String path, InputStream in, boolean autoClose, boolean overrideIfExist) throws Exception {
return delegate.upload(path, in, autoClose, overrideIfExist);
}
// TODO getOutputStream
/**
* 检查文件是否存在
*
* @param path path
* @return 是否存在
*/
public static boolean isExists(String path) {
return delegate.isExists(path);
}
/**
* 删除文件
*
* @param path 路径
* @return 是否删除
* @throws Exception Exception
*/
public static boolean delete(String path) throws Exception {
return delegate.delete(path);
}
/**
* 获取文件内容
*
* @param path path
* @return bytes
* @throws Exception Exception
*/
public static byte[] getContent(String path) throws Exception {
return delegate.getContent(path);
}
/**
* 获取文件输入流
*
* @param path path
* @return stream
* @throws Exception Exception
*/
public static InputStream getContentInputStream(String path) throws Exception {
return delegate.getContentInputStream(path);
}
public static void setDelegate(FileClient delegate) {
FileClientUtils.delegate = delegate;
}
}

View File

@@ -0,0 +1,28 @@
package com.orion.ops.framework.common.utils;
import com.orion.lang.utils.time.Dates;
import com.orion.ops.framework.common.constant.Const;
/**
* 文件名称
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/8/31 17:57
*/
public class FileNames {
private FileNames() {
}
/**
* 导出文件名称
*
* @param title title
* @return name
*/
public static String exportName(String title) {
return title + "-" + Dates.current(Dates.YMD_HMS2) + "." + Const.SUFFIX_XLSX;
}
}

View File

@@ -0,0 +1,54 @@
package com.orion.ops.framework.common.utils;
import com.orion.ext.location.Region;
import com.orion.ext.location.region.LocationRegions;
import com.orion.ops.framework.common.constant.Const;
/**
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/14 16:26
*/
public class IpUtils {
private IpUtils() {
}
/**
* 获取 ip 位置
*
* @param ip ip
* @return ip 位置
*/
public static String getLocation(String ip) {
if (ip == null) {
return Const.UNKNOWN;
}
Region region;
try {
region = LocationRegions.getRegion(ip, 3);
} catch (Exception e) {
return Const.UNKNOWN;
}
if (region != null) {
String net = region.getNet();
String province = region.getProvince();
if (net.equals(Const.INTRANET_IP)) {
return net;
}
if (province.equals(Const.UNKNOWN)) {
return province;
}
StringBuilder location = new StringBuilder()
.append(region.getCountry())
.append(Const.DASHED)
.append(province)
.append(Const.DASHED)
.append(region.getCity());
location.append(" (").append(net).append(')');
return location.toString();
}
return Const.UNKNOWN;
}
}

View File

@@ -0,0 +1,51 @@
package com.orion.ops.framework.common.utils;
import com.orion.lang.utils.collect.Maps;
import com.orion.lang.utils.reflect.Annotations;
import com.orion.ops.framework.common.constant.Const;
import io.swagger.v3.oas.annotations.Operation;
import java.lang.reflect.Method;
import java.util.Map;
/**
* swagger 工具类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/6 14:52
*/
public class SwaggerUtils {
/**
* api 描述
*/
private static final Map<String, String> SUMMARY_MAPPING = Maps.newMap();
private SwaggerUtils() {
}
/**
* 获取 api 描述
*
* @param m method
* @return summary
*/
public static String getOperationSummary(Method m) {
// 缓存中获取描述
String key = m.toString();
String cache = SUMMARY_MAPPING.get(key);
if (cache != null) {
return cache;
}
// 获取注解描述
Operation operation = Annotations.getAnnotation(m, Operation.class);
String summary = Const.EMPTY;
if (operation != null) {
summary = operation.summary();
}
SUMMARY_MAPPING.put(key, summary);
return summary;
}
}

View File

@@ -0,0 +1,84 @@
package com.orion.ops.framework.common.utils;
import com.orion.ops.framework.common.meta.TraceIdHolder;
import org.slf4j.MDC;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* 多线程下 MDC 工具类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/10 14:55
*/
public class ThreadMdcUtils {
private ThreadMdcUtils() {
}
/**
* 设置 MDC traceId
*/
public static void setTraceIdIfAbsent() {
if (MDC.get(TraceIdHolder.TRACE_ID_MDC) == null) {
MDC.put(TraceIdHolder.TRACE_ID_MDC, TraceIdHolder.get());
}
}
/**
* 设置线程 MDC 上下文
*
* @param callable callable
* @param <T> T
* @return callable
*/
public static <T> Callable<T> wrap(Callable<T> callable) {
// 获取当前线程 MDC 上下文
Map<String, String> callerContext = MDC.getCopyOfContextMap();
return () -> {
if (callerContext == null) {
MDC.clear();
} else {
MDC.setContextMap(callerContext);
}
// 设置 traceId
setTraceIdIfAbsent();
// 执行线程并且清理MDC
try {
return callable.call();
} finally {
MDC.clear();
}
};
}
/**
* 设置线程 MDC 上下文
*
* @param runnable runnable
* @return callable
*/
public static Runnable wrap(Runnable runnable) {
// 获取当前线程 MDC 上下文
Map<String, String> callerContext = MDC.getCopyOfContextMap();
return () -> {
//
if (callerContext == null) {
MDC.clear();
} else {
MDC.setContextMap(callerContext);
}
// 设置 traceId
setTraceIdIfAbsent();
// 执行线程并且清理MDC
try {
runnable.run();
} finally {
MDC.clear();
}
};
}
}

View File

@@ -0,0 +1,119 @@
package com.orion.ops.framework.common.utils;
import com.orion.lang.utils.Arrays1;
import com.orion.ops.framework.common.constant.ErrorMessage;
import com.orion.spring.SpringHolder;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
/**
* 验证器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/18 11:23
*/
public class Valid extends com.orion.lang.utils.Valid {
private static final Validator VALIDATOR = SpringHolder.getBean(Validator.class);
public static <T> T notNull(T object) {
return notNull(object, ErrorMessage.PARAM_MISSING);
}
public static String notBlank(String s) {
return notBlank(s, ErrorMessage.PARAM_MISSING);
}
public static <T extends Collection<?>> T notEmpty(T object) {
return notEmpty(object, ErrorMessage.PARAM_MISSING);
}
public static void allNotNull(Object... objects) {
if (objects != null) {
for (Object t : objects) {
notNull(t, ErrorMessage.PARAM_MISSING);
}
}
}
public static void allNotBlank(String... ss) {
if (ss != null) {
for (String s : ss) {
notBlank(s, ErrorMessage.PARAM_MISSING);
}
}
}
public static void eq(Object o1, Object o2) {
eq(o1, o2, ErrorMessage.INVALID_PARAM);
}
public static boolean isTrue(boolean s) {
return isTrue(s, ErrorMessage.INVALID_PARAM);
}
public static boolean isFalse(boolean s) {
return isFalse(s, ErrorMessage.INVALID_PARAM);
}
public static <T extends Comparable<T>> T gte(T t1, T t2) {
return gte(t1, t2, ErrorMessage.INVALID_PARAM);
}
@SafeVarargs
public static <T> T in(T t, T... ts) {
notNull(t, ErrorMessage.INVALID_PARAM);
notEmpty(ts, ErrorMessage.INVALID_PARAM);
isTrue(Arrays1.contains(ts, t), ErrorMessage.INVALID_PARAM);
return t;
}
/**
* 验证枚举
*
* @param of of method
* @param obj obj
* @param <T> param
* @param <E> enum
* @return enum
*/
public static <T, E extends Enum<?>> E valid(Function<T, E> of, T obj) {
return notNull(of.apply(obj), ErrorMessage.INVALID_PARAM);
}
/**
* 验证对象
*
* @param obj obj
* @param groups groups
* @param <T> T
* @return obj
*/
public static <T> T valid(T obj, Class<?>... groups) {
notNull(obj, ErrorMessage.PARAM_MISSING);
// 验证对象
Set<ConstraintViolation<T>> set = VALIDATOR.validate(obj, groups);
if (!set.isEmpty()) {
throw new ConstraintViolationException(set);
}
return obj;
}
/**
* 检查是否更新成功
*
* @param effect effect
* @return effect
*/
public static int version(int effect) {
isTrue(effect > 0, ErrorMessage.DATA_MODIFIED);
return effect;
}
}

View File

@@ -0,0 +1,11 @@
package com.orion.ops.framework.common.valid.group;
/**
* 分页验证分组
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/1 19:13
*/
public interface Id {
}

View File

@@ -0,0 +1,11 @@
package com.orion.ops.framework.common.valid.group;
/**
* 分页验证分组
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/1 19:13
*/
public interface Page {
}

View File

@@ -0,0 +1,35 @@
{
"groups": [
{
"name": "orion.async.executor",
"type": "com.orion.ops.framework.common.config.AsyncExecutorConfig",
"sourceType": "com.orion.ops.framework.common.config.AsyncExecutorConfig"
}
],
"properties": [
{
"name": "orion.async.executor.core-pool-size",
"type": "java.lang.Integer",
"description": "核心线程数量",
"defaultValue": "8"
},
{
"name": "orion.async.executor.max-pool-size",
"type": "java.lang.Integer",
"description": "最大线程数量.",
"defaultValue": "16"
},
{
"name": "orion.async.executor.queue-capacity",
"type": "java.lang.Integer",
"description": "队列容量.",
"defaultValue": "200"
},
{
"name": "orion.async.executor.keep-alive-seconds",
"type": "java.lang.Integer",
"description": "活跃时间.",
"defaultValue": "300"
}
]
}

View File

@@ -0,0 +1 @@
com.orion.ops.framework.common.config.OrionCommonAutoConfiguration