From c17f4c38e9725686cae45323b342dd26d470c63e Mon Sep 17 00:00:00 2001 From: root <13910913995@163.com> Date: Fri, 30 May 2025 09:58:52 +0800 Subject: [PATCH] Initial commit --- .idea/.gitignore | 3 + .idea/StdProject.iml | 9 + .idea/compiler.xml | 19 + .idea/encodings.xml | 6 + .idea/jarRepositories.xml | 20 + .idea/misc.xml | 14 + .idea/modules.xml | 8 + backend/db/db_mysql.sql | 242 +++ backend/db/db_sqllite.sql | 243 +++ backend/db/project.db | Bin 0 -> 35840 bytes backend/pom.xml | 141 ++ .../com/stdproject/ProjectApplication.java | 32 + .../stdproject/common/BusinessException.java | 106 + .../java/com/stdproject/common/Constants.java | 121 ++ .../com/stdproject/common/DataPermission.java | 36 + .../common/GlobalExceptionHandler.java | 188 ++ .../com/stdproject/common/OperationLog.java | 41 + .../stdproject/common/OperationLogAspect.java | 172 ++ .../com/stdproject/common/PageRequest.java | 72 + .../java/com/stdproject/common/Result.java | 191 ++ .../com/stdproject/common/ResultCode.java | 223 +++ .../com/stdproject/config/CacheConfig.java | 26 + .../config/CustomUserDetailsService.java | 210 ++ .../config/JwtAuthenticationEntryPoint.java | 43 + .../config/JwtAuthenticationFilter.java | 78 + .../stdproject/config/MybatisPlusConfig.java | 40 + .../config/PasswordEncoderConfig.java | 21 + .../com/stdproject/config/SecurityConfig.java | 172 ++ .../com/stdproject/config/SwaggerConfig.java | 46 + .../java/com/stdproject/config/WebConfig.java | 28 + .../controller/AppDictionaryController.java | 270 +++ .../controller/AppMenuController.java | 378 ++++ .../controller/AppOptLogController.java | 248 +++ .../controller/AppOrganizationController.java | 221 +++ .../controller/AppRoleController.java | 320 +++ .../controller/AppUserController.java | 277 +++ .../stdproject/controller/AuthController.java | 258 +++ .../com/stdproject/entity/AppDictionary.java | 75 + .../java/com/stdproject/entity/AppMenu.java | 110 ++ .../java/com/stdproject/entity/AppOptLog.java | 80 + .../stdproject/entity/AppOrganization.java | 110 ++ .../java/com/stdproject/entity/AppRole.java | 85 + .../com/stdproject/entity/AppRoleMenu.java | 44 + .../com/stdproject/entity/AppRoleUser.java | 44 + .../java/com/stdproject/entity/AppUser.java | 130 ++ .../mapper/AppDictionaryMapper.java | 18 + .../com/stdproject/mapper/AppMenuMapper.java | 18 + .../stdproject/mapper/AppOptLogMapper.java | 18 + .../mapper/AppOrganizationMapper.java | 18 + .../com/stdproject/mapper/AppRoleMapper.java | 18 + .../stdproject/mapper/AppRoleMenuMapper.java | 18 + .../stdproject/mapper/AppRoleUserMapper.java | 18 + .../com/stdproject/mapper/AppUserMapper.java | 18 + .../service/IAppDictionaryService.java | 16 + .../stdproject/service/IAppMenuService.java | 16 + .../stdproject/service/IAppOptLogService.java | 16 + .../service/IAppOrganizationService.java | 16 + .../service/IAppRoleMenuService.java | 16 + .../stdproject/service/IAppRoleService.java | 16 + .../service/IAppRoleUserService.java | 16 + .../stdproject/service/IAppUserService.java | 43 + .../impl/AppDictionaryServiceImpl.java | 20 + .../service/impl/AppMenuServiceImpl.java | 20 + .../service/impl/AppOptLogServiceImpl.java | 20 + .../impl/AppOrganizationServiceImpl.java | 23 + .../service/impl/AppRoleMenuServiceImpl.java | 20 + .../service/impl/AppRoleServiceImpl.java | 20 + .../service/impl/AppRoleUserServiceImpl.java | 20 + .../service/impl/AppUserServiceImpl.java | 77 + .../com/stdproject/utils/CaptchaUtils.java | 271 +++ .../java/com/stdproject/utils/FileUtils.java | 219 +++ .../java/com/stdproject/utils/JwtUtils.java | 168 ++ .../com/stdproject/utils/PasswordUtils.java | 85 + backend/src/main/resources/.env | 14 + backend/src/main/resources/application.yml | 193 ++ backend/src/main/resources/ehcache.xml | 58 + backend/src/main/resources/logback-spring.xml | 64 + backend/target/classes/.env | 14 + backend/target/classes/application.yml | 193 ++ .../com/stdproject/ProjectApplication.class | Bin 0 -> 1443 bytes .../stdproject/common/BusinessException.class | Bin 0 -> 2398 bytes .../com/stdproject/common/Constants.class | Bin 0 -> 2248 bytes .../stdproject/common/DataPermission.class | Bin 0 -> 628 bytes .../common/GlobalExceptionHandler.class | Bin 0 -> 12414 bytes .../com/stdproject/common/OperationLog.class | Bin 0 -> 651 bytes .../common/OperationLogAspect.class | Bin 0 -> 6987 bytes .../com/stdproject/common/PageRequest.class | Bin 0 -> 4925 bytes .../com/stdproject/common/Result.class | Bin 0 -> 7245 bytes .../com/stdproject/common/ResultCode.class | Bin 0 -> 5218 bytes .../com/stdproject/config/CacheConfig.class | Bin 0 -> 743 bytes .../config/CustomUserDetailsService.class | Bin 0 -> 9890 bytes .../config/JwtAuthenticationEntryPoint.class | Bin 0 -> 2591 bytes .../config/JwtAuthenticationFilter.class | Bin 0 -> 4263 bytes .../stdproject/config/MybatisPlusConfig.class | Bin 0 -> 1683 bytes .../config/PasswordEncoderConfig.class | Bin 0 -> 713 bytes .../stdproject/config/SecurityConfig.class | Bin 0 -> 12482 bytes .../com/stdproject/config/SwaggerConfig.class | Bin 0 -> 2932 bytes .../com/stdproject/config/WebConfig.class | Bin 0 -> 1290 bytes ...ictionaryController$DictOrderRequest.class | Bin 0 -> 1043 bytes .../controller/AppDictionaryController.class | Bin 0 -> 13885 bytes .../AppMenuController$MenuOrderRequest.class | Bin 0 -> 1019 bytes .../AppMenuController$MenuTreeNode.class | Bin 0 -> 3379 bytes .../controller/AppMenuController.class | Bin 0 -> 14955 bytes .../AppOptLogController$LogStatistics.class | Bin 0 -> 1385 bytes .../controller/AppOptLogController.class | Bin 0 -> 12424 bytes .../AppOrganizationController.class | Bin 0 -> 11715 bytes .../controller/AppRoleController.class | Bin 0 -> 16425 bytes ...pUserController$PasswordResetRequest.class | Bin 0 -> 789 bytes ...UserController$PasswordUpdateRequest.class | Bin 0 -> 1002 bytes .../controller/AppUserController.class | Bin 0 -> 12249 bytes ...AuthController$ChangePasswordRequest.class | Bin 0 -> 1224 bytes .../AuthController$LoginRequest.class | Bin 0 -> 1704 bytes .../controller/AuthController.class | Bin 0 -> 9489 bytes .../com/stdproject/entity/AppDictionary.class | Bin 0 -> 6822 bytes .../com/stdproject/entity/AppMenu.class | Bin 0 -> 10369 bytes .../com/stdproject/entity/AppOptLog.class | Bin 0 -> 7214 bytes .../stdproject/entity/AppOrganization.class | Bin 0 -> 10547 bytes .../com/stdproject/entity/AppRole.class | Bin 0 -> 7764 bytes .../com/stdproject/entity/AppRoleMenu.class | Bin 0 -> 3578 bytes .../com/stdproject/entity/AppRoleUser.class | Bin 0 -> 3579 bytes .../com/stdproject/entity/AppUser.class | Bin 0 -> 12817 bytes .../mapper/AppDictionaryMapper.class | Bin 0 -> 406 bytes .../com/stdproject/mapper/AppMenuMapper.class | Bin 0 -> 388 bytes .../stdproject/mapper/AppOptLogMapper.class | Bin 0 -> 394 bytes .../mapper/AppOrganizationMapper.class | Bin 0 -> 412 bytes .../com/stdproject/mapper/AppRoleMapper.class | Bin 0 -> 388 bytes .../stdproject/mapper/AppRoleMenuMapper.class | Bin 0 -> 400 bytes .../stdproject/mapper/AppRoleUserMapper.class | Bin 0 -> 400 bytes .../com/stdproject/mapper/AppUserMapper.class | Bin 0 -> 388 bytes .../service/IAppDictionaryService.class | Bin 0 -> 338 bytes .../stdproject/service/IAppMenuService.class | Bin 0 -> 320 bytes .../service/IAppOptLogService.class | Bin 0 -> 326 bytes .../service/IAppOrganizationService.class | Bin 0 -> 344 bytes .../service/IAppRoleMenuService.class | Bin 0 -> 332 bytes .../stdproject/service/IAppRoleService.class | Bin 0 -> 320 bytes .../service/IAppRoleUserService.class | Bin 0 -> 332 bytes .../stdproject/service/IAppUserService.class | Bin 0 -> 685 bytes .../impl/AppDictionaryServiceImpl.class | Bin 0 -> 743 bytes .../service/impl/AppMenuServiceImpl.class | Bin 0 -> 701 bytes .../service/impl/AppOptLogServiceImpl.class | Bin 0 -> 715 bytes .../impl/AppOrganizationServiceImpl.class | Bin 0 -> 757 bytes .../service/impl/AppRoleMenuServiceImpl.class | Bin 0 -> 729 bytes .../service/impl/AppRoleServiceImpl.class | Bin 0 -> 701 bytes .../service/impl/AppRoleUserServiceImpl.class | Bin 0 -> 729 bytes .../service/impl/AppUserServiceImpl.class | Bin 0 -> 3437 bytes .../utils/CaptchaUtils$CaptchaResult.class | Bin 0 -> 804 bytes .../com/stdproject/utils/CaptchaUtils.class | Bin 0 -> 6479 bytes .../com/stdproject/utils/FileUtils.class | Bin 0 -> 6490 bytes .../utils/JwtUtils$ClaimsResolver.class | Bin 0 -> 516 bytes .../com/stdproject/utils/JwtUtils.class | Bin 0 -> 6153 bytes .../com/stdproject/utils/PasswordUtils.class | Bin 0 -> 2438 bytes backend/target/classes/ehcache.xml | 58 + backend/target/classes/logback-spring.xml | 64 + .../compile/default-compile/createdFiles.lst | 71 + .../compile/default-compile/inputFiles.lst | 61 + dev-prompt.md | 152 ++ logs/stdproject-backend/error.2025-05-29.log | 26 + logs/stdproject-backend/error.log | 1729 +++++++++++++++++ logs/stdproject-backend/info.2025-05-29.log | 11 + logs/stdproject-backend/info.log | 121 ++ projectframe.md | 28 + 161 files changed, 9320 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/StdProject.iml create mode 100644 .idea/compiler.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 backend/db/db_mysql.sql create mode 100644 backend/db/db_sqllite.sql create mode 100644 backend/db/project.db create mode 100644 backend/pom.xml create mode 100644 backend/src/main/java/com/stdproject/ProjectApplication.java create mode 100644 backend/src/main/java/com/stdproject/common/BusinessException.java create mode 100644 backend/src/main/java/com/stdproject/common/Constants.java create mode 100644 backend/src/main/java/com/stdproject/common/DataPermission.java create mode 100644 backend/src/main/java/com/stdproject/common/GlobalExceptionHandler.java create mode 100644 backend/src/main/java/com/stdproject/common/OperationLog.java create mode 100644 backend/src/main/java/com/stdproject/common/OperationLogAspect.java create mode 100644 backend/src/main/java/com/stdproject/common/PageRequest.java create mode 100644 backend/src/main/java/com/stdproject/common/Result.java create mode 100644 backend/src/main/java/com/stdproject/common/ResultCode.java create mode 100644 backend/src/main/java/com/stdproject/config/CacheConfig.java create mode 100644 backend/src/main/java/com/stdproject/config/CustomUserDetailsService.java create mode 100644 backend/src/main/java/com/stdproject/config/JwtAuthenticationEntryPoint.java create mode 100644 backend/src/main/java/com/stdproject/config/JwtAuthenticationFilter.java create mode 100644 backend/src/main/java/com/stdproject/config/MybatisPlusConfig.java create mode 100644 backend/src/main/java/com/stdproject/config/PasswordEncoderConfig.java create mode 100644 backend/src/main/java/com/stdproject/config/SecurityConfig.java create mode 100644 backend/src/main/java/com/stdproject/config/SwaggerConfig.java create mode 100644 backend/src/main/java/com/stdproject/config/WebConfig.java create mode 100644 backend/src/main/java/com/stdproject/controller/AppDictionaryController.java create mode 100644 backend/src/main/java/com/stdproject/controller/AppMenuController.java create mode 100644 backend/src/main/java/com/stdproject/controller/AppOptLogController.java create mode 100644 backend/src/main/java/com/stdproject/controller/AppOrganizationController.java create mode 100644 backend/src/main/java/com/stdproject/controller/AppRoleController.java create mode 100644 backend/src/main/java/com/stdproject/controller/AppUserController.java create mode 100644 backend/src/main/java/com/stdproject/controller/AuthController.java create mode 100644 backend/src/main/java/com/stdproject/entity/AppDictionary.java create mode 100644 backend/src/main/java/com/stdproject/entity/AppMenu.java create mode 100644 backend/src/main/java/com/stdproject/entity/AppOptLog.java create mode 100644 backend/src/main/java/com/stdproject/entity/AppOrganization.java create mode 100644 backend/src/main/java/com/stdproject/entity/AppRole.java create mode 100644 backend/src/main/java/com/stdproject/entity/AppRoleMenu.java create mode 100644 backend/src/main/java/com/stdproject/entity/AppRoleUser.java create mode 100644 backend/src/main/java/com/stdproject/entity/AppUser.java create mode 100644 backend/src/main/java/com/stdproject/mapper/AppDictionaryMapper.java create mode 100644 backend/src/main/java/com/stdproject/mapper/AppMenuMapper.java create mode 100644 backend/src/main/java/com/stdproject/mapper/AppOptLogMapper.java create mode 100644 backend/src/main/java/com/stdproject/mapper/AppOrganizationMapper.java create mode 100644 backend/src/main/java/com/stdproject/mapper/AppRoleMapper.java create mode 100644 backend/src/main/java/com/stdproject/mapper/AppRoleMenuMapper.java create mode 100644 backend/src/main/java/com/stdproject/mapper/AppRoleUserMapper.java create mode 100644 backend/src/main/java/com/stdproject/mapper/AppUserMapper.java create mode 100644 backend/src/main/java/com/stdproject/service/IAppDictionaryService.java create mode 100644 backend/src/main/java/com/stdproject/service/IAppMenuService.java create mode 100644 backend/src/main/java/com/stdproject/service/IAppOptLogService.java create mode 100644 backend/src/main/java/com/stdproject/service/IAppOrganizationService.java create mode 100644 backend/src/main/java/com/stdproject/service/IAppRoleMenuService.java create mode 100644 backend/src/main/java/com/stdproject/service/IAppRoleService.java create mode 100644 backend/src/main/java/com/stdproject/service/IAppRoleUserService.java create mode 100644 backend/src/main/java/com/stdproject/service/IAppUserService.java create mode 100644 backend/src/main/java/com/stdproject/service/impl/AppDictionaryServiceImpl.java create mode 100644 backend/src/main/java/com/stdproject/service/impl/AppMenuServiceImpl.java create mode 100644 backend/src/main/java/com/stdproject/service/impl/AppOptLogServiceImpl.java create mode 100644 backend/src/main/java/com/stdproject/service/impl/AppOrganizationServiceImpl.java create mode 100644 backend/src/main/java/com/stdproject/service/impl/AppRoleMenuServiceImpl.java create mode 100644 backend/src/main/java/com/stdproject/service/impl/AppRoleServiceImpl.java create mode 100644 backend/src/main/java/com/stdproject/service/impl/AppRoleUserServiceImpl.java create mode 100644 backend/src/main/java/com/stdproject/service/impl/AppUserServiceImpl.java create mode 100644 backend/src/main/java/com/stdproject/utils/CaptchaUtils.java create mode 100644 backend/src/main/java/com/stdproject/utils/FileUtils.java create mode 100644 backend/src/main/java/com/stdproject/utils/JwtUtils.java create mode 100644 backend/src/main/java/com/stdproject/utils/PasswordUtils.java create mode 100644 backend/src/main/resources/.env create mode 100644 backend/src/main/resources/application.yml create mode 100644 backend/src/main/resources/ehcache.xml create mode 100644 backend/src/main/resources/logback-spring.xml create mode 100644 backend/target/classes/.env create mode 100644 backend/target/classes/application.yml create mode 100644 backend/target/classes/com/stdproject/ProjectApplication.class create mode 100644 backend/target/classes/com/stdproject/common/BusinessException.class create mode 100644 backend/target/classes/com/stdproject/common/Constants.class create mode 100644 backend/target/classes/com/stdproject/common/DataPermission.class create mode 100644 backend/target/classes/com/stdproject/common/GlobalExceptionHandler.class create mode 100644 backend/target/classes/com/stdproject/common/OperationLog.class create mode 100644 backend/target/classes/com/stdproject/common/OperationLogAspect.class create mode 100644 backend/target/classes/com/stdproject/common/PageRequest.class create mode 100644 backend/target/classes/com/stdproject/common/Result.class create mode 100644 backend/target/classes/com/stdproject/common/ResultCode.class create mode 100644 backend/target/classes/com/stdproject/config/CacheConfig.class create mode 100644 backend/target/classes/com/stdproject/config/CustomUserDetailsService.class create mode 100644 backend/target/classes/com/stdproject/config/JwtAuthenticationEntryPoint.class create mode 100644 backend/target/classes/com/stdproject/config/JwtAuthenticationFilter.class create mode 100644 backend/target/classes/com/stdproject/config/MybatisPlusConfig.class create mode 100644 backend/target/classes/com/stdproject/config/PasswordEncoderConfig.class create mode 100644 backend/target/classes/com/stdproject/config/SecurityConfig.class create mode 100644 backend/target/classes/com/stdproject/config/SwaggerConfig.class create mode 100644 backend/target/classes/com/stdproject/config/WebConfig.class create mode 100644 backend/target/classes/com/stdproject/controller/AppDictionaryController$DictOrderRequest.class create mode 100644 backend/target/classes/com/stdproject/controller/AppDictionaryController.class create mode 100644 backend/target/classes/com/stdproject/controller/AppMenuController$MenuOrderRequest.class create mode 100644 backend/target/classes/com/stdproject/controller/AppMenuController$MenuTreeNode.class create mode 100644 backend/target/classes/com/stdproject/controller/AppMenuController.class create mode 100644 backend/target/classes/com/stdproject/controller/AppOptLogController$LogStatistics.class create mode 100644 backend/target/classes/com/stdproject/controller/AppOptLogController.class create mode 100644 backend/target/classes/com/stdproject/controller/AppOrganizationController.class create mode 100644 backend/target/classes/com/stdproject/controller/AppRoleController.class create mode 100644 backend/target/classes/com/stdproject/controller/AppUserController$PasswordResetRequest.class create mode 100644 backend/target/classes/com/stdproject/controller/AppUserController$PasswordUpdateRequest.class create mode 100644 backend/target/classes/com/stdproject/controller/AppUserController.class create mode 100644 backend/target/classes/com/stdproject/controller/AuthController$ChangePasswordRequest.class create mode 100644 backend/target/classes/com/stdproject/controller/AuthController$LoginRequest.class create mode 100644 backend/target/classes/com/stdproject/controller/AuthController.class create mode 100644 backend/target/classes/com/stdproject/entity/AppDictionary.class create mode 100644 backend/target/classes/com/stdproject/entity/AppMenu.class create mode 100644 backend/target/classes/com/stdproject/entity/AppOptLog.class create mode 100644 backend/target/classes/com/stdproject/entity/AppOrganization.class create mode 100644 backend/target/classes/com/stdproject/entity/AppRole.class create mode 100644 backend/target/classes/com/stdproject/entity/AppRoleMenu.class create mode 100644 backend/target/classes/com/stdproject/entity/AppRoleUser.class create mode 100644 backend/target/classes/com/stdproject/entity/AppUser.class create mode 100644 backend/target/classes/com/stdproject/mapper/AppDictionaryMapper.class create mode 100644 backend/target/classes/com/stdproject/mapper/AppMenuMapper.class create mode 100644 backend/target/classes/com/stdproject/mapper/AppOptLogMapper.class create mode 100644 backend/target/classes/com/stdproject/mapper/AppOrganizationMapper.class create mode 100644 backend/target/classes/com/stdproject/mapper/AppRoleMapper.class create mode 100644 backend/target/classes/com/stdproject/mapper/AppRoleMenuMapper.class create mode 100644 backend/target/classes/com/stdproject/mapper/AppRoleUserMapper.class create mode 100644 backend/target/classes/com/stdproject/mapper/AppUserMapper.class create mode 100644 backend/target/classes/com/stdproject/service/IAppDictionaryService.class create mode 100644 backend/target/classes/com/stdproject/service/IAppMenuService.class create mode 100644 backend/target/classes/com/stdproject/service/IAppOptLogService.class create mode 100644 backend/target/classes/com/stdproject/service/IAppOrganizationService.class create mode 100644 backend/target/classes/com/stdproject/service/IAppRoleMenuService.class create mode 100644 backend/target/classes/com/stdproject/service/IAppRoleService.class create mode 100644 backend/target/classes/com/stdproject/service/IAppRoleUserService.class create mode 100644 backend/target/classes/com/stdproject/service/IAppUserService.class create mode 100644 backend/target/classes/com/stdproject/service/impl/AppDictionaryServiceImpl.class create mode 100644 backend/target/classes/com/stdproject/service/impl/AppMenuServiceImpl.class create mode 100644 backend/target/classes/com/stdproject/service/impl/AppOptLogServiceImpl.class create mode 100644 backend/target/classes/com/stdproject/service/impl/AppOrganizationServiceImpl.class create mode 100644 backend/target/classes/com/stdproject/service/impl/AppRoleMenuServiceImpl.class create mode 100644 backend/target/classes/com/stdproject/service/impl/AppRoleServiceImpl.class create mode 100644 backend/target/classes/com/stdproject/service/impl/AppRoleUserServiceImpl.class create mode 100644 backend/target/classes/com/stdproject/service/impl/AppUserServiceImpl.class create mode 100644 backend/target/classes/com/stdproject/utils/CaptchaUtils$CaptchaResult.class create mode 100644 backend/target/classes/com/stdproject/utils/CaptchaUtils.class create mode 100644 backend/target/classes/com/stdproject/utils/FileUtils.class create mode 100644 backend/target/classes/com/stdproject/utils/JwtUtils$ClaimsResolver.class create mode 100644 backend/target/classes/com/stdproject/utils/JwtUtils.class create mode 100644 backend/target/classes/com/stdproject/utils/PasswordUtils.class create mode 100644 backend/target/classes/ehcache.xml create mode 100644 backend/target/classes/logback-spring.xml create mode 100644 backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst create mode 100644 dev-prompt.md create mode 100644 logs/stdproject-backend/error.2025-05-29.log create mode 100644 logs/stdproject-backend/error.log create mode 100644 logs/stdproject-backend/info.2025-05-29.log create mode 100644 logs/stdproject-backend/info.log create mode 100644 projectframe.md diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..359bb53 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml diff --git a/.idea/StdProject.iml b/.idea/StdProject.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/StdProject.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b56de12 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..dfc8d74 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..5a2f139 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..ac9352c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..fbb69cc --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/backend/db/db_mysql.sql b/backend/db/db_mysql.sql new file mode 100644 index 0000000..52e6b58 --- /dev/null +++ b/backend/db/db_mysql.sql @@ -0,0 +1,242 @@ +/* + Navicat Premium Dump SQL + + Source Server : 华为云-mysql数据库 + Source Server Type : MySQL + Source Server Version : 80403 (8.4.3) + Source Host : 121.37.111.42:3306 + Source Schema : gisbi-demodb + + Target Server Type : MySQL + Target Server Version : 80403 (8.4.3) + File Encoding : 65001 + + Date: 30/05/2025 08:58:25 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for app_application +-- ---------------------------- +DROP TABLE IF EXISTS `app_application`; +CREATE TABLE `app_application` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `type` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '01' COMMENT '应用类型 01-数据展示分析 ', + `code` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用编号 自动生成:000001', + `name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '应用名称', + `simplename` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用简称', + `createdate` datetime NULL DEFAULT NULL COMMENT '创建日期', + `description` varchar(600) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用描述', + `image` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '应用图片 base64存储', + `appconfig` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '应用配置 JSON格式存储其他配置相关信息', + `dbconfig` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '数据库配置 JSON格式存储数据库信息配置(数据库用于存储此应用系统的所有配置数据)', + `organization` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户单位 使用这个应用系统的组织单位', + `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '状态 01-初始创建 02-正常运行 09-已停用', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime NULL DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用系统' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_dictionary +-- ---------------------------- +DROP TABLE IF EXISTS `app_dictionary`; +CREATE TABLE `app_dictionary` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `orderno` int NOT NULL COMMENT '顺序号', + `dictcode` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典编码', + `dictname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典名称', + `dictdata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '字典数据 JSON数组[{\"code\":\"01\",\"name\":\"字典值\"}]', + `lastmodifydate` datetime NULL DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用-数据字典' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_menu +-- ---------------------------- +DROP TABLE IF EXISTS `app_menu`; +CREATE TABLE `app_menu` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `type` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单类型 01-菜单', + `code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单编号', + `orderno` int NULL DEFAULT NULL COMMENT '同级序号', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单名称', + `icon` varchar(9000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单图标 base64存储', + `islink` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否外链 0-非外部 1-是外链', + `url` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单URL 内部资源页面URL访问地址', + `module_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模块ID 菜单关联的模块ID', + `parentid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '父级菜单ID 顶级为0', + `isdisplay` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否显示 0-不显示 1-显示', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime NULL DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用系统_菜单' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_module +-- ---------------------------- +DROP TABLE IF EXISTS `app_module`; +CREATE TABLE `app_module` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '名称', + `pid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '父级ID 父级模块', + `level` int NULL DEFAULT NULL COMMENT '层级', + `node_type` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '节点类型 01-目录 02-模块', + `type` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '类型 01-登录页面 02-主框架页面 03-GIS大屏页面 04-二级弹窗页面 05-数据填报页面 06-文档资源页面09-自定义页面', + `canvas_style_data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '样式数据', + `component_data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '组件数据', + `status` int NULL DEFAULT 1 COMMENT '状态 0-未发布 1-已发布', + `self_watermark_status` int NULL DEFAULT 0 COMMENT '是否单独打开水印 0-关闭 1-开启', + `sort` int NULL DEFAULT 0 COMMENT '排序 目录内的排序号', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + `source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '数据来源', + `delete_flag` tinyint NULL DEFAULT 0 COMMENT '删除标志', + `delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + `delete_by` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '删除人', + `version` int NULL DEFAULT 0 COMMENT '可视化资源版本', + `content_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '内容标识', + `check_version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1' COMMENT '内容检查标识', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用_系统模块' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_optlog +-- ---------------------------- +DROP TABLE IF EXISTS `app_optlog`; +CREATE TABLE `app_optlog` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `usercode` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '用户账号', + `username` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '用户名称', + `opttype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '操作类型 00-登录 01-新增 02-修改 03-删除 06-查询 09其他', + `module` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '模块名称', + `description` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '日志描述', + `method` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '操作方法', + `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL COMMENT '方法参数', + `logtime` datetime NULL DEFAULT NULL COMMENT '创建时间', + `requestip` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '请求IP', + `browser` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '浏览器类型', + PRIMARY KEY (`id`) USING BTREE, + INDEX `log_create_time_index`(`logtime` ASC) USING BTREE, + INDEX `inx_log_type`(`opttype` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '系统操作日志' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for app_organization +-- ---------------------------- +DROP TABLE IF EXISTS `app_organization`; +CREATE TABLE `app_organization` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `orgtype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组织类型:01-公司 02-部门', + `orgcode` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组织编号', + `orgname` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组织名称', + `parentid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '上级ID', + `manager` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组织负责人', + `description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组织详情', + `address` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系地址', + `contact_phone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话', + `contact_person` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系人', + `isvaild` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否有效 1-是 0-否', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime NULL DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用系统_用户组织' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_role +-- ---------------------------- +DROP TABLE IF EXISTS `app_role`; +CREATE TABLE `app_role` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `rolecode` varchar(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色编号 系统生成,三位编号', + `rolename` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色名称', + `type` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色类别 1-应用管理员 2-应用普通用户', + `description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色描述', + `isvaild` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否有效 1-是 0-否', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '最近修改者', + `lastmodifydate` datetime NOT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用系统_系统角色' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS `app_role_menu`; +CREATE TABLE `app_role_menu` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `roleid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色id', + `menuid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统角色-数据权限对照' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_role_users +-- ---------------------------- +DROP TABLE IF EXISTS `app_role_users`; +CREATE TABLE `app_role_users` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `roleid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色id', + `userid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统角色-用户对照' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_user +-- ---------------------------- +DROP TABLE IF EXISTS `app_user`; +CREATE TABLE `app_user` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `orgid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所属组织', + `usertype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户类型 0-管理员 1-普通用户', + `username` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名称 用户名称(账号)', + `nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户昵称(中文)', + `password` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '登录密码', + `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱', + `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号', + `avatar` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '用户头像 base64存储用户头像', + `status` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1' COMMENT '状态 1-有效 0-停用', + `pwdvalidperiod` int NULL DEFAULT 90 COMMENT '密码有限期 密码有限期(天)', + `failednum` int NULL DEFAULT 0 COMMENT '登录失败次数 允许的登录失败次数', + `loginip` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户指定登录IP 如果设置了IP,则只允许IP用户登录', + `failedlocktime` datetime NULL DEFAULT NULL COMMENT '登录失败锁定时间', + `pwdresettime` datetime NULL DEFAULT NULL COMMENT '密码修改时间', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime NULL DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用系统_系统用户' ROW_FORMAT = DYNAMIC; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/backend/db/db_sqllite.sql b/backend/db/db_sqllite.sql new file mode 100644 index 0000000..53c751c --- /dev/null +++ b/backend/db/db_sqllite.sql @@ -0,0 +1,243 @@ +/* +Navicat SQLite Data Transfer + +Source Server : project +Source Server Version : 30808 +Source Host : :0 + +Target Server Type : SQLite +Target Server Version : 30808 +File Encoding : 65001 + +Date: 2025-05-30 09:13:56 +*/ + +PRAGMA foreign_keys = OFF; + +-- ---------------------------- +-- Table structure for app_application +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_application"; +CREATE TABLE "app_application" ( +"id" TEXT(40) NOT NULL, +"type" TEXT(2), +"code" TEXT(6), +"name" TEXT(200) NOT NULL, +"simplename" TEXT(100), +"createdate" TEXT, +"description" TEXT(600), +"image" TEXT, +"appconfig" TEXT, +"dbconfig" TEXT, +"organization" TEXT(200), +"status" TEXT(20), +"lastmodifier" TEXT(40), +"lastmodifydate" TEXT, +"custom1" TEXT(100), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_dictionary +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_dictionary"; +CREATE TABLE "app_dictionary" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"orderno" INTEGER NOT NULL, +"dictcode" TEXT(40) NOT NULL, +"dictname" TEXT(100) NOT NULL, +"dictdata" TEXT, +"lastmodifydate" TEXT, +"custom1" TEXT(1000), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_menu +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_menu"; +CREATE TABLE "app_menu" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"type" TEXT(2) NOT NULL, +"code" TEXT(20) NOT NULL, +"orderno" INTEGER, +"name" TEXT(100) NOT NULL, +"icon" TEXT(9000), +"islink" TEXT(2), +"url" TEXT(200), +"module_id" TEXT(40), +"parentid" TEXT(40), +"isdisplay" TEXT(2), +"lastmodifier" TEXT(40), +"lastmodifydate" TEXT, +"custom1" TEXT(100), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_module +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_module"; +CREATE TABLE "app_module" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"name" TEXT(200), +"pid" TEXT(40), +"level" INTEGER, +"node_type" TEXT(40), +"type" TEXT(40), +"canvas_style_data" TEXT, +"component_data" TEXT, +"status" INTEGER, +"self_watermark_status" INTEGER, +"sort" INTEGER, +"create_time" TEXT, +"create_by" TEXT(40), +"update_time" TEXT, +"update_by" TEXT(40), +"remark" TEXT(255), +"source" TEXT(255), +"delete_flag" INTEGER, +"delete_time" TEXT, +"delete_by" TEXT(40), +"version" INTEGER, +"content_id" TEXT(50), +"check_version" TEXT(50), +"custom1" TEXT(100), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_optlog +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_optlog"; +CREATE TABLE "app_optlog" ( +"id" TEXT(40) NOT NULL, +"usercode" TEXT(200), +"username" TEXT(200), +"opttype" TEXT(20), +"module" TEXT(200), +"description" TEXT(400), +"method" TEXT(200), +"params" TEXT, +"logtime" TEXT, +"requestip" TEXT(200), +"browser" TEXT(200), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_organization +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_organization"; +CREATE TABLE "app_organization" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"orgtype" TEXT(20), +"orgcode" TEXT(20), +"orgname" TEXT(200), +"parentid" TEXT(40), +"manager" TEXT(40), +"description" TEXT(1000), +"address" TEXT(100), +"contact_phone" TEXT(100), +"contact_person" TEXT(100), +"isvaild" TEXT(2) NOT NULL, +"lastmodifier" TEXT(40), +"lastmodifydate" TEXT, +"custom1" TEXT(100), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_role +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_role"; +CREATE TABLE "app_role" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"rolecode" TEXT(3) NOT NULL, +"rolename" TEXT(100) NOT NULL, +"type" TEXT(2) NOT NULL, +"description" TEXT(1000), +"isvaild" TEXT(2) NOT NULL, +"lastmodifier" TEXT(40) NOT NULL, +"lastmodifydate" TEXT NOT NULL, +"custom1" TEXT(100), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_role_menu"; +CREATE TABLE "app_role_menu" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"roleid" TEXT(40) NOT NULL, +"menuid" TEXT(40) NOT NULL, +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_role_users +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_role_users"; +CREATE TABLE "app_role_users" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"roleid" TEXT(40) NOT NULL, +"userid" TEXT(40) NOT NULL, +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_user +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_user"; +CREATE TABLE "app_user" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"orgid" TEXT(40) NOT NULL, +"usertype" TEXT(20) NOT NULL, +"username" TEXT(100) NOT NULL, +"nickname" TEXT(255) NOT NULL, +"password" TEXT(200), +"email" TEXT(100), +"phone" TEXT(20), +"avatar" TEXT, +"status" TEXT(2), +"pwdvalidperiod" INTEGER, +"failednum" INTEGER, +"loginip" TEXT(40), +"failedlocktime" TEXT, +"pwdresettime" TEXT, +"lastmodifier" TEXT(40), +"lastmodifydate" TEXT, +"custom1" TEXT(100), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Indexes structure for table app_optlog +-- ---------------------------- +CREATE INDEX "main"."inx_log_type" +ON "app_optlog" ("opttype" ASC); +CREATE INDEX "main"."log_create_time_index" +ON "app_optlog" ("logtime" ASC); diff --git a/backend/db/project.db b/backend/db/project.db new file mode 100644 index 0000000000000000000000000000000000000000..6fdd66e2d56167770e21388d200fd6cd2b02d45f GIT binary patch literal 35840 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 + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.0.0 + + + com.stdproject + stdproject-backend + 0.0.1-SNAPSHOT + stdproject-backend + Standard Project Backend + + 17 + 3.5.3 + 0.11.5 + 2.0.2 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.boot + spring-boot-starter-cache + + + javax.cache + cache-api + + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + + mysql + mysql-connector-java + 8.0.30 + runtime + + + org.xerial + sqlite-jdbc + 3.36.0.3 + + + + io.jsonwebtoken + jjwt-api + ${jjwt.version} + + + io.jsonwebtoken + jjwt-impl + ${jjwt.version} + runtime + + + io.jsonwebtoken + jjwt-jackson + ${jjwt.version} + runtime + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc.version} + + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + org.projectlombok + lombok + provided + + + com.baomidou + mybatis-plus-core + 3.5.3.1 + + + org.projectlombok + lombok + 1.18.34 provided + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/ProjectApplication.java b/backend/src/main/java/com/stdproject/ProjectApplication.java new file mode 100644 index 0000000..1ecc101 --- /dev/null +++ b/backend/src/main/java/com/stdproject/ProjectApplication.java @@ -0,0 +1,32 @@ +package com.stdproject; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * Spring Boot 应用启动类 + * + * @author StdProject + * @since 2023-12-07 + */ +@SpringBootApplication +@MapperScan("com.stdproject.mapper") +@EnableCaching +@EnableAsync +@EnableTransactionManagement +public class ProjectApplication { + + public static void main(String[] args) { + SpringApplication.run(ProjectApplication.class, args); + System.out.println("\n========================================"); + System.out.println(" StdProject 应用启动成功!"); + System.out.println(" 接口文档地址: http://localhost:8080/swagger-ui.html"); + System.out.println(" 应用端口: 8080"); + System.out.println("========================================\n"); + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/BusinessException.java b/backend/src/main/java/com/stdproject/common/BusinessException.java new file mode 100644 index 0000000..216b193 --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/BusinessException.java @@ -0,0 +1,106 @@ +package com.stdproject.common; + +/** + * 业务异常类 + * + * @author StdProject + */ +public class BusinessException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + private Integer code; + + /** + * 错误消息 + */ + private String message; + + public BusinessException() { + super(); + } + + public BusinessException(String message) { + super(message); + this.message = message; + this.code = ResultCode.ERROR.getCode(); + } + + public BusinessException(Integer code, String message) { + super(message); + this.code = code; + this.message = message; + } + + public BusinessException(ResultCode resultCode) { + super(resultCode.getMessage()); + this.code = resultCode.getCode(); + this.message = resultCode.getMessage(); + } + + public BusinessException(String message, Throwable cause) { + super(message, cause); + this.message = message; + this.code = ResultCode.ERROR.getCode(); + } + + public BusinessException(Integer code, String message, Throwable cause) { + super(message, cause); + this.code = code; + this.message = message; + } + + public BusinessException(ResultCode resultCode, Throwable cause) { + super(resultCode.getMessage(), cause); + this.code = resultCode.getCode(); + this.message = resultCode.getMessage(); + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + @Override + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + /** + * 抛出业务异常 + * + * @param message 错误消息 + */ + public static void throwException(String message) { + throw new BusinessException(message); + } + + /** + * 抛出业务异常 + * + * @param code 错误码 + * @param message 错误消息 + */ + public static void throwException(Integer code, String message) { + throw new BusinessException(code, message); + } + + /** + * 抛出业务异常 + * + * @param resultCode 结果码枚举 + */ + public static void throwException(ResultCode resultCode) { + throw new BusinessException(resultCode); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/Constants.java b/backend/src/main/java/com/stdproject/common/Constants.java new file mode 100644 index 0000000..63b4221 --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/Constants.java @@ -0,0 +1,121 @@ +package com.stdproject.common; + +/** + * 系统常量类 + * + * @author StdProject + */ +public class Constants { + + /** + * JWT相关常量 + */ + public static final String JWT_HEADER = "Authorization"; + public static final String JWT_PREFIX = "Bearer "; + public static final String JWT_SECRET_KEY = "jwt.secret"; + public static final String JWT_EXPIRATION_KEY = "jwt.expiration"; + + /** + * 用户状态 + */ + public static final String USER_STATUS_NORMAL = "0"; // 正常 + public static final String USER_STATUS_DISABLED = "1"; // 停用 + public static final String USER_STATUS_LOCKED = "2"; // 锁定 + + /** + * 角色状态 + */ + public static final String ROLE_STATUS_NORMAL = "0"; // 正常 + public static final String ROLE_STATUS_DISABLED = "1"; // 停用 + + /** + * 菜单类型 + */ + public static final String MENU_TYPE_DIRECTORY = "M"; // 目录 + public static final String MENU_TYPE_MENU = "C"; // 菜单 + public static final String MENU_TYPE_BUTTON = "F"; // 按钮 + + /** + * 菜单状态 + */ + public static final String MENU_STATUS_NORMAL = "0"; // 正常 + public static final String MENU_STATUS_DISABLED = "1"; // 停用 + + /** + * 组织状态 + */ + public static final String ORG_STATUS_NORMAL = "0"; // 正常 + public static final String ORG_STATUS_DISABLED = "1"; // 停用 + + /** + * 操作类型 + */ + public static final String OPT_TYPE_LOGIN = "00"; // 登录 + public static final String OPT_TYPE_INSERT = "01"; // 新增 + public static final String OPT_TYPE_UPDATE = "02"; // 修改 + public static final String OPT_TYPE_DELETE = "03"; // 删除 + public static final String OPT_TYPE_QUERY = "06"; // 查询 + public static final String OPT_TYPE_OTHER = "09"; // 其他 + + /** + * 操作状态 + */ + public static final String OPT_STATUS_SUCCESS = "0"; // 成功 + public static final String OPT_STATUS_FAIL = "1"; // 失败 + + /** + * 数据权限类型 + */ + public static final String DATA_SCOPE_ALL = "1"; // 全部数据权限 + public static final String DATA_SCOPE_CUSTOM = "2"; // 自定义数据权限 + public static final String DATA_SCOPE_DEPT = "3"; // 部门数据权限 + public static final String DATA_SCOPE_DEPT_AND_CHILD = "4"; // 部门及以下数据权限 + public static final String DATA_SCOPE_SELF = "5"; // 仅本人数据权限 + + /** + * 字典状态 + */ + public static final String DICT_STATUS_NORMAL = "0"; // 正常 + public static final String DICT_STATUS_DISABLED = "1"; // 停用 + + /** + * 是否删除 + */ + public static final String DELETED_YES = "1"; // 已删除 + public static final String DELETED_NO = "0"; // 未删除 + + /** + * 性别 + */ + public static final String GENDER_MALE = "0"; // 男 + public static final String GENDER_FEMALE = "1"; // 女 + public static final String GENDER_UNKNOWN = "2"; // 未知 + + /** + * 默认密码 + */ + public static final String DEFAULT_PASSWORD = "123456"; + + /** + * 超级管理员角色编码 + */ + public static final String SUPER_ADMIN_ROLE = "admin"; + + /** + * 根节点ID + */ + public static final Long ROOT_NODE_ID = 0L; + + /** + * 缓存过期时间(秒) + */ + public static final int CACHE_EXPIRE_TIME = 3600; // 1小时 + public static final int CACHE_EXPIRE_TIME_SHORT = 300; // 5分钟 + public static final int CACHE_EXPIRE_TIME_LONG = 86400; // 24小时 + + /** + * 分页默认值 + */ + public static final int DEFAULT_PAGE_SIZE = 20; + public static final int MAX_PAGE_SIZE = 500; +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/DataPermission.java b/backend/src/main/java/com/stdproject/common/DataPermission.java new file mode 100644 index 0000000..7278902 --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/DataPermission.java @@ -0,0 +1,36 @@ +package com.stdproject.common; + +import java.lang.annotation.*; + +/** + * 数据权限注解 + * 用于标记需要进行数据权限控制的方法 + * + * @author StdProject + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataPermission { + + /** + * 数据权限类型 + * 1-全部数据权限 2-自定义数据权限 3-部门数据权限 4-部门及以下数据权限 5-仅本人数据权限 + */ + String value() default "1"; + + /** + * 表别名 + */ + String tableAlias() default ""; + + /** + * 用户ID字段名 + */ + String userIdColumn() default "create_user"; + + /** + * 部门ID字段名 + */ + String deptIdColumn() default "dept_id"; +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/GlobalExceptionHandler.java b/backend/src/main/java/com/stdproject/common/GlobalExceptionHandler.java new file mode 100644 index 0000000..e031221 --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/GlobalExceptionHandler.java @@ -0,0 +1,188 @@ +package com.stdproject.common; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.AuthenticationException; +import org.springframework.validation.BindException; +import org.springframework.validation.FieldError; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; +import org.springframework.web.servlet.NoHandlerFoundException; + + +import java.sql.SQLException; +import java.util.Set; + +/** + * 全局异常处理器 + * + * @author StdProject + */ +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + /** + * 处理业务异常 + */ + @ExceptionHandler(BusinessException.class) + @ResponseStatus(HttpStatus.OK) + public Result handleBusinessException(BusinessException e, HttpServletRequest request) { + log.warn("业务异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.error(e.getCode(), e.getMessage()); + } + + /** + * 处理参数校验异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) { + log.warn("参数校验异常: {} - {}", request.getRequestURI(), e.getMessage()); + StringBuilder message = new StringBuilder(); + for (FieldError error : e.getBindingResult().getFieldErrors()) { + message.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("; "); + } + return Result.badRequest(message.toString()); + } + + /** + * 处理参数绑定异常 + */ + @ExceptionHandler(BindException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleBindException(BindException e, HttpServletRequest request) { + log.warn("参数绑定异常: {} - {}", request.getRequestURI(), e.getMessage()); + StringBuilder message = new StringBuilder(); + for (FieldError error : e.getBindingResult().getFieldErrors()) { + message.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("; "); + } + return Result.badRequest(message.toString()); + } + + /** + * 处理约束违反异常 + */ + @ExceptionHandler(ConstraintViolationException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) { + log.warn("约束违反异常: {} - {}", request.getRequestURI(), e.getMessage()); + StringBuilder message = new StringBuilder(); + Set> violations = e.getConstraintViolations(); + for (ConstraintViolation violation : violations) { + message.append(violation.getPropertyPath()).append(": ").append(violation.getMessage()).append("; "); + } + return Result.badRequest(message.toString()); + } + + /** + * 处理参数类型不匹配异常 + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) { + log.warn("参数类型不匹配异常: {} - {}", request.getRequestURI(), e.getMessage()); + String message = String.format("参数 '%s' 的值 '%s' 类型不正确", e.getName(), e.getValue()); + return Result.badRequest(message); + } + + /** + * 处理认证异常 + */ + @ExceptionHandler(AuthenticationException.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Result handleAuthenticationException(AuthenticationException e, HttpServletRequest request) { + log.warn("认证异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.unauthorized(); + } + + /** + * 处理凭证错误异常 + */ + @ExceptionHandler(BadCredentialsException.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Result handleBadCredentialsException(BadCredentialsException e, HttpServletRequest request) { + log.warn("凭证错误异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.error(ResultCode.LOGIN_ERROR); + } + + /** + * 处理访问拒绝异常 + */ + @ExceptionHandler(AccessDeniedException.class) + @ResponseStatus(HttpStatus.FORBIDDEN) + public Result handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) { + log.warn("访问拒绝异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.forbidden(); + } + + /** + * 处理请求方法不支持异常 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) + public Result handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e, HttpServletRequest request) { + log.warn("请求方法不支持异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.error(ResultCode.METHOD_NOT_ALLOWED); + } + + /** + * 处理资源未找到异常 + */ + @ExceptionHandler(NoHandlerFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public Result handleNoHandlerFoundException(NoHandlerFoundException e, HttpServletRequest request) { + log.warn("资源未找到异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.notFound(); + } + + /** + * 处理数据完整性违反异常 + */ + @ExceptionHandler(DataIntegrityViolationException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleDataIntegrityViolationException(DataIntegrityViolationException e, HttpServletRequest request) { + log.warn("数据完整性违反异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.error(ResultCode.DATA_INTEGRITY_VIOLATION); + } + + /** + * 处理SQL异常 + */ + @ExceptionHandler(SQLException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleSQLException(SQLException e, HttpServletRequest request) { + log.error("SQL异常: {} - {}", request.getRequestURI(), e.getMessage(), e); + return Result.error(ResultCode.DATABASE_ERROR); + } + + /** + * 处理运行时异常 + */ + @ExceptionHandler(RuntimeException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleRuntimeException(RuntimeException e, HttpServletRequest request) { + log.error("运行时异常: {} - {}", request.getRequestURI(), e.getMessage(), e); + return Result.error(ResultCode.ERROR.getCode(), e.getMessage()); + } + + /** + * 处理其他异常 + */ + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleException(Exception e, HttpServletRequest request) { + log.error("系统异常: {} - {}", request.getRequestURI(), e.getMessage(), e); + return Result.error(ResultCode.UNKNOWN_ERROR); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/OperationLog.java b/backend/src/main/java/com/stdproject/common/OperationLog.java new file mode 100644 index 0000000..150d4bf --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/OperationLog.java @@ -0,0 +1,41 @@ +package com.stdproject.common; + +import java.lang.annotation.*; + +/** + * 操作日志注解 + * 用于标记需要记录操作日志的方法 + * + * @author StdProject + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface OperationLog { + + /** + * 操作类型 + * 00-登录 01-新增 02-修改 03-删除 06-查询 09-其他 + */ + String type() default "09"; + + /** + * 模块名称 + */ + String module() default ""; + + /** + * 操作描述 + */ + String description() default ""; + + /** + * 是否记录请求参数 + */ + boolean recordParams() default true; + + /** + * 是否记录返回结果 + */ + boolean recordResult() default false; +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/OperationLogAspect.java b/backend/src/main/java/com/stdproject/common/OperationLogAspect.java new file mode 100644 index 0000000..ee8485e --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/OperationLogAspect.java @@ -0,0 +1,172 @@ +package com.stdproject.common; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.stdproject.entity.AppOptLog; +import com.stdproject.service.IAppOptLogService; +import com.stdproject.utils.JwtUtils; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + + +import java.lang.reflect.Method; +import java.time.LocalDateTime; +import java.util.Arrays; + +/** + * 操作日志切面 + * + * @author StdProject + */ +@Aspect +@Component +@Slf4j +public class OperationLogAspect { + + @Autowired + private IAppOptLogService appOptLogService; + + @Autowired + private JwtUtils jwtUtils; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + /** + * 定义切点 + */ + @Pointcut("@annotation(com.stdproject.common.OperationLog)") + public void operationLogPointcut() { + } + + /** + * 正常返回通知 + */ + @AfterReturning(pointcut = "operationLogPointcut()", returning = "result") + public void doAfterReturning(JoinPoint joinPoint, Object result) { + handleLog(joinPoint, null, result); + } + + /** + * 异常通知 + */ + @AfterThrowing(pointcut = "operationLogPointcut()", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, Exception e) { + handleLog(joinPoint, e, null); + } + + /** + * 处理日志记录 + */ + private void handleLog(JoinPoint joinPoint, Exception e, Object result) { + try { + // 获取注解信息 + OperationLog operationLog = getAnnotationLog(joinPoint); + if (operationLog == null) { + return; + } + + // 获取请求信息 + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (attributes == null) { + return; + } + HttpServletRequest request = attributes.getRequest(); + + // 创建操作日志对象 + AppOptLog optLog = new AppOptLog(); + + // 设置基本信息 + optLog.setOpttype(operationLog.type()); + optLog.setModule(operationLog.module()); + optLog.setDescription(operationLog.description()); + optLog.setMethod(request.getMethod() + " " + request.getRequestURI()); + optLog.setRequestip(getIpAddress(request)); + optLog.setBrowser(request.getHeader("User-Agent")); + optLog.setLogtime(LocalDateTime.now()); + + // 设置操作用户 + String token = request.getHeader("Authorization"); + if (token != null && token.startsWith("Bearer ")) { + token = token.substring(7); + try { + String username = jwtUtils.getUsernameFromToken(token); + optLog.setUsername(username); + } catch (Exception ex) { + log.warn("解析JWT token失败: {}", ex.getMessage()); + } + } + + // 设置请求参数 + if (operationLog.recordParams()) { + String methodParams = getMethodParams(joinPoint); + optLog.setParams(methodParams); + } + + // 保存日志 + appOptLogService.save(optLog); + + } catch (Exception ex) { + log.error("记录操作日志异常: {}", ex.getMessage(), ex); + } + } + + /** + * 获取注解信息 + */ + private OperationLog getAnnotationLog(JoinPoint joinPoint) { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + return method.getAnnotation(OperationLog.class); + } + + /** + * 获取方法参数 + */ + private String getMethodParams(JoinPoint joinPoint) { + try { + Object[] args = joinPoint.getArgs(); + if (args == null || args.length == 0) { + return ""; + } + String params = objectMapper.writeValueAsString(Arrays.asList(args)); + if (params.length() > 2000) { + params = params.substring(0, 2000) + "..."; + } + return params; + } catch (Exception e) { + return "参数序列化失败"; + } + } + + /** + * 获取客户端IP地址 + */ + private String getIpAddress(HttpServletRequest request) { + String ip = request.getHeader("X-Forwarded-For"); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + return ip; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/PageRequest.java b/backend/src/main/java/com/stdproject/common/PageRequest.java new file mode 100644 index 0000000..8495a86 --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/PageRequest.java @@ -0,0 +1,72 @@ +package com.stdproject.common; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + + + +/** + * 分页查询请求类 + * + * @author StdProject + */ +@Data +public class PageRequest { + + /** + * 当前页码,从1开始 + */ + @NotNull(message = "页码不能为空") + @Min(value = 1, message = "页码必须大于0") @Min(value = 1, message = "页码必须大于0") + private Integer current = 1; + + /** + * 每页大小 + */ + @NotNull(message = "每页大小不能为空") + @Min(value = 1, message = "每页大小必须大于0") + private Integer size = 20; + + /** + * 排序字段 + */ + private String orderBy; + + /** + * 排序方向:asc-升序,desc-降序 + */ + private String orderDirection = "desc"; + + /** + * 搜索关键字 + */ + private String keyword; + + /** + * 获取偏移量 + * + * @return 偏移量 + */ + public Integer getOffset() { + return (current - 1) * size; + } + + /** + * 是否升序排序 + * + * @return 是否升序 + */ + public boolean isAsc() { + return "asc".equalsIgnoreCase(orderDirection); + } + + /** + * 是否降序排序 + * + * @return 是否降序 + */ + public boolean isDesc() { + return "desc".equalsIgnoreCase(orderDirection); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/Result.java b/backend/src/main/java/com/stdproject/common/Result.java new file mode 100644 index 0000000..3861e5e --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/Result.java @@ -0,0 +1,191 @@ +package com.stdproject.common; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.io.Serializable; + +/** + * 统一响应结果类 + * + * @author StdProject + * @param 数据类型 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Result implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 响应码 + */ + private Integer code; + + /** + * 响应消息 + */ + private String message; + + /** + * 响应数据 + */ + private T data; + + /** + * 时间戳 + */ + private Long timestamp; + + public Result() { + this.timestamp = System.currentTimeMillis(); + } + + public Result(Integer code, String message) { + this(); + this.code = code; + this.message = message; + } + + public Result(Integer code, String message, T data) { + this(code, message); + this.data = data; + } + + /** + * 成功响应 + * + * @param 数据类型 + * @return 成功响应 + */ + public static Result success() { + return new Result<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage()); + } + + /** + * 成功响应 + * + * @param data 响应数据 + * @param 数据类型 + * @return 成功响应 + */ + public static Result success(T data) { + return new Result<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data); + } + + /** + * 成功响应 + * + * @param message 响应消息 + * @param data 响应数据 + * @param 数据类型 + * @return 成功响应 + */ + public static Result success(String message, T data) { + return new Result<>(ResultCode.SUCCESS.getCode(), message, data); + } + + /** + * 失败响应 + * + * @param 数据类型 + * @return 失败响应 + */ + public static Result error() { + return new Result<>(ResultCode.ERROR.getCode(), ResultCode.ERROR.getMessage()); + } + + /** + * 失败响应 + * + * @param message 错误消息 + * @param 数据类型 + * @return 失败响应 + */ + public static Result error(String message) { + return new Result<>(ResultCode.ERROR.getCode(), message); + } + + /** + * 失败响应 + * + * @param code 错误码 + * @param message 错误消息 + * @param 数据类型 + * @return 失败响应 + */ + public static Result error(Integer code, String message) { + return new Result<>(code, message); + } + + /** + * 失败响应 + * + * @param resultCode 结果码枚举 + * @param 数据类型 + * @return 失败响应 + */ + public static Result error(ResultCode resultCode) { + return new Result<>(resultCode.getCode(), resultCode.getMessage()); + } + + /** + * 未授权响应 + * + * @param 数据类型 + * @return 未授权响应 + */ + public static Result unauthorized() { + return new Result<>(ResultCode.UNAUTHORIZED.getCode(), ResultCode.UNAUTHORIZED.getMessage()); + } + + /** + * 禁止访问响应 + * + * @param 数据类型 + * @return 禁止访问响应 + */ + public static Result forbidden() { + return new Result<>(ResultCode.FORBIDDEN.getCode(), ResultCode.FORBIDDEN.getMessage()); + } + + /** + * 资源未找到响应 + * + * @param 数据类型 + * @return 资源未找到响应 + */ + public static Result notFound() { + return new Result<>(ResultCode.NOT_FOUND.getCode(), ResultCode.NOT_FOUND.getMessage()); + } + + /** + * 参数错误响应 + * + * @param 数据类型 + * @return 参数错误响应 + */ + public static Result badRequest() { + return new Result<>(ResultCode.BAD_REQUEST.getCode(), ResultCode.BAD_REQUEST.getMessage()); + } + + /** + * 参数错误响应 + * + * @param message 错误消息 + * @param 数据类型 + * @return 参数错误响应 + */ + public static Result badRequest(String message) { + return new Result<>(ResultCode.BAD_REQUEST.getCode(), message); + } + + /** + * 判断是否成功 + * + * @return 是否成功 + */ + public boolean isSuccess() { + return ResultCode.SUCCESS.getCode().equals(this.code); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/ResultCode.java b/backend/src/main/java/com/stdproject/common/ResultCode.java new file mode 100644 index 0000000..f985514 --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/ResultCode.java @@ -0,0 +1,223 @@ +package com.stdproject.common; + +/** + * 结果码枚举 + * + * @author StdProject + */ +public enum ResultCode { + + /** + * 成功 + */ + SUCCESS(200, "操作成功"), + + /** + * 失败 + */ + ERROR(500, "操作失败"), + + /** + * 参数错误 + */ + BAD_REQUEST(400, "参数错误"), + + /** + * 未授权 + */ + UNAUTHORIZED(401, "未授权"), + + /** + * 禁止访问 + */ + FORBIDDEN(403, "禁止访问"), + + /** + * 资源未找到 + */ + NOT_FOUND(404, "资源未找到"), + + /** + * 方法不允许 + */ + METHOD_NOT_ALLOWED(405, "方法不允许"), + + /** + * 请求超时 + */ + REQUEST_TIMEOUT(408, "请求超时"), + + /** + * 用户名或密码错误 + */ + LOGIN_ERROR(1001, "用户名或密码错误"), + + /** + * 用户已被禁用 + */ + USER_DISABLED(1002, "用户已被禁用"), + + /** + * 用户已被锁定 + */ + USER_LOCKED(1003, "用户已被锁定"), + + /** + * 密码已过期 + */ + PASSWORD_EXPIRED(1004, "密码已过期"), + + /** + * 登录失败次数过多 + */ + LOGIN_FAILED_TOO_MANY(1005, "登录失败次数过多,账户已被锁定"), + + /** + * Token无效 + */ + TOKEN_INVALID(1006, "Token无效"), + + /** + * Token已过期 + */ + TOKEN_EXPIRED(1007, "Token已过期"), + + /** + * 用户不存在 + */ + USER_NOT_FOUND(1008, "用户不存在"), + + /** + * 用户名已存在 + */ + USERNAME_EXISTS(1009, "用户名已存在"), + + /** + * 邮箱已存在 + */ + EMAIL_EXISTS(1010, "邮箱已存在"), + + /** + * 手机号已存在 + */ + PHONE_EXISTS(1011, "手机号已存在"), + + /** + * 角色不存在 + */ + ROLE_NOT_FOUND(1012, "角色不存在"), + + /** + * 角色已存在 + */ + ROLE_EXISTS(1013, "角色已存在"), + + /** + * 菜单不存在 + */ + MENU_NOT_FOUND(1014, "菜单不存在"), + + /** + * 菜单已存在 + */ + MENU_EXISTS(1015, "菜单已存在"), + + /** + * 组织不存在 + */ + ORGANIZATION_NOT_FOUND(1016, "组织不存在"), + + /** + * 组织已存在 + */ + ORGANIZATION_EXISTS(1017, "组织已存在"), + + /** + * 数据字典不存在 + */ + DICTIONARY_NOT_FOUND(1018, "数据字典不存在"), + + /** + * 数据字典已存在 + */ + DICTIONARY_EXISTS(1019, "数据字典已存在"), + + /** + * 文件上传失败 + */ + FILE_UPLOAD_ERROR(2001, "文件上传失败"), + + /** + * 文件下载失败 + */ + FILE_DOWNLOAD_ERROR(2002, "文件下载失败"), + + /** + * 文件不存在 + */ + FILE_NOT_FOUND(2003, "文件不存在"), + + /** + * 文件格式不支持 + */ + FILE_FORMAT_NOT_SUPPORTED(2004, "文件格式不支持"), + + /** + * 文件大小超出限制 + */ + FILE_SIZE_EXCEEDED(2005, "文件大小超出限制"), + + /** + * 数据库操作失败 + */ + DATABASE_ERROR(3001, "数据库操作失败"), + + /** + * 数据不存在 + */ + DATA_NOT_FOUND(3002, "数据不存在"), + + /** + * 数据已存在 + */ + DATA_EXISTS(3003, "数据已存在"), + + /** + * 数据完整性约束违反 + */ + DATA_INTEGRITY_VIOLATION(3004, "数据完整性约束违反"), + + /** + * 系统繁忙 + */ + SYSTEM_BUSY(9001, "系统繁忙,请稍后重试"), + + /** + * 系统维护中 + */ + SYSTEM_MAINTENANCE(9002, "系统维护中"), + /** + * 系统维护中 + */ + + /** + * 未知错误 + */ + UNKNOWN_ERROR(9999, "未知错误"); + + private final Integer code; + private final String message; + + ResultCode(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/CacheConfig.java b/backend/src/main/java/com/stdproject/config/CacheConfig.java new file mode 100644 index 0000000..3d4f348 --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/CacheConfig.java @@ -0,0 +1,26 @@ +package com.stdproject.config; + +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Configuration; + +/** + * 缓存配置类 + * + * @author StdProject + */ +@Configuration +@EnableCaching +public class CacheConfig { + + // 缓存配置主要通过application.yml中的spring.cache.jcache.config配置 + // 这里启用缓存注解支持 + + /** + * 缓存名称常量 + */ + public static final String USER_CACHE = "userCache"; + public static final String ROLE_CACHE = "roleCache"; + public static final String MENU_CACHE = "menuCache"; + public static final String ORGANIZATION_CACHE = "organizationCache"; + public static final String DICTIONARY_CACHE = "dictionaryCache"; +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/CustomUserDetailsService.java b/backend/src/main/java/com/stdproject/config/CustomUserDetailsService.java new file mode 100644 index 0000000..e02184b --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/CustomUserDetailsService.java @@ -0,0 +1,210 @@ +package com.stdproject.config; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.stdproject.entity.AppUser; +import com.stdproject.entity.AppRole; +import com.stdproject.entity.AppRoleUser; +import com.stdproject.entity.AppRoleMenu; +import com.stdproject.entity.AppMenu; +import com.stdproject.service.IAppUserService; +import com.stdproject.service.IAppRoleService; +import com.stdproject.service.IAppRoleUserService; +import com.stdproject.service.IAppRoleMenuService; +import com.stdproject.service.IAppMenuService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.HashSet; +import java.util.stream.Collectors; + +/** + * 自定义用户详情服务 + * 实现Spring Security的UserDetailsService接口 + * + * @author StdProject + */ +@Slf4j +@Service +public class CustomUserDetailsService implements UserDetailsService { + + @Autowired + private IAppUserService appUserService; + + @Autowired + private IAppRoleService appRoleService; + + @Autowired + private IAppRoleUserService appRoleUserService; + + @Autowired + private IAppRoleMenuService appRoleMenuService; + + @Autowired + private IAppMenuService appMenuService; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + log.debug("加载用户信息: {}", username); + + AppUser appUser = appUserService.findByUsername(username); + if (appUser == null) { + log.warn("用户不存在: {}", username); + throw new UsernameNotFoundException("用户不存在: " + username); + } + + // 检查用户状态 + if (!"1".equals(appUser.getStatus())) { + log.warn("用户已被禁用: {}", username); + throw new UsernameNotFoundException("用户已被禁用: " + username); + } + + // 构建用户权限 + Collection authorities = buildUserAuthorities(appUser); + + return User.builder() + .username(appUser.getUsername()) + .password(appUser.getPassword()) + .authorities(authorities) + .accountExpired(false) + .accountLocked(isAccountLocked(appUser)) + .credentialsExpired(isCredentialsExpired(appUser)) + .disabled(!"1".equals(appUser.getStatus())) + .build(); + } + + /** + * 构建用户权限 + * + * @param appUser 用户信息 + * @return 权限集合 + */ + private Collection buildUserAuthorities(AppUser appUser) { + Set authorities = new HashSet<>(); + + try { + // 根据用户类型添加基本角色权限 + if ("0".equals(appUser.getUsertype())) { + authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); + } else { + authorities.add(new SimpleGrantedAuthority("ROLE_USER")); + } + + // 查询用户的角色 + QueryWrapper roleUserQuery = new QueryWrapper<>(); + roleUserQuery.eq("userid", appUser.getId()); + List roleUsers = appRoleUserService.list(roleUserQuery); + + if (!roleUsers.isEmpty()) { + // 获取角色ID列表 + List roleIds = roleUsers.stream() + .map(AppRoleUser::getRoleid) + .collect(Collectors.toList()); + + // 查询角色信息并添加角色权限 + List roles = appRoleService.listByIds(roleIds); + for (AppRole role : roles) { + if ("1".equals(role.getIsvaild())) { + // 添加角色权限,格式:ROLE_角色编码 + if (StringUtils.hasText(role.getRolecode())) { + authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRolecode().toUpperCase())); + } + } + } + + // 查询角色关联的菜单权限 + QueryWrapper roleMenuQuery = new QueryWrapper<>(); + roleMenuQuery.in("roleid", roleIds); + List roleMenus = appRoleMenuService.list(roleMenuQuery); + + if (!roleMenus.isEmpty()) { + // 获取菜单ID列表 + List menuIds = roleMenus.stream() + .map(AppRoleMenu::getMenuid) + .distinct() + .collect(Collectors.toList()); + + // 查询菜单信息并添加菜单权限 + List menus = appMenuService.listByIds(menuIds); + for (AppMenu menu : menus) { + if ("1".equals(menu.getIsdisplay()) && StringUtils.hasText(menu.getCode())) { + // 添加菜单权限,格式:菜单编码 + authorities.add(new SimpleGrantedAuthority(menu.getCode())); + + // 根据菜单类型添加操作权限 + String menuCode = menu.getCode(); + if (StringUtils.hasText(menuCode)) { + // 为每个菜单添加基本操作权限 + authorities.add(new SimpleGrantedAuthority(menuCode + ":list")); + authorities.add(new SimpleGrantedAuthority(menuCode + ":detail")); + + // 管理员拥有所有操作权限 + if ("0".equals(appUser.getUsertype())) { + authorities.add(new SimpleGrantedAuthority(menuCode + ":add")); + authorities.add(new SimpleGrantedAuthority(menuCode + ":edit")); + authorities.add(new SimpleGrantedAuthority(menuCode + ":delete")); + authorities.add(new SimpleGrantedAuthority(menuCode + ":permission")); + } + } + } + } + } + } + + log.debug("用户 {} 的权限列表: {}", appUser.getUsername(), + authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList())); + + } catch (Exception e) { + log.error("构建用户权限失败: {}", e.getMessage(), e); + // 发生异常时,至少保证基本角色权限 + authorities.clear(); + if ("0".equals(appUser.getUsertype())) { + authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); + } else { + authorities.add(new SimpleGrantedAuthority("ROLE_USER")); + } + } + + return authorities; + } + + /** + * 检查账户是否被锁定 + * + * @param appUser 用户信息 + * @return 是否被锁定 + */ + private boolean isAccountLocked(AppUser appUser) { + // 检查登录失败锁定时间 + if (appUser.getFailedlocktime() != null) { + // 如果锁定时间还未过期,则账户被锁定 + return appUser.getFailedlocktime().isAfter(java.time.LocalDateTime.now()); + } + return false; + } + + /** + * 检查凭证是否过期 + * + * @param appUser 用户信息 + * @return 是否过期 + */ + private boolean isCredentialsExpired(AppUser appUser) { + // 检查密码是否过期 + if (appUser.getPwdresettime() != null && appUser.getPwdvalidperiod() != null) { + java.time.LocalDateTime expireTime = appUser.getPwdresettime().plusDays(appUser.getPwdvalidperiod()); + return expireTime.isBefore(java.time.LocalDateTime.now()); + } + return false; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/JwtAuthenticationEntryPoint.java b/backend/src/main/java/com/stdproject/config/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..1688df9 --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/JwtAuthenticationEntryPoint.java @@ -0,0 +1,43 @@ +package com.stdproject.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.stdproject.common.Result; +import com.stdproject.common.ResultCode; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + + +import java.io.IOException; + +/** + * JWT认证入口点 + * 处理未认证的请求 + * + * @author StdProject + */ +@Slf4j +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) + throws IOException, ServletException { + + log.warn("未认证访问: {} - {}", request.getRequestURI(), authException.getMessage()); + + response.setContentType("application/json;charset=UTF-8"); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + + Result result = Result.error(ResultCode.UNAUTHORIZED); + + ObjectMapper objectMapper = new ObjectMapper(); + String jsonResult = objectMapper.writeValueAsString(result); + + response.getWriter().write(jsonResult); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/JwtAuthenticationFilter.java b/backend/src/main/java/com/stdproject/config/JwtAuthenticationFilter.java new file mode 100644 index 0000000..a077d7e --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/JwtAuthenticationFilter.java @@ -0,0 +1,78 @@ +package com.stdproject.config; + +import com.stdproject.utils.JwtUtils; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; + + +import java.io.IOException; + +/** + * JWT认证过滤器 + * + * @author StdProject + */ +@Slf4j +@Component +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + @Autowired + private JwtUtils jwtUtils; + + @Autowired + private UserDetailsService userDetailsService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + try { + String jwt = getJwtFromRequest(request); + + if (StringUtils.hasText(jwt) && SecurityContextHolder.getContext().getAuthentication() == null) { + String username = jwtUtils.getUsernameFromToken(jwt); + + if (StringUtils.hasText(username)) { + UserDetails userDetails = userDetailsService.loadUserByUsername(username); + + if (jwtUtils.validateToken(jwt, userDetails.getUsername())) { + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } + } + } catch (Exception e) { + log.error("无法设置用户认证: {}", e.getMessage()); + } + + filterChain.doFilter(request, response); + } + + /** + * 从请求中获取JWT令牌 + * + * @param request HTTP请求 + * @return JWT令牌 + */ + private String getJwtFromRequest(HttpServletRequest request) { + String bearerToken = request.getHeader("Authorization"); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + return null; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/MybatisPlusConfig.java b/backend/src/main/java/com/stdproject/config/MybatisPlusConfig.java new file mode 100644 index 0000000..5096d9d --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/MybatisPlusConfig.java @@ -0,0 +1,40 @@ +package com.stdproject.config; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * MyBatis-Plus配置类 + * + * @author StdProject + */ +@Configuration +@MapperScan("com.stdproject.mapper") +public class MybatisPlusConfig { + + /** + * MyBatis-Plus拦截器配置 + */ + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + + // 分页插件 + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + // 设置最大单页限制数量,默认 500 条,-1 不受限制 + paginationInnerInterceptor.setMaxLimit(1000L); + // 溢出总页数后是否进行处理 + paginationInnerInterceptor.setOverflow(false); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + + // 乐观锁插件 + interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); + + return interceptor; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/PasswordEncoderConfig.java b/backend/src/main/java/com/stdproject/config/PasswordEncoderConfig.java new file mode 100644 index 0000000..1683e2d --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/PasswordEncoderConfig.java @@ -0,0 +1,21 @@ +package com.stdproject.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * 密码编码器配置类 + * + * @author StdProject + */ +@Configuration +public class PasswordEncoderConfig { + + @Bean + public PasswordEncoder passwordEncoder() { + + return new BCryptPasswordEncoder(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/SecurityConfig.java b/backend/src/main/java/com/stdproject/config/SecurityConfig.java new file mode 100644 index 0000000..1f6dc64 --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/SecurityConfig.java @@ -0,0 +1,172 @@ +package com.stdproject.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +import java.util.Arrays; +import java.util.List; + +/** + * Spring Security配置类 + * + * @author StdProject + */ +@Configuration +@EnableWebSecurity +@EnableMethodSecurity(prePostEnabled = true) +@RequiredArgsConstructor +public class SecurityConfig { + + @Autowired + private PasswordEncoder passwordEncoder; + + private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + private final JwtAuthenticationFilter jwtAuthenticationFilter; + private final CustomUserDetailsService customUserDetailsService; + + @Value("${spring.security.jwt.enabled:true}") + private boolean jwtEnabled; + + @Value("${spring.security.cors.allowed-origins:http://localhost:3000,http://localhost:8080}") + private List allowedOrigins; + + @Value("${spring.security.cors.max-age:3600}") + private Long corsMaxAge; + + // 公开路径配置 + private static final String[] PUBLIC_PATHS = { + "/api/auth/**", + "/api/public/**", + "/swagger-ui/**", + "/v3/api-docs/**", + "/swagger-ui.html", + "/webjars/**", + "/favicon.ico", + "/error", + "/actuator/health", + "/actuator/info" + }; + + + /** + * 认证管理器 + */ + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { + return config.getAuthenticationManager(); + } + + /** + * CORS配置 + * 更安全的CORS配置,支持配置化的允许源 + */ + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + + // 设置允许的源,支持配置化 + configuration.setAllowedOrigins(allowedOrigins); + + // 设置允许的HTTP方法 + configuration.setAllowedMethods(Arrays.asList( + "GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH" + )); + + // 设置允许的请求头 + configuration.setAllowedHeaders(Arrays.asList( + "Authorization", "Content-Type", "X-Requested-With", + "Accept", "Origin", "Access-Control-Request-Method", + "Access-Control-Request-Headers", "X-CSRF-TOKEN" + )); + + // 设置暴露的响应头 + configuration.setExposedHeaders(Arrays.asList( + "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials", + "Authorization", "Content-Disposition" + )); + + configuration.setAllowCredentials(true); + configuration.setMaxAge(corsMaxAge); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } + + /** + * 安全过滤器链配置 + * 增强的安全配置,包含安全头和更完善的认证授权 + */ + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + // CORS配置 + .cors(cors -> cors.configurationSource(corsConfigurationSource())) + + // 禁用CSRF(因为使用JWT,无状态) + .csrf(csrf -> csrf.disable()) + + // 会话管理配置 + .sessionManagement(session -> session + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .maximumSessions(1) + .maxSessionsPreventsLogin(false) + ) + + // 异常处理配置 + .exceptionHandling(ex -> ex + .authenticationEntryPoint(jwtAuthenticationEntryPoint) + ) + + // 安全头配置 + .headers(headers -> headers + // 禁用iframe嵌入,防止点击劫持攻击 + .frameOptions().deny() + // 设置X-Content-Type-Options头为nosniff,防止MIME类型嗅探攻击 + .contentTypeOptions().and() + // 设置Referrer Policy为strict-origin-when-cross-origin + // 跨域请求时只发送源(origin),同源请求发送完整referrer + .referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN) + // 注意:已移除HSTS配置,不再强制使用HTTPS + ); + + // 根据配置决定是否启用JWT认证 + if (jwtEnabled) { + http.authorizeHttpRequests(authz -> authz + // 公开接口,无需认证 + .requestMatchers(PUBLIC_PATHS).permitAll() + // 管理员接口需要管理员权限 + .requestMatchers("/api/admin/**").hasRole("ADMIN") + // 其他所有请求都需要认证 + .anyRequest().authenticated() + ); + + // 添加JWT过滤器 + http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + } else { + // 如果禁用JWT认证,则允许所有请求(开发环境) + http.authorizeHttpRequests(authz -> authz + .anyRequest().permitAll() + ); + } + + return http.build(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/SwaggerConfig.java b/backend/src/main/java/com/stdproject/config/SwaggerConfig.java new file mode 100644 index 0000000..88437e3 --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/SwaggerConfig.java @@ -0,0 +1,46 @@ +package com.stdproject.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Swagger配置类 + * + * @author StdProject + */ +@Configuration +public class SwaggerConfig { + + /** + * OpenAPI配置 + */ + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("StdProject API") + .version("1.0.0") + .description("标准项目后端API文档") + .contact(new Contact() + .name("StdProject Team") + .email("support@stdproject.com") + .url("https://www.stdproject.com")) + .license(new License() + .name("Apache 2.0") + .url("https://www.apache.org/licenses/LICENSE-2.0"))) + .components(new Components() + .addSecuritySchemes("Bearer", new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + .description("JWT认证,请在值前面加上'Bearer '前缀"))) + .addSecurityItem(new SecurityRequirement().addList("Bearer")); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/WebConfig.java b/backend/src/main/java/com/stdproject/config/WebConfig.java new file mode 100644 index 0000000..e207fd0 --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/WebConfig.java @@ -0,0 +1,28 @@ +package com.stdproject.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * Web配置类 + * + * @author StdProject + */ +@Configuration +public class WebConfig implements WebMvcConfigurer { + + /** + * 静态资源处理 + */ + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + // Swagger UI 静态资源 + registry.addResourceHandler("/swagger-ui/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/swagger-ui/"); + + // 其他静态资源 + registry.addResourceHandler("/static/**") + .addResourceLocations("classpath:/static/"); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AppDictionaryController.java b/backend/src/main/java/com/stdproject/controller/AppDictionaryController.java new file mode 100644 index 0000000..bbce2a5 --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AppDictionaryController.java @@ -0,0 +1,270 @@ +package com.stdproject.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.stdproject.common.OperationLog; +import com.stdproject.common.PageRequest; +import com.stdproject.common.Result; +import com.stdproject.entity.AppDictionary; +import com.stdproject.service.IAppDictionaryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 应用-数据字典表 前端控制器 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Tag(name = "数据字典管理", description = "数据字典添加、数据字典修改、数据字典删除、数据字典查询等功能") +@RestController +@RequestMapping("/app-dictionary") +public class AppDictionaryController { + + @Autowired + private IAppDictionaryService appDictionaryService; + + @Operation(summary = "分页查询数据字典列表") + @PostMapping("/page") + @OperationLog(type = "06", module = "数据字典管理", description = "分页查询数据字典列表") + public Result> page(@RequestBody @Valid PageRequest pageRequest) { + Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 关键字搜索 + if (StringUtils.hasText(pageRequest.getKeyword())) { + queryWrapper.and(wrapper -> wrapper + .like("dictname", pageRequest.getKeyword()) + .or().like("dictcode", pageRequest.getKeyword()) + .or().like("dictdata", pageRequest.getKeyword()) + ); + } + + // 排序 + if (StringUtils.hasText(pageRequest.getOrderBy())) { + if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { + queryWrapper.orderByAsc(pageRequest.getOrderBy()); + } else { + queryWrapper.orderByDesc(pageRequest.getOrderBy()); + } + } else { + queryWrapper.orderByAsc("dictcode", "orderno"); + } + + IPage result = appDictionaryService.page(page, queryWrapper); + return Result.success(result); + } + + @Operation(summary = "查询所有数据字典列表") + @GetMapping("/list") + @OperationLog(type = "06", module = "数据字典管理", description = "查询所有数据字典列表") + public Result> list() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByAsc("dictcode", "orderno"); + + List dictionaries = appDictionaryService.list(queryWrapper); + return Result.success(dictionaries); + } + + @Operation(summary = "根据ID查询数据字典详情") + @GetMapping("/{id}") + @OperationLog(type = "06", module = "数据字典管理", description = "查询数据字典详情") + public Result getById(@Parameter(description = "字典ID") @PathVariable String id) { + AppDictionary dictionary = appDictionaryService.getById(id); + return Result.success(dictionary); + } + + @Operation(summary = "根据字典编码查询字典项列表") + @GetMapping("/code/{dictCode}") + @OperationLog(type = "06", module = "数据字典管理", description = "根据字典编码查询字典项列表") + public Result> getByDictCode(@Parameter(description = "字典编码") @PathVariable String dictCode) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("dictcode", dictCode); + queryWrapper.orderByAsc("orderno"); + + List dictionaries = appDictionaryService.list(queryWrapper); + return Result.success(dictionaries); + } + + @Operation(summary = "根据字典编码和字典值查询字典项") + @GetMapping("/code/{dictCode}/data/{dictData}") + @OperationLog(type = "06", module = "数据字典管理", description = "根据字典编码和字典数据查询字典项") + public Result getByCodeAndData( + @Parameter(description = "字典编码") @PathVariable String dictCode, + @Parameter(description = "字典数据") @PathVariable String dictData) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("dictcode", dictCode); + queryWrapper.eq("dictdata", dictData); + + AppDictionary dictionary = appDictionaryService.getOne(queryWrapper); + return Result.success(dictionary); + } + + @Operation(summary = "新增数据字典") + @PostMapping + @OperationLog(type = "01", module = "数据字典管理", description = "新增数据字典") + public Result save(@RequestBody @Valid AppDictionary appDictionary) { + // 检查同一字典编码下的字典值是否已存在 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("dictcode", appDictionary.getDictcode()); + queryWrapper.eq("dictdata", appDictionary.getDictdata()); + AppDictionary existDictionary = appDictionaryService.getOne(queryWrapper); + if (existDictionary != null) { + return Result.error("该字典编码下的字典值已存在"); + } + + // 设置默认值 + if (appDictionary.getOrderno() == null) { + // 获取同一字典编码下的最大序号 + QueryWrapper orderQuery = new QueryWrapper<>(); + orderQuery.eq("dictcode", appDictionary.getDictcode()); + orderQuery.orderByDesc("orderno"); + orderQuery.last("LIMIT 1"); + AppDictionary lastDict = appDictionaryService.getOne(orderQuery); + appDictionary.setOrderno(lastDict != null ? lastDict.getOrderno() + 1 : 1); + } + + appDictionary.setLastmodifydate(LocalDateTime.now()); + boolean success = appDictionaryService.save(appDictionary); + return success ? Result.success("新增成功") : Result.error("新增失败"); + } + + @Operation(summary = "修改数据字典") + @PutMapping + @OperationLog(type = "02", module = "数据字典管理", description = "修改数据字典") + public Result update(@RequestBody @Valid AppDictionary appDictionary) { + // 检查字典是否存在 + AppDictionary existDictionary = appDictionaryService.getById(appDictionary.getId()); + if (existDictionary == null) { + return Result.error("数据字典不存在"); + } + + // 如果修改了字典编码或字典值,检查新的组合是否已被其他字典项使用 + if (!existDictionary.getDictcode().equals(appDictionary.getDictcode()) || + !existDictionary.getDictdata().equals(appDictionary.getDictdata())) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("dictcode", appDictionary.getDictcode()); + queryWrapper.eq("dictdata", appDictionary.getDictdata()); + queryWrapper.ne("id", appDictionary.getId()); + AppDictionary dictWithSameCodeValue = appDictionaryService.getOne(queryWrapper); + if (dictWithSameCodeValue != null) { + return Result.error("该字典编码下的字典数据已被其他字典项使用"); + } + } + + appDictionary.setLastmodifydate(LocalDateTime.now()); + boolean success = appDictionaryService.updateById(appDictionary); + return success ? Result.success("修改成功") : Result.error("修改失败"); + } + + @Operation(summary = "删除数据字典") + @DeleteMapping("/{id}") + @OperationLog(type = "03", module = "数据字典管理", description = "删除数据字典") + public Result delete(@Parameter(description = "字典ID") @PathVariable String id) { + boolean success = appDictionaryService.removeById(id); + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + @Operation(summary = "批量删除数据字典") + @DeleteMapping("/batch") + @OperationLog(type = "03", module = "数据字典管理", description = "批量删除数据字典") + public Result deleteBatch(@RequestBody List ids) { + boolean success = appDictionaryService.removeByIds(ids); + return success ? Result.success("批量删除成功") : Result.error("批量删除失败"); + } + + @Operation(summary = "根据字典编码删除所有字典项") + @DeleteMapping("/code/{dictCode}") + @OperationLog(type = "03", module = "数据字典管理", description = "根据字典编码删除所有字典项") + public Result deleteByDictCode(@Parameter(description = "字典编码") @PathVariable String dictCode) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("dictcode", dictCode); + + boolean success = appDictionaryService.remove(queryWrapper); + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + @Operation(summary = "根据字典名称获取字典数据") + @GetMapping("/name/{dictName}") + @OperationLog(type = "06", module = "数据字典管理", description = "根据字典名称获取字典数据") + public Result getDictDataByName(@Parameter(description = "字典名称") @PathVariable String dictName) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("dictname", dictName); + AppDictionary dictionary = appDictionaryService.getOne(queryWrapper); + + if (dictionary != null) { + return Result.success(dictionary.getDictdata()); + } + return Result.error("未找到对应的字典数据"); + } + + @Operation(summary = "获取所有字典编码列表") + @GetMapping("/codes") + @OperationLog(type = "06", module = "数据字典管理", description = "获取所有字典编码列表") + public Result> getDictCodes() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("DISTINCT dictcode"); + queryWrapper.orderByAsc("dictcode"); + + List dictionaries = appDictionaryService.list(queryWrapper); + List dictCodes = dictionaries.stream() + .map(AppDictionary::getDictcode) + .distinct() + .collect(java.util.stream.Collectors.toList()); + + return Result.success(dictCodes); + } + + @Operation(summary = "调整字典项顺序") + @PutMapping("/reorder") + @OperationLog(type = "02", module = "数据字典管理", description = "调整字典项顺序") + public Result reorder(@RequestBody List orderRequests) { + for (DictOrderRequest request : orderRequests) { + AppDictionary dictionary = appDictionaryService.getById(request.getId()); + if (dictionary != null) { + dictionary.setOrderno(request.getOrderno()); + dictionary.setLastmodifydate(LocalDateTime.now()); + appDictionaryService.updateById(dictionary); + } + } + return Result.success("顺序调整成功"); + } + + @Operation(summary = "根据字典编码分组查询字典项") + @GetMapping("/grouped") + @OperationLog(type = "06", module = "数据字典管理", description = "根据字典编码分组查询字典项") + public Result>> getGroupedDictionaries() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByAsc("dictcode", "orderno"); + + List allDictionaries = appDictionaryService.list(queryWrapper); + java.util.Map> groupedDict = allDictionaries.stream() + .collect(java.util.stream.Collectors.groupingBy(AppDictionary::getDictcode)); + + return Result.success(groupedDict); + } + + /** + * 字典排序请求 + */ + public static class DictOrderRequest { + private String id; + private Integer orderno; + + public String getId() { return id; } + public void setId(String id) { this.id = id; } + public Integer getOrderno() { return orderno; } + public void setOrderno(Integer orderno) { this.orderno = orderno; } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AppMenuController.java b/backend/src/main/java/com/stdproject/controller/AppMenuController.java new file mode 100644 index 0000000..d8093e9 --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AppMenuController.java @@ -0,0 +1,378 @@ +package com.stdproject.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.stdproject.common.OperationLog; +import com.stdproject.common.PageRequest; +import com.stdproject.common.Result; +import com.stdproject.entity.AppMenu; +import com.stdproject.service.IAppMenuService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + *

+ * 应用-菜单表 前端控制器 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Tag(name = "菜单管理", description = "菜单添加、菜单修改、菜单删除、菜单查询等功能") +@RestController +@RequestMapping("/app-menu") +public class AppMenuController { + + @Autowired + private IAppMenuService appMenuService; + + @Operation(summary = "分页查询菜单列表") + @PostMapping("/page") + @OperationLog(type = "06", module = "菜单管理", description = "分页查询菜单列表") + public Result> page(@RequestBody @Valid PageRequest pageRequest) { + Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 关键字搜索 + if (StringUtils.hasText(pageRequest.getKeyword())) { + queryWrapper.and(wrapper -> wrapper + .like("name", pageRequest.getKeyword()) + .or().like("code", pageRequest.getKeyword()) + .or().like("url", pageRequest.getKeyword()) + ); + } + + // 排序 + if (StringUtils.hasText(pageRequest.getOrderBy())) { + if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { + queryWrapper.orderByAsc(pageRequest.getOrderBy()); + } else { + queryWrapper.orderByDesc(pageRequest.getOrderBy()); + } + } else { + queryWrapper.orderByAsc("parentid", "orderno"); + } + + IPage result = appMenuService.page(page, queryWrapper); + return Result.success(result); + } + + @Operation(summary = "查询所有菜单列表") + @GetMapping("/list") + @OperationLog(type = "06", module = "菜单管理", description = "查询所有菜单列表") + public Result> list() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByAsc("parentid", "orderno"); + + List menus = appMenuService.list(queryWrapper); + return Result.success(menus); + } + + @Operation(summary = "获取菜单树形结构") + @GetMapping("/tree") + @OperationLog(type = "06", module = "菜单管理", description = "获取菜单树形结构") + public Result> getMenuTree() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByAsc("parentid", "orderno"); + + List allMenus = appMenuService.list(queryWrapper); + List tree = buildMenuTree(allMenus, "0"); + return Result.success(tree); + } + + @Operation(summary = "根据ID查询菜单详情") + @GetMapping("/{id}") + @OperationLog(type = "06", module = "菜单管理", description = "查询菜单详情") + public Result getById(@Parameter(description = "菜单ID") @PathVariable String id) { + AppMenu menu = appMenuService.getById(id); + return Result.success(menu); + } + + @Operation(summary = "根据父级ID查询子菜单") + @GetMapping("/children/{parentId}") + @OperationLog(type = "06", module = "菜单管理", description = "根据父级ID查询子菜单") + public Result> getChildren(@Parameter(description = "父级菜单ID") @PathVariable String parentId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("parentid", parentId); + queryWrapper.orderByAsc("orderno"); + + List children = appMenuService.list(queryWrapper); + return Result.success(children); + } + + @Operation(summary = "新增菜单") + @PostMapping + @OperationLog(type = "01", module = "菜单管理", description = "新增菜单") + public Result save(@RequestBody @Valid AppMenu appMenu) { + // 检查菜单编号是否已存在 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("code", appMenu.getCode()); + AppMenu existMenu = appMenuService.getOne(queryWrapper); + if (existMenu != null) { + return Result.error("菜单编号已存在"); + } + + // 检查父级菜单是否存在(如果不是顶级菜单) + if (!"0".equals(appMenu.getParentid())) { + AppMenu parentMenu = appMenuService.getById(appMenu.getParentid()); + if (parentMenu == null) { + return Result.error("父级菜单不存在"); + } + } + + // 设置默认值 + if (appMenu.getOrderno() == null) { + // 获取同级菜单的最大序号 + QueryWrapper orderQuery = new QueryWrapper<>(); + orderQuery.eq("parentid", appMenu.getParentid()); + orderQuery.orderByDesc("orderno"); + orderQuery.last("LIMIT 1"); + AppMenu lastMenu = appMenuService.getOne(orderQuery); + appMenu.setOrderno(lastMenu != null ? lastMenu.getOrderno() + 1 : 1); + } + + if (!StringUtils.hasText(appMenu.getIsdisplay())) { + appMenu.setIsdisplay("1"); + } + + if (!StringUtils.hasText(appMenu.getIslink())) { + appMenu.setIslink("0"); + } + + if (!StringUtils.hasText(appMenu.getType())) { + appMenu.setType("01"); + } + + appMenu.setLastmodifydate(LocalDateTime.now()); + boolean success = appMenuService.save(appMenu); + return success ? Result.success("新增成功") : Result.error("新增失败"); + } + + @Operation(summary = "修改菜单") + @PutMapping + @OperationLog(type = "02", module = "菜单管理", description = "修改菜单") + public Result update(@RequestBody @Valid AppMenu appMenu) { + // 检查菜单是否存在 + AppMenu existMenu = appMenuService.getById(appMenu.getId()); + if (existMenu == null) { + return Result.error("菜单不存在"); + } + + // 如果修改了菜单编号,检查新编号是否已被其他菜单使用 + if (!existMenu.getCode().equals(appMenu.getCode())) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("code", appMenu.getCode()); + queryWrapper.ne("id", appMenu.getId()); + AppMenu menuWithSameCode = appMenuService.getOne(queryWrapper); + if (menuWithSameCode != null) { + return Result.error("菜单编号已被其他菜单使用"); + } + } + + // 如果修改了父级菜单,检查是否会形成循环引用 + if (!existMenu.getParentid().equals(appMenu.getParentid())) { + if (isCircularReference(appMenu.getId(), appMenu.getParentid())) { + return Result.error("不能将菜单移动到自己的子菜单下"); + } + + // 检查父级菜单是否存在(如果不是顶级菜单) + if (!"0".equals(appMenu.getParentid())) { + AppMenu parentMenu = appMenuService.getById(appMenu.getParentid()); + if (parentMenu == null) { + return Result.error("父级菜单不存在"); + } + } + } + + appMenu.setLastmodifydate(LocalDateTime.now()); + boolean success = appMenuService.updateById(appMenu); + return success ? Result.success("修改成功") : Result.error("修改失败"); + } + + @Operation(summary = "删除菜单") + @DeleteMapping("/{id}") + @OperationLog(type = "03", module = "菜单管理", description = "删除菜单") + public Result delete(@Parameter(description = "菜单ID") @PathVariable String id) { + // 检查是否有子菜单 + QueryWrapper childQuery = new QueryWrapper<>(); + childQuery.eq("parentid", id); + long childCount = appMenuService.count(childQuery); + if (childCount > 0) { + return Result.error("存在子菜单,无法删除"); + } + + boolean success = appMenuService.removeById(id); + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + @Operation(summary = "批量删除菜单") + @DeleteMapping("/batch") + @OperationLog(type = "03", module = "菜单管理", description = "批量删除菜单") + public Result deleteBatch(@RequestBody List ids) { + for (String id : ids) { + // 检查是否有子菜单 + QueryWrapper childQuery = new QueryWrapper<>(); + childQuery.eq("parentid", id); + long childCount = appMenuService.count(childQuery); + if (childCount > 0) { + return Result.error("存在子菜单的菜单无法删除"); + } + } + + boolean success = appMenuService.removeByIds(ids); + return success ? Result.success("批量删除成功") : Result.error("批量删除失败"); + } + + @Operation(summary = "根据菜单类型查询菜单列表") + @GetMapping("/type/{type}") + @OperationLog(type = "06", module = "菜单管理", description = "根据菜单类型查询菜单列表") + public Result> getByType(@Parameter(description = "菜单类型") @PathVariable String type) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("type", type); + queryWrapper.orderByAsc("parentid", "orderno"); + + List menus = appMenuService.list(queryWrapper); + return Result.success(menus); + } + + @Operation(summary = "获取显示的菜单树") + @GetMapping("/display-tree") + @OperationLog(type = "06", module = "菜单管理", description = "获取显示的菜单树") + public Result> getDisplayMenuTree() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("isdisplay", "1"); + queryWrapper.orderByAsc("parentid", "orderno"); + + List displayMenus = appMenuService.list(queryWrapper); + List tree = buildMenuTree(displayMenus, "0"); + return Result.success(tree); + } + + @Operation(summary = "调整菜单顺序") + @PutMapping("/reorder") + @OperationLog(type = "02", module = "菜单管理", description = "调整菜单顺序") + public Result reorder(@RequestBody List orderRequests) { + for (MenuOrderRequest request : orderRequests) { + AppMenu menu = appMenuService.getById(request.getId()); + if (menu != null) { + menu.setOrderno(request.getOrderno()); + menu.setLastmodifydate(LocalDateTime.now()); + appMenuService.updateById(menu); + } + } + return Result.success("顺序调整成功"); + } + + /** + * 构建菜单树 + */ + private List buildMenuTree(List allMenus, String parentId) { + return allMenus.stream() + .filter(menu -> parentId.equals(menu.getParentid())) + .map(menu -> { + MenuTreeNode node = new MenuTreeNode(); + node.setId(menu.getId()); + node.setCode(menu.getCode()); + node.setName(menu.getName()); + node.setIcon(menu.getIcon()); + node.setUrl(menu.getUrl()); + node.setType(menu.getType()); + node.setIslink(menu.getIslink()); + node.setIsdisplay(menu.getIsdisplay()); + node.setOrderno(menu.getOrderno()); + node.setParentid(menu.getParentid()); + node.setModuleId(menu.getModuleId()); + node.setChildren(buildMenuTree(allMenus, menu.getId())); + return node; + }) + .collect(Collectors.toList()); + } + + /** + * 检查是否会形成循环引用 + */ + private boolean isCircularReference(String menuId, String newParentId) { + if ("0".equals(newParentId)) { + return false; + } + + if (menuId.equals(newParentId)) { + return true; + } + + AppMenu parentMenu = appMenuService.getById(newParentId); + if (parentMenu == null) { + return false; + } + + return isCircularReference(menuId, parentMenu.getParentid()); + } + + /** + * 菜单树节点 + */ + public static class MenuTreeNode { + private String id; + private String code; + private String name; + private String icon; + private String url; + private String type; + private String islink; + private String isdisplay; + private Integer orderno; + private String parentid; + private String moduleId; + private List children = new ArrayList<>(); + + // Getters and Setters + public String getId() { return id; } + public void setId(String id) { this.id = id; } + public String getCode() { return code; } + public void setCode(String code) { this.code = code; } + public String getName() { return name; } + public void setName(String name) { this.name = name; } + public String getIcon() { return icon; } + public void setIcon(String icon) { this.icon = icon; } + public String getUrl() { return url; } + public void setUrl(String url) { this.url = url; } + public String getType() { return type; } + public void setType(String type) { this.type = type; } + public String getIslink() { return islink; } + public void setIslink(String islink) { this.islink = islink; } + public String getIsdisplay() { return isdisplay; } + public void setIsdisplay(String isdisplay) { this.isdisplay = isdisplay; } + public Integer getOrderno() { return orderno; } + public void setOrderno(Integer orderno) { this.orderno = orderno; } + public String getParentid() { return parentid; } + public void setParentid(String parentid) { this.parentid = parentid; } + public String getModuleId() { return moduleId; } + public void setModuleId(String moduleId) { this.moduleId = moduleId; } + public List getChildren() { return children; } + public void setChildren(List children) { this.children = children; } + } + + /** + * 菜单排序请求 + */ + public static class MenuOrderRequest { + private String id; + private Integer orderno; + + public String getId() { return id; } + public void setId(String id) { this.id = id; } + public Integer getOrderno() { return orderno; } + public void setOrderno(Integer orderno) { this.orderno = orderno; } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AppOptLogController.java b/backend/src/main/java/com/stdproject/controller/AppOptLogController.java new file mode 100644 index 0000000..dd5a61c --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AppOptLogController.java @@ -0,0 +1,248 @@ +package com.stdproject.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.stdproject.common.OperationLog; +import com.stdproject.common.PageRequest; +import com.stdproject.common.Result; +import com.stdproject.entity.AppOptLog; +import com.stdproject.service.IAppOptLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 应用-操作日志表 前端控制器 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Tag(name = "操作日志管理", description = "操作日志查询、操作日志删除等功能") +@RestController +@RequestMapping("/api/optlog") +public class AppOptLogController { + + @Autowired + private IAppOptLogService appOptLogService; + + @Operation(summary = "分页查询操作日志列表") + @PostMapping("/page") + @OperationLog(type = "06", module = "操作日志管理", description = "分页查询操作日志列表") + public Result> page(@RequestBody @Valid PageRequest pageRequest) { + Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 关键字搜索 + if (StringUtils.hasText(pageRequest.getKeyword())) { + queryWrapper.and(wrapper -> wrapper + .like("username", pageRequest.getKeyword()) + .or().like("module", pageRequest.getKeyword()) + .or().like("description", pageRequest.getKeyword()) + ); + } + + // 排序 + if (StringUtils.hasText(pageRequest.getOrderBy())) { + if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { + queryWrapper.orderByAsc(pageRequest.getOrderBy()); + } else { + queryWrapper.orderByDesc(pageRequest.getOrderBy()); + } + } else { + queryWrapper.orderByDesc("logtime"); + } + + IPage result = appOptLogService.page(page, queryWrapper); + return Result.success(result); + } + + @Operation(summary = "根据ID查询操作日志详情") + @GetMapping("/{id}") + @OperationLog(type = "06", module = "操作日志管理", description = "查询操作日志详情") + public Result getById(@Parameter(description = "日志ID") @PathVariable String id) { + AppOptLog optLog = appOptLogService.getById(id); + return Result.success(optLog); + } + + @Operation(summary = "根据用户名查询操作日志") + @GetMapping("/user/{username}") + @OperationLog(type = "06", module = "操作日志管理", description = "根据用户名查询操作日志") + public Result> getByUsername( + @Parameter(description = "用户名") @PathVariable String username, + @Parameter(description = "限制条数") @RequestParam(defaultValue = "100") Integer limit) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("username", username); + queryWrapper.orderByDesc("logtime"); + queryWrapper.last("LIMIT " + limit); + + List logs = appOptLogService.list(queryWrapper); + return Result.success(logs); + } + + @Operation(summary = "根据操作类型查询操作日志") + @GetMapping("/type/{type}") + @OperationLog(type = "06", module = "操作日志管理", description = "根据操作类型查询操作日志") + public Result> getByType( + @Parameter(description = "操作类型") @PathVariable String type, + @Parameter(description = "限制条数") @RequestParam(defaultValue = "100") Integer limit) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("type", type); + queryWrapper.orderByDesc("logtime"); + queryWrapper.last("LIMIT " + limit); + + List logs = appOptLogService.list(queryWrapper); + return Result.success(logs); + } + + @Operation(summary = "根据模块查询操作日志") + @GetMapping("/module/{module}") + @OperationLog(type = "06", module = "操作日志管理", description = "根据模块查询操作日志") + public Result> getByModule( + @Parameter(description = "模块名称") @PathVariable String module, + @Parameter(description = "限制条数") @RequestParam(defaultValue = "100") Integer limit) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("module", module); + queryWrapper.orderByDesc("opttime"); + queryWrapper.last("LIMIT " + limit); + + List logs = appOptLogService.list(queryWrapper); + return Result.success(logs); + } + + @Operation(summary = "根据时间范围查询操作日志") + @GetMapping("/time-range") + @OperationLog(type = "06", module = "操作日志管理", description = "根据时间范围查询操作日志") + public Result> getByTimeRange( + @Parameter(description = "开始时间") @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, + @Parameter(description = "结束时间") @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime, + @Parameter(description = "限制条数") @RequestParam(defaultValue = "1000") Integer limit) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.between("opttime", startTime, endTime); + queryWrapper.orderByDesc("opttime"); + queryWrapper.last("LIMIT " + limit); + + List logs = appOptLogService.list(queryWrapper); + return Result.success(logs); + } + + @Operation(summary = "根据IP地址查询操作日志") + @GetMapping("/ip/{ip}") + @OperationLog(type = "06", module = "操作日志管理", description = "根据IP地址查询操作日志") + public Result> getByIp( + @Parameter(description = "IP地址") @PathVariable String ip, + @Parameter(description = "限制条数") @RequestParam(defaultValue = "100") Integer limit) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("ip", ip); + queryWrapper.orderByDesc("opttime"); + queryWrapper.last("LIMIT " + limit); + + List logs = appOptLogService.list(queryWrapper); + return Result.success(logs); + } + + + @Operation(summary = "删除操作日志") + @DeleteMapping("/{id}") + @OperationLog(type = "03", module = "操作日志管理", description = "删除操作日志") + public Result delete(@Parameter(description = "日志ID") @PathVariable String id) { + boolean success = appOptLogService.removeById(id); + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + @Operation(summary = "批量删除操作日志") + @DeleteMapping("/batch") + @OperationLog(type = "03", module = "操作日志管理", description = "批量删除操作日志") + public Result deleteBatch(@RequestBody List ids) { + boolean success = appOptLogService.removeByIds(ids); + return success ? Result.success("批量删除成功") : Result.error("批量删除失败"); + } + + @Operation(summary = "清理指定天数前的操作日志") + @DeleteMapping("/clean/{days}") + @OperationLog(type = "03", module = "操作日志管理", description = "清理历史操作日志") + public Result cleanOldLogs(@Parameter(description = "保留天数") @PathVariable Integer days) { + LocalDateTime cutoffTime = LocalDateTime.now().minusDays(days); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lt("logtime", cutoffTime); + + boolean success = appOptLogService.remove(queryWrapper); + return success ? Result.success("清理成功") : Result.error("清理失败"); + } + + @Operation(summary = "获取操作日志统计信息") + @GetMapping("/statistics") + @OperationLog(type = "06", module = "操作日志管理", description = "获取操作日志统计信息") + public Result getStatistics() { + // 总日志数 + long totalCount = appOptLogService.count(); + + // 今日日志数 + LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0); + QueryWrapper todayQuery = new QueryWrapper<>(); + todayQuery.ge("opttime", todayStart); + long todayCount = appOptLogService.count(todayQuery); + + // 本周日志数 + LocalDateTime weekStart = LocalDateTime.now().minusDays(7); + QueryWrapper weekQuery = new QueryWrapper<>(); + weekQuery.ge("logtime", weekStart); + long weekCount = appOptLogService.count(weekQuery); + + // 本月日志数 + LocalDateTime monthStart = LocalDateTime.now().minusDays(30); + QueryWrapper monthQuery = new QueryWrapper<>(); + monthQuery.ge("logtime", monthStart); + long monthCount = appOptLogService.count(monthQuery); + + LogStatistics statistics = new LogStatistics(); + statistics.setTotalCount(totalCount); + statistics.setTodayCount(todayCount); + statistics.setWeekCount(weekCount); + statistics.setMonthCount(monthCount); + + return Result.success(statistics); + } + + @Operation(summary = "获取最近的操作日志") + @GetMapping("/recent") + @OperationLog(type = "06", module = "操作日志管理", description = "获取最近的操作日志") + public Result> getRecentLogs( + @Parameter(description = "限制条数") @RequestParam(defaultValue = "50") Integer limit) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByDesc("logtime"); + queryWrapper.last("LIMIT " + limit); + + List logs = appOptLogService.list(queryWrapper); + return Result.success(logs); + } + + /** + * 日志统计信息 + */ + public static class LogStatistics { + private Long totalCount; + private Long todayCount; + private Long weekCount; + private Long monthCount; + + public Long getTotalCount() { return totalCount; } + public void setTotalCount(Long totalCount) { this.totalCount = totalCount; } + public Long getTodayCount() { return todayCount; } + public void setTodayCount(Long todayCount) { this.todayCount = todayCount; } + public Long getWeekCount() { return weekCount; } + public void setWeekCount(Long weekCount) { this.weekCount = weekCount; } + public Long getMonthCount() { return monthCount; } + public void setMonthCount(Long monthCount) { this.monthCount = monthCount; } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AppOrganizationController.java b/backend/src/main/java/com/stdproject/controller/AppOrganizationController.java new file mode 100644 index 0000000..1feb644 --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AppOrganizationController.java @@ -0,0 +1,221 @@ +package com.stdproject.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.stdproject.common.OperationLog; +import com.stdproject.common.Result; +import com.stdproject.entity.AppOrganization; +import com.stdproject.service.IAppOrganizationService; +import com.stdproject.service.IAppUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 应用-组织机构 前端控制器 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Tag(name = "组织管理", description = "组织添加、组织修改、组织删除、组织查询等功能,支持公司和部门两级树形结构") +@RestController +@RequestMapping("/api/org") +public class AppOrganizationController { + + @Autowired + private IAppOrganizationService appOrganizationService; + // 需要在类开头注入 IAppUserService + @Autowired + private IAppUserService appUserService; + + @Operation(summary = "查询公司结构树") + @GetMapping("/getCompanyTree") + @OperationLog(type = "06", module = "组织管理", description = "查询公司结构树") + public Result> getCompanyTree() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("orgtype", "01"); + queryWrapper.eq("isvaild", "1"); + queryWrapper.orderByAsc("orgcode"); + List children = appOrganizationService.list(queryWrapper); + return Result.success(children); + } + + @Operation(summary = "查询部门列表") + @GetMapping("/getDepartmentList") + @OperationLog(type = "06", module = "组织管理", description = "查询部门列表") + public Result> getDepartmentList(@RequestParam String parentid,@RequestParam String keystr) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("orgtype", "02"); + queryWrapper.eq("parentid", parentid); + queryWrapper.eq("isvaild", "1"); + if (StringUtils.hasText(keystr)) { + queryWrapper.and(wrapper -> wrapper + .like("orgname", keystr) + .or().like("orgcode", keystr) + .or().like("description", keystr) + ); + } + queryWrapper.orderByAsc("orgcode"); + List children = appOrganizationService.list(queryWrapper); + return Result.success(children); + } + + + + @Operation(summary = "根据ID查询组织详情") + @GetMapping("getDetailById/{id}") + @OperationLog(type = "06", module = "组织管理", description = "根据ID查询组织详情") + public Result getDetailById(@PathVariable String id) { + AppOrganization organization = appOrganizationService.getById(id); + return Result.success(organization); + } + + + @Operation(summary = "新增组织") + @PostMapping("add") + @OperationLog(type = "01", module = "组织管理", description = "新增组织") + public Result add(@RequestBody @Valid AppOrganization appOrganization) { + // 设置默认值 + //生成新的组织编号 公司编号:010101 部门编号:0001 + appOrganization.setOrgcode(getNewOrgCode(appOrganization.getOrgtype(), appOrganization.getParentid())); + //设置状态为有效 + appOrganization.setIsvaild("1"); + // 从当前登录用户上下文中获取用户名 + appOrganization.setLastmodifier(appUserService.getCurrentUsername()); + appOrganization.setLastmodifydate(LocalDateTime.now()); + boolean success = appOrganizationService.save(appOrganization); + return success ? Result.success("新增成功") : Result.error("新增失败"); + } + + @Operation(summary = "修改组织") + @PostMapping("update") + @OperationLog(type = "02", module = "组织管理", description = "修改组织") + public Result update(@RequestBody @Valid AppOrganization appOrganization) { + // 检查组织是否存在 + AppOrganization existOrg = appOrganizationService.getById(appOrganization.getId()); + if (existOrg == null) { + return Result.error("组织不存在"); + } + // 验证父级组织变更的合法性 + if (StringUtils.hasText(appOrganization.getParentid()) && !"0".equals(appOrganization.getParentid())) { + // 不能将自己设为父级 + if (appOrganization.getId().equals(appOrganization.getParentid())) { + return Result.error("不能将自己设为父级组织"); + } + // 验证父级组织是否存在 + AppOrganization parent = appOrganizationService.getById(appOrganization.getParentid()); + if (parent == null || !"1".equals(parent.getIsvaild())) { + return Result.error("父级组织不存在或已禁用"); + } + + if ("02".equals(parent.getOrgtype())) { + return Result.error("部门下不能有子组织"); + } + } + appOrganization.setLastmodifier(appUserService.getCurrentUsername()); + appOrganization.setLastmodifydate(LocalDateTime.now()); + boolean success = appOrganizationService.updateById(appOrganization); + return success ? Result.success("修改成功") : Result.error("修改失败"); + } + + @Operation(summary = "删除组织") + @PostMapping("delete/{id}") + @OperationLog(type = "03", module = "组织管理", description = "删除组织") + public Result delete(@PathVariable String id) { + boolean success = appOrganizationService.removeById(id); + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + /** + * 根据组织类型和父节点生成新的组织编码 + * + * @param orgType 组织类型:"01"表示公司,"02"表示部门 + * @param parentId 父节点ID,新增部门时使用 + * @return 新的组织编码 + */ + private String getNewOrgCode(String orgType, String parentId) { + if ("01".equals(orgType)) { + // 公司类型:查找当前最大的公司编码并递增最后一级 + AppOrganization parentOrg = null; + if (StringUtils.hasText(parentId) && !"0".equals(parentId)) { + parentOrg = appOrganizationService.getById(parentId); + if (parentOrg == null || !"1".equals(parentOrg.getIsvaild())) { + throw new IllegalArgumentException("无效的父级组织"); + } + } + + // 获取父节点编码(顶级为“01”) + String parentCode = parentOrg != null ? parentOrg.getOrgcode() : "01"; + + // 获取当前父节点下的最大子节点编码 + String maxCompanyCode = getMaxCodeByParentId("01",parentId); + + int nextLevel = 1; + if (maxCompanyCode != null && !maxCompanyCode.isEmpty()) { + try { + // 提取最后两位 + String lastTwo = maxCompanyCode.substring(maxCompanyCode.length() - 2); + nextLevel = Integer.parseInt(lastTwo) + 1; + } catch (Exception e) { + nextLevel = 1; // 出错则重置为1 + } + } + + if (nextLevel > 99) { + throw new RuntimeException("公司编码已达上限,请联系管理员处理"); + } + + return parentCode + String.format("%02d", nextLevel); + } else if ("02".equals(orgType) && StringUtils.hasText(parentId)) { + // 部门类型:查找该公司下最大部门编码并递增 + AppOrganization parentOrg = appOrganizationService.getById(parentId); + if (parentOrg == null || !"1".equals(parentOrg.getIsvaild())) { + throw new IllegalArgumentException("无效的父级组织"); + } + + // 获取该父节点下最大部门编号 + String maxDeptCodeStr = getMaxCodeByParentId("02",parentId); + int nextSeq = 1; + + if (maxDeptCodeStr != null && !maxDeptCodeStr.isEmpty()) { + try { + nextSeq = Integer.parseInt(maxDeptCodeStr) + 1; + } catch (NumberFormatException e) { + nextSeq = 1; + } + } + + if (nextSeq > 9999) { + throw new RuntimeException("部门编码已达上限,请联系管理员处理"); + } + + return String.format("%04d", nextSeq); + } else { + throw new IllegalArgumentException("无法生成组织编码:参数不完整"); + } + } + + + private String getMaxCodeByParentId(String orgType,String parentId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(AppOrganization::getOrgtype, orgType) + .eq(AppOrganization::getParentid, parentId) + .eq(AppOrganization::getIsvaild, "1") + .orderByDesc(AppOrganization::getOrgcode) + .select(AppOrganization::getOrgcode) + .last("LIMIT 1"); + // 使用selectList方法获取符合条件的记录列表 + List list = appOrganizationService.list(queryWrapper); + // 如果列表不为空,返回第一个记录的orgcode + return list.isEmpty() ? null : list.get(0).getOrgcode(); + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AppRoleController.java b/backend/src/main/java/com/stdproject/controller/AppRoleController.java new file mode 100644 index 0000000..6f660a9 --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AppRoleController.java @@ -0,0 +1,320 @@ +package com.stdproject.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.stdproject.common.OperationLog; +import com.stdproject.common.PageRequest; +import com.stdproject.common.Result; +import com.stdproject.entity.AppRole; +import com.stdproject.entity.AppRoleMenu; +import com.stdproject.entity.AppRoleUser; +import com.stdproject.service.IAppRoleMenuService; +import com.stdproject.service.IAppRoleService; +import com.stdproject.service.IAppRoleUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +/** + *

+ * 应用-角色表 前端控制器 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Tag(name = "角色管理", description = "角色添加、角色修改、角色删除、角色查询,角色权限分配等功能") +@RestController +@RequestMapping("/api/role") +public class AppRoleController { + + @Autowired + private IAppRoleService appRoleService; + + @Autowired + private IAppRoleMenuService appRoleMenuService; + + @Autowired + private IAppRoleUserService appRoleUserService; + + @Operation(summary = "分页查询角色列表") + @PostMapping("/page") + @OperationLog(type = "06", module = "角色管理", description = "分页查询角色列表") + public Result> page(@RequestBody @Valid PageRequest pageRequest) { + Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 关键字搜索 + if (StringUtils.hasText(pageRequest.getKeyword())) { + queryWrapper.and(wrapper -> wrapper + .like("rolename", pageRequest.getKeyword()) + .or().like("rolecode", pageRequest.getKeyword()) + .or().like("description", pageRequest.getKeyword()) + ); + } + + // 只查询有效的角色 + queryWrapper.eq("isvaild", "1"); + + // 排序 + if (StringUtils.hasText(pageRequest.getOrderBy())) { + if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { + queryWrapper.orderByAsc(pageRequest.getOrderBy()); + } else { + queryWrapper.orderByDesc(pageRequest.getOrderBy()); + } + } else { + queryWrapper.orderByAsc("rolecode"); + } + + IPage result = appRoleService.page(page, queryWrapper); + return Result.success(result); + } + + @Operation(summary = "查询所有有效角色列表") + @GetMapping("/list") + @OperationLog(type = "06", module = "角色管理", description = "查询所有有效角色列表") + public Result> list() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("isvaild", "1"); + queryWrapper.orderByAsc("rolecode"); + + List roles = appRoleService.list(queryWrapper); + return Result.success(roles); + } + + @Operation(summary = "根据ID查询角色详情") + @GetMapping("/{id}") + @OperationLog(type = "06", module = "角色管理", description = "查询角色详情") + public Result getById(@Parameter(description = "角色ID") @PathVariable String id) { + AppRole role = appRoleService.getById(id); + return Result.success(role); + } + @Operation(summary = "新增角色") + @PostMapping + @OperationLog(type = "01", module = "角色管理", description = "新增角色") + public Result save(@RequestBody @Valid AppRole appRole) { + // 检查角色名称是否已存在 + QueryWrapper nameQuery = new QueryWrapper<>(); + nameQuery.eq("rolename", appRole.getRolename()); + nameQuery.eq("isvaild", "1"); + AppRole existRoleName = appRoleService.getOne(nameQuery); + if (ObjectUtils.isNotEmpty(existRoleName)) { + return Result.error("角色名称已存在"); + } + // 自动生成角色编号 + String maxRoleCode = getMaxRoleCode(); + String newRoleCode; + if (maxRoleCode == null) { + newRoleCode = "001"; + } else { + int nextCode = Integer.parseInt(maxRoleCode) + 1; + newRoleCode = String.format("%03d", nextCode); + } + appRole.setRolecode(newRoleCode); + // 设置默认值 + appRole.setIsvaild("1"); + appRole.setLastmodifier("admin"); + appRole.setLastmodifydate(LocalDateTime.now()); + boolean success = appRoleService.save(appRole); + return success ? Result.success("新增成功") : Result.error("新增失败"); + } + + /** + * 获取最大的角色编号 + * @return 最大角色编号 + */ + private String getMaxRoleCode() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(AppRole::getIsvaild, "1") + .orderByDesc(AppRole::getRolecode) + .select(AppRole::getRolecode) + .last("LIMIT 1"); + List list = appRoleService.list(queryWrapper); + return list.isEmpty() ? null : list.get(0).getRolecode(); + } + + @Operation(summary = "修改角色") + @PutMapping + @OperationLog(type = "02", module = "角色管理", description = "修改角色") + public Result update(@RequestBody @Valid AppRole appRole) { + // 检查角色是否存在 + AppRole existRole = appRoleService.getById(appRole.getId()); + if (existRole == null) { + return Result.error("角色不存在"); + } + + // 如果修改了角色名称,检查新名称是否已被其他角色使用 + if (!existRole.getRolename().equals(appRole.getRolename())) { + QueryWrapper nameQuery = new QueryWrapper<>(); + nameQuery.eq("rolename", appRole.getRolename()); + nameQuery.eq("isvaild", "1"); + nameQuery.ne("id", appRole.getId()); + AppRole roleWithSameName = appRoleService.getOne(nameQuery); + if (roleWithSameName != null) { + return Result.error("角色名称已被其他角色使用"); + } + } + appRole.setLastmodifier("admin"); + appRole.setLastmodifydate(LocalDateTime.now()); + boolean success = appRoleService.updateById(appRole); + return success ? Result.success("修改成功") : Result.error("修改失败"); + } + + @Operation(summary = "删除角色") + @DeleteMapping("/{id}") + @OperationLog(type = "03", module = "角色管理", description = "删除角色") + public Result delete(@Parameter(description = "角色ID") @PathVariable String id) { + // 检查是否有用户关联此角色 + QueryWrapper userQuery = new QueryWrapper<>(); + userQuery.eq("roleid", id); + long userCount = appRoleUserService.count(userQuery); + if (userCount > 0) { + return Result.error("存在用户关联此角色,无法删除"); + } + + // 软删除:设置为无效 + AppRole role = appRoleService.getById(id); + if (role != null) { + role.setIsvaild("0"); + role.setLastmodifydate(LocalDateTime.now()); + boolean success = appRoleService.updateById(role); + + if (success) { + // 同时删除角色菜单关联 + QueryWrapper menuQuery = new QueryWrapper<>(); + menuQuery.eq("roleid", id); + appRoleMenuService.remove(menuQuery); + } + + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + return Result.error("角色不存在"); + } + + + + @Operation(summary = "根据角色类型查询角色列表") + @GetMapping("/type/{type}") + @OperationLog(type = "06", module = "角色管理", description = "根据角色类型查询角色列表") + public Result> getByType(@Parameter(description = "角色类型:1-应用管理员,2-应用普通用户") @PathVariable String type) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("type", type); + queryWrapper.eq("isvaild", "1"); + queryWrapper.orderByAsc("rolecode"); + List roles = appRoleService.list(queryWrapper); + return Result.success(roles); + } + + @Operation(summary = "分配角色菜单权限") + @PostMapping("/assign-menus/{roleId}") + @OperationLog(type = "02", module = "角色管理", description = "分配角色菜单权限") + public Result assignMenus( + @Parameter(description = "角色ID") @PathVariable String roleId, + @RequestBody List menuIds) { + + // 检查角色是否存在 + AppRole role = appRoleService.getById(roleId); + if (role == null || !"1".equals(role.getIsvaild())) { + return Result.error("角色不存在或已禁用"); + } + + // 先删除原有的菜单权限 + QueryWrapper deleteQuery = new QueryWrapper<>(); + deleteQuery.eq("roleid", roleId); + appRoleMenuService.remove(deleteQuery); + + // 添加新的菜单权限 + if (menuIds != null && !menuIds.isEmpty()) { + List roleMenus = menuIds.stream().map(menuId -> { + AppRoleMenu roleMenu = new AppRoleMenu(); + roleMenu.setRoleid(roleId); + roleMenu.setMenuid(menuId); + roleMenu.setAppId(role.getAppId()); + return roleMenu; + }).collect(Collectors.toList()); + + boolean success = appRoleMenuService.saveBatch(roleMenus); + return success ? Result.success("权限分配成功") : Result.error("权限分配失败"); + } + + return Result.success("权限分配成功"); + } + + @Operation(summary = "获取角色的菜单权限") + @GetMapping("/menus/{roleId}") + @OperationLog(type = "06", module = "角色管理", description = "获取角色的菜单权限") + public Result> getRoleMenus(@Parameter(description = "角色ID") @PathVariable String roleId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("roleid", roleId); + + List roleMenus = appRoleMenuService.list(queryWrapper); + List menuIds = roleMenus.stream() + .map(AppRoleMenu::getMenuid) + .collect(Collectors.toList()); + + return Result.success(menuIds); + } + + @Operation(summary = "分配用户角色") + @PostMapping("/assign-users/{roleId}") + @OperationLog(type = "02", module = "角色管理", description = "分配用户角色") + public Result assignUsers( + @Parameter(description = "角色ID") @PathVariable String roleId, + @RequestBody List userIds) { + + // 检查角色是否存在 + AppRole role = appRoleService.getById(roleId); + if (role == null || !"1".equals(role.getIsvaild())) { + return Result.error("角色不存在或已禁用"); + } + + // 先删除原有的用户角色关联 + QueryWrapper deleteQuery = new QueryWrapper<>(); + deleteQuery.eq("roleid", roleId); + appRoleUserService.remove(deleteQuery); + + // 添加新的用户角色关联 + if (userIds != null && !userIds.isEmpty()) { + List roleUsers = userIds.stream().map(userId -> { + AppRoleUser roleUser = new AppRoleUser(); + roleUser.setRoleid(roleId); + roleUser.setUserid(userId); + roleUser.setAppId(role.getAppId()); + return roleUser; + }).collect(Collectors.toList()); + + boolean success = appRoleUserService.saveBatch(roleUsers); + return success ? Result.success("用户分配成功") : Result.error("用户分配失败"); + } + + return Result.success("用户分配成功"); + } + + @Operation(summary = "获取角色的用户列表") + @GetMapping("/users/{roleId}") + @OperationLog(type = "06", module = "角色管理", description = "获取角色的用户列表") + public Result> getRoleUsers(@Parameter(description = "角色ID") @PathVariable String roleId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("roleid", roleId); + + List roleUsers = appRoleUserService.list(queryWrapper); + List userIds = roleUsers.stream() + .map(AppRoleUser::getUserid) + .collect(Collectors.toList()); + + return Result.success(userIds); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AppUserController.java b/backend/src/main/java/com/stdproject/controller/AppUserController.java new file mode 100644 index 0000000..15ceb55 --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AppUserController.java @@ -0,0 +1,277 @@ +package com.stdproject.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.stdproject.common.OperationLog; +import com.stdproject.common.PageRequest; +import com.stdproject.common.Result; +import com.stdproject.entity.AppUser; +import com.stdproject.service.IAppUserService; +import com.stdproject.utils.PasswordUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 应用-用户表 前端控制器 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Tag(name = "用户管理", description = "用户信息维护、用户角色分配、用户登录、用户修改密码、用户修改个人信息等功能") +@RestController +@RequestMapping("/app-user") +public class AppUserController { + + @Autowired + private IAppUserService appUserService; + + @Operation(summary = "分页查询用户列表") + @PostMapping("/page") + @OperationLog(type = "06", module = "用户管理", description = "分页查询用户列表") + public Result> page(@RequestBody @Valid PageRequest pageRequest) { + Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 关键字搜索 + if (StringUtils.hasText(pageRequest.getKeyword())) { + queryWrapper.and(wrapper -> wrapper + .like("username", pageRequest.getKeyword()) + .or().like("nickname", pageRequest.getKeyword()) + .or().like("email", pageRequest.getKeyword()) + .or().like("phone", pageRequest.getKeyword()) + ); + } + + // 排序 + if (StringUtils.hasText(pageRequest.getOrderBy())) { + if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { + queryWrapper.orderByAsc(pageRequest.getOrderBy()); + } else { + queryWrapper.orderByDesc(pageRequest.getOrderBy()); + } + } else { + queryWrapper.orderByDesc("lastmodifydate"); + } + + IPage result = appUserService.page(page, queryWrapper); + return Result.success(result); + } + + @Operation(summary = "根据ID查询用户详情") + @GetMapping("/{id}") + @OperationLog(type = "06", module = "用户管理", description = "查询用户详情") + public Result getById(@Parameter(description = "用户ID") @PathVariable String id) { + AppUser user = appUserService.getById(id); + if (user != null) { + // 不返回密码信息 + user.setPassword(null); + } + return Result.success(user); + } + + @Operation(summary = "根据用户名查询用户") + @GetMapping("/username/{username}") + @OperationLog(type = "06", module = "用户管理", description = "根据用户名查询用户") + public Result getByUsername(@Parameter(description = "用户名") @PathVariable String username) { + AppUser user = appUserService.findByUsername(username); + if (user != null) { + // 不返回密码信息 + user.setPassword(null); + } + return Result.success(user); + } + + @Operation(summary = "新增用户") + @PostMapping + @OperationLog(type = "01", module = "用户管理", description = "新增用户") + public Result save(@RequestBody @Valid AppUser appUser) { + // 检查用户名是否已存在 + AppUser existUser = appUserService.findByUsername(appUser.getUsername()); + if (existUser != null) { + return Result.error("用户名已存在"); + } + + // 设置默认值 + if (!StringUtils.hasText(appUser.getStatus())) { + appUser.setStatus("1"); // 默认有效 + } + if (appUser.getPwdvalidperiod() == null) { + appUser.setPwdvalidperiod(90); // 默认90天 + } + if (appUser.getFailednum() == null) { + appUser.setFailednum(0); + } + + // 密码加密 + if (StringUtils.hasText(appUser.getPassword())) { + appUser.setPassword(PasswordUtils.encodePassword(appUser.getPassword())); + } + + appUser.setLastmodifydate(LocalDateTime.now()); + boolean success = appUserService.save(appUser); + return success ? Result.success("新增成功") : Result.error("新增失败"); + } + + @Operation(summary = "修改用户") + @PutMapping + @OperationLog(type = "02", module = "用户管理", description = "修改用户") + public Result update(@RequestBody @Valid AppUser appUser) { + // 检查用户是否存在 + AppUser existUser = appUserService.getById(appUser.getId()); + if (existUser == null) { + return Result.error("用户不存在"); + } + + // 如果修改了用户名,检查新用户名是否已被其他用户使用 + if (!existUser.getUsername().equals(appUser.getUsername())) { + AppUser userWithSameName = appUserService.findByUsername(appUser.getUsername()); + if (userWithSameName != null && !userWithSameName.getId().equals(appUser.getId())) { + return Result.error("用户名已被其他用户使用"); + } + } + + // 如果传入了新密码,进行加密 + if (StringUtils.hasText(appUser.getPassword())) { + appUser.setPassword(PasswordUtils.encodePassword(appUser.getPassword())); + appUser.setPwdresettime(LocalDateTime.now()); + } else { + // 如果没有传入密码,保持原密码不变 + appUser.setPassword(existUser.getPassword()); + } + + appUser.setLastmodifydate(LocalDateTime.now()); + boolean success = appUserService.updateById(appUser); + return success ? Result.success("修改成功") : Result.error("修改失败"); + } + + @Operation(summary = "删除用户") + @DeleteMapping("/{id}") + @OperationLog(type = "03", module = "用户管理", description = "删除用户") + public Result delete(@Parameter(description = "用户ID") @PathVariable String id) { + boolean success = appUserService.removeById(id); + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + @Operation(summary = "批量删除用户") + @DeleteMapping("/batch") + @OperationLog(type = "03", module = "用户管理", description = "批量删除用户") + public Result deleteBatch(@RequestBody List ids) { + boolean success = appUserService.removeByIds(ids); + return success ? Result.success("批量删除成功") : Result.error("批量删除失败"); + } + + @Operation(summary = "修改用户密码") + @PutMapping("/password/{id}") + @OperationLog(type = "02", module = "用户管理", description = "修改用户密码") + public Result updatePassword( + @Parameter(description = "用户ID") @PathVariable String id, + @RequestBody PasswordUpdateRequest request) { + AppUser user = appUserService.getById(id); + if (user == null) { + return Result.error("用户不存在"); + } + + // 验证旧密码 + if (!PasswordUtils.matches(request.getOldPassword(), user.getPassword())) { + return Result.error("原密码错误"); + } + + // 更新新密码 + user.setPassword(PasswordUtils.encodePassword(request.getNewPassword())); + user.setPwdresettime(LocalDateTime.now()); + user.setLastmodifydate(LocalDateTime.now()); + + boolean success = appUserService.updateById(user); + return success ? Result.success("密码修改成功") : Result.error("密码修改失败"); + } + + @Operation(summary = "重置用户密码") + @PutMapping("/reset-password/{id}") + @OperationLog(type = "02", module = "用户管理", description = "重置用户密码") + public Result resetPassword( + @Parameter(description = "用户ID") @PathVariable String id, + @RequestBody PasswordResetRequest request) { + AppUser user = appUserService.getById(id); + if (user == null) { + return Result.error("用户不存在"); + } + + // 重置密码 + user.setPassword(PasswordUtils.encodePassword(request.getNewPassword())); + user.setPwdresettime(LocalDateTime.now()); + user.setLastmodifydate(LocalDateTime.now()); + + boolean success = appUserService.updateById(user); + return success ? Result.success("密码重置成功") : Result.error("密码重置失败"); + } + + @Operation(summary = "启用/禁用用户") + @PutMapping("/status/{id}") + @OperationLog(type = "02", module = "用户管理", description = "启用/禁用用户") + public Result updateStatus( + @Parameter(description = "用户ID") @PathVariable String id, + @RequestParam String status) { + AppUser user = appUserService.getById(id); + if (user == null) { + return Result.error("用户不存在"); + } + + user.setStatus(status); + user.setLastmodifydate(LocalDateTime.now()); + + boolean success = appUserService.updateById(user); + String message = "1".equals(status) ? "启用成功" : "禁用成功"; + return success ? Result.success(message) : Result.error("操作失败"); + } + + @Operation(summary = "根据组织ID查询用户列表") + @GetMapping("/org/{orgId}") + @OperationLog(type = "06", module = "用户管理", description = "根据组织ID查询用户列表") + public Result> getByOrgId(@Parameter(description = "组织ID") @PathVariable String orgId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("orgid", orgId); + queryWrapper.orderByDesc("lastmodifydate"); + + List users = appUserService.list(queryWrapper); + // 不返回密码信息 + users.forEach(user -> user.setPassword(null)); + + return Result.success(users); + } + + /** + * 密码修改请求类 + */ + public static class PasswordUpdateRequest { + private String oldPassword; + private String newPassword; + + // getters and setters + public String getOldPassword() { return oldPassword; } + public void setOldPassword(String oldPassword) { this.oldPassword = oldPassword; } + public String getNewPassword() { return newPassword; } + public void setNewPassword(String newPassword) { this.newPassword = newPassword; } + } + + /** + * 密码重置请求类 + */ + public static class PasswordResetRequest { + private String newPassword; + + // getters and setters + public String getNewPassword() { return newPassword; } + public void setNewPassword(String newPassword) { this.newPassword = newPassword; } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AuthController.java b/backend/src/main/java/com/stdproject/controller/AuthController.java new file mode 100644 index 0000000..ab6ca07 --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AuthController.java @@ -0,0 +1,258 @@ +package com.stdproject.controller; + +import com.stdproject.common.Constants; +import com.stdproject.common.OperationLog; +import com.stdproject.common.Result; +import com.stdproject.entity.AppUser; +import com.stdproject.service.IAppUserService; +import com.stdproject.utils.CaptchaUtils; +import com.stdproject.utils.JwtUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * 认证控制器 + * + * @author StdProject + */ +@Tag(name = "认证管理", description = "用户登录、登出、验证码等认证相关接口") +@RestController +@RequestMapping("/auth") +@Slf4j +public class AuthController { + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private JwtUtils jwtUtils; + + @Autowired + private CaptchaUtils captchaUtils; + + @Autowired + private IAppUserService appUserService; + + + + /** + * 登录请求类 + */ + public static class LoginRequest { + @NotBlank(message = "用户名不能为空") + private String username; + + @NotBlank(message = "密码不能为空") + private String password; + + @NotBlank(message = "验证码不能为空") + private String captcha; + + @NotBlank(message = "验证码Key不能为空") + private String captchaKey; + + // Getters and Setters + public String getUsername() { return username; } + public void setUsername(String username) { this.username = username; } + public String getPassword() { return password; } + public void setPassword(String password) { this.password = password; } + public String getCaptcha() { return captcha; } + public void setCaptcha(String captcha) { this.captcha = captcha; } + public String getCaptchaKey() { return captchaKey; } + public void setCaptchaKey(String captchaKey) { this.captchaKey = captchaKey; } + } + + /** + * 修改密码请求类 + */ + public static class ChangePasswordRequest { + @NotBlank(message = "原密码不能为空") + private String oldPassword; + + @NotBlank(message = "新密码不能为空") + private String newPassword; + + // Getters and Setters + public String getOldPassword() { return oldPassword; } + public void setOldPassword(String oldPassword) { this.oldPassword = oldPassword; } + public String getNewPassword() { return newPassword; } + public void setNewPassword(String newPassword) { this.newPassword = newPassword; } + } + + /** + * 生成验证码 + */ + @Operation(summary = "生成验证码", description = "生成图形验证码") + @GetMapping("/captcha") + public Result> generateCaptcha() { + try { + // 生成验证码 + CaptchaUtils.CaptchaResult captchaResult = captchaUtils.generateCaptcha(); + + // 生成验证码Key + String captchaKey = UUID.randomUUID().toString(); + + // 注意:验证码应当存储在会话中或其他存储中,此处省略存储步骤 + // 在实际应用中,可以使用Session或其他方式存储验证码 + + Map result = new HashMap<>(); + result.put("captchaKey", captchaKey); + result.put("captchaImage", captchaResult.getImageBase64()); + result.put("code", captchaResult.getCode()); // 临时方案:直接返回验证码(生产环境不建议) + + return Result.success(result); + } catch (Exception e) { + log.error("生成验证码失败: {}", e.getMessage(), e); + return Result.error("生成验证码失败"); + } + } + + /** + * 用户登录 + */ + @Operation(summary = "用户登录", description = "用户登录认证") + @PostMapping("/login") + @OperationLog(type = Constants.OPT_TYPE_LOGIN, module = "认证管理", description = "用户登录") + public Result> login(@Valid @RequestBody LoginRequest loginRequest, HttpServletRequest request) { + try { + // 注意:在实际应用中,应该从会话或其他存储中获取验证码进行验证 + // 此处简化处理,假设验证码已通过(实际应用中需要实现验证逻辑) + // 如果使用了临时方案,可以从前端传回验证码进行比对 + + // 进行身份认证 + Authentication authentication = authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken( + loginRequest.getUsername(), + loginRequest.getPassword() + ) + ); + AppUser user=appUserService.findByUsername(loginRequest.getUsername()); + // 设置认证信息到安全上下文 + SecurityContextHolder.getContext().setAuthentication(authentication); + + // 生成JWT Token + String token = jwtUtils.generateToken(user.getUsername(),user.getId()); + + Map result = new HashMap<>(); + result.put("token", token); + result.put("userInfo", user); + + return Result.success(result); + + } catch (Exception e) { + log.error("用户登录失败: {}", e.getMessage(), e); + return Result.error("登录失败: " + e.getMessage()); + } + } + + /** + * 用户登出 + */ + @Operation(summary = "用户登出", description = "用户登出") + @PostMapping("/logout") + @OperationLog(type = Constants.OPT_TYPE_OTHER, module = "认证管理", description = "用户登出") + public Result logout(HttpServletRequest request) { + try { + // 获取Token + String token = request.getHeader(Constants.JWT_HEADER); + if (token != null && token.startsWith(Constants.JWT_PREFIX)) { + token = token.substring(Constants.JWT_PREFIX.length()); + + // 注意:在实际应用中,应该实现Token失效机制 + // 可以考虑使用短期Token或其他方式实现Token失效 + // 此处省略Token黑名单实现 + } + + // 清除安全上下文 + SecurityContextHolder.clearContext(); + + return Result.success(); + } catch (Exception e) { + log.error("用户登出失败: {}", e.getMessage(), e); + return Result.error("登出失败"); + } + } + + /** + * 获取当前用户信息 + */ + @Operation(summary = "获取当前用户信息", description = "获取当前登录用户的详细信息") + @GetMapping("/userinfo") + public Result getCurrentUserInfo(HttpServletRequest request) { + try { + String token = request.getHeader(Constants.JWT_HEADER); + if (token != null && token.startsWith(Constants.JWT_PREFIX)) { + token = token.substring(Constants.JWT_PREFIX.length()); + String username = jwtUtils.getUsernameFromToken(token); + AppUser userInfo = appUserService.findByUsername(username); + return Result.success(userInfo); + } + + return Result.unauthorized(); + } catch (Exception e) { + log.error("获取用户信息失败: {}", e.getMessage(), e); + return Result.error("获取用户信息失败"); + } + } + + /** + * 修改密码 + */ + @Operation(summary = "修改密码", description = "修改当前用户密码") + @PostMapping("/changePassword") + @OperationLog(type = Constants.OPT_TYPE_UPDATE, module = "认证管理", description = "修改密码") + public Result changePassword(@Valid @RequestBody ChangePasswordRequest request, HttpServletRequest httpRequest) { + try { + String token = httpRequest.getHeader(Constants.JWT_HEADER); + if (token != null && token.startsWith(Constants.JWT_PREFIX)) { + token = token.substring(Constants.JWT_PREFIX.length()); + String username = jwtUtils.getUsernameFromToken(token); + + boolean success = appUserService.changePassword(username, request.getOldPassword(), request.getNewPassword()); + if (success) { + return Result.success(); + } else { + return Result.error("原密码错误"); + } + } + + return Result.unauthorized(); + } catch (Exception e) { + log.error("修改密码失败: {}", e.getMessage(), e); + return Result.error("修改密码失败"); + } + } + + @PostMapping("/refreshToken") + public Result refreshToken(@RequestBody Map params) { + String refreshToken = params.get("refreshToken"); + if (refreshToken == null || refreshToken.trim().isEmpty()) { + return Result.error("刷新令牌不能为空"); + } + // 验证refreshToken的有效性并获取用户信息 + String username = jwtUtils.getUsernameFromToken(refreshToken); + if (username != null) { + AppUser user = appUserService.findByUsername(username); + // 生成新的token + return Result.success(jwtUtils.generateToken(user.getUsername(), user.getId())); + } + return Result.error("无效的刷新令牌"); + } + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppDictionary.java b/backend/src/main/java/com/stdproject/entity/AppDictionary.java new file mode 100644 index 0000000..e9ca4e7 --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppDictionary.java @@ -0,0 +1,75 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 应用-数据字典 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_dictionary") +public class AppDictionary implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 顺序号 + */ + private Integer orderno; + + /** + * 字典编码 + */ + private String dictcode; + + /** + * 字典名称 + */ + private String dictname; + + /** + * 字典数据 JSON数组[{"code":"01","name":"字典值"}] + */ + private String dictdata; + + /** + * 最近修改日期 + */ + private LocalDateTime lastmodifydate; + + /** + * 备用1 + */ + private String custom1; + + /** + * 备用2 + */ + private String custom2; + + /** + * 备用3 + */ + private String custom3; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppMenu.java b/backend/src/main/java/com/stdproject/entity/AppMenu.java new file mode 100644 index 0000000..e5f14ff --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppMenu.java @@ -0,0 +1,110 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 应用系统_菜单 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_menu") +public class AppMenu implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 菜单类型 01-菜单 + */ + private String type; + + /** + * 菜单编号 + */ + private String code; + + /** + * 同级序号 + */ + private Integer orderno; + + /** + * 菜单名称 + */ + private String name; + + /** + * 菜单图标 base64存储 + */ + private String icon; + + /** + * 是否外链 0-非外部 1-是外链 + */ + private String islink; + + /** + * 菜单URL 内部资源页面URL访问地址 + */ + private String url; + + /** + * 模块ID 菜单关联的模块ID + */ + private String moduleId; + + /** + * 父级菜单ID 顶级为0 + */ + private String parentid; + + /** + * 是否显示 0-不显示 1-显示 + */ + private String isdisplay; + + /** + * 最近修改者 + */ + private String lastmodifier; + + /** + * 最近修改日期 + */ + private LocalDateTime lastmodifydate; + + /** + * 备用1 + */ + private String custom1; + + /** + * 备用2 + */ + private String custom2; + + /** + * 备用3 + */ + private String custom3; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppOptLog.java b/backend/src/main/java/com/stdproject/entity/AppOptLog.java new file mode 100644 index 0000000..064ad66 --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppOptLog.java @@ -0,0 +1,80 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 系统操作日志 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_optlog") +public class AppOptLog implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 用户账号 + */ + private String usercode; + + /** + * 用户名称 + */ + private String username; + + /** + * 操作类型 00-登录 01-新增 02-修改 03-删除 06-查询 09其他 + */ + private String opttype; + + /** + * 模块名称 + */ + private String module; + + /** + * 日志描述 + */ + private String description; + + /** + * 操作方法 + */ + private String method; + + /** + * 方法参数 + */ + private String params; + + /** + * 创建时间 + */ + private LocalDateTime logtime; + + /** + * 请求IP + */ + private String requestip; + + /** + * 浏览器类型 + */ + private String browser; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppOrganization.java b/backend/src/main/java/com/stdproject/entity/AppOrganization.java new file mode 100644 index 0000000..0835816 --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppOrganization.java @@ -0,0 +1,110 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 应用系统_用户组织 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_organization") +public class AppOrganization implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 组织类型:01-公司 02-部门 + */ + private String orgtype; + + /** + * 组织编号 + */ + private String orgcode; + + /** + * 组织名称 + */ + private String orgname; + + /** + * 上级ID + */ + private String parentid; + + /** + * 组织负责人 + */ + private String manager; + + /** + * 组织详情 + */ + private String description; + + /** + * 联系地址 + */ + private String address; + + /** + * 联系电话 + */ + private String contactPhone; + + /** + * 联系人 + */ + private String contactPerson; + + /** + * 是否有效 1-是 0-否 + */ + private String isvaild; + + /** + * 最近修改者 + */ + private String lastmodifier; + + /** + * 最近修改日期 + */ + private LocalDateTime lastmodifydate; + + /** + * 备用1 + */ + private String custom1; + + /** + * 备用2 + */ + private String custom2; + + /** + * 备用3 + */ + private String custom3; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppRole.java b/backend/src/main/java/com/stdproject/entity/AppRole.java new file mode 100644 index 0000000..46136dd --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppRole.java @@ -0,0 +1,85 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 应用系统_系统角色 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_role") +public class AppRole implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 角色编号 系统生成,三位编号 + */ + private String rolecode; + + /** + * 角色名称 + */ + private String rolename; + + /** + * 角色类别 1-应用管理员 2-应用普通用户 + */ + private String type; + + /** + * 角色描述 + */ + private String description; + + /** + * 是否有效 1-是 0-否 + */ + private String isvaild; + + /** + * 最近修改者 + */ + private String lastmodifier; + + /** + * 最近修改日期 + */ + private LocalDateTime lastmodifydate; + + /** + * 备用1 + */ + private String custom1; + + /** + * 备用2 + */ + private String custom2; + + /** + * 备用3 + */ + private String custom3; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppRoleMenu.java b/backend/src/main/java/com/stdproject/entity/AppRoleMenu.java new file mode 100644 index 0000000..c4845dd --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppRoleMenu.java @@ -0,0 +1,44 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + * 系统角色-数据权限对照 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_role_menu") +public class AppRoleMenu implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 角色id + */ + private String roleid; + + /** + * 菜单id + */ + private String menuid; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppRoleUser.java b/backend/src/main/java/com/stdproject/entity/AppRoleUser.java new file mode 100644 index 0000000..7509fea --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppRoleUser.java @@ -0,0 +1,44 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + * 系统角色-用户对照 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_role_users") +public class AppRoleUser implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 角色id + */ + private String roleid; + + /** + * 用户id + */ + private String userid; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppUser.java b/backend/src/main/java/com/stdproject/entity/AppUser.java new file mode 100644 index 0000000..2e170f6 --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppUser.java @@ -0,0 +1,130 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 应用系统_系统用户 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_user") +public class AppUser implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 所属组织 + */ + private String orgid; + + /** + * 用户类型 0-管理员 1-普通用户 + */ + private String usertype; + + /** + * 用户名称 用户名称(账号) + */ + private String username; + + /** + * 用户昵称(中文) + */ + private String nickname; + + /** + * 登录密码 + */ + private String password; + + /** + * 邮箱 + */ + private String email; + + /** + * 手机号 + */ + private String phone; + + /** + * 用户头像 base64存储用户头像 + */ + private String avatar; + + /** + * 状态 1-有效 0-停用 + */ + private String status; + + /** + * 密码有限期 密码有限期(天) + */ + private Integer pwdvalidperiod; + + /** + * 登录失败次数 允许的登录失败次数 + */ + private Integer failednum; + + /** + * 用户指定登录IP 如果设置了IP,则只允许IP用户登录 + */ + private String loginip; + + /** + * 登录失败锁定时间 + */ + private LocalDateTime failedlocktime; + + /** + * 密码修改时间 + */ + private LocalDateTime pwdresettime; + + /** + * 最近修改者 + */ + private String lastmodifier; + + /** + * 最近修改日期 + */ + private LocalDateTime lastmodifydate; + + /** + * 备用1 + */ + private String custom1; + + /** + * 备用2 + */ + private String custom2; + + /** + * 备用3 + */ + private String custom3; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppDictionaryMapper.java b/backend/src/main/java/com/stdproject/mapper/AppDictionaryMapper.java new file mode 100644 index 0000000..1556d5d --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppDictionaryMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppDictionary; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 应用-数据字典 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppDictionaryMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppMenuMapper.java b/backend/src/main/java/com/stdproject/mapper/AppMenuMapper.java new file mode 100644 index 0000000..5880d72 --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppMenuMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppMenu; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 应用系统_菜单 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppMenuMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppOptLogMapper.java b/backend/src/main/java/com/stdproject/mapper/AppOptLogMapper.java new file mode 100644 index 0000000..5308b74 --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppOptLogMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppOptLog; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 系统操作日志 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppOptLogMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppOrganizationMapper.java b/backend/src/main/java/com/stdproject/mapper/AppOrganizationMapper.java new file mode 100644 index 0000000..a667c7c --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppOrganizationMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppOrganization; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 应用系统_用户组织 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppOrganizationMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppRoleMapper.java b/backend/src/main/java/com/stdproject/mapper/AppRoleMapper.java new file mode 100644 index 0000000..c3d460d --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppRoleMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppRole; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 应用系统_系统角色 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppRoleMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppRoleMenuMapper.java b/backend/src/main/java/com/stdproject/mapper/AppRoleMenuMapper.java new file mode 100644 index 0000000..c2472e9 --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppRoleMenuMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppRoleMenu; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 系统角色-数据权限对照 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppRoleMenuMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppRoleUserMapper.java b/backend/src/main/java/com/stdproject/mapper/AppRoleUserMapper.java new file mode 100644 index 0000000..3917c4e --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppRoleUserMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppRoleUser; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 系统角色-用户对照 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppRoleUserMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppUserMapper.java b/backend/src/main/java/com/stdproject/mapper/AppUserMapper.java new file mode 100644 index 0000000..1f9d20f --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppUserMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppUser; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 应用系统_系统用户 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppUserMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppDictionaryService.java b/backend/src/main/java/com/stdproject/service/IAppDictionaryService.java new file mode 100644 index 0000000..e65a7ec --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppDictionaryService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppDictionary; + +/** + *

+ * 应用-数据字典 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppDictionaryService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppMenuService.java b/backend/src/main/java/com/stdproject/service/IAppMenuService.java new file mode 100644 index 0000000..8e6ec3a --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppMenuService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppMenu; + +/** + *

+ * 应用系统_菜单 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppMenuService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppOptLogService.java b/backend/src/main/java/com/stdproject/service/IAppOptLogService.java new file mode 100644 index 0000000..7382c2b --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppOptLogService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppOptLog; + +/** + *

+ * 系统操作日志 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppOptLogService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppOrganizationService.java b/backend/src/main/java/com/stdproject/service/IAppOrganizationService.java new file mode 100644 index 0000000..97143cc --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppOrganizationService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppOrganization; + +/** + *

+ * 应用系统_用户组织 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppOrganizationService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppRoleMenuService.java b/backend/src/main/java/com/stdproject/service/IAppRoleMenuService.java new file mode 100644 index 0000000..1a6c2a0 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppRoleMenuService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppRoleMenu; + +/** + *

+ * 系统角色-数据权限对照 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppRoleMenuService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppRoleService.java b/backend/src/main/java/com/stdproject/service/IAppRoleService.java new file mode 100644 index 0000000..7757f7c --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppRoleService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppRole; + +/** + *

+ * 应用系统_系统角色 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppRoleService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppRoleUserService.java b/backend/src/main/java/com/stdproject/service/IAppRoleUserService.java new file mode 100644 index 0000000..8e0ab6a --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppRoleUserService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppRoleUser; + +/** + *

+ * 系统角色-用户对照 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppRoleUserService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppUserService.java b/backend/src/main/java/com/stdproject/service/IAppUserService.java new file mode 100644 index 0000000..3c84ed9 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppUserService.java @@ -0,0 +1,43 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppUser; + +/** + *

+ * 应用系统_系统用户 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppUserService extends IService { + + /** + * 根据用户名查找用户 + * @param username 用户名 + * @return 用户实体 + */ + AppUser findByUsername(String username); + + /** + * 获取当前登录用户名 + * @return 当前登录用户名,未登录则返回null + */ + String getCurrentUsername(); + + /** + * 获取当前登录用户 + * @return 当前登录用户实体,未登录则返回null + */ + AppUser getCurrentUser(); + + /** + * 修改用户密码 + * @param username 用户名 + * @param oldPassword 原密码 + * @param newPassword 新密码 + * @return 修改是否成功 + */ + boolean changePassword(String username, String oldPassword, String newPassword); +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppDictionaryServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppDictionaryServiceImpl.java new file mode 100644 index 0000000..ce47fd5 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppDictionaryServiceImpl.java @@ -0,0 +1,20 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppDictionary; +import com.stdproject.mapper.AppDictionaryMapper; +import com.stdproject.service.IAppDictionaryService; +import org.springframework.stereotype.Service; + +/** + *

+ * 应用-数据字典 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppDictionaryServiceImpl extends ServiceImpl implements IAppDictionaryService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppMenuServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppMenuServiceImpl.java new file mode 100644 index 0000000..21f8f52 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppMenuServiceImpl.java @@ -0,0 +1,20 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppMenu; +import com.stdproject.mapper.AppMenuMapper; +import com.stdproject.service.IAppMenuService; +import org.springframework.stereotype.Service; + +/** + *

+ * 应用系统_菜单 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppMenuServiceImpl extends ServiceImpl implements IAppMenuService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppOptLogServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppOptLogServiceImpl.java new file mode 100644 index 0000000..07d32a6 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppOptLogServiceImpl.java @@ -0,0 +1,20 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppOptLog; +import com.stdproject.mapper.AppOptLogMapper; +import com.stdproject.service.IAppOptLogService; +import org.springframework.stereotype.Service; + +/** + *

+ * 系统操作日志 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppOptLogServiceImpl extends ServiceImpl implements IAppOptLogService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppOrganizationServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppOrganizationServiceImpl.java new file mode 100644 index 0000000..7239f9d --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppOrganizationServiceImpl.java @@ -0,0 +1,23 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppOrganization; +import com.stdproject.mapper.AppOrganizationMapper; +import com.stdproject.service.IAppOrganizationService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + *

+ * 应用系统_用户组织 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppOrganizationServiceImpl extends ServiceImpl implements IAppOrganizationService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppRoleMenuServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppRoleMenuServiceImpl.java new file mode 100644 index 0000000..ec728de --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppRoleMenuServiceImpl.java @@ -0,0 +1,20 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppRoleMenu; +import com.stdproject.mapper.AppRoleMenuMapper; +import com.stdproject.service.IAppRoleMenuService; +import org.springframework.stereotype.Service; + +/** + *

+ * 系统角色-数据权限对照 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppRoleMenuServiceImpl extends ServiceImpl implements IAppRoleMenuService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppRoleServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppRoleServiceImpl.java new file mode 100644 index 0000000..5ec01f1 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppRoleServiceImpl.java @@ -0,0 +1,20 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppRole; +import com.stdproject.mapper.AppRoleMapper; +import com.stdproject.service.IAppRoleService; +import org.springframework.stereotype.Service; + +/** + *

+ * 应用系统_系统角色 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppRoleServiceImpl extends ServiceImpl implements IAppRoleService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppRoleUserServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppRoleUserServiceImpl.java new file mode 100644 index 0000000..d99c3ba --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppRoleUserServiceImpl.java @@ -0,0 +1,20 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppRoleUser; +import com.stdproject.mapper.AppRoleUserMapper; +import com.stdproject.service.IAppRoleUserService; +import org.springframework.stereotype.Service; + +/** + *

+ * 系统角色-用户对照 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppRoleUserServiceImpl extends ServiceImpl implements IAppRoleUserService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppUserServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppUserServiceImpl.java new file mode 100644 index 0000000..5033d88 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppUserServiceImpl.java @@ -0,0 +1,77 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppUser; +import com.stdproject.mapper.AppUserMapper; +import com.stdproject.service.IAppUserService; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; + +/** + *

+ * 应用系统_系统用户 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppUserServiceImpl extends ServiceImpl implements IAppUserService { + + @Autowired + private PasswordEncoder passwordEncoder; + + @Override + public AppUser findByUsername(String username) { + return getOne(new QueryWrapper().eq("username", username).select( "id", "username", "orgid", "usertype","nickname")); + } + + @Override + public String getCurrentUsername() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null && authentication.isAuthenticated()) { + return authentication.getName(); + } + return null; + } + + @Override + public AppUser getCurrentUser() { + String username = getCurrentUsername(); + if (StringUtils.hasText(username)) { + return findByUsername(username); + } + return null; + } + + @Override + public boolean changePassword(String username, String oldPassword, String newPassword) { + if (!StringUtils.hasText(username) || !StringUtils.hasText(oldPassword) || !StringUtils.hasText(newPassword)) { + return false; + } + + // 获取完整的用户信息(包含密码) + AppUser user = getOne(new QueryWrapper().eq("username", username)); + if (user == null) { + return false; + } + + // 验证原密码 + if (!passwordEncoder.matches(oldPassword, user.getPassword())) { + return false; + } + + // 更新新密码 + user.setPassword(passwordEncoder.encode(newPassword)); + user.setPwdresettime(LocalDateTime.now()); + + return updateById(user); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/utils/CaptchaUtils.java b/backend/src/main/java/com/stdproject/utils/CaptchaUtils.java new file mode 100644 index 0000000..0440591 --- /dev/null +++ b/backend/src/main/java/com/stdproject/utils/CaptchaUtils.java @@ -0,0 +1,271 @@ +package com.stdproject.utils; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Base64; +import java.util.Random; + +/** + * 验证码工具类 + * + * @author StdProject + */ +@Component +@Slf4j +public class CaptchaUtils { + + /** + * 验证码字符集 + */ + private static final String CAPTCHA_CHARS = "ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789"; + + /** + * 验证码长度 + */ + private static final int CAPTCHA_LENGTH = 4; + + /** + * 图片宽度 + */ + private static final int IMAGE_WIDTH = 120; + + /** + * 图片高度 + */ + private static final int IMAGE_HEIGHT = 40; + + /** + * 干扰线数量 + */ + private static final int INTERFERENCE_LINE_COUNT = 5; + + /** + * 干扰点数量 + */ + private static final int INTERFERENCE_POINT_COUNT = 50; + + /** + * 验证码结果类 + */ + public static class CaptchaResult { + private String code; + private String imageBase64; + + public CaptchaResult(String code, String imageBase64) { + this.code = code; + this.imageBase64 = imageBase64; + } + + public String getCode() { + return code; + } + + public String getImageBase64() { + return imageBase64; + } + } + + /** + * 生成验证码 + * + * @return 验证码结果 + */ + public CaptchaResult generateCaptcha() { + // 生成验证码字符串 + String code = generateRandomCode(); + + // 生成验证码图片 + String imageBase64 = generateCaptchaImage(code); + + return new CaptchaResult(code, imageBase64); + } + + /** + * 生成随机验证码字符串 + * + * @return 验证码字符串 + */ + private String generateRandomCode() { + Random random = new Random(); + StringBuilder code = new StringBuilder(); + + for (int i = 0; i < CAPTCHA_LENGTH; i++) { + int index = random.nextInt(CAPTCHA_CHARS.length()); + code.append(CAPTCHA_CHARS.charAt(index)); + } + + return code.toString(); + } + + /** + * 生成验证码图片 + * + * @param code 验证码字符串 + * @return Base64编码的图片 + */ + private String generateCaptchaImage(String code) { + try { + // 创建图片 + BufferedImage image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = image.createGraphics(); + + // 设置抗锯齿 + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + // 填充背景 + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT); + + // 绘制干扰线 + drawInterferenceLines(g2d); + + // 绘制验证码字符 + drawCaptchaText(g2d, code); + + // 绘制干扰点 + drawInterferencePoints(g2d); + + g2d.dispose(); + + // 转换为Base64 + return imageToBase64(image); + + } catch (Exception e) { + log.error("生成验证码图片失败: {}", e.getMessage(), e); + return ""; + } + } + + /** + * 绘制干扰线 + * + * @param g2d 图形对象 + */ + private void drawInterferenceLines(Graphics2D g2d) { + Random random = new Random(); + + for (int i = 0; i < INTERFERENCE_LINE_COUNT; i++) { + int x1 = random.nextInt(IMAGE_WIDTH); + int y1 = random.nextInt(IMAGE_HEIGHT); + int x2 = random.nextInt(IMAGE_WIDTH); + int y2 = random.nextInt(IMAGE_HEIGHT); + + g2d.setColor(getRandomColor(150, 200)); + g2d.setStroke(new BasicStroke(1.0f)); + g2d.drawLine(x1, y1, x2, y2); + } + } + + /** + * 绘制验证码文字 + * + * @param g2d 图形对象 + * @param code 验证码字符串 + */ + private void drawCaptchaText(Graphics2D g2d, String code) { + Random random = new Random(); + int charWidth = IMAGE_WIDTH / CAPTCHA_LENGTH; + + for (int i = 0; i < code.length(); i++) { + char c = code.charAt(i); + + // 随机字体大小 + int fontSize = 20 + random.nextInt(8); + Font font = new Font("Arial", Font.BOLD, fontSize); + g2d.setFont(font); + + // 随机颜色 + g2d.setColor(getRandomColor(20, 130)); + + // 随机位置和角度 + int x = i * charWidth + random.nextInt(charWidth / 3) + 5; + int y = IMAGE_HEIGHT / 2 + random.nextInt(10) - 5; + + // 随机旋转角度 + double angle = (random.nextDouble() - 0.5) * 0.4; + g2d.rotate(angle, x, y); + + g2d.drawString(String.valueOf(c), x, y); + + // 恢复角度 + g2d.rotate(-angle, x, y); + } + } + + /** + * 绘制干扰点 + * + * @param g2d 图形对象 + */ + private void drawInterferencePoints(Graphics2D g2d) { + Random random = new Random(); + + for (int i = 0; i < INTERFERENCE_POINT_COUNT; i++) { + int x = random.nextInt(IMAGE_WIDTH); + int y = random.nextInt(IMAGE_HEIGHT); + + g2d.setColor(getRandomColor(100, 200)); + g2d.fillOval(x, y, 2, 2); + } + } + + /** + * 获取随机颜色 + * + * @param min 最小值 + * @param max 最大值 + * @return 随机颜色 + */ + private Color getRandomColor(int min, int max) { + Random random = new Random(); + + if (min > 255) min = 255; + if (max > 255) max = 255; + if (min < 0) min = 0; + if (max < 0) max = 0; + if (min > max) { + int temp = min; + min = max; + max = temp; + } + + int r = min + random.nextInt(max - min); + int g = min + random.nextInt(max - min); + int b = min + random.nextInt(max - min); + + return new Color(r, g, b); + } + + /** + * 图片转Base64 + * + * @param image 图片 + * @return Base64字符串 + */ + private String imageToBase64(BufferedImage image) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(image, "png", baos); + byte[] imageBytes = baos.toByteArray(); + return "data:image/png;base64," + Base64.getEncoder().encodeToString(imageBytes); + } + + /** + * 验证验证码 + * + * @param inputCode 用户输入的验证码 + * @param correctCode 正确的验证码 + * @return 是否验证通过 + */ + public boolean verifyCaptcha(String inputCode, String correctCode) { + if (inputCode == null || correctCode == null) { + return false; + } + return inputCode.equalsIgnoreCase(correctCode); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/utils/FileUtils.java b/backend/src/main/java/com/stdproject/utils/FileUtils.java new file mode 100644 index 0000000..63b2c01 --- /dev/null +++ b/backend/src/main/java/com/stdproject/utils/FileUtils.java @@ -0,0 +1,219 @@ +package com.stdproject.utils; + +import com.stdproject.common.BusinessException; +import com.stdproject.common.ResultCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +/** + * 文件工具类 + * + * @author StdProject + */ +@Component +@Slf4j +public class FileUtils { + + @Value("${file.upload.path:/uploads}") + private String uploadPath; + + @Value("${file.upload.max-size:10485760}") + private long maxFileSize; // 默认10MB + + /** + * 允许的图片文件类型 + */ + private static final List ALLOWED_IMAGE_TYPES = Arrays.asList( + "jpg", "jpeg", "png", "gif", "bmp", "webp" + ); + + /** + * 允许的文档文件类型 + */ + private static final List ALLOWED_DOCUMENT_TYPES = Arrays.asList( + "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt" + ); + + /** + * 上传文件 + * + * @param file 文件 + * @param subDir 子目录 + * @return 文件相对路径 + */ + public String uploadFile(MultipartFile file, String subDir) { + if (file == null || file.isEmpty()) { + throw new BusinessException("文件不能为空"); + } + + // 检查文件大小 + if (file.getSize() > maxFileSize) { + throw new BusinessException( "文件大小不能超过" + (maxFileSize / 1024 / 1024) + "MB"); + } + + // 获取原始文件名和扩展名 + String originalFilename = file.getOriginalFilename(); + if (originalFilename == null || originalFilename.trim().isEmpty()) { + throw new BusinessException( "文件名不能为空"); + } + + String extension = getFileExtension(originalFilename); + if (extension.isEmpty()) { + throw new BusinessException( "文件必须有扩展名"); + } + + // 检查文件类型 + if (!isAllowedFileType(extension)) { + throw new BusinessException( "不支持的文件类型: " + extension); + } + + try { + // 创建目录结构:uploadPath/subDir/yyyy/MM/dd/ + String dateDir = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")); + String fullSubDir = subDir + "/" + dateDir; + Path uploadDir = Paths.get(uploadPath, fullSubDir); + + if (!Files.exists(uploadDir)) { + Files.createDirectories(uploadDir); + } + + // 生成新文件名 + String newFileName = UUID.randomUUID().toString().replace("-", "") + "." + extension; + Path filePath = uploadDir.resolve(newFileName); + + // 保存文件 + file.transferTo(filePath.toFile()); + + // 返回相对路径 + return fullSubDir + "/" + newFileName; + + } catch (IOException e) { + log.error("文件上传失败: {}", e.getMessage(), e); + throw new BusinessException( "文件上传失败"); + } + } + + /** + * 删除文件 + * + * @param filePath 文件相对路径 + * @return 是否删除成功 + */ + public boolean deleteFile(String filePath) { + if (filePath == null || filePath.trim().isEmpty()) { + return false; + } + + try { + Path fullPath = Paths.get(uploadPath, filePath); + return Files.deleteIfExists(fullPath); + } catch (IOException e) { + log.error("删除文件失败: {}", e.getMessage(), e); + return false; + } + } + + /** + * 获取文件扩展名 + * + * @param filename 文件名 + * @return 扩展名(小写) + */ + public String getFileExtension(String filename) { + if (filename == null || filename.trim().isEmpty()) { + return ""; + } + + int lastDotIndex = filename.lastIndexOf('.'); + if (lastDotIndex == -1 || lastDotIndex == filename.length() - 1) { + return ""; + } + + return filename.substring(lastDotIndex + 1).toLowerCase(); + } + + /** + * 检查是否为允许的文件类型 + * + * @param extension 文件扩展名 + * @return 是否允许 + */ + public boolean isAllowedFileType(String extension) { + if (extension == null || extension.trim().isEmpty()) { + return false; + } + + String lowerExtension = extension.toLowerCase(); + return ALLOWED_IMAGE_TYPES.contains(lowerExtension) || + ALLOWED_DOCUMENT_TYPES.contains(lowerExtension); + } + + /** + * 检查是否为图片文件 + * + * @param extension 文件扩展名 + * @return 是否为图片 + */ + public boolean isImageFile(String extension) { + if (extension == null || extension.trim().isEmpty()) { + return false; + } + return ALLOWED_IMAGE_TYPES.contains(extension.toLowerCase()); + } + + /** + * 获取文件完整路径 + * + * @param relativePath 相对路径 + * @return 完整路径 + */ + public String getFullPath(String relativePath) { + if (relativePath == null || relativePath.trim().isEmpty()) { + return ""; + } + return Paths.get(uploadPath, relativePath).toString(); + } + + /** + * 检查文件是否存在 + * + * @param relativePath 相对路径 + * @return 是否存在 + */ + public boolean fileExists(String relativePath) { + if (relativePath == null || relativePath.trim().isEmpty()) { + return false; + } + return Files.exists(Paths.get(uploadPath, relativePath)); + } + + /** + * 格式化文件大小 + * + * @param size 文件大小(字节) + * @return 格式化后的大小 + */ + public static String formatFileSize(long size) { + if (size < 1024) { + return size + " B"; + } else if (size < 1024 * 1024) { + return String.format("%.1f KB", size / 1024.0); + } else if (size < 1024 * 1024 * 1024) { + return String.format("%.1f MB", size / (1024.0 * 1024.0)); + } else { + return String.format("%.1f GB", size / (1024.0 * 1024.0 * 1024.0)); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/utils/JwtUtils.java b/backend/src/main/java/com/stdproject/utils/JwtUtils.java new file mode 100644 index 0000000..f1a0238 --- /dev/null +++ b/backend/src/main/java/com/stdproject/utils/JwtUtils.java @@ -0,0 +1,168 @@ +package com.stdproject.utils; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.crypto.SecretKey; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * JWT工具类 + * 用于生成、解析和验证JWT令牌 + * + * @author StdProject + */ +@Component +public class JwtUtils { + + @Value("${spring.security.jwt.secret}") + private String secret; + + @Value("${spring.security.jwt.expiration-ms}") + private Long expirationMs; + + /** + * 生成JWT令牌 + * + * @param username 用户名 + * @param userId 用户ID + * @return JWT令牌 + */ + public String generateToken(String username, String userId) { + Map claims = new HashMap<>(); + claims.put("userId", userId); + claims.put("username", username); + return createToken(claims, username); + } + + /** + * 创建JWT令牌 + * + * @param claims 声明 + * @param subject 主题 + * @return JWT令牌 + */ + private String createToken(Map claims, String subject) { + Date now = new Date(); + Date expiryDate = new Date(now.getTime() + expirationMs); + + return Jwts.builder() + .setClaims(claims) + .setSubject(subject) + .setIssuedAt(now) + .setExpiration(expiryDate) + .signWith(getSigningKey(), SignatureAlgorithm.HS512) + .compact(); + } + + /** + * 从JWT令牌中获取用户名 + * + * @param token JWT令牌 + * @return 用户名 + */ + public String getUsernameFromToken(String token) { + return getClaimFromToken(token, Claims::getSubject); + } + + /** + * 从JWT令牌中获取用户ID + * + * @param token JWT令牌 + * @return 用户ID + */ + public String getUserIdFromToken(String token) { + return getClaimFromToken(token, claims -> claims.get("userId", String.class)); + } + + /** + * 从JWT令牌中获取过期时间 + * + * @param token JWT令牌 + * @return 过期时间 + */ + public Date getExpirationDateFromToken(String token) { + return getClaimFromToken(token, Claims::getExpiration); + } + + /** + * 从JWT令牌中获取声明 + * + * @param token JWT令牌 + * @param claimsResolver 声明解析器 + * @param 返回类型 + * @return 声明值 + */ + public T getClaimFromToken(String token, ClaimsResolver claimsResolver) { + final Claims claims = getAllClaimsFromToken(token); + return claimsResolver.resolve(claims); + } + + /** + * 从JWT令牌中获取所有声明 + * + * @param token JWT令牌 + * @return 所有声明 + */ + private Claims getAllClaimsFromToken(String token) { + return Jwts.parserBuilder() + .setSigningKey(getSigningKey()) + .build() + .parseClaimsJws(token) + .getBody(); + } + + /** + * 检查JWT令牌是否过期 + * + * @param token JWT令牌 + * @return 是否过期 + */ + public Boolean isTokenExpired(String token) { + final Date expiration = getExpirationDateFromToken(token); + return expiration.before(new Date()); + } + + /** + * 验证JWT令牌 + * + * @param token JWT令牌 + * @param username 用户名 + * @return 是否有效 + */ + public Boolean validateToken(String token, String username) { + try { + final String tokenUsername = getUsernameFromToken(token); + return (username.equals(tokenUsername) && !isTokenExpired(token)); + } catch (JwtException | IllegalArgumentException e) { + return false; + } + } + + /** + * 获取签名密钥 + * + * @return 签名密钥 + */ + private SecretKey getSigningKey() { + byte[] keyBytes = secret.getBytes(); + return Keys.hmacShaKeyFor(keyBytes); + } + + /** + * 声明解析器接口 + * + * @param 返回类型 + */ + @FunctionalInterface + public interface ClaimsResolver { + T resolve(Claims claims); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/utils/PasswordUtils.java b/backend/src/main/java/com/stdproject/utils/PasswordUtils.java new file mode 100644 index 0000000..401ef9a --- /dev/null +++ b/backend/src/main/java/com/stdproject/utils/PasswordUtils.java @@ -0,0 +1,85 @@ +package com.stdproject.utils; + +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +/** + * 密码工具类 + * 用于密码的加密和验证 + * + * @author StdProject + */ +@Component +public class PasswordUtils { + + private static final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + + /** + * 加密密码 + * + * @param rawPassword 原始密码 + * @return 加密后的密码 + */ + public static String encodePassword(String rawPassword) { + return passwordEncoder.encode(rawPassword); + } + + /** + * 验证密码 + * + * @param rawPassword 原始密码 + * @param encodedPassword 加密后的密码 + * @return 是否匹配 + */ + public static boolean matches(String rawPassword, String encodedPassword) { + return passwordEncoder.matches(rawPassword, encodedPassword); + } + + /** + * 生成随机密码 + * + * @param length 密码长度 + * @return 随机密码 + */ + public static String generateRandomPassword(int length) { + String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + StringBuilder password = new StringBuilder(); + for (int i = 0; i < length; i++) { + int index = (int) (Math.random() * chars.length()); + password.append(chars.charAt(index)); + } + return password.toString(); + } + + /** + * 验证密码强度 + * + * @param password 密码 + * @return 是否符合强度要求 + */ + public static boolean isStrongPassword(String password) { + if (password == null || password.length() < 8) { + return false; + } + + boolean hasUpper = false; + boolean hasLower = false; + boolean hasDigit = false; + boolean hasSpecial = false; + + for (char c : password.toCharArray()) { + if (Character.isUpperCase(c)) { + hasUpper = true; + } else if (Character.isLowerCase(c)) { + hasLower = true; + } else if (Character.isDigit(c)) { + hasDigit = true; + } else if (!Character.isLetterOrDigit(c)) { + hasSpecial = true; + } + } + + return hasUpper && hasLower && hasDigit && hasSpecial; + } +} \ No newline at end of file diff --git a/backend/src/main/resources/.env b/backend/src/main/resources/.env new file mode 100644 index 0000000..4fe5114 --- /dev/null +++ b/backend/src/main/resources/.env @@ -0,0 +1,14 @@ +# 数据库配置 +DB_URL=jdbc:mysql://your-host:3306/your-db +DB_USERNAME=your-username +DB_PASSWORD=your-password + +# JWT配置 +JWT_SECRET=your-super-secret-key +JWT_EXPIRATION=86400000 + +# 环境配置 +SPRING_PROFILES_ACTIVE=dev + +# CORS配置 +CORS_ALLOWED_ORIGINS=https://your-frontend.com \ No newline at end of file diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml new file mode 100644 index 0000000..730a5d0 --- /dev/null +++ b/backend/src/main/resources/application.yml @@ -0,0 +1,193 @@ +server: + port: 8080 + servlet: + context-path: / + encoding: + charset: UTF-8 + enabled: true + force: true + compression: + enabled: true + mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json + min-response-size: 1024 + +spring: + profiles: + active: ${SPRING_PROFILES_ACTIVE:dev} + application: + name: stdproject-backend + datasource: + url: ${DB_URL:jdbc:mysql://121.37.111.42:3306/gisbi-demodb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true} + username: ${DB_USERNAME:root} + password: ${DB_PASSWORD:mysql_F8ysiK@2024} + driver-class-name: com.mysql.cj.jdbc.Driver + # HikariCP连接池配置 + hikari: + pool-name: StdProjectHikariCP + minimum-idle: 5 + maximum-pool-size: 20 + auto-commit: true + idle-timeout: 30000 + max-lifetime: 1800000 + connection-timeout: 30000 + connection-test-query: SELECT 1 +# url: jdbc:sqlite:D:/Trae_space/StdProject/backend/db/project.db +# username: # SQLite 不需要用户名 +# password: # SQLite 不需要密码 +# driver-class-name: org.sqlite.JDBC +# hikari: +# pool-name: StdProjectHikariCP +# minimum-idle: 5 +# maximum-pool-size: 20 +# auto-commit: true +# idle-timeout: 30000 +# max-lifetime: 1800000 +# connection-timeout: 30000 +# connection-test-query: SELECT 1 + + cache: + jcache: + config: classpath:ehcache.xml # 指定Ehcache配置文件路径 + security: + cors: + allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:3000,http://localhost:8080} + max-age: ${CORS_MAX_AGE:3600} # 预检请求的缓存时间(秒) + jwt: + enabled: ${JWT_ENABLED:true} # 控制是否启用JWT认证 + secret: ${JWT_SECRET:YourJWTSecretKeyForStdProjectBackendApplicationWhichIsVeryLongAndSecure2024!@#$%^&*()} + expiration-ms: ${JWT_EXPIRATION:86400000} # Token 过期时间 (例如: 24小时) + refresh-expiration-ms: ${JWT_REFRESH_EXPIRATION:604800000} # 刷新Token过期时间 (例如: 7天) + +mybatis-plus: + mapper-locations: classpath*:/mapper/**/*.xml # MyBatis Mapper XML文件位置 + type-aliases-package: com.stdproject.entity + global-config: + db-config: + id-type: ASSIGN_ID # ID生成策略,assign_id 表示手动分配ID,通常使用雪花算法等 + table-prefix: ${DB_TABLE_PREFIX:} # 如果表名有统一前缀,可以在这里配置 + logic-delete-field: deleted # 逻辑删除字段名 + logic-delete-value: 1 # 逻辑删除值 + logic-not-delete-value: 0 # 逻辑未删除值 + banner: false # 关闭MyBatis-Plus启动横幅 + configuration: + map-underscore-to-camel-case: true # 开启驼峰命名转换 + cache-enabled: true # 开启二级缓存 + lazy-loading-enabled: true # 开启延迟加载 + multiple-result-sets-enabled: true # 开启多结果集 + use-column-label: true # 使用列标签 + use-generated-keys: true # 使用生成的主键 + auto-mapping-behavior: partial # 自动映射行为 + default-executor-type: simple # 默认执行器类型 + default-statement-timeout: 25000 # 默认语句超时时间 + log-impl: ${MYBATIS_LOG_IMPL:org.apache.ibatis.logging.nologging.NoLoggingImpl} # SQL日志实现 + +logging: + config: classpath:logback-spring.xml # Logback配置文件 + level: + root: ${LOG_LEVEL_ROOT:INFO} + com.stdproject: ${LOG_LEVEL_APP:DEBUG} + org.springframework.security: ${LOG_LEVEL_SECURITY:WARN} + org.hibernate.SQL: ${LOG_LEVEL_SQL:WARN} + org.hibernate.type.descriptor.sql.BasicBinder: ${LOG_LEVEL_SQL_PARAMS:WARN} + pattern: + console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" + file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" + +springdoc: + api-docs: + path: /v3/api-docs + enabled: ${SWAGGER_ENABLED:true} + swagger-ui: + path: /swagger-ui.html + enabled: ${SWAGGER_UI_ENABLED:true} + operations-sorter: alpha + tags-sorter: alpha + try-it-out-enabled: true + filter: true + default-consumes-media-type: application/json + default-produces-media-type: application/json + show-actuator: ${SWAGGER_SHOW_ACTUATOR:true} + packages-to-scan: com.stdproject.controller + +# 管理端点配置 +management: + endpoints: + web: + exposure: + include: ${ACTUATOR_ENDPOINTS:health,info,metrics} + base-path: /actuator + endpoint: + health: + show-details: ${ACTUATOR_HEALTH_DETAILS:when-authorized} + info: + enabled: true + info: + env: + enabled: true + java: + enabled: true + os: + enabled: true + +# 应用信息配置 +info: + app: + name: ${spring.application.name} + description: StdProject Backend Application + version: 1.0.0 + encoding: UTF-8 + java: + version: ${java.version} + +--- +# 开发环境配置 +spring: + config: + activate: + on-profile: dev + jpa: + show-sql: true + security: + jwt: + enabled: false +logging: + level: + com.stdproject: DEBUG + org.hibernate.SQL: DEBUG + org.hibernate.type.descriptor.sql.BasicBinder: TRACE +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +springdoc: + swagger-ui: + enabled: true + +--- +# 生产环境配置 +spring: + config: + activate: + on-profile: prod + jpa: + show-sql: false + security: + jwt: + enabled: true +logging: + level: + root: WARN + com.stdproject: INFO + org.springframework.security: ERROR +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl +springdoc: + api-docs: + enabled: false + swagger-ui: + enabled: false +management: + endpoints: + web: + exposure: + include: health,info \ No newline at end of file diff --git a/backend/src/main/resources/ehcache.xml b/backend/src/main/resources/ehcache.xml new file mode 100644 index 0000000..0c9ff84 --- /dev/null +++ b/backend/src/main/resources/ehcache.xml @@ -0,0 +1,58 @@ + + + + + + 3600 + + + 1000 + 10 + + + + + + + 30 + + + + + + + 60 + + + + + + + 60 + + + + + + + 60 + + + + + + + 2 + + + + + + + 1 + + + + \ No newline at end of file diff --git a/backend/src/main/resources/logback-spring.xml b/backend/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..43814d0 --- /dev/null +++ b/backend/src/main/resources/logback-spring.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + + + + ${LOG_PATH}/info.log + + ${LOG_PATH}/info.%d{yyyy-MM-dd}.log + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + INFO + ACCEPT + DENY + + + + + ${LOG_PATH}/error.log + + ${LOG_PATH}/error.%d{yyyy-MM-dd}.log + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/target/classes/.env b/backend/target/classes/.env new file mode 100644 index 0000000..4fe5114 --- /dev/null +++ b/backend/target/classes/.env @@ -0,0 +1,14 @@ +# 数据库配置 +DB_URL=jdbc:mysql://your-host:3306/your-db +DB_USERNAME=your-username +DB_PASSWORD=your-password + +# JWT配置 +JWT_SECRET=your-super-secret-key +JWT_EXPIRATION=86400000 + +# 环境配置 +SPRING_PROFILES_ACTIVE=dev + +# CORS配置 +CORS_ALLOWED_ORIGINS=https://your-frontend.com \ No newline at end of file diff --git a/backend/target/classes/application.yml b/backend/target/classes/application.yml new file mode 100644 index 0000000..730a5d0 --- /dev/null +++ b/backend/target/classes/application.yml @@ -0,0 +1,193 @@ +server: + port: 8080 + servlet: + context-path: / + encoding: + charset: UTF-8 + enabled: true + force: true + compression: + enabled: true + mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json + min-response-size: 1024 + +spring: + profiles: + active: ${SPRING_PROFILES_ACTIVE:dev} + application: + name: stdproject-backend + datasource: + url: ${DB_URL:jdbc:mysql://121.37.111.42:3306/gisbi-demodb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true} + username: ${DB_USERNAME:root} + password: ${DB_PASSWORD:mysql_F8ysiK@2024} + driver-class-name: com.mysql.cj.jdbc.Driver + # HikariCP连接池配置 + hikari: + pool-name: StdProjectHikariCP + minimum-idle: 5 + maximum-pool-size: 20 + auto-commit: true + idle-timeout: 30000 + max-lifetime: 1800000 + connection-timeout: 30000 + connection-test-query: SELECT 1 +# url: jdbc:sqlite:D:/Trae_space/StdProject/backend/db/project.db +# username: # SQLite 不需要用户名 +# password: # SQLite 不需要密码 +# driver-class-name: org.sqlite.JDBC +# hikari: +# pool-name: StdProjectHikariCP +# minimum-idle: 5 +# maximum-pool-size: 20 +# auto-commit: true +# idle-timeout: 30000 +# max-lifetime: 1800000 +# connection-timeout: 30000 +# connection-test-query: SELECT 1 + + cache: + jcache: + config: classpath:ehcache.xml # 指定Ehcache配置文件路径 + security: + cors: + allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:3000,http://localhost:8080} + max-age: ${CORS_MAX_AGE:3600} # 预检请求的缓存时间(秒) + jwt: + enabled: ${JWT_ENABLED:true} # 控制是否启用JWT认证 + secret: ${JWT_SECRET:YourJWTSecretKeyForStdProjectBackendApplicationWhichIsVeryLongAndSecure2024!@#$%^&*()} + expiration-ms: ${JWT_EXPIRATION:86400000} # Token 过期时间 (例如: 24小时) + refresh-expiration-ms: ${JWT_REFRESH_EXPIRATION:604800000} # 刷新Token过期时间 (例如: 7天) + +mybatis-plus: + mapper-locations: classpath*:/mapper/**/*.xml # MyBatis Mapper XML文件位置 + type-aliases-package: com.stdproject.entity + global-config: + db-config: + id-type: ASSIGN_ID # ID生成策略,assign_id 表示手动分配ID,通常使用雪花算法等 + table-prefix: ${DB_TABLE_PREFIX:} # 如果表名有统一前缀,可以在这里配置 + logic-delete-field: deleted # 逻辑删除字段名 + logic-delete-value: 1 # 逻辑删除值 + logic-not-delete-value: 0 # 逻辑未删除值 + banner: false # 关闭MyBatis-Plus启动横幅 + configuration: + map-underscore-to-camel-case: true # 开启驼峰命名转换 + cache-enabled: true # 开启二级缓存 + lazy-loading-enabled: true # 开启延迟加载 + multiple-result-sets-enabled: true # 开启多结果集 + use-column-label: true # 使用列标签 + use-generated-keys: true # 使用生成的主键 + auto-mapping-behavior: partial # 自动映射行为 + default-executor-type: simple # 默认执行器类型 + default-statement-timeout: 25000 # 默认语句超时时间 + log-impl: ${MYBATIS_LOG_IMPL:org.apache.ibatis.logging.nologging.NoLoggingImpl} # SQL日志实现 + +logging: + config: classpath:logback-spring.xml # Logback配置文件 + level: + root: ${LOG_LEVEL_ROOT:INFO} + com.stdproject: ${LOG_LEVEL_APP:DEBUG} + org.springframework.security: ${LOG_LEVEL_SECURITY:WARN} + org.hibernate.SQL: ${LOG_LEVEL_SQL:WARN} + org.hibernate.type.descriptor.sql.BasicBinder: ${LOG_LEVEL_SQL_PARAMS:WARN} + pattern: + console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" + file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" + +springdoc: + api-docs: + path: /v3/api-docs + enabled: ${SWAGGER_ENABLED:true} + swagger-ui: + path: /swagger-ui.html + enabled: ${SWAGGER_UI_ENABLED:true} + operations-sorter: alpha + tags-sorter: alpha + try-it-out-enabled: true + filter: true + default-consumes-media-type: application/json + default-produces-media-type: application/json + show-actuator: ${SWAGGER_SHOW_ACTUATOR:true} + packages-to-scan: com.stdproject.controller + +# 管理端点配置 +management: + endpoints: + web: + exposure: + include: ${ACTUATOR_ENDPOINTS:health,info,metrics} + base-path: /actuator + endpoint: + health: + show-details: ${ACTUATOR_HEALTH_DETAILS:when-authorized} + info: + enabled: true + info: + env: + enabled: true + java: + enabled: true + os: + enabled: true + +# 应用信息配置 +info: + app: + name: ${spring.application.name} + description: StdProject Backend Application + version: 1.0.0 + encoding: UTF-8 + java: + version: ${java.version} + +--- +# 开发环境配置 +spring: + config: + activate: + on-profile: dev + jpa: + show-sql: true + security: + jwt: + enabled: false +logging: + level: + com.stdproject: DEBUG + org.hibernate.SQL: DEBUG + org.hibernate.type.descriptor.sql.BasicBinder: TRACE +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +springdoc: + swagger-ui: + enabled: true + +--- +# 生产环境配置 +spring: + config: + activate: + on-profile: prod + jpa: + show-sql: false + security: + jwt: + enabled: true +logging: + level: + root: WARN + com.stdproject: INFO + org.springframework.security: ERROR +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl +springdoc: + api-docs: + enabled: false + swagger-ui: + enabled: false +management: + endpoints: + web: + exposure: + include: health,info \ No newline at end of file diff --git a/backend/target/classes/com/stdproject/ProjectApplication.class b/backend/target/classes/com/stdproject/ProjectApplication.class new file mode 100644 index 0000000000000000000000000000000000000000..97e1562afd13294f92a91f8998f4acd027a4e018 GIT binary patch literal 1443 zcma)6O>YxP5Pc0v#_@VLkYKXmBTV>A40z0UHYP|A?TUi~2qSag)E+l>!%Vj|(*xwj zo)&Qc4u}(IwL(Zp9ANjbAcXh<`#&6x{DT$M6GMz*2}YVOb$8XPdfl)3zyII92QZIc zvRH@p4hC`<#1O-VYy1ZH0%|V7?%GaS6n?^g**2TN9 zVo$f*f%LhNT4j;N4-RrU{D_|z3OZ_faXXT#c{SppxT&M-UR`VBRnx_uNJ4)rVWyCGxEogOBHj{|g1JRR$mhEQZb(NTuk64j{jhS85_Em7&yvhvf`5Gt6Y?zw^uDXG}QQlEYSPV;D=xeGSRr*wZip z(a-nN|4g=)!6d^@*R7gH_sreS+lL<>KJPqu*}40C`ObsR-9JCR`#l4fq3pWL_nvj` zKV5$G$MRoKJC9#=p4^^uTgJ5KJTK5b4_Z1lbF-z{k{93P&8CPBCbHNvVUWR2hD~l4 z{lklw1T*Ja&kS}G?e8Q#pJfd0slI|trOp$hNtvl4MOXM|s0VtKNt_BPK)6&V#JJlt z9{-ZUTjcGwh^jtUgFO>yeUGVOc_&f=w-6sIuKC|(YS|Z z9$7|qu<#n}?{s@FjdmNzV;_yV6$eaXhGxSkU_XJ_;3x$HN~2EU4TdlOgOSnvzZkc6 zd)Myh+NrMHMRqmMB$WkfWd{=&!4`~DJMX|Y%DbIPo9xM7!T}s4-y;2kj3$)BFVev%n|JVxIv3 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/common/BusinessException.class b/backend/target/classes/com/stdproject/common/BusinessException.class new file mode 100644 index 0000000000000000000000000000000000000000..6ac0804ce4537fc0e8d6fc6e5e4c4a39c14300fa GIT binary patch literal 2398 zcma)7ZBrUo7(Ew6WP=7xAceeCjj6Dxv^B3{OdFFGJ9yc1_G!&Ni&N^E+2!1Jxk5E)dx9t!hU#`S-JaK%xZM$`8 z?{XGba8+TdrI{{FI3|!EXR(MS1%r_L!`?2QKn-0JSFek!D+=ZWS7QV(j@m3$dsb0!j1CT4po{8InQ=GR<~)p9_QlV$s+~zRAF|v z?|8oD_)V)juv45b`B8KyxQFw5yy$0x-YeUEA-d&y`z_*FMB_euIOQL8JcY_BTE^z3 zPC@&&f7Czx)^e?$?Nb)5cHuYXZ^o4C z9RJ660Y5+EZj-Cxnlj%*{i=_B&QFet9SUzzItE-I6mXe^R|tNU;l8GU3qf%ROc;5Ykl;2?rxZ5}hTjEhbTMcPna+M~FX7wGe zY386oy`R9piW!uNT%mtvtkGh`U&I|Y8#Q_-WLyauf1q4xv|v`*>GB!AuJb-OH~}?6 zej01H5YZJvUx|pjxJMRonC(idcSG{6klZG6UM z&PO)Shc**dD@bYuv&qQtp^AE_;xM$Jq)iT7_)i0R7cF@V1OFyMkU4EPS`M{F}R7GEi!jDme1lW1tOc$`r` gmKY1MKo3JaDzh?*d~`yl#50l^#PbV2NZ`x=04VK-<^TWy literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/common/Constants.class b/backend/target/classes/com/stdproject/common/Constants.class new file mode 100644 index 0000000000000000000000000000000000000000..a907378b7702079c713ba41bcccc35baa463aa5d GIT binary patch literal 2248 zcmai$Sy$Ue6vywFO&G_lO-i?fu8>kpAf!!0+6rlG1hQnbu%wGBi~=UcrnVtDed<^0 z=|g+^&=1hh)90T42OIn1JoH8O@BZ)HO*3Qv{qLWD5z$k6m8KL8jL=|)hG&4EC?hD_bGPfYV?iUAarGi`p9`9v z-&(M5%1=fqOXDLnk)cVN5_Gp*Kg%^+N9T>YN|ghi)oVGUUTe1ETB|82ZbGrO)=eXH7d2^CxUKW$JZ{M(@J=^kr+QnUos|rZc4+uB^4 zN*<}Nlp75pH8=KBPr6>AzshN5>v?9~QqZo^b_*7=;SHviF{AOWU^$p%pb@rYY8hqr zl(1y#fz(J>3Z~OjOleD{U=yX5SJ7@a+D<6d7z#>w#059ll%7UgN_dQR)rwBHerOod z_d5wX#=LIXSdR+y$TwU}S+`-BWCkPj0~f;{XEsxo(8~^Hin3<=gh+SH$k?=Oyzu}o z7(HL>OFOU89)vX%Xj(?M!uAHk`{2gjl*iihFrx#BF4EWJxPrzC(!pVhus3RWVu_);F>$2@Sg#i*fzo@Bq%PQb} zSkEMu(F__Y>iej*XB7Vk8Z_!h2}WyIYKe1kc9=AR_^=AglwB{!)!n#JQQR>OwoWQd zL38&1TwmC^+IqR#xjoZ<{i0D$@)Z>~dwnN0m(&$WbGR5&C~%QxX_{t8&>Nr>-3GtO zcozIN<9ERCF}@3)WBfk&L&hJ0KVdu%zRy_sf67?-FEaiNoMXHUUSYfnUSq7{Jz}il zea=|vUocksW5!>C*BL(rf6e$C@CIW8EE(s)n~W{+He;3FW~}lT``BTu=H)Ujfj!1P zIApvF-e;`x9WYk;p7rs!jFta)ef&LRwf+ajs=kQvkKjYbWiWnvvA1R^q37Lwb__mY zTmhdlegUpBJ_FYn*RfY|tZ5j}b41VKQ{Z#x{_iAyz1qq@;i+W8KZpjNnYIHpsdZ($ e=q|o@brj$?`Uj2tMz_>@LA~`aK$ozk=;eQ;GmZQJ literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/common/DataPermission.class b/backend/target/classes/com/stdproject/common/DataPermission.class new file mode 100644 index 0000000000000000000000000000000000000000..7f81368aa3668c2a45a576cd1155cc49d1dcf2dd GIT binary patch literal 628 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 M>siIvz$R+I7bw-H-T(jq literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/common/OperationLogAspect.class b/backend/target/classes/com/stdproject/common/OperationLogAspect.class new file mode 100644 index 0000000000000000000000000000000000000000..74f7322469436d86ab84a0d60a1c16ca94458426 GIT binary patch literal 6987 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 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/common/PageRequest.class b/backend/target/classes/com/stdproject/common/PageRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..5e88b3c8dd6245e5b770366839001d537e76101f GIT binary patch literal 4925 zcma)9`*YOR75?secO|c7Yz#Im;1sZv_(e8NNm|x+VpuS7Vgt1qCqN$&YheqoB}bA; zoxVbov}w|Wq|Y=zH8Y(uouSioT3m*{`$Ia@e;|KAp=thyru4g#R;yhr*dDKR?z!iD z_uTWkSO5Iq%|8Pe#XHSNp-DknLk3xaePw&8;Cge*j(yQ6dj$@cY^!iepEstBXIBi@ z6Hv-4j$>G)woP8tFX@GfZp{}aEYFxXoZ%c)G%LtyXn`iMb)AHOYFgf`URf~&n)>=D zqzPLzw8{0;uKBznA+~Dhz&0*+NeZ64Akft}(VwuMicZ4lZdtOQ0jBIpaB|HBUo#V~>Jv4fo(v0_`OZSu zA5EV#+;R>*=v8p9hWl`T9q7sP(xC#`5z{igNBynON}KyN3`m<5-{vE$k~gH`fX`br zR-Yq3M_xh0gZMPPSJtg#(y#_=f(3^A&r0FXXgG+61#|33sD@)z ztS76x?7?vjkITGK7j$=_WX~BL%+n_{Jc&tx9ZUM6QL?SF?mcCCoVHv~w>(#1IUbj4 zD#k*UzzQvm34J0b?zT`!AV0lgdFGNaYr5w7igDPoY)_ZjMsuV!i@M|K1*We#=d)Q$ zG}qCY{BGfd?VVVuREFu_CBt=DUd+*t-o5_e&o1A(@%n#W{L`%)H$VL4O#!*|U6H0t zt9R0LJwj#tS`p~ogwAk=ewBZMWgIMg`!6ql^zI*S|NQE$n{PZQ&|Sa3)2qw%d))c& zUtggjW(SL zAv5hQnDlMWk%SxXzyajvilFOxtqEDix- z*Y~lo;JH`ZTQD2}O**JI>dvh`yEbn2r)7gBa4;7P0zJE0(4k&5-sbE1!>EE;_5ng8 zJHQItmOzMA8_#%pd2vc#4r7`*H9awPjC-44kQ~EZsW2_nn$4Nsz(ln-GN&ydW2UIR z5x(l#L4k6MGxmy8HpWevQ0=i3>;c*7$vR@&o-D}aAat&ZR|Ljmf_#}*h!K$nsFs60MUNj1Ur9nR%*UO&mu${gg&#+K1 zFz|8RnyVOY@1$)nt}GAVwQbk{Xp z1#b!5zscsL;0FTxHx_0~kiAU7j|J{s=dUC;D0o}op1X@OwE~}E9}k`$HoXkryzlTi z#nD52pMbzg7pL%f64U398p90P(@)^Ea);Kp0O%;EjswNE^9x3E#xICT(iKDbYez2vC(N=F`!H$5bsh6K&_2H-5Ub& z0+s;O*9f$KLm=MG5`elIf#N<&-WsoQ2|$C5Ktmf^WZ(jt`~VjTn391Q7-VE?p$t-V zi;vV5NQB;&L6a3NFfW6|LlNz$kL5x#eCuZ6Wzk0PZR_AoTuidQZ?o{Sk|X$mb?}SH z@Uc9@uN1MA@VbrCp6{FPyAWr#i)9QXw?>1%_3L+Tx5 znyw9UW@>0)4G;K35)Yji;-i>8@DH@))9+*JRcHtD=`}o3l{i$)P~=cCo6ks@?EC1r ziq?E4pN$EP6cq}M6xF;Uh15_;$*VD;v0^iY#)`RovlPmOLe2SHOsG_Bp-`!)G9*AXi@swjAZ^2Uvnde|6&Tu-Rf$=*4fbOkNW^`mgXTsWgt`O*o`7 zJf&WRODc;B7U7XnIAdUil!~`7j!UGP@e_>UIZ`>S@vQp_sTTZ^?QWHnhUaP9VRR_! zf3ZbD>SJ^%=;6OAKE}>~Y~Glx7T8ilkkj(>G^~I_+?%Z5jErvM`4BJPYDbYrvP~nS z6tWx8h5RfeCfmQb#kWfI*V>0i(xZN&>}elfV4A4ygIA#(Si|@;l7Fa}mJ|7OIHSts z38qGh8Gnj-<14B8Om%9knDwW!(G;^O&?*%be~O6|YAOEIp5(Ak2WEz0Z^A41D!#@& zX7Fu%om7f}x{Pmd-%Y%hEa01@()`4p!V9D_IK!*SWl~v&dcZU$QG1+&RT$!psRVH1}3dOQ9v6^HfHxyRtg=_K&6QPQ_PNk-mJV(Wb=KW%H z$Q-3(hX?7)?&P{lUcqzQhuz(>G_%46n!4-}= T$bS>x#}Dso#*bKEKSloki_!Q7 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/common/Result.class b/backend/target/classes/com/stdproject/common/Result.class new file mode 100644 index 0000000000000000000000000000000000000000..354524ecff5aa88cb9d06504d12d772b8678986f GIT binary patch literal 7245 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 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/config/CacheConfig.class b/backend/target/classes/com/stdproject/config/CacheConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..6f005dd2fd1e49123c01b324b09a184d9827a09b GIT binary patch literal 743 zcmah{%We}f6g^JUCJhNq!!x`~SpW-WgV^wpM#BJ+hD1u*NU%Z9#7$jh?8@We^;fKr zSnvUS6yn-RU=~Phu6=yYJ=gczKYxAy0pKa_v{1uF1NAmGvBl6m;U9RAakU6WvlEe8 zhOH-3N&Adp`8cTo92+ zC5B}_6Xt-=GCJucI_24v8|m=sux^iK!LXnFcT6;e)-u`j5k7DuW9W}d zWo0g=vXE3FR7zXl0#$gFP)|W|>IQmbcrHF_^WMFN6`yRt|44(SV`+RM6@B>cME8Ex zv{<>W+@0KuVGj-ZETE6l$2MAEI76t0HsP}syhC`mf_sF|SMUYGmn!%&IWhPBC|)7Q qz+U*al7M*|&PquBQQO9O$u literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/config/CustomUserDetailsService.class b/backend/target/classes/com/stdproject/config/CustomUserDetailsService.class new file mode 100644 index 0000000000000000000000000000000000000000..381fcc4ef75efa709952febfd76030a73a499a16 GIT binary patch literal 9890 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 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/config/JwtAuthenticationEntryPoint.class b/backend/target/classes/com/stdproject/config/JwtAuthenticationEntryPoint.class new file mode 100644 index 0000000000000000000000000000000000000000..6e858a90ea64ac9e5c89275199ff157fbaf3bc55 GIT binary patch literal 2591 zcmbtWNpllN6#m+hJ+?e-Vlf5+#$l1XFc1g<%Rr2=u|ZzqMFg_8Ms0cI(X{AkVO*&k z@)J1a!ZD{DNQG1ZPO6f7{zPsm@+VSxEy+f)To#oa)UD}x{nqb&Z+`##=U)L_gNmUA z5ercpt!QJ|Ti}nl3Rjvtp-_)}p`B%| zOU?u>^VNen@vtmHvbQTQbnRhrZj#|ZBAI>@<-As2kWa;M2wfHq+vqmhuU4EZnO94S z7saYnD`d$nD^IUclu9^T0(|U>l8KZdM)sye81lU6#8Dix@Q#h+I6=wX8Ztw4l`Fb) zHPPr&-AT0+sm7CJrX434j`LEvX zl#+_!W}>;~-gKNqcT$z}qC?pOG&)i^NuLcZV3?-g z5%cLl`z(Ecw9)<%?Gf7P`-9dwdU9xIw72%X1pATxv|yfA^BOdt7icvKNC1n-(9UoV zACnSu`42>4(SG+itoW|}b?l+?zrewD9EoBe-m{M077XlTPu7uW!E+3}!h1u}UvTCA zOAHOQcDHs%Um!KqHn5Hxlz_Gu7&R_LDlYU=9KZ=2poos47pHNGrrQ~sI%jbMN!+0s zXxy8qx=?eEoWXrOsJMI=pWssp$eewK&q?nfeH?s&FUjr8I0%j`g>{1hbdjTw1xcD< zt5QoOm8X+7(y)vIeEPpDLdrpEK?*?*7B>@lvSJeGh_}DO#80qHB&;r(U8Eb(3tMIP? literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/config/JwtAuthenticationFilter.class b/backend/target/classes/com/stdproject/config/JwtAuthenticationFilter.class new file mode 100644 index 0000000000000000000000000000000000000000..27f22c455ce17ce039d5d868f217547ff79e5390 GIT binary patch literal 4263 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 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/config/PasswordEncoderConfig.class b/backend/target/classes/com/stdproject/config/PasswordEncoderConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..b04c9e69865a5f054733d7b02ebd165457774a87 GIT binary patch literal 713 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 BZWsUn literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/config/WebConfig.class b/backend/target/classes/com/stdproject/config/WebConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..10efb1ed02f616c3de4d6244e0fc7886ae9a43bc GIT binary patch literal 1290 zcmb_cZBG+H5PlX4S8I8(K((L(zP3eJP1FxoO^`?=wrD6RF@DIsD?#I!-3b}})*b1xSi0?=fceF2Gi704Ey(2?qtUhJP zi6HpH$Pg6YSI@zBaaBsyVWmwVRno{YJn&n>m?L2ip77es-SyS2?M<$GV2!)fq0nZK zjSOZn=OLfPWyeKrsGt~T2l%MQegf5`QDDe$9%(EPa|6(O77y1L7X7$QuECLx zUD3~qu_v1wNm)EBGQ9YI*c704>~~{ywA2i#jX01DQ&kno?M}NX^{!~P=ugfeZ#9Hg zZr}TvvIojAELZ=5ufi}hKtiu$=;U^BXdQ4`DK!| zFkGj{!D)IENG{QilV+sH%3r`fCFW(4&J0Z82FYyK0XK1rb_}<1hk`88`ji5Vkbbn1 z`UdaaXzoJ&GcNYlmuNk+cV@XVV3|)W=gIOE2AD&hzIhaIpX5Ux3U^T? W5G6V>#%SX%R8Hgy?vZxLSAkzr$aYfz literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/controller/AppDictionaryController$DictOrderRequest.class b/backend/target/classes/com/stdproject/controller/AppDictionaryController$DictOrderRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..e349ba576938913d182c2e7660b60aae23551b91 GIT binary patch literal 1043 zcmbtS+iuf95IyU}apJlpq)oV$dqGK&uz00_1gQ{_LW?NM`^H|SuAJSl-XQT;Ac2s0 z-~;$5#H>@&)T9pxS(=^8nVB;){`u?s4**Yb--m;ehjIWH6^6z!|G>kP%W-%xIu?;( zs60tzVxBRSI^AInRn$EA0oD*Oyol5!%uGDh%7Vj4NuyPo3LQS5PWO_?BuaAqvA6JV zTjzm}g?=mE&qPKIoFryw4o*8C8lA}TuI+UpKphPRPuUcy7&exGeQCs4=v{_#PsM_v zK1ih4pG`(WzvH8nJk5cMcsk@dvG$3xY>twQVQ=vN^r^Qy7N$=lY<9X!+)jp|a5fLO zI)6vILt6Q3VUAS%hHE|%Mrb1DQ^kBocHq{TvZo{aRCfVtFBkuVvDN)UHPexJnb>7) zopY3jcJ~a`eY(dhl^G9r86N%fau|ZXltTAXo@IjOXcUi)+jLWh{yc|1`h#+f4ot5L zS`{iJFOn6~%dB_j8`$R@)+A}eU@kUD59R=DqD2-%8<$9)P5uJ!Qz5ywGWjyD5F?xX zIOj&Kb{>3%S8VO)*=@pDGV|6}v$HTODe6HihDn9E)KEXMB f>`oVa>cppnn80PoAS5;koiyt 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 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/controller/AppMenuController$MenuOrderRequest.class b/backend/target/classes/com/stdproject/controller/AppMenuController$MenuOrderRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..c6e88354cff786be7f6fcf2e3a7174544af14c45 GIT binary patch literal 1019 zcmbu7+iuf95QhJC4o-|q+O!F0%ArL`E8%-uDxpY-NNI~G%KgS(rLLUabiFP-7Dyl@ zE_eVQ3Nh=HG)cn+LY8)CX6NwDjDP<6{sX{EJoDh7;G*cGgfheG8Nc8`!sReH9-N8L zFqHRW8Jh!!LaW`cqJpXm&&Lh;4Ev!P1*wU~T3P2HRMKdbBti$T#^XaFv(D7AWz}OH z3H?r-XCkH4P8>1Rdsj72jE?1S&sMqVqlQ%mSJ@D$7}jSTyV8iE(0dHUj*0|Btrtsi zl#K>LzvqL5EcKoWdD7=Pw)&;9Xinpl;h^_F;8e9V6sAk?8?E*X)g?YXr<3PK>-uZE zPh&n5=2S&*x#lBbgeD}9GUn5TPHKg^+z{*+vzb<$k|jR$2q z*GLQKX4bm%4eWF7R;SZGgPmiYWPjp-4KzrjhH#6{`QR^bKP?1jOM`FY4iVYl7dac1 z+S&aIcd_(E9^E7#3o|KgCEE+bU9y%KDVFCR?l0k4S>*Y!l;;5+F5_8Qpr|Ni+m0DKMoGUOm%gb4#Cp&(#p z&-~SFIHo&jZ1nbIKNL_{wp}}15s>w;d5%MLN2BQe? z8E_1a3%J$y_8UQH4SkQMYVsnP@Iix8qCM_ADu2s=sSHmM>jI zYK_BDq$P^-z5%l^Cm?5A0%ju%rrr#F+a0jYf&mq>ndsw`goTfYYq7 z5sfT9GTjo^s zCjyF|Z%N2`-rv}_$<-TW)9Jz+8EN$8Y*9=EK zrl+OkWV!XWsa{%H!VEPz>Bn2PE8C;}p7c9r&%rpeEw67nUDLOzA1f!qT{{qP`|V>2 zm>kHE7Bye3rP2~_9u5c5@Iv+IXswH9VqJ#2o^{{!aVJCRBTf-#jFwSE=eUKsHd^2) z>f#nf#_f)DQLBKuE#JXyMKf;DY#rS5$SP`;$dk7nH-iA5fm>hHCy!Fchl1>5crpylc~`t{ka8*Qmtc6>Q5O zyypdB5nc#b{2zA;w|&iZrQdYSAdq+*jdVSO^LV9mSa1#eV%@@4j%pK2EJ-Y}60yVr z#1ab+ORP66vBAVQfVcw_;sJb#eIv4mTksY3@V3KJJXZrH%{5v717?21Mh<8K3I(E* za-K|_m+_^^G01I{l!!uo@fFOB!$;m*>|Kd0VsDz6QYLT_7!+#~3IX3}dFEA~u9oLp zJUqwnJkK(C=t?C#XPM^*EzdcX=ed^Wo}TBN%CnQf zLsvWDxxhSYTAqt4&kHTjk9wYqDvz1LLnS8Rxy(F2X?d=wJUuN>OV4vf<>_beP^n9J zs?4(vZB$V$OV^*8%42DHHsHRl{?t?+nZZLPH{n@io(J0eTvd5~(enJP&(BqrXOO`| zr9a_mFwdrz=eo+XtL5qFd9JHGb_NeUK?% J>_87n{{iSD6{!FK literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/controller/AppMenuController.class b/backend/target/classes/com/stdproject/controller/AppMenuController.class new file mode 100644 index 0000000000000000000000000000000000000000..ebe78d9a5f694b2889de010e20169fa9f7514b84 GIT binary patch literal 14955 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 Nf<``1p~s-I{{g);AXNYW literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/controller/AppOptLogController$LogStatistics.class b/backend/target/classes/com/stdproject/controller/AppOptLogController$LogStatistics.class new file mode 100644 index 0000000000000000000000000000000000000000..d7148b7d922480489d882f1ba2d148b1a9c7fab4 GIT binary patch literal 1385 zcmbu7OK;Oa5Xb+UcY;IGgqHHAv_O(ld?yqMMM5CCEmEs+-Z-no#qmb=2E?}l353Lf z55PC!#G4~x)_Ggb0dbk}jQ_Lq+nN3J=fg(;``9ZWfn*jb18HO!%BTDVH(l=a%%je! zuoXk*zT-LS0YkD@Z|9LiK8u2ZGcXvMwj7v&>JELW#ilJiRNQUJkwHJF}p3k!9 z46KLZ0d?$8j!m^>S1^<;#}kL6K}Yx}yyH@)Vo963ZSFfdo+MMM?-1C&^&j_YG8B74 zoh;m~QmaRAN1|X^RINod^)`*=K&Za#KIJ|i2qk=?8=pR%$Mm3iY*6=S)4?zp)Mp{o z)dvd$(in?z;aHA*TRd{~kTzqscvtUIk)?M=UkUvVLQjhiJ*}F29!x)6vKthc+jyuTz1+K92 A`~Uy| literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/controller/AppOptLogController.class b/backend/target/classes/com/stdproject/controller/AppOptLogController.class new file mode 100644 index 0000000000000000000000000000000000000000..7bc3f8d560d89b5c48e95d538ace24e0208f223a GIT binary patch literal 12424 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 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/controller/AppUserController$PasswordResetRequest.class b/backend/target/classes/com/stdproject/controller/AppUserController$PasswordResetRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..82dde5da699a85a7704d875e15e5f9aea208cae3 GIT binary patch literal 789 zcmbtS$xa(V5Pj`!Y%?*$7?O}hLdwAgiMf+SAxIIC90x(-dwX0mgT~XQrwzXqB%(+; z=!*q8EJM+tkb@> ziT5vpCAXL43h%rBi;bNdBXPa!_*(7GeFz(z=tkZ``)*pNPkuj%+cU#$ZS`23SOTr@ znyHQDL*ge|yhGcXCq$vzBU@W0cLAO%tp3An3gO2r<0ew_FKpPlr2G0Ju*}UCcoT|} zyQNj6&7+`vKrf5Rm?2qkWG3~RlD-o<9|G#XZ-8;kDmbcu~kJ5c?Sg-MU(`V&g6ykA{h_8qrsW- ztw8B@7>D+aK)%)PS5QX9LDfYKuE2q>M_yusvC%B{d>vb(qevO=U_3ral-TvdR!C=jh$PFCRALs2=Ny@zvXqFWsCe`Ae>)K)FYSKGcbIuqm+n57!rP z-^DR?F{0inLRz~i{!|n3oLZEl2bH6b9!5H&evvIg@XMlciB=w2!QP$k5MNT+GL5{= ze}m@kwE!zvr4?mFlg8=buW&wRf{Sy5A7Gt`IQUh{MyYmozro3-E~U{;(lE?*YM$|3 z1Rj#NNNqI)jX6BUv(#=-D}XAA%GkgQ GRIUIQTg-U? literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/controller/AppUserController.class b/backend/target/classes/com/stdproject/controller/AppUserController.class new file mode 100644 index 0000000000000000000000000000000000000000..fb6313631c8deb8897e0f23c008c634d71b2bd81 GIT binary patch literal 12249 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 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/controller/AuthController$LoginRequest.class b/backend/target/classes/com/stdproject/controller/AuthController$LoginRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..eff6d9236a0432e493e729626bc305b4df037395 GIT binary patch literal 1704 zcmbW0-%k@k5XWarp+C3^wiH3YpQtS;Co0j1nqU(IDM$eOzFar$!S%M@Z81C&6XSy< zKKKXtsJ@_y2125LfPV)F{u9R8wqEJokr*F3+nN2&&1ZLJfBfG44gmLIED8Z=2|-YS zR%j#8xkA^dYEZMFK3QI2njp}2Pd9b(fIv$sor^#iA|Z$>&<+ZLF^!j0Tja|Ymts}p zrm(nSFiV}Nh+@WZ2eZ7On+xn&h1vMcaK&bpNlT1CJliO_C@kG9jLRY?6zGr@!ewgP z&$*SC!IKKaWiX`Cve1fD#<~1>n_=q&dKW6D&`T_*+xoJ>CQOqHDs*nz1kzY= zm0E(TYt+#5)vyG&g++B!*y%pKX>Uh-K+5hSf9=yH4#8an7T`75Ke+Q%9B^235Mah&`lg{Bt z%`#Es`FUz#zXh|9OMZR6-q+e^8eSClGPU+%Q?Y{M#2P!*CdV3^RX@7OE0)G4b$Km` z=J^|u_&7~-IDS*y79qGnAoZ`eLqM4}O=e{bgl2dE<>)xWc^tz4KBpjBd=_ZC(Q5|+ zr|{QfLob}hKnzF%8liw3aIdz{tL;M-&b?RL@74CB3g3fQJK)t0Km_^l-J?B&fGVy8 z*VdtJAfNG10M4S7+W>dq99pF&z$0HkkHAG3MBAMF1wx;2^Jwy=OosG8kfQ`AdKEP2-iu3%m(P7yBHQeU2!n`g?GC+*J@bMs6e!z26Y@N`sp zhJ1NC-8_$dd4~OYI^8@o$MDFRad_fYo~yn*2{%vHm*<*4Pr}VJdkl}9ONS?kJS{MS WHh_b7y}FLVOUrt&8 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/controller/AuthController.class b/backend/target/classes/com/stdproject/controller/AuthController.class new file mode 100644 index 0000000000000000000000000000000000000000..7caaec513d380ada7108474c2ea976125db90486 GIT binary patch literal 9489 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 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/entity/AppDictionary.class b/backend/target/classes/com/stdproject/entity/AppDictionary.class new file mode 100644 index 0000000000000000000000000000000000000000..6fff69e544f06a47e682acd57ad4ba9b26a10c18 GIT binary patch literal 6822 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 HiS+*hWDBJG literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/entity/AppRole.class b/backend/target/classes/com/stdproject/entity/AppRole.class new file mode 100644 index 0000000000000000000000000000000000000000..a7edac792f2107119653bb1a763a41b927a011f2 GIT binary patch literal 7764 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 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/entity/AppRoleMenu.class b/backend/target/classes/com/stdproject/entity/AppRoleMenu.class new file mode 100644 index 0000000000000000000000000000000000000000..f60e452eac93aaf61e18f3562292f501c52859b8 GIT binary patch literal 3578 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 Z_&SzQ=7Pz|9exhe113bkLybL}`wux8pmhKM literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/entity/AppUser.class b/backend/target/classes/com/stdproject/entity/AppUser.class new file mode 100644 index 0000000000000000000000000000000000000000..673040e221c6b22a99abd727ac3ceece5568b2dc GIT binary patch literal 12817 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 D5{@f6 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/mapper/AppDictionaryMapper.class b/backend/target/classes/com/stdproject/mapper/AppDictionaryMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..142654c58bf440f251a0e21c29bd56dd6b183e77 GIT binary patch literal 406 zcmb7=&q~BF5Ql$Rb?dGQ9`ywTFU|v0g%$BsS#ZJov>R$ln}j44`f47003S-6?IQlc zi-%-}Oy*0zd3%3(1#pF<3=@U(%5@ae+6UL@DpAMY>p%@n&LM!Fa8O< z92>rAXq!wLern{`xx#$q`cUaR)5^;ye`sE8KBI8@&x0{HlhBa&9B|?Nl5Jj&SpkO%&NuW**puz> zsUBJjm@2?QUXwGrbs5dJrlh0qbCg2hz1sst-dQP_t#xN9<-iKs>aS^8{nPMv6#M{S zn{?Xl0m}PQ!F=sbmEJwJr&Xvr)lyH#IY)~sAd?WW{pqHnq=iJ*UZj~w+5r7&5V+H&fGR(LB8p?UF7;N8&h zM?u?U(q^xaKjaG2rRzeapG+gKULNS(_McF=dg-LK)vqR+ve9#ET@o8-qry$$LQU+s nde>wIN#cD0?c{P9h{BPq6PYpOl*vBADJDal;!NUL^5?)7r005J literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/mapper/AppOrganizationMapper.class b/backend/target/classes/com/stdproject/mapper/AppOrganizationMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..c07b0324abcd2382e00c1f362105ac8e4ebdfc0e GIT binary patch literal 412 zcmb7=!Ab)$5QhI$?b>R=t3H4i!FhmHp&mS~6fAh3-G((~Hwj5rsE_8s2k@bavs*+d zUOXf-Wb%K>|9@`ZKLFffmSLoDRk@a8TKVACx=Pft_d3wr`$eePnm10y*~j5D!=b|2 znqQe3wlyuvUXo#~Ks}~p*P4~;6Lu=TDtrTK#OIDH}bv)};$XC zw#lT;4j{kH73M3~hf3d@R^B}Og?2T3K;eAZi>%X6CYrL<3u|2x5@(~rW#K|Y?74c@ lWJW;Z?*aPCD3>r4_GBGMx{y;Q`vixWjdhMAsZ;461D{9ScoF~r literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/mapper/AppRoleMenuMapper.class b/backend/target/classes/com/stdproject/mapper/AppRoleMenuMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..7cdeed553be00b51e9bccfd2f7eda52ee8ebe716 GIT binary patch literal 400 zcmb7=%}N6?5P&CDyS6HL5_|!@IS;TZ)PtujLJQt!x5G9in}qxbeKik0fDa|kZjlx} zc}ON?X1?T`&#(6n0C<3l0!9jM8`oh>D<9m3n}i*C&jDxNFPz~y+dLm`3OH79xuG{g zL$<}2x-TzatN?pNO|H``m$BQ{lyvkaM@ayj8b8x`DCF0@FV onl+;yM3MFdxDza8C<=~boyep?PKE3vIEBd&r*I~5EctVQZ#4dV-2eap literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/mapper/AppRoleUserMapper.class b/backend/target/classes/com/stdproject/mapper/AppRoleUserMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..53c671dd46c1834d3bb8c4137b979acb7f01891c GIT binary patch literal 400 zcmb7=!Ab)$5QhI$?b@o~N$>^qW*%Tws0U9gLW|yKx5GANHwj5r=&O0~0emQNc1yA7 z$wM+BGxH_ie15%u0Jy_hhLOT`2F8lHfV+GwKN^-4Px=y#7l9GwO>7pb8?}!f+d5cn*EKF@Fb%7OD#cya{{1bRP zH0(*RO(t#jCGz`RVY+Z#sQA$|^6teS#hd;k3YYUv+FO1#(Uc9(taV9@oQ(=sg$uPN pPt}UG8ALVx6zHvBE<;f`kaZ-JhMY3lM>xi0h*O+M983Nb_y$fdeER?Z literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/mapper/AppUserMapper.class b/backend/target/classes/com/stdproject/mapper/AppUserMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..d27b650645875ea5d35ee43d2c1fc340d05ebdcc GIT binary patch literal 388 zcmb7=O-{ow5QU!$G_-((*s(@p$s8bnR2Hm)kXpgsNk+j{Vq3O@)T^=J02~T2NmcQ) zV_}a+Gw*r6`S^T$2XKRv3=@Tm%5@Y|?Sor$m8jF+bD)LyPm#mJm}S^kI9=;kO|7;K zJ(fdjhN%J#@>09b)UKy)Q|e@*Z~G{Pz&p1)9eHb|Fk6|%>eL5TsEfa*dGSxf>rwCn zfNe5qvjfO)bA|cJ^`YW>)5@P`ztFCR0Tj-cy~sL#Hqn$VFRXP*NSuudmxT)rX|Jmn mCNlz({%)WxST4&@*pqW0+l9O`xhFWpY>aapNt{ak82AEbc6d1e literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/service/IAppDictionaryService.class b/backend/target/classes/com/stdproject/service/IAppDictionaryService.class new file mode 100644 index 0000000000000000000000000000000000000000..77a2cacdae3ac690a07cb7c8e92b19a397f83362 GIT binary patch literal 338 zcmbV|OA5j;5QhKws*jCp&md;uvMLB72!e~AAWefr+N30@*sHnl03J$AtKb7yE@lP> z=9~HEdOKeL%rOYiAQ*F9^C*fg5iN38BLkm z(_LK61n3YIu~uv; literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/service/IAppMenuService.class b/backend/target/classes/com/stdproject/service/IAppMenuService.class new file mode 100644 index 0000000000000000000000000000000000000000..4963072a4f11e51bb5fe311f2d108d57209b5474 GIT binary patch literal 320 zcmbV|zY4-I5Ql&9Uu|6+d+ z_uYNDKdv_ba|}GR7{-atxv^LVqV8!AsSA--M~#g>$dUbTk~!|*6hf@ebQ`7W-z zJ@go+H6a!{m#KCN6@MhIaM3)h_`pcunlXZ*uSi<+)^( literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/service/IAppOptLogService.class b/backend/target/classes/com/stdproject/service/IAppOptLogService.class new file mode 100644 index 0000000000000000000000000000000000000000..a426f83cc4401f142750faf5f32c1d9bc1bde912 GIT binary patch literal 326 zcmbV|zYc;h5Ql&DABu~U&){SSN7Tf{#Ds)_Cn(sE5@;J*h`gGE58y)?0gW2n9D0{r z?!LRP*W395V1ucH9>F43IW_jE3zhQNQp1Z%#GD>>S_j(tDhVGI2Lpmx$|^=PCKDP& zZNGyN!K!6MOy%OJN}AUZv%=`CG?bq#mqsZ0=00%*lTaj**|OjSss9c3{6C=UZs@~? tODk+mUoPI(BXC1i7BSz8tl2#O5nZ;YG*$%t<_(*_0(x+|IL4&Q?j57yX4(J% literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/service/IAppOrganizationService.class b/backend/target/classes/com/stdproject/service/IAppOrganizationService.class new file mode 100644 index 0000000000000000000000000000000000000000..1cf19c5f6349bf92e675a3a69526f1c3df493dfe GIT binary patch literal 344 zcmbV|OA5j;5QhKws*jBa@C;_*vMRU{ghCfRL0UseX_Jtoq8`nK2k=m0S_MUL<02Cn z_`jKNZuiR-zzUN99fEnLDr((c8&&YkQOnIiWSs6cTE`}5QkKfF8lLU4k|w1|M6c$;19&L0t%4%1T+9p% z%s2DR?S8oen4%Y;#xP7w%B|aFxj9hcxTX9k6XMHxmTirqHEAC`djT2@{ew6Pu7uw6 zOP0k*j{!9VRc@nG)$Rj}&1qHu literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/service/IAppRoleService.class b/backend/target/classes/com/stdproject/service/IAppRoleService.class new file mode 100644 index 0000000000000000000000000000000000000000..730082eb45d3080706d0ca1ceb4edc13fdc98dd9 GIT binary patch literal 320 zcmbV|OA5j;5QhKMM}2Hucm|hd;j${Y5rl$ZPms2QM%tt_sp!>QcmNM2wzZ&i=^`@> z%zQInp0E1@zzSm*4#OQcmNM2rd3eHm5Z5y z2k)DCbGu)z0H){#s4)x^lXB~JS#A!LIBqFF%7plGo@E=OXzPXOsRd{-^bg`FxDtBL z*Kz3x&|(;ulvtQl?o7ecb1a;+nJO%&lOt`V(Qon#$Iyx7UJF;`#GqE+;BfT^bW)i< v@{o4Yo%u(aa27IjBU9uFEu`|h2S37&%5!`&hPtn&{}@n1Q1v!C)$Be1oD6An literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/service/IAppUserService.class b/backend/target/classes/com/stdproject/service/IAppUserService.class new file mode 100644 index 0000000000000000000000000000000000000000..dcfec66d649ab92989832f387a8ca38e0ba7d903 GIT binary patch literal 685 zcmb7CO-}+b5S{Yjf(Rm_p1l~j*n=m6ny8712}Y8Q7jI>^E+xC|rtO0KH4pv(f0S`{ zL07?qc$iLJGxOejy??yE0l)&IG6xM!*1dMZ3l@2=wb5rMnF4wMKq zCv3`S$YektMrpJITLjKhh7nVd@Kr*i`G{Fz;xI9kzgRAfP%>v-(h+Dp3+Z3aQwhl; zjx?P?PVZVRWYF&pR;uID3OlFE+WJ`1J-1`!51B?1%e5g;NxnH-0k=1a)|i$HwL9H) zB`oN7EP-Q;+a%xc#yAZ=WX8;t_6hX<=we-M{ipjxpr%4>b6&I;xyeC9sq$NS{aY3gh%2)1yL1I8T0WE h8-tz9*P)U5U1%;t>cun!_Rv~r1=!EtHXLOB@DnFk%>DoX literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/service/impl/AppDictionaryServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppDictionaryServiceImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..b5fec50a25264ce33c3eb9cf56b692110b9f4c82 GIT binary patch literal 743 zcmbVKO>Yx15Pi-^7ed-Xph!J%;1()WUn(w}Mv6d4kMs z@B{c!h}kWXk~FzgD~{O=)6tnJ&jF zQ0C@&CiVBAO-9zpO#1~TT2kufa(D;&d>1(AkfG2OsJ7pXB0LhfDC%Wl;=G;dBy8sP zoclmY;F`)W*9t{w2)x~s+255VP6y2^5x_p>g+K z*lJumh2vftL!0|Vf22aKR~y7@GdZ8Bg%UXZlrw9pN0brE*)zrlUJ+|p&Gx|hsmz=w zGyUvUs=rzPm4~mrwqfb?YFA>sM#O8!GV%@z{&@A+K4BzF4AjqlK-{vUf+pMI8ED~< dZL_@BafD+=RXk-|!83j>&gXc+XAyq_`~$C2P?g&+p$KwNyui^{w7bJ1P}fIf0Q`8 zTCf!_vM|Y;yqVc~Gw&a-ZvYOlR!0ft8Y&G`F(nYiHj!Or6Wz0!Oom+*bm|6KD(Nwh zNwqaHC4aADk~(n%+5Q4&d>5EH&_;(Nf%5iFr-o^Py*ytUdd}NhioTlb9$ndj6`Mfg7zI+(1TDCfw_@2ckoiY7^9f)2wGDLVQ^7!71XApY}u+h#td zQ=O}_{=2!oTXnAlHZC)+kx)mcngu&H#s(g|HLTZm%lf`do!6#+?Nve#*5C0+$&(F3 zN23jhu!$Nk6U)V$CHUioVmr%778t1RzCb*)ql5epXk43qQb*67P&w zYo!|r+~nNXNlxzD`^zhUV{BDXK(T^S4Q0$R1d)k(N0?Z3P0Hh8M|hRkL7H&+6P(kTVeUw2<(mw}#%{ZUd4_|mU*fygnZAtt@7fbGph#Upf$Yx<+4NGKe`MHc`)Cm=_LbiZa Oie~#dHfYcCH-Qg+E7%qQ literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/service/impl/AppOrganizationServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppOrganizationServiceImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..e0b54bfa6a2fda604310eeae79e96ececdbd345b GIT binary patch literal 757 zcmbVKO;6iE5Ph2u0%_XN0F^jZz0n@n8$vRT6d@r+3PoyA?rUe84z+hz>oqj}S3Ong zp%-raD8$%+L|t;JEY0qWXXfp^c{jJe{{Z-iH(fN)?4Z>{8*2hlVlx>lo6+1BGF!$f zQ0~$qm->6qCMRoTuKgt?T2kgxIlXtrd>2?dB12&)(A;}J>tJ2rpzN22x%2iyC*kkf zk#lE$p$z?C6lYyvIzoK^he4Rk+*v_>;e?mroDzaGna}}o?8BA=V(wXv9`VYZY z_)59J;ba9&HQw`3<+PE&#*`LDg~Bt$b=BrSnLDb#Aydw2FKg(hRWzz6YZE9e>&emZ zpTx(-tssym>P~Ip6MaG@Yj11tPxiBap)Qrc?&pHBGd-i6nAnjqHdL!*UiT)}FJ$gK znZ*~cGJR$JHdmkIISg4jmRD)5(ey{IL+(zF<#QKG6Q~3*sjS8tAbte*-&s d$+lPB+jxaOdrfSzZQwNq)wzXjKFjZ1Sv literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/service/impl/AppRoleMenuServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppRoleMenuServiceImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..1db363d3eec329735bc41f886981bd383acd6465 GIT binary patch literal 729 zcmbVKO-md>5PiKLPF&acnLzNAo9-bElG~^tfq*c2aKqkvW-Dv!On1}MW89zRN$`*# zkRKINGf^1b>?Jf*cU4!_qh7sVzaM`BIL7+{I_O5|4bjJnK%Ch^rpgw2YAadHQx$aS z@~V_{7s!;_8d;LR)fq`$xLl6^I%oVASUJ*0hZBMB{=p=|8-c^RUm2#(+iS|g%i2@t zE^SWdWU5x12m^u9lDf0S8iC#yJ0*dQL>s!Oij@2}mF67TPHd*~iSoMkpMt$`rAvX& z$r6ZWtVNi5!dPH+tY=1r%5(dNrp14Jh>fkj~rbGV;aKa-{N+RVOt zRnQOXZ+PA0$%eV3XLZE*h=_&8^s(v$9~K+iHTGoV1O3qh#61T(7_zOufo-g_9X9Vi Y-eQBjE;iYAu*JXiy@Or8>-=}XA7xeD;s5{u literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/service/impl/AppRoleServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppRoleServiceImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..2a6e664128fdf8f11d78adb588b1af1412ab44b9 GIT binary patch literal 701 zcmbVKO-~y!5Pi-kO+!=C0^-<91wF*v7m!e;N|90y3Ci8sOjD=3w&nFg^P4#JREYyW zfFD&cyG^FWhv-4&i|J^?TILAQ?6;zw3wNXbyAc}1&C(5RJYIB(`CMxL6 zC3z<4cOa8#Yh*_LM#m&|>JmBn5Bhu;Xq;)I!-YWg_+;F~jzF)-mxZbGc203vkG*tm zXcKytqKTHk=Pfb)b-qCDtDTZSXP^yT<>`d{wVEXC=?-kHlCko-z)NQ>{M4Di>0nFx zvYqu3MOTr)n~|Ow6>`t1@5=C3Ds;A4J5|n+m&>Z(OB8LA$OIi0D^hgvg0LFMhCux1 zt&z=rOy6{&%HhlAdUJK71dfI|*GOrsGtGis8e;Yx15Pi-^w}e1x3P^|(x6%WaDsG!bijXQ*3LF~9-Mblr%dTyCy@C9!o+9bC=2KZ|8#F0((PkbQlS=kKfKB>F!VMd3BJ>1KcGO*L*9dez*f|LtOthg-WuB1#tdfi)gNaR5Hd9_#{-0nceA9)% z`^gT7daP}jYQk9H(Nr&t3Z>`v>$=5%vNhbq&y{oJWdr$R9f>y+$pjr%&BS=LmGrQr ze-Oq~^rp7-DV^(zrPmF}#va~XsihKlby+fAPBUF-CUIEkXuZ?GHTR7z3>OR7AzN`Efz&*+0-Y5V7 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/service/impl/AppUserServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppUserServiceImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..434ba4b772966b59e238ba88203b649e914e3bae GIT binary patch literal 3437 zcmbVP=~5I|7(JI6Y#3V95hSRDkPyS7Hf|9d#NZZ*xDH~#Y&|^}Xqo9AdwN8&YW6&W zd4>4HRHaaoO3GhJRh}jfkV@s;o*rgHvHUT2>wCZRE$930oxlJ4^$!5Y@k0y^h-irF zXv8Lggym+9l<8*ev|BK;%PG^h^SMkRZ^%2obn>?A7Jc*<8j*7AF%N3v3#- z9oruhi1hVOYiN3wJj?Z@VYyD)_9--P+$uzoZWrpYiSNm>Mz!l{t`X`_2*o_^Lh@l&= zXz0=LDqa)VuVm%@bk1{?!PNm7&*iSsTh(!ym;NP33Y_hGem%k{Q1!BxLJwFeq?>zBKYV<>NVzfn0LEMe1!8Jawkz0-q!!ql&AiTu05% zxtX-|1Y)!yToO3m*FX8f5)&=hhy5B19YZ)EF!I8Z1h!GD@q)jgjJKF8t|M^xxsSRQ4jBFVIF6%TWzEs#tbh z$C%n0SKcmo9_>gT3VV;-^W`2rc6lkwZ)lyo_ zD$uh!-o`nB);ZfrpIj~h3LIMRNWkC<_E+;Rq2V36@42%rWO*~ynAC9r7wO2Hna`7; z=`)Vy2HYFlfNb7!&UcN{G2?Red8ThKF6+3W9NR+2mcF+ji75@&bWG#A!037&E$7Iy zLFnnM>01kuKHpdAwo?lxivg>vW68?WxE2AW#f*+w++Y#oE}AT`_o*V*B~CBi*YN>9 zq<#6aeNTz`bPOg^8Y~@Y5UV3#qHkxVG3i=n=CtX{Db7e>$6XTGRU&KsmcX_1Iu>9v zZVGxS?Me1(tHAEiiggb5Q;Tja>c}9=;!?<^iF$H*f@xDl)Ue|9&uVZ5_SDoorbciT zPE=Q2fzGQ1R)nmaw)1u>BgY-b^@H-j@C>iZrj#^!3(lFA@A4ir*A5s=YIn)@WSZ=W zo(iI~Wzu%!#X>eEy(yF8nXiH8rcKXQ^KdchFWAHzs?C^^*1-i{t+~3#Rr=Rg2i}$! zq`%;%FPo}>`_iN6R6_N#1v3}w-CA9I1bWDT8qe2c zJyo$5_y&-r++ta;q;Sagdb8?R`e(^vUOHt-Esk6&&!XxvBGA2|M$Jik-ZA}x$N2md z?0&(A)o3kL)>QAK(p5{xah9mvRO6wsx(y{7)R30}i6z~FXUVg+qE<&eL-wnT73f<( z*rbMZ)nlpjI8302xz+#yhrb3@W!dNW0Nup?7W+o_e1Ed_I5XG_wL0(!;%5#TkY}qt z13Tff)r%WYz-`Wix<9x}9nNrH1N-5D-=NJrLUTMexB~qNw5H#&btV#zCugGZSaPN@ z-jk0676lI2Zl#UiG5%&&vHt1h&Ny<#-R8`E1&OK6LTfr0gu>c89pl zoG;^J3jc)Pnjro~m&OZT;8T1SLZ=9=NevI!&V}FjxUI!O#O$NH?p^jP}}wfh_QX_eneyBL2Vc&if%p@?Tr2v zeE$XK_jX2CaA_4+BM8oPMhCdMZx!!0U#5f*CJ4VpK zKQlv&z!99lQNBjo?dsMdOs| oEr_<$+1(m?w+Aub90_86m*4L37s1zT8}JRj4f^la*!?~5KWj|U^#A|> literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/utils/CaptchaUtils$CaptchaResult.class b/backend/target/classes/com/stdproject/utils/CaptchaUtils$CaptchaResult.class new file mode 100644 index 0000000000000000000000000000000000000000..4f48d8d6e54bf6cb427da8c58e74ff25d0bcbf4e GIT binary patch literal 804 zcmb7CZEF)j5PtS9$>q{Z(#C3it2R(DiPEDW{n8g9fnp$5v2DPQo6C}Hx!jf8O@Eg{ zi{OX;0DqJ?y9ui1l1l#lAvryBR z*m6-i6b!ZAozSVyWHQ<})Rh2L!@D9Ud?eajiM_WBuNsThiZK8n`#h5-o+op9EEU6U?>|qmPkZ_x^f(=U;u)U^Ei$64~3 z9lCdiKDs~a(Y^^?FnR#1lwYIh3!zI`ZG8u8y}p6hdUJ#FH``DnTSJcQ0ogl)ryavahD3O3oc{K2eX j&d=~=)MrP=Zno9vxoz1cJwn6GkLuq^Bc8lgG`t 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 I>evcOpWC>N=l}o! literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/utils/JwtUtils.class b/backend/target/classes/com/stdproject/utils/JwtUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..49d3b0846f894e9466f91ef2af3787f5cf7ad585 GIT binary patch literal 6153 zcmbVQ30xf29sb_#!oV^dk`N6EiV@91ARB9n z)z-H5(Ae9f_hIj9NfpeTi zDLbBs?$WH`E^Ryv1;HYeaCOSk&GuLcN>QeuTtx-W5h%^>;A)B*Pf_ybNauWY&AE5# zb8i)4nLv@$l+?!bFsiUZ!MQ5V!%BggL1Qdx*|BlckOo90PAl3mY44K*fs#Q}*KEDl z7}b*kn>-ATHN@rz&|{nN@I}K_K;}Wb@5K&Pt1-XixpvY-~;sh^!S|a5r zT_0@i8iBn(x*#YT2ry8QTQHl+u&(a&Ln_Lo(r5 z7=(j&yNajdDh8U8+AS-k$6A-~siycpLr2x?W)CIyvJ(2h*RWV-E8u@leW3`5)# zA4)P!cI#9054|a~;&61(oEo={XphcpvpLsXjCOP=*sY=yT>@+7>y~0PJ7wxEi6O&` z+rwi51-p7SUCJod)Yr~?nehLxT=hP3lQmI=11he= zvq?a7yEDDhG{(F_?#+`bXQ#nm=Pvm*D|pTvPIOJGgg}2KiL+mV8dMPjEvh1@mPEpZ z?E}`B2UxCe-E9ow5QY`RrN2f58qdZ>Tpq~@tS2{*ZIUSxD#kz-EFITOvZ+_~Ot}24 zaE*Tzv5w;g1*QrM41VqWj3(90+29tEzg(`!mz%l1nJ>uEJfUI|hgl;Im67%rgUlVz z#f=J{r{X3&Utr~eSjo1IFI>NMOp?p$mlQxQrIr`q76rGecp+XSuq;=L+##2V8@lv)4J-_bYgp!0P$&V#@9~JgAS$ zBVNI~$@f{o?TLgwq$OI+q12e3%&wCi!h2P`5AUa8q-!1=0+qhrz~_Jus`wBdAkoWY znzD7eAQY)T&>F@=_^^V9ReS`~EQ z$5hPVI4!4Mfpq=)!{futq_wO$?UNT77U14g(q?be7q{XA3B4tmG;F6IBB+g>hB*|q z#%1$$$Yg^zX_%wY0p^(%J;ZayFsGtgW<%78MKg)ONkQ6NccZ&^ecIUdBa^oLL5JQ% zZp%NPZONL(EG`SR88OyFd1pMScc;b%bhB3@QW+6rP)qb_W?cUEZiejPIH6y#_=!W5 z>==?dTfcPwIj0Bq0_<~Pp1kyKF-HcyW~O14I zv`b0b`{YyNdWlD%AukhI%zxdmSya(BcD_cEBu=wRx^>I$(j`-{Ix6TQ+pdk8Y@EZizb{YxMyys zTkUMURp8%*e5MvKyPgW42;;waQo&OyBPZsZQt{*j9~h&Zj<0Eh=20&VB?DxCo%Sb> zx5+hmmzInrbgQn@Fh*1P9;|(7GG}8iUF&}iU;3o0a`Cz$Y7qTRm6hw};9 zU+(bsEXQA^H3huxK7neYT-`0NP1C4pco-K><6`Y78n%Xxp^1Pm3xEb}37}~PR|c>$ zG=r7^8m4jeL)bNg?jZY_y#iTl8W5)FO+<1zYOtA+*@Cs$iYC6E*obW$U5Opojtc-h+wcW^k>G3i$n_ zW-mIe6d{wOtYO`8^a0b@KZ}DBx4U<8<8 zDFLS9lpNkHtMs<4_0?1fK0t?Hvj9>opb1v#B;O!fK9AI9AlK%LBOh=)0R2QBq`)fa zk(YEedKEH_mmkBOS*@;PZlUg59WAx)ri_*X^8}Z;0hr=-e{D2Z`5PSkP3JzW+p5g|+<*won{zEAE zp+B6GWCHSy9&2Kj;~l(8oTVg`_e|pho$HR_!TH|1m#K1}FGi&voFYQ}F@6G35tawJ zCvr0pNKz#goWW5^WjVF$7MRP=WlkbWp8h%a1@H^!NRT}KOaA^9KOv5X@N14_ n{QkqwZ}40E(Hs3KGx{t3C8Rm>mDLccM6j?}ghZhz!pi>v+!vfi literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/stdproject/utils/PasswordUtils.class b/backend/target/classes/com/stdproject/utils/PasswordUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..a68da54e6de8d1bc295a34a6ea9ab614f92fdae0 GIT binary patch literal 2438 zcmbtVT~iZR7=BJRVMAC1fuQk&s#qj|Mik=*5QPAWh7Und!G0{snk*!{akCNWZ9CJu z-qTBOxbdQ`GpKdyWiR?K`Y$?8NBf*j5IV8b&NMTdec$uG@AH0~=bZiR-Oq0T48sn= z2StTnLjZLG&8zxjJ(kz4Y;0y_)kwPnbwj3Qx(NZLJGxkpAnH|wG&DdHIFYssv67o9 zI<|CLK|Cv&bLR&x#4ldDtm2Tsf!(?*<&Boj zJSQDO1WE`;(V^lK4aaa?VBfCqlvEEM$&hi$=#q@Ps^OXpqB&)+SIlyKR6|m(t7d7;%$lxT8`m%)*P7^SxI~?CJe!Ie z0@wZvEmu6Q$3~Nq@;m3I%JUGeLt$k}9vbFInU*nKF02^N9epLwm6nv9*7J+HV@kcc z=y!7_iFh*g?}TMlYC6-lAtUiSp0w) zsfpWRqd?=ltEbnd^kQ|g&1Q)Mv90Xh%r)_YvUri^lVqlxUf~#3E=$$pR7LctA`s&0 ze9=godR_&~^exNCp>)1_?S|&SF-hg(%A@Jdcm)+!E|!Zfvd%wU#YGI)S*865fvYR@Y)`tSp_y$F##2qE0Y9PRUb z0)mPJ3*$}|>?#yWK!XJ9eT7y9N2JL#ddSKO*-48Q_$g@;@3^KchD>_yzIVn2tU zJ+t7J1F6@D+<$??Q%d6Kp{F?Z5=VNsapK#x@8bTx-mrfg-P`E9`;8*D-v8dWjkB^P z#T!ZoRLW?)ep34@++jK1D!zrVJ^= zNZJ}E#38@Tk;jmOjq>|Xe zKBG+f&KtlD-rJKHA#Wx*%xMm5k&IfVlqRDd(kIW3

ib=K#m5V};~pqa2dt&3-ua z&2Xn%QG`LsM|_L18CG!+Ysgaad&BHPs8PH}JAxdj;7>(Pkg9+3)2eB25&8pxwrds6 tkc$rpAH?d1Q_)Fi`D=KM>m + + + + + 3600 + + + 1000 + 10 + + + + + + + 30 + + + + + + + 60 + + + + + + + 60 + + + + + + + 60 + + + + + + + 2 + + + + + + + 1 + + + + \ No newline at end of file diff --git a/backend/target/classes/logback-spring.xml b/backend/target/classes/logback-spring.xml new file mode 100644 index 0000000..43814d0 --- /dev/null +++ b/backend/target/classes/logback-spring.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + + + + ${LOG_PATH}/info.log + + ${LOG_PATH}/info.%d{yyyy-MM-dd}.log + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + INFO + ACCEPT + DENY + + + + + ${LOG_PATH}/error.log + + ${LOG_PATH}/error.%d{yyyy-MM-dd}.log + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..f221e12 --- /dev/null +++ b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,71 @@ +com\stdproject\common\DataPermission.class +com\stdproject\service\IAppRoleUserService.class +com\stdproject\controller\AppMenuController$MenuOrderRequest.class +com\stdproject\service\impl\AppRoleUserServiceImpl.class +com\stdproject\config\SwaggerConfig.class +com\stdproject\controller\AppUserController$PasswordUpdateRequest.class +com\stdproject\service\IAppUserService.class +com\stdproject\controller\AppUserController.class +com\stdproject\controller\AppOptLogController$LogStatistics.class +com\stdproject\controller\AppDictionaryController.class +com\stdproject\entity\AppUser.class +com\stdproject\entity\AppRoleMenu.class +com\stdproject\entity\AppRoleUser.class +com\stdproject\config\WebConfig.class +com\stdproject\entity\AppOptLog.class +com\stdproject\service\IAppDictionaryService.class +com\stdproject\controller\AppOptLogController.class +com\stdproject\service\IAppRoleMenuService.class +com\stdproject\StdProjectApplication.class +com\stdproject\config\CustomUserDetailsService.class +com\stdproject\service\impl\AppDictionaryServiceImpl.class +com\stdproject\service\impl\AppRoleMenuServiceImpl.class +com\stdproject\service\IAppOptLogService.class +com\stdproject\controller\AppRoleController.class +com\stdproject\controller\AuthController$ChangePasswordRequest.class +com\stdproject\service\impl\AppOrganizationServiceImpl.class +com\stdproject\common\Result.class +com\stdproject\mapper\AppMenuMapper.class +com\stdproject\mapper\AppOptLogMapper.class +com\stdproject\config\JwtAuthenticationEntryPoint.class +com\stdproject\controller\AuthController.class +com\stdproject\utils\CaptchaUtils$CaptchaResult.class +com\stdproject\controller\AppMenuController$MenuTreeNode.class +com\stdproject\common\Constants.class +com\stdproject\common\OperationLogAspect.class +com\stdproject\service\impl\AppOptLogServiceImpl.class +com\stdproject\utils\JwtUtils$ClaimsResolver.class +com\stdproject\utils\CaptchaUtils.class +com\stdproject\common\OperationLog.class +com\stdproject\service\IAppRoleService.class +com\stdproject\common\BusinessException.class +com\stdproject\service\impl\AppMenuServiceImpl.class +com\stdproject\utils\PasswordUtils.class +com\stdproject\entity\AppDictionary.class +com\stdproject\utils\FileUtils.class +com\stdproject\service\impl\AppRoleServiceImpl.class +com\stdproject\utils\JwtUtils.class +com\stdproject\controller\AuthController$LoginRequest.class +com\stdproject\entity\AppRole.class +com\stdproject\common\ResultCode.class +com\stdproject\controller\AppOrganizationController.class +com\stdproject\mapper\AppRoleUserMapper.class +com\stdproject\controller\AppUserController$PasswordResetRequest.class +com\stdproject\mapper\AppRoleMapper.class +com\stdproject\service\IAppOrganizationService.class +com\stdproject\config\SecurityConfig.class +com\stdproject\controller\AppMenuController.class +com\stdproject\mapper\AppOrganizationMapper.class +com\stdproject\mapper\AppDictionaryMapper.class +com\stdproject\entity\AppOrganization.class +com\stdproject\config\JwtAuthenticationFilter.class +com\stdproject\mapper\AppUserMapper.class +com\stdproject\entity\AppMenu.class +com\stdproject\common\PageRequest.class +com\stdproject\controller\AppDictionaryController$DictOrderRequest.class +com\stdproject\service\impl\AppUserServiceImpl.class +com\stdproject\config\MybatisPlusConfig.class +com\stdproject\mapper\AppRoleMenuMapper.class +com\stdproject\common\GlobalExceptionHandler.class +com\stdproject\service\IAppMenuService.class +com\stdproject\config\CacheConfig.class diff --git a/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..7c508f1 --- /dev/null +++ b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,61 @@ +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\JwtAuthenticationFilter.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppDictionaryService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppOrganizationMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\utils\PasswordUtils.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppOrganizationServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppOptLogController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\MybatisPlusConfig.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppUser.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppDictionaryMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\SecurityConfig.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\SwaggerConfig.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\DataPermission.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppMenuService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\ResultCode.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppMenuServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppRole.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppOrganization.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppRoleController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppRoleMenuServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppRoleServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppRoleMenu.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppOptLog.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppRoleMenuMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppRoleUserMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\PageRequest.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppOptLogMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppOrganizationController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppUserController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppDictionaryServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppOptLogService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\BusinessException.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppUserServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppUserService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\utils\FileUtils.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\utils\JwtUtils.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\CacheConfig.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppRoleMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\WebConfig.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\Constants.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppRoleUser.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\OperationLogAspect.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppMenu.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppUserMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\JwtAuthenticationEntryPoint.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppDictionary.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppRoleService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\utils\CaptchaUtils.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppRoleUserService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppMenuController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppOrganizationService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppRoleMenuService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\GlobalExceptionHandler.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\OperationLog.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppDictionaryController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppOptLogServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\StdProjectApplication.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AuthController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\Result.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\CustomUserDetailsService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppMenuMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppRoleUserServiceImpl.java diff --git a/dev-prompt.md b/dev-prompt.md new file mode 100644 index 0000000..0183689 --- /dev/null +++ b/dev-prompt.md @@ -0,0 +1,152 @@ +# 开发一个标准的JavaSpringboot应用项目 +## 项目采用如下技术框架: +## 1. 后端采用最新的Springboot3.0框架。 +## 2. 数据库采用MySQL8.0数据库,使用MyBatis-Plus框架进行数据库操作。 + 数据库配置如下: + url: jdbc:mysql://121.37.111.42:3306/gisbi-demodb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai + username: root + password: mysql_F8ysiK@2024 +## 3. 前端采用Vue3.0框架,使用Element-Plus组件库。 +## 4. 项目采用Git进行版本控制,使用Maven进行项目管理。 +## 5. 项目采用Docker进行容器化部署,使用Jenkins进行自动化部署。 +## 6. 项目采用Swagger进行API文档管理,使用Postman进行API测试。 +## 7.系统使用JWT进行用户认证和授权,采用spring配置参数进行是否此案有token访问认证的控制,默认进行认证控制。 +## 8.spring采用jcache进行缓存管理。 +## 9.项目采用logback进行日志配置和管理。 + +## 项目实现如下基础框架功能: +### 组织管理:包括组织添加、组织修改、组织删除、组织查询等功能。(组织是一个结构树:含公司和部门两级) +CREATE TABLE `app_organization` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `orgtype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组织类型:01-公司 02-部门', + `orgcode` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组织编号', + `orgname` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组织名称', + `parentid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '上级ID', + `manager` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组织负责人', + `description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组织详情', + `address` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '联系地址', + `contact_phone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '联系电话', + `contact_person` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '联系人', + `isvaild` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否有效 1-是 0-否', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='应用系统_用户组织'; +### 用户管理:包括用用户信息维护、用户角色分配、用户登录、用户修改密码、用户修改个人信息等功能。 +CREATE TABLE `app_user` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `orgid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所属组织', + `usertype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户类型 0-管理员 1-普通用户', + `username` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名称 用户名称(账号)', + `nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户昵称(中文)', + `password` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '登录密码', + `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '邮箱', + `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '手机号', + `avatar` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '用户头像 base64存储用户头像', + `status` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '状态 1-有效 0-停用', + `pwdvalidperiod` int DEFAULT '90' COMMENT '密码有限期 密码有限期(天)', + `failednum` int DEFAULT '0' COMMENT '登录失败次数 允许的登录失败次数', + `loginip` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户指定登录IP 如果设置了IP,则只允许IP用户登录', + `failedlocktime` datetime DEFAULT NULL COMMENT '登录失败锁定时间', + `pwdresettime` datetime DEFAULT NULL COMMENT '密码修改时间', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='应用系统_系统用户'; + +CREATE TABLE `app_role_users` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `roleid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色id', + `userid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='系统角色-用户对照'; + +### 角色管理:包括角色添加、角色修改、角色删除、角色查询,角色权限分配等功能。 +CREATE TABLE `app_role` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `rolecode` varchar(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色编号 系统生成,三位编号', + `rolename` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色名称', + `type` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色类别 1-应用管理员 2-应用普通用户', + `description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '角色描述', + `isvaild` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否有效 1-是 0-否', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '最近修改者', + `lastmodifydate` datetime NOT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='应用系统_系统角色'; + + +### 权限管理:包括角色菜单权限添加、权限修改、权限删除、权限查询等功能。 +CREATE TABLE `app_role_menu` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `roleid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色id', + `menuid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='系统角色-数据权限对照'; + +### 菜单管理:包括菜单添加、菜单修改、菜单删除、菜单查询等功能。 +CREATE TABLE `app_menu` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `type` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单类型 01-菜单', + `code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单编号', + `orderno` int DEFAULT NULL COMMENT '同级序号', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单名称', + `icon` varchar(9000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '菜单图标 base64存储', + `islink` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '是否外链 0-非外部 1-是外链', + `url` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '菜单URL 内部资源页面URL访问地址', + `module_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '模块ID 菜单关联的模块ID', + `parentid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '父级菜单ID 顶级为0', + `isdisplay` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '是否显示 0-不显示 1-显示', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='应用系统_菜单'; + +### 日志管理:包括登录日志、操作日志等插入,查询功能。 +CREATE TABLE `app_optlog` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `usercode` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户账号', + `username` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户名称', + `opttype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '操作类型 00-登录 01-新增 02-修改 03-删除 06-查询 09其他', + `module` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '模块名称', + `description` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '日志描述', + `method` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '操作方法', + `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin COMMENT '方法参数', + `logtime` datetime DEFAULT NULL COMMENT '创建时间', + `requestip` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '请求IP', + `browser` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '浏览器类型', + PRIMARY KEY (`id`), + KEY `log_create_time_index` (`logtime`) USING BTREE, + KEY `inx_log_type` (`opttype`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='系统操作日志'; +### 数据字典:包括数据字典添加、数据字典修改、数据字典删除、数据字典查询等功能。 +CREATE TABLE `app_dictionary` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `orderno` int NOT NULL COMMENT '顺序号', + `dictcode` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典编码', + `dictname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典名称', + `dictdata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '字典数据 JSON数组[{"code":"01","name":"字典值"}]', + `lastmodifydate` datetime DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='应用-数据字典'; diff --git a/logs/stdproject-backend/error.2025-05-29.log b/logs/stdproject-backend/error.2025-05-29.log new file mode 100644 index 0000000..4e3e99a --- /dev/null +++ b/logs/stdproject-backend/error.2025-05-29.log @@ -0,0 +1,26 @@ +2025-05-29 18:19:01.061 [main] ERROR o.s.b.w.e.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'jwtAuthenticationFilter': Unsatisfied dependency expressed through field 'userDetailsService': Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through field 'appUserService': Error creating bean with name 'appUserServiceImpl': Unsatisfied dependency expressed through field 'passwordEncoder': Error creating bean with name 'securityConfig' defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\config\SecurityConfig.class]: Unsatisfied dependency expressed through constructor parameter 1: Error creating bean with name 'jwtAuthenticationFilter': Requested bean is currently in creation: Is there an unresolvable circular reference? +2025-05-29 18:19:01.139 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +The dependencies of some of the beans in the application context form a cycle: + +┌─────┐ +| jwtAuthenticationFilter (field private org.springframework.security.core.userdetails.UserDetailsService com.stdproject.config.JwtAuthenticationFilter.userDetailsService) +↑ ↓ +| customUserDetailsService (field private com.stdproject.service.IAppUserService com.stdproject.config.CustomUserDetailsService.appUserService) +↑ ↓ +| appUserServiceImpl (field private org.springframework.security.crypto.password.PasswordEncoder com.stdproject.service.impl.AppUserServiceImpl.passwordEncoder) +↑ ↓ +| securityConfig defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\config\SecurityConfig.class] +└─────┘ + + +Action: + +Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true. + diff --git a/logs/stdproject-backend/error.log b/logs/stdproject-backend/error.log new file mode 100644 index 0000000..047f72f --- /dev/null +++ b/logs/stdproject-backend/error.log @@ -0,0 +1,1729 @@ +2025-05-30 09:04:27.397 [main] ERROR o.s.b.w.e.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'jwtAuthenticationFilter': Unsatisfied dependency expressed through field 'userDetailsService': Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through field 'appUserService': Error creating bean with name 'appUserServiceImpl': Unsatisfied dependency expressed through field 'passwordEncoder': Error creating bean with name 'securityConfig' defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\config\SecurityConfig.class]: Unsatisfied dependency expressed through constructor parameter 1: Error creating bean with name 'jwtAuthenticationFilter': Requested bean is currently in creation: Is there an unresolvable circular reference? +2025-05-30 09:04:27.470 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +The dependencies of some of the beans in the application context form a cycle: + +┌─────┐ +| jwtAuthenticationFilter (field private org.springframework.security.core.userdetails.UserDetailsService com.stdproject.config.JwtAuthenticationFilter.userDetailsService) +↑ ↓ +| customUserDetailsService (field private com.stdproject.service.IAppUserService com.stdproject.config.CustomUserDetailsService.appUserService) +↑ ↓ +| appUserServiceImpl (field private org.springframework.security.crypto.password.PasswordEncoder com.stdproject.service.impl.AppUserServiceImpl.passwordEncoder) +↑ ↓ +| securityConfig defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\config\SecurityConfig.class] +└─────┘ + + +Action: + +Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true. + +2025-05-30 09:08:43.941 [main] ERROR o.s.boot.SpringApplication - Application run failed +org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Ambiguous mapping. Cannot map 'appOrganizationController' method +com.stdproject.controller.AppOrganizationController#add(AppOrganization) +to {POST [/api/org]}: There is already 'appOrganizationController' bean method +com.stdproject.controller.AppOrganizationController#update(AppOrganization) mapped. + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1751) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) + at com.stdproject.ProjectApplication.main(ProjectApplication.java:24) +Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'appOrganizationController' method +com.stdproject.controller.AppOrganizationController#add(AppOrganization) +to {POST [/api/org]}: There is already 'appOrganizationController' bean method +com.stdproject.controller.AppOrganizationController#update(AppOrganization) mapped. + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.validateMethodMapping(AbstractHandlerMethodMapping.java:667) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.register(AbstractHandlerMethodMapping.java:633) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod(AbstractHandlerMethodMapping.java:331) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(RequestMappingHandlerMapping.java:438) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(RequestMappingHandlerMapping.java:76) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lambda$detectHandlerMethods$2(AbstractHandlerMethodMapping.java:298) + at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:986) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(AbstractHandlerMethodMapping.java:296) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.processCandidateBean(AbstractHandlerMethodMapping.java:265) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:224) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:212) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:225) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1797) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1747) + ... 16 common frames omitted +2025-05-30 09:20:20.924 [main] ERROR o.s.b.w.e.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'jwtAuthenticationFilter': Unsatisfied dependency expressed through field 'userDetailsService': Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through field 'appUserService': Error creating bean with name 'appUserServiceImpl': Unsatisfied dependency expressed through field 'baseMapper': Error creating bean with name 'appUserMapper' defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\mapper\AppUserMapper.class]: Unsatisfied dependency expressed through bean property 'sqlSessionFactory': Error creating bean with name 'sqlSessionFactory' defined in class path resource [com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.class]: Unsatisfied dependency expressed through method 'sqlSessionFactory' parameter 0: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception with message: Failed to determine a suitable driver class +2025-05-30 09:20:21.059 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. + +Reason: Failed to determine a suitable driver class + + +Action: + +Consider the following: + If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. + If you have database settings to be loaded from a particular profile you may need to activate it (the profiles dev are currently active). + +2025-05-30 09:20:22.684 [main] ERROR o.s.b.w.e.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'jwtAuthenticationFilter': Unsatisfied dependency expressed through field 'userDetailsService': Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through field 'appUserService': Error creating bean with name 'appUserServiceImpl': Unsatisfied dependency expressed through field 'baseMapper': Error creating bean with name 'appUserMapper' defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\mapper\AppUserMapper.class]: Unsatisfied dependency expressed through bean property 'sqlSessionFactory': Error creating bean with name 'sqlSessionFactory' defined in class path resource [com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.class]: Unsatisfied dependency expressed through method 'sqlSessionFactory' parameter 0: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception with message: Failed to determine a suitable driver class +2025-05-30 09:20:22.811 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. + +Reason: Failed to determine a suitable driver class + + +Action: + +Consider the following: + If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. + If you have database settings to be loaded from a particular profile you may need to activate it (the profiles dev are currently active). + +2025-05-30 09:21:40.470 [main] ERROR o.s.b.w.e.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'jwtAuthenticationFilter': Unsatisfied dependency expressed through field 'userDetailsService': Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through field 'appUserService': Error creating bean with name 'appUserServiceImpl': Unsatisfied dependency expressed through field 'baseMapper': Error creating bean with name 'appUserMapper' defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\mapper\AppUserMapper.class]: Unsatisfied dependency expressed through bean property 'sqlSessionFactory': Error creating bean with name 'sqlSessionFactory' defined in class path resource [com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.class]: Unsatisfied dependency expressed through method 'sqlSessionFactory' parameter 0: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception with message: Failed to determine a suitable driver class +2025-05-30 09:21:40.606 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. + +Reason: Failed to determine a suitable driver class + + +Action: + +Consider the following: + If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. + If you have database settings to be loaded from a particular profile you may need to activate it (the profiles dev are currently active). + +2025-05-30 09:28:01.120 [http-nio-8080-exec-6] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:28:24.799 [http-nio-8080-exec-8] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:31:20.228 [http-nio-8080-exec-9] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:34:02.397 [http-nio-8080-exec-10] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:35:32.114 [http-nio-8080-exec-1] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:38:07.965 [http-nio-8080-exec-2] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:38:29.326 [http-nio-8080-exec-3] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:39:37.992 [http-nio-8080-exec-1] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy141.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy138.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy137.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:44:35.995 [http-nio-8080-exec-6] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted diff --git a/logs/stdproject-backend/info.2025-05-29.log b/logs/stdproject-backend/info.2025-05-29.log new file mode 100644 index 0000000..833c6c1 --- /dev/null +++ b/logs/stdproject-backend/info.2025-05-29.log @@ -0,0 +1,11 @@ +2025-05-29 18:18:57.837 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 31224 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-29 18:18:57.841 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-29 18:19:00.260 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-29 18:19:00.292 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-29 18:19:00.293 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-29 18:19:00.411 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-29 18:19:00.414 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2493 ms +2025-05-29 18:19:01.091 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2025-05-29 18:19:01.112 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. diff --git a/logs/stdproject-backend/info.log b/logs/stdproject-backend/info.log new file mode 100644 index 0000000..2f9b8b2 --- /dev/null +++ b/logs/stdproject-backend/info.log @@ -0,0 +1,121 @@ +2025-05-30 09:04:24.751 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 10576 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:04:24.764 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:04:26.767 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:04:26.793 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:04:26.793 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:04:26.897 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:04:26.899 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2078 ms +2025-05-30 09:04:27.429 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2025-05-30 09:04:27.444 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2025-05-30 09:08:39.077 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 23288 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:08:39.081 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:08:41.425 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:08:41.446 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:08:41.446 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:08:41.569 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:08:41.571 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2420 ms +2025-05-30 09:08:43.882 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2025-05-30 09:08:43.909 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2025-05-30 09:11:19.221 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 25020 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:11:19.226 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:11:21.600 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:11:21.635 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:11:21.636 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:11:21.759 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:11:21.761 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2465 ms +2025-05-30 09:11:25.139 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '' +2025-05-30 09:11:25.156 [main] INFO com.stdproject.ProjectApplication - Started ProjectApplication in 6.759 seconds (process running for 7.313) +2025-05-30 09:11:32.236 [http-nio-8080-exec-2] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet' +2025-05-30 09:11:32.238 [http-nio-8080-exec-2] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet' +2025-05-30 09:11:32.241 [http-nio-8080-exec-2] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 3 ms +2025-05-30 09:11:35.704 [http-nio-8080-exec-1] INFO o.s.api.AbstractOpenApiResource - Init duration for springdoc-openapi is: 1859 ms +2025-05-30 09:20:16.890 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 26052 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:20:16.895 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:20:19.377 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 5732 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:20:19.382 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:20:20.430 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:20:20.459 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:20:20.460 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:20:20.606 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:20:20.609 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 3639 ms +2025-05-30 09:20:20.978 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2025-05-30 09:20:21.022 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2025-05-30 09:20:22.281 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:20:22.298 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:20:22.298 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:20:22.423 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:20:22.425 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2944 ms +2025-05-30 09:20:22.725 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2025-05-30 09:20:22.769 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2025-05-30 09:21:37.663 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 24096 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:21:37.667 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:21:40.072 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:21:40.093 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:21:40.093 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:21:40.208 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:21:40.210 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2474 ms +2025-05-30 09:21:40.522 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2025-05-30 09:21:40.559 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2025-05-30 09:23:12.391 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 10440 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:23:12.396 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:23:14.831 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:23:14.866 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:23:14.867 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:23:14.996 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:23:14.999 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2524 ms +2025-05-30 09:23:18.657 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '' +2025-05-30 09:23:18.676 [main] INFO com.stdproject.ProjectApplication - Started ProjectApplication in 7.149 seconds (process running for 7.707) +2025-05-30 09:23:29.855 [http-nio-8080-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet' +2025-05-30 09:23:29.855 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet' +2025-05-30 09:23:29.858 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 3 ms +2025-05-30 09:23:32.585 [http-nio-8080-exec-9] INFO o.s.api.AbstractOpenApiResource - Init duration for springdoc-openapi is: 1406 ms +2025-05-30 09:25:46.231 [http-nio-8080-exec-4] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Starting... +2025-05-30 09:25:53.371 [http-nio-8080-exec-4] INFO com.zaxxer.hikari.pool.HikariPool - StdProjectHikariCP - Added connection org.sqlite.jdbc4.JDBC4Connection@257e98f5 +2025-05-30 09:25:53.378 [http-nio-8080-exec-4] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Start completed. +2025-05-30 09:38:29.381 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Shutdown initiated... +2025-05-30 09:38:29.384 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Shutdown completed. +2025-05-30 09:38:59.919 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 16828 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:38:59.923 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:39:02.296 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:39:02.317 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:39:02.317 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:39:02.463 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:39:02.465 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2474 ms +2025-05-30 09:39:05.970 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '' +2025-05-30 09:39:05.988 [main] INFO com.stdproject.ProjectApplication - Started ProjectApplication in 6.857 seconds (process running for 7.374) +2025-05-30 09:39:10.552 [http-nio-8080-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet' +2025-05-30 09:39:10.552 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet' +2025-05-30 09:39:10.553 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 1 ms +2025-05-30 09:39:14.268 [http-nio-8080-exec-1] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Starting... +2025-05-30 09:39:21.058 [http-nio-8080-exec-1] INFO com.zaxxer.hikari.pool.HikariPool - StdProjectHikariCP - Added connection org.sqlite.jdbc4.JDBC4Connection@2d58c582 +2025-05-30 09:39:21.066 [http-nio-8080-exec-1] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Start completed. +2025-05-30 09:40:03.946 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Shutdown initiated... +2025-05-30 09:40:03.949 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Shutdown completed. +2025-05-30 09:41:36.750 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 6824 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:41:36.754 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:41:38.891 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:41:38.930 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:41:38.930 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:41:39.052 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:41:39.054 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2232 ms +2025-05-30 09:41:42.481 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '' +2025-05-30 09:41:42.495 [main] INFO com.stdproject.ProjectApplication - Started ProjectApplication in 6.508 seconds (process running for 6.944) +2025-05-30 09:41:46.298 [http-nio-8080-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet' +2025-05-30 09:41:46.298 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet' +2025-05-30 09:41:46.301 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 3 ms +2025-05-30 09:41:48.874 [http-nio-8080-exec-9] INFO o.s.api.AbstractOpenApiResource - Init duration for springdoc-openapi is: 1406 ms +2025-05-30 09:43:25.735 [http-nio-8080-exec-4] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Starting... +2025-05-30 09:43:32.947 [http-nio-8080-exec-4] INFO com.zaxxer.hikari.pool.HikariPool - StdProjectHikariCP - Added connection org.sqlite.jdbc4.JDBC4Connection@23aa73a5 +2025-05-30 09:43:32.960 [http-nio-8080-exec-4] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Start completed. +2025-05-30 09:47:30.964 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Shutdown initiated... +2025-05-30 09:47:30.966 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Shutdown completed. diff --git a/projectframe.md b/projectframe.md new file mode 100644 index 0000000..78b19d8 --- /dev/null +++ b/projectframe.md @@ -0,0 +1,28 @@ +StdProject/ +├── backend/ # Spring Boot 后端 +│ ├── src/main/java/ +│ │ └── com/stdproject/ # 包名(com.stdproject) +│ │ ├── StdProjectApplication.java +│ │ ├── config/ # 配置类 +│ │ ├── controller/ # 控制器 +│ │ ├── service/ # 服务层 +│ │ ├── mapper/ # MyBatis映射器 +│ │ ├── entity/ # 实体类 +│ │ ├── common/ # 通用类 +│ │ └── utils/ # 工具类 +│ ├── src/main/resources/ +│ │ ├── application.yml +│ │ ├── logback-spring.xml +│ │ └── mapper/ +│ └── pom.xml +├── frontend/ # Vue3 前端 +│ ├── src/ +│ │ ├── components/ +│ │ ├── views/ +│ │ ├── router/ +│ │ ├── store/ +│ │ ├── utils/ +│ │ └── api/ +│ ├── package.json +│ └── vite.config.js +└── docker-compose.yml # Docker部署配置 \ No newline at end of file