核心模块
This commit is contained in:
parent
402ac5340d
commit
84d5e8fe13
@ -1,6 +1,6 @@
|
||||
package com.cpop.common.utils;
|
||||
|
||||
import com.pupu.common.enums.CycleEnum;
|
||||
import com.cpop.common.enums.CycleEnum;
|
||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.cpop.common.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.pupu.common.utils.text.Convert;
|
||||
import com.cpop.common.utils.text.Convert;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.cpop.common.utils;
|
||||
|
||||
import com.pupu.common.constant.Constants;
|
||||
import com.pupu.common.utils.text.StrFormatter;
|
||||
import com.cpop.common.constant.Constants;
|
||||
import com.cpop.common.utils.text.StrFormatter;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.cpop.common.utils.html;
|
||||
|
||||
|
||||
import com.pupu.common.utils.StringUtils;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* 转义和反转义工具类
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.cpop.common.utils.http;
|
||||
|
||||
import com.pupu.common.constant.Constants;
|
||||
import com.pupu.common.utils.StringUtils;
|
||||
import com.cpop.common.constant.Constants;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package com.cpop.common.utils.ip;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.pupu.common.constant.Constants;
|
||||
import com.pupu.common.utils.StringUtils;
|
||||
import com.pupu.common.utils.http.HttpUtils;
|
||||
import com.cpop.common.constant.Constants;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.cpop.common.utils.http.HttpUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.cpop.common.utils.ip;
|
||||
|
||||
import com.pupu.common.utils.StringUtils;
|
||||
import com.pupu.common.utils.html.EscapeUtil;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.cpop.common.utils.html.EscapeUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.InetAddress;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.cpop.common.utils.text;
|
||||
|
||||
import com.pupu.common.utils.StringUtils;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.cpop.common.utils.text;
|
||||
|
||||
import com.pupu.common.utils.StringUtils;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.cpop.common.utils.text;
|
||||
|
||||
import com.pupu.common.utils.StringUtils;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* 字符串格式化
|
||||
|
||||
62
Cpop-Core/pom.xml
Normal file
62
Cpop-Core/pom.xml
Normal file
@ -0,0 +1,62 @@
|
||||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.cpop</groupId>
|
||||
<artifactId>Cpop-Union</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>Cpop-Core</artifactId>
|
||||
<name>Cpop-Core</name>
|
||||
<description>核心包</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!--Cpop公共包-->
|
||||
<dependency>
|
||||
<groupId>com.cpop</groupId>
|
||||
<artifactId>Cpop-Common</artifactId>
|
||||
</dependency>
|
||||
<!--AOP-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<!--Mybatis-flex-->
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-processor</artifactId>
|
||||
</dependency>
|
||||
<!--Security-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<!--Redis-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<!--redis分布式锁依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-integration</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-redis</artifactId>
|
||||
</dependency>
|
||||
<!--easyExcel-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
100
Cpop-Core/sql/System.sql
Normal file
100
Cpop-Core/sql/System.sql
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
Navicat Premium Data Transfer
|
||||
|
||||
Source Server : Localhost
|
||||
Source Server Type : MySQL
|
||||
Source Server Version : 80032
|
||||
Source Host : localhost:3306
|
||||
Source Schema : pupu-union
|
||||
|
||||
Target Server Type : MySQL
|
||||
Target Server Version : 80032
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 15/09/2023 15:03:53
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for pp_sys_config
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `cp_sys_config`;
|
||||
CREATE TABLE `cp_sys_config` (
|
||||
`config_key` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '参数键',
|
||||
`config_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '参数名',
|
||||
`config_value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '参数值',
|
||||
`config_type` tinyint(1) NULL DEFAULT NULL COMMENT '系统内置(0否1是)',
|
||||
`remarks` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '备注',
|
||||
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
|
||||
`create_user_id` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人id',
|
||||
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
|
||||
`update_user_id` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人id',
|
||||
PRIMARY KEY (`config_key`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统配置表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of pp_sys_config
|
||||
-- ----------------------------
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for pp_sys_operation_log
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `cp_sys_operation_log`;
|
||||
CREATE TABLE `cp_sys_operation_log` (
|
||||
`id` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID',
|
||||
`operation_user_id` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户ID',
|
||||
`operation_user_name` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作用户',
|
||||
`operation_user_type` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户类型',
|
||||
`code` int(0) NULL DEFAULT NULL COMMENT '操作码',
|
||||
`info` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作信息',
|
||||
`dev_ip` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作终端的IP地址',
|
||||
`result` tinyint(1) NULL DEFAULT NULL COMMENT '结果 0:失败 1:成功',
|
||||
`level` int(0) NULL DEFAULT NULL COMMENT '日志级别,0-提示,1-一般,2-危险,3-高危',
|
||||
`action_type` int(0) NULL DEFAULT NULL COMMENT '行为类别,1-一般行为,2-异常行为',
|
||||
`fail_reason` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '失败原因',
|
||||
`description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '操作描述',
|
||||
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
|
||||
`create_user_id` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人id',
|
||||
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
|
||||
`update_user_id` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人id',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '操作日志表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of pp_sys_operation_log
|
||||
-- ----------------------------
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for pp_sys_user
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `cp_sys_user`;
|
||||
CREATE TABLE `cp_sys_user` (
|
||||
`id` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
|
||||
`user_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名',
|
||||
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码',
|
||||
`nick_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '昵称',
|
||||
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱',
|
||||
`phone_number` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号',
|
||||
`sex` tinyint(1) NULL DEFAULT NULL COMMENT '性别(0:男;1:女)',
|
||||
`avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '头像',
|
||||
`salt` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '盐',
|
||||
`status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0:停用;1:启用)',
|
||||
`login_ip` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '登录地IP',
|
||||
`user_type` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户类型',
|
||||
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
|
||||
`create_user_id` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人id',
|
||||
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
|
||||
`update_user_id` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人id',
|
||||
`is_delete` tinyint(1) NULL DEFAULT 0 COMMENT '逻辑删除(0否1是)',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `uni_user_name_type`(`user_name`, `user_type`) USING BTREE COMMENT '用户名和用户类型联合唯一'
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统用户' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of pp_sys_user
|
||||
-- ----------------------------
|
||||
INSERT INTO `cp_sys_user` VALUES ('1', 'Cpop', '$2a$10$6CA0M3iyO8u8zSVtmufYGO3KfLvjaE5fxdHCqTQ2NpxYH/Dxi/fBu', 'SuperAdmin', 'cpop@qq.com', '18900000000', 1, NULL, '$2a$10$6CA0M3iyO8u8zSVtmufYGO', 1, '127.0.0.1', 'OAM_USER', '2022-10-01 19:26:49', '1', '2023-08-24 17:47:30', '1', 0);
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
@ -0,0 +1,21 @@
|
||||
package com.cpop.core.annontation;
|
||||
|
||||
import com.cpop.core.base.enums.OperationLogEnum;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author: DB
|
||||
* @date: 2022-08-12 9:41
|
||||
* @Description: 操作日志注解
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD})
|
||||
@Documented
|
||||
public @interface OperationLog {
|
||||
|
||||
/**
|
||||
* 操作枚举
|
||||
*/
|
||||
OperationLogEnum operationLogEnumType();
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.cpop.core.annontation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.cpop.core.strategy.ArrayToStringDeserializer;
|
||||
import com.cpop.core.strategy.StringToArraySerializer;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 数组和逗号拼接转换注解
|
||||
* @author DB
|
||||
*/
|
||||
@Documented
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@JacksonAnnotationsInside
|
||||
@JsonSerialize(using = StringToArraySerializer.class)
|
||||
@JsonDeserialize(using = ArrayToStringDeserializer.class)
|
||||
public @interface StringArrayConvert {
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
package com.cpop.core.aspect;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.cpop.common.constant.HttpStatus;
|
||||
import com.cpop.common.enums.ErrorCodeEnum;
|
||||
import com.cpop.core.base.R;
|
||||
import com.cpop.core.base.entity.LoginUser;
|
||||
import com.cpop.core.base.enums.OperationLogEnum;
|
||||
import com.cpop.core.base.exception.ServiceException;
|
||||
import com.cpop.core.base.table.SysOperationLog;
|
||||
import com.cpop.core.event.OperationLogEvent;
|
||||
import com.cpop.core.utils.MessageUtils;
|
||||
import com.cpop.core.utils.SecurityUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.*;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author: DB
|
||||
* @date: 2022-08-12 9:45
|
||||
* @Description:
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
public class OperationLogAspect {
|
||||
|
||||
private final SysOperationLog operationLog = new SysOperationLog();
|
||||
|
||||
private OperationLogEnum operationLogEnum;
|
||||
|
||||
/**
|
||||
* 事件发布是由ApplicationContext对象管控的,我们发布事件前需要注入ApplicationContext对象调用publishEvent方法完成事件发布
|
||||
*/
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* 定义controller切入点拦截规则,拦截SysLog注解的方法
|
||||
*/
|
||||
@Pointcut("@annotation(com.cpop.core.annontation.OperationLog)")
|
||||
public void operationLogAspect() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param joinPoint 切入点
|
||||
* @author LOST.yuan
|
||||
* @Description: 拦截控制层的操作日志
|
||||
* @date 16:37 2022/10/12
|
||||
**/
|
||||
@Before(value = "operationLogAspect()")
|
||||
public void recordLog(JoinPoint joinPoint) {
|
||||
//设置枚举信息
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
com.cpop.core.annontation.OperationLog annotation = signature.getMethod().getAnnotation(com.cpop.core.annontation.OperationLog.class);
|
||||
operationLogEnum = annotation.operationLogEnumType();
|
||||
try {
|
||||
LoginUser loginUser = SecurityUtils.getInstance().getLoginUser();
|
||||
operationLog.setOperationUserName(loginUser.getUsername())
|
||||
.setOperationUserId(loginUser.getUserId())
|
||||
.setOperationUserType(loginUser.getUserType())
|
||||
.setDevIp(loginUser.getIpAddr())
|
||||
.setCode(operationLogEnum.getCode())
|
||||
.setInfo(MessageUtils.message(operationLogEnum.getInfo()))
|
||||
.setCreateUserId(loginUser.getUserId());
|
||||
operationLog.setUpdateUserId(loginUser.getUserId());
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException(ErrorCodeEnum.OPERATION_LOG_EXCEPTION.getInfo(), ErrorCodeEnum.OPERATION_LOG_EXCEPTION.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ret 返回
|
||||
* @author LOST.yuan
|
||||
* @Description 返回通知
|
||||
* @date 16:43 2022/10/12
|
||||
**/
|
||||
@AfterReturning(returning = "ret", pointcut = "operationLogAspect()")
|
||||
public void doAfterReturning(Object ret) {
|
||||
// 处理完请求,返回内容
|
||||
R r = new ObjectMapper().convertValue(ret, R.class);
|
||||
operationLog.setActionType(1);
|
||||
if (r.getCode() == HttpStatus.SUCCESS) {
|
||||
// 正常返回
|
||||
operationLog.setResult(true);
|
||||
operationLog.setLevel(operationLogEnum.getSuccessLevel());
|
||||
operationLog.setDescription(MessageUtils.message(operationLogEnum.getInfo()) + "成功");
|
||||
} else {
|
||||
operationLog.setResult(false);
|
||||
operationLog.setFailReason(r.getMsg());
|
||||
operationLog.setLevel(operationLogEnum.getExceptionLevel());
|
||||
operationLog.setDescription(MessageUtils.message(operationLogEnum.getInfo()) + "失败");
|
||||
}
|
||||
// 发布事件
|
||||
applicationContext.publishEvent(new OperationLogEvent(operationLog));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param e 异常
|
||||
* @author LOST.yuan
|
||||
* @Description 异常通知
|
||||
* @date 16:37 2022/10/12
|
||||
**/
|
||||
@AfterThrowing(pointcut = "operationLogAspect()", throwing = "e")
|
||||
public void doAfterThrowable(Throwable e) {
|
||||
// 异常
|
||||
operationLog.setResult(false)
|
||||
.setActionType(2)
|
||||
.setFailReason(e.getMessage())
|
||||
.setDescription(MessageUtils.message(operationLogEnum.getInfo()) + "异常")
|
||||
.setLevel(operationLogEnum.getExceptionLevel());
|
||||
// 发布事件
|
||||
applicationContext.publishEvent(new OperationLogEvent(operationLog));
|
||||
}
|
||||
|
||||
}
|
||||
95
Cpop-Core/src/main/java/com/cpop/core/base/R.java
Normal file
95
Cpop-Core/src/main/java/com/cpop/core/base/R.java
Normal file
@ -0,0 +1,95 @@
|
||||
package com.cpop.core.base;
|
||||
|
||||
import com.cpop.common.constant.Constants;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 响应信息主体
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class R<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 成功
|
||||
*/
|
||||
public static final int SUCCESS = Constants.SUCCESS;
|
||||
|
||||
/**
|
||||
* 失败
|
||||
*/
|
||||
public static final int FAIL = Constants.FAIL;
|
||||
|
||||
private int code;
|
||||
|
||||
private String msg;
|
||||
|
||||
private T result;
|
||||
|
||||
public static <T> R<T> ok() {
|
||||
return restResult(null, SUCCESS, "成功");
|
||||
}
|
||||
|
||||
public static <T> R<T> ok(T result) {
|
||||
return restResult(result, SUCCESS, "成功");
|
||||
}
|
||||
|
||||
public static <T> R<T> ok(T result, String msg) {
|
||||
return restResult(result, SUCCESS, msg);
|
||||
}
|
||||
|
||||
public static <T> R<T> fail() {
|
||||
return restResult(null, FAIL, "失败");
|
||||
}
|
||||
|
||||
public static <T> R<T> fail(String msg) {
|
||||
return restResult(null, FAIL, msg);
|
||||
}
|
||||
|
||||
public static <T> R<T> fail(T result) {
|
||||
return restResult(result, FAIL, "失败");
|
||||
}
|
||||
|
||||
public static <T> R<T> fail(T result, String msg) {
|
||||
return restResult(result, FAIL, msg);
|
||||
}
|
||||
|
||||
public static <T> R<T> fail(int code, String msg) {
|
||||
return restResult(null, code, msg);
|
||||
}
|
||||
|
||||
private static <T> R<T> restResult(T result, int code, String msg) {
|
||||
R<T> apiResult = new R<>();
|
||||
apiResult.setCode(code);
|
||||
apiResult.setResult(result);
|
||||
apiResult.setMsg(msg);
|
||||
return apiResult;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public T getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(T result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package com.cpop.core.base.entity;
|
||||
|
||||
import com.mybatisflex.annotation.Column;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author LOST.yuan
|
||||
*/
|
||||
@Data
|
||||
public class BaseEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5809782578272943991L;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private String createUserId;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
private String updateUserId;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
@Column(ignore = true)
|
||||
private Map<String, Object> params;
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.cpop.core.base.entity;
|
||||
|
||||
import com.cpop.core.utils.SecurityUtils;
|
||||
import com.mybatisflex.annotation.InsertListener;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author: DB
|
||||
* @Date: 2023/08/04/15:12
|
||||
* @Description: 添加自动填充
|
||||
*/
|
||||
public class BaseInsertListener implements InsertListener {
|
||||
|
||||
@Override
|
||||
public void onInsert(Object entity) {
|
||||
BaseEntity baseEntity = (BaseEntity) entity;
|
||||
LoginUser loginUser = SecurityUtils.getInstance().getLoginUser();
|
||||
//设置 account 被新增时的一些默认数据
|
||||
baseEntity.setCreateTime(LocalDateTime.now());
|
||||
baseEntity.setCreateUserId(null == loginUser ? "1" : loginUser.getUserId());
|
||||
baseEntity.setUpdateTime(LocalDateTime.now());
|
||||
baseEntity.setUpdateUserId(null == loginUser ? "1" : loginUser.getUserId());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.cpop.core.base.entity;
|
||||
|
||||
import com.cpop.core.utils.SecurityUtils;
|
||||
import com.mybatisflex.annotation.UpdateListener;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author: DB
|
||||
* @Date: 2023/08/04/15:13
|
||||
* @Description:
|
||||
*/
|
||||
public class BaseUpdateListener implements UpdateListener {
|
||||
|
||||
@Override
|
||||
public void onUpdate(Object entity) {
|
||||
BaseEntity baseEntity = (BaseEntity) entity;
|
||||
LoginUser loginUser = SecurityUtils.getInstance().getLoginUser();
|
||||
//设置 account 被更新时的一些默认数据
|
||||
baseEntity.setUpdateTime(LocalDateTime.now());
|
||||
baseEntity.setUpdateUserId(null == loginUser ? "1" : loginUser.getUserId());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.cpop.core.base.entity;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.SerializationException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Description:
|
||||
* date: 2023/5/10 17:39
|
||||
* @Author: DB
|
||||
*/
|
||||
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
private final Class<T> clazz;
|
||||
|
||||
static {
|
||||
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
|
||||
//如果遇到反序列化autoType is not support错误,请添加并修改一下包名到bean文件路径
|
||||
// ParserConfig.getGlobalInstance().addAccept("com.xxxxx.xxx");
|
||||
}
|
||||
public FastJson2JsonRedisSerializer(Class<T> clazz) {
|
||||
super();
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(T t) throws SerializationException {
|
||||
if (t == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T deserialize(byte[] bytes) throws SerializationException {
|
||||
if (bytes == null || bytes.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
String str = new String(bytes, DEFAULT_CHARSET);
|
||||
|
||||
return JSON.parseObject(str, clazz);
|
||||
}
|
||||
public void setObjectMapper(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "'objectMapper' must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
protected JavaType getJavaType(Class<?> clazz) {
|
||||
return TypeFactory.defaultInstance().constructType(clazz);
|
||||
}
|
||||
|
||||
}
|
||||
155
Cpop-Core/src/main/java/com/cpop/core/base/entity/LoginUser.java
Normal file
155
Cpop-Core/src/main/java/com/cpop/core/base/entity/LoginUser.java
Normal file
@ -0,0 +1,155 @@
|
||||
package com.cpop.core.base.entity;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.cpop.core.base.enums.UserType;
|
||||
import com.cpop.core.base.table.SysUser;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 登录用户身份权限
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class LoginUser implements UserDetails {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户唯一标识
|
||||
*/
|
||||
private String identification;
|
||||
|
||||
/**
|
||||
* 登录时间
|
||||
*/
|
||||
private Long loginTime = System.currentTimeMillis();
|
||||
|
||||
/**
|
||||
* 过期时间
|
||||
*/
|
||||
private Long expireTime;
|
||||
|
||||
/**
|
||||
* 登录IP地址
|
||||
*/
|
||||
private String ipAddr;
|
||||
|
||||
/**
|
||||
* 登录地点
|
||||
*/
|
||||
private String loginLocation;
|
||||
|
||||
/**
|
||||
* 权限列表
|
||||
*/
|
||||
private Set<String> permissions;
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*/
|
||||
private SysUser user;
|
||||
|
||||
/**
|
||||
* 消息
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* 登录状态
|
||||
*/
|
||||
private Boolean status;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
private UserType userType = UserType.OAM_USER;
|
||||
|
||||
public LoginUser() {
|
||||
}
|
||||
|
||||
public LoginUser(SysUser user, Set<String> permissions) {
|
||||
this.user = user;
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
public LoginUser(String userId, SysUser user, Set<String> permissions) {
|
||||
this.userId = userId;
|
||||
this.user = user;
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
@JSONField(serialize = false)
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return user.getPassword();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
if (StringUtils.isBlank(this.userName)){
|
||||
return user.getUserName();
|
||||
}else {
|
||||
return this.userName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 账户是否未过期,过期无法验证
|
||||
*/
|
||||
@JSONField(serialize = false)
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定用户是否解锁,锁定的用户无法进行身份验证
|
||||
*/
|
||||
@JSONField(serialize = false)
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
|
||||
*/
|
||||
@JSONField(serialize = false)
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否可用 ,禁用的用户不能身份验证
|
||||
*/
|
||||
@JSONField(serialize = false)
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
//根据自定义逻辑来返回用户权限,如果用户权限返回空或者和拦截路径对应权限不同,验证不通过;自定义权限注解,此处设定为null
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
package com.cpop.core.base.entity;
|
||||
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* 分页数据
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class PageDomain {
|
||||
/**
|
||||
* 当前记录起始索引
|
||||
*/
|
||||
private Integer page;
|
||||
|
||||
/**
|
||||
* 每页显示记录数
|
||||
*/
|
||||
private Integer pageSize;
|
||||
|
||||
/**
|
||||
* 排序列
|
||||
*/
|
||||
private String orderByColumn;
|
||||
|
||||
/**
|
||||
* 排序的方向desc或者asc
|
||||
*/
|
||||
private String isAsc = "asc";
|
||||
|
||||
/**
|
||||
* 分页参数合理化
|
||||
*/
|
||||
private Boolean reasonable = true;
|
||||
|
||||
public String getOrderBy() {
|
||||
if (StringUtils.isEmpty(orderByColumn)) {
|
||||
return "";
|
||||
}
|
||||
return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc;
|
||||
}
|
||||
|
||||
public Integer getPageNum() {
|
||||
return page;
|
||||
}
|
||||
|
||||
public void setPageNum(Integer pageNum) {
|
||||
this.page = pageNum;
|
||||
}
|
||||
|
||||
public Integer getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public void setPageSize(Integer pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
public String getOrderByColumn() {
|
||||
return orderByColumn;
|
||||
}
|
||||
|
||||
public void setOrderByColumn(String orderByColumn) {
|
||||
this.orderByColumn = orderByColumn;
|
||||
}
|
||||
|
||||
public String getIsAsc() {
|
||||
return isAsc;
|
||||
}
|
||||
|
||||
public void setIsAsc(String isAsc) {
|
||||
if (StringUtils.isNotEmpty(isAsc)) {
|
||||
// 兼容前端排序类型
|
||||
if ("ascending".equals(isAsc)) {
|
||||
isAsc = "asc";
|
||||
} else if ("descending".equals(isAsc)) {
|
||||
isAsc = "desc";
|
||||
}
|
||||
this.isAsc = isAsc;
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean getReasonable() {
|
||||
if (StringUtils.isNull(reasonable)) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
return reasonable;
|
||||
}
|
||||
|
||||
public void setReasonable(Boolean reasonable) {
|
||||
this.reasonable = reasonable;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package com.cpop.core.base.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author DB
|
||||
* @Description:
|
||||
* @create: 2023-08-26 18:52
|
||||
*/
|
||||
@Getter
|
||||
public enum OperationLogEnum {
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* 操作码
|
||||
*/
|
||||
private final Integer code;
|
||||
/**
|
||||
* 操作信息
|
||||
*/
|
||||
private final String info;
|
||||
/**
|
||||
* 操作模块
|
||||
*/
|
||||
private final String operationModel;
|
||||
|
||||
/**
|
||||
* 7-调试,6-信息,5-通知,4-警告,3-错误,2-关键,1-报警,0-紧急
|
||||
* 成功行为等级
|
||||
*/
|
||||
private final Integer successLevel;
|
||||
|
||||
/**
|
||||
* 7-调试,6-信息,5-通知,4-警告,3-错误,2-关键,1-报警,0-紧急
|
||||
* 异常行为等级
|
||||
*/
|
||||
private final Integer exceptionLevel;
|
||||
|
||||
OperationLogEnum(Integer code, String info, String operationModel, Integer successLevel, Integer exceptionLevel) {
|
||||
this.code = code;
|
||||
this.info = info;
|
||||
this.operationModel = operationModel;
|
||||
this.successLevel = successLevel;
|
||||
this.exceptionLevel = exceptionLevel;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.cpop.core.base.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
* @author DB
|
||||
*/
|
||||
@Getter
|
||||
public enum UserType {
|
||||
|
||||
/**
|
||||
* oam系统员工
|
||||
*/
|
||||
OAM_USER(0, "oam:loginUser:"),
|
||||
/**
|
||||
* 小程序用户
|
||||
*/
|
||||
MINI_USER(1, "mini:loginUser:");
|
||||
|
||||
/**
|
||||
* code
|
||||
*/
|
||||
private final Integer code;
|
||||
|
||||
/**
|
||||
* redisKey
|
||||
*/
|
||||
private final String key;
|
||||
|
||||
UserType(Integer code, String key) {
|
||||
this.code = code;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
package com.cpop.core.base.exception;
|
||||
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.cpop.core.utils.MessageUtils;
|
||||
|
||||
/**
|
||||
* 基础异常
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class BaseException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 所属模块
|
||||
*/
|
||||
private final String module;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private final String code;
|
||||
|
||||
/**
|
||||
* 错误码对应的参数
|
||||
*/
|
||||
private final Object[] args;
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
private final 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 (!StringUtils.isEmpty(code)) {
|
||||
message = MessageUtils.message(code, args);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.cpop.core.base.exception;
|
||||
|
||||
/**
|
||||
* 业务异常
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public final class ServiceException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* 错误提示
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 错误明细,内部调试错误
|
||||
*/
|
||||
private String detailMessage;
|
||||
|
||||
/**
|
||||
* 空构造方法,避免反序列化问题
|
||||
*/
|
||||
public ServiceException() {
|
||||
}
|
||||
|
||||
public ServiceException(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public ServiceException(String message, Integer code) {
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getDetailMessage() {
|
||||
return detailMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public ServiceException setMessage(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServiceException setDetailMessage(String detailMessage) {
|
||||
this.detailMessage = detailMessage;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.cpop.core.base.exception;
|
||||
|
||||
/**
|
||||
* 工具类异常
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class UtilException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 8247610319171014183L;
|
||||
|
||||
public UtilException(Throwable e) {
|
||||
super(e.getMessage(), e);
|
||||
}
|
||||
|
||||
public UtilException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UtilException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.cpop.core.base.exception.file;
|
||||
|
||||
import com.cpop.core.base.exception.BaseException;
|
||||
|
||||
/**
|
||||
* 文件信息异常类
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class FileException extends BaseException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public FileException(String code, Object[] args) {
|
||||
super("file", code, args, null);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.cpop.core.base.exception.file;
|
||||
|
||||
|
||||
/**
|
||||
* 文件名称超长限制异常类
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class FileNameLengthLimitExceededException extends FileException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public FileNameLengthLimitExceededException(int defaultFileNameLength) {
|
||||
super("upload.filename.exceed.length", new Object[]{defaultFileNameLength});
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
package com.cpop.core.base.exception.file;
|
||||
|
||||
|
||||
/**
|
||||
* 文件名大小限制异常类
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class FileSizeLimitExceededException extends FileException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public FileSizeLimitExceededException(long defaultMaxSize) {
|
||||
super("upload.exceed.maxSize", new Object[]{defaultMaxSize});
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
package com.cpop.core.base.exception.file;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* 文件上传异常类
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class FileUploadException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Throwable cause;
|
||||
|
||||
public FileUploadException() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public FileUploadException(final String msg) {
|
||||
this(msg, null);
|
||||
}
|
||||
|
||||
public FileUploadException(String msg, Throwable cause) {
|
||||
super(msg);
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printStackTrace(PrintStream stream) {
|
||||
super.printStackTrace(stream);
|
||||
if (cause != null) {
|
||||
stream.println("Caused by:");
|
||||
cause.printStackTrace(stream);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printStackTrace(PrintWriter writer) {
|
||||
super.printStackTrace(writer);
|
||||
if (cause != null) {
|
||||
writer.println("Caused by:");
|
||||
cause.printStackTrace(writer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getCause() {
|
||||
return cause;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,69 @@
|
||||
package com.cpop.core.base.exception.file;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 文件上传 误异常类
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class InvalidExtensionException extends FileUploadException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String[] allowedExtension;
|
||||
private final String extension;
|
||||
private final String filename;
|
||||
|
||||
public InvalidExtensionException(String[] allowedExtension, String extension, String filename) {
|
||||
super("文件[" + filename + "]后缀[" + extension + "]不正确,请上传" + Arrays.toString(allowedExtension) + "格式");
|
||||
this.allowedExtension = allowedExtension;
|
||||
this.extension = extension;
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public String[] getAllowedExtension() {
|
||||
return allowedExtension;
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
return extension;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public static class InvalidImageExtensionException extends InvalidExtensionException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename) {
|
||||
super(allowedExtension, extension, filename);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvalidFlashExtensionException extends InvalidExtensionException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename) {
|
||||
super(allowedExtension, extension, filename);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvalidMediaExtensionException extends InvalidExtensionException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename) {
|
||||
super(allowedExtension, extension, filename);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvalidVideoExtensionException extends InvalidExtensionException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename) {
|
||||
super(allowedExtension, extension, filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,54 @@
|
||||
package com.cpop.core.base.table;
|
||||
|
||||
import com.cpop.core.base.entity.BaseEntity;
|
||||
import com.cpop.core.base.entity.BaseInsertListener;
|
||||
import com.cpop.core.base.entity.BaseUpdateListener;
|
||||
import com.mybatisflex.annotation.Id;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 系统配置表 实体类。
|
||||
*
|
||||
* @author DB
|
||||
* @since 2023-08-11
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
@Table(value = "pp_sys_config", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
|
||||
public class SysConfig extends BaseEntity implements Serializable {
|
||||
|
||||
/**
|
||||
* 参数键
|
||||
*/
|
||||
@Id
|
||||
private String configKey;
|
||||
|
||||
/**
|
||||
* 参数名
|
||||
*/
|
||||
private String configName;
|
||||
|
||||
/**
|
||||
* 参数值
|
||||
*/
|
||||
private String configValue;
|
||||
|
||||
/**
|
||||
* 系统内置(0否1是)
|
||||
*/
|
||||
private Boolean configType;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remarks;
|
||||
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package com.cpop.core.base.table;
|
||||
|
||||
import com.cpop.core.base.entity.BaseEntity;
|
||||
import com.cpop.core.base.entity.BaseInsertListener;
|
||||
import com.cpop.core.base.entity.BaseUpdateListener;
|
||||
import com.cpop.core.base.enums.UserType;
|
||||
import com.mybatisflex.annotation.Id;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 操作日志表 实体类。
|
||||
*
|
||||
* @author DB
|
||||
* @since 2023-08-05
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
@Table(value = "pp_sys_operation_log", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
|
||||
public class SysOperationLog extends BaseEntity implements Serializable {
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private String operationUserId;
|
||||
|
||||
/**
|
||||
* 操作用户
|
||||
*/
|
||||
private String operationUserName;
|
||||
|
||||
/**
|
||||
* 操作用户类型
|
||||
*/
|
||||
private UserType operationUserType;
|
||||
|
||||
/**
|
||||
* 操作码
|
||||
*/
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* 操作信息
|
||||
*/
|
||||
private String info;
|
||||
|
||||
/**
|
||||
* 操作终端的IP地址
|
||||
*/
|
||||
private String devIp;
|
||||
|
||||
/**
|
||||
* 结果 -1:失败 1:成功
|
||||
*/
|
||||
private Boolean result;
|
||||
|
||||
/**
|
||||
* 日志级别,0-提示,1-一般,2-危险,3-高危
|
||||
*/
|
||||
private Integer level;
|
||||
|
||||
/**
|
||||
* 行为类别,1-一般行为,2-异常行为
|
||||
*/
|
||||
private Integer actionType;
|
||||
|
||||
/**
|
||||
* 失败原因
|
||||
*/
|
||||
private String failReason;
|
||||
|
||||
/**
|
||||
* 操作描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
package com.cpop.core.base.table;
|
||||
|
||||
import com.cpop.core.base.entity.BaseEntity;
|
||||
import com.cpop.core.base.entity.BaseInsertListener;
|
||||
import com.cpop.core.base.entity.BaseUpdateListener;
|
||||
import com.mybatisflex.annotation.Column;
|
||||
import com.mybatisflex.annotation.Id;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import com.cpop.core.base.enums.UserType;
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 系统用户
|
||||
*
|
||||
* @author DB.lost
|
||||
* @Date: 2023-05-05
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
@Table(value = "pp_sys_user", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
|
||||
public class SysUser extends BaseEntity implements Serializable {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 性别(0:男;1:女)
|
||||
*/
|
||||
private Boolean sex;
|
||||
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 盐
|
||||
*/
|
||||
private String salt;
|
||||
|
||||
/**
|
||||
* 状态(0:停用;1:启用)
|
||||
*/
|
||||
private Boolean status;
|
||||
|
||||
/**
|
||||
* 登录地IP
|
||||
*/
|
||||
private String loginIp;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
private UserType userType;
|
||||
|
||||
/**
|
||||
* 逻辑删除(0否1是)
|
||||
*/
|
||||
@Column(isLogicDelete = true)
|
||||
private Boolean isDelete;
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.cpop.core.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* @author: DB
|
||||
* @date: 2022-10-13 11:45
|
||||
* @Description:
|
||||
*/
|
||||
@Configuration
|
||||
public class AsyncScheduledTaskConfig {
|
||||
|
||||
@Autowired
|
||||
private TaskThreadPoolConfig config;
|
||||
|
||||
/**
|
||||
* 1.这种形式的线程池配置是需要在使用的方法上面添加@Async("customAsyncThreadPool")注解的
|
||||
* 2.如果在使用的方法上不添加该注解,那么spring就会使用默认的线程池
|
||||
* 3.所以如果添加@Async注解但是不指定使用的线程池,又想自己自定义线程池,那么就可以重写spring默认的线程池
|
||||
* 4.所以第二个方法就是重写spring默认的线程池
|
||||
* @return Executor
|
||||
*/
|
||||
@Bean("customAsyncThreadPool")
|
||||
public Executor customAsyncThreadPool() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
//最大线程数
|
||||
executor.setMaxPoolSize(config.getMaxPoolSize());
|
||||
//核心线程数
|
||||
executor.setCorePoolSize(config.getCorePoolSize());
|
||||
//任务队列的大小
|
||||
executor.setQueueCapacity(config.getQueueCapacity());
|
||||
//线程池名的前缀
|
||||
executor.setThreadNamePrefix(config.getThreadNamePrefix());
|
||||
//允许线程的空闲时间30秒
|
||||
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
|
||||
//设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
|
||||
executor.setWaitForTasksToCompleteOnShutdown(true);
|
||||
//设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
|
||||
executor.setAwaitTerminationSeconds(config.getAwaitTerminationSeconds());
|
||||
/**
|
||||
* 拒绝处理策略
|
||||
* CallerRunsPolicy():交由调用方线程运行,比如 main 线程。
|
||||
* AbortPolicy():直接抛出异常。
|
||||
* DiscardPolicy():直接丢弃。
|
||||
* DiscardOldestPolicy():丢弃队列中最老的任务。
|
||||
* 特殊说明:
|
||||
* 1. 这里演示环境,拒绝策略咱们采用抛出异常
|
||||
* 2.真实业务场景会把缓存队列的大小会设置大一些,
|
||||
* 如果,提交的任务数量超过最大线程数量或将任务环缓存到本地、redis、mysql中,保证消息不丢失
|
||||
* 3.如果项目比较大的话,异步通知种类很多的话,建议采用MQ做异步通知方案
|
||||
*/
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
|
||||
//线程初始化
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
|
||||
}
|
||||
94
Cpop-Core/src/main/java/com/cpop/core/config/CpopConfig.java
Normal file
94
Cpop-Core/src/main/java/com/cpop/core/config/CpopConfig.java
Normal file
@ -0,0 +1,94 @@
|
||||
package com.cpop.core.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 读取项目相关配置
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "cpop")
|
||||
public class CpopConfig {
|
||||
/**
|
||||
* 项目名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 上传路径
|
||||
*/
|
||||
private static String profile;
|
||||
|
||||
/**
|
||||
* 验证码类型
|
||||
*/
|
||||
private static String captchaType;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public static String getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public void setProfile(String profile) {
|
||||
CpopConfig.profile = profile;
|
||||
}
|
||||
|
||||
public static String getCaptchaType() {
|
||||
return captchaType;
|
||||
}
|
||||
|
||||
public void setCaptchaType(String captchaType) {
|
||||
CpopConfig.captchaType = captchaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导入上传路径
|
||||
*/
|
||||
public static String getImportPath() {
|
||||
return getProfile() + "/import";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头像上传路径
|
||||
*/
|
||||
public static String getAvatarPath() {
|
||||
return getProfile() + "/avatar";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下载路径
|
||||
*/
|
||||
public static String getDownloadPath() {
|
||||
return getProfile() + "/download/";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传路径
|
||||
*/
|
||||
public static String getUploadPath() {
|
||||
return getProfile() + "/upload";
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
package com.cpop.core.config;
|
||||
|
||||
import com.cpop.core.base.entity.FastJson2JsonRedisSerializer;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
/**
|
||||
* redis配置
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings(value = {"unchecked", "rawtypes"})
|
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
|
||||
// 使用StringRedisSerializer来序列化和反序列化redis的key值
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setValueSerializer(serializer);
|
||||
// Hash的key也采用StringRedisSerializer的序列化方式
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
template.setHashValueSerializer(serializer);
|
||||
template.afterPropertiesSet();
|
||||
return template;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultRedisScript<Long> limitScript() {
|
||||
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
|
||||
redisScript.setScriptText(limitScriptText());
|
||||
redisScript.setResultType(Long.class);
|
||||
return redisScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* 限流脚本
|
||||
*/
|
||||
private String limitScriptText() {
|
||||
return "local key = KEYS[1]\n" +
|
||||
"local count = tonumber(ARGV[1])\n" +
|
||||
"local time = tonumber(ARGV[2])\n" +
|
||||
"local current = redis.call('get', key);\n" +
|
||||
"if current and tonumber(current) > count then\n" +
|
||||
" return tonumber(current);\n" +
|
||||
"end\n" +
|
||||
"current = redis.call('incr', key)\n" +
|
||||
"if tonumber(current) == 1 then\n" +
|
||||
" redis.call('expire', key, time)\n" +
|
||||
"end\n" +
|
||||
"return tonumber(current);";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.cpop.core.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.integration.redis.util.RedisLockRegistry;
|
||||
|
||||
/**
|
||||
* @author DB
|
||||
*/
|
||||
@Configuration
|
||||
public class RedisLockConfig {
|
||||
|
||||
@Bean
|
||||
public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
|
||||
//第一个参数redisConnectionFactory
|
||||
//第二个参数registryKey,分布式锁前缀,设置为项目名称会好些
|
||||
//该构造方法对应的分布式锁,默认有效期是60秒.可以自定义
|
||||
return new RedisLockRegistry(redisConnectionFactory, "Cpop-");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package com.cpop.core.config;
|
||||
|
||||
import com.cpop.common.utils.ServletUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 服务相关配置
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
@Component
|
||||
public class ServerConfig {
|
||||
|
||||
/**
|
||||
* 获取完整的请求路径,包括:域名,端口,上下文访问路径
|
||||
*
|
||||
* @return 服务地址
|
||||
*/
|
||||
public String getUrl() {
|
||||
HttpServletRequest request = ServletUtils.getRequest();
|
||||
return getDomain(request);
|
||||
}
|
||||
|
||||
public static String getDomain(HttpServletRequest request) {
|
||||
StringBuffer url = request.getRequestURL();
|
||||
String contextPath = request.getServletContext().getContextPath();
|
||||
return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.cpop.core.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author: DB
|
||||
* @date: 2022-10-13 11:40
|
||||
* @Description: 线程配置属性类
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "task.pool")
|
||||
public class TaskThreadPoolConfig {
|
||||
|
||||
/**
|
||||
* 设置核心线程数
|
||||
*/
|
||||
private Integer corePoolSize;
|
||||
/**
|
||||
* 设置最大线程数
|
||||
*/
|
||||
private Integer maxPoolSize;
|
||||
/**
|
||||
* 设置空闲线程存活时间(秒)
|
||||
*/
|
||||
private Integer keepAliveSeconds;
|
||||
/**
|
||||
* 设置队列容量
|
||||
*/
|
||||
private Integer queueCapacity;
|
||||
/**
|
||||
* 设置线程名称前缀
|
||||
*/
|
||||
private Integer awaitTerminationSeconds;
|
||||
/**
|
||||
* 设置线程池等待终止时间(秒)
|
||||
*/
|
||||
private String threadNamePrefix;
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.cpop.core.event;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* @author: DB
|
||||
* @date: 2022-08-12 10:10
|
||||
* @Description: 操作日志事件
|
||||
*/
|
||||
public class OperationLogEvent extends ApplicationEvent {
|
||||
|
||||
/**
|
||||
* @author LOST.yuan
|
||||
* @date 10:10 2022/8/12
|
||||
* @param source 源
|
||||
**/
|
||||
public OperationLogEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.cpop.core.filter;
|
||||
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* Repeatable 过滤器
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
@Component
|
||||
public class RepeatableFilter implements Filter {
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
ServletRequest requestWrapper = null;
|
||||
if (request instanceof HttpServletRequest && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
|
||||
requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
|
||||
}
|
||||
if (null == requestWrapper) {
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
chain.doFilter(requestWrapper, response);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
package com.cpop.core.filter;
|
||||
|
||||
import com.cpop.common.utils.http.HttpHelper;
|
||||
|
||||
import javax.servlet.ReadListener;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 构建可重复读取inputStream的request
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
|
||||
private final byte[] body;
|
||||
|
||||
public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
|
||||
super(request);
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
|
||||
body = HttpHelper.getBodyString(request).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedReader getReader() throws IOException {
|
||||
return new BufferedReader(new InputStreamReader(getInputStream()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
|
||||
return new ServletInputStream() {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return bais.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return body.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
61
Cpop-Core/src/main/java/com/cpop/core/filter/XssFilter.java
Normal file
61
Cpop-Core/src/main/java/com/cpop/core/filter/XssFilter.java
Normal file
@ -0,0 +1,61 @@
|
||||
package com.cpop.core.filter;
|
||||
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 防止XSS攻击的过滤器
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class XssFilter implements Filter {
|
||||
/**
|
||||
* 排除链接
|
||||
*/
|
||||
public List<String> excludes = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
String tempExcludes = filterConfig.getInitParameter("excludes");
|
||||
if (StringUtils.isNotEmpty(tempExcludes)) {
|
||||
String[] url = tempExcludes.split(",");
|
||||
for (int i = 0; url != null && i < url.length; i++) {
|
||||
excludes.add(url[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest req = (HttpServletRequest) request;
|
||||
HttpServletResponse resp = (HttpServletResponse) response;
|
||||
if (handleExcludeURL(req, resp)) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
|
||||
chain.doFilter(xssRequest, response);
|
||||
}
|
||||
|
||||
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
|
||||
String url = request.getServletPath();
|
||||
String method = request.getMethod();
|
||||
// GET DELETE 不过滤
|
||||
if (method == null || method.matches("GET") || method.matches("DELETE")) {
|
||||
return true;
|
||||
}
|
||||
return StringUtils.matches(url, excludes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
package com.cpop.core.filter;
|
||||
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.cpop.common.utils.html.EscapeUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import javax.servlet.ReadListener;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* XSS过滤处理
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
/**
|
||||
* @param request
|
||||
*/
|
||||
public XssHttpServletRequestWrapper(HttpServletRequest request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getParameterValues(String name) {
|
||||
String[] values = super.getParameterValues(name);
|
||||
if (values != null) {
|
||||
int length = values.length;
|
||||
String[] escapseValues = new String[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
// 防xss攻击和过滤前后空格
|
||||
escapseValues[i] = EscapeUtil.clean(values[i]).trim();
|
||||
}
|
||||
return escapseValues;
|
||||
}
|
||||
return super.getParameterValues(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
// 非json类型,直接返回
|
||||
if (!isJsonRequest()) {
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
// 为空,直接返回
|
||||
String json = IOUtils.toString(super.getInputStream(), StandardCharsets.UTF_8);
|
||||
if (StringUtils.isEmpty(json)) {
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
// xss过滤
|
||||
json = EscapeUtil.clean(json).trim();
|
||||
byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8);
|
||||
final ByteArrayInputStream bis = new ByteArrayInputStream(jsonBytes);
|
||||
return new ServletInputStream() {
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return jsonBytes.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return bis.read();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是Json请求
|
||||
*/
|
||||
public boolean isJsonRequest() {
|
||||
String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
|
||||
return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
package com.cpop.core.handler;
|
||||
|
||||
import com.cpop.core.base.R;
|
||||
import com.cpop.core.base.exception.ServiceException;
|
||||
import com.cpop.common.enums.ErrorCodeEnum;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author: DB
|
||||
* @date: 2022-10-13 17:08
|
||||
* @Description: 全局异常处理器
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
||||
|
||||
/**
|
||||
* 业务异常
|
||||
*/
|
||||
@ExceptionHandler(ServiceException.class)
|
||||
public R handleServiceException(ServiceException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
Integer code = e.getCode();
|
||||
return null != code ? R.fail(code, e.getMessage()) : R.fail(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截未知的运行时异常
|
||||
* @param e
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public R handleRuntimeException(RuntimeException e, HttpServletRequest request) {
|
||||
String requestUrl = request.getRequestURI();
|
||||
log.error("请求地址'{}',发生未知异常.", requestUrl, e);
|
||||
return R.fail(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统异常
|
||||
* @param e
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
public R handleException(Exception e, HttpServletRequest request) {
|
||||
String requestUrl = request.getRequestURI();
|
||||
log.error("请求地址'{}',发生系统异常.", requestUrl, e);
|
||||
return R.fail(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限不足
|
||||
* @param e 权限不足异常
|
||||
*/
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public R handleException(AccessDeniedException e) {
|
||||
return R.fail(ErrorCodeEnum.HTTP_401.getInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义验证异常
|
||||
*/
|
||||
@ExceptionHandler(BindException.class)
|
||||
public R handleBindException(BindException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
String message = e.getAllErrors().get(0).getDefaultMessage();
|
||||
return R.fail(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义验证异常
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
String message = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
|
||||
return R.fail(message);
|
||||
}
|
||||
|
||||
//TODO:可以自行后续拓展
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.cpop.core.listen;
|
||||
|
||||
import com.cpop.core.base.table.SysOperationLog;
|
||||
import com.cpop.core.event.OperationLogEvent;
|
||||
import com.cpop.core.utils.uuid.IdUtils;
|
||||
import com.cpop.core.service.CoreService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author: DB
|
||||
* @date: 2022-08-12 10:25
|
||||
* @Description: 操作日志监听
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SysOperationLogListen {
|
||||
|
||||
@Autowired
|
||||
private CoreService coreService;
|
||||
|
||||
@Async
|
||||
@Order
|
||||
@EventListener(OperationLogEvent.class)
|
||||
public void saveSysOperationLog(OperationLogEvent event) {
|
||||
SysOperationLog operationLog = (SysOperationLog) event.getSource();
|
||||
// 保存日志
|
||||
operationLog.setId(IdUtils.fastSimpleUUID());
|
||||
if (coreService.saveOperationLog(operationLog)) {
|
||||
//TODO;后续可自定义其他操作
|
||||
}
|
||||
}
|
||||
}
|
||||
124
Cpop-Core/src/main/java/com/cpop/core/mapper/CoreMapper.java
Normal file
124
Cpop-Core/src/main/java/com/cpop/core/mapper/CoreMapper.java
Normal file
@ -0,0 +1,124 @@
|
||||
package com.cpop.core.mapper;
|
||||
|
||||
import com.cpop.core.base.enums.UserType;
|
||||
import com.cpop.core.base.table.SysConfig;
|
||||
import com.cpop.core.base.table.SysOperationLog;
|
||||
import com.cpop.core.base.table.SysUser;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author DB
|
||||
* @Description:
|
||||
* @create 2023-08-27 10:54
|
||||
*/
|
||||
public interface CoreMapper {
|
||||
|
||||
/**
|
||||
* @Description: 插入操作日志
|
||||
* @param log
|
||||
* @return Integer
|
||||
* @Author DB
|
||||
* @Date: 2023/8/27 10:56
|
||||
*/
|
||||
Boolean insertOperationLog(SysOperationLog log);
|
||||
|
||||
/**
|
||||
* @Description: 根据用户名获取用户信息
|
||||
* @param username 用户名
|
||||
* @param userType 用户类型
|
||||
* @return SysUser
|
||||
* @Author DB
|
||||
* @Date: 2023/8/27 23:39
|
||||
*/
|
||||
SysUser getSysUser(@Param("username") String username, @Param("userType") UserType userType);
|
||||
|
||||
/**
|
||||
* @Description: 更新登录地址
|
||||
* @param ipAddr
|
||||
* @param username
|
||||
* @return
|
||||
* @author DB
|
||||
* @Date: 2023/8/28 0028 13:49
|
||||
*/
|
||||
void updateSysUserLoginIp(String ipAddr, String username);
|
||||
|
||||
/**
|
||||
* @Description: 加载参数缓存数据
|
||||
* @param
|
||||
* @return List<SysConfig>
|
||||
* @Author DB
|
||||
* @Date: 2023/8/28 22:33
|
||||
*/
|
||||
List<SysConfig> loadingConfigCache();
|
||||
|
||||
/**
|
||||
* @Description: 根据键名查询参数配置信息
|
||||
* @param configKey
|
||||
* @return SysConfig
|
||||
* @Author DB
|
||||
* @Date: 2023/8/28 22:49
|
||||
*/
|
||||
SysConfig selectConfigByKey(String configKey);
|
||||
|
||||
/**
|
||||
* @Description: 新增参数配置
|
||||
* @param config
|
||||
* @return boolean
|
||||
* @Author DB
|
||||
* @Date: 2023/8/28 23:03
|
||||
*/
|
||||
boolean insertConfig(SysConfig config);
|
||||
|
||||
/**
|
||||
* @Description: 修改参数配置
|
||||
* @param config
|
||||
* @return boolean
|
||||
* @Author DB
|
||||
* @Date: 2023/8/28 23:17
|
||||
*/
|
||||
boolean updateConfig(SysConfig config);
|
||||
|
||||
/**
|
||||
* @Description: 根据键查询配置
|
||||
* @param list
|
||||
* @return List<SysConfig>
|
||||
* @Author DB
|
||||
* @Date: 2023/8/28 23:25
|
||||
*/
|
||||
List<SysConfig> selectConfigByKeys(List<String> list);
|
||||
|
||||
/**
|
||||
* @Description: 需要删除的参数ID
|
||||
* @param list
|
||||
* @return
|
||||
* @Author DB
|
||||
* @Date: 2023/8/28 23:29
|
||||
*/
|
||||
void deleteConfigByKeys(List<String> list);
|
||||
|
||||
/**
|
||||
* @descriptions 新增系统用户
|
||||
* @author DB
|
||||
* @date 2023/09/08 15:04
|
||||
* @param sysUser 系统用户参数
|
||||
*/
|
||||
void insertSysUser(SysUser sysUser);
|
||||
|
||||
/**
|
||||
* @descriptions 修改系统用户
|
||||
* @author DB
|
||||
* @date 2023/09/08 17:21
|
||||
* @param sysUser 系统用户参数d
|
||||
*/
|
||||
void updateSysUser(SysUser sysUser);
|
||||
|
||||
/**
|
||||
* @descriptions 根据主键删除用户(逻辑删除)
|
||||
* @author DB
|
||||
* @date 2023/09/08 17:50
|
||||
* @param id 主键
|
||||
*/
|
||||
void removeSysUserById(String id);
|
||||
}
|
||||
111
Cpop-Core/src/main/java/com/cpop/core/service/CoreService.java
Normal file
111
Cpop-Core/src/main/java/com/cpop/core/service/CoreService.java
Normal file
@ -0,0 +1,111 @@
|
||||
package com.cpop.core.service;
|
||||
|
||||
import com.cpop.core.base.entity.LoginUser;
|
||||
import com.cpop.core.base.enums.OperationLogEnum;
|
||||
import com.cpop.core.base.enums.UserType;
|
||||
import com.cpop.core.base.table.SysConfig;
|
||||
import com.cpop.core.base.table.SysOperationLog;
|
||||
import com.cpop.core.base.table.SysUser;
|
||||
|
||||
/**
|
||||
* @author DB
|
||||
* @Description:
|
||||
* @create: 2023-08-27 11:04
|
||||
*/
|
||||
public interface CoreService {
|
||||
|
||||
/**
|
||||
* @Description: 添加操作日志
|
||||
* @param status 状态
|
||||
* @param loginUser 登陆用户
|
||||
* @param failReason 失败原因
|
||||
* @return String
|
||||
* @Author: DB
|
||||
* @Date: 2023/8/27 11:08
|
||||
*/
|
||||
String insertOperationLog(Integer status, OperationLogEnum operationLogEnum, LoginUser loginUser, String failReason);
|
||||
|
||||
/**
|
||||
* @Description: 添加操作日志
|
||||
* @param operationLog 日志
|
||||
* @return boolean
|
||||
* @Author: DB
|
||||
* @Date: 2023/8/29 23:46
|
||||
*/
|
||||
boolean saveOperationLog(SysOperationLog operationLog);
|
||||
|
||||
/**
|
||||
* @Description: 根据用户名获取用户信息
|
||||
* @param username 用户名
|
||||
* @return SysUser
|
||||
* @Author: DB
|
||||
* @Date: 2023/8/27 23:37
|
||||
*/
|
||||
SysUser getSysUser(String username, UserType userType);
|
||||
|
||||
/**
|
||||
* @Description: 更新登录地址
|
||||
* @param ipAddr ip地址
|
||||
* @param username 用户名
|
||||
* @author DB
|
||||
* @Date: 2023/8/28 0028 13:48
|
||||
*/
|
||||
void updateSysUserLoginIp(String ipAddr, String username);
|
||||
|
||||
/**
|
||||
* 根据键名查询参数配置信息
|
||||
*
|
||||
* @param configKey 参数键名
|
||||
* @return 参数键值
|
||||
*/
|
||||
SysConfig selectConfigByKey(String configKey);
|
||||
|
||||
/**
|
||||
* @Description: 新增参数配置
|
||||
* @param config
|
||||
* @author DB
|
||||
* @Date: 2023/6/7 0007 16:17
|
||||
*/
|
||||
void insertConfig(SysConfig config);
|
||||
|
||||
/**
|
||||
* @Description: 修改参数配置
|
||||
* @param config
|
||||
* @author DB
|
||||
* @Date: 2023/6/7 0007 16:19
|
||||
*/
|
||||
void updateConfig(SysConfig config);
|
||||
|
||||
/**
|
||||
* @Description: 批量删除参数信息
|
||||
* @param keys
|
||||
* @author DB
|
||||
* @Date: 2023/6/8 0008 9:58
|
||||
*/
|
||||
void deleteConfigByKeys(String[] keys);
|
||||
|
||||
/**
|
||||
* @descriptions 新增系统用户
|
||||
* @author DB
|
||||
* @date 2023/09/08 15:04
|
||||
* @param sysUser 系统用户参数
|
||||
*/
|
||||
void insertSysUser(SysUser sysUser);
|
||||
|
||||
/**
|
||||
* @descriptions 修改系统用户
|
||||
* @author DB
|
||||
* @date 2023/09/08 17:20
|
||||
* @param sysUser 系统用户参数
|
||||
*/
|
||||
void updateSysUser(SysUser sysUser);
|
||||
|
||||
/**
|
||||
* @descriptions 根据主键删除用户
|
||||
* @author DB
|
||||
* @date 2023/09/08 17:49
|
||||
* @param id 主键
|
||||
* @return void
|
||||
*/
|
||||
void removeSysUserById(String id);
|
||||
}
|
||||
188
Cpop-Core/src/main/java/com/cpop/core/service/RedisService.java
Normal file
188
Cpop-Core/src/main/java/com/cpop/core/service/RedisService.java
Normal file
@ -0,0 +1,188 @@
|
||||
package com.cpop.core.service;
|
||||
|
||||
import org.springframework.data.redis.core.BoundSetOperations;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
/**
|
||||
* spring redis 工具类
|
||||
*
|
||||
* @author DB
|
||||
**/
|
||||
public interface RedisService {
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
*/
|
||||
<T> void setCacheObject(final String key, final T value);
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
* @param timeout 时间
|
||||
* @param timeUnit 时间颗粒度
|
||||
*/
|
||||
<T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit);
|
||||
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param timeout 超时时间
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
boolean expire(final String key, final long timeout);
|
||||
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param timeout 超时时间
|
||||
* @param unit 时间单位
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
boolean expire(final String key, final long timeout, final TimeUnit unit);
|
||||
|
||||
/**
|
||||
* 获取有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @return 有效时间
|
||||
*/
|
||||
long getExpire(final String key);
|
||||
|
||||
/**
|
||||
* 判断 key是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
Boolean hasKey(String key);
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象。
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
<T> T getCacheObject(final String key);
|
||||
|
||||
/**
|
||||
* 删除单个对象
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
boolean deleteObject(final String key);
|
||||
|
||||
/**
|
||||
* 删除集合对象
|
||||
*
|
||||
* @param collection 多个对象
|
||||
* @return
|
||||
*/
|
||||
long deleteObject(final Collection collection);
|
||||
|
||||
/**
|
||||
* 缓存List数据
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param dataList 待缓存的List数据
|
||||
* @return 缓存的对象
|
||||
*/
|
||||
<T> long setCacheList(final String key, final List<T> dataList);
|
||||
|
||||
/**
|
||||
* 获得缓存的list对象
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
<T> List<T> getCacheList(final String key);
|
||||
|
||||
/**
|
||||
* 缓存Set
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @param dataSet 缓存的数据
|
||||
* @return 缓存数据的对象
|
||||
*/
|
||||
<T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet);
|
||||
|
||||
/**
|
||||
* 获得缓存的set
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
<T> Set<T> getCacheSet(final String key);
|
||||
|
||||
/**
|
||||
* 缓存Map
|
||||
*
|
||||
* @param key
|
||||
* @param dataMap
|
||||
*/
|
||||
<T> void setCacheMap(final String key, final Map<String, T> dataMap);
|
||||
|
||||
/**
|
||||
* 获得缓存的Map
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
<T> Map<String, T> getCacheMap(final String key);
|
||||
|
||||
/**
|
||||
* 往Hash中存入数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @param value 值
|
||||
*/
|
||||
<T> void setCacheMapValue(final String key, final String hKey, final T value);
|
||||
|
||||
/**
|
||||
* 获取Hash中的数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @return Hash中的对象
|
||||
*/
|
||||
<T> T getCacheMapValue(final String key, final String hKey);
|
||||
|
||||
/**
|
||||
* 获取多个Hash中的数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKeys Hash键集合
|
||||
* @return Hash对象集合
|
||||
*/
|
||||
<T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys);
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象列表
|
||||
*
|
||||
* @param pattern 字符串前缀
|
||||
* @return 对象列表
|
||||
*/
|
||||
Collection<String> keys(final String pattern);
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @return
|
||||
* @Description: 分布式锁
|
||||
* @Author DB
|
||||
* @Date: 2023/4/12 22:23
|
||||
*/
|
||||
Lock distributedLock(String key);
|
||||
}
|
||||
@ -0,0 +1,195 @@
|
||||
package com.cpop.core.service.impl;
|
||||
|
||||
import com.cpop.core.base.entity.LoginUser;
|
||||
import com.cpop.core.base.enums.OperationLogEnum;
|
||||
import com.cpop.core.base.enums.UserType;
|
||||
import com.cpop.core.base.exception.ServiceException;
|
||||
import com.cpop.core.base.table.SysConfig;
|
||||
import com.cpop.core.base.table.SysOperationLog;
|
||||
import com.cpop.core.base.table.SysUser;
|
||||
import com.cpop.core.mapper.CoreMapper;
|
||||
import com.cpop.core.service.CoreService;
|
||||
import com.cpop.core.utils.MessageUtils;
|
||||
import com.cpop.core.utils.SecurityUtils;
|
||||
import com.cpop.core.utils.uuid.IdUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author DB
|
||||
* @Description:
|
||||
* @create: 2023-08-27 11:04
|
||||
*/
|
||||
@Service("coreService")
|
||||
public class CoreServiceImpl implements CoreService {
|
||||
|
||||
@Autowired
|
||||
private CoreMapper coreMapper;
|
||||
|
||||
/**
|
||||
* @Description: 添加操作日志
|
||||
* @param status 状态
|
||||
* @param operationLogEnum 日志枚举
|
||||
* @param loginUser 登陆用户
|
||||
* @param failReason 失败原因
|
||||
* @return String
|
||||
* @Author: DB
|
||||
* @Date: 2023/8/27 11:08
|
||||
*/
|
||||
@Override
|
||||
public String insertOperationLog(Integer status, OperationLogEnum operationLogEnum, LoginUser loginUser, String failReason) {
|
||||
SysOperationLog operationLog = new SysOperationLog();
|
||||
operationLog.setId(IdUtils.fastSimpleUUID())
|
||||
.setCode(operationLogEnum.getCode())
|
||||
.setInfo(MessageUtils.message(operationLogEnum.getInfo()))
|
||||
.setDevIp(loginUser.getIpAddr())
|
||||
.setOperationUserName(loginUser.getUsername());
|
||||
if (200 == status) {
|
||||
operationLog.setOperationUserId(loginUser.getUserId())
|
||||
.setLevel(operationLogEnum.getSuccessLevel())
|
||||
.setDescription(MessageUtils.message(operationLogEnum.getInfo()) + MessageUtils.message("i18n_baseInfo_success"))
|
||||
.setResult(true)
|
||||
.setActionType(1);
|
||||
} else {
|
||||
operationLog.setLevel(operationLogEnum.getExceptionLevel())
|
||||
.setDescription(MessageUtils.message(operationLogEnum.getInfo()) + MessageUtils.message("i18n_baseInfo_failed"))
|
||||
.setFailReason(failReason)
|
||||
.setResult(false)
|
||||
.setActionType(2);
|
||||
}
|
||||
operationLog.setCreateUserId(loginUser.getUserId());
|
||||
operationLog.setUpdateUserId(loginUser.getUserId());
|
||||
if (coreMapper.insertOperationLog(operationLog)) {
|
||||
//TODO:后续可自定义其他操作
|
||||
}
|
||||
return operationLog.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 添加操作日志
|
||||
* @param operationLog 操作日志
|
||||
* @return boolean
|
||||
* @Author DB
|
||||
* @Date: 2023/8/29 23:46
|
||||
*/
|
||||
@Override
|
||||
public boolean saveOperationLog(SysOperationLog operationLog) {
|
||||
return coreMapper.insertOperationLog(operationLog);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 根据用户名获取用户信息
|
||||
* @param username 用户名
|
||||
* @return SysUser
|
||||
* @Author DB
|
||||
* @Date: 2023/8/27 23:37
|
||||
*/
|
||||
@Override
|
||||
public SysUser getSysUser(String username, UserType userType) {
|
||||
return coreMapper.getSysUser(username, userType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 更新登录地址
|
||||
* @param ipAddr 地址
|
||||
* @param username 用户名
|
||||
* @author DB
|
||||
* @Date: 2023/8/28 0028 13:48
|
||||
*/
|
||||
@Override
|
||||
public void updateSysUserLoginIp(String ipAddr, String username) {
|
||||
coreMapper.updateSysUserLoginIp(ipAddr, username);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 根据键名查询参数配置信息
|
||||
* @param configKey 键
|
||||
* @return String
|
||||
* @author DB
|
||||
* @Date: 2023/6/7 0007 15:59
|
||||
*/
|
||||
@Override
|
||||
public SysConfig selectConfigByKey(String configKey) {
|
||||
return coreMapper.selectConfigByKey(configKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增参数配置
|
||||
*
|
||||
* @param config 参数配置信息
|
||||
*/
|
||||
@Override
|
||||
public void insertConfig(SysConfig config) {
|
||||
LoginUser loginUser = SecurityUtils.getInstance().getLoginUser();
|
||||
config.setCreateUserId(null == loginUser ? "1" : loginUser.getUserId());
|
||||
config.setUpdateUserId(null == loginUser ? "1" : loginUser.getUserId());
|
||||
coreMapper.insertConfig(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改参数配置
|
||||
*
|
||||
* @param config 参数配置信息
|
||||
*/
|
||||
@Override
|
||||
public void updateConfig(SysConfig config) {
|
||||
LoginUser loginUser = SecurityUtils.getInstance().getLoginUser();
|
||||
config.setUpdateUserId(null == loginUser ? "1" : loginUser.getUserId());
|
||||
coreMapper.updateConfig(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除参数信息
|
||||
*
|
||||
* @param keys 需要删除的参数ID
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteConfigByKeys(String[] keys) {
|
||||
List<String> keyList = Arrays.asList(keys);
|
||||
List<SysConfig> sysConfigList = coreMapper.selectConfigByKeys(keyList);
|
||||
sysConfigList.forEach(item -> {
|
||||
if (item.getConfigType()) {
|
||||
throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", item.getConfigKey()));
|
||||
}
|
||||
});
|
||||
coreMapper.deleteConfigByKeys(keyList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @descriptions 新增系统用户
|
||||
* @author DB
|
||||
* @date 2023/09/08 15:04
|
||||
* @param sysUser 系统用户参数
|
||||
*/
|
||||
@Override
|
||||
public void insertSysUser(SysUser sysUser) {
|
||||
coreMapper.insertSysUser(sysUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* @descriptions 修改系统用户
|
||||
* @author DB
|
||||
* @date 2023/09/08 17:20
|
||||
* @param sysUser 系统用户参数
|
||||
*/
|
||||
@Override
|
||||
public void updateSysUser(SysUser sysUser) {
|
||||
coreMapper.updateSysUser(sysUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* @descriptions 根据主键删除用户
|
||||
* @author DB
|
||||
* @date 2023/09/08 17:50
|
||||
* @param id 主键
|
||||
*/
|
||||
@Override
|
||||
public void removeSysUserById(String id) {
|
||||
coreMapper.removeSysUserById(id);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
package com.cpop.core.service.impl;
|
||||
|
||||
import com.cpop.core.service.RedisService;
|
||||
import org.springframework.data.redis.core.BoundSetOperations;
|
||||
import org.springframework.data.redis.core.HashOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.integration.redis.util.RedisLockRegistry;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
/**
|
||||
* spring redis 工具类
|
||||
*
|
||||
* @author DB
|
||||
**/
|
||||
@SuppressWarnings(value = {"unchecked", "rawtypes"})
|
||||
@Service("redisService")
|
||||
public class RedisServiceImpl implements RedisService {
|
||||
@Resource
|
||||
public RedisTemplate redisTemplate;
|
||||
|
||||
@Resource
|
||||
private RedisLockRegistry redisLockRegistry;
|
||||
|
||||
@Override
|
||||
public <T> void setCacheObject(final String key, final T value) {
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
|
||||
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expire(final String key, final long timeout) {
|
||||
return expire(key, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expire(final String key, final long timeout, final TimeUnit unit) {
|
||||
return Boolean.TRUE.equals(redisTemplate.expire(key, timeout, unit));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExpire(final String key) {
|
||||
return redisTemplate.getExpire(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean hasKey(String key) {
|
||||
return redisTemplate.hasKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getCacheObject(final String key) {
|
||||
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
||||
return operation.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteObject(final String key) {
|
||||
return Boolean.TRUE.equals(redisTemplate.delete(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long deleteObject(final Collection collection) {
|
||||
return redisTemplate.delete(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> long setCacheList(final String key, final List<T> dataList) {
|
||||
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
|
||||
return count == null ? 0 : count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getCacheList(final String key) {
|
||||
return redisTemplate.opsForList().range(key, 0, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
|
||||
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
|
||||
for (T t : dataSet) {
|
||||
setOperation.add(t);
|
||||
}
|
||||
return setOperation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Set<T> getCacheSet(final String key) {
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
|
||||
if (dataMap != null) {
|
||||
redisTemplate.opsForHash().putAll(key, dataMap);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Map<String, T> getCacheMap(final String key) {
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
|
||||
redisTemplate.opsForHash().put(key, hKey, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getCacheMapValue(final String key, final String hKey) {
|
||||
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
|
||||
return opsForHash.get(key, hKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
|
||||
return redisTemplate.opsForHash().multiGet(key, hKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> keys(final String pattern) {
|
||||
return redisTemplate.keys(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 分布式锁
|
||||
* @param key
|
||||
* @return
|
||||
* @Author DB
|
||||
* @Date: 2023/4/12 22:23
|
||||
*/
|
||||
@Override
|
||||
public Lock distributedLock(String key) {
|
||||
return redisLockRegistry.obtain(key);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package com.cpop.core.strategy;
|
||||
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.TreeNode;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.node.*;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 反序列化时 将数组转为逗号拼接 ["0","1","2"] -> "0","1","2"
|
||||
*
|
||||
* @author Lynn
|
||||
* @date 2022/11/8 14:36
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class ArrayToStringDeserializer extends JsonDeserializer<String> {
|
||||
|
||||
@Override
|
||||
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
|
||||
TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);
|
||||
if (treeNode instanceof IntNode) {
|
||||
return ((IntNode) treeNode).asText();
|
||||
} else if (treeNode instanceof LongNode) {
|
||||
return ((LongNode) treeNode).asText();
|
||||
} else if (treeNode instanceof DoubleNode) {
|
||||
return ((DoubleNode) treeNode).asText();
|
||||
} else if (treeNode instanceof ArrayNode) {
|
||||
//字符串数组,会多出两个引号,需要手动去除
|
||||
return StringUtils.replace(StringUtils.join((ArrayNode) treeNode, ","), "\"", "");
|
||||
} else if (treeNode instanceof TextNode) {
|
||||
return ((TextNode) treeNode).asText();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
package com.cpop.core.strategy;
|
||||
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 序列化时 逗号拼接转数组 "0","1","2" -> ["0","1","2"]
|
||||
*
|
||||
* @author Lynn
|
||||
* @date 2022/11/8 14:45
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class StringToArraySerializer extends JsonSerializer<String> {
|
||||
|
||||
@Override
|
||||
public void serialize(String str, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
|
||||
if (StringUtils.isNotBlank(str)) {
|
||||
String[] split = str.split(",");
|
||||
jsonGenerator.writeArray(split, 0, split.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
package com.cpop.core.utils;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
|
||||
/**
|
||||
* 获取i18n资源文件
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class MessageUtils {
|
||||
|
||||
/**
|
||||
* 根据消息键和参数 获取消息 委托给spring messageSource
|
||||
*
|
||||
* @param code 消息键
|
||||
* @param args 参数
|
||||
* @return 获取国际化翻译值
|
||||
*/
|
||||
public static String message(String code, Object... args) {
|
||||
MessageSource messageSource = SpringUtils.getBean(MessageSource.class);
|
||||
return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.cpop.core.utils;
|
||||
|
||||
import com.cpop.core.base.entity.LoginUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
/**
|
||||
* @author: DB
|
||||
* @date: 2022-09-26 23:06
|
||||
* @Description:
|
||||
*/
|
||||
public class SecurityUtils {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(SecurityUtils.class);
|
||||
|
||||
private SecurityUtils() {
|
||||
}
|
||||
|
||||
private static class securityUtilsInstance {
|
||||
private static final SecurityUtils INSTANCE = new SecurityUtils();
|
||||
}
|
||||
|
||||
public static SecurityUtils getInstance() {
|
||||
return securityUtilsInstance.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author LOST.yuan
|
||||
* @Description: 获取登录用户信息
|
||||
* @date 23:07 2022/9/26
|
||||
* @return {@link LoginUser}
|
||||
**/
|
||||
public LoginUser getLoginUser() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (null != authentication.getPrincipal()) {
|
||||
return (LoginUser) authentication.getPrincipal();
|
||||
} else {
|
||||
return (LoginUser) authentication.getDetails();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
189
Cpop-Core/src/main/java/com/cpop/core/utils/SpringUtils.java
Normal file
189
Cpop-Core/src/main/java/com/cpop/core/utils/SpringUtils.java
Normal file
@ -0,0 +1,189 @@
|
||||
package com.cpop.core.utils;
|
||||
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.cpop.core.base.entity.BaseEntity;
|
||||
import com.cpop.core.base.exception.BaseException;
|
||||
import com.mybatisflex.core.service.IService;
|
||||
import org.springframework.aop.framework.AopContext;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* spring工具类 方便在非spring管理环境中获取bean
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
@Component
|
||||
public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware {
|
||||
/**
|
||||
* Spring应用上下文环境
|
||||
*/
|
||||
private static ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
private static ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
SpringUtils.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
SpringUtils.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象
|
||||
*
|
||||
* @param name
|
||||
* @return Object 一个以所给名字注册的bean的实例
|
||||
* @throws BeansException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getBean(String name) throws BeansException {
|
||||
return (T) beanFactory.getBean(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型为requiredType的对象
|
||||
*
|
||||
* @param clz
|
||||
* @return
|
||||
* @throws BeansException
|
||||
*/
|
||||
public static <T> T getBean(Class<T> clz) throws BeansException {
|
||||
return (T) beanFactory.getBean(clz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
|
||||
*
|
||||
* @param name
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean containsBean(String name) {
|
||||
return beanFactory.containsBean(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
|
||||
*
|
||||
* @param name
|
||||
* @return boolean
|
||||
* @throws NoSuchBeanDefinitionException
|
||||
*/
|
||||
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
|
||||
return beanFactory.isSingleton(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return Class 注册对象的类型
|
||||
* @throws NoSuchBeanDefinitionException
|
||||
*/
|
||||
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
|
||||
return beanFactory.getType(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
* @throws NoSuchBeanDefinitionException
|
||||
*/
|
||||
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
|
||||
return beanFactory.getAliases(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取aop代理对象
|
||||
*
|
||||
* @param invoker
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getAopProxy(T invoker) {
|
||||
return (T) AopContext.currentProxy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前的环境配置,无配置返回null
|
||||
*
|
||||
* @return 当前的环境配置
|
||||
*/
|
||||
public static String[] getActiveProfiles() {
|
||||
return applicationContext.getEnvironment().getActiveProfiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前的环境配置,当有多个环境配置时,只获取第一个
|
||||
*
|
||||
* @return 当前的环境配置
|
||||
*/
|
||||
public static String getActiveProfile() {
|
||||
final String[] activeProfiles = getActiveProfiles();
|
||||
return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clazz
|
||||
* @param <T>
|
||||
* @return 返回Spring容器中service对象,防止Service循环调用出现的异常
|
||||
*/
|
||||
public <T extends BaseEntity> IService<T> getServiceBean(Class<T> clazz) {
|
||||
String name = clazz.getSimpleName();
|
||||
String service = nameToService(name);
|
||||
return getBean(service);
|
||||
}
|
||||
|
||||
private String nameToService(String name) {
|
||||
String entity = name.substring(0, 1).toLowerCase() + name.substring(1);
|
||||
return entity.replaceAll("", "") + "Service";
|
||||
}
|
||||
|
||||
public <T extends Object, E> List<T> copyProperties(List<E> sources, Class<T> clazz) {
|
||||
List<T> list = new ArrayList<>();
|
||||
if (sources == null || sources.isEmpty()) {
|
||||
return list;
|
||||
}
|
||||
for (E item : sources) {
|
||||
T t = null;
|
||||
try {
|
||||
t = clazz.newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
throw new BaseException(e.getMessage());
|
||||
}
|
||||
BeanUtils.copyProperties(item, t);
|
||||
list.add(t);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* StringToList
|
||||
*
|
||||
* @param longs
|
||||
* @return
|
||||
*/
|
||||
public List<Long> stringToLongList(String longs) {
|
||||
|
||||
if (StringUtils.isBlank(longs)) {
|
||||
return null;
|
||||
}
|
||||
String[] split = longs.split(",");
|
||||
return Arrays.stream(split).map(Long::valueOf).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package com.cpop.core.utils.file;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 文件类型工具类
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class FileTypeUtils {
|
||||
|
||||
public FileTypeUtils() {
|
||||
}
|
||||
|
||||
private static class FileTypeUtilsInstance {
|
||||
private static final FileTypeUtils INSTANCE = new FileTypeUtils();
|
||||
}
|
||||
|
||||
public static FileTypeUtils getInstance() {
|
||||
return FileTypeUtilsInstance.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件类型
|
||||
*
|
||||
* @param file 文件名
|
||||
* @return 后缀(不含".")
|
||||
*/
|
||||
public String getFileType(File file) {
|
||||
if (null == file) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
return getFileType(file.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件类型
|
||||
* @param fileName 文件名
|
||||
* @return 后缀(不含".")
|
||||
*/
|
||||
public String getFileType(String fileName) {
|
||||
int separatorIndex = fileName.lastIndexOf(".");
|
||||
if (separatorIndex < 0) {
|
||||
return "";
|
||||
}
|
||||
return fileName.substring(separatorIndex + 1).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件类型
|
||||
*
|
||||
* @param photoByte 文件字节码
|
||||
* @return 后缀(不含".")
|
||||
*/
|
||||
public String getFileExtendName(byte[] photoByte) {
|
||||
String strFileExtendName = "JPG";
|
||||
if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
|
||||
&& ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) {
|
||||
strFileExtendName = "GIF";
|
||||
} else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) {
|
||||
strFileExtendName = "JPG";
|
||||
} else if ((photoByte[0] == 66) && (photoByte[1] == 77)) {
|
||||
strFileExtendName = "BMP";
|
||||
} else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) {
|
||||
strFileExtendName = "PNG";
|
||||
}
|
||||
return strFileExtendName;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,207 @@
|
||||
package com.cpop.core.utils.file;
|
||||
|
||||
import com.cpop.core.config.CpopConfig;
|
||||
import com.cpop.common.constant.Constants;
|
||||
import com.cpop.common.utils.DateUtils;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.cpop.core.base.exception.file.FileNameLengthLimitExceededException;
|
||||
import com.cpop.core.base.exception.file.FileSizeLimitExceededException;
|
||||
import com.cpop.core.base.exception.file.InvalidExtensionException;
|
||||
import com.cpop.core.utils.uuid.Seq;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 文件上传工具类
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class FileUploadUtils {
|
||||
|
||||
public FileUploadUtils() {
|
||||
}
|
||||
|
||||
private static class FileUploadUtilsInstance {
|
||||
private static final FileUploadUtils INSTANCE = new FileUploadUtils();
|
||||
}
|
||||
|
||||
public static FileUploadUtils getInstance() {
|
||||
return FileUploadUtilsInstance.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认大小 50M
|
||||
*/
|
||||
public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* 默认的文件名最大长度 100
|
||||
*/
|
||||
public static final int DEFAULT_FILE_NAME_LENGTH = 100;
|
||||
|
||||
/**
|
||||
* 默认上传的地址
|
||||
*/
|
||||
private static String defaultBaseDir = CpopConfig.getProfile();
|
||||
|
||||
public void setDefaultBaseDir(String defaultBaseDir) {
|
||||
FileUploadUtils.defaultBaseDir = defaultBaseDir;
|
||||
}
|
||||
|
||||
public String getDefaultBaseDir() {
|
||||
return defaultBaseDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以默认配置进行文件上传
|
||||
*
|
||||
* @param file 上传的文件
|
||||
* @return 文件名称
|
||||
* @throws Exception
|
||||
*/
|
||||
public final String upload(MultipartFile file) throws IOException {
|
||||
try {
|
||||
return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件路径上传
|
||||
*
|
||||
* @param baseDir 相对应用的基目录
|
||||
* @param file 上传的文件
|
||||
* @return 文件名称
|
||||
* @throws IOException
|
||||
*/
|
||||
public final String upload(String baseDir, MultipartFile file) throws IOException {
|
||||
try {
|
||||
return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @param baseDir 相对应用的基目录
|
||||
* @param file 上传的文件
|
||||
* @param allowedExtension 上传文件类型
|
||||
* @return 返回上传成功的文件名
|
||||
* @throws FileSizeLimitExceededException 如果超出最大大小
|
||||
* @throws FileNameLengthLimitExceededException 文件名太长
|
||||
* @throws IOException 比如读写文件出错时
|
||||
* @throws InvalidExtensionException 文件校验异常
|
||||
*/
|
||||
public final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
|
||||
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
|
||||
InvalidExtensionException {
|
||||
int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length();
|
||||
if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
|
||||
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
|
||||
}
|
||||
assertAllowed(file, allowedExtension);
|
||||
String fileName = extractFilename(file);
|
||||
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
|
||||
file.transferTo(Paths.get(absPath));
|
||||
return getPathFileName(baseDir, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码文件名
|
||||
*/
|
||||
public final String extractFilename(MultipartFile file) {
|
||||
return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
|
||||
FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
|
||||
}
|
||||
|
||||
public final File getAbsoluteFile(String uploadDir, String fileName) throws IOException {
|
||||
File desc = new File(uploadDir + File.separator + fileName);
|
||||
|
||||
if (!desc.exists()) {
|
||||
if (!desc.getParentFile().exists()) {
|
||||
desc.getParentFile().mkdirs();
|
||||
}
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
public final String getPathFileName(String uploadDir, String fileName) throws IOException {
|
||||
int dirLastIndex = CpopConfig.getProfile().length() + 1;
|
||||
String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
|
||||
return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件大小校验
|
||||
*
|
||||
* @param file 上传的文件
|
||||
* @return
|
||||
* @throws FileSizeLimitExceededException 如果超出最大大小
|
||||
* @throws InvalidExtensionException
|
||||
*/
|
||||
public final void assertAllowed(MultipartFile file, String[] allowedExtension)
|
||||
throws FileSizeLimitExceededException, InvalidExtensionException {
|
||||
long size = file.getSize();
|
||||
if (size > DEFAULT_MAX_SIZE) {
|
||||
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
|
||||
}
|
||||
|
||||
String fileName = file.getOriginalFilename();
|
||||
String extension = getExtension(file);
|
||||
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
|
||||
if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) {
|
||||
throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
|
||||
fileName);
|
||||
} else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) {
|
||||
throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
|
||||
fileName);
|
||||
} else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) {
|
||||
throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
|
||||
fileName);
|
||||
} else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) {
|
||||
throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
|
||||
fileName);
|
||||
} else {
|
||||
throw new InvalidExtensionException(allowedExtension, extension, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断MIME类型是否是允许的MIME类型
|
||||
*
|
||||
* @param extension
|
||||
* @param allowedExtension
|
||||
* @return
|
||||
*/
|
||||
public final boolean isAllowedExtension(String extension, String[] allowedExtension) {
|
||||
for (String str : allowedExtension) {
|
||||
if (str.equalsIgnoreCase(extension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名的后缀
|
||||
*
|
||||
* @param file 表单文件
|
||||
* @return 后缀名
|
||||
*/
|
||||
public final String getExtension(MultipartFile file) {
|
||||
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
||||
if (StringUtils.isEmpty(extension)) {
|
||||
extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
|
||||
}
|
||||
return extension;
|
||||
}
|
||||
}
|
||||
312
Cpop-Core/src/main/java/com/cpop/core/utils/file/FileUtils.java
Normal file
312
Cpop-Core/src/main/java/com/cpop/core/utils/file/FileUtils.java
Normal file
@ -0,0 +1,312 @@
|
||||
package com.cpop.core.utils.file;
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.context.AnalysisContext;
|
||||
import com.alibaba.excel.read.listener.ReadListener;
|
||||
import com.cpop.common.utils.DateUtils;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.cpop.core.base.exception.UtilException;
|
||||
import com.cpop.core.config.CpopConfig;
|
||||
import com.cpop.core.utils.uuid.IdUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件处理工具类
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class FileUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FileUtils.class);
|
||||
|
||||
public FileUtils() {
|
||||
}
|
||||
|
||||
private static class FileUtilsInstance {
|
||||
private static final FileUtils INSTANCE = new FileUtils();
|
||||
}
|
||||
|
||||
public static FileUtils getInstance() {
|
||||
return FileUtilsInstance.INSTANCE;
|
||||
}
|
||||
|
||||
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
|
||||
|
||||
/**
|
||||
* 输出指定文件的byte数组
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param os 输出流
|
||||
* @return
|
||||
*/
|
||||
public void writeBytes(String filePath, OutputStream os) throws IOException {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
File file = new File(filePath);
|
||||
if (!file.exists()) {
|
||||
throw new FileNotFoundException(filePath);
|
||||
}
|
||||
fis = new FileInputStream(file);
|
||||
byte[] b = new byte[1024];
|
||||
int length;
|
||||
while ((length = fis.read(b)) > 0) {
|
||||
os.write(b, 0, length);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} finally {
|
||||
IOUtils.close(os);
|
||||
IOUtils.close(fis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写数据到文件中
|
||||
*
|
||||
* @param data 数据
|
||||
* @return 目标文件
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public String writeImportBytes(byte[] data) throws IOException {
|
||||
return writeBytes(data, CpopConfig.getImportPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 写数据到文件中
|
||||
*
|
||||
* @param data 数据
|
||||
* @param uploadDir 目标文件
|
||||
* @return 目标文件
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public String writeBytes(byte[] data, String uploadDir) throws IOException {
|
||||
FileOutputStream fos = null;
|
||||
String pathName = "";
|
||||
try {
|
||||
String extension = getFileExtendName(data);
|
||||
pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
|
||||
File file = FileUploadUtils.getInstance().getAbsoluteFile(uploadDir, pathName);
|
||||
fos = new FileOutputStream(file);
|
||||
fos.write(data);
|
||||
} finally {
|
||||
IOUtils.close(fos);
|
||||
}
|
||||
return FileUploadUtils.getInstance().getPathFileName(uploadDir, pathName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param filePath 文件
|
||||
* @return
|
||||
*/
|
||||
public boolean deleteFile(String filePath) {
|
||||
boolean flag = false;
|
||||
File file = new File(filePath);
|
||||
// 路径为文件且不为空则进行删除
|
||||
if (file.isFile() && file.exists()) {
|
||||
flag = file.delete();
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件名称验证
|
||||
*
|
||||
* @param filename 文件名称
|
||||
* @return true 正常 false 非法
|
||||
*/
|
||||
public boolean isValidFilename(String filename) {
|
||||
return filename.matches(FILENAME_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否可下载
|
||||
*
|
||||
* @param resource 需要下载的文件
|
||||
* @return true 正常 false 非法
|
||||
*/
|
||||
public boolean checkAllowDownload(String resource) {
|
||||
// 禁止目录上跳级别
|
||||
if (StringUtils.contains(resource, "..")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查允许下载的文件规则
|
||||
if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getInstance().getFileType(resource))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 不在允许下载的文件规则
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件名重新编码
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @param fileName 文件名
|
||||
* @return 编码后的文件名
|
||||
*/
|
||||
public String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException {
|
||||
final String agent = request.getHeader("USER-AGENT");
|
||||
String filename = fileName;
|
||||
if (agent.contains("MSIE")) {
|
||||
// IE浏览器
|
||||
filename = URLEncoder.encode(filename, "utf-8");
|
||||
filename = filename.replace("+", " ");
|
||||
} else if (agent.contains("Firefox")) {
|
||||
// 火狐浏览器
|
||||
filename = new String(fileName.getBytes(), "ISO8859-1");
|
||||
} else if (agent.contains("Chrome")) {
|
||||
// google浏览器
|
||||
filename = URLEncoder.encode(filename, "utf-8");
|
||||
} else {
|
||||
// 其它浏览器
|
||||
filename = URLEncoder.encode(filename, "utf-8");
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件名重新编码
|
||||
*
|
||||
* @param response 响应对象
|
||||
* @param realFileName 真实文件名
|
||||
*/
|
||||
public void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException {
|
||||
String percentEncodedFileName = percentEncode(realFileName);
|
||||
|
||||
StringBuilder contentDispositionValue = new StringBuilder();
|
||||
contentDispositionValue.append("attachment; filename=")
|
||||
.append(percentEncodedFileName)
|
||||
.append(";")
|
||||
.append("filename*=")
|
||||
.append("utf-8''")
|
||||
.append(percentEncodedFileName);
|
||||
|
||||
response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
|
||||
response.setHeader("Content-disposition", contentDispositionValue.toString());
|
||||
response.setHeader("download-filename", percentEncodedFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 百分号编码工具方法
|
||||
*
|
||||
* @param s 需要百分号编码的字符串
|
||||
* @return 百分号编码后的字符串
|
||||
*/
|
||||
public String percentEncode(String s) throws UnsupportedEncodingException {
|
||||
String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
|
||||
return encode.replaceAll("\\+", "%20");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取图像后缀
|
||||
*
|
||||
* @param photoByte 图像数据
|
||||
* @return 后缀名
|
||||
*/
|
||||
public String getFileExtendName(byte[] photoByte) {
|
||||
String strFileExtendName = "jpg";
|
||||
if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
|
||||
&& ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) {
|
||||
strFileExtendName = "gif";
|
||||
} else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) {
|
||||
strFileExtendName = "jpg";
|
||||
} else if ((photoByte[0] == 66) && (photoByte[1] == 77)) {
|
||||
strFileExtendName = "bmp";
|
||||
} else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) {
|
||||
strFileExtendName = "png";
|
||||
}
|
||||
return strFileExtendName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png
|
||||
*
|
||||
* @param fileName 路径名称
|
||||
* @return 没有文件路径的名称
|
||||
*/
|
||||
public String getName(String fileName) {
|
||||
if (fileName == null) {
|
||||
return null;
|
||||
}
|
||||
int lastUnixPos = fileName.lastIndexOf('/');
|
||||
int lastWindowsPos = fileName.lastIndexOf('\\');
|
||||
int index = Math.max(lastUnixPos, lastWindowsPos);
|
||||
return fileName.substring(index + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi
|
||||
*
|
||||
* @param fileName 路径名称
|
||||
* @return 没有文件路径和后缀的名称
|
||||
*/
|
||||
public String getNameNotSuffix(String fileName) {
|
||||
if (fileName == null) {
|
||||
return null;
|
||||
}
|
||||
String baseName = FilenameUtils.getBaseName(fileName);
|
||||
return baseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 下载Excel
|
||||
* @param response
|
||||
* @return
|
||||
* @author DB
|
||||
* @Date: 2023/7/14 0014 13:42
|
||||
*/
|
||||
public void downloadExcel(HttpServletResponse response, List<T> list) {
|
||||
// 写入数据
|
||||
try {
|
||||
response.setContentType("application/vnd.excel");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
String fileName = URLEncoder.encode("file", "UTF-8").replaceAll("\\+", "%20");
|
||||
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
|
||||
EasyExcel.write(response.getOutputStream(), T.class).sheet("sheet1").doWrite(list);
|
||||
} catch (IOException e) {
|
||||
throw new UtilException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 读取Excel
|
||||
* @param filePath
|
||||
* @param list
|
||||
* @return
|
||||
* @author DB
|
||||
* @Date: 2023/7/14 0014 13:53
|
||||
*/
|
||||
public void readExcel(String filePath, List<T> list) {
|
||||
//excel文件路径
|
||||
File file = new File(filePath);
|
||||
EasyExcel.read(file, T.class, new ReadListener<T>() {
|
||||
@Override
|
||||
public void invoke(T t, AnalysisContext analysisContext) {
|
||||
list.add(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
|
||||
LOGGER.info("read finished");
|
||||
}
|
||||
}).sheet("sheet1").doRead();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
package com.cpop.core.utils.file;
|
||||
|
||||
/**
|
||||
* 媒体类型工具类
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class MimeTypeUtils {
|
||||
public static final String IMAGE_PNG = "image/png";
|
||||
|
||||
public static final String IMAGE_JPG = "image/jpg";
|
||||
|
||||
public static final String IMAGE_JPEG = "image/jpeg";
|
||||
|
||||
public static final String IMAGE_BMP = "image/bmp";
|
||||
|
||||
public static final String IMAGE_GIF = "image/gif";
|
||||
|
||||
public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"};
|
||||
|
||||
public static final String[] FLASH_EXTENSION = {"swf", "flv"};
|
||||
|
||||
public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
|
||||
"asf", "rm", "rmvb"};
|
||||
|
||||
public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"};
|
||||
|
||||
public static final String[] DEFAULT_ALLOWED_EXTENSION = {
|
||||
// 图片
|
||||
"bmp", "gif", "jpg", "jpeg", "png",
|
||||
// word excel powerpoint
|
||||
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
|
||||
// 压缩文件
|
||||
"rar", "zip", "gz", "bz2",
|
||||
// 视频格式
|
||||
"mp4", "avi", "rmvb",
|
||||
// pdf
|
||||
"pdf"};
|
||||
|
||||
public static String getExtension(String prefix) {
|
||||
switch (prefix) {
|
||||
case IMAGE_PNG:
|
||||
return "png";
|
||||
case IMAGE_JPG:
|
||||
return "jpg";
|
||||
case IMAGE_JPEG:
|
||||
return "jpeg";
|
||||
case IMAGE_BMP:
|
||||
return "bmp";
|
||||
case IMAGE_GIF:
|
||||
return "gif";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
101
Cpop-Core/src/main/java/com/cpop/core/utils/sql/SqlUtils.java
Normal file
101
Cpop-Core/src/main/java/com/cpop/core/utils/sql/SqlUtils.java
Normal file
@ -0,0 +1,101 @@
|
||||
package com.cpop.core.utils.sql;
|
||||
|
||||
import com.cpop.common.utils.ServletUtils;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
import com.cpop.core.base.entity.PageDomain;
|
||||
import com.cpop.core.base.exception.UtilException;
|
||||
|
||||
/**
|
||||
* sql操作工具类
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public class SqlUtils {
|
||||
|
||||
public SqlUtils() {
|
||||
}
|
||||
|
||||
private static class SqlUtilInstance {
|
||||
private static final SqlUtils INSTANCE = new SqlUtils();
|
||||
}
|
||||
|
||||
public static SqlUtils getInstance() {
|
||||
return SqlUtilInstance.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前记录起始索引
|
||||
*/
|
||||
public final String PAGE_NUM = "page";
|
||||
|
||||
/**
|
||||
* 每页显示记录数
|
||||
*/
|
||||
public final String PAGE_SIZE = "pageSize";
|
||||
|
||||
/**
|
||||
* 排序列
|
||||
*/
|
||||
public final String ORDER_BY_COLUMN = "orderByColumn";
|
||||
|
||||
/**
|
||||
* 排序的方向 "desc" 或者 "asc".
|
||||
*/
|
||||
public final String IS_ASC = "isAsc";
|
||||
|
||||
/**
|
||||
* 分页参数合理化
|
||||
*/
|
||||
public final String REASONABLE = "reasonable";
|
||||
|
||||
/**
|
||||
* 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
|
||||
*/
|
||||
public final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
|
||||
|
||||
/**
|
||||
* 封装分页对象
|
||||
*/
|
||||
public PageDomain getPageDomain() {
|
||||
PageDomain pageDomain = new PageDomain();
|
||||
pageDomain.setPageNum(ServletUtils.getParameterToInt(PAGE_NUM));
|
||||
pageDomain.setPageSize(ServletUtils.getParameterToInt(PAGE_SIZE));
|
||||
pageDomain.setOrderByColumn(null == ServletUtils.getParameter(ORDER_BY_COLUMN) ? null : SqlUtils.getInstance().escapeOrderBySql(ServletUtils.getParameter(ORDER_BY_COLUMN)));
|
||||
pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
|
||||
pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));
|
||||
return pageDomain;
|
||||
}
|
||||
|
||||
public PageDomain buildPageRequest() {
|
||||
return getPageDomain();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查字符,防止注入绕过
|
||||
*/
|
||||
public String escapeOrderBySql(String value) {
|
||||
if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) {
|
||||
throw new UtilException("参数不符合规范,不能进行查询");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证 order by 语法是否符合规范
|
||||
*/
|
||||
public boolean isValidOrderBySql(String value) {
|
||||
return value.matches(SQL_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求排序数据
|
||||
*/
|
||||
public String startOrderBy() {
|
||||
PageDomain pageDomain = getPageDomain();
|
||||
if (StringUtils.isNotEmpty(pageDomain.getOrderBy())) {
|
||||
return escapeOrderBySql(pageDomain.getOrderBy());
|
||||
}else {
|
||||
throw new UtilException("获取排序参数失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.cpop.core.utils.uuid;
|
||||
|
||||
/**
|
||||
* ID生成器工具类
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
92
Cpop-Core/src/main/java/com/cpop/core/utils/uuid/Seq.java
Normal file
92
Cpop-Core/src/main/java/com/cpop/core/utils/uuid/Seq.java
Normal file
@ -0,0 +1,92 @@
|
||||
package com.cpop.core.utils.uuid;
|
||||
|
||||
|
||||
import com.cpop.common.utils.DateUtils;
|
||||
import com.cpop.common.utils.StringUtils;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @author DB 序列生成类
|
||||
*/
|
||||
public class Seq {
|
||||
/**
|
||||
* 通用序列类型
|
||||
*/
|
||||
public static final String commSeqType = "COMMON";
|
||||
|
||||
/**
|
||||
* 上传序列类型
|
||||
*/
|
||||
public static final String uploadSeqType = "UPLOAD";
|
||||
|
||||
/**
|
||||
* 通用接口序列数
|
||||
*/
|
||||
private static AtomicInteger commSeq = new AtomicInteger(1);
|
||||
|
||||
/**
|
||||
* 上传接口序列数
|
||||
*/
|
||||
private static AtomicInteger uploadSeq = new AtomicInteger(1);
|
||||
|
||||
/**
|
||||
* 机器标识
|
||||
*/
|
||||
private static final String machineCode = "A";
|
||||
|
||||
/**
|
||||
* 获取通用序列号
|
||||
*
|
||||
* @return 序列值
|
||||
*/
|
||||
public static String getId() {
|
||||
return getId(commSeqType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
|
||||
*
|
||||
* @return 序列值
|
||||
*/
|
||||
public static String getId(String type) {
|
||||
AtomicInteger atomicInt = commSeq;
|
||||
if (uploadSeqType.equals(type)) {
|
||||
atomicInt = uploadSeq;
|
||||
}
|
||||
return getId(atomicInt, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
|
||||
*
|
||||
* @param atomicInt 序列数
|
||||
* @param length 数值长度
|
||||
* @return 序列值
|
||||
*/
|
||||
public static String getId(AtomicInteger atomicInt, int length) {
|
||||
String result = DateUtils.dateTimeNow();
|
||||
result += machineCode;
|
||||
result += getSeq(atomicInt, length);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
|
||||
*
|
||||
* @return 序列值
|
||||
*/
|
||||
private synchronized static String getSeq(AtomicInteger atomicInt, int length) {
|
||||
// 先取值再+1
|
||||
int value = atomicInt.getAndIncrement();
|
||||
|
||||
// 如果更新后值>=10 的 (length)幂次方则重置为1
|
||||
int maxSeq = (int) Math.pow(10, length);
|
||||
if (atomicInt.get() >= maxSeq) {
|
||||
atomicInt.set(1);
|
||||
}
|
||||
// 转字符串,用0左补齐
|
||||
return StringUtils.padL(value, length);
|
||||
}
|
||||
}
|
||||
|
||||
447
Cpop-Core/src/main/java/com/cpop/core/utils/uuid/UUID.java
Normal file
447
Cpop-Core/src/main/java/com/cpop/core/utils/uuid/UUID.java
Normal file
@ -0,0 +1,447 @@
|
||||
package com.cpop.core.utils.uuid;
|
||||
|
||||
import com.cpop.core.base.exception.UtilException;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* 提供通用唯一识别码(universally unique identifier)(UUID)实现
|
||||
*
|
||||
* @author DB
|
||||
*/
|
||||
public final class UUID implements java.io.Serializable, Comparable<UUID> {
|
||||
private static final long serialVersionUID = -1185015143654744140L;
|
||||
|
||||
/**
|
||||
* SecureRandom 的单例
|
||||
*/
|
||||
private static class Holder {
|
||||
static final SecureRandom numberGenerator = getSecureRandom();
|
||||
}
|
||||
|
||||
/**
|
||||
* 此UUID的最高64有效位
|
||||
*/
|
||||
private final long mostSigBits;
|
||||
|
||||
/**
|
||||
* 此UUID的最低64有效位
|
||||
*/
|
||||
private final long leastSigBits;
|
||||
|
||||
/**
|
||||
* 私有构造
|
||||
*
|
||||
* @param data 数据
|
||||
*/
|
||||
private UUID(byte[] data) {
|
||||
long msb = 0;
|
||||
long lsb = 0;
|
||||
assert data.length == 16 : "data must be 16 bytes in length";
|
||||
for (int i = 0; i < 8; i++) {
|
||||
msb = (msb << 8) | (data[i] & 0xff);
|
||||
}
|
||||
for (int i = 8; i < 16; i++) {
|
||||
lsb = (lsb << 8) | (data[i] & 0xff);
|
||||
}
|
||||
this.mostSigBits = msb;
|
||||
this.leastSigBits = lsb;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定的数据构造新的 UUID。
|
||||
*
|
||||
* @param mostSigBits 用于 {@code UUID} 的最高有效 64 位
|
||||
* @param leastSigBits 用于 {@code UUID} 的最低有效 64 位
|
||||
*/
|
||||
public UUID(long mostSigBits, long leastSigBits) {
|
||||
this.mostSigBits = mostSigBits;
|
||||
this.leastSigBits = leastSigBits;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。
|
||||
*
|
||||
* @return 随机生成的 {@code UUID}
|
||||
*/
|
||||
public static UUID fastUUID() {
|
||||
return randomUUID(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
|
||||
*
|
||||
* @return 随机生成的 {@code UUID}
|
||||
*/
|
||||
public static UUID randomUUID() {
|
||||
return randomUUID(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
|
||||
*
|
||||
* @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能
|
||||
* @return 随机生成的 {@code UUID}
|
||||
*/
|
||||
public static UUID randomUUID(boolean isSecure) {
|
||||
final Random ng = isSecure ? Holder.numberGenerator : getRandom();
|
||||
|
||||
byte[] randomBytes = new byte[16];
|
||||
ng.nextBytes(randomBytes);
|
||||
//clear version
|
||||
randomBytes[6] &= 0x0f;
|
||||
//set to version 4
|
||||
randomBytes[6] |= 0x40;
|
||||
//clear variant
|
||||
randomBytes[8] &= 0x3f;
|
||||
//set to IETF variant
|
||||
randomBytes[8] |= 0x80;
|
||||
return new UUID(randomBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。
|
||||
*
|
||||
* @param name 用于构造 UUID 的字节数组。
|
||||
* @return 根据指定数组生成的 {@code UUID}
|
||||
*/
|
||||
public static UUID nameUUIDFromBytes(byte[] name) {
|
||||
MessageDigest md;
|
||||
try {
|
||||
md = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new InternalError("MD5 not supported");
|
||||
}
|
||||
byte[] md5Bytes = md.digest(name);
|
||||
//clear version
|
||||
md5Bytes[6] &= 0x0f;
|
||||
//set to version 3
|
||||
md5Bytes[6] |= 0x30;
|
||||
//clear variant
|
||||
md5Bytes[8] &= 0x3f;
|
||||
//set to IETF variant
|
||||
md5Bytes[8] |= 0x80;
|
||||
return new UUID(md5Bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。
|
||||
*
|
||||
* @param name 指定 {@code UUID} 字符串
|
||||
* @return 具有指定值的 {@code UUID}
|
||||
* @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常
|
||||
*/
|
||||
public static UUID fromString(String name) {
|
||||
String[] components = name.split("-");
|
||||
if (components.length != 5) {
|
||||
throw new IllegalArgumentException("Invalid UUID string: " + name);
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
components[i] = "0x" + components[i];
|
||||
}
|
||||
|
||||
long mostSigBits = Long.decode(components[0]).longValue();
|
||||
mostSigBits <<= 16;
|
||||
mostSigBits |= Long.decode(components[1]).longValue();
|
||||
mostSigBits <<= 16;
|
||||
mostSigBits |= Long.decode(components[2]).longValue();
|
||||
|
||||
long leastSigBits = Long.decode(components[3]).longValue();
|
||||
leastSigBits <<= 48;
|
||||
leastSigBits |= Long.decode(components[4]).longValue();
|
||||
|
||||
return new UUID(mostSigBits, leastSigBits);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此 UUID 的 128 位值中的最低有效 64 位。
|
||||
*
|
||||
* @return 此 UUID 的 128 位值中的最低有效 64 位。
|
||||
*/
|
||||
public long getLeastSignificantBits() {
|
||||
return leastSigBits;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此 UUID 的 128 位值中的最高有效 64 位。
|
||||
*
|
||||
* @return 此 UUID 的 128 位值中最高有效 64 位。
|
||||
*/
|
||||
public long getMostSignificantBits() {
|
||||
return mostSigBits;
|
||||
}
|
||||
|
||||
/**
|
||||
* 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。
|
||||
* <p>
|
||||
* 版本号具有以下含意:
|
||||
* <ul>
|
||||
* <li>1 基于时间的 UUID
|
||||
* <li>2 DCE 安全 UUID
|
||||
* <li>3 基于名称的 UUID
|
||||
* <li>4 随机生成的 UUID
|
||||
* </ul>
|
||||
*
|
||||
* @return 此 {@code UUID} 的版本号
|
||||
*/
|
||||
public int version() {
|
||||
// Version is bits masked by 0x000000000000F000 in MS long
|
||||
return (int) ((mostSigBits >> 12) & 0x0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。
|
||||
* <p>
|
||||
* 变体号具有以下含意:
|
||||
* <ul>
|
||||
* <li>0 为 NCS 向后兼容保留
|
||||
* <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF RFC 4122</a>(Leach-Salz), 用于此类
|
||||
* <li>6 保留,微软向后兼容
|
||||
* <li>7 保留供以后定义使用
|
||||
* </ul>
|
||||
*
|
||||
* @return 此 {@code UUID} 相关联的变体号
|
||||
*/
|
||||
public int variant() {
|
||||
// This field is composed of a varying number of bits.
|
||||
// 0 - - Reserved for NCS backward compatibility
|
||||
// 1 0 - The IETF aka Leach-Salz variant (used by this class)
|
||||
// 1 1 0 Reserved, Microsoft backward compatibility
|
||||
// 1 1 1 Reserved for future definition.
|
||||
return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63));
|
||||
}
|
||||
|
||||
/**
|
||||
* 与此 UUID 相关联的时间戳值。
|
||||
*
|
||||
* <p>
|
||||
* 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。<br>
|
||||
* 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。
|
||||
*
|
||||
* <p>
|
||||
* 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>
|
||||
* 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。
|
||||
*
|
||||
* @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。
|
||||
*/
|
||||
public long timestamp() throws UnsupportedOperationException {
|
||||
checkTimeBase();
|
||||
return (mostSigBits & 0x0FFFL) << 48
|
||||
| ((mostSigBits >> 16) & 0x0FFFFL) << 32
|
||||
| mostSigBits >>> 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* 与此 UUID 相关联的时钟序列值。
|
||||
*
|
||||
* <p>
|
||||
* 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。
|
||||
* <p>
|
||||
* {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出
|
||||
* UnsupportedOperationException。
|
||||
*
|
||||
* @return 此 {@code UUID} 的时钟序列
|
||||
* @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
|
||||
*/
|
||||
public int clockSequence() throws UnsupportedOperationException {
|
||||
checkTimeBase();
|
||||
return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);
|
||||
}
|
||||
|
||||
/**
|
||||
* 与此 UUID 相关的节点值。
|
||||
*
|
||||
* <p>
|
||||
* 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。
|
||||
* <p>
|
||||
* 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>
|
||||
* 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。
|
||||
*
|
||||
* @return 此 {@code UUID} 的节点值
|
||||
* @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
|
||||
*/
|
||||
public long node() throws UnsupportedOperationException {
|
||||
checkTimeBase();
|
||||
return leastSigBits & 0x0000FFFFFFFFFFFFL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此{@code UUID} 的字符串表现形式。
|
||||
*
|
||||
* <p>
|
||||
* UUID 的字符串表示形式由此 BNF 描述:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
|
||||
* time_low = 4*<hexOctet>
|
||||
* time_mid = 2*<hexOctet>
|
||||
* time_high_and_version = 2*<hexOctet>
|
||||
* variant_and_sequence = 2*<hexOctet>
|
||||
* node = 6*<hexOctet>
|
||||
* hexOctet = <hexDigit><hexDigit>
|
||||
* hexDigit = [0-9a-fA-F]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @return 此{@code UUID} 的字符串表现形式
|
||||
* @see #toString(boolean)
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此{@code UUID} 的字符串表现形式。
|
||||
*
|
||||
* <p>
|
||||
* UUID 的字符串表示形式由此 BNF 描述:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
|
||||
* time_low = 4*<hexOctet>
|
||||
* time_mid = 2*<hexOctet>
|
||||
* time_high_and_version = 2*<hexOctet>
|
||||
* variant_and_sequence = 2*<hexOctet>
|
||||
* node = 6*<hexOctet>
|
||||
* hexOctet = <hexDigit><hexDigit>
|
||||
* hexDigit = [0-9a-fA-F]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串
|
||||
* @return 此{@code UUID} 的字符串表现形式
|
||||
*/
|
||||
public String toString(boolean isSimple) {
|
||||
final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);
|
||||
// time_low
|
||||
builder.append(digits(mostSigBits >> 32, 8));
|
||||
if (!isSimple) {
|
||||
builder.append('-');
|
||||
}
|
||||
// time_mid
|
||||
builder.append(digits(mostSigBits >> 16, 4));
|
||||
if (!isSimple) {
|
||||
builder.append('-');
|
||||
}
|
||||
// time_high_and_version
|
||||
builder.append(digits(mostSigBits, 4));
|
||||
if (!isSimple) {
|
||||
builder.append('-');
|
||||
}
|
||||
// variant_and_sequence
|
||||
builder.append(digits(leastSigBits >> 48, 4));
|
||||
if (!isSimple) {
|
||||
builder.append('-');
|
||||
}
|
||||
// node
|
||||
builder.append(digits(leastSigBits, 12));
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此 UUID 的哈希码。
|
||||
*
|
||||
* @return UUID 的哈希码值。
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
long hilo = mostSigBits ^ leastSigBits;
|
||||
return ((int) (hilo >> 32)) ^ (int) hilo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将此对象与指定对象比较。
|
||||
* <p>
|
||||
* 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。
|
||||
*
|
||||
* @param obj 要与之比较的对象
|
||||
* @return 如果对象相同,则返回 {@code true};否则返回 {@code false}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ((null == obj) || (obj.getClass() != UUID.class)) {
|
||||
return false;
|
||||
}
|
||||
UUID id = (UUID) obj;
|
||||
return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits);
|
||||
}
|
||||
|
||||
// Comparison Operations
|
||||
|
||||
/**
|
||||
* 将此 UUID 与指定的 UUID 比较。
|
||||
*
|
||||
* <p>
|
||||
* 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。
|
||||
*
|
||||
* @param val 与此 UUID 比较的 UUID
|
||||
* @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(UUID val) {
|
||||
// The ordering is intentionally set up so that the UUIDs
|
||||
// can simply be numerically compared as two numbers
|
||||
return (this.mostSigBits < val.mostSigBits ? -1 :
|
||||
(this.mostSigBits > val.mostSigBits ? 1 :
|
||||
(Long.compare(this.leastSigBits, val.leastSigBits))));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Private method start
|
||||
|
||||
/**
|
||||
* 返回指定数字对应的hex值
|
||||
*
|
||||
* @param val 值
|
||||
* @param digits 位
|
||||
* @return 值
|
||||
*/
|
||||
private static String digits(long val, int digits) {
|
||||
long hi = 1L << (digits * 4);
|
||||
return Long.toHexString(hi | (val & (hi - 1))).substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为time-based版本UUID
|
||||
*/
|
||||
private void checkTimeBase() {
|
||||
if (version() != 1) {
|
||||
throw new UnsupportedOperationException("Not a time-based UUID");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
|
||||
*
|
||||
* @return {@link SecureRandom}
|
||||
*/
|
||||
public static SecureRandom getSecureRandom() {
|
||||
try {
|
||||
return SecureRandom.getInstance("SHA1PRNG");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new UtilException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机数生成器对象<br>
|
||||
* ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。
|
||||
*
|
||||
* @return {@link ThreadLocalRandom}
|
||||
*/
|
||||
public static ThreadLocalRandom getRandom() {
|
||||
return ThreadLocalRandom.current();
|
||||
}
|
||||
}
|
||||
1
Cpop-Core/src/main/resources/application.properties
Normal file
1
Cpop-Core/src/main/resources/application.properties
Normal file
@ -0,0 +1 @@
|
||||
|
||||
303
Cpop-Core/src/main/resources/mapper/CoreMapper.xml
Normal file
303
Cpop-Core/src/main/resources/mapper/CoreMapper.xml
Normal file
@ -0,0 +1,303 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.cpop.core.mapper.CoreMapper">
|
||||
|
||||
<!--插入操作日志-->
|
||||
<insert id="insertOperationLog">
|
||||
INSERT INTO cp_sys_operation_log
|
||||
(id, operation_user_id, operation_user_name, operation_user_type, code, info, dev_ip, result, level, action_type, fail_reason, description,
|
||||
create_time, update_time, create_user_id, update_user_id)
|
||||
VALUES
|
||||
(#{id}, #{operationUserId}, #{operationUserName}, #{operationUserType}, #{code}, #{info}, #{devIp}, #{result}, #{level}, #{actionType}, #{failReason}, #{description},
|
||||
now(), now(), #{createUserId}, #{updateUserId})
|
||||
</insert>
|
||||
|
||||
<!--更新系统用户登录地址-->
|
||||
<update id="updateSysUserLoginIp">
|
||||
UPDATE
|
||||
cp_sys_user
|
||||
SET
|
||||
login_ip = #{ipAddr}
|
||||
WHERE
|
||||
user_name = #{username}
|
||||
</update>
|
||||
|
||||
<!--根据用户名获取用户信息-->
|
||||
<select id="getSysUser" resultType="com.cpop.core.base.table.SysUser">
|
||||
SELECT
|
||||
id,
|
||||
user_name AS userName,
|
||||
password,
|
||||
nick_name AS nickName,
|
||||
email,
|
||||
phone_number AS phoneNumber,
|
||||
sex,
|
||||
avatar,
|
||||
salt,
|
||||
status,
|
||||
login_ip AS loginIp,
|
||||
user_type AS userType,
|
||||
create_time AS createTime,
|
||||
create_user_id AS createUserId,
|
||||
update_time AS updateTime,
|
||||
update_user_id AS updateUserId
|
||||
FROM
|
||||
cp_sys_user
|
||||
WHERE
|
||||
is_delete = 0
|
||||
AND
|
||||
user_name = #{username}
|
||||
AND
|
||||
user_type = #{userType}
|
||||
</select>
|
||||
|
||||
<!--加载参数缓存数据-->
|
||||
<select id="loadingConfigCache" resultType="com.cpop.core.base.table.SysConfig">
|
||||
SELECT
|
||||
config_key AS configKey,
|
||||
config_name AS configName,
|
||||
config_value AS configValue,
|
||||
config_type AS configType,
|
||||
remarks,
|
||||
create_time AS createTime,
|
||||
create_user_id AS createUserId,
|
||||
update_time AS updateTime,
|
||||
update_user_id AS updateUserId
|
||||
FROM
|
||||
cp_sys_config
|
||||
</select>
|
||||
|
||||
<!--根据键名查询参数配置信息-->
|
||||
<select id="selectConfigByKey" resultType="com.cpop.core.base.table.SysConfig">
|
||||
SELECT
|
||||
config_key AS configKey,
|
||||
config_name AS configName,
|
||||
config_value AS configValue,
|
||||
config_type AS configType,
|
||||
remarks,
|
||||
create_time AS createTime,
|
||||
create_user_id AS createUserId,
|
||||
update_time AS updateTime,
|
||||
update_user_id AS updateUserId
|
||||
FROM
|
||||
cp_sys_config
|
||||
WHERE
|
||||
config_key = #{configKey}
|
||||
</select>
|
||||
|
||||
<!--新增参数配置-->
|
||||
<insert id="insertConfig">
|
||||
INSERT INTO
|
||||
cp_sys_config
|
||||
(config_key, config_name, config_value, config_type, remarks, create_time, create_user_id, update_time, update_user_id)
|
||||
VALUES
|
||||
(#{configKey}, #{configName}, #{configValue}, #{configType}, #{remarks}, now(), #{createUserId}, now(), #{updateUserId})
|
||||
</insert>
|
||||
|
||||
<!--修改参数配置-->
|
||||
<update id="updateConfig">
|
||||
UPDATE cp_sys_config
|
||||
SET
|
||||
<if test="configName != null and configName != ''">
|
||||
config_name = #{configName},
|
||||
</if>
|
||||
<if test="config_value != null and config_value != ''">
|
||||
config_value = #{config_value},
|
||||
</if>
|
||||
<if test="configType != null and configType != ''">
|
||||
config_type = #{configType},
|
||||
</if>
|
||||
<if test="remarks != null and remarks != ''">
|
||||
remarks = #{remarks},
|
||||
</if>
|
||||
<if test="updateUserId != null and updateUserId != ''">
|
||||
update_user_id = #{updateUserId},
|
||||
</if>
|
||||
update_time = now()
|
||||
WHERE
|
||||
config_key = #{configKey}
|
||||
</update>
|
||||
|
||||
<!--根据键查询配置-->
|
||||
<select id="selectConfigByKeys" resultType="com.pupu.core.base.table.SysConfig">
|
||||
SELECT
|
||||
config_key AS configKey,
|
||||
config_name AS configName,
|
||||
config_value AS configValue,
|
||||
config_type AS configType,
|
||||
remarks,
|
||||
create_time AS createTime,
|
||||
create_user_id AS createUserId,
|
||||
update_time AS updateTime,
|
||||
update_user_id AS updateUserId
|
||||
FROM
|
||||
cp_sys_config
|
||||
WHERE
|
||||
config_key IN
|
||||
<foreach collection="list" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<!--需要删除的参数ID-->
|
||||
<delete id="deleteConfigByKeys">
|
||||
DELETE FROM cp_sys_config
|
||||
WHERE
|
||||
config_key IN
|
||||
<foreach collection="list" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<!--新增系统用户-->
|
||||
<insert id="insertSysUser">
|
||||
INSERT INTO cp_sys_user
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="id != null and id != ''">
|
||||
id,
|
||||
</if>
|
||||
<if test="userName != null and userName != ''">
|
||||
user_name,
|
||||
</if>
|
||||
<if test="password != null and password != ''">
|
||||
password,
|
||||
</if>
|
||||
<if test="nickName != null and nickName != ''">
|
||||
nick_name,
|
||||
</if>
|
||||
<if test="email != null and email != ''">
|
||||
email,
|
||||
</if>
|
||||
<if test="phoneNumber != null and phoneNumber != ''">
|
||||
phone_number,
|
||||
</if>
|
||||
<if test="sex != null">
|
||||
sex,
|
||||
</if>
|
||||
<if test="avatar != null and avatar != ''">
|
||||
avatar,
|
||||
</if>
|
||||
<if test="salt != null and salt != ''">
|
||||
salt,
|
||||
</if>
|
||||
<if test="status != null">
|
||||
status,
|
||||
</if>
|
||||
<if test="loginIp != null and loginIp != ''">
|
||||
dev_ip,
|
||||
</if>
|
||||
<if test="userType != null">
|
||||
user_type,
|
||||
</if>
|
||||
<if test="createUserId != null and createUserId != ''">
|
||||
create_user_id,
|
||||
</if>
|
||||
<if test="updateUserId != null and updateUserId != ''">
|
||||
update_user_id,
|
||||
</if>
|
||||
create_time,
|
||||
update_time,
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="id != null and id != ''">
|
||||
#{id},
|
||||
</if>
|
||||
<if test="userName != null and userName != ''">
|
||||
#{userName},
|
||||
</if>
|
||||
<if test="password != null and password != ''">
|
||||
#{password},
|
||||
</if>
|
||||
<if test="nickName != null and nickName != ''">
|
||||
#{nickName},
|
||||
</if>
|
||||
<if test="email != null and email != ''">
|
||||
#{email},
|
||||
</if>
|
||||
<if test="phoneNumber != null and phoneNumber != ''">
|
||||
#{phoneNumber},
|
||||
</if>
|
||||
<if test="sex != null">
|
||||
#{sex},
|
||||
</if>
|
||||
<if test="avatar != null and avatar != ''">
|
||||
#{avatar},
|
||||
</if>
|
||||
<if test="salt != null and salt != ''">
|
||||
#{salt},
|
||||
</if>
|
||||
<if test="status != null">
|
||||
#{status},
|
||||
</if>
|
||||
<if test="loginIp != null and loginIp != ''">
|
||||
#{loginIp},
|
||||
</if>
|
||||
<if test="userType != null">
|
||||
#{userType},
|
||||
</if>
|
||||
<if test="createUserId != null and createUserId != ''">
|
||||
#{createUserId},
|
||||
</if>
|
||||
<if test="updateUserId != null and updateUserId != ''">
|
||||
#{updateUserId},
|
||||
</if>
|
||||
now(),
|
||||
now(),
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<!--修改系统用户-->
|
||||
<update id="updateSysUser">
|
||||
UPDATE cp_sys_user
|
||||
<set>
|
||||
<if test="userName != null and userName != ''">
|
||||
user_name = #{userName},
|
||||
</if>
|
||||
<if test="password != null and password != ''">
|
||||
password = #{password},
|
||||
</if>
|
||||
<if test="nickName != null and nickName != ''">
|
||||
nick_name = #{nickName},
|
||||
</if>
|
||||
<if test="email != null and email != ''">
|
||||
email = #{email},
|
||||
</if>
|
||||
<if test="phoneNumber != null and phoneNumber != ''">
|
||||
phone_number = #{phoneNumber},
|
||||
</if>
|
||||
<if test="sex != null">
|
||||
sex = #{sex},
|
||||
</if>
|
||||
<if test="avatar != null and avatar != ''">
|
||||
avatar = #{avatar},
|
||||
</if>
|
||||
<if test="salt != null and salt != ''">
|
||||
salt = #{salt},
|
||||
</if>
|
||||
<if test="status != null">
|
||||
status = #{status},
|
||||
</if>
|
||||
<if test="loginIp != null and loginIp != ''">
|
||||
dev_ip = #{loginIp},
|
||||
</if>
|
||||
<if test="updateUserId != null and updateUserId != ''">
|
||||
update_user_id = #{updateUserId},
|
||||
</if>
|
||||
update_time = now(),
|
||||
</set>
|
||||
WHERE
|
||||
is_delete = 0
|
||||
AND id = #{id}
|
||||
</update>
|
||||
|
||||
<!--根据主键删除用户(逻辑删除)-->
|
||||
<update id="removeSysUserById">
|
||||
UPDATE cp_sys_user
|
||||
SET
|
||||
is_delete = 1
|
||||
WHERE
|
||||
id = #{id}
|
||||
</update>
|
||||
</mapper>
|
||||
BIN
Cpop-Core/src/main/resources/static.keyPair/privateKey
Normal file
BIN
Cpop-Core/src/main/resources/static.keyPair/privateKey
Normal file
Binary file not shown.
BIN
Cpop-Core/src/main/resources/static.keyPair/publicKey
Normal file
BIN
Cpop-Core/src/main/resources/static.keyPair/publicKey
Normal file
Binary file not shown.
35
pom.xml
35
pom.xml
@ -17,15 +17,19 @@
|
||||
|
||||
<modules>
|
||||
<module>Cpop-Common</module>
|
||||
<module>Cpop-Core</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<cpop.version>1.0.0</cpop.version>
|
||||
<snakeyaml.version>2.0</snakeyaml.version>
|
||||
<common-text.version>1.10.0</common-text.version>
|
||||
<commons-IO.version>2.13.0</commons-IO.version>
|
||||
<joda.time.version>2.12.5</joda.time.version>
|
||||
<fastjson.version>2.0.38</fastjson.version>
|
||||
<mybatis-flex.version>1.6.4</mybatis-flex.version>
|
||||
<easyexcel.version>3.3.2</easyexcel.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -54,6 +58,29 @@
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
<!--Cpop公共包-->
|
||||
<dependency>
|
||||
<groupId>com.cpop</groupId>
|
||||
<artifactId>Cpop-Common</artifactId>
|
||||
<version>${cpop.version}</version>
|
||||
</dependency>
|
||||
<!--Mybatis-flex-->
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-spring-boot-starter</artifactId>
|
||||
<version>${mybatis-flex.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-processor</artifactId>
|
||||
<version>${mybatis-flex.version}</version>
|
||||
</dependency>
|
||||
<!--easyExcel-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>${easyexcel.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@ -62,7 +89,7 @@
|
||||
<!--Web-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!--Test-->
|
||||
<dependency>
|
||||
@ -76,5 +103,11 @@
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>${snakeyaml.version}</version>
|
||||
</dependency>
|
||||
<!--Lombok-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user