diff --git a/smart-admin-api-java17-springboot3/pom.xml b/smart-admin-api-java17-springboot3/pom.xml
index 1e2b044f..1d4f850f 100644
--- a/smart-admin-api-java17-springboot3/pom.xml
+++ b/smart-admin-api-java17-springboot3/pom.xml
@@ -16,52 +16,49 @@
- 17
UTF-8
UTF-8
- 3.3.1
- 2.0.8
- 6.4.3
- 3.5.7
+ 17
+ 3.5.4
+ 6.5.1
+ 3.5.12
3.9.1
- 4.4.0
- 2.0.52
- 1.2.23
+ 2.8.9
+ 4.6.0
+ 2.0.57
+ 1.2.25
1.4.2
20.0
- 0.9.11
- 2.15.0
- 3.12.0
- 4.4
- 1.26.0
- 1.13
- 1.9
- 2.12.0
- 1.0.0
- 5.2.4
- 1.4
- 1.11.842
- 2.23.1
- 5.8.29
- 2.3
+ 0.10.2
+ 2.19.0
+ 3.18.0
+ 4.5.0
+ 1.27.1
+ 1.18.0
+ 1.13.1
+ 1.2.0
+ 5.4.1
+ 2.31.78
+ 9.3.0
+ 5.8.39
+ 2.4.1
3.1
- 1.41.0
+ 1.44.0
2.7.0
1.80
- 2.13.4
- 2.16.1
1.2.0
- 3.25.0
- 2.2
- 2.3.33
- 1.18.1
+ 3.50.0
+ 2.4
+ 2.3.34
+ 1.21.1
3.1.0
+ 5.5
-
+
org.springframework.boot
spring-boot-dependencies
@@ -69,19 +66,16 @@
pom
import
-
-
+
+
com.baomidou
- mybatis-plus-spring-boot3-starter
+ mybatis-plus-bom
${mybatis-plus.version}
-
-
- org.springframework.boot
- spring-boot-starter-logging
-
-
+ pom
+ import
+
org.springframework.security
@@ -89,6 +83,12 @@
${spring-security-crypto.version}
+
+ com.mysql
+ mysql-connector-j
+ ${mysql-connector-j.version}
+
+
p6spy
p6spy
@@ -96,7 +96,7 @@
- com.github.xiaoymin
+ com.github.xingfudeshi
knife4j-openapi3-jakarta-spring-boot-starter
${knife4j.version}
@@ -107,7 +107,6 @@
${fastjson.version}
-
com.alibaba
druid-spring-boot-3-starter
@@ -169,9 +168,9 @@
- com.amazonaws
- aws-java-sdk-s3
- ${aws-java-sdk.version}
+ software.amazon.awssdk
+ s3
+ ${awssdk-s3.version}
commons-logging
@@ -217,6 +216,7 @@
sa-token-redis-jackson
${sa-token.version}
+
@@ -254,12 +254,6 @@
${poi.version}
-
- org.apache.poi
- poi-ooxml
- ${poi.version}
-
-
org.apache.poi
poi-scratchpad
@@ -268,20 +262,8 @@
org.apache.poi
- ooxml-schemas
- ${ooxml-schemas.version}
-
-
-
- com.fasterxml.jackson.datatype
- jackson-datatype-jsr310
- ${jackson-datatype-jsr310.version}
-
-
-
- com.fasterxml.jackson.dataformat
- jackson-dataformat-yaml
- ${jackson-dataformat-yaml.version}
+ poi-ooxml-full
+ ${poi.version}
@@ -295,6 +277,25 @@
org.redisson
redisson-spring-boot-starter
${redisson.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.redisson
+ redisson-spring-data-32
+
+
+ objenesis
+ org.objenesis
+
+
+
+
+ org.redisson
+ redisson-spring-data-27
+ ${redisson.version}
@@ -321,6 +322,12 @@
${tika.version}
+
+ org.apache.httpcomponents.client5
+ httpclient5
+ ${httpcomponents.version}
+
+
diff --git a/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java b/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java
index 5bf8c733..7e754860 100644
--- a/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java
+++ b/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java
@@ -68,6 +68,7 @@ public class AdminInterceptor implements HandlerInterceptor {
NoNeedLogin noNeedLogin = ((HandlerMethod) handler).getMethodAnnotation(NoNeedLogin.class);
if (noNeedLogin != null) {
checkActiveTimeout(requestEmployee);
+ SmartRequestUtil.setRequestUser(requestEmployee);
return true;
}
diff --git a/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/entity/DepartmentEntity.java b/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/entity/DepartmentEntity.java
index 4d52bb16..cc4b1639 100644
--- a/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/entity/DepartmentEntity.java
+++ b/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/entity/DepartmentEntity.java
@@ -36,7 +36,7 @@ public class DepartmentEntity {
/**
* 负责人员工 id
*/
- @TableField(updateStrategy = FieldStrategy.IGNORED)
+ @TableField(updateStrategy = FieldStrategy.NEVER)
private Long managerId;
/**
diff --git a/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java b/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java
index edc53e61..f6819cde 100644
--- a/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java
+++ b/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java
@@ -23,6 +23,12 @@ public class EmployeeEntity {
@TableId(type = IdType.AUTO)
private Long employeeId;
+ /**
+ * 唯一id
+ */
+ private String employeeUid;
+
+
/**
* 登录账号
*/
diff --git a/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java b/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java
index 65352b58..1598e4a2 100644
--- a/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java
+++ b/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java
@@ -138,16 +138,20 @@ public class EmployeeService {
}
EmployeeEntity entity = SmartBeanUtil.copy(employeeAddForm, EmployeeEntity.class);
+ // 员工uid
+ String employeeUid = cn.hutool.core.lang.UUID.randomUUID(true).toString(true);
+ entity.setEmployeeUid(employeeUid);
- // 设置密码 默认密码
- String password = securityPasswordService.randomPassword();
- entity.setLoginPwd(SecurityPasswordService.getEncryptPwd(password));
+ // 设置密码 随机密码
+ String randomPassword = securityPasswordService.randomPassword();
+ String generateSaltPassword = this.generateSaltPassword(randomPassword, employeeUid);
+ entity.setLoginPwd(SecurityPasswordService.getEncryptPwd(generateSaltPassword));
// 保存数据
entity.setDeletedFlag(Boolean.FALSE);
employeeManager.saveEmployee(entity, employeeAddForm.getRoleIdList());
- return ResponseDTO.ok(password);
+ return ResponseDTO.ok(randomPassword);
}
/**
@@ -241,7 +245,6 @@ public class EmployeeService {
/**
* 更新登录人头像
- *
*/
public ResponseDTO updateAvatar(EmployeeUpdateAvatarForm employeeUpdateAvatarForm) {
Long employeeId = employeeUpdateAvatarForm.getEmployeeId();
@@ -343,12 +346,12 @@ public class EmployeeService {
}
// 校验原始密码
- if (!SecurityPasswordService.matchesPwd(updatePasswordForm.getOldPassword(),employeeEntity.getLoginPwd()) ) {
+ if (!SecurityPasswordService.matchesPwd(this.generateSaltPassword(updatePasswordForm.getOldPassword(), employeeEntity.getEmployeeUid()), employeeEntity.getLoginPwd())) {
return ResponseDTO.userErrorParam("原密码有误,请重新输入");
}
// 新旧密码相同
- if (Objects.equals(updatePasswordForm.getOldPassword(), updatePasswordForm.getNewPassword()) ){
+ if (Objects.equals(updatePasswordForm.getOldPassword(), updatePasswordForm.getNewPassword())) {
return ResponseDTO.userErrorParam("新密码与原始密码相同,请重新输入");
}
@@ -359,14 +362,13 @@ public class EmployeeService {
}
// 根据三级等保规则,校验密码是否重复
- ResponseDTO passwordRepeatTimes = securityPasswordService.validatePasswordRepeatTimes(requestUser, updatePasswordForm.getNewPassword());
+ ResponseDTO passwordRepeatTimes = securityPasswordService.validatePasswordRepeatTimes(requestUser, this.generateSaltPassword(updatePasswordForm.getNewPassword(), employeeEntity.getEmployeeUid()));
if (!passwordRepeatTimes.getOk()) {
return ResponseDTO.error(passwordRepeatTimes);
}
-
// 更新密码
- String newEncryptPassword = SecurityPasswordService.getEncryptPwd(updatePasswordForm.getNewPassword());
+ String newEncryptPassword = SecurityPasswordService.getEncryptPwd(this.generateSaltPassword(updatePasswordForm.getNewPassword(), employeeEntity.getEmployeeUid()));
EmployeeEntity updateEntity = new EmployeeEntity();
updateEntity.setEmployeeId(employeeId);
updateEntity.setLoginPwd(newEncryptPassword);
@@ -405,8 +407,14 @@ public class EmployeeService {
* 重置密码
*/
public ResponseDTO resetPassword(Long employeeId) {
+ EmployeeEntity employeeEntity = employeeDao.selectById(employeeId);
+ if (employeeEntity == null) {
+ return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST);
+ }
+
String password = securityPasswordService.randomPassword();
- employeeDao.updatePassword(employeeId, SecurityPasswordService.getEncryptPwd(password));
+ String saltPassword = this.generateSaltPassword(password, employeeEntity.getEmployeeUid());
+ employeeDao.updatePassword(employeeId, SecurityPasswordService.getEncryptPwd(saltPassword));
return ResponseDTO.ok(password);
}
@@ -426,4 +434,14 @@ public class EmployeeService {
return employeeDao.getByLoginName(loginName, false);
}
+ /**
+ * 生成加盐密码
+ * 格式为:[password]_[uid大写]_[uid小写]
+ */
+ public String generateSaltPassword(String password, String employeeUid) {
+ return password + StringConst.UNDERLINE +
+ employeeUid.toUpperCase() +
+ StringConst.UNDERLINE +
+ employeeUid.toLowerCase();
+ }
}
diff --git a/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java b/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java
index 28aa85ed..a76dd67d 100644
--- a/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java
+++ b/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java
@@ -57,7 +57,7 @@ public class LoginController {
return ResponseDTO.ok(loginResult);
}
- @Operation(summary = "退出登陆 @author 卓大")
+ @Operation(summary = "退出登录 @author 卓大")
@GetMapping("/login/logout")
public ResponseDTO logout() {
return loginService.logout(SmartRequestUtil.getRequestUser());
diff --git a/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java b/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java
index c5fa8c7d..7b18f257 100644
--- a/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java
+++ b/smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java
@@ -9,7 +9,6 @@ import cn.hutool.extra.servlet.JakartaServletUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
-import net.lab1024.sa.admin.module.system.department.service.DepartmentService;
import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity;
import net.lab1024.sa.admin.module.system.employee.service.EmployeeService;
import net.lab1024.sa.admin.module.system.login.domain.LoginForm;
@@ -38,7 +37,6 @@ import net.lab1024.sa.base.module.support.captcha.CaptchaService;
import net.lab1024.sa.base.module.support.captcha.domain.CaptchaVO;
import net.lab1024.sa.base.module.support.config.ConfigKeyEnum;
import net.lab1024.sa.base.module.support.config.ConfigService;
-import net.lab1024.sa.base.module.support.file.service.IFileStorageService;
import net.lab1024.sa.base.module.support.loginlog.LoginLogResultEnum;
import net.lab1024.sa.base.module.support.loginlog.LoginLogService;
import net.lab1024.sa.base.module.support.loginlog.domain.LoginLogEntity;
@@ -79,9 +77,6 @@ public class LoginService implements StpInterface {
@Resource
private EmployeeService employeeService;
- @Resource
- private DepartmentService departmentService;
-
@Resource
private CaptchaService captchaService;
@@ -103,9 +98,6 @@ public class LoginService implements StpInterface {
@Resource
private SecurityPasswordService protectPasswordService;
- @Resource
- private IFileStorageService fileStorageService;
-
@Resource
private ApiEncryptService apiEncryptService;
@@ -129,7 +121,7 @@ public class LoginService implements StpInterface {
}
/**
- * 员工登陆
+ * 员工登录
*
* @return 返回用户登录信息
*/
@@ -193,7 +185,7 @@ public class LoginService implements StpInterface {
}
// 密码错误
- if (!SecurityPasswordService.matchesPwd(requestPassword, employeeEntity.getLoginPwd())) {
+ if (!SecurityPasswordService.matchesPwd(employeeService.generateSaltPassword(requestPassword, employeeEntity.getEmployeeUid()), employeeEntity.getLoginPwd())) {
// 记录登录失败
saveLoginLog(employeeEntity, ip, userAgent, "密码错误", LoginLogResultEnum.LOGIN_FAIL, loginDeviceEnum);
// 记录等级保护次数
@@ -270,7 +262,7 @@ public class LoginService implements StpInterface {
/**
- * 根据登陆token 获取员请求工信息
+ * 根据登录token 获取员请求工信息
*/
public RequestEmployee getLoginEmployee(String loginId, HttpServletRequest request) {
if (loginId == null) {
diff --git a/smart-admin-api-java17-springboot3/sa-base/pom.xml b/smart-admin-api-java17-springboot3/sa-base/pom.xml
index bd5b22d7..73578857 100644
--- a/smart-admin-api-java17-springboot3/sa-base/pom.xml
+++ b/smart-admin-api-java17-springboot3/sa-base/pom.xml
@@ -64,7 +64,6 @@
cn.dev33
sa-token-redis-jackson
-
@@ -118,19 +117,25 @@
mybatis-plus-spring-boot3-starter
+
+ com.baomidou
+ mybatis-plus-jsqlparser
+
+
p6spy
p6spy
+
- com.github.xiaoymin
+ com.github.xingfudeshi
knife4j-openapi3-jakarta-spring-boot-starter
- com.squareup.okhttp3
- okhttp
+ org.apache.httpcomponents.client5
+ httpclient5
@@ -159,10 +164,11 @@
- com.amazonaws
- aws-java-sdk-s3
+ software.amazon.awssdk
+ s3
+
org.apache.commons
commons-lang3
@@ -217,11 +223,6 @@
poi
-
- org.apache.poi
- poi-ooxml
-
-
org.apache.poi
poi-scratchpad
@@ -229,12 +230,7 @@
org.apache.poi
- ooxml-schemas
-
-
-
- com.fasterxml.jackson.datatype
- jackson-datatype-jsr310
+ poi-ooxml-full
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartPageUtil.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartPageUtil.java
index edd4768a..eb88c587 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartPageUtil.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartPageUtil.java
@@ -52,11 +52,7 @@ public class SmartPageUtil {
log.error("《存在SQL注入:》 : {}", sortItem.getColumn());
throw new BusinessException("存在SQL注入风险,请联系技术工作人员!");
}
-
- OrderItem orderItem = new OrderItem();
- orderItem.setColumn(sortItem.getColumn());
- orderItem.setAsc(sortItem.getIsAsc());
- orderItemList.add(orderItem);
+ orderItemList.add(sortItem.getIsAsc() ? OrderItem.asc(sortItem.getColumn()) : OrderItem.desc(sortItem.getColumn()));
}
page.setOrders(orderItemList);
return page;
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartRequestUtil.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartRequestUtil.java
index ab6e5746..aab02304 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartRequestUtil.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartRequestUtil.java
@@ -18,6 +18,9 @@ public class SmartRequestUtil {
private static final ThreadLocal REQUEST_THREAD_LOCAL = new ThreadLocal<>();
public static void setRequestUser(RequestUser requestUser) {
+ if(requestUser == null){
+ return;
+ }
REQUEST_THREAD_LOCAL.set(requestUser);
}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/FileConfig.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/FileConfig.java
index a929cca6..98eb03fe 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/FileConfig.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/FileConfig.java
@@ -1,12 +1,5 @@
package net.lab1024.sa.base.config;
-import com.amazonaws.ClientConfiguration;
-import com.amazonaws.Protocol;
-import com.amazonaws.auth.AWSStaticCredentialsProvider;
-import com.amazonaws.auth.BasicAWSCredentials;
-import com.amazonaws.client.builder.AwsClientBuilder;
-import com.amazonaws.services.s3.AmazonS3;
-import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import lombok.Data;
import net.lab1024.sa.base.module.support.file.service.FileStorageCloudServiceImpl;
import net.lab1024.sa.base.module.support.file.service.FileStorageLocalServiceImpl;
@@ -17,6 +10,13 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.services.s3.S3Configuration;
+
+import java.net.URI;
/**
* 文件上传 配置
@@ -31,6 +31,10 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class FileConfig implements WebMvcConfigurer {
+ private static final String HTTPS = "https://";
+
+ private static final String HTTP = "http://";
+
private static final String MODE_CLOUD = "cloud";
private static final String MODE_LOCAL = "local";
@@ -69,15 +73,17 @@ public class FileConfig implements WebMvcConfigurer {
*/
@Bean
@ConditionalOnProperty(prefix = "file.storage", name = {"mode"}, havingValue = MODE_CLOUD)
- public AmazonS3 initAmazonS3() {
- ClientConfiguration clientConfig = new ClientConfiguration();
- clientConfig.setProtocol(Protocol.HTTPS);
- return AmazonS3ClientBuilder.standard()
- .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)))
- .withClientConfiguration(clientConfig)
- .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region))
- .withPathStyleAccessEnabled(false)
- .withChunkedEncodingDisabled(true)
+ public S3Client initAmazonS3() {
+ return S3Client.builder()
+ .region(Region.AWS_GLOBAL)
+ .endpointOverride(URI.create((urlPrefix.startsWith(HTTPS) ? HTTPS : HTTP) + endpoint))
+ .credentialsProvider(
+ StaticCredentialsProvider.create(
+ AwsBasicCredentials.create(accessKey, secretKey)))
+ .serviceConfiguration(S3Configuration.builder()
+ .pathStyleAccessEnabled(false)
+ .chunkedEncodingEnabled(false)
+ .build())
.build();
}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/RepeatSubmitConfig.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/RepeatSubmitConfig.java
index 5a9130ff..aa68b046 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/RepeatSubmitConfig.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/RepeatSubmitConfig.java
@@ -1,13 +1,14 @@
package net.lab1024.sa.base.config;
import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletRequest;
import net.lab1024.sa.base.common.constant.StringConst;
import net.lab1024.sa.base.common.util.SmartRequestUtil;
import net.lab1024.sa.base.module.support.repeatsubmit.RepeatSubmitAspect;
import net.lab1024.sa.base.module.support.repeatsubmit.ticket.RepeatSubmitRedisTicket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.data.redis.core.RedisTemplate;
/**
* 重复提交配置
@@ -22,22 +23,22 @@ import org.springframework.data.redis.core.ValueOperations;
public class RepeatSubmitConfig {
@Resource
- private ValueOperations valueOperations;
+ private RedisTemplate redisTemplate;
@Bean
public RepeatSubmitAspect repeatSubmitAspect() {
- RepeatSubmitRedisTicket caffeineTicket = new RepeatSubmitRedisTicket(valueOperations, this::ticket);
- return new RepeatSubmitAspect(caffeineTicket);
+ RepeatSubmitRedisTicket ticket = new RepeatSubmitRedisTicket(redisTemplate, this::ticket);
+ return new RepeatSubmitAspect(ticket);
}
/**
* 获取指明某个用户的凭证
*/
- private String ticket(String servletPath) {
+ private String ticket(HttpServletRequest request) {
Long userId = SmartRequestUtil.getRequestUserId();
if (null == userId) {
return StringConst.EMPTY;
}
- return servletPath + "_" + userId;
+ return request.getServletPath() + "_" + userId;
}
}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/RestClientConfig.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/RestClientConfig.java
new file mode 100644
index 00000000..36ad124d
--- /dev/null
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/RestClientConfig.java
@@ -0,0 +1,92 @@
+package net.lab1024.sa.base.config;
+
+import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
+import org.apache.hc.client5.http.classic.HttpClient;
+import org.apache.hc.client5.http.config.TlsConfig;
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
+import org.apache.hc.core5.util.TimeValue;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.web.client.RestClient;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * http请求配置
+ *
+ * @Author 1024创新实验室: 卓大
+ * @Date 2025-07-26 21:22:12
+ * @Wechat zhuoda1024
+ * @Email lab1024@163.com
+ * @Copyright 1024创新实验室
+ */
+@Configuration
+public class RestClientConfig {
+
+ @Value("${http.pool.max-total}")
+ private Integer maxTotal;
+
+ @Value("${http.pool.connect-timeout}")
+ private Integer connectTimeout;
+
+ @Value("${http.pool.read-timeout}")
+ private Integer readTimeout;
+
+ @Value("${http.pool.write-timeout}")
+ private Integer writeTimeout;
+
+ @Value("${http.pool.keep-alive}")
+ private Integer keepAlive;
+
+ @Bean
+ public RestClient restClient() {
+
+ HttpComponentsClientHttpRequestFactory factory =
+ new HttpComponentsClientHttpRequestFactory();
+ factory.setConnectTimeout(connectTimeout);
+ factory.setConnectionRequestTimeout(connectTimeout);
+ factory.setReadTimeout(readTimeout);
+
+ PoolingHttpClientConnectionManager cm =
+ new PoolingHttpClientConnectionManager();
+
+ cm.setMaxTotal(this.maxTotal);
+ cm.setDefaultTlsConfig(TlsConfig.DEFAULT);
+
+ HttpClient httpClient = HttpClients.custom()
+ .setConnectionManager(cm)
+ .setKeepAliveStrategy((response, context) -> TimeValue.of(this.keepAlive, TimeUnit.MICROSECONDS))
+ .build();
+
+ factory.setHttpClient(httpClient);
+
+ return RestClient.builder()
+ .requestFactory(factory)
+ .messageConverters(converters())
+ .build();
+ }
+
+ public List> converters() {
+ List> converters = new ArrayList<>();
+ HttpMessageConverter> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
+ FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
+ List fastMediaTypes = new ArrayList<>();
+ fastMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
+ fastMediaTypes.add(MediaType.APPLICATION_JSON);
+ fastConverter.setSupportedMediaTypes(fastMediaTypes);
+ converters.add(converter);
+ converters.add(fastConverter);
+ return converters;
+ }
+
+
+}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/RestTemplateConfig.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/RestTemplateConfig.java
deleted file mode 100644
index 1a3cdf4a..00000000
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/RestTemplateConfig.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package net.lab1024.sa.base.config;
-
-import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
-import okhttp3.ConnectionPool;
-import okhttp3.OkHttpClient;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.MediaType;
-import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
-import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.http.converter.StringHttpMessageConverter;
-import org.springframework.web.client.RestTemplate;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-import java.nio.charset.StandardCharsets;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * http请求配置
- *
- * @Author 1024创新实验室: 罗伊
- * @Date 2022-05-30 21:22:12
- * @Wechat zhuoda1024
- * @Email lab1024@163.com
- * @Copyright 1024创新实验室
- */
-@Configuration
-public class RestTemplateConfig {
-
- @Value("${http.pool.max-total}")
- private Integer maxTotal;
-
- @Value("${http.pool.connect-timeout}")
- private Integer connectTimeout;
-
- @Value("${http.pool.read-timeout}")
- private Integer readTimeout;
-
- @Value("${http.pool.write-timeout}")
- private Integer writeTimeout;
-
- @Value("${http.pool.keep-alive}")
- private Integer keepAlive;
-
- @Bean
- public RestTemplate restTemplate() {
- RestTemplate restTemplate = new RestTemplate();
- restTemplate.setRequestFactory(this.clientHttpRequestFactory());
- List> messageConverterList = restTemplate.getMessageConverters();
- messageConverterList.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
- messageConverterList.addAll(this.converters());
- return restTemplate;
- }
-
- public List> converters() {
- List> converters = new ArrayList<>();
- HttpMessageConverter> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
- FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
- List fastMediaTypes = new ArrayList<>();
- fastMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
- fastMediaTypes.add(MediaType.APPLICATION_JSON);
- fastConverter.setSupportedMediaTypes(fastMediaTypes);
- converters.add(converter);
- converters.add(fastConverter);
- return converters;
- }
-
-
- public OkHttp3ClientHttpRequestFactory clientHttpRequestFactory() {
- return new OkHttp3ClientHttpRequestFactory(httpClientBuilder());
- }
-
- public OkHttpClient httpClientBuilder() {
- return new OkHttpClient.Builder()
- .retryOnConnectionFailure(true)
- .connectionPool(this.pool())
- .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
- .readTimeout(readTimeout, TimeUnit.MILLISECONDS)
- .writeTimeout(writeTimeout, TimeUnit.MILLISECONDS)
- .build();
- }
-
- public ConnectionPool pool() {
- return new ConnectionPool(maxTotal, keepAlive, TimeUnit.MILLISECONDS);
- }
-
-
- @Bean
- public X509TrustManager x509TrustManager() {
- return new X509TrustManager() {
- @Override
- public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
- }
-
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
- };
- }
-
- @Bean
- public SSLSocketFactory sslSocketFactory() {
- try {
- //信任任何链接
- SSLContext sslContext = SSLContext.getInstance("TLS");
- sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());
- return sslContext.getSocketFactory();
- } catch (NoSuchAlgorithmException | KeyManagementException e) {
- e.printStackTrace();
- }
- return null;
- }
-
-}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/SwaggerConfig.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/SwaggerConfig.java
index 5aff202f..3764677d 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/SwaggerConfig.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/SwaggerConfig.java
@@ -12,6 +12,7 @@ import net.lab1024.sa.base.common.constant.RequestHeaderConst;
import net.lab1024.sa.base.common.swagger.SmartOperationCustomizer;
import net.lab1024.sa.base.constant.SwaggerTagConst;
import org.apache.commons.lang3.StringUtils;
+import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
import org.springdoc.core.models.GroupedOpenApi;
@@ -24,6 +25,8 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpRequest;
import java.util.List;
import java.util.Optional;
@@ -80,6 +83,21 @@ public class SwaggerConfig {
.addSecuritySchemes(RequestHeaderConst.TOKEN, new SecurityScheme().scheme("Bearer").description("请输入token,格式为[Bearer xxxxxxxx]").type(SecurityScheme.Type.APIKEY).in(SecurityScheme.In.HEADER).name(RequestHeaderConst.TOKEN));
}
+ @Bean
+ public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() {
+ return openApi -> {
+ // 全局添加鉴权参数
+ if(openApi.getPaths()!=null){
+ openApi.getPaths().forEach((s, pathItem) -> {
+ // 为所有接口添加鉴权
+ pathItem.readOperations().forEach(operation -> {
+ operation.addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION));
+ });
+ });
+ }
+ };
+ }
+
@Bean
public GroupedOpenApi businessApi() {
return GroupedOpenApi.builder()
@@ -122,11 +140,11 @@ public class SwaggerConfig {
Optional javadocProvider) {
List list = Lists.newArrayList(new ServerBaseUrlCustomizer() {
@Override
- public String customize(String baseUrl) {
+ public String customize(String serverBaseUrl, HttpRequest request) {
if (StringUtils.isNotBlank(serverBaseUrl)) {
return serverBaseUrl;
}
- return baseUrl;
+ return serverBaseUrl;
}
});
return new OpenAPIService(openAPI, securityParser, springDocConfigProperties,
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/captcha/CaptchaService.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/captcha/CaptchaService.java
index 2058b344..715f92c8 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/captcha/CaptchaService.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/captcha/CaptchaService.java
@@ -3,10 +3,10 @@ package net.lab1024.sa.base.module.support.captcha;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.img.ImgUtil;
+import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
-import net.lab1024.sa.base.common.constant.StringConst;
import net.lab1024.sa.base.common.domain.ResponseDTO;
import net.lab1024.sa.base.common.domain.SystemEnvironment;
import net.lab1024.sa.base.constant.RedisKeyConst;
@@ -18,7 +18,6 @@ import org.springframework.stereotype.Service;
import java.awt.*;
import java.util.Objects;
-import java.util.UUID;
/**
* 图形验证码 服务
@@ -70,7 +69,7 @@ public class CaptchaService {
* 图片 base64格式
*/
// uuid 唯一标识
- String uuid = UUID.randomUUID().toString().replace("-", StringConst.EMPTY);
+ String uuid = IdUtil.fastSimpleUUID();
CaptchaVO captchaVO = new CaptchaVO();
captchaVO.setCaptchaUuid(uuid);
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorService.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorService.java
index f8918480..faaafa98 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorService.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorService.java
@@ -40,7 +40,7 @@ import java.util.Optional;
@Service
public class CodeGeneratorService {
- private static final String COLUMN_NULLABLE_IDENTIFY = "NO";
+ private static final String COLUMN_NO_NULLABLE_IDENTIFY = "NO";
private static final String COLUMN_PRIMARY_KEY = "PRI";
@@ -65,7 +65,7 @@ public class CodeGeneratorService {
public List getTableColumns(String tableName) {
List tableColumns = codeGeneratorDao.selectTableColumn(tableName);
for (TableColumnVO tableColumn : tableColumns) {
- tableColumn.setNullableFlag(!COLUMN_NULLABLE_IDENTIFY.equalsIgnoreCase(tableColumn.getIsNullable()));
+ tableColumn.setNullableFlag(!COLUMN_NO_NULLABLE_IDENTIFY.equalsIgnoreCase(tableColumn.getIsNullable()));
tableColumn.setPrimaryKeyFlag(COLUMN_PRIMARY_KEY.equalsIgnoreCase(tableColumn.getColumnKey()));
tableColumn.setAutoIncreaseFlag(SmartStringUtil.isNotEmpty(tableColumn.getExtra()) && COLUMN_AUTO_INCREASE.equalsIgnoreCase(tableColumn.getExtra()));
}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorTemplateService.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorTemplateService.java
index d7675eee..18beb1b1 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorTemplateService.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorTemplateService.java
@@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
+import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
@@ -34,7 +35,10 @@ import java.io.File;
import java.io.OutputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
-import java.util.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
import java.util.stream.Collectors;
/**
@@ -82,7 +86,7 @@ public class CodeGeneratorTemplateService {
}
public void zipGeneratedFiles(OutputStream outputStream, String tableName, CodeGeneratorConfigEntity codeGeneratorConfigEntity) {
- String uuid = UUID.randomUUID().toString();
+ String uuid = IdUtil.fastSimpleUUID();
File dir = new File(uuid);
// 1、生产文件
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileService.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileService.java
index f31a797b..290a2f7e 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileService.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileService.java
@@ -55,9 +55,6 @@ public class FileService {
@Resource
private FileDao fileDao;
- @Resource
- private RedisService redisService;
-
@Resource
private SecurityFileService securityFileService;
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileStorageCloudServiceImpl.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileStorageCloudServiceImpl.java
index 311f3d71..8de329a5 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileStorageCloudServiceImpl.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileStorageCloudServiceImpl.java
@@ -2,10 +2,7 @@ package net.lab1024.sa.base.module.support.file.service;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
-import com.amazonaws.services.s3.AmazonS3;
-import com.amazonaws.services.s3.model.CannedAccessControlList;
-import com.amazonaws.services.s3.model.ObjectMetadata;
-import com.amazonaws.services.s3.model.S3Object;
+import cn.hutool.core.util.IdUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.base.common.code.SystemErrorCode;
@@ -22,21 +19,27 @@ import net.lab1024.sa.base.module.support.file.domain.vo.FileVO;
import net.lab1024.sa.base.module.support.redis.RedisService;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
-import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
+import software.amazon.awssdk.core.ResponseBytes;
+import software.amazon.awssdk.core.sync.RequestBody;
+import software.amazon.awssdk.core.sync.ResponseTransformer;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.services.s3.model.*;
+import software.amazon.awssdk.services.s3.presigner.S3Presigner;
+import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
+import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
import java.io.IOException;
import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
+import java.time.Duration;
import java.time.LocalDateTime;
-import java.util.Date;
import java.util.HashMap;
import java.util.Map;
-import java.util.UUID;
/**
* 云计算 实现
@@ -45,7 +48,7 @@ import java.util.UUID;
* @Date 2019年10月11日 15:34:47
* @Wechat zhuoda1024
* @Email lab1024@163.com
- * @Copyright 1024创新实验室
+ * @Copyright 1024创新实验室
*/
@Slf4j
public class FileStorageCloudServiceImpl implements IFileStorageService {
@@ -66,7 +69,7 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
private static final String USER_METADATA_FILE_SIZE = "file-size";
@Resource
- private AmazonS3 amazonS3;
+ private S3Client s3Client;
@Resource
private FileConfig cloudConfig;
@@ -86,44 +89,40 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
}
String fileType = FilenameUtils.getExtension(originalFileName);
- String uuid = UUID.randomUUID().toString().replaceAll("-", "");
+ String uuid = IdUtil.fastSimpleUUID();
String time = LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_FORMATTER);
- String fileKey = path + uuid + "_" + time+ "." + fileType;
+ String fileKey = path + uuid + "_" + time + "." + fileType;
// 文件名称 URL 编码
String urlEncoderFilename;
- try {
- urlEncoderFilename = URLEncoder.encode(originalFileName, StandardCharsets.UTF_8.name());
- } catch (UnsupportedEncodingException e) {
- log.error("文件上传服务URL ENCODE-发生异常:", e);
- return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, "上传失败");
- }
- ObjectMetadata meta = new ObjectMetadata();
- meta.setContentEncoding(StandardCharsets.UTF_8.name());
- meta.setContentDisposition("attachment;filename=" + urlEncoderFilename);
+ urlEncoderFilename = URLEncoder.encode(originalFileName, StandardCharsets.UTF_8);
Map userMetadata = new HashMap<>(10);
userMetadata.put(USER_METADATA_FILE_NAME, urlEncoderFilename);
userMetadata.put(USER_METADATA_FILE_FORMAT, fileType);
userMetadata.put(USER_METADATA_FILE_SIZE, String.valueOf(file.getSize()));
- meta.setUserMetadata(userMetadata);
- meta.setContentLength(file.getSize());
- meta.setContentType(this.getContentType(fileType));
+
+ PutObjectRequest putObjectRequest = PutObjectRequest.builder().bucket(cloudConfig.getBucketName()).key(fileKey).metadata(userMetadata).contentLength(file.getSize()).contentType(this.getContentType(fileType)).contentEncoding(StandardCharsets.UTF_8.name()).contentDisposition("attachment;filename=" + urlEncoderFilename).build();
+ InputStream inputStream = null;
try {
- amazonS3.putObject(cloudConfig.getBucketName(), fileKey, file.getInputStream(), meta);
+ inputStream = file.getInputStream();
+ s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(inputStream, file.getSize()));
} catch (IOException e) {
log.error("文件上传-发生异常:", e);
return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, "上传失败");
+ } finally {
+ IOUtils.closeQuietly(inputStream);
}
// 根据文件路径获取并设置访问权限
- CannedAccessControlList acl = this.getACL(path);
- amazonS3.setObjectAcl(cloudConfig.getBucketName(), fileKey, acl);
+ ObjectCannedACL acl = this.getACL(path);
+ PutObjectAclRequest aclRequest = PutObjectAclRequest.builder().bucket(cloudConfig.getBucketName()).key(fileKey).acl(this.getACL(path)).build();
+ s3Client.putObjectAcl(aclRequest);
// 返回上传结果
FileUploadVO uploadVO = new FileUploadVO();
uploadVO.setFileName(originalFileName);
uploadVO.setFileType(fileType);
// 根据 访问权限 返回不同的 URL
String url = cloudConfig.getUrlPrefix() + fileKey;
- if (CannedAccessControlList.Private.equals(acl)) {
+ if (ObjectCannedACL.PRIVATE.equals(acl)) {
// 获取临时访问的URL
url = this.getFileUrl(fileKey).getData();
}
@@ -136,8 +135,8 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
/**
* 获取文件url
*
- * @param fileKey
- * @return
+ * @param fileKey 文件key
+ * @return url
*/
@Override
public ResponseDTO getFileUrl(String fileKey) {
@@ -159,10 +158,14 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
if (fileVO == null) {
return ResponseDTO.userErrorParam("文件不存在");
}
+ GetObjectRequest getUrlRequest = GetObjectRequest.builder().bucket(cloudConfig.getBucketName()).key(fileKey).build();
+ GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder().signatureDuration(Duration.ofSeconds(cloudConfig.getPrivateUrlExpireSeconds())).getObjectRequest(getUrlRequest).build();
- Date expiration = new Date(System.currentTimeMillis() + cloudConfig.getPrivateUrlExpireSeconds() * 1000L);
- URL url = amazonS3.generatePresignedUrl(cloudConfig.getBucketName(), fileKey, expiration);
- fileVO.setFileUrl(url.toString());
+ S3Presigner presigner = S3Presigner.builder().region(Region.of(cloudConfig.getRegion())).build();
+
+ PresignedGetObjectRequest presignedGetObjectRequest = presigner.presignGetObject(getObjectPresignRequest);
+ String url = presignedGetObjectRequest.url().toString();
+ fileVO.setFileUrl(url);
redisService.set(fileRedisKey, fileVO, cloudConfig.getPrivateUrlExpireSeconds() - 5);
}
@@ -175,11 +178,11 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
*/
@Override
public ResponseDTO download(String key) {
- //获取oss对象
- S3Object s3Object = amazonS3.getObject(cloudConfig.getBucketName(), key);
+
// 获取文件 meta
- ObjectMetadata metadata = s3Object.getObjectMetadata();
- Map userMetadata = metadata.getUserMetadata();
+ HeadObjectRequest objectRequest = HeadObjectRequest.builder().bucket(this.cloudConfig.getBucketName()).key(key).build();
+ HeadObjectResponse headObjectResponse = s3Client.headObject(objectRequest);
+ Map userMetadata = headObjectResponse.metadata();
FileMetadataVO metadataDTO = null;
if (MapUtils.isNotEmpty(userMetadata)) {
metadataDTO = new FileMetadataVO();
@@ -190,43 +193,31 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
metadataDTO.setFileSize(fileSize);
}
- // 获得输入流
- InputStream objectContent = s3Object.getObjectContent();
- try {
- // 输入流转换为字节流
- byte[] buffer = FileCopyUtils.copyToByteArray(objectContent);
+ //获取oss对象
+ GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(cloudConfig.getBucketName()).key(key).build();
+ ResponseBytes s3ClientObject = s3Client.getObject(getObjectRequest, ResponseTransformer.toBytes());
- FileDownloadVO fileDownloadVO = new FileDownloadVO();
- fileDownloadVO.setData(buffer);
- fileDownloadVO.setMetadata(metadataDTO);
- return ResponseDTO.ok(fileDownloadVO);
- } catch (IOException e) {
- log.error("文件下载-发生异常:", e);
- return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, "下载失败");
- } finally {
- try {
- // 关闭输入流
- objectContent.close();
- s3Object.close();
- } catch (IOException e) {
- log.error("文件下载-发生异常:", e);
- }
- }
+ // 输入流转换为字节流
+ byte[] buffer = s3ClientObject.asByteArray();
+ FileDownloadVO fileDownloadVO = new FileDownloadVO();
+ fileDownloadVO.setData(buffer);
+ fileDownloadVO.setMetadata(metadataDTO);
+ return ResponseDTO.ok(fileDownloadVO);
}
/**
* 根据文件夹路径 返回对应的访问权限
*
- * @param fileKey
- * @return
+ * @param fileKey 文件key
+ * @return 权限
*/
- private CannedAccessControlList getACL(String fileKey) {
+ private ObjectCannedACL getACL(String fileKey) {
// 公用读
if (fileKey.contains(FileFolderTypeEnum.FOLDER_PUBLIC)) {
- return CannedAccessControlList.PublicRead;
+ return ObjectCannedACL.PUBLIC_READ;
}
// 其他默认私有读写
- return CannedAccessControlList.Private;
+ return ObjectCannedACL.PRIVATE;
}
/**
@@ -235,11 +226,11 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
* ps:不能删除fileKey不为空的文件夹
*
* @param fileKey 文件or文件夹
- * @return
*/
@Override
public ResponseDTO delete(String fileKey) {
- amazonS3.deleteObject(cloudConfig.getBucketName(), fileKey);
+ DeleteObjectRequest deleteObjectRequest = DeleteObjectRequest.builder().bucket(cloudConfig.getBucketName()).key(fileKey).build();
+ s3Client.deleteObject(deleteObjectRequest);
return ResponseDTO.ok();
}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/mail/MailService.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/mail/MailService.java
index 18fac72a..777f89a8 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/mail/MailService.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/mail/MailService.java
@@ -1,7 +1,7 @@
package net.lab1024.sa.base.module.support.mail;
-import cn.hutool.core.lang.UUID;
+import cn.hutool.core.util.IdUtil;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
@@ -19,7 +19,6 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringSubstitutor;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
@@ -163,7 +162,7 @@ public class MailService {
private String freemarkerResolverContent(String htmlTemplate, Map templateParamsMap) {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);
StringTemplateLoader stringLoader = new StringTemplateLoader();
- String templateName = UUID.fastUUID().toString(true);
+ String templateName = IdUtil.fastSimpleUUID();
stringLoader.putTemplate(templateName, htmlTemplate);
configuration.setTemplateLoader(stringLoader);
try {
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/RepeatSubmitAspect.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/RepeatSubmitAspect.java
index 723ecd7e..79107a07 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/RepeatSubmitAspect.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/RepeatSubmitAspect.java
@@ -1,5 +1,6 @@
package net.lab1024.sa.base.module.support.repeatsubmit;
+import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.base.common.code.UserErrorCode;
import net.lab1024.sa.base.common.domain.ResponseDTO;
@@ -16,10 +17,19 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import java.lang.reflect.Method;
/**
- * 重复提交 aop切口
+ * 重复提交 aop切口
+ * -------------------------
+ * 着重说明:
+ * 注解属性 intervalMilliSecond 是指 一段时间内只允许有一次请求;
+ * intervalMilliSecond = 0: 表示只有上个请求执行完以后才可以执行
+ * intervalMilliSecond > 0: 表示指定时间内只才能执行,特别提醒
+ * ------------------------
+ * 特殊说明 intervalMilliSecond > 0
+ * 若假设 方法执行时间为 100ms,若 intervalMilliSecond = 50,则 同一时间内可能会有2个请求同时在执行!
+ * 若假设 方法执行时间为 100ms,若 intervalMilliSecond = 200,则 同一时间内只能有1请求执行,且执行完后100ms,才会执行下一次请求
*
- * @Author 1024创新实验室: 胡克
- * @Date 2020-11-25 20:56:58
+ * @Author 1024创新实验室-主任: 卓大
+ * @Date 2025-07-26 23:56:58
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室
@@ -43,36 +53,46 @@ public class RepeatSubmitAspect {
@Around("@annotation(net.lab1024.sa.base.module.support.repeatsubmit.annoation.RepeatSubmit)")
public Object around(ProceedingJoinPoint point) throws Throwable {
+
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
- String ticketToken = attributes.getRequest().getServletPath();
- String ticket = this.repeatSubmitTicket.getTicket(ticketToken);
+ if (attributes == null) {
+ return point.proceed();
+ }
+
+ /**
+ * 第一步:生成防重复提交的 ticket凭证
+ * ticket 是根据 Request对象 自定义 生成的,可以加入请求user相关属性作为生成要素
+ */
+
+ HttpServletRequest request = attributes.getRequest();
+ String ticket = this.repeatSubmitTicket.generateTicket(request);
if (StringUtils.isEmpty(ticket)) {
return point.proceed();
}
Method method = ((MethodSignature) point.getSignature()).getMethod();
RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
- int limit = annotation.value();
+ Long intervalMilliSecond = (long) annotation.intervalMilliSecond();
- // 获取上一次请求时间
- Long lastRequestTime = this.repeatSubmitTicket.getTicketTimestamp(ticket);
- // 校验是否限制时间内重复提交
- if (lastRequestTime != null && System.currentTimeMillis() < lastRequestTime + limit) {
+ /**
+ * 第二步:根据 ticket 凭证进行 加锁
+ * 能加锁,则可以执行
+ * 若不能加锁,则证明还是时间间隔interval中
+ */
+
+ boolean lockSuccessFlag = this.repeatSubmitTicket.tryLock(ticket, System.currentTimeMillis(), intervalMilliSecond);
+ if (!lockSuccessFlag) {
return ResponseDTO.error(UserErrorCode.REPEAT_SUBMIT);
}
- // 执行
- Object obj = null;
try {
- // 给 ticket 设置在执行中
- this.repeatSubmitTicket.putTicket(ticket);
- // 执行
- obj = point.proceed();
+ return point.proceed();
} catch (Throwable throwable) {
- log.error("", throwable);
+ log.error(throwable.getMessage(), throwable);
throw throwable;
+ } finally {
+ this.repeatSubmitTicket.unLock(ticket, intervalMilliSecond);
}
- return obj;
}
}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/annoation/RepeatSubmit.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/annoation/RepeatSubmit.java
index 371f7b95..18bec0c3 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/annoation/RepeatSubmit.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/annoation/RepeatSubmit.java
@@ -7,10 +7,19 @@ import java.lang.annotation.Target;
/**
* 标记 需要防止重复提交 的注解
- * 单位:毫秒
+ * 单位:毫秒
+ * -------------------------
+ * 着重说明:
+ * 注解属性 intervalMilliSecond 是指 一段时间内只允许有一次请求;
+ * intervalMilliSecond = 0: 表示只有上个请求执行完以后才可以执行
+ * intervalMilliSecond > 0: 表示指定时间内只才能执行,特别提醒
+ * ------------------------
+ * 特殊说明 intervalMilliSecond > 0
+ * 若假设 方法执行时间为 100ms,若 intervalMilliSecond = 50,则 同一时间内可能会有2个请求同时在执行!
+ * 若假设 方法执行时间为 100ms,若 intervalMilliSecond = 200,则 同一时间内只能有1请求执行,且执行完后100ms,才会执行下一次请求
*
- * @Author 1024创新实验室: 胡克
- * @Date 2020-11-25 20:56:58
+ * @Author 1024创新实验室-主任: 卓大
+ * @Date 2025-07-26 20:56:58
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室
@@ -20,8 +29,8 @@ import java.lang.annotation.Target;
public @interface RepeatSubmit {
/**
- * 重复提交间隔时间/毫秒
+ * 间隔时间/毫秒
*/
- int value() default 300;
+ int intervalMilliSecond() default 0;
}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/AbstractRepeatSubmitTicket.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/AbstractRepeatSubmitTicket.java
index bc2f8e60..1329f504 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/AbstractRepeatSubmitTicket.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/AbstractRepeatSubmitTicket.java
@@ -1,42 +1,43 @@
package net.lab1024.sa.base.module.support.repeatsubmit.ticket;
+import jakarta.servlet.http.HttpServletRequest;
+
import java.util.function.Function;
/**
* 凭证(用于校验重复提交的东西)
*
- * @Author 1024创新实验室: 罗伊
- * @Date 2020-11-25 20:56:58
+ * @Author 1024创新实验室-主任: 卓大
+ * @Date 2025-07-26 23:56:58
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室
*/
public abstract class AbstractRepeatSubmitTicket {
- private final Function ticketFunction;
+ private final Function generateTicketFunction;
- public AbstractRepeatSubmitTicket(Function ticketFunction) {
- this.ticketFunction = ticketFunction;
+ public AbstractRepeatSubmitTicket(Function generateTicketFunction) {
+ this.generateTicketFunction = generateTicketFunction;
}
/**
- * 获取凭证
+ * 生成 加锁的 凭证
*/
- public String getTicket(String ticketToken) {
- return this.ticketFunction.apply(ticketToken);
+ public String generateTicket(HttpServletRequest request) {
+ return this.generateTicketFunction.apply(request);
}
/**
- * 获取凭证 时间戳
+ * 加锁
*/
- public abstract Long getTicketTimestamp(String ticket);
-
+ public abstract boolean tryLock(String ticket, Long currentTimestamp, Long intervalMilliSecond);
/**
- * 设置本次请求时间
+ * 移除锁
*/
- public abstract void putTicket(String ticket);
+ public abstract void unLock(String ticket, Long intervalMilliSecond);
}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitCaffeineTicket.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitCaffeineTicket.java
deleted file mode 100644
index c18cc038..00000000
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitCaffeineTicket.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package net.lab1024.sa.base.module.support.repeatsubmit.ticket;
-
-import com.github.benmanes.caffeine.cache.Cache;
-import com.github.benmanes.caffeine.cache.Caffeine;
-
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-
-/**
- * 凭证(内存实现)
- *
- * @Author 1024创新实验室: 罗伊
- * @Date 2020-11-25 20:56:58
- * @Wechat zhuoda1024
- * @Email lab1024@163.com
- * @Copyright 1024创新实验室
- */
-public class RepeatSubmitCaffeineTicket extends AbstractRepeatSubmitTicket {
-
- /**
- * 限制缓存最大数量 超过后先放入的会自动移除
- * 默认缓存时间
- * 初始大小为:100万
- */
- private static final Cache cache = Caffeine.newBuilder()
- .maximumSize(100 * 10000)
- .expireAfterWrite(300 * 1000L, TimeUnit.MILLISECONDS).build();
-
-
- public RepeatSubmitCaffeineTicket(Function ticketFunction) {
- super(ticketFunction);
- }
-
- @Override
- public Long getTicketTimestamp(String ticket) {
- return cache.getIfPresent(ticket);
- }
-
-
- @Override
- public void putTicket(String ticket) {
- cache.put(ticket, System.currentTimeMillis());
- }
-}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitMemoryTicket.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitMemoryTicket.java
new file mode 100644
index 00000000..31ccfe0d
--- /dev/null
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitMemoryTicket.java
@@ -0,0 +1,60 @@
+package net.lab1024.sa.base.module.support.repeatsubmit.ticket;
+
+import com.google.common.collect.Interner;
+import com.google.common.collect.Interners;
+import com.google.common.collect.Maps;
+import jakarta.servlet.http.HttpServletRequest;
+
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.Function;
+
+/**
+ * 凭证(内存实现)
+ *
+ * @Author 1024创新实验室-主任: 卓大
+ * @Date 2025-07-26 23:56:58
+ * @Wechat zhuoda1024
+ * @Email lab1024@163.com
+ * @Copyright 1024创新实验室
+ */
+public class RepeatSubmitMemoryTicket extends AbstractRepeatSubmitTicket {
+
+ private Interner pool = Interners.newStrongInterner();
+
+ private ConcurrentMap ticketMap = Maps.newConcurrentMap();
+
+ public RepeatSubmitMemoryTicket(Function ticketFunction) {
+ super(ticketFunction);
+ }
+
+ @Override
+ public boolean tryLock(String ticket, Long currentTimestamp, Long intervalMilliSecond) {
+ synchronized (pool.intern(ticket)) {
+ Long lastTime = ticketMap.putIfAbsent(ticket, currentTimestamp);
+ if (lastTime == null) {
+ return true;
+ }
+
+ if (intervalMilliSecond <= 0) {
+ return false;
+ }
+
+ if (currentTimestamp - lastTime < intervalMilliSecond) {
+ return false;
+
+ }
+ ticketMap.put(ticket, currentTimestamp);
+ return true;
+ }
+ }
+
+ @Override
+ public void unLock(String ticket, Long intervalMilliSecond) {
+ if (intervalMilliSecond > 0) {
+ return;
+ }
+ ticketMap.remove(ticket);
+ }
+
+
+}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitRedisTicket.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitRedisTicket.java
index f940fdbb..9caa3778 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitRedisTicket.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitRedisTicket.java
@@ -1,38 +1,47 @@
package net.lab1024.sa.base.module.support.repeatsubmit.ticket;
-import org.springframework.data.redis.core.ValueOperations;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.data.redis.core.RedisTemplate;
+import java.util.concurrent.TimeUnit;
import java.util.function.Function;
/**
* 凭证(redis实现)
*
- * @Author 1024创新实验室: 罗伊
- * @Date 2020-11-25 20:56:58
+ * @Author 1024创新实验室-主任: 卓大
+ * @Date 2025-07-26 23:56:58
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室
*/
public class RepeatSubmitRedisTicket extends AbstractRepeatSubmitTicket {
- private final ValueOperations redisValueOperations;
+ private final RedisTemplate redisTemplate;
- public RepeatSubmitRedisTicket(ValueOperations redisValueOperations,
- Function ticketFunction) {
+ public RepeatSubmitRedisTicket(RedisTemplate redisTemplate,
+ Function ticketFunction) {
super(ticketFunction);
- this.redisValueOperations = redisValueOperations;
+ this.redisTemplate = redisTemplate;
}
@Override
- public Long getTicketTimestamp(String ticket) {
- String ticketLastTime = redisValueOperations.get(ticket);
- return ticketLastTime == null ? null : Long.valueOf(ticketLastTime);
+ public boolean tryLock(String ticket, Long currentTimestamp, Long intervalMilliSecond) {
+ if (intervalMilliSecond > 0) {
+ return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(ticket, String.valueOf(currentTimestamp), intervalMilliSecond, TimeUnit.MILLISECONDS));
+ } else {
+ return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(ticket, String.valueOf(currentTimestamp)));
+ }
}
@Override
- public void putTicket(String ticket) {
- redisValueOperations.getOperations().delete(ticket);
- this.getTicketTimestamp(ticket);
+ public void unLock(String ticket, Long intervalMilliSecond) {
+ if (intervalMilliSecond > 0) {
+ return;
+ }
+
+ redisTemplate.delete(ticket);
}
+
}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/securityprotect/service/SecurityFileService.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/securityprotect/service/SecurityFileService.java
index 9ecfd757..95873390 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/securityprotect/service/SecurityFileService.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/securityprotect/service/SecurityFileService.java
@@ -3,6 +3,7 @@ package net.lab1024.sa.base.module.support.securityprotect.service;
import lombok.extern.slf4j.Slf4j;
import jakarta.annotation.Resource;
import net.lab1024.sa.base.common.domain.ResponseDTO;
+import org.apache.commons.io.IOUtils;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.exception.TikaException;
import org.apache.tika.io.TikaInputStream;
@@ -14,6 +15,7 @@ import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
+import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
@@ -35,27 +37,9 @@ public class SecurityFileService {
private Level3ProtectConfigService level3ProtectConfigService;
// 定义白名单MIME类型
- private static final List ALLOWED_MIME_TYPES = Arrays.asList(
- "application/json",
- "application/zip",
- "application/x-7z-compressed",
- "application/pdf",
- "application/vnd.ms-excel",
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- "application/vnd.ms-powerpoint",
- "application/vnd.openxmlformats-officedocument.presentationml.presentation",
- "application/msword",
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- "application/vnd.ms-works",
- "text/csv",
- "audio/*",
- "video/*",
+ private static final List ALLOWED_MIME_TYPES = Arrays.asList("application/json", "application/zip", "application/x-7z-compressed", "application/pdf", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.ms-works", "text/csv", "audio/*", "video/*",
// 图片类型 svg有安全隐患,所以不使用"image/*"
- "image/jpeg",
- "image/png",
- "image/gif",
- "image/bmp"
- );
+ "image/jpeg", "image/png", "image/gif", "image/bmp");
/**
* 检测文件安全类型
@@ -73,8 +57,7 @@ public class SecurityFileService {
// 文件类型安全检测
if (level3ProtectConfigService.isFileDetectFlag()) {
String fileType = getFileMimeType(file);
- if (ALLOWED_MIME_TYPES.stream()
- .noneMatch(allowedType -> matchesMimeType(fileType, allowedType))) {
+ if (ALLOWED_MIME_TYPES.stream().noneMatch(allowedType -> matchesMimeType(fileType, allowedType))) {
return ResponseDTO.userErrorParam("禁止上传此文件类型");
}
}
@@ -89,16 +72,20 @@ public class SecurityFileService {
* @return 文件的 MIME 类型
*/
public static String getFileMimeType(MultipartFile file) {
+ InputStream inputStream = null;
try {
+ inputStream = file.getInputStream();
TikaConfig tika = new TikaConfig();
Metadata metadata = new Metadata();
metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, file.getOriginalFilename());
- TikaInputStream stream = TikaInputStream.get(file.getInputStream());
+ TikaInputStream stream = TikaInputStream.get(inputStream);
MediaType mimetype = tika.getDetector().detect(stream, metadata);
return mimetype.toString();
} catch (IOException | TikaException e) {
log.error(e.getMessage(), e);
return MimeTypes.OCTET_STREAM;
+ } finally {
+ IOUtils.closeQuietly(inputStream);
}
}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/SerialNumberBaseService.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/SerialNumberBaseService.java
index fce5e110..c136dea5 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/SerialNumberBaseService.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/SerialNumberBaseService.java
@@ -27,7 +27,7 @@ import java.util.concurrent.ConcurrentHashMap;
* @Date 2022-03-25 21:46:07
* @Wechat zhuoda1024
* @Email lab1024@163.com
- * @Copyright 1024创新实验室
+ * @Copyright 1024创新实验室
*/
public abstract class SerialNumberBaseService implements SerialNumberService {
@@ -37,7 +37,7 @@ public abstract class SerialNumberBaseService implements SerialNumberService {
@Resource
protected SerialNumberDao serialNumberDao;
- private ConcurrentHashMap serialNumberMap = new ConcurrentHashMap<>();
+ protected ConcurrentHashMap serialNumberMap = new ConcurrentHashMap<>();
public abstract List generateSerialNumberList(SerialNumberInfoBO serialNumber, int count);
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/impl/SerialNumberRedisService.java b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/impl/SerialNumberRedisService.java
index b70f8b24..b797f59e 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/impl/SerialNumberRedisService.java
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/impl/SerialNumberRedisService.java
@@ -1,23 +1,34 @@
package net.lab1024.sa.base.module.support.serialnumber.service.impl;
+import cn.hutool.core.util.RandomUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
-import net.lab1024.sa.base.common.exception.BusinessException;
+import net.lab1024.sa.base.common.util.SmartDateFormatterEnum;
+import net.lab1024.sa.base.common.util.SmartEnumUtil;
+import net.lab1024.sa.base.common.util.SmartLocalDateUtil;
+import net.lab1024.sa.base.common.util.SmartStringUtil;
import net.lab1024.sa.base.constant.RedisKeyConst;
import net.lab1024.sa.base.module.support.redis.RedisService;
+import net.lab1024.sa.base.module.support.serialnumber.constant.SerialNumberRuleTypeEnum;
import net.lab1024.sa.base.module.support.serialnumber.domain.SerialNumberEntity;
import net.lab1024.sa.base.module.support.serialnumber.domain.SerialNumberGenerateResultBO;
import net.lab1024.sa.base.module.support.serialnumber.domain.SerialNumberInfoBO;
-import net.lab1024.sa.base.module.support.serialnumber.domain.SerialNumberLastGenerateBO;
import net.lab1024.sa.base.module.support.serialnumber.service.SerialNumberBaseService;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
- * 单据序列号 基于redis锁实现
+ * 单据序列号 基于redis key-value increase 实现
*
* @Author 1024创新实验室-主任: 卓大
- * @Date 2022-03-25 21:46:07
+ * @Date 2025-08-03 22:46:07
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室
@@ -25,86 +36,128 @@ import java.util.List;
@Slf4j
public class SerialNumberRedisService extends SerialNumberBaseService {
- private static final int MAX_GET_LOCK_COUNT = 5;
-
- private static final long SLEEP_MILLISECONDS = 200L;
-
@Resource
private RedisService redisService;
+ @Resource
+ private RedisTemplate redisTemplate;
+
@Override
public void initLastGenerateData(List serialNumberEntityList) {
if (serialNumberEntityList == null) {
return;
}
- //删除之前的
- redisService.delete(RedisKeyConst.Support.SERIAL_NUMBER_LAST_INFO);
-
+ // 设置redis的上次值
for (SerialNumberEntity serialNumberEntity : serialNumberEntityList) {
- SerialNumberLastGenerateBO lastGenerateBO = SerialNumberLastGenerateBO
- .builder()
- .serialNumberId(serialNumberEntity.getSerialNumberId())
- .lastNumber(serialNumberEntity.getLastNumber())
- .lastTime(serialNumberEntity.getLastTime())
- .build();
+ if (serialNumberEntity.getLastTime() == null) {
+ continue;
+ }
- redisService.mset(RedisKeyConst.Support.SERIAL_NUMBER_LAST_INFO,
- String.valueOf(serialNumberEntity.getSerialNumberId()),
- lastGenerateBO
- );
+ String redisKey = generateRedisKeyByDate(serialNumberEntity.getSerialNumberId(),
+ SmartEnumUtil.getEnumByName(serialNumberEntity.getRuleType().toUpperCase(), SerialNumberRuleTypeEnum.class),
+ serialNumberEntity.getLastTime().toLocalDate());
+
+ Object o = redisTemplate.opsForValue().get(redisKey);
+ if (o == null) {
+ redisTemplate.opsForValue().set(redisKey, serialNumberEntity.getLastNumber());
+ }
+ }
+ }
+
+ /**
+ * 每天凌晨一点进行检测;
+ * 检测单位数量为3; 3天前、3月前、3年前
+ */
+ @Scheduled(cron = "0 0 1 * * ?")
+ public void tryDeleteUnusedRedisKey() {
+ for (SerialNumberInfoBO serialNumberInfoBO : serialNumberMap.values()) {
+ SerialNumberRuleTypeEnum typeEnum = serialNumberInfoBO.getSerialNumberRuleTypeEnum();
+ String dateStr = "";
+ switch (typeEnum) {
+ case DAY -> {
+ dateStr = SmartLocalDateUtil.format(LocalDate.now().minusDays(3), SmartDateFormatterEnum.YMD);
+ }
+ case MONTH -> {
+ dateStr = SmartLocalDateUtil.format(LocalDate.now().minusMonths(3), SmartDateFormatterEnum.YM);
+ }
+ case YEAR -> {
+ dateStr = String.valueOf(LocalDate.now().minusYears(3));
+ }
+ }
+ if (SmartStringUtil.isNotEmpty(dateStr)) {
+ String redisKey = RedisKeyConst.Support.SERIAL_NUMBER + serialNumberInfoBO.getSerialNumberId() + ":" + dateStr;
+ redisService.delete(redisKey);
+ }
}
}
@Override
public List generateSerialNumberList(SerialNumberInfoBO serialNumberInfo, int count) {
- SerialNumberGenerateResultBO serialNumberGenerateResult = null;
- String lockKey = RedisKeyConst.Support.SERIAL_NUMBER + serialNumberInfo.getSerialNumberId();
-
- boolean lock = false;
- for (int i = 0; i < MAX_GET_LOCK_COUNT; i++) {
- try {
- lock = redisService.getLock(lockKey, 60 * 1000L);
- if (lock) {
- break;
- }
- Thread.sleep(SLEEP_MILLISECONDS);
- } catch (Throwable e) {
- log.error(e.getMessage(), e);
+ // 根据步长,计算 redis 增加值
+ ArrayList list = new ArrayList<>(count);
+ int redisIncrease = 0;
+ for (int i = 0; i < count; i++) {
+ int stepIncrease = 1;
+ Integer stepRandomRange = serialNumberInfo.getStepRandomRange();
+ if (stepRandomRange > 1) {
+ stepIncrease = RandomUtil.getSecureRandom().nextInt(1, serialNumberInfo.getStepRandomRange() + 1);
}
+ redisIncrease += stepIncrease;
+ list.add(stepIncrease);
}
- if (!lock) {
- throw new BusinessException("SerialNumber 尝试5次,未能生成单号");
- }
-
try {
- // 获取上次的生成结果
- SerialNumberLastGenerateBO lastGenerateBO = (SerialNumberLastGenerateBO) redisService.mget(
- RedisKeyConst.Support.SERIAL_NUMBER_LAST_INFO,
- String.valueOf(serialNumberInfo.getSerialNumberId()));
+ String redisKey = generateRedisKeyByDate(serialNumberInfo.getSerialNumberId(), serialNumberInfo.getSerialNumberRuleTypeEnum(), LocalDate.now());
+ Long increaseResult = redisTemplate.opsForValue().increment(redisKey, redisIncrease);
+
+ ArrayList numberList = new ArrayList<>(count);
+ Long number = increaseResult;
+ for (Integer i : list) {
+ number = number - i;
+ numberList.add((number + 1));
+ }
+
+ Collections.reverse(numberList);
+
+ SerialNumberGenerateResultBO serialNumberGenerateResult = SerialNumberGenerateResultBO
+ .builder()
+ .serialNumberId(serialNumberInfo.getSerialNumberId())
+ .lastNumber(increaseResult)
+ .lastTime(LocalDateTime.now())
+ .numberList(numberList)
+ .isReset(false)
+ .build();
- // 生成
- serialNumberGenerateResult = super.loopNumberList(lastGenerateBO, serialNumberInfo, count);
// 将生成信息保存的内存和数据库
- lastGenerateBO.setLastNumber(serialNumberGenerateResult.getLastNumber());
- lastGenerateBO.setLastTime(serialNumberGenerateResult.getLastTime());
serialNumberDao.updateLastNumberAndTime(serialNumberInfo.getSerialNumberId(),
serialNumberGenerateResult.getLastNumber(),
serialNumberGenerateResult.getLastTime());
- redisService.mset(RedisKeyConst.Support.SERIAL_NUMBER_LAST_INFO,
- String.valueOf(serialNumberInfo.getSerialNumberId()), lastGenerateBO);
-
// 把生成过程保存到数据库里
super.saveRecord(serialNumberGenerateResult);
+ return formatNumberList(serialNumberGenerateResult, serialNumberInfo);
} catch (Throwable e) {
log.error(e.getMessage(), e);
throw e;
- } finally {
- redisService.unLock(lockKey);
}
+ }
- return formatNumberList(serialNumberGenerateResult, serialNumberInfo);
+ private String generateRedisKeyByDate(Integer serialNumberId, SerialNumberRuleTypeEnum serialNumberRuleTypeEnum, LocalDate localDate) {
+ return switch (serialNumberRuleTypeEnum) {
+ case DAY -> {
+ String dayStr = SmartLocalDateUtil.format(localDate, SmartDateFormatterEnum.YMD);
+ yield RedisKeyConst.Support.SERIAL_NUMBER + serialNumberId + ":" + dayStr;
+ }
+ case MONTH -> {
+ String monthStr = SmartLocalDateUtil.format(localDate, SmartDateFormatterEnum.YM);
+ yield RedisKeyConst.Support.SERIAL_NUMBER + serialNumberId + ":" + monthStr;
+ }
+ case YEAR -> {
+ String yearStr = String.valueOf(localDate.getYear());
+ yield RedisKeyConst.Support.SERIAL_NUMBER + serialNumberId + ":" + yearStr;
+ }
+ case NONE -> RedisKeyConst.Support.SERIAL_NUMBER + serialNumberId;
+ };
}
}
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/resources/dev/sa-base.yaml b/smart-admin-api-java17-springboot3/sa-base/src/main/resources/dev/sa-base.yaml
index d6802f47..c6cf7410 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/resources/dev/sa-base.yaml
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/resources/dev/sa-base.yaml
@@ -65,10 +65,26 @@ spring:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
+ # 上传文件和请求大小
+ servlet:
+ multipart:
+ max-file-size: 20MB # 单个文件的最大大小
+ max-request-size: 10MB # 整个请求的最大大小
+
# 缓存实现类型
cache:
type: redis
+# 健康检查
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health,info
+ health:
+ mail:
+ enabled: false
+
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server:
tomcat:
@@ -110,7 +126,7 @@ knife4j:
username: api # Basic认证用户名
password: 1024 # Basic认证密码
-# RestTemplate 请求配置
+# RestTemplate 请求配置 毫秒
http:
pool:
max-total: 20
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/resources/pre/sa-base.yaml b/smart-admin-api-java17-springboot3/sa-base/src/main/resources/pre/sa-base.yaml
index 2836bad0..ebcdf8f8 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/resources/pre/sa-base.yaml
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/resources/pre/sa-base.yaml
@@ -65,10 +65,26 @@ spring:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
+ # 上传文件和请求大小
+ servlet:
+ multipart:
+ max-file-size: 20MB # 单个文件的最大大小
+ max-request-size: 10MB # 整个请求的最大大小
+
# 缓存实现类型
cache:
type: redis
+# 健康检查
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health,info
+ health:
+ mail:
+ enabled: false
+
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server:
tomcat:
@@ -110,7 +126,7 @@ knife4j:
username: api # Basic认证用户名
password: 1024 # Basic认证密码
-# RestTemplate 请求配置
+# RestTemplate 请求配置 毫秒
http:
pool:
max-total: 20
@@ -134,7 +150,7 @@ reload:
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: Authorization
- # token 前缀 例如:Bear
+ # token 前缀 例如:Bearer
token-prefix: Bearer
# token 有效期(单位:秒) 默认30天(2592000秒),-1 代表永久有效
timeout: 2592000
@@ -168,4 +184,4 @@ smart:
# 数据库配置检测-开关 默认开启 可选(作用是固定间隔读取数据库配置更新任务,关闭后只能重启服务或通过接口修改定时任务,建议开启)
db-refresh-enabled: true
# 数据库配置检测-执行间隔 默认120秒 可选
- db-refresh-interval: 60
\ No newline at end of file
+ db-refresh-interval: 60
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/resources/prod/sa-base.yaml b/smart-admin-api-java17-springboot3/sa-base/src/main/resources/prod/sa-base.yaml
index 3cf50f34..f50a9669 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/resources/prod/sa-base.yaml
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/resources/prod/sa-base.yaml
@@ -7,14 +7,14 @@ spring:
driver-class-name: com.mysql.cj.jdbc.Driver
initial-size: 10
min-idle: 10
- max-active: 100
+ max-active: 200
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
filters: stat
druid:
username: druid
- password: 1024lab
+ password: 1024
login:
enabled: false
method:
@@ -34,7 +34,6 @@ spring:
min-idle: 10
max-idle: 50
max-wait: 30000ms
-
# 邮件,置以SSL的方式发送, 这个需要使用这种方式并且端口是465
mail:
host: smtp.163.com
@@ -65,10 +64,26 @@ spring:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
+ # 上传文件和请求大小
+ servlet:
+ multipart:
+ max-file-size: 20MB # 单个文件的最大大小
+ max-request-size: 10MB # 整个请求的最大大小
+
# 缓存实现类型
cache:
type: redis
+# 健康检查
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health,info
+ health:
+ mail:
+ enabled: false
+
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server:
tomcat:
@@ -95,14 +110,13 @@ file:
url-prefix: https://${file.storage.cloud.bucket-name}.${file.storage.cloud.endpoint}/
private-url-expire-seconds: 3600
-
# open api配置
springdoc:
swagger-ui:
enabled: true # 开关
doc-expansion: none #关闭展开
tags-sorter: alpha
- server-base-url: https://preview.smartadmin.vip/smart-admin-api
+ server-base-url:
api-docs:
enabled: true # 开关
knife4j:
@@ -112,7 +126,7 @@ knife4j:
username: api # Basic认证用户名
password: 1024 # Basic认证密码
-# RestTemplate 请求配置
+# RestTemplate 请求配置 毫秒
http:
pool:
max-total: 100
@@ -133,7 +147,7 @@ reload:
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: Authorization
- # token 前缀 例如:Bear
+ # token 前缀 例如:Bearer
token-prefix: Bearer
# token 有效期(单位:秒) 默认30天(2592000秒),-1 代表永久有效
timeout: 2592000
diff --git a/smart-admin-api-java17-springboot3/sa-base/src/main/resources/test/sa-base.yaml b/smart-admin-api-java17-springboot3/sa-base/src/main/resources/test/sa-base.yaml
index 2836bad0..ebcdf8f8 100644
--- a/smart-admin-api-java17-springboot3/sa-base/src/main/resources/test/sa-base.yaml
+++ b/smart-admin-api-java17-springboot3/sa-base/src/main/resources/test/sa-base.yaml
@@ -65,10 +65,26 @@ spring:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
+ # 上传文件和请求大小
+ servlet:
+ multipart:
+ max-file-size: 20MB # 单个文件的最大大小
+ max-request-size: 10MB # 整个请求的最大大小
+
# 缓存实现类型
cache:
type: redis
+# 健康检查
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health,info
+ health:
+ mail:
+ enabled: false
+
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server:
tomcat:
@@ -110,7 +126,7 @@ knife4j:
username: api # Basic认证用户名
password: 1024 # Basic认证密码
-# RestTemplate 请求配置
+# RestTemplate 请求配置 毫秒
http:
pool:
max-total: 20
@@ -134,7 +150,7 @@ reload:
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: Authorization
- # token 前缀 例如:Bear
+ # token 前缀 例如:Bearer
token-prefix: Bearer
# token 有效期(单位:秒) 默认30天(2592000秒),-1 代表永久有效
timeout: 2592000
@@ -168,4 +184,4 @@ smart:
# 数据库配置检测-开关 默认开启 可选(作用是固定间隔读取数据库配置更新任务,关闭后只能重启服务或通过接口修改定时任务,建议开启)
db-refresh-enabled: true
# 数据库配置检测-执行间隔 默认120秒 可选
- db-refresh-interval: 60
\ No newline at end of file
+ db-refresh-interval: 60
diff --git a/smart-admin-api-java8-springboot2/pom.xml b/smart-admin-api-java8-springboot2/pom.xml
index 28671c02..5226771a 100644
--- a/smart-admin-api-java8-springboot2/pom.xml
+++ b/smart-admin-api-java8-springboot2/pom.xml
@@ -22,48 +22,43 @@
2.7.18
2.0.8
5.8.16
- 3.5.2
- 8.0.33
+ 3.5.12
+ 9.3.0
3.9.1
1.7.0
- 4.3.0
- 2.0.48
- 1.2.14
+ 4.5.0
+ 2.0.57
+ 1.2.25
1.4.2
20.0
- 0.9.11
- 2.15.0
- 3.12.0
- 4.4
- 1.26.0
- 1.13
- 1.9
- 2.12.0
- 1.0.0
- 5.2.4
- 1.4
- 1.11.842
- 2.23.1
- 5.7.22
- 2.3
+ 0.10.2
+ 2.19.0
+ 3.18.0
+ 4.5.0
+ 1.27.1
+ 1.18.0
+ 1.13.1
+ 1.2.0
+ 5.4.1
+ 2.31.78
+ 5.8.39
+ 2.4.1
3.1
- 1.41.0
+ 1.44.0
2.7.0
1.80
- 2.13.4
- 2.16.1
1.2.0
- 3.25.0
- 2.2
- 2.3.33
- 1.18.1
- 2.9.3
+ 3.50.0
+ 2.4
+ 2.3.34
+ 1.21.1
+ 2.9.4
-
+
org.springframework.boot
spring-boot-dependencies
@@ -71,7 +66,16 @@
pom
import
-
+
+
+
+ com.baomidou
+ mybatis-plus-bom
+ ${mybatis-plus.version}
+ pom
+ import
+
+
org.springframework
@@ -97,18 +101,6 @@
${mysql-connector-j.version}
-
- com.baomidou
- mybatis-plus-boot-starter
- ${mybatis-plus.version}
-
-
- org.springframework.boot
- spring-boot-starter-logging
-
-
-
-
p6spy
p6spy
@@ -194,9 +186,9 @@
- com.amazonaws
- aws-java-sdk-s3
- ${aws-java-sdk.version}
+ software.amazon.awssdk
+ s3
+ ${awssdk-s3.version}
commons-logging
@@ -294,20 +286,8 @@
org.apache.poi
- ooxml-schemas
- ${ooxml-schemas.version}
-
-
-
- com.fasterxml.jackson.datatype
- jackson-datatype-jsr310
- ${jackson-datatype-jsr310.version}
-
-
-
- com.fasterxml.jackson.dataformat
- jackson-dataformat-yaml
- ${jackson-dataformat-yaml.version}
+ poi-ooxml-full
+ ${poi.version}
diff --git a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java
index 61d7f7f4..fd323906 100644
--- a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java
+++ b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java
@@ -4,7 +4,6 @@ import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.strategy.SaAnnotationStrategy;
-import cn.dev33.satoken.strategy.SaStrategy;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.module.system.login.domain.RequestEmployee;
import net.lab1024.sa.admin.module.system.login.service.LoginService;
@@ -69,6 +68,7 @@ public class AdminInterceptor implements HandlerInterceptor {
NoNeedLogin noNeedLogin = ((HandlerMethod) handler).getMethodAnnotation(NoNeedLogin.class);
if (noNeedLogin != null) {
checkActiveTimeout(requestEmployee);
+ SmartRequestUtil.setRequestUser(requestEmployee);
return true;
}
diff --git a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/entity/DepartmentEntity.java b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/entity/DepartmentEntity.java
index 4d52bb16..cc4b1639 100644
--- a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/entity/DepartmentEntity.java
+++ b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/entity/DepartmentEntity.java
@@ -36,7 +36,7 @@ public class DepartmentEntity {
/**
* 负责人员工 id
*/
- @TableField(updateStrategy = FieldStrategy.IGNORED)
+ @TableField(updateStrategy = FieldStrategy.NEVER)
private Long managerId;
/**
diff --git a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java
index edc53e61..f6819cde 100644
--- a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java
+++ b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java
@@ -23,6 +23,12 @@ public class EmployeeEntity {
@TableId(type = IdType.AUTO)
private Long employeeId;
+ /**
+ * 唯一id
+ */
+ private String employeeUid;
+
+
/**
* 登录账号
*/
diff --git a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java
index d2b97e50..9de2d20c 100644
--- a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java
+++ b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java
@@ -1,6 +1,7 @@
package net.lab1024.sa.admin.module.system.employee.service;
import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import net.lab1024.sa.admin.module.system.department.dao.DepartmentDao;
@@ -138,16 +139,20 @@ public class EmployeeService {
}
EmployeeEntity entity = SmartBeanUtil.copy(employeeAddForm, EmployeeEntity.class);
+ // 员工uid
+ String employeeUid = UUID.randomUUID(true).toString(true);
+ entity.setEmployeeUid(employeeUid);
- // 设置密码 默认密码
- String password = securityPasswordService.randomPassword();
- entity.setLoginPwd(SecurityPasswordService.getEncryptPwd(password));
+ // 设置密码 随机密码
+ String randomPassword = securityPasswordService.randomPassword();
+ String generateSaltPassword = this.generateSaltPassword(randomPassword, employeeUid);
+ entity.setLoginPwd(SecurityPasswordService.getEncryptPwd(generateSaltPassword));
// 保存数据
entity.setDeletedFlag(Boolean.FALSE);
employeeManager.saveEmployee(entity, employeeAddForm.getRoleIdList());
- return ResponseDTO.ok(password);
+ return ResponseDTO.ok(randomPassword);
}
/**
@@ -241,7 +246,6 @@ public class EmployeeService {
/**
* 更新登录人头像
- *
*/
public ResponseDTO updateAvatar(EmployeeUpdateAvatarForm employeeUpdateAvatarForm) {
Long employeeId = employeeUpdateAvatarForm.getEmployeeId();
@@ -343,12 +347,12 @@ public class EmployeeService {
}
// 校验原始密码
- if (!SecurityPasswordService.matchesPwd(updatePasswordForm.getOldPassword(),employeeEntity.getLoginPwd()) ) {
+ if (!SecurityPasswordService.matchesPwd(this.generateSaltPassword(updatePasswordForm.getOldPassword(), employeeEntity.getEmployeeUid()), employeeEntity.getLoginPwd())) {
return ResponseDTO.userErrorParam("原密码有误,请重新输入");
}
// 新旧密码相同
- if (Objects.equals(updatePasswordForm.getOldPassword(), updatePasswordForm.getNewPassword()) ){
+ if (Objects.equals(updatePasswordForm.getOldPassword(), updatePasswordForm.getNewPassword())) {
return ResponseDTO.userErrorParam("新密码与原始密码相同,请重新输入");
}
@@ -359,14 +363,13 @@ public class EmployeeService {
}
// 根据三级等保规则,校验密码是否重复
- ResponseDTO passwordRepeatTimes = securityPasswordService.validatePasswordRepeatTimes(requestUser, updatePasswordForm.getNewPassword());
+ ResponseDTO passwordRepeatTimes = securityPasswordService.validatePasswordRepeatTimes(requestUser, this.generateSaltPassword(updatePasswordForm.getNewPassword(), employeeEntity.getEmployeeUid()));
if (!passwordRepeatTimes.getOk()) {
return ResponseDTO.error(passwordRepeatTimes);
}
-
// 更新密码
- String newEncryptPassword = SecurityPasswordService.getEncryptPwd(updatePasswordForm.getNewPassword());
+ String newEncryptPassword = SecurityPasswordService.getEncryptPwd(this.generateSaltPassword(updatePasswordForm.getNewPassword(), employeeEntity.getEmployeeUid()));
EmployeeEntity updateEntity = new EmployeeEntity();
updateEntity.setEmployeeId(employeeId);
updateEntity.setLoginPwd(newEncryptPassword);
@@ -405,8 +408,14 @@ public class EmployeeService {
* 重置密码
*/
public ResponseDTO resetPassword(Long employeeId) {
+ EmployeeEntity employeeEntity = employeeDao.selectById(employeeId);
+ if (employeeEntity == null) {
+ return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST);
+ }
+
String password = securityPasswordService.randomPassword();
- employeeDao.updatePassword(employeeId, SecurityPasswordService.getEncryptPwd(password));
+ String saltPassword = this.generateSaltPassword(password, employeeEntity.getEmployeeUid());
+ employeeDao.updatePassword(employeeId, SecurityPasswordService.getEncryptPwd(saltPassword));
return ResponseDTO.ok(password);
}
@@ -426,4 +435,14 @@ public class EmployeeService {
return employeeDao.getByLoginName(loginName, false);
}
+ /**
+ * 生成加盐密码
+ * 格式为:[password]_[uid大写]_[uid小写]
+ */
+ public String generateSaltPassword(String password, String employeeUid) {
+ return password + StringConst.UNDERLINE +
+ employeeUid.toUpperCase() +
+ StringConst.UNDERLINE +
+ employeeUid.toLowerCase();
+ }
}
diff --git a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java
index d51f2c4a..889e1ad4 100644
--- a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java
+++ b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java
@@ -58,7 +58,7 @@ public class LoginController {
return ResponseDTO.ok(loginResult);
}
- @Operation(summary = "退出登陆 @author 卓大")
+ @Operation(summary = "退出登录 @author 卓大")
@GetMapping("/login/logout")
public ResponseDTO logout() {
return loginService.logout(SmartRequestUtil.getRequestUser());
diff --git a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java
index 21f62753..29d4778a 100644
--- a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java
+++ b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java
@@ -7,7 +7,6 @@ import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.servlet.ServletUtil;
import lombok.extern.slf4j.Slf4j;
-import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO;
import net.lab1024.sa.admin.module.system.department.service.DepartmentService;
import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity;
import net.lab1024.sa.admin.module.system.employee.service.EmployeeService;
@@ -49,8 +48,6 @@ import net.lab1024.sa.base.module.support.securityprotect.domain.LoginFailEntity
import net.lab1024.sa.base.module.support.securityprotect.service.Level3ProtectConfigService;
import net.lab1024.sa.base.module.support.securityprotect.service.SecurityLoginService;
import net.lab1024.sa.base.module.support.securityprotect.service.SecurityPasswordService;
-import org.apache.commons.lang3.BooleanUtils;
-import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@@ -82,9 +79,6 @@ public class LoginService implements StpInterface {
@Resource
private EmployeeService employeeService;
- @Resource
- private DepartmentService departmentService;
-
@Resource
private CaptchaService captchaService;
@@ -106,9 +100,6 @@ public class LoginService implements StpInterface {
@Resource
private SecurityPasswordService protectPasswordService;
- @Resource
- private IFileStorageService fileStorageService;
-
@Resource
private ApiEncryptService apiEncryptService;
@@ -132,7 +123,7 @@ public class LoginService implements StpInterface {
}
/**
- * 员工登陆
+ * 员工登录
*
* @return 返回用户登录信息
*/
@@ -196,7 +187,7 @@ public class LoginService implements StpInterface {
}
// 密码错误
- if (!SecurityPasswordService.matchesPwd(requestPassword, employeeEntity.getLoginPwd())) {
+ if (!SecurityPasswordService.matchesPwd(employeeService.generateSaltPassword(requestPassword, employeeEntity.getEmployeeUid()), employeeEntity.getLoginPwd())) {
// 记录登录失败
saveLoginLog(employeeEntity, ip, userAgent, "密码错误", LoginLogResultEnum.LOGIN_FAIL, loginDeviceEnum);
// 记录等级保护次数
@@ -273,7 +264,7 @@ public class LoginService implements StpInterface {
/**
- * 根据登陆token 获取员请求工信息
+ * 根据登录token 获取员请求工信息
*/
public RequestEmployee getLoginEmployee(String loginId, HttpServletRequest request) {
if (loginId == null) {
diff --git a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleVO.java b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleVO.java
index 82592f12..767cda9e 100644
--- a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleVO.java
+++ b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleVO.java
@@ -2,9 +2,6 @@ package net.lab1024.sa.admin.module.system.role.domain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
-import org.hibernate.validator.constraints.Length;
-
-import javax.validation.constraints.NotNull;
/**
* 角色
diff --git a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleMenuManager.java b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleMenuManager.java
index a43f3eeb..8ee4bc5a 100644
--- a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleMenuManager.java
+++ b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleMenuManager.java
@@ -3,7 +3,6 @@ package net.lab1024.sa.admin.module.system.role.manager;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.lab1024.sa.admin.module.system.role.dao.RoleMenuDao;
import net.lab1024.sa.admin.module.system.role.domain.entity.RoleMenuEntity;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
diff --git a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleDataScopeService.java b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleDataScopeService.java
index 66d538e8..f73a8528 100644
--- a/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleDataScopeService.java
+++ b/smart-admin-api-java8-springboot2/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleDataScopeService.java
@@ -1,14 +1,13 @@
package net.lab1024.sa.admin.module.system.role.service;
import com.google.common.collect.Lists;
+import net.lab1024.sa.admin.module.system.role.domain.entity.RoleDataScopeEntity;
import net.lab1024.sa.admin.module.system.role.domain.form.RoleDataScopeUpdateForm;
import net.lab1024.sa.admin.module.system.role.domain.vo.RoleDataScopeVO;
+import net.lab1024.sa.admin.module.system.role.manager.RoleDataScopeManager;
import net.lab1024.sa.base.common.code.UserErrorCode;
import net.lab1024.sa.base.common.domain.ResponseDTO;
import net.lab1024.sa.base.common.util.SmartBeanUtil;
-import net.lab1024.sa.admin.module.system.role.domain.entity.RoleDataScopeEntity;
-import net.lab1024.sa.admin.module.system.role.manager.RoleDataScopeManager;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
diff --git a/smart-admin-api-java8-springboot2/sa-base/pom.xml b/smart-admin-api-java8-springboot2/sa-base/pom.xml
index 788b77ae..3fc30e01 100644
--- a/smart-admin-api-java8-springboot2/sa-base/pom.xml
+++ b/smart-admin-api-java8-springboot2/sa-base/pom.xml
@@ -131,6 +131,17 @@
com.baomidou
mybatis-plus-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+
+
+
+ com.baomidou
+ mybatis-plus-jsqlparser-4.9
@@ -179,8 +190,8 @@
- com.amazonaws
- aws-java-sdk-s3
+ software.amazon.awssdk
+ s3
@@ -250,17 +261,12 @@
org.apache.poi
- ooxml-schemas
+ poi-ooxml
- com.fasterxml.jackson.datatype
- jackson-datatype-jsr310
-
-
-
- com.fasterxml.jackson.dataformat
- jackson-dataformat-yaml
+ org.apache.poi
+ poi-ooxml-full
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartPageUtil.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartPageUtil.java
index 9dca8487..eb88c587 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartPageUtil.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartPageUtil.java
@@ -52,8 +52,7 @@ public class SmartPageUtil {
log.error("《存在SQL注入:》 : {}", sortItem.getColumn());
throw new BusinessException("存在SQL注入风险,请联系技术工作人员!");
}
-
- orderItemList.add(new OrderItem(sortItem.getColumn(), sortItem.getIsAsc()));
+ orderItemList.add(sortItem.getIsAsc() ? OrderItem.asc(sortItem.getColumn()) : OrderItem.desc(sortItem.getColumn()));
}
page.setOrders(orderItemList);
return page;
@@ -94,7 +93,7 @@ public class SmartPageUtil {
return newPageResult;
}
- public static PageResult subListPage(Integer pageNum, Integer pageSize, List list) {
+ public static PageResult subListPage(Integer pageNum, Integer pageSize, List list) {
PageResult pageRet = new PageResult();
//总条数
int count = list.size();
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartRequestUtil.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartRequestUtil.java
index ab6e5746..aab02304 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartRequestUtil.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartRequestUtil.java
@@ -18,6 +18,9 @@ public class SmartRequestUtil {
private static final ThreadLocal REQUEST_THREAD_LOCAL = new ThreadLocal<>();
public static void setRequestUser(RequestUser requestUser) {
+ if(requestUser == null){
+ return;
+ }
REQUEST_THREAD_LOCAL.set(requestUser);
}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartResponseUtil.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartResponseUtil.java
index bca8077d..95995bd9 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartResponseUtil.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartResponseUtil.java
@@ -11,7 +11,6 @@ import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
import static cn.hutool.core.util.CharsetUtil.UTF_8;
@@ -55,9 +54,8 @@ public class SmartResponseUtil {
if (SmartStringUtil.isNotEmpty(fileName)) {
response.setHeader(HttpHeaders.CONTENT_TYPE, MediaTypeFactory.getMediaType(fileName).orElse(MediaType.APPLICATION_OCTET_STREAM) + ";charset=utf-8");
try {
- response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(fileName, UTF_8).replaceAll("\\+", "%20"));
+ response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(fileName, "utf-8").replaceAll("\\+", "%20"));
} catch (UnsupportedEncodingException e) {
- log.error(e.getMessage(), e);
throw new RuntimeException(e);
}
response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/config/FileConfig.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/config/FileConfig.java
index a929cca6..98eb03fe 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/config/FileConfig.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/config/FileConfig.java
@@ -1,12 +1,5 @@
package net.lab1024.sa.base.config;
-import com.amazonaws.ClientConfiguration;
-import com.amazonaws.Protocol;
-import com.amazonaws.auth.AWSStaticCredentialsProvider;
-import com.amazonaws.auth.BasicAWSCredentials;
-import com.amazonaws.client.builder.AwsClientBuilder;
-import com.amazonaws.services.s3.AmazonS3;
-import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import lombok.Data;
import net.lab1024.sa.base.module.support.file.service.FileStorageCloudServiceImpl;
import net.lab1024.sa.base.module.support.file.service.FileStorageLocalServiceImpl;
@@ -17,6 +10,13 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.services.s3.S3Configuration;
+
+import java.net.URI;
/**
* 文件上传 配置
@@ -31,6 +31,10 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class FileConfig implements WebMvcConfigurer {
+ private static final String HTTPS = "https://";
+
+ private static final String HTTP = "http://";
+
private static final String MODE_CLOUD = "cloud";
private static final String MODE_LOCAL = "local";
@@ -69,15 +73,17 @@ public class FileConfig implements WebMvcConfigurer {
*/
@Bean
@ConditionalOnProperty(prefix = "file.storage", name = {"mode"}, havingValue = MODE_CLOUD)
- public AmazonS3 initAmazonS3() {
- ClientConfiguration clientConfig = new ClientConfiguration();
- clientConfig.setProtocol(Protocol.HTTPS);
- return AmazonS3ClientBuilder.standard()
- .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)))
- .withClientConfiguration(clientConfig)
- .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region))
- .withPathStyleAccessEnabled(false)
- .withChunkedEncodingDisabled(true)
+ public S3Client initAmazonS3() {
+ return S3Client.builder()
+ .region(Region.AWS_GLOBAL)
+ .endpointOverride(URI.create((urlPrefix.startsWith(HTTPS) ? HTTPS : HTTP) + endpoint))
+ .credentialsProvider(
+ StaticCredentialsProvider.create(
+ AwsBasicCredentials.create(accessKey, secretKey)))
+ .serviceConfiguration(S3Configuration.builder()
+ .pathStyleAccessEnabled(false)
+ .chunkedEncodingEnabled(false)
+ .build())
.build();
}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/config/RepeatSubmitConfig.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/config/RepeatSubmitConfig.java
index 52733fb9..c077e416 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/config/RepeatSubmitConfig.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/config/RepeatSubmitConfig.java
@@ -3,13 +3,13 @@ package net.lab1024.sa.base.config;
import net.lab1024.sa.base.common.constant.StringConst;
import net.lab1024.sa.base.common.util.SmartRequestUtil;
import net.lab1024.sa.base.module.support.repeatsubmit.RepeatSubmitAspect;
-import net.lab1024.sa.base.module.support.repeatsubmit.ticket.RepeatSubmitCaffeineTicket;
import net.lab1024.sa.base.module.support.repeatsubmit.ticket.RepeatSubmitRedisTicket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.data.redis.core.RedisTemplate;
import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
/**
* 重复提交配置
@@ -24,22 +24,22 @@ import javax.annotation.Resource;
public class RepeatSubmitConfig {
@Resource
- private ValueOperations valueOperations;
+ private RedisTemplate redisTemplate;
@Bean
public RepeatSubmitAspect repeatSubmitAspect() {
- RepeatSubmitRedisTicket caffeineTicket = new RepeatSubmitRedisTicket(valueOperations, this::ticket);
- return new RepeatSubmitAspect(caffeineTicket);
+ RepeatSubmitRedisTicket ticket = new RepeatSubmitRedisTicket(redisTemplate, this::ticket);
+ return new RepeatSubmitAspect(ticket);
}
/**
* 获取指明某个用户的凭证
*/
- private String ticket(String servletPath) {
+ private String ticket(HttpServletRequest request) {
Long userId = SmartRequestUtil.getRequestUserId();
if (null == userId) {
return StringConst.EMPTY;
}
- return servletPath + "_" + userId;
+ return request.getServletPath() + "_" + userId;
}
}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/listener/WebServerListener.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/listener/WebServerListener.java
index 8faa6acf..c248c7da 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/listener/WebServerListener.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/listener/WebServerListener.java
@@ -6,15 +6,10 @@ import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.base.common.code.ErrorCodeRegister;
import net.lab1024.sa.base.common.enumeration.SystemEnvironmentEnum;
import net.lab1024.sa.base.common.util.SmartEnumUtil;
-import net.lab1024.sa.base.module.support.reload.ReloadCommand;
-import net.lab1024.sa.base.module.support.reload.core.SmartReloadManager;
import org.springframework.beans.factory.annotation.Value;
-import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.web.context.WebServerApplicationContext;
import org.springframework.boot.web.context.WebServerInitializedEvent;
-import org.springframework.boot.web.server.WebServer;
import org.springframework.context.ApplicationListener;
-import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/captcha/CaptchaService.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/captcha/CaptchaService.java
index 8ff1e9ef..314107fc 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/captcha/CaptchaService.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/captcha/CaptchaService.java
@@ -3,9 +3,9 @@ package net.lab1024.sa.base.module.support.captcha;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.img.ImgUtil;
+import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
-import net.lab1024.sa.base.common.constant.StringConst;
import net.lab1024.sa.base.common.domain.ResponseDTO;
import net.lab1024.sa.base.common.domain.SystemEnvironment;
import net.lab1024.sa.base.constant.RedisKeyConst;
@@ -18,7 +18,6 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.awt.*;
import java.util.Objects;
-import java.util.UUID;
/**
* 图形验证码 服务
@@ -70,7 +69,7 @@ public class CaptchaService {
* 图片 base64格式
*/
// uuid 唯一标识
- String uuid = UUID.randomUUID().toString().replace("-", StringConst.EMPTY);
+ String uuid = IdUtil.fastSimpleUUID();
CaptchaVO captchaVO = new CaptchaVO();
captchaVO.setCaptchaUuid(uuid);
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorService.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorService.java
index 8500ca04..5dd85e17 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorService.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorService.java
@@ -40,7 +40,7 @@ import java.util.Optional;
@Service
public class CodeGeneratorService {
- private static final String COLUMN_NULLABLE_IDENTIFY = "NO";
+ private static final String COLUMN_NO_NULLABLE_IDENTIFY = "NO";
private static final String COLUMN_PRIMARY_KEY = "PRI";
@@ -65,7 +65,7 @@ public class CodeGeneratorService {
public List getTableColumns(String tableName) {
List tableColumns = codeGeneratorDao.selectTableColumn(tableName);
for (TableColumnVO tableColumn : tableColumns) {
- tableColumn.setNullableFlag(!COLUMN_NULLABLE_IDENTIFY.equalsIgnoreCase(tableColumn.getIsNullable()));
+ tableColumn.setNullableFlag(!COLUMN_NO_NULLABLE_IDENTIFY.equalsIgnoreCase(tableColumn.getIsNullable()));
tableColumn.setPrimaryKeyFlag(COLUMN_PRIMARY_KEY.equalsIgnoreCase(tableColumn.getColumnKey()));
tableColumn.setAutoIncreaseFlag(SmartStringUtil.isNotEmpty(tableColumn.getExtra()) && COLUMN_AUTO_INCREASE.equalsIgnoreCase(tableColumn.getExtra()));
}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorTemplateService.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorTemplateService.java
index 507e323b..dddc985a 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorTemplateService.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/CodeGeneratorTemplateService.java
@@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
+import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
@@ -82,7 +83,7 @@ public class CodeGeneratorTemplateService {
}
public void zipGeneratedFiles(OutputStream outputStream, String tableName, CodeGeneratorConfigEntity codeGeneratorConfigEntity) {
- String uuid = UUID.randomUUID().toString();
+ String uuid = IdUtil.fastSimpleUUID();
File dir = new File(uuid);
// 1、生产文件
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/variable/backend/domain/QueryFormVariableService.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/variable/backend/domain/QueryFormVariableService.java
index ef1f4398..028275b2 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/variable/backend/domain/QueryFormVariableService.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/service/variable/backend/domain/QueryFormVariableService.java
@@ -8,7 +8,6 @@ import net.lab1024.sa.base.module.support.codegenerator.domain.form.CodeGenerato
import net.lab1024.sa.base.module.support.codegenerator.domain.model.CodeField;
import net.lab1024.sa.base.module.support.codegenerator.domain.model.CodeQueryField;
import net.lab1024.sa.base.module.support.codegenerator.service.variable.CodeGenerateBaseVariableService;
-import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import java.util.*;
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileService.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileService.java
index 9b30e482..a6c3ac8d 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileService.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileService.java
@@ -18,7 +18,6 @@ import net.lab1024.sa.base.module.support.file.domain.form.FileQueryForm;
import net.lab1024.sa.base.module.support.file.domain.vo.FileDownloadVO;
import net.lab1024.sa.base.module.support.file.domain.vo.FileUploadVO;
import net.lab1024.sa.base.module.support.file.domain.vo.FileVO;
-import net.lab1024.sa.base.module.support.redis.RedisService;
import net.lab1024.sa.base.module.support.securityprotect.service.SecurityFileService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@@ -55,9 +54,6 @@ public class FileService {
@Resource
private FileDao fileDao;
- @Resource
- private RedisService redisService;
-
@Resource
private SecurityFileService securityFileService;
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileStorageCloudServiceImpl.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileStorageCloudServiceImpl.java
index 008c9fa3..0493a4db 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileStorageCloudServiceImpl.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileStorageCloudServiceImpl.java
@@ -2,10 +2,7 @@ package net.lab1024.sa.base.module.support.file.service;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
-import com.amazonaws.services.s3.AmazonS3;
-import com.amazonaws.services.s3.model.CannedAccessControlList;
-import com.amazonaws.services.s3.model.ObjectMetadata;
-import com.amazonaws.services.s3.model.S3Object;
+import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.base.common.code.SystemErrorCode;
import net.lab1024.sa.base.common.domain.ResponseDTO;
@@ -21,22 +18,29 @@ import net.lab1024.sa.base.module.support.file.domain.vo.FileVO;
import net.lab1024.sa.base.module.support.redis.RedisService;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
-import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
+import software.amazon.awssdk.core.ResponseBytes;
+import software.amazon.awssdk.core.sync.RequestBody;
+import software.amazon.awssdk.core.sync.ResponseTransformer;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.services.s3.model.*;
+import software.amazon.awssdk.services.s3.presigner.S3Presigner;
+import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
+import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
-import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
+import java.time.Duration;
import java.time.LocalDateTime;
-import java.util.Date;
import java.util.HashMap;
import java.util.Map;
-import java.util.UUID;
/**
* 云计算 实现
@@ -45,7 +49,7 @@ import java.util.UUID;
* @Date 2019年10月11日 15:34:47
* @Wechat zhuoda1024
* @Email lab1024@163.com
- * @Copyright 1024创新实验室
+ * @Copyright 1024创新实验室
*/
@Slf4j
public class FileStorageCloudServiceImpl implements IFileStorageService {
@@ -66,7 +70,7 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
private static final String USER_METADATA_FILE_SIZE = "file-size";
@Resource
- private AmazonS3 amazonS3;
+ private S3Client s3Client;
@Resource
private FileConfig cloudConfig;
@@ -86,44 +90,44 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
}
String fileType = FilenameUtils.getExtension(originalFileName);
- String uuid = UUID.randomUUID().toString().replaceAll("-", "");
+ String uuid = IdUtil.fastSimpleUUID();
String time = LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_FORMATTER);
- String fileKey = path + uuid + "_" + time+ "." + fileType;
+ String fileKey = path + uuid + "_" + time + "." + fileType;
// 文件名称 URL 编码
String urlEncoderFilename;
try {
- urlEncoderFilename = URLEncoder.encode(originalFileName, StandardCharsets.UTF_8.name());
+ urlEncoderFilename = URLEncoder.encode(originalFileName, "utf-8");
} catch (UnsupportedEncodingException e) {
- log.error("文件上传服务URL ENCODE-发生异常:", e);
- return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, "上传失败");
+ throw new RuntimeException(e);
}
- ObjectMetadata meta = new ObjectMetadata();
- meta.setContentEncoding(StandardCharsets.UTF_8.name());
- meta.setContentDisposition("attachment;filename=" + urlEncoderFilename);
Map userMetadata = new HashMap<>(10);
userMetadata.put(USER_METADATA_FILE_NAME, urlEncoderFilename);
userMetadata.put(USER_METADATA_FILE_FORMAT, fileType);
userMetadata.put(USER_METADATA_FILE_SIZE, String.valueOf(file.getSize()));
- meta.setUserMetadata(userMetadata);
- meta.setContentLength(file.getSize());
- meta.setContentType(this.getContentType(fileType));
+
+ PutObjectRequest putObjectRequest = PutObjectRequest.builder().bucket(cloudConfig.getBucketName()).key(fileKey).metadata(userMetadata).contentLength(file.getSize()).contentType(this.getContentType(fileType)).contentEncoding(StandardCharsets.UTF_8.name()).contentDisposition("attachment;filename=" + urlEncoderFilename).build();
+ InputStream inputStream = null;
try {
- amazonS3.putObject(cloudConfig.getBucketName(), fileKey, file.getInputStream(), meta);
+ inputStream = file.getInputStream();
+ s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(inputStream, file.getSize()));
} catch (IOException e) {
log.error("文件上传-发生异常:", e);
return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, "上传失败");
+ } finally {
+ IOUtils.closeQuietly(inputStream);
}
// 根据文件路径获取并设置访问权限
- CannedAccessControlList acl = this.getACL(path);
- amazonS3.setObjectAcl(cloudConfig.getBucketName(), fileKey, acl);
+ ObjectCannedACL acl = this.getACL(path);
+ PutObjectAclRequest aclRequest = PutObjectAclRequest.builder().bucket(cloudConfig.getBucketName()).key(fileKey).acl(this.getACL(path)).build();
+ s3Client.putObjectAcl(aclRequest);
// 返回上传结果
FileUploadVO uploadVO = new FileUploadVO();
uploadVO.setFileName(originalFileName);
uploadVO.setFileType(fileType);
// 根据 访问权限 返回不同的 URL
String url = cloudConfig.getUrlPrefix() + fileKey;
- if (CannedAccessControlList.Private.equals(acl)) {
+ if (ObjectCannedACL.PRIVATE.equals(acl)) {
// 获取临时访问的URL
url = this.getFileUrl(fileKey).getData();
}
@@ -136,8 +140,8 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
/**
* 获取文件url
*
- * @param fileKey
- * @return
+ * @param fileKey 文件key
+ * @return url
*/
@Override
public ResponseDTO getFileUrl(String fileKey) {
@@ -159,10 +163,14 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
if (fileVO == null) {
return ResponseDTO.userErrorParam("文件不存在");
}
+ GetObjectRequest getUrlRequest = GetObjectRequest.builder().bucket(cloudConfig.getBucketName()).key(fileKey).build();
+ GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder().signatureDuration(Duration.ofSeconds(cloudConfig.getPrivateUrlExpireSeconds())).getObjectRequest(getUrlRequest).build();
- Date expiration = new Date(System.currentTimeMillis() + cloudConfig.getPrivateUrlExpireSeconds() * 1000L);
- URL url = amazonS3.generatePresignedUrl(cloudConfig.getBucketName(), fileKey, expiration);
- fileVO.setFileUrl(url.toString());
+ S3Presigner presigner = S3Presigner.builder().region(Region.of(cloudConfig.getRegion())).build();
+
+ PresignedGetObjectRequest presignedGetObjectRequest = presigner.presignGetObject(getObjectPresignRequest);
+ String url = presignedGetObjectRequest.url().toString();
+ fileVO.setFileUrl(url);
redisService.set(fileRedisKey, fileVO, cloudConfig.getPrivateUrlExpireSeconds() - 5);
}
@@ -175,11 +183,11 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
*/
@Override
public ResponseDTO download(String key) {
- //获取oss对象
- S3Object s3Object = amazonS3.getObject(cloudConfig.getBucketName(), key);
+
// 获取文件 meta
- ObjectMetadata metadata = s3Object.getObjectMetadata();
- Map userMetadata = metadata.getUserMetadata();
+ HeadObjectRequest objectRequest = HeadObjectRequest.builder().bucket(this.cloudConfig.getBucketName()).key(key).build();
+ HeadObjectResponse headObjectResponse = s3Client.headObject(objectRequest);
+ Map userMetadata = headObjectResponse.metadata();
FileMetadataVO metadataDTO = null;
if (MapUtils.isNotEmpty(userMetadata)) {
metadataDTO = new FileMetadataVO();
@@ -190,43 +198,31 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
metadataDTO.setFileSize(fileSize);
}
- // 获得输入流
- InputStream objectContent = s3Object.getObjectContent();
- try {
- // 输入流转换为字节流
- byte[] buffer = FileCopyUtils.copyToByteArray(objectContent);
+ //获取oss对象
+ GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(cloudConfig.getBucketName()).key(key).build();
+ ResponseBytes s3ClientObject = s3Client.getObject(getObjectRequest, ResponseTransformer.toBytes());
- FileDownloadVO fileDownloadVO = new FileDownloadVO();
- fileDownloadVO.setData(buffer);
- fileDownloadVO.setMetadata(metadataDTO);
- return ResponseDTO.ok(fileDownloadVO);
- } catch (IOException e) {
- log.error("文件下载-发生异常:", e);
- return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, "下载失败");
- } finally {
- try {
- // 关闭输入流
- objectContent.close();
- s3Object.close();
- } catch (IOException e) {
- log.error("文件下载-发生异常:", e);
- }
- }
+ // 输入流转换为字节流
+ byte[] buffer = s3ClientObject.asByteArray();
+ FileDownloadVO fileDownloadVO = new FileDownloadVO();
+ fileDownloadVO.setData(buffer);
+ fileDownloadVO.setMetadata(metadataDTO);
+ return ResponseDTO.ok(fileDownloadVO);
}
/**
* 根据文件夹路径 返回对应的访问权限
*
- * @param fileKey
- * @return
+ * @param fileKey 文件key
+ * @return 权限
*/
- private CannedAccessControlList getACL(String fileKey) {
+ private ObjectCannedACL getACL(String fileKey) {
// 公用读
if (fileKey.contains(FileFolderTypeEnum.FOLDER_PUBLIC)) {
- return CannedAccessControlList.PublicRead;
+ return ObjectCannedACL.PUBLIC_READ;
}
// 其他默认私有读写
- return CannedAccessControlList.Private;
+ return ObjectCannedACL.PRIVATE;
}
/**
@@ -235,11 +231,11 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
* ps:不能删除fileKey不为空的文件夹
*
* @param fileKey 文件or文件夹
- * @return
*/
@Override
public ResponseDTO delete(String fileKey) {
- amazonS3.deleteObject(cloudConfig.getBucketName(), fileKey);
+ DeleteObjectRequest deleteObjectRequest = DeleteObjectRequest.builder().bucket(cloudConfig.getBucketName()).key(fileKey).build();
+ s3Client.deleteObject(deleteObjectRequest);
return ResponseDTO.ok();
}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileStorageLocalServiceImpl.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileStorageLocalServiceImpl.java
index 45f21420..c75ce0bc 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileStorageLocalServiceImpl.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/file/service/FileStorageLocalServiceImpl.java
@@ -19,7 +19,6 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/helpdoc/service/HelpDocService.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/helpdoc/service/HelpDocService.java
index f8861ad5..856bada9 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/helpdoc/service/HelpDocService.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/helpdoc/service/HelpDocService.java
@@ -13,7 +13,6 @@ import net.lab1024.sa.base.module.support.helpdoc.domain.form.HelpDocUpdateForm;
import net.lab1024.sa.base.module.support.helpdoc.domain.vo.HelpDocDetailVO;
import net.lab1024.sa.base.module.support.helpdoc.domain.vo.HelpDocVO;
import net.lab1024.sa.base.module.support.helpdoc.manager.HelpDocManager;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/mail/MailService.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/mail/MailService.java
index 84adc038..ada8f544 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/mail/MailService.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/mail/MailService.java
@@ -1,7 +1,7 @@
package net.lab1024.sa.base.module.support.mail;
-import cn.hutool.core.lang.UUID;
+import cn.hutool.core.util.IdUtil;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
@@ -16,7 +16,6 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringSubstitutor;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
@@ -163,7 +162,7 @@ public class MailService {
private String freemarkerResolverContent(String htmlTemplate, Map templateParamsMap) {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);
StringTemplateLoader stringLoader = new StringTemplateLoader();
- String templateName = UUID.fastUUID().toString(true);
+ String templateName = IdUtil.fastSimpleUUID();
stringLoader.putTemplate(templateName, htmlTemplate);
configuration.setTemplateLoader(stringLoader);
try {
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/RepeatSubmitAspect.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/RepeatSubmitAspect.java
index 723ecd7e..2ad0a7b6 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/RepeatSubmitAspect.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/RepeatSubmitAspect.java
@@ -13,13 +13,23 @@ import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
+import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
/**
- * 重复提交 aop切口
+ * 重复提交 aop切口
+ * -------------------------
+ * 着重说明:
+ * 注解属性 intervalMilliSecond 是指 一段时间内只允许有一次请求;
+ * intervalMilliSecond = 0: 表示只有上个请求执行完以后才可以执行
+ * intervalMilliSecond > 0: 表示指定时间内只才能执行,特别提醒
+ * ------------------------
+ * 特殊说明 intervalMilliSecond > 0
+ * 若假设 方法执行时间为 100ms,若 intervalMilliSecond = 50,则 同一时间内可能会有2个请求同时在执行!
+ * 若假设 方法执行时间为 100ms,若 intervalMilliSecond = 200,则 同一时间内只能有1请求执行,且执行完后100ms,才会执行下一次请求
*
- * @Author 1024创新实验室: 胡克
- * @Date 2020-11-25 20:56:58
+ * @Author 1024创新实验室-主任: 卓大
+ * @Date 2025-07-26 23:56:58
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室
@@ -43,36 +53,46 @@ public class RepeatSubmitAspect {
@Around("@annotation(net.lab1024.sa.base.module.support.repeatsubmit.annoation.RepeatSubmit)")
public Object around(ProceedingJoinPoint point) throws Throwable {
+
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
- String ticketToken = attributes.getRequest().getServletPath();
- String ticket = this.repeatSubmitTicket.getTicket(ticketToken);
+ if (attributes == null) {
+ return point.proceed();
+ }
+
+ /**
+ * 第一步:生成防重复提交的 ticket凭证
+ * ticket 是根据 Request对象 自定义 生成的,可以加入请求user相关属性作为生成要素
+ */
+
+ HttpServletRequest request = attributes.getRequest();
+ String ticket = this.repeatSubmitTicket.generateTicket(request);
if (StringUtils.isEmpty(ticket)) {
return point.proceed();
}
Method method = ((MethodSignature) point.getSignature()).getMethod();
RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
- int limit = annotation.value();
+ Long intervalMilliSecond = (long) annotation.intervalMilliSecond();
- // 获取上一次请求时间
- Long lastRequestTime = this.repeatSubmitTicket.getTicketTimestamp(ticket);
- // 校验是否限制时间内重复提交
- if (lastRequestTime != null && System.currentTimeMillis() < lastRequestTime + limit) {
+ /**
+ * 第二步:根据 ticket 凭证进行 加锁
+ * 能加锁,则可以执行
+ * 若不能加锁,则证明还是时间间隔interval中
+ */
+
+ boolean lockSuccessFlag = this.repeatSubmitTicket.tryLock(ticket, System.currentTimeMillis(), intervalMilliSecond);
+ if (!lockSuccessFlag) {
return ResponseDTO.error(UserErrorCode.REPEAT_SUBMIT);
}
- // 执行
- Object obj = null;
try {
- // 给 ticket 设置在执行中
- this.repeatSubmitTicket.putTicket(ticket);
- // 执行
- obj = point.proceed();
+ return point.proceed();
} catch (Throwable throwable) {
- log.error("", throwable);
+ log.error(throwable.getMessage(), throwable);
throw throwable;
+ } finally {
+ this.repeatSubmitTicket.unLock(ticket, intervalMilliSecond);
}
- return obj;
}
}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/annoation/RepeatSubmit.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/annoation/RepeatSubmit.java
index 371f7b95..18bec0c3 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/annoation/RepeatSubmit.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/annoation/RepeatSubmit.java
@@ -7,10 +7,19 @@ import java.lang.annotation.Target;
/**
* 标记 需要防止重复提交 的注解
- * 单位:毫秒
+ * 单位:毫秒
+ * -------------------------
+ * 着重说明:
+ * 注解属性 intervalMilliSecond 是指 一段时间内只允许有一次请求;
+ * intervalMilliSecond = 0: 表示只有上个请求执行完以后才可以执行
+ * intervalMilliSecond > 0: 表示指定时间内只才能执行,特别提醒
+ * ------------------------
+ * 特殊说明 intervalMilliSecond > 0
+ * 若假设 方法执行时间为 100ms,若 intervalMilliSecond = 50,则 同一时间内可能会有2个请求同时在执行!
+ * 若假设 方法执行时间为 100ms,若 intervalMilliSecond = 200,则 同一时间内只能有1请求执行,且执行完后100ms,才会执行下一次请求
*
- * @Author 1024创新实验室: 胡克
- * @Date 2020-11-25 20:56:58
+ * @Author 1024创新实验室-主任: 卓大
+ * @Date 2025-07-26 20:56:58
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室
@@ -20,8 +29,8 @@ import java.lang.annotation.Target;
public @interface RepeatSubmit {
/**
- * 重复提交间隔时间/毫秒
+ * 间隔时间/毫秒
*/
- int value() default 300;
+ int intervalMilliSecond() default 0;
}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/AbstractRepeatSubmitTicket.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/AbstractRepeatSubmitTicket.java
index bc2f8e60..845ab0a2 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/AbstractRepeatSubmitTicket.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/AbstractRepeatSubmitTicket.java
@@ -1,42 +1,42 @@
package net.lab1024.sa.base.module.support.repeatsubmit.ticket;
+import javax.servlet.http.HttpServletRequest;
import java.util.function.Function;
/**
* 凭证(用于校验重复提交的东西)
*
- * @Author 1024创新实验室: 罗伊
- * @Date 2020-11-25 20:56:58
+ * @Author 1024创新实验室-主任: 卓大
+ * @Date 2025-07-26 23:56:58
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室
*/
public abstract class AbstractRepeatSubmitTicket {
- private final Function ticketFunction;
+ private final Function generateTicketFunction;
- public AbstractRepeatSubmitTicket(Function ticketFunction) {
- this.ticketFunction = ticketFunction;
+ public AbstractRepeatSubmitTicket(Function generateTicketFunction) {
+ this.generateTicketFunction = generateTicketFunction;
}
/**
- * 获取凭证
+ * 生成 加锁的 凭证
*/
- public String getTicket(String ticketToken) {
- return this.ticketFunction.apply(ticketToken);
+ public String generateTicket(HttpServletRequest request) {
+ return this.generateTicketFunction.apply(request);
}
/**
- * 获取凭证 时间戳
+ * 加锁
*/
- public abstract Long getTicketTimestamp(String ticket);
-
+ public abstract boolean tryLock(String ticket, Long currentTimestamp, Long intervalMilliSecond);
/**
- * 设置本次请求时间
+ * 移除锁
*/
- public abstract void putTicket(String ticket);
+ public abstract void unLock(String ticket, Long intervalMilliSecond);
}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitCaffeineTicket.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitCaffeineTicket.java
deleted file mode 100644
index c18cc038..00000000
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitCaffeineTicket.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package net.lab1024.sa.base.module.support.repeatsubmit.ticket;
-
-import com.github.benmanes.caffeine.cache.Cache;
-import com.github.benmanes.caffeine.cache.Caffeine;
-
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-
-/**
- * 凭证(内存实现)
- *
- * @Author 1024创新实验室: 罗伊
- * @Date 2020-11-25 20:56:58
- * @Wechat zhuoda1024
- * @Email lab1024@163.com
- * @Copyright 1024创新实验室
- */
-public class RepeatSubmitCaffeineTicket extends AbstractRepeatSubmitTicket {
-
- /**
- * 限制缓存最大数量 超过后先放入的会自动移除
- * 默认缓存时间
- * 初始大小为:100万
- */
- private static final Cache cache = Caffeine.newBuilder()
- .maximumSize(100 * 10000)
- .expireAfterWrite(300 * 1000L, TimeUnit.MILLISECONDS).build();
-
-
- public RepeatSubmitCaffeineTicket(Function ticketFunction) {
- super(ticketFunction);
- }
-
- @Override
- public Long getTicketTimestamp(String ticket) {
- return cache.getIfPresent(ticket);
- }
-
-
- @Override
- public void putTicket(String ticket) {
- cache.put(ticket, System.currentTimeMillis());
- }
-}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitMemoryTicket.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitMemoryTicket.java
new file mode 100644
index 00000000..376ca937
--- /dev/null
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitMemoryTicket.java
@@ -0,0 +1,60 @@
+package net.lab1024.sa.base.module.support.repeatsubmit.ticket;
+
+import com.google.common.collect.Interner;
+import com.google.common.collect.Interners;
+import com.google.common.collect.Maps;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.Function;
+
+/**
+ * 凭证(内存实现)
+ *
+ * @Author 1024创新实验室-主任: 卓大
+ * @Date 2025-07-26 23:56:58
+ * @Wechat zhuoda1024
+ * @Email lab1024@163.com
+ * @Copyright 1024创新实验室
+ */
+public class RepeatSubmitMemoryTicket extends AbstractRepeatSubmitTicket {
+
+ private Interner pool = Interners.newStrongInterner();
+
+ private ConcurrentMap ticketMap = Maps.newConcurrentMap();
+
+ public RepeatSubmitMemoryTicket(Function ticketFunction) {
+ super(ticketFunction);
+ }
+
+ @Override
+ public boolean tryLock(String ticket, Long currentTimestamp, Long intervalMilliSecond) {
+ synchronized (pool.intern(ticket)) {
+ Long lastTime = ticketMap.putIfAbsent(ticket, currentTimestamp);
+ if (lastTime == null) {
+ return true;
+ }
+
+ if (intervalMilliSecond <= 0) {
+ return false;
+ }
+
+ if (currentTimestamp - lastTime < intervalMilliSecond) {
+ return false;
+
+ }
+ ticketMap.put(ticket, currentTimestamp);
+ return true;
+ }
+ }
+
+ @Override
+ public void unLock(String ticket, Long intervalMilliSecond) {
+ if (intervalMilliSecond > 0) {
+ return;
+ }
+ ticketMap.remove(ticket);
+ }
+
+
+}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitRedisTicket.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitRedisTicket.java
index f940fdbb..6bb86e4c 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitRedisTicket.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitRedisTicket.java
@@ -1,38 +1,47 @@
package net.lab1024.sa.base.module.support.repeatsubmit.ticket;
-import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import javax.servlet.http.HttpServletRequest;
+import java.util.concurrent.TimeUnit;
import java.util.function.Function;
/**
* 凭证(redis实现)
*
- * @Author 1024创新实验室: 罗伊
- * @Date 2020-11-25 20:56:58
+ * @Author 1024创新实验室-主任: 卓大
+ * @Date 2025-07-26 23:56:58
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室
*/
public class RepeatSubmitRedisTicket extends AbstractRepeatSubmitTicket {
- private final ValueOperations redisValueOperations;
+ private final RedisTemplate redisTemplate;
- public RepeatSubmitRedisTicket(ValueOperations redisValueOperations,
- Function ticketFunction) {
+ public RepeatSubmitRedisTicket(RedisTemplate redisTemplate,
+ Function ticketFunction) {
super(ticketFunction);
- this.redisValueOperations = redisValueOperations;
+ this.redisTemplate = redisTemplate;
}
@Override
- public Long getTicketTimestamp(String ticket) {
- String ticketLastTime = redisValueOperations.get(ticket);
- return ticketLastTime == null ? null : Long.valueOf(ticketLastTime);
+ public boolean tryLock(String ticket, Long currentTimestamp, Long intervalMilliSecond) {
+ if (intervalMilliSecond > 0) {
+ return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(ticket, String.valueOf(currentTimestamp), intervalMilliSecond, TimeUnit.MILLISECONDS));
+ } else {
+ return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(ticket, String.valueOf(currentTimestamp)));
+ }
}
@Override
- public void putTicket(String ticket) {
- redisValueOperations.getOperations().delete(ticket);
- this.getTicketTimestamp(ticket);
+ public void unLock(String ticket, Long intervalMilliSecond) {
+ if (intervalMilliSecond > 0) {
+ return;
+ }
+
+ redisTemplate.delete(ticket);
}
+
}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/securityprotect/service/SecurityFileService.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/securityprotect/service/SecurityFileService.java
index e49bee98..3d17fa1a 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/securityprotect/service/SecurityFileService.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/securityprotect/service/SecurityFileService.java
@@ -2,6 +2,7 @@ package net.lab1024.sa.base.module.support.securityprotect.service;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.base.common.domain.ResponseDTO;
+import org.apache.commons.io.IOUtils;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.exception.TikaException;
import org.apache.tika.io.TikaInputStream;
@@ -14,6 +15,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
+import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
@@ -35,27 +37,9 @@ public class SecurityFileService {
private Level3ProtectConfigService level3ProtectConfigService;
// 定义白名单MIME类型
- private static final List ALLOWED_MIME_TYPES = Arrays.asList(
- "application/json",
- "application/zip",
- "application/x-7z-compressed",
- "application/pdf",
- "application/vnd.ms-excel",
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- "application/vnd.ms-powerpoint",
- "application/vnd.openxmlformats-officedocument.presentationml.presentation",
- "application/msword",
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- "application/vnd.ms-works",
- "text/csv",
- "audio/*",
- "video/*",
+ private static final List ALLOWED_MIME_TYPES = Arrays.asList("application/json", "application/zip", "application/x-7z-compressed", "application/pdf", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.ms-works", "text/csv", "audio/*", "video/*",
// 图片类型 svg有安全隐患,所以不使用"image/*"
- "image/jpeg",
- "image/png",
- "image/gif",
- "image/bmp"
- );
+ "image/jpeg", "image/png", "image/gif", "image/bmp");
/**
* 检测文件安全类型
@@ -73,8 +57,7 @@ public class SecurityFileService {
// 文件类型安全检测
if (level3ProtectConfigService.isFileDetectFlag()) {
String fileType = getFileMimeType(file);
- if (ALLOWED_MIME_TYPES.stream()
- .noneMatch(allowedType -> matchesMimeType(fileType, allowedType))) {
+ if (ALLOWED_MIME_TYPES.stream().noneMatch(allowedType -> matchesMimeType(fileType, allowedType))) {
return ResponseDTO.userErrorParam("禁止上传此文件类型");
}
}
@@ -89,16 +72,20 @@ public class SecurityFileService {
* @return 文件的 MIME 类型
*/
public static String getFileMimeType(MultipartFile file) {
+ InputStream inputStream = null;
try {
+ inputStream = file.getInputStream();
TikaConfig tika = new TikaConfig();
Metadata metadata = new Metadata();
metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, file.getOriginalFilename());
- TikaInputStream stream = TikaInputStream.get(file.getInputStream());
+ TikaInputStream stream = TikaInputStream.get(inputStream);
MediaType mimetype = tika.getDetector().detect(stream, metadata);
return mimetype.toString();
} catch (IOException | TikaException e) {
log.error(e.getMessage(), e);
return MimeTypes.OCTET_STREAM;
+ } finally {
+ IOUtils.closeQuietly(inputStream);
}
}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/SerialNumberBaseService.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/SerialNumberBaseService.java
index 95f7ed32..acbfba6d 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/SerialNumberBaseService.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/SerialNumberBaseService.java
@@ -27,7 +27,7 @@ import java.util.concurrent.ConcurrentHashMap;
* @Date 2022-03-25 21:46:07
* @Wechat zhuoda1024
* @Email lab1024@163.com
- * @Copyright 1024创新实验室
+ * @Copyright 1024创新实验室
*/
public abstract class SerialNumberBaseService implements SerialNumberService {
@@ -37,7 +37,7 @@ public abstract class SerialNumberBaseService implements SerialNumberService {
@Resource
protected SerialNumberDao serialNumberDao;
- private ConcurrentHashMap serialNumberMap = new ConcurrentHashMap<>();
+ protected ConcurrentHashMap serialNumberMap = new ConcurrentHashMap<>();
public abstract List generateSerialNumberList(SerialNumberInfoBO serialNumber, int count);
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/impl/SerialNumberRedisService.java b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/impl/SerialNumberRedisService.java
index 6bf65f77..3f788953 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/impl/SerialNumberRedisService.java
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/serialnumber/service/impl/SerialNumberRedisService.java
@@ -1,23 +1,34 @@
package net.lab1024.sa.base.module.support.serialnumber.service.impl;
+import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.base.common.exception.BusinessException;
+import net.lab1024.sa.base.common.util.SmartDateFormatterEnum;
+import net.lab1024.sa.base.common.util.SmartEnumUtil;
+import net.lab1024.sa.base.common.util.SmartLocalDateUtil;
+import net.lab1024.sa.base.common.util.SmartStringUtil;
import net.lab1024.sa.base.constant.RedisKeyConst;
import net.lab1024.sa.base.module.support.redis.RedisService;
+import net.lab1024.sa.base.module.support.serialnumber.constant.SerialNumberRuleTypeEnum;
import net.lab1024.sa.base.module.support.serialnumber.domain.SerialNumberEntity;
import net.lab1024.sa.base.module.support.serialnumber.domain.SerialNumberGenerateResultBO;
import net.lab1024.sa.base.module.support.serialnumber.domain.SerialNumberInfoBO;
-import net.lab1024.sa.base.module.support.serialnumber.domain.SerialNumberLastGenerateBO;
import net.lab1024.sa.base.module.support.serialnumber.service.SerialNumberBaseService;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.Resource;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
- * 单据序列号 基于redis锁实现
+ * 单据序列号 基于redis key-value increase 实现
*
* @Author 1024创新实验室-主任: 卓大
- * @Date 2022-03-25 21:46:07
+ * @Date 2025-08-03 22:46:07
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室
@@ -25,86 +36,125 @@ import java.util.List;
@Slf4j
public class SerialNumberRedisService extends SerialNumberBaseService {
- private static final int MAX_GET_LOCK_COUNT = 5;
-
- private static final long SLEEP_MILLISECONDS = 200L;
-
@Resource
private RedisService redisService;
+ @Resource
+ private RedisTemplate redisTemplate;
+
@Override
public void initLastGenerateData(List serialNumberEntityList) {
if (serialNumberEntityList == null) {
return;
}
- //删除之前的
- redisService.delete(RedisKeyConst.Support.SERIAL_NUMBER_LAST_INFO);
-
+ // 设置redis的上次值
for (SerialNumberEntity serialNumberEntity : serialNumberEntityList) {
- SerialNumberLastGenerateBO lastGenerateBO = SerialNumberLastGenerateBO
- .builder()
- .serialNumberId(serialNumberEntity.getSerialNumberId())
- .lastNumber(serialNumberEntity.getLastNumber())
- .lastTime(serialNumberEntity.getLastTime())
- .build();
+ if (serialNumberEntity.getLastTime() == null) {
+ continue;
+ }
- redisService.mset(RedisKeyConst.Support.SERIAL_NUMBER_LAST_INFO,
- String.valueOf(serialNumberEntity.getSerialNumberId()),
- lastGenerateBO
- );
+ String redisKey = generateRedisKeyByDate(serialNumberEntity.getSerialNumberId(),
+ SmartEnumUtil.getEnumByName(serialNumberEntity.getRuleType().toUpperCase(), SerialNumberRuleTypeEnum.class),
+ serialNumberEntity.getLastTime().toLocalDate());
+
+ Object o = redisTemplate.opsForValue().get(redisKey);
+ if (o == null) {
+ redisTemplate.opsForValue().set(redisKey, serialNumberEntity.getLastNumber());
+ }
+ }
+ }
+
+ /**
+ * 每天凌晨一点进行检测;
+ * 检测单位数量为3; 3天前、3月前、3年前
+ */
+ @Scheduled(cron = "0 0 1 * * ?")
+ public void tryDeleteUnusedRedisKey() {
+ for (SerialNumberInfoBO serialNumberInfoBO : serialNumberMap.values()) {
+ SerialNumberRuleTypeEnum typeEnum = serialNumberInfoBO.getSerialNumberRuleTypeEnum();
+ String dateStr = "";
+ switch (typeEnum) {
+ case DAY:
+ dateStr = SmartLocalDateUtil.format(LocalDate.now().minusDays(3), SmartDateFormatterEnum.YMD);
+ case MONTH:
+ dateStr = SmartLocalDateUtil.format(LocalDate.now().minusMonths(3), SmartDateFormatterEnum.YM);
+ case YEAR:
+ dateStr = String.valueOf(LocalDate.now().minusYears(3));
+ }
+ if (SmartStringUtil.isNotEmpty(dateStr)) {
+ String redisKey = RedisKeyConst.Support.SERIAL_NUMBER + serialNumberInfoBO.getSerialNumberId() + ":" + dateStr;
+ redisService.delete(redisKey);
+ }
}
}
@Override
public List generateSerialNumberList(SerialNumberInfoBO serialNumberInfo, int count) {
- SerialNumberGenerateResultBO serialNumberGenerateResult = null;
- String lockKey = RedisKeyConst.Support.SERIAL_NUMBER + serialNumberInfo.getSerialNumberId();
-
- boolean lock = false;
- for (int i = 0; i < MAX_GET_LOCK_COUNT; i++) {
- try {
- lock = redisService.getLock(lockKey, 60 * 1000L);
- if (lock) {
- break;
- }
- Thread.sleep(SLEEP_MILLISECONDS);
- } catch (Throwable e) {
- log.error(e.getMessage(), e);
+ // 根据步长,计算 redis 增加值
+ ArrayList list = new ArrayList<>(count);
+ int redisIncrease = 0;
+ for (int i = 0; i < count; i++) {
+ int stepIncrease = 1;
+ Integer stepRandomRange = serialNumberInfo.getStepRandomRange();
+ if (stepRandomRange > 1) {
+ stepIncrease = RandomUtil.getSecureRandom().nextInt(serialNumberInfo.getStepRandomRange()) + 1;
}
+ redisIncrease += stepIncrease;
+ list.add(stepIncrease);
}
- if (!lock) {
- throw new BusinessException("SerialNumber 尝试5次,未能生成单号");
- }
-
try {
- // 获取上次的生成结果
- SerialNumberLastGenerateBO lastGenerateBO = (SerialNumberLastGenerateBO) redisService.mget(
- RedisKeyConst.Support.SERIAL_NUMBER_LAST_INFO,
- String.valueOf(serialNumberInfo.getSerialNumberId()));
+ String redisKey = generateRedisKeyByDate(serialNumberInfo.getSerialNumberId(), serialNumberInfo.getSerialNumberRuleTypeEnum(), LocalDate.now());
+ Long increaseResult = redisTemplate.opsForValue().increment(redisKey, redisIncrease);
+
+ ArrayList numberList = new ArrayList<>(count);
+ Long number = increaseResult;
+ for (Integer i : list) {
+ number = number - i;
+ numberList.add((number + 1));
+ }
+
+ Collections.reverse(numberList);
+
+ SerialNumberGenerateResultBO serialNumberGenerateResult = SerialNumberGenerateResultBO
+ .builder()
+ .serialNumberId(serialNumberInfo.getSerialNumberId())
+ .lastNumber(increaseResult)
+ .lastTime(LocalDateTime.now())
+ .numberList(numberList)
+ .isReset(false)
+ .build();
- // 生成
- serialNumberGenerateResult = super.loopNumberList(lastGenerateBO, serialNumberInfo, count);
// 将生成信息保存的内存和数据库
- lastGenerateBO.setLastNumber(serialNumberGenerateResult.getLastNumber());
- lastGenerateBO.setLastTime(serialNumberGenerateResult.getLastTime());
serialNumberDao.updateLastNumberAndTime(serialNumberInfo.getSerialNumberId(),
serialNumberGenerateResult.getLastNumber(),
serialNumberGenerateResult.getLastTime());
- redisService.mset(RedisKeyConst.Support.SERIAL_NUMBER_LAST_INFO,
- String.valueOf(serialNumberInfo.getSerialNumberId()), lastGenerateBO);
-
// 把生成过程保存到数据库里
super.saveRecord(serialNumberGenerateResult);
+ return formatNumberList(serialNumberGenerateResult, serialNumberInfo);
} catch (Throwable e) {
log.error(e.getMessage(), e);
throw e;
- } finally {
- redisService.unLock(lockKey);
}
+ }
- return formatNumberList(serialNumberGenerateResult, serialNumberInfo);
+ private String generateRedisKeyByDate(Integer serialNumberId, SerialNumberRuleTypeEnum serialNumberRuleTypeEnum, LocalDate localDate) {
+ switch (serialNumberRuleTypeEnum) {
+ case DAY:
+ String dayStr = SmartLocalDateUtil.format(localDate, SmartDateFormatterEnum.YMD);
+ return RedisKeyConst.Support.SERIAL_NUMBER + serialNumberId + ":" + dayStr;
+ case MONTH:
+ String monthStr = SmartLocalDateUtil.format(localDate, SmartDateFormatterEnum.YM);
+ return RedisKeyConst.Support.SERIAL_NUMBER + serialNumberId + ":" + monthStr;
+ case YEAR:
+ String yearStr = String.valueOf(localDate.getYear());
+ return RedisKeyConst.Support.SERIAL_NUMBER + serialNumberId + ":" + yearStr;
+ case NONE:
+ return RedisKeyConst.Support.SERIAL_NUMBER + serialNumberId;
+ default:
+ throw new BusinessException("serialNumberRuleTypeEnum not exist error");
+ }
}
}
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/resources/dev/sa-base.yaml b/smart-admin-api-java8-springboot2/sa-base/src/main/resources/dev/sa-base.yaml
index fbc5185e..4a70d9ea 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/resources/dev/sa-base.yaml
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/resources/dev/sa-base.yaml
@@ -64,10 +64,26 @@ spring:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
+ # 上传文件和请求大小
+ servlet:
+ multipart:
+ max-file-size: 20MB # 单个文件的最大大小
+ max-request-size: 10MB # 整个请求的最大大小
+
# 缓存实现类型
cache:
type: redis
+# 健康检查
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health,info
+ health:
+ mail:
+ enabled: false
+
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server:
tomcat:
@@ -109,7 +125,7 @@ knife4j:
username: api # Basic认证用户名
password: 1024 # Basic认证密码
-# RestTemplate 请求配置
+# RestTemplate 请求配置 毫秒
http:
pool:
max-total: 20
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/resources/pre/sa-base.yaml b/smart-admin-api-java8-springboot2/sa-base/src/main/resources/pre/sa-base.yaml
index ca25d856..7ba3d1e9 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/resources/pre/sa-base.yaml
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/resources/pre/sa-base.yaml
@@ -64,10 +64,26 @@ spring:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
+ # 上传文件和请求大小
+ servlet:
+ multipart:
+ max-file-size: 20MB # 单个文件的最大大小
+ max-request-size: 10MB # 整个请求的最大大小
+
# 缓存实现类型
cache:
type: redis
+# 健康检查
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health,info
+ health:
+ mail:
+ enabled: false
+
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server:
tomcat:
@@ -109,7 +125,7 @@ knife4j:
username: api # Basic认证用户名
password: 1024 # Basic认证密码
-# RestTemplate 请求配置
+# RestTemplate 请求配置 毫秒
http:
pool:
max-total: 20
@@ -133,7 +149,7 @@ reload:
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: Authorization
- # token 前缀 例如:Bear
+ # token 前缀 例如:Bearer
token-prefix: Bearer
# token 有效期(单位:秒) 默认30天(2592000秒),-1 代表永久有效
timeout: 2592000
@@ -167,4 +183,4 @@ smart:
# 数据库配置检测-开关 默认开启 可选(作用是固定间隔读取数据库配置更新任务,关闭后只能重启服务或通过接口修改定时任务,建议开启)
db-refresh-enabled: true
# 数据库配置检测-执行间隔 默认120秒 可选
- db-refresh-interval: 60
\ No newline at end of file
+ db-refresh-interval: 60
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/resources/prod/sa-base.yaml b/smart-admin-api-java8-springboot2/sa-base/src/main/resources/prod/sa-base.yaml
index d00ad41d..bd2ecb97 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/resources/prod/sa-base.yaml
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/resources/prod/sa-base.yaml
@@ -7,14 +7,14 @@ spring:
driver-class-name: com.mysql.cj.jdbc.Driver
initial-size: 10
min-idle: 10
- max-active: 100
+ max-active: 200
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
filters: stat
druid:
username: druid
- password: 1024lab
+ password: 1024
login:
enabled: false
method:
@@ -63,10 +63,26 @@ spring:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
+ # 上传文件和请求大小
+ servlet:
+ multipart:
+ max-file-size: 20MB # 单个文件的最大大小
+ max-request-size: 10MB # 整个请求的最大大小
+
# 缓存实现类型
cache:
type: redis
+# 健康检查
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health,info
+ health:
+ mail:
+ enabled: false
+
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server:
tomcat:
@@ -93,14 +109,13 @@ file:
url-prefix: https://${file.storage.cloud.bucket-name}.${file.storage.cloud.endpoint}/
private-url-expire-seconds: 3600
-
# open api配置
springdoc:
swagger-ui:
enabled: true # 开关
doc-expansion: none #关闭展开
tags-sorter: alpha
- server-base-url: https://preview.smartadmin.vip/smart-admin-api
+ server-base-url:
api-docs:
enabled: true # 开关
knife4j:
@@ -110,7 +125,7 @@ knife4j:
username: api # Basic认证用户名
password: 1024 # Basic认证密码
-# RestTemplate 请求配置
+# RestTemplate 请求配置 毫秒
http:
pool:
max-total: 100
@@ -131,7 +146,7 @@ reload:
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: Authorization
- # token 前缀 例如:Bear
+ # token 前缀 例如:Bearer
token-prefix: Bearer
# token 有效期(单位:秒) 默认30天(2592000秒),-1 代表永久有效
timeout: 2592000
diff --git a/smart-admin-api-java8-springboot2/sa-base/src/main/resources/test/sa-base.yaml b/smart-admin-api-java8-springboot2/sa-base/src/main/resources/test/sa-base.yaml
index ca25d856..7ba3d1e9 100644
--- a/smart-admin-api-java8-springboot2/sa-base/src/main/resources/test/sa-base.yaml
+++ b/smart-admin-api-java8-springboot2/sa-base/src/main/resources/test/sa-base.yaml
@@ -64,10 +64,26 @@ spring:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
+ # 上传文件和请求大小
+ servlet:
+ multipart:
+ max-file-size: 20MB # 单个文件的最大大小
+ max-request-size: 10MB # 整个请求的最大大小
+
# 缓存实现类型
cache:
type: redis
+# 健康检查
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health,info
+ health:
+ mail:
+ enabled: false
+
# tomcat 配置,主要用于 配置 访问日志(便于将来排查错误)
server:
tomcat:
@@ -109,7 +125,7 @@ knife4j:
username: api # Basic认证用户名
password: 1024 # Basic认证密码
-# RestTemplate 请求配置
+# RestTemplate 请求配置 毫秒
http:
pool:
max-total: 20
@@ -133,7 +149,7 @@ reload:
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: Authorization
- # token 前缀 例如:Bear
+ # token 前缀 例如:Bearer
token-prefix: Bearer
# token 有效期(单位:秒) 默认30天(2592000秒),-1 代表永久有效
timeout: 2592000
@@ -167,4 +183,4 @@ smart:
# 数据库配置检测-开关 默认开启 可选(作用是固定间隔读取数据库配置更新任务,关闭后只能重启服务或通过接口修改定时任务,建议开启)
db-refresh-enabled: true
# 数据库配置检测-执行间隔 默认120秒 可选
- db-refresh-interval: 60
\ No newline at end of file
+ db-refresh-interval: 60
diff --git a/smart-admin-web-javascript/src/App.vue b/smart-admin-web-javascript/src/App.vue
index cb5c9816..90baebfe 100644
--- a/smart-admin-web-javascript/src/App.vue
+++ b/smart-admin-web-javascript/src/App.vue
@@ -12,7 +12,7 @@
+
diff --git a/smart-admin-web-javascript/src/components/support/table-operator/index.vue b/smart-admin-web-javascript/src/components/support/table-operator/index.vue
index c2f67107..1aa3d364 100644
--- a/smart-admin-web-javascript/src/components/support/table-operator/index.vue
+++ b/smart-admin-web-javascript/src/components/support/table-operator/index.vue
@@ -74,13 +74,13 @@
watch(
() => props.modelValue,
(value) => {
- newColumn.forEach(item=>{
- value.forEach(itemNewColumns=>{
- if(item.dataIndex==itemNewColumns.dataIndex){
- Object.assign(item,itemNewColumns)
+ newColumn.forEach((item) => {
+ value.forEach((itemNewColumns) => {
+ if (item.dataIndex === itemNewColumns.dataIndex) {
+ Object.assign(item, itemNewColumns);
}
- })
- })
+ });
+ });
},
{
deep: true,
@@ -90,6 +90,7 @@
//构建用户的数据列
async function buildUserTableColumns() {
+
if (!props.tableId) {
return;
}
@@ -127,6 +128,7 @@
// 处理退出全屏
function handleExitFullScreen() {
+ document.querySelector('#smartAdminHeader').style.display = 'block';
fullScreenFlag.value = false;
useAppConfigStore().exitFullScreen();
document.removeEventListener('fullscreenchange', handleFullscreenChange);
@@ -137,6 +139,7 @@
//判断各种浏览器 -全屏
function launchElementFullScreen(element) {
+ document.querySelector('#smartAdminHeader').style.display = 'none';
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.mozRequestFullScreen) {
@@ -179,28 +182,29 @@
// ----------------- 弹窗 修改表格列 -------------------
const smartTableColumnModal = ref();
+
function showModal() {
smartTableColumnModal.value.show(newColumn, props.tableId);
}
// 将弹窗修改的列数据,赋值给原表格 列数组
function updateColumn(changeColumnArray) {
- let obj={}
+ let obj = {};
// 如果为空数组代表恢复默认,使用原始表格数据
//合并列
- if(_.isEmpty(changeColumnArray)){
+ if (_.isEmpty(changeColumnArray)) {
obj = mergeColumn(_.cloneDeep(originalColumn), changeColumnArray);
- }else{
+ } else {
obj = mergeColumn(_.cloneDeep(newColumn), changeColumnArray);
}
const newColumns = obj.newColumns;
- newColumn.forEach(item=>{
- obj.newColumns.forEach(itemNewColumns=>{
- if(item.dataIndex==itemNewColumns.dataIndex){
- Object.assign(item,itemNewColumns)
+ newColumn.forEach((item) => {
+ obj.newColumns.forEach((itemNewColumns) => {
+ if (item.dataIndex === itemNewColumns.dataIndex) {
+ Object.assign(item, itemNewColumns);
}
- })
- })
+ });
+ });
emit(
'update:modelValue',
newColumns.filter((e) => e.showFlag)
@@ -217,6 +221,6 @@
buildUserTableColumns();
}
},
- { immediate: true }
+ { immediate: false }
);
diff --git a/smart-admin-web-javascript/src/config/app-config.js b/smart-admin-web-javascript/src/config/app-config.js
index 89e852a3..d9dad8a1 100644
--- a/smart-admin-web-javascript/src/config/app-config.js
+++ b/smart-admin-web-javascript/src/config/app-config.js
@@ -16,6 +16,8 @@ export const appDefaultConfig = {
sideMenuWidth: 200,
//标签页位置
pageTagLocation: 'center',
+ // 夜间模式
+ darkModeFlag: false,
// 菜单主题
sideMenuTheme: 'dark',
// 主题颜色索引
diff --git a/smart-admin-web-javascript/src/i18n/lang/en-US/index.js b/smart-admin-web-javascript/src/i18n/lang/en-US/index.js
index 30a5cf10..bbe64914 100644
--- a/smart-admin-web-javascript/src/i18n/lang/en-US/index.js
+++ b/smart-admin-web-javascript/src/i18n/lang/en-US/index.js
@@ -17,6 +17,7 @@ export default {
'setting.table.yHeight': 'Table Height',
'setting.pagetag.location': 'TagPage Position',
'setting.color': 'Theme Color',
+ 'setting.darkmode': 'Dark Mode',
'setting.menu.layout': 'Menu Layout',
'setting.menu.width': 'Menu Width',
'setting.menu.theme': 'Menu Theme',
diff --git a/smart-admin-web-javascript/src/i18n/lang/zh-CN/index.js b/smart-admin-web-javascript/src/i18n/lang/zh-CN/index.js
index 6e085c9a..29e5b74d 100644
--- a/smart-admin-web-javascript/src/i18n/lang/zh-CN/index.js
+++ b/smart-admin-web-javascript/src/i18n/lang/zh-CN/index.js
@@ -17,6 +17,7 @@ export default {
'setting.table.yHeight': '表格高度',
'setting.pagetag.location': '标签页位置',
'setting.color': '主题颜色',
+ 'setting.darkmode': '夜间模式',
'setting.menu.layout': '菜单布局',
'setting.menu.width': '菜单宽度',
'setting.menu.theme': '菜单主题',
diff --git a/smart-admin-web-javascript/src/layout/components/header-user-space/header-message.vue b/smart-admin-web-javascript/src/layout/components/header-user-space/header-message.vue
index aa3de6d6..000416b2 100644
--- a/smart-admin-web-javascript/src/layout/components/header-user-space/header-message.vue
+++ b/smart-admin-web-javascript/src/layout/components/header-user-space/header-message.vue
@@ -252,7 +252,6 @@
}
.dropdown-tabs {
- background-color: @base-bg-color;
border-radius: 4px;
}
diff --git a/smart-admin-web-javascript/src/layout/components/header-user-space/header-setting.vue b/smart-admin-web-javascript/src/layout/components/header-user-space/header-setting.vue
index fa1808c8..eaf1b9e5 100644
--- a/smart-admin-web-javascript/src/layout/components/header-user-space/header-setting.vue
+++ b/smart-admin-web-javascript/src/layout/components/header-user-space/header-setting.vue
@@ -13,7 +13,7 @@
- {{ item.text }}
+ {{ item.text }}
@@ -51,12 +51,6 @@
像素(px)或者 百分比
-
-
- 默认
- 紧凑
-
-
@@ -70,6 +64,12 @@
Light
+
+
+ 默认
+ 紧凑
+
+
顶部
@@ -92,7 +92,6 @@
+
+
+
diff --git a/smart-admin-web-javascript/src/layout/components/page-tag/components/default-tab.vue b/smart-admin-web-javascript/src/layout/components/page-tag/components/default-tab.vue
index 243fcee5..b8c44454 100644
--- a/smart-admin-web-javascript/src/layout/components/page-tag/components/default-tab.vue
+++ b/smart-admin-web-javascript/src/layout/components/page-tag/components/default-tab.vue
@@ -9,16 +9,17 @@
-->
-
+
-
+
+
+
{{ item.menuTitle }}
-
@@ -137,18 +138,17 @@
diff --git a/smart-admin-web-javascript/src/layout/components/side-expand-menu/recursion-menu.vue b/smart-admin-web-javascript/src/layout/components/side-expand-menu/recursion-menu.vue
index 67fd92b6..86c62a26 100644
--- a/smart-admin-web-javascript/src/layout/components/side-expand-menu/recursion-menu.vue
+++ b/smart-admin-web-javascript/src/layout/components/side-expand-menu/recursion-menu.vue
@@ -43,6 +43,7 @@
import _ from 'lodash';
import menuEmitter from './side-expand-menu-mitt';
import { useUserStore } from '/@/store/modules/system/user';
+ import { theme } from 'ant-design-vue';
// 选中的顶级菜单
let topMenu = ref({});
@@ -83,12 +84,20 @@
}
defineExpose({ updateSelectKeyAndOpenKey });
+
+ const { useToken } = theme;
+ const { token } = useToken();
diff --git a/smart-admin-web-javascript/src/layout/components/top-expand-menu/recursion-menu.vue b/smart-admin-web-javascript/src/layout/components/top-expand-menu/recursion-menu.vue
index 992e763d..9502a08e 100644
--- a/smart-admin-web-javascript/src/layout/components/top-expand-menu/recursion-menu.vue
+++ b/smart-admin-web-javascript/src/layout/components/top-expand-menu/recursion-menu.vue
@@ -12,14 +12,13 @@
![]()
-
{{ websiteName }}
-
{{ websiteName }}
+
{{ websiteName }}
-
+
@@ -123,25 +122,25 @@
defineExpose({ updateSelectKeyAndOpenKey });
- const isLight = computed(() => useAppConfigStore().$state.sideMenuTheme === 'light');
- const color = computed(() => {
- let isLight = useAppConfigStore().$state.sideMenuTheme === 'light';
- return {
- background: isLight ? '#FFFFFF' : '#001529',
- };
+ const darkModeFlag = computed(() => useAppConfigStore().$state.darkModeFlag);
+
+ const logoHeight = computed(() => {
+ if(useAppConfigStore().$state.compactFlag){
+ return '40px';
+ }else{
+ return '46px';
+ }
});
diff --git a/smart-admin-web-javascript/src/layout/components/top-expand-menu/top-menu.vue b/smart-admin-web-javascript/src/layout/components/top-expand-menu/top-menu.vue
index 210ee324..581dd304 100644
--- a/smart-admin-web-javascript/src/layout/components/top-expand-menu/top-menu.vue
+++ b/smart-admin-web-javascript/src/layout/components/top-expand-menu/top-menu.vue
@@ -10,7 +10,7 @@
+
-
diff --git a/smart-admin-web-typescript/src/components/support/table-operator/index.vue b/smart-admin-web-typescript/src/components/support/table-operator/index.vue
index b368b920..2a8b4c82 100644
--- a/smart-admin-web-typescript/src/components/support/table-operator/index.vue
+++ b/smart-admin-web-typescript/src/components/support/table-operator/index.vue
@@ -74,13 +74,13 @@
watch(
() => props.modelValue,
(value) => {
- newColumn.forEach(item=>{
- value.forEach(itemNewColumns=>{
- if(item.dataIndex==itemNewColumns.dataIndex){
- Object.assign(item,itemNewColumns)
+ newColumn.forEach((item) => {
+ value.forEach((itemNewColumns) => {
+ if (item.dataIndex === itemNewColumns.dataIndex) {
+ Object.assign(item, itemNewColumns);
}
- })
- })
+ });
+ });
},
{
deep: true,
@@ -90,6 +90,7 @@
//构建用户的数据列
async function buildUserTableColumns() {
+
if (!props.tableId) {
return;
}
@@ -127,6 +128,7 @@
// 处理退出全屏
function handleExitFullScreen() {
+ document.querySelector('#smartAdminHeader').style.display = 'block';
fullScreenFlag.value = false;
useAppConfigStore().exitFullScreen();
document.removeEventListener('fullscreenchange', handleFullscreenChange);
@@ -137,6 +139,7 @@
//判断各种浏览器 -全屏
function launchElementFullScreen(element) {
+ document.querySelector('#smartAdminHeader').style.display = 'none';
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.mozRequestFullScreen) {
@@ -179,28 +182,29 @@
// ----------------- 弹窗 修改表格列 -------------------
const smartTableColumnModal = ref();
+
function showModal() {
smartTableColumnModal.value.show(newColumn, props.tableId);
}
// 将弹窗修改的列数据,赋值给原表格 列数组
function updateColumn(changeColumnArray) {
- let obj={}
+ let obj = {};
// 如果为空数组代表恢复默认,使用原始表格数据
//合并列
- if(_.isEmpty(changeColumnArray)){
+ if (_.isEmpty(changeColumnArray)) {
obj = mergeColumn(_.cloneDeep(originalColumn), changeColumnArray);
- }else{
+ } else {
obj = mergeColumn(_.cloneDeep(newColumn), changeColumnArray);
}
const newColumns = obj.newColumns;
- newColumn.forEach(item=>{
- obj.newColumns.forEach(itemNewColumns=>{
- if(item.dataIndex==itemNewColumns.dataIndex){
- Object.assign(item,itemNewColumns)
+ newColumn.forEach((item) => {
+ obj.newColumns.forEach((itemNewColumns) => {
+ if (item.dataIndex === itemNewColumns.dataIndex) {
+ Object.assign(item, itemNewColumns);
}
- })
- })
+ });
+ });
emit(
'update:modelValue',
newColumns.filter((e) => e.showFlag)
@@ -217,6 +221,6 @@
buildUserTableColumns();
}
},
- { immediate: true }
+ { immediate: false }
);
diff --git a/smart-admin-web-typescript/src/config/app-config.ts b/smart-admin-web-typescript/src/config/app-config.ts
index 89e852a3..d9dad8a1 100644
--- a/smart-admin-web-typescript/src/config/app-config.ts
+++ b/smart-admin-web-typescript/src/config/app-config.ts
@@ -16,6 +16,8 @@ export const appDefaultConfig = {
sideMenuWidth: 200,
//标签页位置
pageTagLocation: 'center',
+ // 夜间模式
+ darkModeFlag: false,
// 菜单主题
sideMenuTheme: 'dark',
// 主题颜色索引
diff --git a/smart-admin-web-typescript/src/i18n/lang/en-US/index.ts b/smart-admin-web-typescript/src/i18n/lang/en-US/index.ts
index 30a5cf10..bbe64914 100644
--- a/smart-admin-web-typescript/src/i18n/lang/en-US/index.ts
+++ b/smart-admin-web-typescript/src/i18n/lang/en-US/index.ts
@@ -17,6 +17,7 @@ export default {
'setting.table.yHeight': 'Table Height',
'setting.pagetag.location': 'TagPage Position',
'setting.color': 'Theme Color',
+ 'setting.darkmode': 'Dark Mode',
'setting.menu.layout': 'Menu Layout',
'setting.menu.width': 'Menu Width',
'setting.menu.theme': 'Menu Theme',
diff --git a/smart-admin-web-typescript/src/i18n/lang/zh-CN/index.ts b/smart-admin-web-typescript/src/i18n/lang/zh-CN/index.ts
index 6e085c9a..29e5b74d 100644
--- a/smart-admin-web-typescript/src/i18n/lang/zh-CN/index.ts
+++ b/smart-admin-web-typescript/src/i18n/lang/zh-CN/index.ts
@@ -17,6 +17,7 @@ export default {
'setting.table.yHeight': '表格高度',
'setting.pagetag.location': '标签页位置',
'setting.color': '主题颜色',
+ 'setting.darkmode': '夜间模式',
'setting.menu.layout': '菜单布局',
'setting.menu.width': '菜单宽度',
'setting.menu.theme': '菜单主题',
diff --git a/smart-admin-web-typescript/src/layout/components/header-user-space/header-message.vue b/smart-admin-web-typescript/src/layout/components/header-user-space/header-message.vue
index 3bfe9a02..61f819cb 100644
--- a/smart-admin-web-typescript/src/layout/components/header-user-space/header-message.vue
+++ b/smart-admin-web-typescript/src/layout/components/header-user-space/header-message.vue
@@ -252,7 +252,6 @@
}
.dropdown-tabs {
- background-color: @base-bg-color;
border-radius: 4px;
}
diff --git a/smart-admin-web-typescript/src/layout/components/header-user-space/header-setting.vue b/smart-admin-web-typescript/src/layout/components/header-user-space/header-setting.vue
index e04647e8..5a4652da 100644
--- a/smart-admin-web-typescript/src/layout/components/header-user-space/header-setting.vue
+++ b/smart-admin-web-typescript/src/layout/components/header-user-space/header-setting.vue
@@ -13,7 +13,7 @@
- {{ item.text }}
+ {{ item.text }}
@@ -51,12 +51,6 @@
像素(px)或者 百分比
-
-
- 默认
- 紧凑
-
-
@@ -70,6 +64,12 @@
Light
+
+
+ 默认
+ 紧凑
+
+
顶部
@@ -92,7 +92,6 @@
+
+
+
diff --git a/smart-admin-web-typescript/src/layout/components/page-tag/components/default-tab.vue b/smart-admin-web-typescript/src/layout/components/page-tag/components/default-tab.vue
index a3486c44..95aa91a5 100644
--- a/smart-admin-web-typescript/src/layout/components/page-tag/components/default-tab.vue
+++ b/smart-admin-web-typescript/src/layout/components/page-tag/components/default-tab.vue
@@ -9,16 +9,17 @@
-->
-
+
-
+
+
+
{{ item.menuTitle }}
-
@@ -137,18 +138,17 @@
diff --git a/smart-admin-web-typescript/src/layout/components/side-expand-menu/recursion-menu.vue b/smart-admin-web-typescript/src/layout/components/side-expand-menu/recursion-menu.vue
index 8eef372e..4b8414ea 100644
--- a/smart-admin-web-typescript/src/layout/components/side-expand-menu/recursion-menu.vue
+++ b/smart-admin-web-typescript/src/layout/components/side-expand-menu/recursion-menu.vue
@@ -43,6 +43,7 @@
import _ from 'lodash';
import menuEmitter from './side-expand-menu-mitt';
import { useUserStore } from '/@/store/modules/system/user';
+ import { theme } from 'ant-design-vue';
// 选中的顶级菜单
let topMenu = ref({});
@@ -83,12 +84,20 @@
}
defineExpose({ updateSelectKeyAndOpenKey });
+
+ const { useToken } = theme;
+ const { token } = useToken();
diff --git a/smart-admin-web-typescript/src/layout/components/top-expand-menu/recursion-menu.vue b/smart-admin-web-typescript/src/layout/components/top-expand-menu/recursion-menu.vue
index ca6cbc41..e6af7a80 100644
--- a/smart-admin-web-typescript/src/layout/components/top-expand-menu/recursion-menu.vue
+++ b/smart-admin-web-typescript/src/layout/components/top-expand-menu/recursion-menu.vue
@@ -12,14 +12,13 @@
![]()
-
{{ websiteName }}
-
{{ websiteName }}
+
{{ websiteName }}
-
+
@@ -123,25 +122,25 @@
defineExpose({ updateSelectKeyAndOpenKey });
- const isLight = computed(() => useAppConfigStore().$state.sideMenuTheme === 'light');
- const color = computed(() => {
- let isLight = useAppConfigStore().$state.sideMenuTheme === 'light';
- return {
- background: isLight ? '#FFFFFF' : '#001529',
- };
+ const darkModeFlag = computed(() => useAppConfigStore().$state.darkModeFlag);
+
+ const logoHeight = computed(() => {
+ if(useAppConfigStore().$state.compactFlag){
+ return '40px';
+ }else{
+ return '46px';
+ }
});
diff --git a/smart-admin-web-typescript/src/layout/components/top-expand-menu/top-menu.vue b/smart-admin-web-typescript/src/layout/components/top-expand-menu/top-menu.vue
index f78e751b..421361bf 100644
--- a/smart-admin-web-typescript/src/layout/components/top-expand-menu/top-menu.vue
+++ b/smart-admin-web-typescript/src/layout/components/top-expand-menu/top-menu.vue
@@ -10,7 +10,7 @@
+