From 075e7ad134fb3157cbf1c05287129a47be92c8e8 Mon Sep 17 00:00:00 2001 From: zhuoda Date: Tue, 5 Aug 2025 20:10:13 +0800 Subject: [PATCH] =?UTF-8?q?v3.25.0=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E5=8A=A0=E5=AF=86=E9=9A=8F=E6=9C=BA=E7=9B=90?= =?UTF-8?q?;=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91java=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=E7=89=88=E6=9C=AC;=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=E4=BE=9D=E8=B5=96=E5=BA=93;=E3=80=90?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E3=80=91=E5=8D=95=E5=8F=B7=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=99=A8;=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91=E9=98=B2?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E6=8F=90=E4=BA=A4;=E3=80=90=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91sa-base.yaml=E5=81=A5=E5=BA=B7=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E9=82=AE=E7=AE=B1;=E3=80=90=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E3=80=91=E5=89=8D=E7=AB=AF=E5=A4=9C=E9=97=B4=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?;=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E9=A1=B5issue;=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91=E5=AD=97?= =?UTF-8?q?=E5=85=B8int=E5=9B=9E=E6=98=BEbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- smart-admin-api-java17-springboot3/pom.xml | 137 +++--- .../admin/interceptor/AdminInterceptor.java | 1 + .../domain/entity/DepartmentEntity.java | 2 +- .../domain/entity/EmployeeEntity.java | 6 + .../employee/service/EmployeeService.java | 40 +- .../login/controller/LoginController.java | 2 +- .../system/login/service/LoginService.java | 14 +- .../sa-base/pom.xml | 30 +- .../sa/base/common/util/SmartPageUtil.java | 6 +- .../sa/base/common/util/SmartRequestUtil.java | 3 + .../lab1024/sa/base/config/FileConfig.java | 38 +- .../sa/base/config/RepeatSubmitConfig.java | 13 +- .../sa/base/config/RestClientConfig.java | 92 ++++ .../sa/base/config/RestTemplateConfig.java | 130 ----- .../lab1024/sa/base/config/SwaggerConfig.java | 22 +- .../support/captcha/CaptchaService.java | 5 +- .../service/CodeGeneratorService.java | 4 +- .../service/CodeGeneratorTemplateService.java | 8 +- .../support/file/service/FileService.java | 3 - .../service/FileStorageCloudServiceImpl.java | 123 +++-- .../base/module/support/mail/MailService.java | 5 +- .../repeatsubmit/RepeatSubmitAspect.java | 56 ++- .../repeatsubmit/annoation/RepeatSubmit.java | 19 +- .../ticket/AbstractRepeatSubmitTicket.java | 27 +- .../ticket/RepeatSubmitCaffeineTicket.java | 44 -- .../ticket/RepeatSubmitMemoryTicket.java | 60 +++ .../ticket/RepeatSubmitRedisTicket.java | 35 +- .../service/SecurityFileService.java | 33 +- .../service/SerialNumberBaseService.java | 4 +- .../impl/SerialNumberRedisService.java | 157 ++++-- .../src/main/resources/dev/sa-base.yaml | 18 +- .../src/main/resources/pre/sa-base.yaml | 22 +- .../src/main/resources/prod/sa-base.yaml | 28 +- .../src/main/resources/test/sa-base.yaml | 22 +- smart-admin-api-java8-springboot2/pom.xml | 98 ++-- .../admin/interceptor/AdminInterceptor.java | 2 +- .../domain/entity/DepartmentEntity.java | 2 +- .../domain/entity/EmployeeEntity.java | 6 + .../employee/service/EmployeeService.java | 41 +- .../login/controller/LoginController.java | 2 +- .../system/login/service/LoginService.java | 15 +- .../module/system/role/domain/vo/RoleVO.java | 3 - .../system/role/manager/RoleMenuManager.java | 1 - .../role/service/RoleDataScopeService.java | 5 +- .../sa-base/pom.xml | 26 +- .../sa/base/common/util/SmartPageUtil.java | 5 +- .../sa/base/common/util/SmartRequestUtil.java | 3 + .../base/common/util/SmartResponseUtil.java | 4 +- .../lab1024/sa/base/config/FileConfig.java | 38 +- .../sa/base/config/RepeatSubmitConfig.java | 14 +- .../sa/base/listener/WebServerListener.java | 5 - .../support/captcha/CaptchaService.java | 5 +- .../service/CodeGeneratorService.java | 4 +- .../service/CodeGeneratorTemplateService.java | 3 +- .../domain/QueryFormVariableService.java | 1 - .../support/file/service/FileService.java | 4 - .../service/FileStorageCloudServiceImpl.java | 120 +++-- .../service/FileStorageLocalServiceImpl.java | 1 - .../helpdoc/service/HelpDocService.java | 1 - .../base/module/support/mail/MailService.java | 5 +- .../repeatsubmit/RepeatSubmitAspect.java | 56 ++- .../repeatsubmit/annoation/RepeatSubmit.java | 19 +- .../ticket/AbstractRepeatSubmitTicket.java | 26 +- .../ticket/RepeatSubmitCaffeineTicket.java | 44 -- .../ticket/RepeatSubmitMemoryTicket.java | 60 +++ .../ticket/RepeatSubmitRedisTicket.java | 35 +- .../service/SecurityFileService.java | 33 +- .../service/SerialNumberBaseService.java | 4 +- .../impl/SerialNumberRedisService.java | 152 ++++-- .../src/main/resources/dev/sa-base.yaml | 18 +- .../src/main/resources/pre/sa-base.yaml | 22 +- .../src/main/resources/prod/sa-base.yaml | 27 +- .../src/main/resources/test/sa-base.yaml | 22 +- smart-admin-web-javascript/src/App.vue | 46 +- .../support/table-operator/index.vue | 36 +- .../src/config/app-config.js | 2 + .../src/i18n/lang/en-US/index.js | 1 + .../src/i18n/lang/zh-CN/index.js | 1 + .../header-user-space/header-message.vue | 1 - .../header-user-space/header-setting.vue | 53 +- .../page-tag/components/antd-tab.vue | 19 +- .../page-tag/components/chrome-tab.vue | 457 +++++++++--------- .../page-tag/components/default-tab.vue | 37 +- .../src/layout/components/page-tag/index.vue | 11 +- .../side-expand-menu/recursion-menu.vue | 16 +- .../top-expand-menu/recursion-menu.vue | 34 +- .../components/top-expand-menu/top-menu.vue | 25 +- .../src/layout/components/top-menu/index.vue | 8 +- .../src/layout/side-expand-layout.vue | 17 +- .../src/layout/side-layout.vue | 34 +- .../src/layout/top-expand-layout.vue | 38 +- .../src/layout/top-layout.vue | 83 ++-- smart-admin-web-javascript/src/main.js | 2 - .../src/store/modules/system/dict.js | 2 +- .../src/store/modules/system/user.js | 3 +- .../src/theme/smart-admin.less | 5 - .../oa/enterprise/enterprise-detail.vue | 8 +- ...code-generator-table-config-form-basic.vue | 8 +- ...ode-generator-table-config-form-delete.vue | 1 - .../preview/code-generator-preview-modal.vue | 1 - .../dict/components/dict-data-form-modal.vue | 2 +- .../src/views/system/account/index.vue | 10 +- .../components/employee-list/index.vue | 3 - .../system/home/components/changelog-card.vue | 2 +- .../home/components/echarts/category.vue | 1 - .../system/home/components/echarts/gauge.vue | 1 - .../home/components/echarts/gradient.vue | 1 - .../system/home/components/echarts/pie.vue | 1 - .../src/views/system/home/home-header.vue | 19 +- smart-admin-web-typescript/src/App.vue | 41 +- .../support/table-operator/index.vue | 36 +- .../src/config/app-config.ts | 2 + .../src/i18n/lang/en-US/index.ts | 1 + .../src/i18n/lang/zh-CN/index.ts | 1 + .../header-user-space/header-message.vue | 1 - .../header-user-space/header-setting.vue | 53 +- .../page-tag/components/antd-tab.vue | 19 +- .../page-tag/components/chrome-tab.vue | 457 +++++++++--------- .../page-tag/components/default-tab.vue | 37 +- .../src/layout/components/page-tag/index.vue | 11 +- .../side-expand-menu/recursion-menu.vue | 16 +- .../top-expand-menu/recursion-menu.vue | 34 +- .../components/top-expand-menu/top-menu.vue | 25 +- .../src/layout/components/top-menu/index.vue | 8 +- .../src/layout/side-expand-layout.vue | 17 +- .../src/layout/side-layout.vue | 34 +- .../src/layout/top-expand-layout.vue | 38 +- .../src/layout/top-layout.vue | 83 ++-- smart-admin-web-typescript/src/main.ts | 2 - .../src/store/modules/system/dict.ts | 2 +- .../src/store/modules/system/user.ts | 3 +- .../src/theme/smart-admin.less | 5 - .../oa/enterprise/enterprise-detail.vue | 8 +- ...code-generator-table-config-form-basic.vue | 8 +- ...ode-generator-table-config-form-delete.vue | 1 - .../preview/code-generator-preview-modal.vue | 1 - .../dict/components/dict-data-form-modal.vue | 2 +- .../src/views/system/account/index.vue | 10 +- .../components/employee-list/index.vue | 3 - .../system/home/components/changelog-card.vue | 2 +- .../home/components/echarts/category.vue | 1 - .../system/home/components/echarts/gauge.vue | 1 - .../home/components/echarts/gradient.vue | 1 - .../system/home/components/echarts/pie.vue | 1 - .../src/views/system/home/home-header.vue | 19 +- sql/smart_admin_v3.sql | 30 +- sql/sql-update-log/v3.25.0.sql | 40 ++ 147 files changed, 2412 insertions(+), 1772 deletions(-) create mode 100644 smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/RestClientConfig.java delete mode 100644 smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/RestTemplateConfig.java delete mode 100644 smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitCaffeineTicket.java create mode 100644 smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitMemoryTicket.java delete mode 100644 smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitCaffeineTicket.java create mode 100644 smart-admin-api-java8-springboot2/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/ticket/RepeatSubmitMemoryTicket.java create mode 100644 sql/sql-update-log/v3.25.0.sql 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 @@ -->