This commit is contained in:
clay
2024-03-06 17:44:09 +08:00
commit adaec0eadd
1493 changed files with 219939 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
<?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>
<artifactId>common</artifactId>
<groupId>cn.fateverse</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-code</artifactId>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>cn.fateverse</groupId>
<artifactId>common-core</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,21 @@
package cn.fateverse.common.code;
import cn.fateverse.common.code.config.JavaCodeProperties;
import cn.fateverse.common.code.engine.JavaCodeEngine;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
/**
* @author Clay
* @date 2023-10-30 23:09
*/
@EnableConfigurationProperties({JavaCodeProperties.class})
public class JavaCodeAutoConfiguration {
@Bean
public JavaCodeEngine javaCodeEngine(JavaCodeProperties javaCodeProperties){
return new JavaCodeEngine(javaCodeProperties);
}
}

View File

@@ -0,0 +1,21 @@
package cn.fateverse.common.code.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Clay
* @date 2023-10-30 23:09
*/
@ConfigurationProperties(prefix = "code.java")
public class JavaCodeProperties {
private String classPath;
public String getClassPath() {
return classPath;
}
public void setClassPath(String classPath) {
this.classPath = classPath;
}
}

View File

@@ -0,0 +1,231 @@
package cn.fateverse.common.code.engine;
import cn.fateverse.common.code.config.JavaCodeProperties;
import cn.fateverse.common.code.exception.SandboxClassNotFoundException;
import cn.fateverse.common.code.lock.SegmentLock;
import cn.fateverse.common.code.sandbox.SandboxClassLoader;
import cn.fateverse.common.code.sandbox.SandboxSecurityManager;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Clay
* @date 2023-10-24
*/
@Slf4j
public class JavaCodeEngine {
private final String JAVA_SUFFIX = ".java";
private final String CLASS_SUFFIX = ".class";
private final String CLASS_PATH;
private final URL url;
private final URLClassLoader classLoader;
private final Map<String, Class<?>> classCache = new ConcurrentHashMap<>();
private final SandboxSecurityManager securityManager = new SandboxSecurityManager(classCache);
// 获取Java编译器
private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
public JavaCodeEngine(JavaCodeProperties javaCodeProperties) {
try {
CLASS_PATH = javaCodeProperties.getClassPath();
File file = new File(CLASS_PATH);
if (!file.exists()) {
file.mkdirs();
}
url = file.toURI().toURL();
classLoader = new SandboxClassLoader(new URL[]{url});
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
/**
* 执行方法
*
* @param code 代码字符串
* @param className 类名
* @param methodName 方法名
* @param paramClass 参数类型数组
* @param args 参数数组
* @param development 是否为开发环境 开发环境下会将生成的类在执行完成后删除,不是生产环境则会缓存提高运行效率
* @return 执行结果
*/
public <T> T execute(String code, String className, String methodName, Class<?>[] paramClass, Object[] args, boolean development) {
if (development) {
return developmentExecute(code, className, methodName, paramClass, args);
} else {
return onlineExecute(code, className, methodName, paramClass, args);
}
}
/**
* 用于在开发环境中执行代码的私有方法。
*
* @param code 需要执行的代码字符串
* @param className 类名
* @param methodName 方法名
* @param paramClass 参数类型数组
* @param args 参数数组
* @param <T> 接收泛型
* @return 执行结构
*/
@SneakyThrows
private <T> T developmentExecute(String code, String className, String methodName, Class<?>[] paramClass, Object[] args) {
Class<?> loadClass = null;
try {
// 加锁,确保类只加载一次
loadClass = SegmentLock.lock(className, () -> {
URLClassLoader tempClassLoader = null;
try {
// 创建一个URLClassLoader用于加载代码字符串
tempClassLoader = new URLClassLoader(new URL[]{url});
// 编译代码字符串为类
Class<?> tempClass = compilerClass(className, code, tempClassLoader);
// 将编译好的类放入缓存
classCache.put(className, tempClass);
return tempClass;
} catch (Exception e) {
e.printStackTrace();
// 异常处理并抛出自定义的SandboxClassNotFoundException异常
throw new SandboxClassNotFoundException(e.getMessage());
} finally {
if (tempClassLoader != null) {
tempClassLoader = null;
}
}
});
// 获取需要执行的方法
Method method = loadClass.getMethod(methodName, paramClass);
// 设置安全检查器
System.setSecurityManager(securityManager);
// 执行方法并返回结果
return (T) method.invoke(null, args);
} finally {
// 从缓存中移除编译好的类
classCache.remove(className);
// 清空安全检查器
System.setSecurityManager(null);
if (loadClass != null) {
loadClass = null;
}
// 删除生成的java文件
File javaFile = new File(CLASS_PATH + className + JAVA_SUFFIX);
if (javaFile.exists()) {
javaFile.delete();
}
// 删除生成的class文件
File classFile = new File(CLASS_PATH + className + CLASS_SUFFIX);
if (classFile.exists()) {
classFile.delete();
}
// 执行垃圾回收
System.gc();
}
}
/**
* 线上环境执行
*
* @param code 需要执行的代码字符串
* @param className 类名
* @param methodName 方法名
* @param paramClass 参数类型数组
* @param args 参数数组
* @param <T> 接收泛型
* @return 执行结构
*/
private <T> T onlineExecute(String code, String className, String methodName, Class<?>[] paramClass, Object[] args) {
try {
Class<?> loadClass = null;
loadClass = classCache.get(className);
if (loadClass == null) {
loadClass = getLoadClass(code, className);
Method method = loadClass.getMethod(methodName, paramClass);
System.setSecurityManager(securityManager);
return (T) method.invoke(null, args);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.setSecurityManager(null);
File javaFile = new File(CLASS_PATH + className + JAVA_SUFFIX);
if (javaFile.exists()) {
javaFile.delete();
}
File classFile = new File(CLASS_PATH + className + CLASS_SUFFIX);
if (classFile.exists()) {
classFile.delete();
}
}
return null;
}
/**
* 获取到编译完成的Class对象
*
* @param code 需要编译的代码
* @param className 类名
* @return 编译后的Java对象
*/
private Class<?> getLoadClass(String code, String className) {
//使用分段锁,提高效率,放多并发情况下多次对同一个类进行编译
return SegmentLock.lock(className, () -> {
try {
//执行编译
Class<?> tempClass = compilerClass(className, code, classLoader);
//将编译之后的类对象放在缓存中,提高线上环境的运行效率
classCache.put(className, tempClass);
return tempClass;
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
/**
* 编译Java代码
*
* @param className 类名
* @param code Java代码
* @param classLoader 类加载器
* @return 编译完成的类对象
*/
private Class<?> compilerClass(String className, String code, URLClassLoader classLoader) {
log.info(code);
File tempFile = new File(CLASS_PATH + className + JAVA_SUFFIX);
try (FileWriter writer = new FileWriter(tempFile)) {
writer.write(code);
writer.close();
// 编译.java文件
compiler.run(null, null, null, tempFile.getPath());
return classLoader.loadClass(className);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,37 @@
package cn.fateverse.common.code.engine;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
/**
* js 工具类
*
* @author Clay
* @date 2023-03-24
*/
public class JavaScriptEngine {
/**
* 执行js代码
* @param script js脚本
* @param function js函数名
* @param args 参数
* @return 返回结构
* @param <T> 泛型类型
*/
public static <T> T executeScript(String script, String function, Object... args) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
try {
engine.eval(script);
Invocable inv = (Invocable) engine;
return (T) inv.invokeFunction(function, args);
} catch (ScriptException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,14 @@
package cn.fateverse.common.code.exception;
import cn.fateverse.common.core.exception.CustomException;
/**
* @author Clay
* @date 2023-10-25
*/
public class SandboxClassNotFoundException extends CustomException {
public SandboxClassNotFoundException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,43 @@
package cn.fateverse.common.code.lock;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
/**
* @author Clay
* @date 2023-10-25
*/
public class SegmentLock {
private static final Map<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();
/**
* 分段锁
* @param key 锁名称
* @param supplier 需要执行的函数
* @return 执行后的结果
* @param <T> 接收泛型
*/
public static <T> T lock(String key, Supplier<T> supplier) {
ReentrantLock lock = lockMap.get(key);
if (lock == null) {
lock = lockMap.get(key);
if (lock == null) {
synchronized (lockMap) {
lock = new ReentrantLock();
lockMap.put(key, lock);
}
}
}
lock.lock();
try {
return supplier.get();
} finally {
lock.unlock();
}
}
}

View File

@@ -0,0 +1,13 @@
package cn.fateverse.common.code.sandbox;
import java.net.URL;
import java.net.URLClassLoader;
public class SandboxClassLoader extends URLClassLoader {
public SandboxClassLoader(final URL[] urls) {
super(urls);
}
}

View File

@@ -0,0 +1,84 @@
package cn.fateverse.common.code.sandbox;
import java.io.FilePermission;
import java.lang.reflect.ReflectPermission;
import java.security.Permission;
import java.util.Map;
import java.util.PropertyPermission;
import java.util.Set;
public class SandboxSecurityManager extends SecurityManager {
private final Map<String, Class<?>> classCache;
public SandboxSecurityManager(Map<String, Class<?>> classCache) {
this.classCache = classCache;
}
@Override
public void checkPermission(Permission perm) {
if (isSandboxCode(perm)) {
if (!isAllowedPermission(perm)) {
throw new SecurityException("Permission denied " + perm);
}
}
}
private boolean isSandboxCode(Permission perm) {
Set<String> classKeySet = classCache.keySet();
for (String key : classKeySet) {
if (perm.getName().contains(key)) {
return true;
}
}
return false;
}
private boolean isAllowedPermission(Permission permission) {
//权限:用于校验文件系统访问权限,包括读取、写入、删除文件,以及目录操作。权限名称可能包括文件路径和操作,如 "read", "write", "delete", "execute" 等。
if (permission instanceof FilePermission){
System.out.println("触发文件读写权限");
return false;
}
//权限:用于校验运行时权限,如程序启动、关闭虚拟机等。您可以根据名称进行控制,如 "exitVM"、"setSecurityManager" 等。
if (permission instanceof RuntimePermission) {
System.out.println("用于校验运行时权限");
return false;
}
//权限用于校验Java反射操作的权限如 `suppressAccessChecks`、`newProxyInPackage` 等。
if (permission instanceof ReflectPermission) {
System.out.println("用于校验Java反射操作的权限");
return false;
}
//权限:用于校验系统属性的权限,包括读取和设置系统属性。权限名称通常以属性名称和操作(如 "read" 或 "write")表示。
if (permission instanceof PropertyPermission) {
System.out.println("用于校验系统属性的权限");
return false;
}
// 权限用于校验数据库访问权限包括连接数据库、执行SQL语句等。权限名称通常与数据库URL和操作相关。
// if (permission instanceof SQLPermission) {
// return false;
//
// }
//权限:用于校验网络套接字的权限,包括连接到特定主机和端口。权限名称通常以主机名和端口号的形式表示,如 "www.example.com:80".
// if (permission instanceof SocketPermission) {
// return false;
//
// }
//权限:用于校验安全管理器操作的权限,如 `createAccessControlContext`、`setPolicy` 等。
// if (permission instanceof SecurityPermission) {
// return false;
//
// }
// //序列化
// if (permission instanceof SerializablePermission) {
// return false;
// }
// System.out.println(permission);
return true;
}
}

View File

@@ -0,0 +1 @@
cn.fateverse.common.code.JavaCodeAutoConfiguration

View File

@@ -0,0 +1,71 @@
<?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>
<artifactId>common</artifactId>
<groupId>cn.fateverse</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-core</artifactId>
<description>common-core核心模块</description>
<properties>
<guava.version>30.1-jre</guava.version>
</properties>
<dependencies>
<!-- Alibaba Fastjson -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>compile</scope>
</dependency>
<!-- Apache Lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,26 @@
package cn.fateverse.common.core.annotaion;
import cn.fateverse.common.core.enums.MethodEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* mybatis自动注入时间
*
* @author Clay
* @date 2023-05-05
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoTime {
/**
* sql 方法 INSERT,UPDATE
* @return 方法类型
*/
MethodEnum method();
}

View File

@@ -0,0 +1,30 @@
package cn.fateverse.common.core.annotaion;
import cn.fateverse.common.core.enums.AutoUserEnum;
import cn.fateverse.common.core.enums.MethodEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* mybatis自动注入用户信息
*
* @author Clay
* @date 2023-05-05
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoUser {
AutoUserEnum value() default AutoUserEnum.USER_NAME;
/**
* sql 方法 INSERT,UPDATE
*
* @return 方法类型
*/
MethodEnum method();
}

View File

@@ -0,0 +1,17 @@
package cn.fateverse.common.core.annotaion;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 开启mybatis自动注入的能力
*
* @author Clay
* @date 2023-05-05
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableAutoField {
}

View File

@@ -0,0 +1,45 @@
package cn.fateverse.common.core.annotaion;
import java.lang.annotation.*;
/**
* 用户实体类需要excel导出的字段
*
* @author Clay
* @date 2022/12/19
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Excel {
/**
* 字段描述
*/
String value() default "";
/**
* 字段排序
*/
int order() default Integer.MAX_VALUE;
/**
* 时间格式
*/
String dateFormat() default "yyyy-MM-dd";
/**
* 字典类型
*/
String dictType() default "";
/**
* 导出时在excel中每个列的高度 单位为字符
* 占时未实现后其迭代
*/
double height() default 14;
/**
* 导出时在excel中每个列的宽 单位为字符
* 占时未实现后其迭代
*/
double width() default 16;
}

View File

@@ -0,0 +1,26 @@
package cn.fateverse.common.core.annotaion;
import java.lang.annotation.*;
/**
* 用于标注当前对象中存在@Excel注解标注的需要导出的字段
*
* @author Clay
* @date 2022/12/19
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Excels {
/**
* 字段描述
*/
String value() default "";
/**
* 字段排序
*/
int order() default Integer.MAX_VALUE;
}

View File

@@ -0,0 +1,23 @@
package cn.fateverse.common.core.annotaion;
import cn.fateverse.common.core.enums.GenIdEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自动生成id
*
* @author Clay
* @date 2023-05-05
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface GenerateId {
GenIdEnum idType() default GenIdEnum.UUID;
}

View File

@@ -0,0 +1,29 @@
package cn.fateverse.common.core.constant;
/**
* 缓存key
* @author Clay
* @date 2022/11/9
*/
public class CacheConstants {
/**
* 验证码 redis key
*/
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
/**
* 路由缓存地址
*/
public static final String ROUTE_CACHE_KEY = "router_key:";
/**
* 登录用户 redis key
*/
public static final String LOGIN_TOKEN_KEY = "login_info:";
/**
* 字典类型 redis key
*/
public static final String DICT_KEY = "dict:";
}

View File

@@ -0,0 +1,38 @@
package cn.fateverse.common.core.constant;
/**
* 通用常量信息
*
* @author Clay
*/
public class Constants {
/**
* 令牌前缀
*/
public static final String TOKEN_PREFIX = "Bearer ";
/**
* http请求
*/
public static final String HTTP = "http://";
/**
* https请求
*/
public static final String HTTPS = "https://";
/**
* 令牌前缀
*/
public static final String LOGIN_USER_KEY = "login_user_key";
/**
* 验证码有效期(分钟)
*/
public static final long CAPTCHA_EXPIRATION = 2;
public static final String UTF8 = "UTF-8";
}

View File

@@ -0,0 +1,20 @@
package cn.fateverse.common.core.constant;
/**
* @author Clay
* @date 2023-05-25
*/
public class DateConstants {
public static String YYYY = "yyyy";
public static String YYYY_MM = "yyyy-MM";
public static String YYYY_MM_DD = "yyyy-MM-dd";
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
}

View File

@@ -0,0 +1,48 @@
package cn.fateverse.common.core.constant;
/**
* 用户常量信息
*
* @author Clay
*/
public class UserConstants {
/**
* 平台内系统用户的唯一标志
*/
public static final String SYS_USER = "SYS_USER";
/**
* 匿名用户
*/
public static final String ANONYMOUS_USER = "anonymousUser";
/**
* 正常状态
*/
public static final String NORMAL = "0";
/**
* 异常状态
*/
public static final String EXCEPTION = "1";
/**
* 部门停用状态
*/
public static final String DEPT_DISABLE = "1";
/**
* Layout组件标识
*/
public final static String LAYOUT = "Layout";
/**
* 校验返回结果码
*/
public final static String UNIQUE = "0";
public final static String NOT_UNIQUE = "1";
}

View File

@@ -0,0 +1,89 @@
package cn.fateverse.common.core.entity;
import cn.fateverse.common.core.annotaion.AutoTime;
import cn.fateverse.common.core.annotaion.AutoUser;
import cn.fateverse.common.core.enums.MethodEnum;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable;
import java.util.Date;
/**
* @author Clay
* @date 2022/10/30
*/
public class BaseEntity implements Serializable {
/**
* 创建者
*/
@AutoUser(method = MethodEnum.INSERT)
private Object createBy;
/**
* 创建时间
*/
@AutoTime(method = MethodEnum.INSERT)
@JsonFormat(locale = "zh",timezone = "GMT+8",pattern = "yyyy-MM-dd")
private Date createTime;
/**
* 更新者
*/
@AutoUser(method = MethodEnum.UPDATE)
private Object updateBy;
/**
* 更新时间
*/
@AutoTime(method = MethodEnum.UPDATE)
@JsonFormat(locale = "zh",timezone = "GMT+8",pattern = "yyyy-MM-dd")
private Date updateTime;
/**
* 备注信息
*/
private String remark;
public Object getCreateBy() {
return createBy;
}
public void setCreateBy(Object createBy) {
this.createBy = createBy;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Object getUpdateBy() {
return updateBy;
}
public void setUpdateBy(Object updateBy) {
this.updateBy = updateBy;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
}

View File

@@ -0,0 +1,19 @@
package cn.fateverse.common.core.entity;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @author Clay
* @date 2023-11-14 21:11
*/
@Data
public class IdWrapper implements Serializable {
private Long id;
private List<Long> ids;
}

View File

@@ -0,0 +1,26 @@
package cn.fateverse.common.core.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Clay
* @date 2022/11/4
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Option {
/**
* 节点ID
*/
private Object value;
/**
* 节点名称
*/
private String label;
}

View File

@@ -0,0 +1,39 @@
package cn.fateverse.common.core.entity;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* Treeselect树结构实体类
*
* @author Clay
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OptionTree implements Serializable {
/**
* 节点ID
*/
private Object value;
/**
* 节点名称
*/
private Object label;
/**
* 子节点
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<OptionTree> children;
}

View File

@@ -0,0 +1,44 @@
package cn.fateverse.common.core.entity;
import cn.hutool.core.util.StrUtil;
import lombok.Data;
/**
* @author Clay
* @date 2022/10/30
*/
@Data
public class PageInfo {
/**
* 当前记录起始索引
*/
private Integer pageNum;
/**
* 每页显示记录数
*/
private Integer pageSize;
/**
* 排序列
*/
private String orderByColumn;
/**
* 排序的方向desc或者asc
*/
private String isAsc = "asc";
/**
* 分页参数合理化
*/
private Boolean reasonable = true;
public String getOrderBy() {
if (StrUtil.isEmpty(orderByColumn)) {
return "";
}
return StrUtil.toUnderlineCase(orderByColumn) + " " + isAsc;
}
}

View File

@@ -0,0 +1,27 @@
package cn.fateverse.common.core.entity;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
/**
* @author Clay
* @date 2022/11/9
*/
@Data
public class QueryTime implements Serializable {
/**
* 筛选创建时间的开始时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/**
* 筛选创建时间的结束时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
}

View File

@@ -0,0 +1,15 @@
package cn.fateverse.common.core.enums;
/**
* @author Clay
* @date 2023-05-05
*/
public enum AutoUserEnum {
/**
* 用户信息
*/
USER_NAME,
USER_ID,
NICK_NAME,
;
}

View File

@@ -0,0 +1,17 @@
package cn.fateverse.common.core.enums;
/**
* @author Clay
* @date 2023-05-05
*/
public enum GenIdEnum {
/**
* id生成类型
*/
UUID,
SNOWFLAKE
;
}

View File

@@ -0,0 +1,37 @@
package cn.fateverse.common.core.enums;
/**
* @author Clay
* @date 2022/11/9
*/
public enum MenuEnum {
/**
* 状态信息
*/
DIRECTORY("D", "目录"),
MENU("M", "菜单"),
BUTTON("B", "按钮"),
LAYOUT("LAYOUT", "Layout"),
PARENT_VIEW("PARENT_VIEW", "ParentView"),
;
private final String code;
private final String info;
MenuEnum(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}

View File

@@ -0,0 +1,15 @@
package cn.fateverse.common.core.enums;
/**
* @author Clay
* @date 2023-05-05
*/
public enum MethodEnum {
/**
* 需要设置的方法
*/
UPDATE,
INSERT,
;
}

View File

@@ -0,0 +1,47 @@
package cn.fateverse.common.core.enums;
import org.springframework.http.HttpStatus;
/**
* @author Clay
* @date 2023-05-10
*/
public enum ResultEnum {
/**
* 返回状态枚举
*/
SUCCESS(1000, "操作成功", HttpStatus.OK),
NO_DATA(1001, "查询结果为空", HttpStatus.OK),
RESUBMIT_LOCK(2002, "重复提交", HttpStatus.INTERNAL_SERVER_ERROR),
ERROR(2000, "操作失败", HttpStatus.INTERNAL_SERVER_ERROR),
SYS_ERROR(2001, "系统异常", HttpStatus.INTERNAL_SERVER_ERROR),
SENTINEL_FLOW(3000, "限流了", HttpStatus.INTERNAL_SERVER_ERROR),
SENTINEL_PARAM_FLOW(3000, "热点参数限流", HttpStatus.INTERNAL_SERVER_ERROR),
SENTINEL_SYSTEM(3000, "系统规则负载等不满足要求", HttpStatus.INTERNAL_SERVER_ERROR),
SENTINEL_AUTHORITY(3000, "授权规则不通过", HttpStatus.UNAUTHORIZED),
SENTINEL_DEGRADE(3000, "降级了", HttpStatus.INTERNAL_SERVER_ERROR),
;
ResultEnum(int code, String msg, HttpStatus status) {
this.code = code;
this.msg = msg;
this.status = status;
}
public final int code;
public final String msg;
public final transient HttpStatus status;
}

View File

@@ -0,0 +1,32 @@
package cn.fateverse.common.core.enums;
/**
* @author Clay
* @date 2022/11/6
*/
public enum StateEnum {
/**
* 状态信息
*/
NORMAL("1", "正常"),
DISABLE("0", "停用");
private final String code;
private final String info;
StateEnum(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}

View File

@@ -0,0 +1,33 @@
package cn.fateverse.common.core.enums;
/**
* 用户状态
*
* @author Clay
* @date 2022/10/30
*/
public enum UserState {
/**
* 用户状态信息
*/
DISABLE("0", "停用"),
OK("1", "正常"),
DELETED("2", "删除");
private final String code;
private final String info;
UserState(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}

View File

@@ -0,0 +1,81 @@
package cn.fateverse.common.core.exception;
/**
* 基础异常
*
* @author Clay
* @date 2022/10/30
*/
public class BaseException extends RuntimeException {
/**
* 所属模块
*/
private String module;
/**
* 错误码
*/
private String code;
/**
* 错误码对应的参数
*/
private Object[] args;
/**
* 错误消息
*/
private String defaultMessage;
public BaseException(String module, String code, Object[] args, String defaultMessage) {
this.module = module;
this.code = code;
this.args = args;
this.defaultMessage = defaultMessage;
}
public BaseException(String module, String code, Object[] args) {
this(module, code, args, null);
}
public BaseException(String module, String defaultMessage) {
this(module, null, null, defaultMessage);
}
public BaseException(String code, Object[] args) {
this(null, code, args, null);
}
public BaseException(String defaultMessage) {
this(null, null, null, defaultMessage);
}
@Override
public String getMessage() {
String message = null;
if (message == null) {
message = defaultMessage;
}
return message;
}
public String getModule() {
return module;
}
public String getCode() {
return code;
}
public Object[] getArgs() {
return args;
}
public String getDefaultMessage() {
return defaultMessage;
}
}

View File

@@ -0,0 +1,44 @@
package cn.fateverse.common.core.exception;
/**
* 自定义异常
*
* @author Clay
* @date 2022/10/29
*/
public class CustomException extends RuntimeException {
private Integer code;
private String message;
public CustomException(String message) {
this.message = message;
}
public CustomException(String message, Integer code) {
this.message = message;
this.code = code;
}
public CustomException(String message, Throwable e) {
super(message, e);
this.message = message;
}
public CustomException() {
}
@Override
public String getMessage() {
return message;
}
public Integer getCode() {
return code;
}
}

View File

@@ -0,0 +1,10 @@
package cn.fateverse.common.core.exception;
import cn.fateverse.common.core.enums.ResultEnum;
public class TierDownException extends CustomException {
public TierDownException(String message) {
super(ResultEnum.SYS_ERROR.msg);
}
}

View File

@@ -0,0 +1,15 @@
package cn.fateverse.common.core.exception;
/**
* 用户信息异常类
*
* @author Clay
* @date 2022/10/30
*/
public class UserException extends BaseException {
public UserException(String code, Object[] args) {
super("user", code, args, null);
}
}

View File

@@ -0,0 +1,16 @@
package cn.fateverse.common.core.exception;
/**
* 用户密码不正确或不符合规范异常类
*
* @author Clay
* @date 2022/10/30
*/
public class UserPasswordNotMatchException extends UserException {
public UserPasswordNotMatchException() {
super("user.password.not.match", null);
}
}

View File

@@ -0,0 +1,149 @@
package cn.fateverse.common.core.result;
import cn.fateverse.common.core.enums.ResultEnum;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.springframework.http.HttpStatus;
import java.io.Serializable;
/**
* 返回结果集
*
* @author: Clay
* @date: 2022/5/31 10:00
*/
public class Result<T> implements Serializable {
private Integer code;
private String msg;
private T data;
private transient HttpStatus status;
public Result() {
}
public Result(Integer code, String msg, T data, HttpStatus status) {
this.code = code;
this.msg = msg;
this.data = data;
this.status = status;
}
public static <T> Result<T> ok(Integer code, String msg, T data) {
return new Result<>(code, msg, data, HttpStatus.OK);
}
public static <T> Result<T> ok(Integer code, String msg, T data, HttpStatus status) {
return new Result<>(code, msg, data, status);
}
public static <T> Result<T> ok(String msg, T data) {
return Result.ok(ResultEnum.SUCCESS.code, msg, data, ResultEnum.SUCCESS.status);
}
public static <T> Result<T> ok(Integer code, T data) {
return Result.ok(code, ResultEnum.SUCCESS.msg, data);
}
public static <T> Result<T> ok(String msg) {
return ok(ResultEnum.SUCCESS.code, msg, null);
}
public static <T> Result<T> ok(T data) {
return Result.ok(ResultEnum.SUCCESS.msg, data);
}
public static <T> Result<T> ok() {
return Result.ok(ResultEnum.SUCCESS.msg, null);
}
public static <T> Result<T> error(String msg, T data) {
return Result.error(ResultEnum.ERROR.code, msg, data);
}
public static <T> Result<T> error(Integer code, String msg) {
return Result.error(code, msg, null);
}
public static <T> Result<T> notFound(String msg) {
return Result.error(HttpStatus.NOT_FOUND.value(), msg, null, HttpStatus.NOT_FOUND);
}
public static <T> Result<T> error(Integer code, String msg, T data) {
return new Result<>(code, msg, data, HttpStatus.INTERNAL_SERVER_ERROR);
}
public static <T> Result<T> error(Integer code, String msg, T data, HttpStatus status) {
return new Result<>(code, msg, data, status);
}
public static <T> Result<T> unauthorized(String msg) {
return new Result<>(HttpStatus.UNAUTHORIZED.value(), msg, null, HttpStatus.UNAUTHORIZED);
}
public static <T> Result<T> error(HttpStatus status, String msg) {
return new Result<>(status.value(), msg, null, status);
}
public static <T> Result<T> error(ResultEnum resultEnum) {
return Result.error(resultEnum.code, resultEnum.msg, null, resultEnum.status);
}
public static <T> Result<T> error(String msg) {
return Result.error(ResultEnum.ERROR.code, msg, null, ResultEnum.ERROR.status);
}
public static <T> Result<T> error() {
return Result.error(ResultEnum.ERROR.code, ResultEnum.ERROR.msg, null);
}
public static <T> Result<T> info(String msg) {
return Result.ok(ResultEnum.NO_DATA.code, msg, null);
}
public static <T> Result<T> info(ResultEnum resultEnum) {
return Result.error(resultEnum.code, resultEnum.msg, null, resultEnum.status);
}
public static <T> Result<T> noData() {
return Result.ok(ResultEnum.NO_DATA.code, ResultEnum.NO_DATA.msg, null);
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@JsonInclude(JsonInclude.Include.NON_NULL)
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
@JsonIgnore
public HttpStatus getStatus() {
return status;
}
@JsonIgnore
public void setStatus(HttpStatus status) {
this.status = status;
}
}

View File

@@ -0,0 +1,46 @@
package cn.fateverse.common.core.result.page;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 表格分页数据对象
*
* @author binlin
*/
@Data
public class TableDataInfo<T> implements Serializable {
/**
* 总记录数
*/
private long total;
/**
* 列表数据
*/
private List<T> rows;
/**
* 表格数据对象
*/
public TableDataInfo() {
}
/**
* 分页
*
* @param list 列表数据
* @param total 总记录数
*/
public TableDataInfo(List<T> list, int total) {
this.rows = list;
this.total = total;
}
}

View File

@@ -0,0 +1,272 @@
package cn.fateverse.common.core.utils;
import cn.fateverse.common.core.annotaion.AutoTime;
import cn.fateverse.common.core.annotaion.AutoUser;
import cn.fateverse.common.core.constant.UserConstants;
import cn.fateverse.common.core.enums.AutoUserEnum;
import cn.fateverse.common.core.enums.MethodEnum;
import cn.fateverse.common.core.exception.CustomException;
import com.alibaba.fastjson2.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Set;
/**
* @author Clay
* @date 2023-05-25
*/
public class AutoSetValueUtils {
private static final Logger log = LoggerFactory.getLogger(AutoSetValueUtils.class);
public static final String LONG_TYPE = "java.lang.Long";
public static final String OBJECT_TYPE = "java.lang.Object";
public static final String STRING_TYPE = "java.lang.String";
public static String BASE_PACKAGE;
static {
BASE_PACKAGE = getBasePackage(AutoSetValueUtils.class);
}
public static String getBasePackage(Class<?> clazz) {
String typeName = clazz.getTypeName();
int fastIndex = typeName.indexOf(".");
return typeName.substring(0, typeName.indexOf(".", fastIndex + 1));
}
/**
* 自动设置userID
*
* @param parameter 参数
* @param methodEnum sql方法
* @param field 字段
*/
public static void autoUser(Object parameter, MethodEnum methodEnum, Field field) {
//获取到设置用户id的注解
AutoUser autoUser = field.getAnnotation(AutoUser.class);
if (null != autoUser && autoUser.method() == methodEnum) {
SecurityContext context = SecurityContextHolder.getContext();
if (context == null) {
return;
}
Object principal = context.getAuthentication().getPrincipal();
if (null == principal || UserConstants.ANONYMOUS_USER.equals(principal)) {
return;
}
JSONObject user = ReflectUserUtils.getUser(principal);
AutoUserEnum value = autoUser.value();
Class<?> type = field.getType();
Object object = null;
String typeName = type.getTypeName();
if (value == AutoUserEnum.USER_ID) {
//设置用户id
long userId = user.getLongValue("userId");
switch (typeName) {
case OBJECT_TYPE:
case LONG_TYPE:
object = userId;
break;
case STRING_TYPE:
object = Long.toString(userId);
break;
default:
break;
}
} else if (value == AutoUserEnum.USER_NAME || value == AutoUserEnum.NICK_NAME) {
object = value == AutoUserEnum.USER_NAME ? user.getString("userName") : user.getString("nickName");
if (!(OBJECT_TYPE.equals(typeName) || STRING_TYPE.equals(typeName))) {
throw new CustomException("数据类型不配配,Field字段类型为" + typeName + "不能放入String类型的数据");
}
} else {
return;
}
try {
field.setAccessible(true);
field.set(parameter, object);
} catch (IllegalAccessException e) {
log.error("字段:{}自动设置参数失败", field.getName());
}
}
}
/**
* 自动设置时间
*
* @param parameter 参数
* @param methodEnum sql方法
* @param field 字段
*/
public static void autoTime(Object parameter, MethodEnum methodEnum, Field field) {
//获取到设置时间的注解
AutoTime autoTime = field.getAnnotation(AutoTime.class);
if (null != autoTime && autoTime.method() == methodEnum) {
field.setAccessible(true);
Class<?> type = field.getType();
Object time = null;
try {
time = type.newInstance();
field.set(parameter, time);
} catch (InstantiationException | IllegalAccessException e) {
log.error("字段:{}自动设置参数失败,参数为:{}", field.getName(), time);
}
}
}
/**
* 自动设置userID
*
* @param parameter 参数
* @param methodEnum sql方法
* @param fields 字段
*/
public static void autoUserNew(Object parameter, MethodEnum methodEnum, Set<Field> fields) {
SecurityContext context = SecurityContextHolder.getContext();
if (context == null) {
return;
}
Authentication authentication = context.getAuthentication();
if (null == authentication) {
return;
}
Object principal = authentication.getPrincipal();
if (null == principal || UserConstants.ANONYMOUS_USER.equals(principal)) {
return;
}
JSONObject user = ReflectUserUtils.getUser(principal);
for (Field field : fields) {
setUser(methodEnum, user, parameter, field);
}
}
/**
* 自动设置时间
*
* @param parameter 参数
* @param methodEnum sql方法
* @param fields 字段
*/
public static void autoTimeNew(Object parameter, MethodEnum methodEnum, Set<Field> fields) {
for (Field field : fields) {
setTime(methodEnum, parameter, field);
}
}
/**
* 自动设置userID
*
* @param list 参数
* @param methodEnum sql方法
* @param fields 字段
*/
public static void autoUserList(List<Object> list, MethodEnum methodEnum, Set<Field> fields) {
if (fields.isEmpty()) {
return;
}
SecurityContext context = SecurityContextHolder.getContext();
if (context == null) {
return;
}
Object principal = context.getAuthentication().getPrincipal();
if (null == principal || UserConstants.ANONYMOUS_USER.equals(principal)) {
return;
}
JSONObject user = ReflectUserUtils.getUser(principal);
for (Object param : list) {
for (Field field : fields) {
setUser(methodEnum, user, param, field);
}
}
}
/**
* 设置用户通用函数
*
* @param methodEnum 方法类型
* @param user 用户信息
* @param param 参数对象
* @param field 字段对象
*/
private static void setUser(MethodEnum methodEnum, JSONObject user, Object param, Field field) {
long userId = user.getLongValue("userId");
//获取到设置用户id的注解
AutoUser autoUser = field.getAnnotation(AutoUser.class);
if (null != autoUser && autoUser.method() == methodEnum) {
AutoUserEnum value = autoUser.value();
Class<?> type = field.getType();
Object object = null;
String typeName = type.getTypeName();
if (value == AutoUserEnum.USER_ID) {
//设置用户id
if (type == Object.class || type == Long.class) {
object = userId;
} else if (type == String.class) {
object = Long.toString(userId);
}
} else if (value == AutoUserEnum.USER_NAME || value == AutoUserEnum.NICK_NAME) {
object = value == AutoUserEnum.USER_NAME ? user.getString("userName") : user.getString("nickName");
if (!(type == Object.class || type == Long.class)) {
throw new CustomException("数据类型不配配,Field字段类型为" + typeName + "不能放入String类型的数据");
}
} else {
return;
}
try {
field.setAccessible(true);
field.set(param, object);
} catch (IllegalAccessException e) {
log.error("字段:{}自动设置参数失败", field.getName());
}
}
}
/**
* 自动设置时间
*
* @param list 参数
* @param methodEnum sql方法
* @param fields 时间
*/
public static void autoTimeList(List<Object> list, MethodEnum methodEnum, Set<Field> fields) {
if (fields.isEmpty()) {
return;
}
for (Object param : list) {
for (Field field : fields) {
setTime(methodEnum, param, field);
}
}
}
/**
* 设置时间
*
* @param methodEnum 方法类型
* @param param 参数对象
* @param field 字段
*/
private static void setTime(MethodEnum methodEnum, Object param, Field field) {
//获取到设置时间的注解
AutoTime autoTime = field.getAnnotation(AutoTime.class);
if (null != autoTime && autoTime.method() == methodEnum) {
field.setAccessible(true);
Class<?> type = field.getType();
Object time = null;
try {
time = type.newInstance();
field.set(param, time);
} catch (InstantiationException | IllegalAccessException e) {
log.error("字段:{}自动设置参数失败,参数为:{}", field.getName(), time);
}
}
}
}

View File

@@ -0,0 +1,36 @@
package cn.fateverse.common.core.utils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Clay
* @date 2023-05-10
*/
public class HttpServletUtils {
/**
* 获取request信息
* @return
*/
public static HttpServletRequest getRequest() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return attributes.getRequest();
}
/**
* 获取http响应对象
*
* @return response
*/
public static HttpServletResponse getResponse() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return attributes.getResponse();
}
}

View File

@@ -0,0 +1,56 @@
package cn.fateverse.common.core.utils;
import cn.fateverse.common.core.exception.CustomException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author Clay
* @date 2023-10-15
*/
public class IpBackUtils {
public static final String BLACK_LIST = "black:list:";
public final static String BLACK_LIST_IPV_4 = BLACK_LIST + "ipv4";
public final static String BLACK_LIST_IPV_6 = BLACK_LIST + "ipv6";
public final static String BLACK_LIST_IP = BLACK_LIST + "ip";
public final static String IPV_4 = "ipv4";
public final static String IPV_6 = "ipv6";
public static long ipToDecimal(String ipAddress) {
try {
// 将IP地址拆分为四个部分
String[] ipParts = ipAddress.split("\\.");
// 将每个部分转换为整数
long decimalNumber = 0;
for (int i = 0; i < 4; i++) {
long ipPart = Long.parseLong(ipParts[i]);
// 每个部分的权重为256的(3-i)次方
decimalNumber += ipPart * Math.pow(256, 3 - i);
}
return decimalNumber;
} catch (Exception e) {
return 0;
}
}
public static String getIpType(String ip) {
try {
InetAddress address = InetAddress.getByName(ip);
if (address instanceof Inet4Address) {
return IPV_4;
} else if (address instanceof Inet6Address) {
return IPV_6;
}
} catch (UnknownHostException e) {
throw new CustomException("无效ip地址");
}
throw new CustomException("无效ip地址");
}
}

View File

@@ -0,0 +1,167 @@
package cn.fateverse.common.core.utils;
import cn.hutool.http.HtmlUtil;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 获取IP方法
*
* @author binlin
*/
public class IpUtils {
public static String getIpAdder(HttpServletRequest request) {
if (request == null) {
return "unknown";
}
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Forwarded-For");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : HtmlUtil.removeHtmlTag(ip);
}
public static boolean internalIp(String ip) {
byte[] addr = textToNumericFormatV4(ip);
return internalIp(addr) || "127.0.0.1".equals(ip);
}
private static boolean internalIp(byte[] addr) {
if (ObjectUtils.isEmpty(addr) || addr.length < 2) {
return true;
}
final byte b0 = addr[0];
final byte b1 = addr[1];
// 10.x.x.x/8
final byte SECTION_1 = 0x0A;
// 172.16.x.x/12
final byte SECTION_2 = (byte) 0xAC;
final byte SECTION_3 = (byte) 0x10;
final byte SECTION_4 = (byte) 0x1F;
// 192.168.x.x/16
final byte SECTION_5 = (byte) 0xC0;
final byte SECTION_6 = (byte) 0xA8;
switch (b0) {
case SECTION_1:
return true;
case SECTION_2:
if (b1 >= SECTION_3 && b1 <= SECTION_4) {
return true;
}
case SECTION_5:
switch (b1) {
case SECTION_6:
return true;
}
default:
return false;
}
}
/**
* 将IPv4地址转换成字节
*
* @param text IPv4地址
* @return byte 字节
*/
public static byte[] textToNumericFormatV4(String text) {
if (text.length() == 0) {
return null;
}
byte[] bytes = new byte[4];
String[] elements = text.split("\\.", -1);
try {
long l;
int i;
switch (elements.length) {
case 1:
l = Long.parseLong(elements[0]);
if ((l < 0L) || (l > 4294967295L)) {
return null;
}
bytes[0] = (byte) (int) (l >> 24 & 0xFF);
bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 2:
l = Integer.parseInt(elements[0]);
if ((l < 0L) || (l > 255L)) {
return null;
}
bytes[0] = (byte) (int) (l & 0xFF);
l = Integer.parseInt(elements[1]);
if ((l < 0L) || (l > 16777215L)) {
return null;
}
bytes[1] = (byte) (int) (l >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 3:
for (i = 0; i < 2; ++i) {
l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L)) {
return null;
}
bytes[i] = (byte) (int) (l & 0xFF);
}
l = Integer.parseInt(elements[2]);
if ((l < 0L) || (l > 65535L)) {
return null;
}
bytes[2] = (byte) (int) (l >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 4:
for (i = 0; i < 4; ++i) {
l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L)) {
return null;
}
bytes[i] = (byte) (int) (l & 0xFF);
}
break;
default:
return null;
}
} catch (NumberFormatException e) {
return null;
}
return bytes;
}
public static String getHostIp() {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
}
return "127.0.0.1";
}
public static String getHostName() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
}
return "未知";
}
}

View File

@@ -0,0 +1,34 @@
package cn.fateverse.common.core.utils;
import cn.fateverse.common.core.exception.CustomException;
/**
* Long工具类
*
* @author Clay
* @date 2022/11/6
*/
public class LongUtils {
public static boolean isNull(Long num){
return null == num || 0L == num;
}
public static boolean isNotNull(Long num){
return !isNull(num);
}
public static void checkId(Long pk){
checkId(pk,"缺少必要参数!");
}
public static void checkId(Long pk, String message){
if (isNull(pk)) {
throw new CustomException(message);
}
}
}

View File

@@ -0,0 +1,16 @@
package cn.fateverse.common.core.utils;
import cn.fateverse.common.core.enums.MenuEnum;
/**
* @author Clay
* @date 2022/11/9
*/
public class MenuTypeUtils {
public static boolean checkMenuTypeLegal(String menuType){
return MenuEnum.MENU.getInfo().equals(menuType) ||
MenuEnum.DIRECTORY.getInfo().equals(menuType)||
MenuEnum.BUTTON.getInfo().equals(menuType);
}
}

View File

@@ -0,0 +1,59 @@
package cn.fateverse.common.core.utils;
import cn.fateverse.common.core.exception.CustomException;
import java.util.List;
/**
* @author Clay
* @date 2022/12/18
*/
public class ObjectUtils extends org.springframework.util.ObjectUtils {
/**
* 检查主键
* @param pk 主键
*/
public static void checkPk(Object pk) {
checkPk(pk, "缺少必要参数!");
}
/**
* 检查主键
* @param pk 主键
* @param message 错误提示消息
*/
public static void checkPk(Object pk, String message) {
if (pk instanceof Long) {
LongUtils.checkId((Long) pk, message);
} else if (pk instanceof String) {
if (isEmpty(pk)) {
throw new CustomException(message);
}
} else {
if (null == pk) {
throw new CustomException(message);
}
}
}
/**
* 检查主键list
* @param pkList 主键list
*/
public static void checkPkList(List<?> pkList) {
checkPkList(pkList,"缺少必要参数!");
}
/**
* 检查主键list
* @param pkList 主键list
* @param message 错误提示消息
*/
public static void checkPkList(List<?> pkList, String message) {
if (isEmpty(pkList)){
throw new CustomException(message);
}
}
}

View File

@@ -0,0 +1,122 @@
package cn.fateverse.common.core.utils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
/**
* @author Clay
* @date 2023-05-10
*/
public class ReflectUserUtils {
/**
* 从loginUser中获取到用户信息
*
* @param loginUser 登录后的用户
* @return 用户的字段信息
*/
private static Field getUserField(Object loginUser) {
Class<?> userClass = loginUser.getClass();
try {
return userClass.getDeclaredField("user");
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
/**
* 获取到token 信息
*
* @param loginUser 登录后的用户
* @return token
*/
public static String getToken(Object loginUser) {
Class<?> loginUserClass = loginUser.getClass();
Field token;
try {
token = loginUserClass.getDeclaredField("token");
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
return getValue(loginUser, token).toString();
}
/**
* 获取用户信息
*
* @param loginUser 登录后的用户
* @return 用户信息
*/
public static JSONObject getUser(Object loginUser) {
Field userField = getUserField(loginUser);
Object user = getValue(loginUser, userField);
return (JSONObject) JSON.toJSON(user);
}
/**
* 获取到用户Id
*
* @param loginUser 登录后的用户
* @return 用户id
*/
public static String getUserId(Object loginUser) {
return getFieldValue(loginUser, "userId");
}
/**
* 获取到用户名
*
* @param loginUser 登录后的用户
* @return 用户名
*/
public static String getUsername(Object loginUser) {
return getFieldValue(loginUser, "userName");
}
/**
* 获取到用户别名
*
* @param loginUser 登录后的用户
* @return 用户别名
*/
public static String getNickname(Object loginUser) {
return getFieldValue(loginUser, "nickName");
}
/**
* 获取到值
*
* @param user 登录后的用户
* @param field 字段
* @return 值
*/
private static Object getValue(Object user, Field field) {
field.setAccessible(true);
return ReflectionUtils.getField(field, user);
}
/**
* 通过字段名获取到值
*
* @param loginUser 登录后的用户
* @param fieldName 字段名
* @return 值
*/
private static String getFieldValue(Object loginUser, String fieldName) {
Field userField = getUserField(loginUser);
Class<?> userClass = userField.getType().getSuperclass();
Object user = getValue(loginUser, userField);
Field field = null;
try {
field = userClass.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
return getValue(user, field).toString();
}
}

View File

@@ -0,0 +1,80 @@
package cn.fateverse.common.core.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Lazy;
/**
* Spring 事件发布工具类
* @author Clay
* @date 2022/11/1
*/
@Slf4j
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
/**
* 从applicationContext中获取到Bean,并转换成为requiredType对应的类型
*/
public static <T> T getBean(Class<T> requiredType){
return applicationContext.getBean(requiredType);
}
/**
* 从applicationContext中获取Bean,并自动转成对应接受的类型
*/
public static <T> T getBean(String name){
return (T) applicationContext.getBean(name);
}
/**
* 发布事件,实现异步执行功能
* @param event
*/
public static void publishEvent(ApplicationEvent event){
if (applicationContext == null){
return;
}
applicationContext.publishEvent(event);
}
/**
*
* @throws Exception
*/
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
/**
* 清除SpringContextHolder中的applicationContext
*/
public static void clearHolder(){
//如果是debug环境下,打印清除ApplicationContext的日志
if (log.isDebugEnabled()){
log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
}
applicationContext = null;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHolder.applicationContext = applicationContext;
}
@Override
public void destroy() throws Exception {
SpringContextHolder.clearHolder();
}
}

View File

@@ -0,0 +1,15 @@
package cn.fateverse.common.core.utils;
import cn.fateverse.common.core.enums.StateEnum;
/**
* @author Clay
* @date 2022/11/6
*/
public class StateUtils {
public static boolean checkStateLegal(String state){
return StateEnum.NORMAL.getCode().equals(state) ||
StateEnum.DISABLE.getCode().equals(state);
}
}

View File

@@ -0,0 +1,80 @@
package cn.fateverse.common.core.utils;
import cn.fateverse.common.core.entity.PageInfo;
import cn.hutool.core.convert.Convert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* 表格数据处理
*
* @author Clay
* @date 2022/10/30
*/
public class TableSupport {
/**
* 当前记录起始索引
*/
public static final String PAGE_NUM = "pageNum";
/**
* 每页显示记录数
*/
public static final String PAGE_SIZE = "pageSize";
/**
* 排序列
*/
public static final String ORDER_BY_COLUMN = "orderByColumn";
/**
* 排序的方向 "desc" 或者 "asc".
*/
public static final String IS_ASC = "isAsc";
/**
* 分页参数合理化
*/
public static final String REASONABLE = "reasonable";
/**
* 封装分页对象
*/
public static PageInfo getPageInfo() {
PageInfo pageInfo = new PageInfo();
pageInfo.setPageNum(Convert.toInt(getParameter(PAGE_NUM), 1));
pageInfo.setPageSize(Convert.toInt(getParameter(PAGE_SIZE), 10));
pageInfo.setOrderByColumn(getParameter(ORDER_BY_COLUMN));
pageInfo.setIsAsc(getParameter(IS_ASC));
pageInfo.setReasonable(getParameterToBool(REASONABLE));
return pageInfo;
}
public static PageInfo buildPageRequest() {
return getPageInfo();
}
/**
* 获取Boolean参数
*/
public static Boolean getParameterToBool(String name) {
return Convert.toBool(getRequest().getParameter(name));
}
/**
* 获取String参数
*/
public static String getParameter(String name) {
return Convert.toStr(getRequest().getParameter(name));
}
public static HttpServletRequest getRequest() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return attributes.getRequest();
}
}

View File

@@ -0,0 +1,56 @@
package cn.fateverse.common.core.utils.convert;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* @author Clay
* @date 2022/11/16
*/
public class ObjectConfig {
private boolean copy;
private Map<String,String> mapper;
private Set<String> exclude;
public ObjectConfig() {
mapper = new LinkedHashMap<>();
exclude = new LinkedHashSet<>();
copy = true;
}
public void setMapper(String targetKey, String sourceKey){
mapper.put(targetKey,sourceKey);
}
public void setExclude(String excludeKey){
exclude.add(excludeKey);
}
public Map<String,String> getMapper(){
return mapper;
}
public Set<String> getExclude() {
return exclude;
}
public void setOption(String value,String label){
this.copy = false;
mapper.put("label",label);
mapper.put("value",value);
}
public boolean isCopy() {
return copy;
}
public void setCopy(boolean copy) {
this.copy = copy;
}
}

View File

@@ -0,0 +1,112 @@
package cn.fateverse.common.core.utils.convert;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* @author Clay
* @date 2022/11/16
* 对象之间的转换
*/
public class ObjectConvertUtil {
private static TreeConfig treeConfig;
private static Map<String, Field> cacheTargetField;
private static Map<String,Field> cacheSourceField;
/**
* 目标class
*/
private static Class<?> targetClass;
private static Class<?> sourceClass;
/**
*
* @param list
* @param target
* @param config
* @return
* @param <T>
*/
@SuppressWarnings("unchecked")
public static <T> List<T> build(List<?> list, Class<T> target, Consumer<TreeConfig> config) {
if (list.isEmpty()){
return new ArrayList<>();
}
//将目标class对象设置为全局对象
targetClass = target;
sourceClass = list.get(0).getClass();
//初始化config
treeConfig = new TreeConfig();
//将目标class对象设置为全局对象
//提供给实现类对config进行修改
config.accept(treeConfig);
List<Object> collect = list.stream().map(ObjectConvertUtil::conversion).collect(Collectors.toList());
return (List<T>) collect;
}
@SuppressWarnings("unchecked")
private static <T> T conversion(Object object) {
try {
Object targetObject = targetClass.newInstance();
//相同字段名称直接赋值
if (treeConfig.isCopy()) {
BeanUtils.copyProperties(object, targetObject);
}
//不同字段名进行赋值
for (Map.Entry<String, String> entry : treeConfig.getMapper().entrySet()) {
Object value = getSourceValue(object,entry.getValue());
setTargetValue(targetObject,entry.getKey(),value);
}
for (String key : treeConfig.getExclude()) {
setTargetValue(targetObject,key,null);
}
//返回结果
return (T) targetObject;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static Object getSourceValue(Object source,String sourceFiled){
Field field = cacheSourceField.get(sourceFiled);
if (null == field){
try {
field = sourceClass.getDeclaredField(sourceFiled);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
cacheSourceField.put(sourceFiled,field);
}
field.setAccessible(true);
return ReflectionUtils.getField(field,source);
}
private static void setTargetValue(Object target,String targetFiled,Object value){
Field field = cacheTargetField.get(targetFiled);
if (null == field){
try {
field = targetClass.getDeclaredField(targetFiled);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
cacheTargetField.put(targetFiled,field);
}
field.setAccessible(true);
ReflectionUtils.setField(field,target,value);
}
}

View File

@@ -0,0 +1,126 @@
package cn.fateverse.common.core.utils.convert;
import cn.hutool.core.util.StrUtil;
import java.util.*;
/**
* @author Clay
* @date 2022/11/16
* TreeConfig的配置文件
*/
public class TreeConfig {
private boolean copy;
private final Map<String, String> mapper;
private final Set<String> exclude;
private String idField;
private String parentField;
private String childrenField;
private Boolean isStore = false;
private String storeField;
public TreeConfig() {
mapper = new LinkedHashMap<>();
exclude = new LinkedHashSet<>();
copy = true;
this.idField = "id";
this.parentField = "parentId";
this.childrenField = "children";
}
public void setParentField(String parentField) {
if (StrUtil.isEmpty(parentField)) {
return;
}
this.parentField = parentField;
}
public Boolean getStore() {
return isStore;
}
public String getStoreField() {
return storeField;
}
public String getParentField() {
return parentField;
}
public String getIdField() {
return idField;
}
public void setIdField(String idField) {
if (StrUtil.isEmpty(idField)) {
return;
}
this.idField = idField;
}
public void setSortOrder(Boolean isStore,String storeField) {
this.isStore = isStore;
this.storeField = storeField;
}
public String getChildrenField() {
return childrenField;
}
public void setChildrenField(String childrenField) {
if (StrUtil.isEmpty(childrenField)) {
return;
}
this.childrenField = childrenField;
}
public void setMapper(String targetKey, String sourceKey) {
mapper.put(targetKey, sourceKey);
}
public void setExclude(String excludeKey) {
exclude.add(excludeKey);
}
public Map<String, String> getMapper() {
return mapper;
}
public Set<String> getExclude() {
return exclude;
}
public void setOption(String valueField, String labelField) {
this.copy = false;
mapper.put("value", valueField);
mapper.put("label", labelField);
}
public boolean isCopy() {
return copy;
}
public void setCopy(boolean copy) {
this.copy = copy;
}
/**
* 空实现
*/
//@Override
//public void build(TreeConfig treeConfig) {
//}
}

View File

@@ -0,0 +1,185 @@
package cn.fateverse.common.core.utils.convert;
import cn.hutool.core.convert.Convert;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* @author Clay
* @date 2022/11/16
* 树形结构转换递归方式
*/
@SuppressWarnings("unchecked")
public class TreeUtil {
/**
* 配置信息
*/
private static TreeConfig treeConfig;
private static Map<String, Field> cacheTargetField;
private static Map<String, Field> cacheSourceField;
/**
* 目标class
*/
private static Class<?> targetClass;
private static Class<?> sourceClass;
/**
* 构建tree结构
*
* @param list 需要转换的list
* @param target 目标class对象
* @param config 配置项
* @param <T> 目标对象类型
* @return
*/
public static <T> List<T> build(List<?> list, Class<T> target, Consumer<TreeConfig> config) {
if (list.isEmpty()) {
return new ArrayList<>();
}
//将目标class对象设置为全局对象
targetClass = target;
sourceClass = list.get(0).getClass();
//初始化config
treeConfig = new TreeConfig();
//初始化字段缓存
cacheTargetField = new HashMap<>();
cacheSourceField = new HashMap<>();
//提供给实现类对config进行修改
config.accept(treeConfig);
//获取到最小的
Object min = list.stream().min(Comparator.comparing(object -> getParentId(object).toString())).get();
//获取到最小的父级id
Object minPid = getParentId(min);
//将数据通过他们的各自的父id进行分组
Map<Object, List<Object>> listMap = list.stream().collect(Collectors.groupingBy(TreeUtil::getParentId));
//最终开始进行tree的构建
return getChildren(listMap, minPid);
}
/**
* 获取到子节点
*
* @param listMap
* @param parentId
* @param <T>
* @return
*/
private static <T> List<T> getChildren(Map<Object, List<Object>> listMap, Object parentId) {
//获取到缓存中的list
List<?> objects = listMap.get(parentId);
if (chickList(objects)) {
return null;
}
if (treeConfig.getStore()) {
objects = objects.stream().sorted(Comparator.comparing(item ->
Convert.toInt(getSourceValue(item, treeConfig.getStoreField()))
)).collect(Collectors.toList());
}
listMap.remove(parentId);
//遍历数组,并将对象一一的转换
List<Object> collect = objects.stream().map(object ->
conversion(object, listMap)).collect(Collectors.toList());
return (List<T>) collect;
}
/**
* 对象直接的字段进行转换
*
* @param object
* @param listMap
* @param <T>
* @return
*/
private static <T> T conversion(Object object, Map<Object, List<Object>> listMap) {
try {
Object targetObject = targetClass.newInstance();
//相同字段名称直接赋值
if (treeConfig.isCopy()) {
BeanUtils.copyProperties(object, targetObject);
}
//不同字段名进行赋值
for (Map.Entry<String, String> entry : treeConfig.getMapper().entrySet()) {
Object value = getSourceValue(object, entry.getValue());
setTargetValue(targetObject, entry.getKey(), value);
}
//设置子节点
Object id = getSourceValue(object, treeConfig.getIdField());
List<Object> children = getChildren(listMap, id);
if (!chickList(children)) {
setTargetValue(targetObject, treeConfig.getChildrenField(), children);
}
//设置完毕后,将需要排除的字段进行置空
for (String key : treeConfig.getExclude()) {
setTargetValue(targetObject, key, null);
}
//返回结果
return (T) targetObject;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static Object getSourceValue(Object source, String sourceFiled) {
Field field = cacheSourceField.get(sourceFiled);
if (null == field) {
try {
field = sourceClass.getDeclaredField(sourceFiled);
field.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
cacheSourceField.put(sourceFiled, field);
}
return ReflectionUtils.getField(field, source);
}
private static void setTargetValue(Object target, String targetFiled, Object value) {
Field field = cacheTargetField.get(targetFiled);
if (null == field) {
try {
field = targetClass.getDeclaredField(targetFiled);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
field.setAccessible(true);
cacheTargetField.put(targetFiled, field);
}
ReflectionUtils.setField(field, target, value);
}
/**
* 检查list是否为空
*
* @param objects
* @return
*/
private static boolean chickList(List<?> objects) {
return null == objects || objects.isEmpty();
}
/**
* 获取到父级id
*
* @param object
* @return
*/
private static Object getParentId(Object object) {
try {
return getSourceValue(object, treeConfig.getParentField());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,56 @@
package cn.fateverse.common.core.utils.sql;
import cn.fateverse.common.core.exception.CustomException;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.lang3.StringUtils;
/**
* sql操作工具类
*
* @author Clay
* @date 2022/10/30
*/
public class SqlUtil {
/**
* 定义常用的 sql关键字
*/
public static String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare ";
/**
* 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
*/
public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
/**
* 检查字符,防止注入绕过
*/
public static String escapeOrderBySql(String value) {
if (!StrUtil.isEmpty(value) && !isValidOrderBySql(value)) {
throw new CustomException("参数不符合规范,不能进行查询");
}
return value;
}
/**
* 验证 order by 语法是否符合规范
*/
public static boolean isValidOrderBySql(String value) {
return value.matches(SQL_PATTERN);
}
/**
* SQL关键字检查
*/
public static void filterKeyword(String value) {
if (StrUtil.isEmpty(value)) {
return;
}
String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
for (String sqlKeyword : sqlKeywords) {
if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) {
throw new CustomException("参数存在SQL注入风险");
}
}
}
}

View File

@@ -0,0 +1,46 @@
package cn.fateverse.common.core.utils.uuid;
import cn.hutool.core.lang.UUID;
/**
* ID生成器工具类
*
* @author Clay
*/
public class IdUtils {
/**
* 获取随机UUID
*
* @return 随机UUID
*/
public static String randomUUID() {
return UUID.randomUUID().toString();
}
/**
* 简化的UUID去掉了横线
*
* @return 简化的UUID去掉了横线
*/
public static String simpleUUID() {
return UUID.randomUUID().toString(true);
}
/**
* 获取随机UUID使用性能更好的ThreadLocalRandom生成UUID
*
* @return 随机UUID
*/
public static String fastUUID() {
return UUID.fastUUID().toString();
}
/**
* 简化的UUID去掉了横线使用性能更好的ThreadLocalRandom生成UUID
*
* @return 简化的UUID去掉了横线
*/
public static String fastSimpleUUID() {
return UUID.fastUUID().toString(true);
}
}

View File

@@ -0,0 +1 @@
cn.fateverse.common.core.utils.SpringContextHolder

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.fateverse</groupId>
<artifactId>common</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>common-decrypt</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cn.fateverse</groupId>
<artifactId>common-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,36 @@
package cn.fateverse.common.decrypt;
import cn.fateverse.common.decrypt.aspect.EncryptAspect;
import cn.fateverse.common.decrypt.config.EncryptProperties;
import cn.fateverse.common.decrypt.service.DefaultEncryptService;
import cn.fateverse.common.decrypt.service.EncryptService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* @author Clay
* @date 2023-07-04
*/
@EnableConfigurationProperties({EncryptProperties.class})
public class DecryptConfiguration {
@Bean
@ConditionalOnMissingBean({EncryptService.class})
public EncryptService encryptService(EncryptProperties encryptProperties) {
return new DefaultEncryptService(encryptProperties);
}
@Bean
@ConditionalOnBean(EncryptService.class)
public EncryptAspect encryptAspect(EncryptService encryptService) {
return new EncryptAspect(encryptService);
}
}

View File

@@ -0,0 +1,15 @@
package cn.fateverse.common.decrypt.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Clay
* @date 2023-07-03
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Encrypt {
}

View File

@@ -0,0 +1,14 @@
package cn.fateverse.common.decrypt.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 定义注解 标记需要加密的字段
*/
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptField {
}

View File

@@ -0,0 +1,156 @@
package cn.fateverse.common.decrypt.aspect;
import cn.fateverse.common.core.exception.CustomException;
import cn.fateverse.common.core.result.Result;
import cn.fateverse.common.decrypt.annotation.EncryptField;
import cn.fateverse.common.decrypt.service.EncryptService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.util.ReflectionUtils;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collection;
import java.util.List;
@Slf4j
@Aspect
public class EncryptAspect {
protected static String BASE_PACKAGE;
static {
String typeName = EncryptAspect.class.getTypeName();
int fastIndex = typeName.indexOf(".");
BASE_PACKAGE = typeName.substring(0, typeName.indexOf(".", fastIndex + 1));
}
private final EncryptService encryptService;
public EncryptAspect(EncryptService encryptService) {
this.encryptService = encryptService;
}
@Around("@annotation(cn.fateverse.common.decrypt.annotation.Encrypt)")
public Object decryptField(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
//获取请求参数
Object[] args = point.getArgs();
//获取方法
Method method = signature.getMethod();
//获取方法参数 Parameter对象集 参数修饰符、参数名、注解及注解类型
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
//获取参数注解
EncryptField encryptField = parameter.getAnnotation(EncryptField.class);
Object arg = args[i];
if (null != encryptField) {
if (arg instanceof String) {
String decrypt = encryptService.decrypt((String) arg);
args[i] = decrypt;
} else if (arg instanceof List) {
try {
List<String> list = (List<String>) arg;
for (int j = 0; j < list.size(); j++) {
String ciphertext = list.get(j);
String decrypt = encryptService.decrypt(ciphertext);
list.set(j, decrypt);
}
args[i] = list;
} catch (Exception e) {
throw new CustomException("接受参数类型错误,请使用String类型的泛型参数");
}
}
} else if (parameter.getType().getName().startsWith(BASE_PACKAGE)) { //返回一个类对象,该类对象标识此参数对象表示的参数的声明类型
decrypt(arg);
}
}
//正常执行业务最后返回的返回值为Result
Object proceed = point.proceed(args);
if (proceed instanceof Result) {
Result<Object> result = (Result<Object>) proceed;
Object data = result.getData();
if (null != data) {
try {
encrypt(data);
} catch (Exception e) {
log.error("加密异常", e);
return Result.error("加密异常!");
}
}
result.setData(data);
} else {
try {
encrypt(proceed);
} catch (Exception e) {
log.error("加密异常", e);
return Result.error("加密异常!");
}
}
return proceed;
}
private void encrypt(Object data) throws Exception {
if (data == null) {
return;
}
Class<?> argClass = data.getClass();
if (argClass.getTypeName().startsWith(BASE_PACKAGE)) {
Field[] fields = argClass.getDeclaredFields();
for (Field field : fields) {
EncryptField encryptField = field.getAnnotation(EncryptField.class);
field.setAccessible(true);
Object value = ReflectionUtils.getField(field, data);
if (null == value) {
continue;
}
if (null != encryptField && value instanceof String) {
String decrypt = encryptService.encrypt((String) value);
ReflectionUtils.setField(field, data, decrypt);
} else if (field.getType().getName().startsWith(BASE_PACKAGE)) {
encrypt(value);
} else if (value instanceof Collection) {
Collection<Object> collection = (Collection<Object>) value;
for (Object item : collection) {
encrypt(item);
}
}
}
} else if (data instanceof Collection) {
Collection<Object> collection = (Collection<Object>) data;
for (Object item : collection) {
encrypt(item);
}
}
}
private void decrypt(Object arg) throws Exception {
Class<?> argClass = arg.getClass();
Field[] fields = argClass.getDeclaredFields();
for (Field field : fields) {
EncryptField encryptField = field.getAnnotation(EncryptField.class);
field.setAccessible(true);
Object value = ReflectionUtils.getField(field, arg);
if (null == value) {
continue;
}
if (null != encryptField && value instanceof String) {
String decrypt = encryptService.decrypt((String) value);
ReflectionUtils.setField(field, arg, decrypt);
} else if (field.getType().getName().startsWith(BASE_PACKAGE)) {
decrypt(value);
}
}
}
}

View File

@@ -0,0 +1,21 @@
package cn.fateverse.common.decrypt.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Clay
* @date 2023-07-04
*/
@ConfigurationProperties(prefix = "encrypt")
public class EncryptProperties {
private String secretKey = "1234567890abcdef";
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
}

View File

@@ -0,0 +1,41 @@
package cn.fateverse.common.decrypt.service;
import cn.fateverse.common.core.exception.CustomException;
import cn.fateverse.common.decrypt.config.EncryptProperties;
import cn.fateverse.common.decrypt.utils.SM4Util;
import javax.annotation.Resource;
/**
* @author Clay
* @date 2023-08-07
*/
public class DefaultEncryptService implements EncryptService {
private final EncryptProperties properties;
public DefaultEncryptService(EncryptProperties properties) {
this.properties = properties;
}
@Override
public String encrypt(String plainText) {
try {
return SM4Util.encrypt(plainText, properties.getSecretKey());
} catch (Exception e) {
throw new CustomException("加密失败", e);
}
}
@Override
public String decrypt(String cipherText) {
try {
return SM4Util.decrypt(cipherText, properties.getSecretKey());
} catch (Exception e) {
throw new CustomException("解密失败", e);
}
}
}

View File

@@ -0,0 +1,24 @@
package cn.fateverse.common.decrypt.service;
/**
* @author Clay
* @date 2024/2/19 16:19
*/
public interface EncryptService {
/**
* 加密方法
*
* @param plainText 需要加密的文档
* @return 加密之后的数据
*/
String encrypt(String plainText);
/**
* 解密方法
*
* @param cipherText 需要解密的文档
* @return 解密之后的文档
*/
String decrypt(String cipherText);
}

View File

@@ -0,0 +1,115 @@
package cn.fateverse.common.decrypt.utils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;
public class SM4Util {
private static final String ALGORITHM_NAME = "SM4";
private static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS7Padding";
private static final String ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS7Padding";
private static final String CHARSET_NAME = "UTF-8";
private static final String IV_PARAMETER = "0000000000000000";
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* SM4 加密
*
* @param plainText 明文
* @param secretKey 密钥
* @return 密文
* @throws Exception 异常
*/
public static String encrypt(String plainText, String secretKey) throws Exception {
byte[] keyBytes = secretKey.getBytes(CHARSET_NAME);
byte[] plainBytes = plainText.getBytes(CHARSET_NAME);
byte[] cipherBytes = encrypt_ECB_Padding(keyBytes, plainBytes);
return new String(Hex.encode(cipherBytes));
}
/**
* SM4 解密
*
* @param cipherText 密文
* @param secretKey 密钥
* @return 明文
* @throws Exception 异常
*/
public static String decrypt(String cipherText, String secretKey) throws Exception {
byte[] keyBytes = secretKey.getBytes(CHARSET_NAME);
byte[] cipherBytes = Hex.decode(cipherText);
byte[] plainBytes = decrypt_ECB_Padding(keyBytes, cipherBytes);
return new String(plainBytes, CHARSET_NAME);
}
/**
* ECB 模式加密
*
* @param keyBytes 密钥
* @param plainBytes 明文
* @return 密文
* @throws Exception 异常
*/
private static byte[] encrypt_ECB_Padding(byte[] keyBytes, byte[] plainBytes) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_ECB_PADDING, BouncyCastleProvider.PROVIDER_NAME);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM_NAME);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
return cipher.doFinal(plainBytes);
}
/**
* ECB 模式解密
*
* @param keyBytes 密钥
* @param cipherBytes 密文
* @return 明文
* @throws Exception 异常
*/
private static byte[] decrypt_ECB_Padding(byte[] keyBytes, byte[] cipherBytes) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_ECB_PADDING, BouncyCastleProvider.PROVIDER_NAME);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM_NAME);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
return cipher.doFinal(cipherBytes);
}
/**
* CBC 模式加密
*
* @param keyBytes 密钥
* @param plainBytes 明文
* @param ivBytes 向量
* @return 密文
* @throws Exception 异常
*/
private static byte[] encrypt_CBC_Padding(byte[] keyBytes, byte[] plainBytes, byte[] ivBytes) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_CBC_PADDING, BouncyCastleProvider.PROVIDER_NAME);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM_NAME);
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
return cipher.doFinal(plainBytes);
}
/**
* CBC 模式解密
*
* @param keyBytes 密钥
* @param cipherBytes 密文
* @param ivBytes 向量
* @return 明文
* @throws Exception 异常
*/
private static byte[] decrypt_CBC_Padding(byte[] keyBytes, byte[] cipherBytes, byte[] ivBytes) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_CBC_PADDING, BouncyCastleProvider.PROVIDER_NAME);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM_NAME); IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); return cipher.doFinal(cipherBytes);
}
}

View File

@@ -0,0 +1 @@
cn.fateverse.common.decrypt.DecryptConfiguration

View File

@@ -0,0 +1,58 @@
<?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>
<artifactId>common</artifactId>
<groupId>cn.fateverse</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-dubbo</artifactId>
<properties>
<dubbo.version>3.0.3</dubbo.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Dubbo Nacos registry dependency -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</exclusion>
<exclusion>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- dubbo 基础依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<!--dubbo sentinel 适配器-->
<!-- <dependency>-->
<!-- <groupId>com.alibaba.csp</groupId>-->
<!-- <artifactId>sentinel-apache-dubbo3-adapter</artifactId>-->
<!-- <version>1.8.6</version>-->
<!-- </dependency>-->
</dependencies>
</project>

View File

@@ -0,0 +1,17 @@
package cn.fateverse.common.dubbo;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
/**
* @author Clay
* @date 2023-08-03
*/
@Activate(group = CommonConstants.PROVIDER)
public class DubboSentinelFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
return invoker.invoke(invocation);
}
}

View File

@@ -0,0 +1 @@
demoProviderFilter=cn.fateverse.common.dubbo.DubboSentinelFilter

View File

@@ -0,0 +1,27 @@
<?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>
<artifactId>common</artifactId>
<groupId>cn.fateverse</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-email</artifactId>
<properties>
<mail.vaersion>1.6.2</mail.vaersion>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>${mail.vaersion}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,31 @@
package cn.fateverse.common.email.config;
import cn.fateverse.common.email.service.EmailService;
import cn.fateverse.common.email.service.impl.EmailServiceImpl;
import cn.fateverse.common.email.service.session.EmailSessionProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
/**
* 邮件配置类
*
* @author Clay
* @date 2023-03-22
*/
@EnableConfigurationProperties({EmailProperties.class})
public class EmailConfiguration {
@Bean
EmailService emailService() {
return new EmailServiceImpl();
}
@Bean
@ConditionalOnMissingBean(EmailSessionProvider.class)
EmailSessionProvider emailSessionProvider() {
return new EmailSessionProvider();
}
}

View File

@@ -0,0 +1,98 @@
package cn.fateverse.common.email.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 系统邮件发送服务器
*
* @author Clay
* @date 2023-03-22
*/
@ConfigurationProperties(prefix = "email")
public class EmailProperties {
/**
* 邮件服务器发送者邮箱
*/
private String sender;
/**
* 发送人名称
*/
private String personal;
/**
* 邮件服务器
*/
private String emailSmtpHost;
/**
* 邮件服务器端口
*/
private String emailSmtpPort;
/**
* 邮件发送者用户名
*/
private String username;
/**
* 发送者密码
*/
private String password;
/**
* 邮件服务器协议
*/
private String encryption;
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getPersonal() {
return personal;
}
public void setPersonal(String personal) {
this.personal = personal;
}
public String getEmailSmtpHost() {
return emailSmtpHost;
}
public void setEmailSmtpHost(String emailSmtpHost) {
this.emailSmtpHost = emailSmtpHost;
}
public String getEmailSmtpPort() {
return emailSmtpPort;
}
public void setEmailSmtpPort(String emailSmtpPort) {
this.emailSmtpPort = emailSmtpPort;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEncryption() {
return encryption;
}
public void setEncryption(String encryption) {
this.encryption = encryption;
}
}

View File

@@ -0,0 +1,93 @@
package cn.fateverse.common.email.entity;
import java.util.List;
/**
* 邮件发送对象
*
* @author Clay
* @date 2023-03-22
*/
public class SendEmailInfo {
/**
* 邮件主题
*/
private String subject;
/**
* 发送对象
*/
private List<String> senders;
/**
* 抄送对象
*/
private List<String> ccPersons;
/**
* 邮件内容
*/
private String content;
/**
* 主题
*/
private String ThemeEnums;
public SendEmailInfo() {
}
public SendEmailInfo(String subject, List<String> senders, List<String> ccPersons, String content) {
this.subject = subject;
this.senders = senders;
this.ccPersons = ccPersons;
this.content = content;
}
public SendEmailInfo(String subject, List<String> senders, List<String> ccPersons, String content, String themeEnums) {
this.subject = subject;
this.senders = senders;
this.ccPersons = ccPersons;
this.content = content;
ThemeEnums = themeEnums;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public List<String> getSenders() {
return senders;
}
public void setSenders(List<String> senders) {
this.senders = senders;
}
public List<String> getCcPersons() {
return ccPersons;
}
public void setCcPersons(List<String> ccPersons) {
this.ccPersons = ccPersons;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getThemeEnums() {
return ThemeEnums;
}
public void setThemeEnums(String themeEnums) {
ThemeEnums = themeEnums;
}
}

View File

@@ -0,0 +1,15 @@
package cn.fateverse.common.email.enums;
/**
* 主题枚举
*
* @author Clay
* @date 2023-03-22
*/
public enum ThemeEnums {
/**
* 主题枚举
*/
DEFAULT,
;
}

View File

@@ -0,0 +1,25 @@
package cn.fateverse.common.email.service;
import cn.fateverse.common.email.entity.SendEmailInfo;
/**
* @author Clay
* @date 2023-03-22
*/
public interface EmailService {
/**
* 同步发送邮件
*
* @param email 邮件信息
* @return 发送结果
*/
boolean sendMail(SendEmailInfo email);
/**
* 异步发送邮件
*
* @param email 邮件信息
*/
void asyncSendMail(SendEmailInfo email);
}

View File

@@ -0,0 +1,88 @@
package cn.fateverse.common.email.service.impl;
import cn.fateverse.common.email.service.session.EmailSessionProvider;
import cn.fateverse.common.email.entity.SendEmailInfo;
import cn.fateverse.common.email.service.EmailService;
import cn.fateverse.common.email.config.EmailProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.UnsupportedEncodingException;
import java.util.Date;
/**
* 邮件服务默认实现
*
* @author Clay
* @date 2023-03-22
*/
@Service
public class EmailServiceImpl implements EmailService {
@Autowired
private EmailProperties properties;
@Autowired
private EmailSessionProvider sessionProvider;
@Override
public boolean sendMail(SendEmailInfo email) {
Session session = sessionProvider.getSession();
// 创建默认的 MimeMessage 对象
MimeMessage message = new MimeMessage(session);
Transport transport = null;
try {
message.setSubject(email.getSubject());
message.setFrom(new InternetAddress(properties.getSender(), properties.getPersonal(), "UTF-8"));
InternetAddress[] senders = new InternetAddress[email.getSenders().size()];
for (int i = 0; i < email.getSenders().size(); i++) {
senders[i] = new InternetAddress(email.getSenders().get(i));
}
message.addRecipients(Message.RecipientType.TO, senders);
if (null != email.getCcPersons() && !email.getCcPersons().isEmpty()) {
InternetAddress[] ccSenders = new InternetAddress[email.getCcPersons().size()];
for (int i = 0; i < email.getCcPersons().size(); i++) {
ccSenders[i] = new InternetAddress(email.getCcPersons().get(i));
}
message.addRecipients(Message.RecipientType.CC, ccSenders);
}
message.setContent(email.getContent(), "text/html;charset=UTF-8");
//new InternetAddress()
message.setSentDate(new Date());
message.saveChanges();
session.setDebug(false);
transport = session.getTransport();
transport.connect();
transport.sendMessage(message, message.getAllRecipients());
// 7. 关闭连接
} catch (MessagingException | UnsupportedEncodingException e) {
e.printStackTrace();
return false;
} finally {
try {
assert transport != null;
transport.close();
} catch (MessagingException e) {
e.printStackTrace();
}
}
return true;
}
@Async
@Override
public void asyncSendMail(SendEmailInfo email) {
sendMail(email);
}
}

View File

@@ -0,0 +1,53 @@
package cn.fateverse.common.email.service.session;
import cn.fateverse.common.email.config.EmailProperties;
import org.springframework.beans.factory.annotation.Autowired;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import java.util.Properties;
/**
* 邮件发送Session获取
*
* @author Clay
* @date 2023-03-22
*/
public class EmailSessionProvider {
@Autowired
private EmailProperties properties;
private volatile Session session;
public Session getSession() {
if (session == null) {
synchronized (this) {
if (session == null) {
// 参数配置
Properties props = new Properties();
// 使用的协议JavaMail规范要求
props.setProperty("mail.transport.protocol", "smtp");
// 发件人的邮箱的 SMTP 服务器地址
props.setProperty("mail.smtp.host", properties.getEmailSmtpHost());
//发件人的邮箱的 SMTP 服务器端口
props.setProperty("mail.smtp.port", properties.getEmailSmtpPort());
// 需要请求认证
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.setProperty("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.socketFactory.port", properties.getEmailSmtpPort());
session = Session.getDefaultInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(properties.getUsername(), properties.getPassword());
}
});
}
}
}
return session;
}
}

View File

@@ -0,0 +1,46 @@
{
"groups": [
{
"name": "email",
"type": "cn.fateverse.email.config.EMailProperties",
"sourceType": "cn.fateverse.email.config.EMailProperties"
}
],
"properties": [
{
"name": "email.sender",
"type": "java.lang.String",
"sourceType": "cn.fateverse.email.config.EMailProperties"
},
{
"name": "email.personal",
"type": "java.lang.String",
"sourceType": "cn.fateverse.email.config.EMailProperties"
},
{
"name": "email.emailSmtpHost",
"type": "java.lang.String",
"sourceType": "cn.fateverse.email.config.EMailProperties"
},
{
"name": "email.emailSmtpPort",
"type": "java.lang.String",
"sourceType": "cn.fateverse.email.config.EMailProperties"
},
{
"name": "email.username",
"type": "java.lang.String",
"sourceType": "cn.fateverse.email.config.EMailProperties"
},
{
"name": "email.password",
"type": "java.lang.String",
"sourceType": "cn.fateverse.email.config.EMailProperties"
},
{
"name": "email.encryption",
"type": "java.lang.String",
"sourceType": "cn.fateverse.email.config.EMailProperties"
}
]
}

View File

@@ -0,0 +1 @@
cn.fateverse.common.email.config.EmailConfiguration

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.fateverse</groupId>
<artifactId>common</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>common-excel</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cn.fateverse</groupId>
<artifactId>admin-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version>
</dependency>
<dependency>
<groupId>cn.fateverse</groupId>
<artifactId>common-core</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>compile</scope>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,23 @@
package cn.fateverse.common.excel;
import cn.fateverse.common.excel.service.ExcelService;
import org.springframework.context.annotation.Bean;
/**
* @author Clay
* @date 2023-11-10 20:18
*/
public class ExcelAutoConfiguration {
/**
* Excel导出时字典对接服务等
*
* @return excelService
*/
@Bean
public ExcelService excelService() {
return new ExcelService();
}
}

View File

@@ -0,0 +1,28 @@
package cn.fateverse.common.excel.service;
import cn.fateverse.admin.dubbo.DubboDictDataService;
import cn.fateverse.admin.vo.DictDataVo;
import org.apache.dubbo.config.annotation.DubboReference;
import java.util.List;
import java.util.Map;
/**
* @author Clay
* @date 2023-02-20
*/
public class ExcelService {
@DubboReference
private DubboDictDataService dictDataService;
public DubboDictDataService getDictDataService() {
return dictDataService;
}
public Map<String, Map<String, DictDataVo>> searchDictDataCacheKeys(List<String> cacheKeys){
return dictDataService.searchDictDataCacheKeys(cacheKeys);
}
}

View File

@@ -0,0 +1,47 @@
package cn.fateverse.common.excel.utils;
import cn.fateverse.common.core.annotaion.Excel;
import cn.fateverse.common.core.annotaion.Excels;
import lombok.Data;
import java.lang.reflect.Field;
/**
* @author Clay
* @date 2022/12/19
*/
@Data
public class ExcelAssist {
private Field field;
private Excel excel;
private Excels excels;
private int order;
private String objectFieldName;
public ExcelAssist(Field field, Excels excels) {
this.field = field;
this.objectFieldName = field.getName();
this.excels = excels;
order = excels.order();
}
public ExcelAssist(Field field, Excel excel, ExcelAssist assist) {
this.field = field;
this.excel = excel;
if (null != assist) {
this.objectFieldName = assist.objectFieldName;
if (excel.order() != Integer.MAX_VALUE && assist.getExcels().order() != Integer.MAX_VALUE) {
order = assist.getExcels().order() * 10 + excel.order();
} else {
order = excel.order();
}
} else {
order = excel.order();
}
}
}

View File

@@ -0,0 +1,206 @@
package cn.fateverse.common.excel.utils;
import cn.fateverse.common.excel.service.ExcelService;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.fateverse.admin.vo.DictDataVo;
import cn.fateverse.common.core.exception.CustomException;
import cn.fateverse.common.core.utils.HttpServletUtils;
import cn.fateverse.common.core.utils.SpringContextHolder;
import cn.fateverse.common.core.annotaion.Excel;
import cn.fateverse.common.core.annotaion.Excels;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
import org.springframework.util.ReflectionUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Clay
* @date 2022/12/19
*/
public class ExcelUtil {
private static final Map<Class<?>, ExcelAssistWrapper> wrapperMap = new ConcurrentHashMap<>(8);
private static Map<String, Map<String, DictDataVo>> dictDataMap;
private static ExcelService getBean() {
return SpringContextHolder.getBean(ExcelService.class);
}
/**
* 获取到数据列表
*
* @param list
* @return
*/
private static List<List<Object>> getDataList(List<?> list, List<ExcelAssist> assistList) {
return list.stream().map(object ->
assistList.stream().map(assist -> {
Field field = assist.getField();
field.setAccessible(true);
Excel excel = assist.getExcel();
Object value = null;
if (StrUtil.isEmpty(assist.getObjectFieldName())) {
value = getData(object, excel, field);
} else {
Object sunValue = null;
try {
sunValue = ReflectionUtils.getField(field, object);
} catch (Exception e) {
return null;
}
if (null != sunValue) {
value = getData(object, excel, field);
}
}
return value;
}).collect(Collectors.toList())
).collect(Collectors.toList());
}
/**
* 获取到对象中的数据
*
* @param object
* @param excel
* @param field
* @return
*/
private static Object getData(Object object, Excel excel, Field field) {
try {
Object objectValue = ReflectionUtils.getField(field, object);
if (objectValue instanceof Date) {
objectValue = DateUtil.format((Date) objectValue, excel.dateFormat());
}
String dictType = excel.dictType();
if (!StrUtil.isEmpty(dictType)) {
Map<String, DictDataVo> dictMap = dictDataMap.get(dictType);
if (null != dictMap) {
DictDataVo dictData = dictMap.get(objectValue.toString());
if (null != dictData) {
objectValue = dictData.getDictLabel();
}
}
}
return objectValue;
} catch (Exception e) {
return null;
}
}
/**
* 初始化header数据
*
* @param clazz
* @param assist
*/
private static void initHeader(Class<?> clazz, ExcelAssist assist, List<ExcelAssist> assistList) {
for (Field field : clazz.getDeclaredFields()) {
Excel excel = field.getAnnotation(Excel.class);
if (null != excel) {
assistList.add(new ExcelAssist(field, excel, assist));
} else {
Excels excels = field.getAnnotation(Excels.class);
if (excels == null) {
continue;
}
Class<?> objectValue = field.getType();
if (clazz == objectValue) {
throw new CustomException("不允许嵌套对象导出Excel");
}
ExcelAssist excelAssist = new ExcelAssist(field, excels);
initHeader(objectValue, excelAssist, assistList);
}
}
}
public static void exportExcel(List<?> list, Class<?> clazz) {
exportExcel(list, clazz, null);
}
/**
* 导出数据Excel
*
* @param list
* @param clazz
* @param sheetName
*/
public static void exportExcel(List<?> list, Class<?> clazz, String sheetName) {
Set<String> dictList = new HashSet<>();
ExcelAssistWrapper wrapper = wrapperMap.get(clazz);
if (wrapper == null) {
synchronized (wrapperMap) {
wrapper = wrapperMap.get(clazz);
if (wrapper == null) {
wrapper = new ExcelAssistWrapper();
List<ExcelAssist> assistList = new ArrayList<>();
initHeader(clazz, null, assistList);
List<List<String>> headerList = new ArrayList<>(assistList.size());
assistList = assistList.stream().sorted(Comparator.comparing(ExcelAssist::getOrder))
.peek(assist -> headerList.add(Collections.singletonList(assist.getExcel().value())))
.peek(assist -> {
String dictType = assist.getExcel().dictType();
if (!StrUtil.isEmpty(dictType)) {
dictList.add(dictType);
}
})
.collect(Collectors.toList());
wrapper.assistList = assistList;
wrapper.headerList = headerList;
wrapperMap.put(clazz, wrapper);
}
}
}
if (dictList.size() > 0) {
getDictData(new ArrayList<>(dictList));
}
List<List<Object>> dataList = getDataList(list, wrapper.assistList);
try {
sheetName = StrUtil.isEmpty(sheetName) ? "sheet" : sheetName;
HttpServletResponse response = getResponse(sheetName);
EasyExcel.write(response.getOutputStream())
.head(wrapper.headerList)
.excelType(ExcelTypeEnum.XLSX)
.sheet(StrUtil.isEmpty(sheetName) ? "sheet" : sheetName)
.doWrite(dataList);
} catch (IOException e) {
throw new CustomException("Excel导出失败!");
}
}
private static HttpServletResponse getResponse(String sheetName) {
HttpServletResponse response = HttpServletUtils.getResponse();
response.setCharacterEncoding("utf-8");
response.setContentType("multipart/form-data");
response.setHeader("Content-Disposition",
"attachment;fileName=" + sheetName + UUID.randomUUID() + ".xlsx");
return response;
}
private static void getDictData(List<String> dictList) {
ExcelService dictDataService = getBean();
Map<String, Map<String, DictDataVo>> result = dictDataService.searchDictDataCacheKeys(dictList);
if (null != result) {
System.out.println(result.toString());
dictDataMap = result;
}
}
private static class ExcelAssistWrapper {
private List<ExcelAssist> assistList;
List<List<String>> headerList;
}
}

View File

@@ -0,0 +1 @@
cn.fateverse.common.excel.ExcelAutoConfiguration

114
common/common-file/pom.xml Normal file
View File

@@ -0,0 +1,114 @@
<?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>
<artifactId>common</artifactId>
<groupId>cn.fateverse</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-file</artifactId>
<properties>
<ftp.version>3.8.0</ftp.version>
<okhttp.version>4.9.3</okhttp.version>
<fastdfs.version>1.27.2</fastdfs.version>
<aliyun.oss.version>3.8.0</aliyun.oss.version>
<huawei.obs.version>3.22.3.1</huawei.obs.version>
<thumbnailator.version>0.4.8</thumbnailator.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!--阿里云oss-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun.oss.version}</version>
</dependency>
<!-- 华为云 OBS -->
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java</artifactId>
<version>${huawei.obs.version}</version>
</dependency>
<!-- MinIO -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.4.3</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>2.8.0</version>
</dependency>
<!-- FTP上传文件 -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>${ftp.version}</version>
</dependency>
<!-- FastDFS对象存储 -->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>${fastdfs.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Common Core 核心依赖 -->
<dependency>
<groupId>cn.fateverse</groupId>
<artifactId>common-core</artifactId>
</dependency>
<!-- Apache io -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
<optional>true</optional>
</dependency>
<!--图片处理工具,处理缩略图-->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>${thumbnailator.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,36 @@
package cn.fateverse.common.file.config;
import cn.fateverse.common.file.service.AliyunFileService;
import cn.fateverse.common.file.service.client.AliyunClient;
import cn.fateverse.common.file.service.client.AliyunClientProvider;
import cn.fateverse.common.file.service.impl.AliyunFileStoreService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
/**
* 阿里云oss 自动装配
*
* @author Clay
* @date 2023-02-17
*/
@EnableConfigurationProperties({AliyunProperties.class})
public class AliyunAutoConfiguration {
@Bean
public AliyunFileService aliyunFileService() {
return new AliyunFileService();
}
@Bean
@ConditionalOnMissingBean(AliyunClientProvider.class)
public AliyunClientProvider aliyunClient() {
return new AliyunClient();
}
@Bean("aliyunFileStoreService")
public AliyunFileStoreService aliyunFileStoreService(AliyunFileService aliyunFileService) {
return new AliyunFileStoreService(aliyunFileService);
}
}

View File

@@ -0,0 +1,60 @@
package cn.fateverse.common.file.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 阿里云 配置文件信息
*
* @author Clay
* @date 2023/1/10
*/
@ConfigurationProperties(prefix = "file.store.aliyun")
public class AliyunProperties {
/**
* 地域节点
*/
private String endpoint;
private String accessKeyId;
private String secretAccessKey;
/**
* OSS的Bucket名称
*/
private String bucket;
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getBucket() {
return bucket;
}
public void setBucket(String bucket) {
this.bucket = bucket;
}
public String getAccessKeyId() {
return accessKeyId;
}
public void setAccessKeyId(String accessKeyId) {
this.accessKeyId = accessKeyId;
}
public String getSecretAccessKey() {
return secretAccessKey;
}
public void setSecretAccessKey(String secretAccessKey) {
this.secretAccessKey = secretAccessKey;
}
}

View File

@@ -0,0 +1,35 @@
package cn.fateverse.common.file.config;
import cn.fateverse.common.file.service.FTPFileService;
import cn.fateverse.common.file.service.client.FTPClientProvider;
import cn.fateverse.common.file.service.impl.FTPFileStoreService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
/**
* FTP 自动装配
*
* @author Clay
* @date 2023-03-15
*/
@EnableConfigurationProperties({FTPProperties.class})
public class FTPAutoConfiguration {
@Bean
public FTPFileService ftpFileService() {
return new FTPFileService();
}
@Bean
@ConditionalOnMissingBean(FTPClientProvider.class)
public FTPClientProvider ftpClient() {
return new FTPClientProvider();
}
@Bean("ftpFileStoreService")
public FTPFileStoreService ftpFileStoreService(FTPFileService ftpFileService) {
return new FTPFileStoreService(ftpFileService);
}
}

View File

@@ -0,0 +1,94 @@
package cn.fateverse.common.file.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* FTP 配置信息
*
* @author Clay
* @date 2023-03-15
*/
@ConfigurationProperties(prefix = "file.store.ftp")
public class FTPProperties {
//服务器地址
private String address;
//端口号
private Integer port;
//用户名
private String username;
//密码
private String password;
//字符集编码
private String encoding;
//资源地址
private String asset;
//公开目录
private String pubfiles;
//保护目录
private String prifiles;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEncoding() {
return encoding;
}
public void setEncoding(String encoding) {
this.encoding = encoding;
}
public String getAsset() {
return asset;
}
public void setAsset(String asset) {
this.asset = asset;
}
public String getPubfiles() {
return pubfiles;
}
public void setPubfiles(String pubfiles) {
this.pubfiles = pubfiles;
}
public String getPrifiles() {
return prifiles;
}
public void setPrifiles(String prifiles) {
this.prifiles = prifiles;
}
}

View File

@@ -0,0 +1,21 @@
package cn.fateverse.common.file.config;
import cn.fateverse.common.file.service.impl.FastDFSStoreService;
import com.github.tobato.fastdfs.FdfsClientConfig;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.support.RegistrationPolicy;
@Import(FdfsClientConfig.class)
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
@EnableConfigurationProperties({FastDFSProperties.class})
public class FastDFSAutoConfiguration {
@Bean("fastDFSStoreService")
public FastDFSStoreService fastDFSStoreService(){
return new FastDFSStoreService();
}
}

View File

@@ -0,0 +1,20 @@
package cn.fateverse.common.file.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.ObjectUtils;
@ConfigurationProperties(prefix = "fdfs")
public class FastDFSProperties {
private String bucket;
public String getBucket() {
return ObjectUtils.isEmpty(bucket) ? "group1" : bucket;
}
public void setBucket(String bucket) {
this.bucket = bucket;
}
}

View File

@@ -0,0 +1,9 @@
package cn.fateverse.common.file.config;
/**
* 华为 OBS 配置信息
* @author Clay
* @date 2023-03-17
*/
public class HuaweiOBSProperties {
}

View File

@@ -0,0 +1,37 @@
package cn.fateverse.common.file.config;
import cn.fateverse.common.file.service.MinioFileService;
import cn.fateverse.common.file.service.client.MinIoClient;
import cn.fateverse.common.file.service.client.MinioClientProvider;
import cn.fateverse.common.file.service.impl.MinioFileStoreService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
/**
* minio 自动装配
*
* @author Clay
* @date 2023-02-17
*/
@EnableConfigurationProperties({MinioProperties.class})
public class MinioAutoConfiguration {
@Bean
public MinioFileService minioFileService() {
return new MinioFileService();
}
@Bean
@ConditionalOnMissingBean(MinioClientProvider.class)
public MinioClientProvider minioClient() {
return new MinIoClient();
}
@Bean("minioFileStoreService")
public MinioFileStoreService minioFileStoreService(MinioFileService minioFileService) {
return new MinioFileStoreService(minioFileService);
}
}

View File

@@ -0,0 +1,49 @@
package cn.fateverse.common.file.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* minio 配置信息
*
* @author Clay
* @date 2023-02-17
*/
@ConfigurationProperties(prefix = "file.store.minio")
public class MinioProperties {
private String endpoint;
private String bucket;
private String accessKey;
private String secretKey;
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getBucket() {
return bucket;
}
public void setBucket(String bucket) {
this.bucket = bucket;
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
}

View File

@@ -0,0 +1,57 @@
package cn.fateverse.common.file.entity;
import lombok.Builder;
import lombok.Data;
/**
* @author Clay
* @date 2023/1/10
*/
@Data
@Builder
public class FileInfo {
/**
* 文件名称
*/
private String fileName;
/**
* 缩略图名称
*/
private String thumbnailFileName;
/**
* 文件原始名称
*/
private String originalFilename;
/**
* 文件url
*/
private String url;
/**
* 资源路径
*/
private String uri;
/**
* 缩略图uri
*/
private String thumbnailUri;
/**
* 路径
*/
private String path;
/**
* 文件类型
*/
private String fileType;
/**
* 文件大小
*/
private Long size;
/**
* 是否是图片
*/
private Boolean isImage;
private String contentType;
}

View File

@@ -0,0 +1,37 @@
package cn.fateverse.common.file.enums;
import cn.fateverse.common.file.service.FileStoreService;
import cn.fateverse.common.file.service.impl.AliyunFileStoreService;
import cn.fateverse.common.file.service.impl.FTPFileStoreService;
import cn.fateverse.common.file.service.impl.MinioFileStoreService;
/**
* @author Clay
* @date 2023-02-16
*/
public enum FTLStoreServiceEnum {
/**
* 阿里云 oss 实现
*/
ALIYUN_OSS(AliyunFileStoreService.class),
/**
* minio 对象存储 实现
*/
MINIO_FILE(MinioFileStoreService.class),
/**
* FTP 文件传输 实现
*/
FTP_FILE(FTPFileStoreService.class),
;
private final Class<? extends FileStoreService> type;
FTLStoreServiceEnum(Class<? extends FileStoreService> type) {
this.type = type;
}
public Class<? extends FileStoreService> getType() {
return type;
}
}

Some files were not shown because too many files have changed in this diff Show More