From a8661d575236be9cf9944e6aa3be6ef1642a6adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Thu, 16 Oct 2025 17:45:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(core):=20=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=9F=BA=E7=A1=80=E9=85=8D=E7=BD=AE=E4=B8=8E?= =?UTF-8?q?=E6=A0=B8=E5=BF=83=E5=B7=A5=E5=85=B7=E7=B1=BB-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0.gitignore=E6=96=87=E4=BB=B6=EF=BC=8C=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=90=84=E7=B1=BBIDE=E5=92=8C=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E5=BF=BD=E7=95=A5=E8=A7=84=E5=88=99=20-=20=E6=96=B0=E5=A2=9EAI?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E6=8E=A7=E5=88=B6=E5=99=A8=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81WebSocket=E6=B6=88=E6=81=AF=E6=8E=A8=E9=80=81=20-=20?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=94=AF=E4=BB=98=E5=AE=9D=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB=EF=BC=8C=E6=94=AF=E6=8C=81=E8=AF=81?= =?UTF-8?q?=E4=B9=A6=E8=AE=A4=E8=AF=81=E6=94=AF=E4=BB=98=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E9=98=BF=E9=87=8C=E4=BA=91=E7=AD=BE=E5=90=8D=E5=8F=91?= =?UTF-8?q?=E9=80=81=E5=B7=A5=E5=85=B7=E7=B1=BB=20-=20=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E7=BB=9F=E4=B8=80API=E8=BF=94=E5=9B=9E=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E5=B0=81=E8=A3=85=E7=B1=BB=20-=20=E9=85=8D=E7=BD=AE=E5=A4=9A?= =?UTF-8?q?=E7=8E=AF=E5=A2=83application=E9=85=8D=E7=BD=AE=E6=96=87?= =?UTF-8?q?=E4=BB=B6=EF=BC=88dev/prod=EF=BC=89-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E8=A7=92=E8=89=B2=E3=80=81=E6=96=87=E7=AB=A0?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E3=80=81=E4=BD=99=E9=A2=9D=E5=8F=98=E5=8A=A8?= =?UTF-8?q?=E7=AD=89=E5=B8=B8=E9=87=8F=E5=AE=9A=E4=B9=89-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0Controller=E5=9F=BA=E7=B1=BB=EF=BC=8C=E5=B0=81?= =?UTF-8?q?=E8=A3=85=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E7=AD=89=E9=80=9A=E7=94=A8=E6=96=B9=E6=B3=95=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=99=A8=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E6=96=87=E4=BB=B6=EF=BC=88add.config.ts.btl=E5=92=8Ca?= =?UTF-8?q?dd.tsx.btl=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 44 + README.md | 286 +++ pom.xml | 427 ++++ .../com/gxwebsoft/WebSoftApplication.java | 31 + .../com/gxwebsoft/common/core/Constants.java | 93 + .../core/config/BigDecimalDeserializer.java | 41 + .../core/config/CertificateProperties.java | 213 ++ .../common/core/config/ConfigProperties.java | 105 + .../core/config/HttpMessageConverter.java | 15 + .../common/core/config/JacksonConfig.java | 26 + .../config/LocalDateTimeDeserializer.java | 29 + .../core/config/LocalDateTimeSerializer.java | 27 + .../common/core/config/MqttProperties.java | 72 + .../common/core/config/MybatisPlusConfig.java | 138 ++ .../core/config/RestTemplateConfig.java | 29 + .../common/core/config/SpringContextUtil.java | 62 + .../common/core/config/SwaggerConfig.java | 111 + .../common/core/config/WebMvcConfig.java | 31 + .../core/constants/AppUserConstants.java | 8 + .../core/constants/ArticleConstants.java | 6 + .../core/constants/BalanceConstants.java | 10 + .../common/core/constants/BaseConstants.java | 5 + .../common/core/constants/OrderConstants.java | 37 + .../core/constants/PlatformConstants.java | 12 + .../core/constants/ProfitConstants.java | 9 + .../core/constants/QRCodeConstants.java | 10 + .../common/core/constants/RedisConstants.java | 47 + .../common/core/constants/TaskConstants.java | 22 + .../core/constants/WebsiteConstants.java | 14 + .../core/constants/WxOfficialConstants.java | 6 + .../core/exception/BusinessException.java | 48 + .../exception/GlobalExceptionHandler.java | 89 + .../core/security/JwtAccessDeniedHandler.java | 29 + .../security/JwtAuthenticationEntryPoint.java | 30 + .../security/JwtAuthenticationFilter.java | 118 + .../common/core/security/JwtSubject.java | 31 + .../common/core/security/JwtUtil.java | 141 ++ .../common/core/security/SecurityConfig.java | 113 + .../service/CertificateHealthService.java | 253 ++ .../core/service/CertificateService.java | 281 +++ .../EnvironmentAwarePaymentService.java | 143 ++ .../core/service/PaymentCacheService.java | 174 ++ .../common/core/utils/AliYunSender.java | 145 ++ .../common/core/utils/AlipayConfigUtil.java | 110 + .../common/core/utils/CacheClient.java | 265 +++ .../common/core/utils/CertificateLoader.java | 230 ++ .../common/core/utils/CommonUtil.java | 321 +++ .../common/core/utils/DateTimeUtil.java | 93 + .../core/utils/EncryptedQrCodeUtil.java | 433 ++++ .../common/core/utils/FileServerUtil.java | 401 ++++ .../common/core/utils/HttpUtils.java | 311 +++ .../common/core/utils/ImageUtil.java | 96 + .../common/core/utils/JChardetFacadeUtil.java | 2025 +++++++++++++++++ .../gxwebsoft/common/core/utils/JSONUtil.java | 69 + .../common/core/utils/MyQrCodeUtil.java | 85 + .../common/core/utils/OpenOfficeUtil.java | 124 + .../core/utils/QrCodeDecryptResult.java | 93 + .../common/core/utils/RedisUtil.java | 279 +++ .../common/core/utils/SignCheckUtil.java | 197 ++ .../core/utils/WechatCertAutoConfig.java | 171 ++ .../utils/WechatPayCertificateDiagnostic.java | 314 +++ .../core/utils/WechatPayCertificateFixer.java | 312 +++ .../core/utils/WechatPayConfigChecker.java | 243 ++ .../core/utils/WechatPayConfigValidator.java | 223 ++ .../core/utils/WechatPayDiagnostic.java | 222 ++ .../common/core/utils/WechatPayUtils.java | 111 + .../common/core/utils/WxNativeUtil.java | 20 + .../common/core/utils/WxOfficialUtil.java | 106 + .../gxwebsoft/common/core/utils/WxUtil.java | 132 ++ .../common/core/utils/WxWorkUtil.java | 134 ++ .../gxwebsoft/common/core/web/ApiResult.java | 87 + .../common/core/web/BaseController.java | 333 +++ .../gxwebsoft/common/core/web/BaseParam.java | 98 + .../gxwebsoft/common/core/web/BatchParam.java | 57 + .../common/core/web/ExistenceParam.java | 96 + .../gxwebsoft/common/core/web/PageParam.java | 343 +++ .../gxwebsoft/common/core/web/PageResult.java | 51 + .../system/controller/AiController.java | 139 ++ .../system/controller/CacheController.java | 117 + .../system/controller/DictController.java | 177 ++ .../system/controller/DictDataController.java | 124 + .../controller/DictionaryController.java | 148 ++ .../controller/DictionaryDataController.java | 123 + .../system/controller/DomainController.java | 127 ++ .../system/controller/EmailController.java | 48 + .../controller/LoginRecordController.java | 55 + .../system/controller/MainController.java | 314 +++ .../system/controller/MenuController.java | 145 ++ .../controller/OperationRecordController.java | 61 + .../controller/OrganizationController.java | 130 ++ .../system/controller/PlugController.java | 161 ++ .../controller/RedisUtilController.java | 77 + .../system/controller/RoleController.java | 144 ++ .../system/controller/RoleMenuController.java | 96 + .../system/controller/SettingController.java | 178 ++ .../system/controller/TenantController.java | 158 ++ .../controller/UserCollectionController.java | 135 ++ .../system/controller/UserController.java | 401 ++++ .../system/controller/UserFileController.java | 158 ++ .../controller/UserRefereeController.java | 183 ++ .../common/system/dto/PaymentCacheDTO.java | 39 + .../gxwebsoft/common/system/entity/Cache.java | 34 + .../common/system/entity/ChatMessage.java | 48 + .../common/system/entity/Company.java | 337 +++ .../common/system/entity/CompanyComment.java | 61 + .../common/system/entity/CompanyContent.java | 44 + .../common/system/entity/CompanyGit.java | 142 ++ .../system/entity/CompanyParameter.java | 57 + .../common/system/entity/CompanyUrl.java | 66 + .../gxwebsoft/common/system/entity/Dict.java | 60 + .../common/system/entity/DictData.java | 66 + .../common/system/entity/Dictionary.java | 59 + .../common/system/entity/DictionaryData.java | 67 + .../common/system/entity/Domain.java | 75 + .../common/system/entity/EmailRecord.java | 59 + .../common/system/entity/FileRecord.java | 94 + .../common/system/entity/KVEntity.java | 56 + .../common/system/entity/LoginRecord.java | 76 + .../gxwebsoft/common/system/entity/Menu.java | 87 + .../common/system/entity/OperationRecord.java | 98 + .../common/system/entity/Organization.java | 92 + .../common/system/entity/Payment.java | 100 + .../gxwebsoft/common/system/entity/Plug.java | 144 ++ .../gxwebsoft/common/system/entity/Role.java | 56 + .../common/system/entity/RoleMenu.java | 47 + .../common/system/entity/Setting.java | 61 + .../common/system/entity/Tenant.java | 78 + .../gxwebsoft/common/system/entity/User.java | 310 +++ .../common/system/entity/UserBalanceLog.java | 87 + .../common/system/entity/UserCollection.java | 45 + .../common/system/entity/UserFile.java | 79 + .../common/system/entity/UserInfo.java | 260 +++ .../common/system/entity/UserReferee.java | 59 + .../common/system/entity/UserRole.java | 52 + .../system/mapper/CompanyCommentMapper.java | 37 + .../system/mapper/CompanyContentMapper.java | 37 + .../system/mapper/CompanyGitMapper.java | 37 + .../common/system/mapper/CompanyMapper.java | 62 + .../system/mapper/CompanyParameterMapper.java | 37 + .../system/mapper/CompanyUrlMapper.java | 37 + .../common/system/mapper/DictDataMapper.java | 47 + .../common/system/mapper/DictMapper.java | 14 + .../system/mapper/DictionaryDataMapper.java | 47 + .../system/mapper/DictionaryMapper.java | 14 + .../common/system/mapper/DomainMapper.java | 37 + .../system/mapper/EmailRecordMapper.java | 14 + .../system/mapper/FileRecordMapper.java | 47 + .../system/mapper/LoginRecordMapper.java | 48 + .../common/system/mapper/MenuMapper.java | 22 + .../system/mapper/OperationRecordMapper.java | 48 + .../system/mapper/OrganizationMapper.java | 37 + .../common/system/mapper/PaymentMapper.java | 40 + .../common/system/mapper/PlugMapper.java | 42 + .../common/system/mapper/RoleMapper.java | 14 + .../common/system/mapper/RoleMenuMapper.java | 39 + .../common/system/mapper/SettingMapper.java | 40 + .../common/system/mapper/TenantMapper.java | 37 + .../system/mapper/UserBalanceLogMapper.java | 37 + .../system/mapper/UserCollectionMapper.java | 37 + .../common/system/mapper/UserFileMapper.java | 14 + .../common/system/mapper/UserMapper.java | 69 + .../system/mapper/UserRefereeMapper.java | 37 + .../common/system/mapper/UserRoleMapper.java | 45 + .../mapper/xml/CompanyCommentMapper.xml | 53 + .../mapper/xml/CompanyContentMapper.xml | 38 + .../system/mapper/xml/CompanyGitMapper.xml | 65 + .../system/mapper/xml/CompanyMapper.xml | 198 ++ .../mapper/xml/CompanyParameterMapper.xml | 50 + .../system/mapper/xml/CompanyUrlMapper.xml | 59 + .../system/mapper/xml/DictDataMapper.xml | 71 + .../common/system/mapper/xml/DictMapper.xml | 5 + .../mapper/xml/DictionaryDataMapper.xml | 71 + .../system/mapper/xml/DictionaryMapper.xml | 5 + .../common/system/mapper/xml/DomainMapper.xml | 62 + .../system/mapper/xml/EmailRecordMapper.xml | 5 + .../system/mapper/xml/FileRecordMapper.xml | 76 + .../system/mapper/xml/LoginRecordMapper.xml | 62 + .../common/system/mapper/xml/MenuMapper.xml | 32 + .../mapper/xml/OperationRecordMapper.xml | 71 + .../system/mapper/xml/OrganizationMapper.xml | 98 + .../system/mapper/xml/PaymentMapper.xml | 90 + .../common/system/mapper/xml/PlugMapper.xml | 105 + .../common/system/mapper/xml/RoleMapper.xml | 5 + .../system/mapper/xml/RoleMenuMapper.xml | 42 + .../system/mapper/xml/SettingMapper.xml | 33 + .../common/system/mapper/xml/TenantMapper.xml | 56 + .../mapper/xml/UserCollectionMapper.xml | 38 + .../system/mapper/xml/UserFileMapper.xml | 5 + .../common/system/mapper/xml/UserMapper.xml | 264 +++ .../system/mapper/xml/UserRefereeMapper.xml | 50 + .../system/mapper/xml/UserRoleMapper.xml | 35 + .../common/system/param/AlipayParam.java | 31 + .../common/system/param/CacheParam.java | 25 + .../system/param/CompanyCommentParam.java | 58 + .../system/param/CompanyContentParam.java | 35 + .../common/system/param/CompanyGitParam.java | 60 + .../common/system/param/CompanyParam.java | 167 ++ .../system/param/CompanyParameterParam.java | 50 + .../common/system/param/CompanyUrlParam.java | 59 + .../common/system/param/DictDataParam.java | 55 + .../common/system/param/DictParam.java | 34 + .../system/param/DictionaryDataParam.java | 55 + .../common/system/param/DictionaryParam.java | 38 + .../common/system/param/DomainParam.java | 61 + .../common/system/param/FileRecordParam.java | 70 + .../common/system/param/LoginParam.java | 37 + .../common/system/param/LoginRecordParam.java | 60 + .../common/system/param/MenuParam.java | 68 + .../system/param/OperationRecordParam.java | 67 + .../system/param/OrganizationParam.java | 81 + .../common/system/param/PaymentParam.java | 81 + .../common/system/param/PlugParam.java | 95 + .../common/system/param/RoleParam.java | 41 + .../common/system/param/SettingParam.java | 50 + .../common/system/param/SmsCaptchaParam.java | 31 + .../common/system/param/TenantParam.java | 55 + .../system/param/UpdatePasswordParam.java | 31 + .../system/param/UserBalanceLogParam.java | 77 + .../system/param/UserCollectionParam.java | 37 + .../common/system/param/UserFileParam.java | 40 + .../common/system/param/UserImportParam.java | 42 + .../common/system/param/UserParam.java | 249 ++ .../common/system/param/UserRefereeParam.java | 48 + .../common/system/result/CaptchaResult.java | 30 + .../common/system/result/LoginResult.java | 31 + .../common/system/result/RedisResult.java | 34 + .../system/result/SmsCaptchaResult.java | 26 + .../system/service/CompanyCommentService.java | 42 + .../system/service/CompanyContentService.java | 42 + .../system/service/CompanyGitService.java | 42 + .../service/CompanyParameterService.java | 42 + .../common/system/service/CompanyService.java | 51 + .../system/service/CompanyUrlService.java | 42 + .../system/service/DictDataService.java | 52 + .../common/system/service/DictService.java | 14 + .../system/service/DictionaryDataService.java | 51 + .../system/service/DictionaryService.java | 14 + .../common/system/service/DomainService.java | 42 + .../system/service/DomainServiceImpl.java | 46 + .../system/service/EmailRecordService.java | 51 + .../system/service/FileRecordService.java | 58 + .../system/service/LoginRecordService.java | 54 + .../common/system/service/MenuService.java | 18 + .../service/OperationRecordService.java | 49 + .../system/service/OrganizationService.java | 42 + .../common/system/service/PaymentService.java | 43 + .../common/system/service/PlugService.java | 44 + .../system/service/RoleMenuService.java | 35 + .../common/system/service/RoleService.java | 14 + .../common/system/service/SettingService.java | 67 + .../common/system/service/TenantService.java | 42 + .../system/service/UserBalanceLogService.java | 42 + .../system/service/UserCollectionService.java | 42 + .../service/UserCollectionServiceImpl.java | 46 + .../system/service/UserFileService.java | 14 + .../system/service/UserRefereeService.java | 45 + .../system/service/UserRoleService.java | 42 + .../common/system/service/UserService.java | 122 + .../impl/CompanyCommentServiceImpl.java | 47 + .../impl/CompanyContentServiceImpl.java | 47 + .../service/impl/CompanyGitServiceImpl.java | 47 + .../impl/CompanyParameterServiceImpl.java | 47 + .../service/impl/CompanyServiceImpl.java | 86 + .../service/impl/CompanyUrlServiceImpl.java | 47 + .../service/impl/DictDataServiceImpl.java | 52 + .../system/service/impl/DictServiceImpl.java | 18 + .../impl/DictionaryDataServiceImpl.java | 52 + .../service/impl/DictionaryServiceImpl.java | 18 + .../service/impl/EmailRecordServiceImpl.java | 99 + .../service/impl/FileRecordServiceImpl.java | 63 + .../service/impl/LoginRecordServiceImpl.java | 78 + .../system/service/impl/MenuServiceImpl.java | 139 ++ .../impl/OperationRecordServiceImpl.java | 52 + .../service/impl/OrganizationServiceImpl.java | 45 + .../service/impl/PaymentServiceImpl.java | 52 + .../system/service/impl/PlugServiceImpl.java | 112 + .../service/impl/RoleMenuServiceImpl.java | 31 + .../system/service/impl/RoleServiceImpl.java | 18 + .../service/impl/SettingServiceImpl.java | 254 +++ .../service/impl/TenantServiceImpl.java | 46 + .../impl/UserBalanceLogServiceImpl.java | 47 + .../service/impl/UserFileServiceImpl.java | 18 + .../service/impl/UserRefereeServiceImpl.java | 74 + .../service/impl/UserRoleServiceImpl.java | 37 + .../system/service/impl/UserServiceImpl.java | 247 ++ src/main/resources/application-dev.yml | 65 + src/main/resources/application-prod.yml | 84 + src/main/resources/application.yml | 236 ++ src/test/java/com/gxwebsoft/TestMain.java | 21 + .../gxwebsoft/generator/ShopGenerator.java | 435 ++++ .../engine/BeetlTemplateEnginePlus.java | 50 + .../generator/templates/add.config.ts.btl | 4 + .../gxwebsoft/generator/templates/add.tsx.btl | 115 + .../templates/columns.config.vue.btl | 47 + .../templates/components.edit.vue.btl | 221 ++ .../templates/components.search.vue.btl | 42 + .../generator/templates/controller.java.btl | 278 +++ .../generator/templates/entity.java.btl | 157 ++ .../generator/templates/index.config.ts.btl | 4 + .../generator/templates/index.ts.btl | 105 + .../generator/templates/index.ts.uniapp.btl | 101 + .../generator/templates/index.tsx.btl | 171 ++ .../generator/templates/index.vue.btl | 242 ++ .../generator/templates/mapper.java.btl | 41 + .../generator/templates/mapper.xml.btl | 100 + .../generator/templates/model.ts.btl | 43 + .../generator/templates/model.ts.uniapp.btl | 43 + .../generator/templates/param.java.btl | 146 ++ .../generator/templates/service.java.btl | 55 + .../generator/templates/serviceImpl.java.btl | 62 + .../generator/templates/smart-columns.vue.btl | 89 + .../templates/table-columns-config.js | 60 + .../templates/table-with-column-settings.vue | 263 +++ 313 files changed, 29669 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/com/gxwebsoft/WebSoftApplication.java create mode 100644 src/main/java/com/gxwebsoft/common/core/Constants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/BigDecimalDeserializer.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/CertificateProperties.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/ConfigProperties.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/HttpMessageConverter.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/JacksonConfig.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeDeserializer.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeSerializer.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/MqttProperties.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/MybatisPlusConfig.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/RestTemplateConfig.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/SpringContextUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java create mode 100644 src/main/java/com/gxwebsoft/common/core/config/WebMvcConfig.java create mode 100644 src/main/java/com/gxwebsoft/common/core/constants/AppUserConstants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/constants/ArticleConstants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/constants/BalanceConstants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/constants/BaseConstants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/constants/OrderConstants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/constants/PlatformConstants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/constants/ProfitConstants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/constants/QRCodeConstants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/constants/RedisConstants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/constants/TaskConstants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/constants/WebsiteConstants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/constants/WxOfficialConstants.java create mode 100644 src/main/java/com/gxwebsoft/common/core/exception/BusinessException.java create mode 100644 src/main/java/com/gxwebsoft/common/core/exception/GlobalExceptionHandler.java create mode 100644 src/main/java/com/gxwebsoft/common/core/security/JwtAccessDeniedHandler.java create mode 100644 src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationEntryPoint.java create mode 100644 src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/gxwebsoft/common/core/security/JwtSubject.java create mode 100644 src/main/java/com/gxwebsoft/common/core/security/JwtUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java create mode 100644 src/main/java/com/gxwebsoft/common/core/service/CertificateHealthService.java create mode 100644 src/main/java/com/gxwebsoft/common/core/service/CertificateService.java create mode 100644 src/main/java/com/gxwebsoft/common/core/service/EnvironmentAwarePaymentService.java create mode 100644 src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/AliYunSender.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/AlipayConfigUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/CacheClient.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/CertificateLoader.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/CommonUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/DateTimeUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/EncryptedQrCodeUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/FileServerUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/HttpUtils.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/ImageUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/JChardetFacadeUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/JSONUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/MyQrCodeUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/OpenOfficeUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/QrCodeDecryptResult.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/RedisUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/SignCheckUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/WechatCertAutoConfig.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateDiagnostic.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateFixer.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigChecker.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/WechatPayDiagnostic.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/WechatPayUtils.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/WxNativeUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/WxUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/utils/WxWorkUtil.java create mode 100644 src/main/java/com/gxwebsoft/common/core/web/ApiResult.java create mode 100644 src/main/java/com/gxwebsoft/common/core/web/BaseController.java create mode 100644 src/main/java/com/gxwebsoft/common/core/web/BaseParam.java create mode 100644 src/main/java/com/gxwebsoft/common/core/web/BatchParam.java create mode 100644 src/main/java/com/gxwebsoft/common/core/web/ExistenceParam.java create mode 100644 src/main/java/com/gxwebsoft/common/core/web/PageParam.java create mode 100644 src/main/java/com/gxwebsoft/common/core/web/PageResult.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/AiController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/CacheController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/DictController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/DictDataController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/DictionaryController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/DictionaryDataController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/DomainController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/EmailController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/LoginRecordController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/MainController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/MenuController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/OperationRecordController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/OrganizationController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/PlugController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/RedisUtilController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/RoleController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/RoleMenuController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/SettingController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/TenantController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/UserCollectionController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/UserController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/UserFileController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/controller/UserRefereeController.java create mode 100644 src/main/java/com/gxwebsoft/common/system/dto/PaymentCacheDTO.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/Cache.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/ChatMessage.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/Company.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/CompanyComment.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/CompanyContent.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/CompanyGit.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/CompanyParameter.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/CompanyUrl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/Dict.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/DictData.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/Dictionary.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/DictionaryData.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/Domain.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/EmailRecord.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/FileRecord.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/KVEntity.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/LoginRecord.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/Menu.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/OperationRecord.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/Organization.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/Payment.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/Plug.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/Role.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/RoleMenu.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/Setting.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/Tenant.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/User.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/UserBalanceLog.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/UserCollection.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/UserFile.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/UserInfo.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/UserReferee.java create mode 100644 src/main/java/com/gxwebsoft/common/system/entity/UserRole.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/CompanyCommentMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/CompanyContentMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/CompanyGitMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/CompanyMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/CompanyParameterMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/CompanyUrlMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/DictDataMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/DictMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/DictionaryDataMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/DictionaryMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/DomainMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/EmailRecordMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/FileRecordMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/LoginRecordMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/MenuMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/OperationRecordMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/OrganizationMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/PaymentMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/PlugMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/RoleMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/RoleMenuMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/SettingMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/TenantMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/UserBalanceLogMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/UserCollectionMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/UserFileMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/UserMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/UserRefereeMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/UserRoleMapper.java create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyCommentMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyContentMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyGitMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyParameterMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyUrlMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/DictDataMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/DictMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryDataMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/DomainMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/EmailRecordMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/FileRecordMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/LoginRecordMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/MenuMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/OperationRecordMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/OrganizationMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/PaymentMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/PlugMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMenuMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/SettingMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/UserCollectionMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/UserFileMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRefereeMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRoleMapper.xml create mode 100644 src/main/java/com/gxwebsoft/common/system/param/AlipayParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/CacheParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/CompanyCommentParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/CompanyContentParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/CompanyGitParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/CompanyParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/CompanyParameterParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/CompanyUrlParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/DictDataParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/DictParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/DictionaryDataParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/DictionaryParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/DomainParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/FileRecordParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/LoginParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/LoginRecordParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/MenuParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/OperationRecordParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/OrganizationParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/PaymentParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/PlugParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/RoleParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/SettingParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/SmsCaptchaParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/TenantParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/UpdatePasswordParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/UserBalanceLogParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/UserCollectionParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/UserFileParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/UserImportParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/UserParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/param/UserRefereeParam.java create mode 100644 src/main/java/com/gxwebsoft/common/system/result/CaptchaResult.java create mode 100644 src/main/java/com/gxwebsoft/common/system/result/LoginResult.java create mode 100644 src/main/java/com/gxwebsoft/common/system/result/RedisResult.java create mode 100644 src/main/java/com/gxwebsoft/common/system/result/SmsCaptchaResult.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/CompanyCommentService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/CompanyContentService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/CompanyGitService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/CompanyParameterService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/CompanyService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/CompanyUrlService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/DictDataService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/DictService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/DictionaryDataService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/DictionaryService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/DomainService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/DomainServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/EmailRecordService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/FileRecordService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/LoginRecordService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/MenuService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/OperationRecordService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/OrganizationService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/PaymentService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/PlugService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/RoleMenuService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/RoleService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/SettingService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/TenantService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/UserBalanceLogService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/UserCollectionService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/UserCollectionServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/UserFileService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/UserRefereeService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/UserRoleService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/UserService.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/CompanyCommentServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/CompanyContentServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/CompanyGitServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/CompanyParameterServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/CompanyServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/CompanyUrlServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/DictDataServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/DictServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryDataServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/EmailRecordServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/FileRecordServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/LoginRecordServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/MenuServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/OperationRecordServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/OrganizationServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/PaymentServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/PlugServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/RoleMenuServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/RoleServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/SettingServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/TenantServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/UserBalanceLogServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/UserFileServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/UserRefereeServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/UserRoleServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/common/system/service/impl/UserServiceImpl.java create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application-prod.yml create mode 100644 src/main/resources/application.yml create mode 100644 src/test/java/com/gxwebsoft/TestMain.java create mode 100644 src/test/java/com/gxwebsoft/generator/ShopGenerator.java create mode 100644 src/test/java/com/gxwebsoft/generator/engine/BeetlTemplateEnginePlus.java create mode 100644 src/test/java/com/gxwebsoft/generator/templates/add.config.ts.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/add.tsx.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/columns.config.vue.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/components.edit.vue.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/components.search.vue.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/controller.java.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/entity.java.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/index.config.ts.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/index.ts.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/index.ts.uniapp.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/index.tsx.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/index.vue.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/mapper.java.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/mapper.xml.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/model.ts.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/model.ts.uniapp.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/param.java.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/service.java.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/serviceImpl.java.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/smart-columns.vue.btl create mode 100644 src/test/java/com/gxwebsoft/generator/templates/table-columns-config.js create mode 100644 src/test/java/com/gxwebsoft/generator/templates/table-with-column-settings.vue diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cda18ea --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ +/cert/ +/src/main/resources/dev/ + +### macOS ### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db +/file/ +/websoft-modules.log diff --git a/README.md b/README.md new file mode 100644 index 0000000..ef5a814 --- /dev/null +++ b/README.md @@ -0,0 +1,286 @@ +
+

🚀 WebSoft API

+

基于 Spring Boot + MyBatis Plus 的企业级后端API服务

+ +

+ Java + Spring Boot + MyBatis Plus + MySQL + Redis + License +

+
+ +## 📖 项目简介 + +WebSoft API 是一个基于 **Spring Boot + MyBatis Plus** 构建的现代化企业级后端API服务,采用最新的Java技术栈: + +- **核心框架**:Spring Boot 2.5.4 + Spring Security + Spring AOP +- **数据访问**:MyBatis Plus 3.4.3 + Druid 连接池 +- **数据库**:MySQL + Redis +- **文档工具**:Swagger 3.0 + Knife4j +- **工具库**:Hutool、Lombok、FastJSON + + + +## 项目演示 +| 后台管理系统 | https://mp.websoft.top | +|--------|-------------------------------------------------------------------------------------------------------------------------------------| +| 测试账号 | 13800010123,123456 +| 正式账号 | [立即注册](https://mp.websoft.top/register/?inviteCode=github) | +| 关注公众号 | ![输入图片说明](https://oss.wsdns.cn/20240327/f1175cc5aae741d3af05484747270bd5.jpeg?x-oss-process=image/resize,m_fixed,w_150/quality,Q_90) | + + + + +## 🛠️ 技术栈 + +### 核心框架 +| 技术 | 版本 | 说明 | +|------|------|------| +| Java | 1.8+ | 编程语言 | +| Spring Boot | 2.5.4 | 微服务框架 | +| Spring Security | 5.5.x | 安全框架 | +| MyBatis Plus | 3.4.3 | ORM框架 | +| MySQL | 8.0+ | 关系型数据库 | +| Redis | 6.0+ | 缓存数据库 | +| Druid | 1.2.6 | 数据库连接池 | + +### 功能组件 +- **Swagger 3.0 + Knife4j** - API文档生成与测试 +- **JWT** - 用户认证与授权 +- **Hutool** - Java工具类库 +- **EasyPOI** - Excel文件处理 +- **阿里云OSS** - 对象存储服务 +- **微信支付/支付宝** - 支付集成 +- **Socket.IO** - 实时通信 +- **MQTT** - 物联网消息传输 + +## 📋 环境要求 + +### 基础环境 +- ☕ **Java 1.8+** +- 🗄️ **MySQL 8.0+** +- 🔴 **Redis 6.0+** +- 📦 **Maven 3.6+** + +### 开发工具 +- **推荐**:IntelliJ IDEA / Eclipse +- **插件**:Lombok Plugin、MyBatis Plugin + +## 🚀 快速开始 + +### 1. 克隆项目 +```bash +git clone https://github.com/websoft-top/mp-java.git +cd mp-java +``` + +### 2. 数据库配置 +```sql +-- 创建数据库 +CREATE DATABASE websoft_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- 导入数据库脚本(如果有的话) +-- source /path/to/database.sql +``` + +### 3. 配置文件 +编辑 `src/main/resources/application-dev.yml` 文件,配置数据库连接: +```yaml +spring: + datasource: + url: jdbc:mysql://localhost:3306/websoft_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8 + username: your_username + password: your_password + redis: + host: localhost + port: 6379 + password: your_redis_password +``` + +### 4. 启动项目 +```bash +# 使用 Maven 启动 +mvn spring-boot:run + +# 或者使用 IDE 直接运行 WebSoftApplication.java +``` + +访问 `http://localhost:9200` 即可看到API服务。 + +### 5. API文档 +启动项目后,访问以下地址查看API文档: +- Swagger UI: `http://localhost:9200/swagger-ui/index.html` +- Knife4j: `http://localhost:9200/doc.html` + +## ⚙️ 配置说明 + +### 数据库配置 +在 `application-dev.yml` 中配置数据库连接: +```yaml +spring: + datasource: + url: jdbc:mysql://localhost:3306/websoft_db + username: root + password: your_password + driver-class-name: com.mysql.cj.jdbc.Driver +``` + +### Redis配置 +```yaml +spring: + redis: + host: localhost + port: 6379 + password: your_redis_password + database: 0 +``` + +### 阿里云OSS配置 +```yaml +config: + endpoint: https://oss-cn-shenzhen.aliyuncs.com + accessKeyId: your_access_key_id + accessKeySecret: your_access_key_secret + bucketName: your_bucket_name + bucketDomain: https://your-domain.com +``` + +### 其他配置 +- **JWT密钥**:`config.token-key` 用于JWT令牌加密 +- **文件上传路径**:`config.upload-path` 本地文件存储路径 +- **邮件服务**:配置SMTP服务器用于发送邮件 + +## 🎯 核心功能 + +### 🔐 用户认证与授权 +- **JWT认证**:基于JSON Web Token的用户认证 +- **Spring Security**:完整的安全框架集成 +- **角色权限**:基于RBAC的权限控制 +- **图形验证码**:防止恶意登录 + +### 📝 内容管理系统(CMS) +- **文章管理**:支持富文本内容管理 +- **媒体文件**:图片/视频文件上传与管理 +- **分类管理**:内容分类与标签管理 +- **SEO优化**:搜索引擎优化支持 + +### 🛒 电商系统 +- **商品管理**:商品信息、规格、库存管理 +- **订单系统**:完整的订单流程管理 +- **支付集成**:支持微信支付、支付宝 +- **物流跟踪**:快递100物流查询集成 + +### 🔧 系统管理 +- **用户管理**:用户信息维护与管理 +- **系统配置**:动态配置管理 +- **日志监控**:系统操作日志记录 +- **数据备份**:数据库备份与恢复 + +### 📊 数据分析 +- **统计报表**:业务数据统计分析 +- **图表展示**:数据可视化展示 +- **导出功能**:Excel数据导出 +- **实时监控**:系统性能监控 + +## 🏗️ 项目结构 + +``` +src/main/java/com/gxwebsoft/ +├── WebSoftApplication.java # 启动类 +├── cms/ # 内容管理模块 +│ ├── controller/ # 控制器层 +│ ├── service/ # 业务逻辑层 +│ ├── mapper/ # 数据访问层 +│ └── entity/ # 实体类 +├── shop/ # 商城模块 +│ ├── controller/ +│ ├── service/ +│ ├── mapper/ +│ └── entity/ +├── common/ # 公共模块 +│ ├── core/ # 核心配置 +│ ├── utils/ # 工具类 +│ └── exception/ # 异常处理 +└── resources/ + ├── application.yml # 主配置文件 + ├── application-dev.yml # 开发环境配置 + └── application-prod.yml# 生产环境配置 +``` + +## 🔧 开发规范 + +### 代码结构 +- **Controller层**:处理HTTP请求,参数验证 +- **Service层**:业务逻辑处理,事务管理 +- **Mapper层**:数据访问,SQL映射 +- **Entity层**:数据实体,数据库表映射 + +### 命名规范 +- **类名**:使用大驼峰命名法(PascalCase) +- **方法名**:使用小驼峰命名法(camelCase) +- **常量**:使用全大写,下划线分隔 +- **包名**:使用小写字母,点分隔 + +## 📚 API文档 + +项目集成了Swagger和Knife4j,提供完整的API文档: + +### 访问地址 +- **Swagger UI**: `http://localhost:9200/swagger-ui/index.html` +- **Knife4j**: `http://localhost:9200/doc.html` + +### 主要接口模块 +- **用户认证**: `/api/auth/**` - 登录、注册、权限验证 +- **用户管理**: `/api/user/**` - 用户CRUD操作 +- **内容管理**: `/api/cms/**` - 文章、媒体文件管理 +- **商城管理**: `/api/shop/**` - 商品、订单管理 +- **系统管理**: `/api/system/**` - 系统配置、日志管理 + +## 🚀 部署指南 + +### 开发环境部署 +```bash +# 1. 启动MySQL和Redis服务 +# 2. 创建数据库并导入初始数据 +# 3. 修改配置文件 +# 4. 启动应用 +mvn spring-boot:run +``` + +### 生产环境部署 +```bash +# 1. 打包应用 +mvn clean package -Dmaven.test.skip=true + +# 2. 运行jar包 +java -jar target/com-gxwebsoft-modules-1.5.0.jar --spring.profiles.active=prod + +# 3. 使用Docker部署(可选) +docker build -t websoft-api . +docker run -d -p 9200:9200 websoft-api +``` + +## 🤝 贡献指南 + +1. Fork 本仓库 +2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) +3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) +4. 推送到分支 (`git push origin feature/AmazingFeature`) +5. 打开 Pull Request + +## 📄 许可证 + +本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情 + +## 📞 联系我们 + +- 官网:https://websoft.top +- 邮箱:170083662@qq.top +- QQ群:479713884 + +--- + +⭐ 如果这个项目对您有帮助,请给我们一个星标! \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c64a5b4 --- /dev/null +++ b/pom.xml @@ -0,0 +1,427 @@ + + + 4.0.0 + + com.gxwebsoft + com-gxwebsoft-modules + 1.5.0 + + com-gxwebsoft-api + WebSoftApi project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 2.7.18 + + + + + 17 + UTF-8 + UTF-8 + + + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.springframework.boot + spring-boot-starter-web + + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + org.projectlombok + lombok + true + + + + + com.mysql + mysql-connector-j + runtime + + + + + com.alibaba + druid-spring-boot-starter + 1.2.20 + + + + + com.baomidou + mybatis-plus-boot-starter + 3.4.3.3 + + + + + com.github.yulichang + mybatis-plus-join-boot-starter + 1.4.5 + + + + + com.baomidou + mybatis-plus-generator + 3.4.1 + + + + + cn.hutool + hutool-core + 5.8.25 + + + cn.hutool + hutool-extra + 5.8.25 + + + cn.hutool + hutool-http + 5.8.25 + + + cn.hutool + hutool-crypto + 5.8.25 + + + + + cn.afterturn + easypoi-base + 4.4.0 + + + + + org.apache.tika + tika-core + 2.9.1 + + + + + com.github.livesense + jodconverter-core + 1.0.5 + + + + + org.springframework.boot + spring-boot-starter-mail + + + + + com.ibeetl + beetl + 3.15.10.RELEASE + + + + + org.springdoc + springdoc-openapi-ui + 1.7.0 + + + + + org.springframework.boot + spring-boot-starter-security + + + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + runtime + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + runtime + + + + + com.github.whvcse + easy-captcha + 1.6.2 + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + com.aliyun + aliyun-java-sdk-core + 4.4.3 + + + + com.alipay.sdk + alipay-sdk-java + 4.35.0.ALL + + + + org.bouncycastle + bcprov-jdk18on + 1.77 + + + + commons-logging + commons-logging + 1.3.0 + + + + com.alibaba + fastjson + 2.0.43 + + + + + com.google.zxing + core + 3.5.2 + + + + com.google.code.gson + gson + 2.10.1 + + + + com.vaadin.external.google + android-json + 0.0.20131108.vaadin1 + compile + + + + + com.corundumstudio.socketio + netty-socketio + 2.0.2 + + + + + com.github.wechatpay-apiv3 + wechatpay-java + 0.2.17 + + + + + org.springframework.integration + spring-integration-mqtt + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + 1.2.0 + + + + com.github.binarywang + weixin-java-miniapp + 4.6.0 + + + + com.github.binarywang + weixin-java-mp + 4.6.0 + + + + + com.aliyun.oss + aliyun-sdk-oss + 3.17.4 + + + + com.github.kuaidi100-api + sdk + 1.0.13 + + + + + com.nuonuo + open-sdk + 1.0.5.2 + + + + + com.github.xiaoymin + knife4j-openapi3-spring-boot-starter + 4.3.0 + + + + com.belerweb + pinyin4j + 2.5.1 + + + + + com.aliyun + alimt20181012 + 1.0.3 + + + com.aliyun + tea-openapi + 0.2.5 + + + + com.squareup.okhttp3 + okhttp + 4.12.0 + + + + com.github.ben-manes.caffeine + caffeine + 3.1.8 + + + + com.freewayso + image-combiner + 2.6.9 + + + + org.springframework.boot + spring-boot-starter-websocket + + + + com.aliyun + bailian20231229 + 2.4.0 + + + + + + + + src/main/java + + **/*Mapper.xml + + + + src/main/resources + + ** + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.project-lombok + lombok + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + + + + + aliYunMaven + https://maven.aliyun.com/repository/public + + + + diff --git a/src/main/java/com/gxwebsoft/WebSoftApplication.java b/src/main/java/com/gxwebsoft/WebSoftApplication.java new file mode 100644 index 0000000..1a7fa35 --- /dev/null +++ b/src/main/java/com/gxwebsoft/WebSoftApplication.java @@ -0,0 +1,31 @@ +package com.gxwebsoft; + +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.config.MqttProperties; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.socket.config.annotation.EnableWebSocket; + +/** + * 启动类 + * Created by WebSoft on 2018-02-22 11:29:03 + */ +@EnableAsync +@EnableTransactionManagement +@MapperScan("com.gxwebsoft.**.mapper") +@EnableConfigurationProperties({ConfigProperties.class, MqttProperties.class}) +@SpringBootApplication +@EnableScheduling +@EnableWebSocket +public class WebSoftApplication { + + public static void main(String[] args) { + SpringApplication.run(WebSoftApplication.class, args); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/Constants.java b/src/main/java/com/gxwebsoft/common/core/Constants.java new file mode 100644 index 0000000..be48387 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/Constants.java @@ -0,0 +1,93 @@ +package com.gxwebsoft.common.core; + +/** + * 系统常量 + * Created by WebSoft on 2019-10-29 15:55 + */ +public class Constants { + /** + * 默认成功码 + */ + public static final int RESULT_OK_CODE = 0; + + /** + * 默认失败码 + */ + public static final int RESULT_ERROR_CODE = 1; + + /** + * 默认成功信息 + */ + public static final String RESULT_OK_MSG = "操作成功"; + + /** + * 默认失败信息 + */ + public static final String RESULT_ERROR_MSG = "操作失败"; + + /** + * 无权限错误码 + */ + public static final int UNAUTHORIZED_CODE = 403; + + /** + * 无权限提示信息 + */ + public static final String UNAUTHORIZED_MSG = "没有访问权限"; + + /** + * 未认证错误码 + */ + public static final int UNAUTHENTICATED_CODE = 401; + + /** + * 未认证提示信息 + */ + public static final String UNAUTHENTICATED_MSG = "请先登录"; + + /** + * 登录过期错误码 + */ + public static final int TOKEN_EXPIRED_CODE = 401; + + /** + * 登录过期提示信息 + */ + public static final String TOKEN_EXPIRED_MSG = "登录已过期"; + + /** + * 非法token错误码 + */ + public static final int BAD_CREDENTIALS_CODE = 401; + + /** + * 非法token提示信息 + */ + public static final String BAD_CREDENTIALS_MSG = "请退出重新登录"; + + /** + * 表示升序的值 + */ + public static final String ORDER_ASC_VALUE = "asc"; + + /** + * 表示降序的值 + */ + public static final String ORDER_DESC_VALUE = "desc"; + + /** + * token通过header传递的名称 + */ + public static final String TOKEN_HEADER_NAME = "Authorization"; + + /** + * token通过参数传递的名称 + */ + public static final String TOKEN_PARAM_NAME = "access_token"; + + /** + * token认证类型 + */ + public static final String TOKEN_TYPE = "Bearer"; + +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/BigDecimalDeserializer.java b/src/main/java/com/gxwebsoft/common/core/config/BigDecimalDeserializer.java new file mode 100644 index 0000000..ed76d34 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/BigDecimalDeserializer.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.common.core.config; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.math.BigDecimal; + +/** + * BigDecimal 自定义反序列化器 + * 处理null值和空字符串,避免反序列化异常 + * + * @author WebSoft + * @since 2025-01-15 + */ +@Slf4j +public class BigDecimalDeserializer extends JsonDeserializer { + + @Override + public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + String value = p.getValueAsString(); + + if (value == null || value.trim().isEmpty() || "null".equals(value)) { + return null; + } + + try { + return new BigDecimal(value); + } catch (NumberFormatException e) { + log.warn("无法解析BigDecimal值: {}, 返回null", value); + return null; + } + } + + @Override + public BigDecimal getNullValue(DeserializationContext ctxt) { + return null; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/CertificateProperties.java b/src/main/java/com/gxwebsoft/common/core/config/CertificateProperties.java new file mode 100644 index 0000000..d8cbb5e --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/CertificateProperties.java @@ -0,0 +1,213 @@ +package com.gxwebsoft.common.core.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 证书配置属性类 + * 支持开发环境从classpath加载证书,生产环境从Docker挂载卷加载证书 + * + * @author 科技小王子 + * @since 2024-07-26 + */ +@Data +@Component +@ConfigurationProperties(prefix = "certificate") +public class CertificateProperties { + + /** + * 证书加载模式 + * CLASSPATH: 从classpath加载(开发环境) + * FILESYSTEM: 从文件系统加载(生产环境) + * VOLUME: 从Docker挂载卷加载(容器环境) + */ + private LoadMode loadMode = LoadMode.CLASSPATH; + + /** + * Docker挂载卷证书根路径 + */ + private String certRootPath = "/www/wwwroot/file.ws"; + + /** + * 开发环境证书路径前缀 + */ + private String devCertPath = "dev"; + + /** + * 微信支付证书配置 + */ + private WechatPayConfig wechatPay = new WechatPayConfig(); + + /** + * 支付宝证书配置 + */ + private AlipayConfig alipay = new AlipayConfig(); + + /** + * 证书加载模式枚举 + */ + public enum LoadMode { + CLASSPATH, // 从classpath加载 + FILESYSTEM, // 从文件系统加载 + VOLUME // 从Docker挂载卷加载 + } + + /** + * 微信支付证书配置 + */ + @Data + public static class WechatPayConfig { + /** + * 开发环境配置 + */ + private DevConfig dev = new DevConfig(); + + /** + * 生产环境基础路径 + */ + private String prodBasePath = "/file"; + + /** + * 微信支付证书目录名 + */ + private String certDir = "wechat"; + + @Data + public static class DevConfig { + /** + * APIv3密钥 + */ + private String apiV3Key; + + /** + * 商户私钥证书文件名 + */ + private String privateKeyFile = "apiclient_key.pem"; + + /** + * 商户证书文件名 + */ + private String apiclientCertFile = "apiclient_cert.pem"; + + /** + * 微信支付平台证书文件名 + */ + private String wechatpayCertFile = "wechatpay_cert.pem"; + } + } + + /** + * 支付宝证书配置 + */ + @Data + public static class AlipayConfig { + /** + * 支付宝证书目录名 + */ + private String certDir = "alipay"; + + /** + * 应用私钥文件名 + */ + private String appPrivateKeyFile = "app_private_key.pem"; + + /** + * 应用公钥证书文件名 + */ + private String appCertPublicKeyFile = "appCertPublicKey.crt"; + + /** + * 支付宝公钥证书文件名 + */ + private String alipayCertPublicKeyFile = "alipayCertPublicKey.crt"; + + /** + * 支付宝根证书文件名 + */ + private String alipayRootCertFile = "alipayRootCert.crt"; + } + + /** + * 获取证书文件的完整路径 + * + * @param certType 证书类型(wechat/alipay) + * @param fileName 文件名 + * @return 完整路径 + */ + public String getCertificatePath(String certType, String fileName) { + switch (loadMode) { + case CLASSPATH: + return devCertPath + "/" + certType + "/" + fileName; + case FILESYSTEM: + return System.getProperty("user.dir") + "/certs/" + certType + "/" + fileName; + case VOLUME: + return certRootPath + "/" + certType + "/" + fileName; + default: + throw new IllegalArgumentException("不支持的证书加载模式: " + loadMode); + } + } + + /** + * 获取微信支付证书路径 + * + * @param fileName 文件名 + * @return 完整路径 + */ + public String getWechatPayCertPath(String fileName) { + // 生产环境特殊处理:数据库中存储的路径需要拼接到 /file/ 目录下 + if (loadMode == LoadMode.VOLUME) { + // 修复路径拼接逻辑:数据库中存储的路径如果已经包含 /file,则直接拼接 + if (fileName.startsWith("/file/")) { + // 路径已经包含 /file/ 前缀,直接拼接到根路径 + return certRootPath + fileName; + } else if (fileName.startsWith("file/")) { + // 路径包含 file/ 前缀,添加根路径和斜杠 + return certRootPath + "/" + fileName; + } else { + // 路径不包含 file 前缀,添加完整的 /file/ 前缀 + return certRootPath + "/file/" + fileName; + } + } else { + // 开发环境和文件系统模式使用原有逻辑 + return getCertificatePath(wechatPay.getCertDir(), fileName); + } + } + + /** + * 获取支付宝证书路径 + * + * @param fileName 文件名 + * @return 完整路径 + */ + public String getAlipayCertPath(String fileName) { + return getCertificatePath(alipay.getCertDir(), fileName); + } + + /** + * 检查证书加载模式是否为classpath模式 + * + * @return true if classpath mode + */ + public boolean isClasspathMode() { + return LoadMode.CLASSPATH.equals(loadMode); + } + + /** + * 检查证书加载模式是否为文件系统模式 + * + * @return true if filesystem mode + */ + public boolean isFilesystemMode() { + return LoadMode.FILESYSTEM.equals(loadMode); + } + + /** + * 检查证书加载模式是否为挂载卷模式 + * + * @return true if volume mode + */ + public boolean isVolumeMode() { + return LoadMode.VOLUME.equals(loadMode); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/ConfigProperties.java b/src/main/java/com/gxwebsoft/common/core/config/ConfigProperties.java new file mode 100644 index 0000000..d500177 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/ConfigProperties.java @@ -0,0 +1,105 @@ +package com.gxwebsoft.common.core.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 系统配置属性 + * + * @author WebSoft + * @since 2021-08-30 17:58:16 + */ +@Data +@ConfigurationProperties(prefix = "config") +public class ConfigProperties { + /** + * 文件上传磁盘位置 + */ + private Integer uploadLocation = 0; + + /** + * 文件上传是否使用uuid命名 + */ + private Boolean uploadUuidName = true; + + /** + * 文件上传生成缩略图的大小(kb) + */ + private Integer thumbnailSize = 60; + + /** + * OpenOffice的安装目录 + */ + private String openOfficeHome; + + /** + * swagger扫描包 + */ + private String swaggerBasePackage; + + /** + * swagger文档标题 + */ + private String swaggerTitle; + + /** + * swagger文档描述 + */ + private String swaggerDescription; + + /** + * swagger文档版本号 + */ + private String swaggerVersion; + + /** + * swagger地址 + */ + private String swaggerHost; + + /** + * token过期时间, 单位秒 + */ + private Long tokenExpireTime = 60 * 60 * 365 * 24L; + + /** + * token快要过期自动刷新时间, 单位分钟 + */ + private int tokenRefreshTime = 30; + + /** + * 生成token的密钥Key的base64字符 + */ + private String tokenKey; + + /** + * 文件上传目录 + */ + private String uploadPath; + + /** + * 本地文件上传目录(开发环境) + */ + private String localUploadPath; + + /** + * 文件服务器 + */ + private String fileServer; + + /** + * 网关地址 + */ + private String serverUrl; + + /** + * 阿里云存储 OSS + * Endpoint + */ + private String endpoint; + private String accessKeyId; + private String accessKeySecret; + private String bucketName; + private String bucketDomain; + +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/HttpMessageConverter.java b/src/main/java/com/gxwebsoft/common/core/config/HttpMessageConverter.java new file mode 100644 index 0000000..6bae59d --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/HttpMessageConverter.java @@ -0,0 +1,15 @@ +package com.gxwebsoft.common.core.config; + +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +import java.util.ArrayList; +import java.util.List; + +public class HttpMessageConverter extends MappingJackson2HttpMessageConverter { + public HttpMessageConverter(){ + List mediaTypes = new ArrayList<>(); + mediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED); + setSupportedMediaTypes(mediaTypes); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/JacksonConfig.java b/src/main/java/com/gxwebsoft/common/core/config/JacksonConfig.java new file mode 100644 index 0000000..eebe6c5 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/JacksonConfig.java @@ -0,0 +1,26 @@ +package com.gxwebsoft.common.core.config; + +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Jackson配置类 + * 确保JSR310模块被正确注册 + * + * @author WebSoft + * @since 2025-01-12 + */ +@Configuration +public class JacksonConfig { + + /** + * 确保JavaTimeModule被注册 + */ + @Bean + @ConditionalOnMissingBean + public JavaTimeModule javaTimeModule() { + return new JavaTimeModule(); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeDeserializer.java b/src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeDeserializer.java new file mode 100644 index 0000000..52ddd0a --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeDeserializer.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.common.core.config; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * LocalDateTime自定义反序列化器 + * + * @author WebSoft + * @since 2025-01-12 + */ +public class LocalDateTimeDeserializer extends JsonDeserializer { + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @Override + public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + String value = p.getValueAsString(); + if (value != null && !value.isEmpty()) { + return LocalDateTime.parse(value, FORMATTER); + } + return null; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeSerializer.java b/src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeSerializer.java new file mode 100644 index 0000000..d3849e7 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeSerializer.java @@ -0,0 +1,27 @@ +package com.gxwebsoft.common.core.config; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * LocalDateTime自定义序列化器 + * + * @author WebSoft + * @since 2025-01-12 + */ +public class LocalDateTimeSerializer extends JsonSerializer { + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @Override + public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + if (value != null) { + gen.writeString(value.format(FORMATTER)); + } + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/MqttProperties.java b/src/main/java/com/gxwebsoft/common/core/config/MqttProperties.java new file mode 100644 index 0000000..cfc882d --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/MqttProperties.java @@ -0,0 +1,72 @@ +package com.gxwebsoft.common.core.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * MQTT配置属性 + * + * @author 科技小王子 + * @since 2025-07-02 + */ +@Data +@Component +@ConfigurationProperties(prefix = "mqtt") +public class MqttProperties { + + /** + * 是否启用MQTT服务 + */ + private boolean enabled = false; + + /** + * MQTT服务器地址 + */ + private String host = "tcp://127.0.0.1:1883"; + + /** + * 用户名 + */ + private String username = ""; + + /** + * 密码 + */ + private String password = ""; + + /** + * 客户端ID前缀 + */ + private String clientIdPrefix = "mqtt_client_"; + + /** + * 订阅主题 + */ + private String topic = "/SW_GPS/#"; + + /** + * QoS等级 + */ + private int qos = 2; + + /** + * 连接超时时间(秒) + */ + private int connectionTimeout = 10; + + /** + * 心跳间隔(秒) + */ + private int keepAliveInterval = 20; + + /** + * 是否自动重连 + */ + private boolean autoReconnect = true; + + /** + * 是否清除会话 + */ + private boolean cleanSession = false; +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/MybatisPlusConfig.java b/src/main/java/com/gxwebsoft/common/core/config/MybatisPlusConfig.java new file mode 100644 index 0000000..b497f29 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/MybatisPlusConfig.java @@ -0,0 +1,138 @@ +package com.gxwebsoft.common.core.config; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.system.entity.User; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.NullValue; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Arrays; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +/** + * MybatisPlus配置 + * + * @author WebSoft + * @since 2018-02-22 11:29:28 + */ +@Configuration +public class MybatisPlusConfig { + @Resource + private RedisUtil redisUtil; + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + + // 多租户插件配置 + TenantLineHandler tenantLineHandler = new TenantLineHandler() { + @Override + public Expression getTenantId() { + String tenantId = null; + try { + // 从Spring上下文获取当前请求 + HttpServletRequest request = getCurrentRequest(); + if (request != null) { + // 从请求头拿ID + tenantId = request.getHeader("tenantId"); + if(tenantId != null){ + return new LongValue(tenantId); + } + // 从域名拿ID + String Domain = request.getHeader("Domain"); + if (StrUtil.isNotBlank(Domain)) { + String key = "Domain:" + Domain; + tenantId = redisUtil.get(key); + if(tenantId != null){ + System.out.println("从域名拿TID = " + tenantId); + return new LongValue(tenantId); + } + } + } + } catch (Exception e) { + // 忽略异常,使用默认逻辑 + } + return getLoginUserTenantId(); + } + + @Override + public boolean ignoreTable(String tableName) { + + // 系统级别的表始终忽略租户隔离 + return Arrays.asList( + "sys_tenant", + "sys_dictionary", + "sys_dictionary_data", + "apps_test_data", + "cms_lang" +// "hjm_car", +// "hjm_fence" +// "cms_website" +// "sys_user" +// "cms_domain" +// "shop_order_goods", +// "shop_goods" +// "shop_users", +// "shop_order" // 移除shop_order,改为通过注解控制 +// "shop_order_info", +// "booking_user_invoice" + ).contains(tableName); + } + }; + TenantLineInnerInterceptor tenantLineInnerInterceptor = new TenantLineInnerInterceptor(tenantLineHandler); + interceptor.addInnerInterceptor(tenantLineInnerInterceptor); + + // 分页插件配置 + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + paginationInnerInterceptor.setMaxLimit(2000L); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + + return interceptor; + } + + /** + * 获取当前登录用户的租户id + * + * @return Integer + */ + public Expression getLoginUserTenantId() { + try { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null) { + Object object = authentication.getPrincipal(); + if (object instanceof User) { + return new LongValue(((User) object).getTenantId()); + } + } + } catch (Exception e) { + System.out.println(e.getMessage()); + } + return new NullValue(); + } + + /** + * 获取当前HTTP请求 + */ + private HttpServletRequest getCurrentRequest() { + try { + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + return attributes != null ? attributes.getRequest() : null; + } catch (Exception e) { + return null; + } + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/RestTemplateConfig.java b/src/main/java/com/gxwebsoft/common/core/config/RestTemplateConfig.java new file mode 100644 index 0000000..786798f --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/RestTemplateConfig.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.common.core.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + + +@Configuration +public class RestTemplateConfig { + + @Bean + public RestTemplate restTemplate(ClientHttpRequestFactory factory) { + RestTemplate restTemplate = new RestTemplate(factory); + restTemplate.getMessageConverters().add(new HttpMessageConverter()); + return restTemplate; + } + @Bean + public ClientHttpRequestFactory simpleClientHttpRequestFactory() { + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + // ms + factory.setReadTimeout(60000); + // ms + factory.setConnectTimeout(60000); + + return factory; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/SpringContextUtil.java b/src/main/java/com/gxwebsoft/common/core/config/SpringContextUtil.java new file mode 100644 index 0000000..4e6d883 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/SpringContextUtil.java @@ -0,0 +1,62 @@ +package com.gxwebsoft.common.core.config; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * @Author ds + * @Date 2022-05-05 + */ +@Component +public class SpringContextUtil implements ApplicationContextAware { + /** + * spring的应用上下文 + */ + private static ApplicationContext applicationContext; + + /** + * 初始化时将应用上下文设置进applicationContext + * @param applicationContext + * @throws BeansException + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + SpringContextUtil.applicationContext=applicationContext; + } + + public static ApplicationContext getApplicationContext(){ + return applicationContext; + } + + /** + * 根据bean名称获取某个bean对象 + * + * @param name bean名称 + * @return Object + * @throws BeansException + */ + public static Object getBean(String name) throws BeansException { + return applicationContext.getBean(name); + } + + /** + * 根据bean的class获取某个bean对象 + * @param beanClass + * @param + * @return + * @throws BeansException + */ + public static T getBean(Class beanClass) throws BeansException { + return applicationContext.getBean(beanClass); + } + + /** + * 获取spring.profiles.active + * @return + */ + public static String getProfile(){ + return getApplicationContext().getEnvironment().getActiveProfiles()[0]; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java b/src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java new file mode 100644 index 0000000..c63c2c7 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java @@ -0,0 +1,111 @@ +package com.gxwebsoft.common.core.config; + +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.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.Components; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.Resource; + +/** + * SpringDoc OpenAPI 配置 + * + * @author WebSoft + * @since 2018-02-22 11:29:05 + */ +@Configuration +public class SwaggerConfig { + @Resource + private ConfigProperties config; + + /** + * 全局 OpenAPI 配置 + */ + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info() + .title(config.getSwaggerTitle()) + .description(config.getSwaggerDescription()) + .version(config.getSwaggerVersion()) + .contact(new Contact() + .name("科技小王子") + .url("https://www.gxwebsoft.com") + .email("170083662@qq.com")) + .termsOfService(config.getServerUrl() + "/system")) + .components(new Components() + .addSecuritySchemes("Authorization", + new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + .name("Authorization") + .description("JWT Authorization header using the Bearer scheme"))) + .addSecurityItem(new SecurityRequirement().addList("Authorization")); + } + + /** + * Common 模块分组 + */ + @Bean + public GroupedOpenApi commonApi() { + return GroupedOpenApi.builder() + .group("common") + .pathsToMatch("/api/common/**", "/api/system/**", "/api/user/**", "/api/role/**", "/api/menu/**") + .packagesToScan("com.gxwebsoft.common") + .build(); + } + + /** + * CMS 模块分组 + */ + @Bean + public GroupedOpenApi cmsApi() { + return GroupedOpenApi.builder() + .group("cms") + .pathsToMatch("/api/cms/**") + .packagesToScan("com.gxwebsoft.cms") + .build(); + } + + /** + * Shop 模块分组 + */ + @Bean + public GroupedOpenApi shopApi() { + return GroupedOpenApi.builder() + .group("shop") + .pathsToMatch("/api/shop/**") + .packagesToScan("com.gxwebsoft.shop") + .build(); + } + + /** + * OA 模块分组 + */ + @Bean + public GroupedOpenApi oaApi() { + return GroupedOpenApi.builder() + .group("oa") + .pathsToMatch("/api/oa/**") + .packagesToScan("com.gxwebsoft.oa") + .build(); + } + + /** + * 其他模块分组 + */ + @Bean + public GroupedOpenApi otherApi() { + return GroupedOpenApi.builder() + .group("other") + .pathsToMatch("/api/docs/**", "/api/project/**", "/api/pwl/**", "/api/bszx/**", "/api/hjm/**") + .packagesToScan("com.gxwebsoft.docs", "com.gxwebsoft.project", "com.gxwebsoft.pwl", "com.gxwebsoft.bszx", "com.gxwebsoft.hjm") + .build(); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/config/WebMvcConfig.java b/src/main/java/com/gxwebsoft/common/core/config/WebMvcConfig.java new file mode 100644 index 0000000..2ed9d8b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/WebMvcConfig.java @@ -0,0 +1,31 @@ +package com.gxwebsoft.common.core.config; + +import com.gxwebsoft.common.core.Constants; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * WebMvc配置, 拦截器、资源映射等都在此配置 + * + * @author WebSoft + * @since 2019-06-12 10:11:16 + */ +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + /** + * 支持跨域访问 + */ + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOriginPatterns("*") + .allowedHeaders("*") + .exposedHeaders(Constants.TOKEN_HEADER_NAME) + .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH") + .allowCredentials(true) + .maxAge(3600); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/constants/AppUserConstants.java b/src/main/java/com/gxwebsoft/common/core/constants/AppUserConstants.java new file mode 100644 index 0000000..538e295 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/constants/AppUserConstants.java @@ -0,0 +1,8 @@ +package com.gxwebsoft.common.core.constants; + +public class AppUserConstants { + // 成员角色 + public static final Integer TRIAL = 10; // 体验成员 + public static final Integer DEVELOPER = 20; // 开发者 + public static final Integer ADMINISTRATOR = 30; // 管理员 +} diff --git a/src/main/java/com/gxwebsoft/common/core/constants/ArticleConstants.java b/src/main/java/com/gxwebsoft/common/core/constants/ArticleConstants.java new file mode 100644 index 0000000..62a38cc --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/constants/ArticleConstants.java @@ -0,0 +1,6 @@ +package com.gxwebsoft.common.core.constants; + +public class ArticleConstants extends BaseConstants { + public static final String[] ARTICLE_STATUS = {"已发布","待审核","已驳回","违规内容"}; + public static final String CACHE_KEY_ARTICLE = "Article:"; +} diff --git a/src/main/java/com/gxwebsoft/common/core/constants/BalanceConstants.java b/src/main/java/com/gxwebsoft/common/core/constants/BalanceConstants.java new file mode 100644 index 0000000..6857250 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/constants/BalanceConstants.java @@ -0,0 +1,10 @@ +package com.gxwebsoft.common.core.constants; + +public class BalanceConstants { + // 余额变动场景 + public static final Integer BALANCE_RECHARGE = 10; // 用户充值 + public static final Integer BALANCE_USE = 20; // 用户消费 + public static final Integer BALANCE_RE_LET = 21; // 续租 + public static final Integer BALANCE_ADMIN = 30; // 管理员操作 + public static final Integer BALANCE_REFUND = 40; // 订单退款 +} diff --git a/src/main/java/com/gxwebsoft/common/core/constants/BaseConstants.java b/src/main/java/com/gxwebsoft/common/core/constants/BaseConstants.java new file mode 100644 index 0000000..66cf4c0 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/constants/BaseConstants.java @@ -0,0 +1,5 @@ +package com.gxwebsoft.common.core.constants; + +public class BaseConstants { + public static final String[] STATUS = {"未定义","显示","隐藏"}; +} diff --git a/src/main/java/com/gxwebsoft/common/core/constants/OrderConstants.java b/src/main/java/com/gxwebsoft/common/core/constants/OrderConstants.java new file mode 100644 index 0000000..e866654 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/constants/OrderConstants.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.core.constants; + +public class OrderConstants { + // 支付方式 + public static final String PAY_METHOD_BALANCE = "10"; // 余额支付 + public static final String PAY_METHOD_WX = "20"; // 微信支付 + public static final String PAY_METHOD_ALIPAY = "30"; // 支付宝支付 + public static final String PAY_METHOD_OTHER = "40"; // 其他支付 + + // 付款状态 + public static final Integer PAY_STATUS_NO_PAY = 10; // 未付款 + public static final Integer PAY_STATUS_SUCCESS = 20; // 已付款 + + // 发货状态 + public static final Integer DELIVERY_STATUS_NO = 10; // 未发货 + public static final Integer DELIVERY_STATUS_YES = 20; // 已发货 + public static final Integer DELIVERY_STATUS_30 = 30; // 部分发货 + + // 收货状态 + public static final Integer RECEIPT_STATUS_NO = 10; // 未收货 + public static final Integer RECEIPT_STATUS_YES = 20; // 已收货 + public static final Integer RECEIPT_STATUS_RETURN = 30; // 已退货 + + // 订单状态 + public static final Integer ORDER_STATUS_DOING = 10; // 进行中 + public static final Integer ORDER_STATUS_CANCEL = 20; // 已取消 + public static final Integer ORDER_STATUS_TO_CANCEL = 21; // 待取消 + public static final Integer ORDER_STATUS_COMPLETED = 30; // 已完成 + + // 订单结算状态 + public static final Integer ORDER_SETTLED_YES = 1; // 已结算 + public static final Integer ORDER_SETTLED_NO = 0; // 未结算 + + + + +} diff --git a/src/main/java/com/gxwebsoft/common/core/constants/PlatformConstants.java b/src/main/java/com/gxwebsoft/common/core/constants/PlatformConstants.java new file mode 100644 index 0000000..896f8e3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/constants/PlatformConstants.java @@ -0,0 +1,12 @@ +package com.gxwebsoft.common.core.constants; + +public class PlatformConstants { + public static final String MP_OFFICIAL = "MP-OFFICIAL"; // 微信公众号 + public static final String MP_WEIXIN = "MP-WEIXIN"; // 微信小程序 + public static final String MP_ALIPAY = "MP-ALIPAY"; // 支付宝小程序 + public static final String WEB = "WEB"; // web(同H5) + public static final String H5 = "H5"; // H5(推荐使用 WEB) + public static final String APP = "APP"; // App + public static final String MP_BAIDU = "MP-BAIDU"; // 百度小程序 + public static final String MP_TOUTIAO = "MP-TOUTIAO"; // 百度小程序 +} diff --git a/src/main/java/com/gxwebsoft/common/core/constants/ProfitConstants.java b/src/main/java/com/gxwebsoft/common/core/constants/ProfitConstants.java new file mode 100644 index 0000000..2cb60fd --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/constants/ProfitConstants.java @@ -0,0 +1,9 @@ +package com.gxwebsoft.common.core.constants; + +public class ProfitConstants { + // 收益类型 + public static final Integer PROFIT_TYPE10 = 10; // 推广收益 + public static final Integer PROFIT_TYPE20 = 20; // 团队收益 + public static final Integer PROFIT_TYPE30 = 30; // 门店收益 + public static final Integer PROFIT_TYPE40 = 30; // 区域收益 +} diff --git a/src/main/java/com/gxwebsoft/common/core/constants/QRCodeConstants.java b/src/main/java/com/gxwebsoft/common/core/constants/QRCodeConstants.java new file mode 100644 index 0000000..1b30868 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/constants/QRCodeConstants.java @@ -0,0 +1,10 @@ +package com.gxwebsoft.common.core.constants; + +public class QRCodeConstants { + // 二维码类型 + public static final String USER_QRCODE = "user"; // 用户二维码 + public static final String TASK_QRCODE = "task"; // 工单二维码 + public static final String ARTICLE_QRCODE = "article"; // 文章二维码 + public static final String GOODS_QRCODE = "goods"; // 商品二维码 + public static final String DIY_QRCODE = "diy"; // 工单二维码 +} diff --git a/src/main/java/com/gxwebsoft/common/core/constants/RedisConstants.java b/src/main/java/com/gxwebsoft/common/core/constants/RedisConstants.java new file mode 100644 index 0000000..68d8fef --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/constants/RedisConstants.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.core.constants; + +public class RedisConstants { + // 短信验证码Key + public static final String SMS_CODE_KEY = "sms"; + // 验证码过期时间 + public static final Long SMS_CODE_TTL = 5L; + // 微信凭证access-token + public static final String ACCESS_TOKEN_KEY = "access-token"; + // 空值防止击穿数据库 + public static final Long CACHE_NULL_TTL = 2L; + // 商户信息 + public static final String MERCHANT_KEY = "merchant"; + // 添加商户定位点 + public static final String MERCHANT_GEO_KEY = "merchant-geo"; + + // token + public static final String TOKEN_USER_ID = "cache:token:"; + // 排行榜 + public static final String USER_RANKING_BY_APPS = "userRankingByApps"; + // 搜索历史 + public static final String SEARCH_HISTORY = "searchHistory"; + // 租户系统设置信息 + public static final String TEN_ANT_SETTING_KEY = "setting"; + // 排行榜Key + public static final String USER_RANKING_BY_APPS_5 = "cache5:userRankingByApps"; + + + + // 扫码登录相关key + public static final String QR_LOGIN_TOKEN_KEY = "qr-login:token:"; // 扫码登录token前缀 + public static final Long QR_LOGIN_TOKEN_TTL = 300L; // 扫码登录token过期时间(5分钟) + public static final String QR_LOGIN_STATUS_PENDING = "pending"; // 等待扫码 + public static final String QR_LOGIN_STATUS_SCANNED = "scanned"; // 已扫码 + public static final String QR_LOGIN_STATUS_CONFIRMED = "confirmed"; // 已确认 + public static final String QR_LOGIN_STATUS_EXPIRED = "expired"; // 已过期 + + // 哗啦啦key + public static final String getAllShop = "allShop"; + public static final String getBaseInfo = "baseInfo"; + public static final String getFoodClassCategory = "foodCategory"; + public static final String getOpenFood = "openFood"; + public static final String haulalaGeoKey = "cache10:hualala-geo"; + public static final String HLL_CART_KEY = "hll-cart"; // hll-cart[shopId]:[userId] + public static final String HLL_CART_FOOD_KEY = "hll-cart-list"; // hll-cart-list[shopId]:[userId] + +} diff --git a/src/main/java/com/gxwebsoft/common/core/constants/TaskConstants.java b/src/main/java/com/gxwebsoft/common/core/constants/TaskConstants.java new file mode 100644 index 0000000..42cec5e --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/constants/TaskConstants.java @@ -0,0 +1,22 @@ +package com.gxwebsoft.common.core.constants; + +public class TaskConstants { + // 工单进度 + public static final Integer TOBEARRANGED = 0; // 待安排 + public static final Integer PENDING = 1; // 待处理 + public static final Integer PROCESSING = 2; // 处理中 + public static final Integer TOBECONFIRMED = 3; // 待评价 + public static final Integer COMPLETED = 4; // 已完成 + public static final Integer CLOSED = 5; // 已关闭 + + // 工单状态 + public static final Integer TASK_STATUS_0 = 0; // 待处理 + public static final Integer TASK_STATUS_1 = 1; // 已完成 + + // 操作类型 + public static final String ACTION_1 = "派单"; + public static final String ACTION_2 = "已解决"; + public static final String ACTION_3 = "关单"; + public static final String ACTION_4 = "分享"; + public static final String ACTION_5 = "编辑"; +} diff --git a/src/main/java/com/gxwebsoft/common/core/constants/WebsiteConstants.java b/src/main/java/com/gxwebsoft/common/core/constants/WebsiteConstants.java new file mode 100644 index 0000000..a49f4ba --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/constants/WebsiteConstants.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.core.constants; + +public class WebsiteConstants extends BaseConstants { + // 运行状态 0未开通 1运行中 2维护中 3已关闭 4已欠费停机 5违规关停 + public static final String[] WEBSITE_STATUS_NAME = {"未开通","运行中","维护中","已关闭","已欠费停机","违规关停"}; + // 状态图标 + public static final String[] WEBSITE_STATUS_ICON = {"error","success","warning","error","error","error"}; + // 关闭原因 + public static final String[] WEBSITE_STATUS_TEXT = {"产品未开通","","系统升级维护","","已欠费停机","违规关停"}; + // 跳转地址 + public static final String[] WEBSITE_STATUS_URL = {"https://websoft.top","","","","https://websoft.top/user","https://websoft.top/user"}; + // 跳转按钮文字 + public static final String[] WEBSITE_STATUS_BTN_TEXT = {"立即开通","","","","立即续费","申请解封"}; +} diff --git a/src/main/java/com/gxwebsoft/common/core/constants/WxOfficialConstants.java b/src/main/java/com/gxwebsoft/common/core/constants/WxOfficialConstants.java new file mode 100644 index 0000000..a025610 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/constants/WxOfficialConstants.java @@ -0,0 +1,6 @@ +package com.gxwebsoft.common.core.constants; + +public class WxOfficialConstants { + // 获取 Access token + public static final String GET_ACCESS_TOKEN_API = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; +} diff --git a/src/main/java/com/gxwebsoft/common/core/exception/BusinessException.java b/src/main/java/com/gxwebsoft/common/core/exception/BusinessException.java new file mode 100644 index 0000000..8e10e82 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/exception/BusinessException.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.common.core.exception; + +import com.gxwebsoft.common.core.Constants; + +/** + * 自定义业务异常 + * + * @author WebSoft + * @since 2018-02-22 11:29:28 + */ +public class BusinessException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private Integer code; + + public BusinessException() { + this(Constants.RESULT_ERROR_MSG); + } + + public BusinessException(String message) { + this(Constants.RESULT_ERROR_CODE, message); + } + + public BusinessException(Integer code, String message) { + super(message); + this.code = code; + } + + public BusinessException(Integer code, String message, Throwable cause) { + super(message, cause); + this.code = code; + } + + public BusinessException(Integer code, String message, Throwable cause, + boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + this.code = code; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/exception/GlobalExceptionHandler.java b/src/main/java/com/gxwebsoft/common/core/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..7fb4c8c --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/exception/GlobalExceptionHandler.java @@ -0,0 +1,89 @@ +package com.gxwebsoft.common.core.exception; + +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.access.AccessDeniedException; +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.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import java.util.Set; + +/** + * 全局异常处理器 + * + * @author WebSoft + * @since 2018-02-22 11:29:30 + */ +@ControllerAdvice +public class GlobalExceptionHandler { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @ResponseBody + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public ApiResult methodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e, + HttpServletResponse response) { + CommonUtil.addCrossHeaders(response); + return new ApiResult<>(Constants.RESULT_ERROR_CODE, "请求方式不正确").setError(e.toString()); + } + + @ResponseBody + @ExceptionHandler(AccessDeniedException.class) + public ApiResult accessDeniedExceptionHandler(AccessDeniedException e, HttpServletResponse response) { + CommonUtil.addCrossHeaders(response); + return new ApiResult<>(Constants.UNAUTHORIZED_CODE, Constants.UNAUTHORIZED_MSG).setError(e.toString()); + } + + @ResponseBody + @ExceptionHandler(BusinessException.class) + public ApiResult businessExceptionHandler(BusinessException e, HttpServletResponse response) { + CommonUtil.addCrossHeaders(response); + return new ApiResult<>(e.getCode(), e.getMessage()); + } + + @ResponseBody + @ExceptionHandler(MethodArgumentNotValidException.class) + public ApiResult methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e, HttpServletResponse response) { + CommonUtil.addCrossHeaders(response); + FieldError fieldError = e.getBindingResult().getFieldError(); + String message = fieldError != null ? fieldError.getDefaultMessage() : "参数验证失败"; + return new ApiResult<>(Constants.RESULT_ERROR_CODE, message); + } + + @ResponseBody + @ExceptionHandler(BindException.class) + public ApiResult bindExceptionHandler(BindException e, HttpServletResponse response) { + CommonUtil.addCrossHeaders(response); + FieldError fieldError = e.getBindingResult().getFieldError(); + String message = fieldError != null ? fieldError.getDefaultMessage() : "参数绑定失败"; + return new ApiResult<>(Constants.RESULT_ERROR_CODE, message); + } + + @ResponseBody + @ExceptionHandler(ConstraintViolationException.class) + public ApiResult constraintViolationExceptionHandler(ConstraintViolationException e, HttpServletResponse response) { + CommonUtil.addCrossHeaders(response); + Set> violations = e.getConstraintViolations(); + String message = violations.isEmpty() ? "参数验证失败" : violations.iterator().next().getMessage(); + return new ApiResult<>(Constants.RESULT_ERROR_CODE, message); + } + + @ResponseBody + @ExceptionHandler(Throwable.class) + public ApiResult exceptionHandler(Throwable e, HttpServletResponse response) { + logger.error(e.getMessage(), e); + CommonUtil.addCrossHeaders(response); + return new ApiResult<>(Constants.RESULT_ERROR_CODE, Constants.RESULT_ERROR_MSG).setError(e.toString()); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/security/JwtAccessDeniedHandler.java b/src/main/java/com/gxwebsoft/common/core/security/JwtAccessDeniedHandler.java new file mode 100644 index 0000000..66acb5c --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/security/JwtAccessDeniedHandler.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.common.core.security; + +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.utils.CommonUtil; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 没有访问权限异常处理 + * + * @author WebSoft + * @since 2020-03-25 00:35:03 + */ +@Component +public class JwtAccessDeniedHandler implements AccessDeniedHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) + throws IOException, ServletException { + CommonUtil.responseError(response, Constants.UNAUTHORIZED_CODE, Constants.UNAUTHORIZED_MSG, e.getMessage()); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationEntryPoint.java b/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..3be2908 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationEntryPoint.java @@ -0,0 +1,30 @@ +package com.gxwebsoft.common.core.security; + +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.utils.CommonUtil; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 没有登录异常处理 + * + * @author WebSoft + * @since 2020-03-25 00:35:03 + */ +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) + throws IOException, ServletException { +// CommonUtil.responseError(response, Constants.UNAUTHENTICATED_CODE, Constants.UNAUTHENTICATED_MSG, +// e.getMessage()); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java b/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..e910c6d --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java @@ -0,0 +1,118 @@ +package com.gxwebsoft.common.core.security; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.utils.SignCheckUtil; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.User; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.annotation.Resource; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 处理携带token的请求过滤器 + * + * @author WebSoft + * @since 2020-03-30 20:48:05 + */ +@Component +public class JwtAuthenticationFilter extends OncePerRequestFilter { + @Resource + private ConfigProperties configProperties; + @Value("${spring.profiles.active}") + String active; + @Resource + private RedisUtil redisUtil; + // 是否读取用户信息 + public static Boolean isReadUserInfo = true; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException { + String access_token = JwtUtil.getAccessToken(request); + if (StrUtil.isNotBlank(access_token)) { + try { + // 解析token + Claims claims = JwtUtil.parseToken(access_token, configProperties.getTokenKey()); + JwtSubject jwtSubject = JwtUtil.getJwtSubject(claims); + + // 请求主服务器获取用户信息 + if (isReadUserInfo) { + HashMap map = new HashMap<>(); + map.put("username", jwtSubject.getUsername()); + map.put("tenantId", jwtSubject.getTenantId()); + // 链式构建请求 + String result = HttpRequest.post(configProperties.getServerUrl() + "/auth/user") + .header("Authorization", access_token) + .header("Tenantid", jwtSubject.getTenantId().toString()) + .body(JSONUtil.toJSONString(map))//表单内容 + .timeout(20000)//超时,毫秒 + .execute().body(); + + // 校验服务器域名白名单 + final SignCheckUtil checkUtil = new SignCheckUtil(); + String key = "WhiteDomain:" + jwtSubject.getTenantId(); + List whiteDomains = redisUtil.get(key, List.class); + // 生产环境 + if (active.equals("prod") && !checkUtil.checkWhiteDomains(whiteDomains, request.getServerName())) { + throw new UsernameNotFoundException("The requested domain name is not on the whitelist"); + } + + JSONObject jsonObject = JSONObject.parseObject(result); + if(jsonObject.getString("code").equals("401")){ + throw new UsernameNotFoundException("Username not found"); + } + final String data = jsonObject.getString("data"); + final User user = JSONObject.parseObject(data, User.class); + List authorities = user.getAuthorities().stream() + .filter(m -> StrUtil.isNotBlank(m.getAuthority())).collect(Collectors.toList()); + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + user, null, authorities); + SecurityContextHolder.getContext().setAuthentication(authentication); + + // token将要过期签发新token, 防止突然退出登录 +// long expiration = (claims.getExpiration().getTime() - new Date().getTime()) / 1000 / 60; +// if (expiration < configProperties.getTokenRefreshTime()) { +// String token = JwtUtil.buildToken(jwtSubject, configProperties.getTokenExpireTime(), +// configProperties.getTokenKey()); +// response.addHeader(Constants.TOKEN_HEADER_NAME, token); +// loginRecordService.saveAsync(user.getUsername(), LoginRecord.TYPE_REFRESH, null, +// user.getTenantId(), request); +// } + + } + } catch (ExpiredJwtException e) { + CommonUtil.responseError(response, Constants.TOKEN_EXPIRED_CODE, Constants.TOKEN_EXPIRED_MSG, + e.getMessage()); + return; + } catch (Exception e) { + CommonUtil.responseError(response, Constants.BAD_CREDENTIALS_CODE, Constants.BAD_CREDENTIALS_MSG, + e.toString()); + return; + } + } + chain.doFilter(request, response); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/security/JwtSubject.java b/src/main/java/com/gxwebsoft/common/core/security/JwtSubject.java new file mode 100644 index 0000000..1a0ff7d --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/security/JwtSubject.java @@ -0,0 +1,31 @@ +package com.gxwebsoft.common.core.security; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * Jwt载体 + * + * @author WebSoft + * @since 2021-09-03 00:11:12 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class JwtSubject implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 账号 + */ + private String username; + + /** + * 租户id + */ + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/core/security/JwtUtil.java b/src/main/java/com/gxwebsoft/common/core/security/JwtUtil.java new file mode 100644 index 0000000..2f05d23 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/security/JwtUtil.java @@ -0,0 +1,141 @@ +package com.gxwebsoft.common.core.security; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.servlet.ServletUtil; +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.utils.JSONUtil; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.io.Encoders; +import io.jsonwebtoken.security.Keys; + +import javax.servlet.http.HttpServletRequest; +import java.security.Key; +import java.util.Date; + +/** + * JWT工具类 + * + * @author WebSoft + * @since 2018-01-21 16:30:59 + */ +public class JwtUtil { + + /** + * 获取请求中的access_token + * + * @param request HttpServletRequest + * @return String + */ + public static String getAccessToken(HttpServletRequest request) { + String access_token = ServletUtil.getHeaderIgnoreCase(request, Constants.TOKEN_HEADER_NAME); + if (StrUtil.isNotBlank(access_token)) { + if (access_token.startsWith(Constants.TOKEN_TYPE)) { + access_token = StrUtil.removePrefix(access_token, Constants.TOKEN_TYPE).trim(); + } + } else { + access_token = request.getParameter(Constants.TOKEN_PARAM_NAME); + } + return access_token; + } + + /** + * 生成token + * + * @param subject 载体 + * @param expire 过期时间 + * @param base64EncodedKey base64编码的Key + * @return token + */ + public static String buildToken(JwtSubject subject, Long expire, String base64EncodedKey) { + return buildToken(JSONUtil.toJSONString(subject), expire, decodeKey(base64EncodedKey)); + } + + /** + * 生成token + * + * @param subject 载体 + * @param expire 过期时间 + * @param key 密钥 + * @return token + */ + public static String buildToken(String subject, Long expire, Key key) { + Date expireDate = new Date(new Date().getTime() + 1000 * expire); + return Jwts.builder() + .setSubject(subject) + .setExpiration(expireDate) + .setIssuedAt(new Date()) + .signWith(key) + .compact(); + } + + /** + * 解析token + * + * @param token token + * @param base64EncodedKey base64编码的Key + * @return Claims + */ + public static Claims parseToken(String token, String base64EncodedKey) { + return parseToken(token, decodeKey(base64EncodedKey)); + } + + /** + * 解析token + * + * @param token token + * @param key 密钥 + * @return Claims + */ + public static Claims parseToken(String token, Key key) { + return Jwts.parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); + } + + /** + * 获取JwtSubject + * + * @param claims Claims + * @return JwtSubject + */ + public static JwtSubject getJwtSubject(Claims claims) { + return JSONUtil.parseObject(claims.getSubject(), JwtSubject.class); + } + + /** + * 生成Key + * + * @return Key + */ + public static Key randomKey() { + return Keys.secretKeyFor(SignatureAlgorithm.HS256); + } + + /** + * base64编码key + * + * @return String + */ + public static String encodeKey(Key key) { + return Encoders.BASE64.encode(key.getEncoded()); + } + + /** + * base64编码Key + * + * @param base64EncodedKey base64编码的key + * @return Key + */ + public static Key decodeKey(String base64EncodedKey) { + if (StrUtil.isBlank(base64EncodedKey)) { + return null; + } + return Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64EncodedKey)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java b/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java new file mode 100644 index 0000000..7972875 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java @@ -0,0 +1,113 @@ +package com.gxwebsoft.common.core.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +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.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +import javax.annotation.Resource; + +/** + * Spring Security配置 + * + * @author WebSoft + * @since 2020-03-23 18:04:52 + */ +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig { + @Resource + private JwtAccessDeniedHandler jwtAccessDeniedHandler; + @Resource + private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + @Resource + private JwtAuthenticationFilter jwtAuthenticationFilter; + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + return http.authorizeRequests() + .antMatchers(HttpMethod.OPTIONS, "/**") + .permitAll() + .antMatchers(HttpMethod.GET, "/api/file/**","/**", "/api/captcha", "/") + .permitAll() + .antMatchers( + "/api/login", + "/api/qr-login/**", + "/api/register", + "/api/cms/website/createWebsite", + "/druid/**", + "/swagger-ui.html", + "/swagger-resources/**", + "/webjars/**", + "/v2/api-docs", + "/v3/api-docs", + "/swagger-ui/**", + "/doc.html", + "/api/open/**", + "/hxz/v1/**", + "/api/sendSmsCaptcha", + "/api/login-alipay/*", + "/api/wx-login/loginByMpWxPhone", + "/api/shop/payment/mp-alipay/notify", + "/api/shop/payment/mp-alipay/test/**", + "/api/shop/payment/mp-alipay/getPhoneNumber", + "/api/cms/cms-order/**", + "/api/shop/shop-order/notify/**", + "/api/mp/mp/component_verify_ticket", + "/api/mp/mp/callback", + "/api/shop/test/**", + "/api/test/payment-debug/**", + "/api/shop/wx-login/**", + "/api/shop/wx-native-pay/**", + "/api/shop/wx-pay/**", + "/api/bszx/bszx-pay/notify/**", + "/api/wxWorkQrConnect", + "/WW_verify_QMv7HoblYU6z63bb.txt", + "/5zbYEPkyV4.txt", + "/api/love/user-plan-log/wx-pay/**", + "/api/cms/form-record", + "/api/shop/merchant-account/getMerchantAccountByPhone", + "/api/hjm/hjm-car/**", + "/api/chat/**", + "/api/shop/getShopInfo", + "/api/shop/shop-order/test", + "/api/qr-code/**" + ) + .permitAll() + .anyRequest() + .authenticated() + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .csrf() + .disable() + .cors() + .and() + .logout() + .disable() + .headers() + .frameOptions() + .disable() + .and() + .exceptionHandling() + .accessDeniedHandler(jwtAccessDeniedHandler) + .authenticationEntryPoint(jwtAuthenticationEntryPoint) + .and() + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) + .build(); + } + + @Bean + public BCryptPasswordEncoder bCryptPasswordEncoder() { + return new BCryptPasswordEncoder(); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/service/CertificateHealthService.java b/src/main/java/com/gxwebsoft/common/core/service/CertificateHealthService.java new file mode 100644 index 0000000..e37bb05 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/service/CertificateHealthService.java @@ -0,0 +1,253 @@ +package com.gxwebsoft.common.core.service; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * 证书健康检查服务 + * 提供证书状态检查和健康监控功能 + * + * @author 科技小王子 + * @since 2024-07-26 + */ +@Slf4j +@Service +public class CertificateHealthService { + + private final CertificateService certificateService; + private final CertificateProperties certificateProperties; + + public CertificateHealthService(CertificateService certificateService, + CertificateProperties certificateProperties) { + this.certificateService = certificateService; + this.certificateProperties = certificateProperties; + } + + /** + * 自定义健康检查结果类 + */ + public static class HealthResult { + private final String status; + private final Map details; + + public HealthResult(String status, Map details) { + this.status = status; + this.details = details; + } + + public String getStatus() { + return status; + } + + public Map getDetails() { + return details; + } + + public static HealthResult up(Map details) { + return new HealthResult("UP", details); + } + + public static HealthResult down(Map details) { + return new HealthResult("DOWN", details); + } + } + + public HealthResult health() { + try { + Map details = new HashMap<>(); + boolean allHealthy = true; + + // 检查微信支付证书 + Map wechatHealth = checkWechatPayCertificates(); + details.put("wechatPay", wechatHealth); + if (!(Boolean) wechatHealth.get("healthy")) { + allHealthy = false; + } + + // 检查支付宝证书 + Map alipayHealth = checkAlipayCertificates(); + details.put("alipay", alipayHealth); + if (!(Boolean) alipayHealth.get("healthy")) { + allHealthy = false; + } + + // 添加系统信息 + details.put("loadMode", certificateProperties.getLoadMode()); + details.put("certRootPath", certificateProperties.getCertRootPath()); + + if (allHealthy) { + return HealthResult.up(details); + } else { + return HealthResult.down(details); + } + + } catch (Exception e) { + log.error("证书健康检查失败", e); + Map errorDetails = new HashMap<>(); + errorDetails.put("error", e.getMessage()); + return HealthResult.down(errorDetails); + } + } + + /** + * 检查微信支付证书健康状态 + */ + private Map checkWechatPayCertificates() { + Map health = new HashMap<>(); + boolean healthy = true; + Map certificates = new HashMap<>(); + + CertificateProperties.WechatPayConfig wechatConfig = certificateProperties.getWechatPay(); + + // 检查私钥证书 + String privateKeyFile = wechatConfig.getDev().getPrivateKeyFile(); + boolean privateKeyExists = certificateService.certificateExists("wechat", privateKeyFile); + certificates.put("privateKey", Map.of( + "file", privateKeyFile, + "exists", privateKeyExists, + "path", certificateService.getWechatPayCertPath(privateKeyFile) + )); + if (!privateKeyExists) healthy = false; + + // 检查商户证书 + String apiclientCertFile = wechatConfig.getDev().getApiclientCertFile(); + boolean apiclientCertExists = certificateService.certificateExists("wechat", apiclientCertFile); + certificates.put("apiclientCert", Map.of( + "file", apiclientCertFile, + "exists", apiclientCertExists, + "path", certificateService.getWechatPayCertPath(apiclientCertFile) + )); + if (!apiclientCertExists) healthy = false; + + // 检查微信支付平台证书 + String wechatpayCertFile = wechatConfig.getDev().getWechatpayCertFile(); + boolean wechatpayCertExists = certificateService.certificateExists("wechat", wechatpayCertFile); + certificates.put("wechatpayCert", Map.of( + "file", wechatpayCertFile, + "exists", wechatpayCertExists, + "path", certificateService.getWechatPayCertPath(wechatpayCertFile) + )); + if (!wechatpayCertExists) healthy = false; + + health.put("healthy", healthy); + health.put("certificates", certificates); + return health; + } + + /** + * 检查支付宝证书健康状态 + */ + private Map checkAlipayCertificates() { + Map health = new HashMap<>(); + boolean healthy = true; + Map certificates = new HashMap<>(); + + CertificateProperties.AlipayConfig alipayConfig = certificateProperties.getAlipay(); + + // 检查应用私钥 + String appPrivateKeyFile = alipayConfig.getAppPrivateKeyFile(); + boolean appPrivateKeyExists = certificateService.certificateExists("alipay", appPrivateKeyFile); + certificates.put("appPrivateKey", Map.of( + "file", appPrivateKeyFile, + "exists", appPrivateKeyExists, + "path", certificateService.getAlipayCertPath(appPrivateKeyFile) + )); + if (!appPrivateKeyExists) healthy = false; + + // 检查应用公钥证书 + String appCertPublicKeyFile = alipayConfig.getAppCertPublicKeyFile(); + boolean appCertExists = certificateService.certificateExists("alipay", appCertPublicKeyFile); + certificates.put("appCertPublicKey", Map.of( + "file", appCertPublicKeyFile, + "exists", appCertExists, + "path", certificateService.getAlipayCertPath(appCertPublicKeyFile) + )); + if (!appCertExists) healthy = false; + + // 检查支付宝公钥证书 + String alipayCertPublicKeyFile = alipayConfig.getAlipayCertPublicKeyFile(); + boolean alipayCertExists = certificateService.certificateExists("alipay", alipayCertPublicKeyFile); + certificates.put("alipayCertPublicKey", Map.of( + "file", alipayCertPublicKeyFile, + "exists", alipayCertExists, + "path", certificateService.getAlipayCertPath(alipayCertPublicKeyFile) + )); + if (!alipayCertExists) healthy = false; + + // 检查支付宝根证书 + String alipayRootCertFile = alipayConfig.getAlipayRootCertFile(); + boolean rootCertExists = certificateService.certificateExists("alipay", alipayRootCertFile); + certificates.put("alipayRootCert", Map.of( + "file", alipayRootCertFile, + "exists", rootCertExists, + "path", certificateService.getAlipayCertPath(alipayRootCertFile) + )); + if (!rootCertExists) healthy = false; + + health.put("healthy", healthy); + health.put("certificates", certificates); + return health; + } + + /** + * 获取详细的证书诊断信息 + */ + public Map getDiagnosticInfo() { + Map diagnostic = new HashMap<>(); + + try { + // 基本系统信息 + diagnostic.put("loadMode", certificateProperties.getLoadMode()); + diagnostic.put("certRootPath", certificateProperties.getCertRootPath()); + diagnostic.put("devCertPath", certificateProperties.getDevCertPath()); + + // 获取所有证书状态 + diagnostic.put("certificateStatus", certificateService.getAllCertificateStatus()); + + // 健康检查结果 + HealthResult health = health(); + diagnostic.put("healthStatus", health.getStatus()); + diagnostic.put("healthDetails", health.getDetails()); + + } catch (Exception e) { + log.error("获取证书诊断信息失败", e); + diagnostic.put("error", e.getMessage()); + } + + return diagnostic; + } + + /** + * 检查特定证书的详细信息 + */ + public Map checkSpecificCertificate(String certType, String fileName) { + Map result = new HashMap<>(); + + try { + boolean exists = certificateService.certificateExists(certType, fileName); + String path = certificateService.getCertificateFilePath(certType, fileName); + + result.put("certType", certType); + result.put("fileName", fileName); + result.put("exists", exists); + result.put("path", path); + + if (exists && (fileName.endsWith(".crt") || fileName.endsWith(".pem"))) { + // 尝试验证证书 + CertificateService.CertificateInfo certInfo = + certificateService.validateX509Certificate(certType, fileName); + result.put("certificateInfo", certInfo); + } + + } catch (Exception e) { + log.error("检查证书失败: {}/{}", certType, fileName, e); + result.put("error", e.getMessage()); + } + + return result; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/service/CertificateService.java b/src/main/java/com/gxwebsoft/common/core/service/CertificateService.java new file mode 100644 index 0000000..e12854a --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/service/CertificateService.java @@ -0,0 +1,281 @@ +package com.gxwebsoft.common.core.service; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 证书管理服务 + * 负责处理不同环境下的证书加载、验证和管理 + * + * @author 科技小王子 + * @since 2024-07-26 + */ +@Slf4j +@Service +public class CertificateService { + + private final CertificateProperties certificateProperties; + + public CertificateService(CertificateProperties certificateProperties) { + this.certificateProperties = certificateProperties; + } + + @PostConstruct + public void init() { + log.info("证书服务初始化,当前加载模式: {}", certificateProperties.getLoadMode()); + log.info("证书根路径: {}", certificateProperties.getCertRootPath()); + + // 检查证书目录和文件 + checkCertificateDirectories(); + } + + /** + * 获取证书文件的输入流 + * + * @param certType 证书类型(wechat/alipay) + * @param fileName 文件名 + * @return 输入流 + * @throws IOException 文件读取异常 + */ + public InputStream getCertificateInputStream(String certType, String fileName) throws IOException { + String certPath = certificateProperties.getCertificatePath(certType, fileName); + + if (certificateProperties.isClasspathMode()) { + // 从classpath加载 + Resource resource = new ClassPathResource(certPath); + if (!resource.exists()) { + throw new IOException("证书文件不存在: " + certPath); + } + log.debug("从classpath加载证书: {}", certPath); + return resource.getInputStream(); + } else { + // 从文件系统加载 + File file = new File(certPath); + if (!file.exists()) { + throw new IOException("证书文件不存在: " + certPath); + } + log.debug("从文件系统加载证书: {}", certPath); + return Files.newInputStream(file.toPath()); + } + } + + /** + * 获取证书文件路径 + * + * @param certType 证书类型 + * @param fileName 文件名 + * @return 文件路径 + */ + public String getCertificateFilePath(String certType, String fileName) { + return certificateProperties.getCertificatePath(certType, fileName); + } + + /** + * 检查证书文件是否存在 + * + * @param certType 证书类型 + * @param fileName 文件名 + * @return 是否存在 + */ + public boolean certificateExists(String certType, String fileName) { + try { + String certPath = certificateProperties.getCertificatePath(certType, fileName); + + if (certificateProperties.isClasspathMode()) { + Resource resource = new ClassPathResource(certPath); + return resource.exists(); + } else { + File file = new File(certPath); + return file.exists() && file.isFile(); + } + } catch (Exception e) { + log.error("检查证书文件存在性时出错: {}", e.getMessage()); + return false; + } + } + + /** + * 获取微信支付证书路径 + * + * @param fileName 文件名 + * @return 证书路径 + */ + public String getWechatPayCertPath(String fileName) { + return certificateProperties.getWechatPayCertPath(fileName); + } + + /** + * 获取支付宝证书路径 + * + * @param fileName 文件名 + * @return 证书路径 + */ + public String getAlipayCertPath(String fileName) { + return certificateProperties.getAlipayCertPath(fileName); + } + + /** + * 验证X509证书 + * + * @param certType 证书类型 + * @param fileName 文件名 + * @return 证书信息 + */ + public CertificateInfo validateX509Certificate(String certType, String fileName) { + try (InputStream inputStream = getCertificateInputStream(certType, fileName)) { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); + + CertificateInfo info = new CertificateInfo(); + info.setSubject(cert.getSubjectX500Principal().toString()); + info.setIssuer(cert.getIssuerX500Principal().toString()); + info.setNotBefore(convertToLocalDateTime(cert.getNotBefore())); + info.setNotAfter(convertToLocalDateTime(cert.getNotAfter())); + info.setSerialNumber(cert.getSerialNumber().toString()); + info.setValid(isValidDate(cert.getNotBefore(), cert.getNotAfter())); + + return info; + } catch (Exception e) { + log.error("验证证书失败: {}/{}, 错误: {}", certType, fileName, e.getMessage()); + return null; + } + } + + /** + * 检查证书目录结构 + */ + private void checkCertificateDirectories() { + String[] certTypes = {"wechat", "alipay"}; + + for (String certType : certTypes) { + if (!certificateProperties.isClasspathMode()) { + // 检查文件系统目录 + String dirPath = certificateProperties.getCertificatePath(certType, ""); + File dir = new File(dirPath); + if (!dir.exists()) { + log.warn("证书目录不存在: {}", dirPath); + } else { + log.info("证书目录存在: {}", dirPath); + } + } + } + } + + /** + * 获取所有证书状态 + * + * @return 证书状态映射 + */ + public Map getAllCertificateStatus() { + Map status = new HashMap<>(); + + // 微信支付证书状态 + Map wechatStatus = new HashMap<>(); + CertificateProperties.WechatPayConfig wechatConfig = certificateProperties.getWechatPay(); + wechatStatus.put("privateKey", getCertStatus("wechat", wechatConfig.getDev().getPrivateKeyFile())); + wechatStatus.put("apiclientCert", getCertStatus("wechat", wechatConfig.getDev().getApiclientCertFile())); + wechatStatus.put("wechatpayCert", getCertStatus("wechat", wechatConfig.getDev().getWechatpayCertFile())); + status.put("wechat", wechatStatus); + + // 支付宝证书状态 + Map alipayStatus = new HashMap<>(); + CertificateProperties.AlipayConfig alipayConfig = certificateProperties.getAlipay(); + alipayStatus.put("appPrivateKey", getCertStatus("alipay", alipayConfig.getAppPrivateKeyFile())); + alipayStatus.put("appCertPublicKey", getCertStatus("alipay", alipayConfig.getAppCertPublicKeyFile())); + alipayStatus.put("alipayCertPublicKey", getCertStatus("alipay", alipayConfig.getAlipayCertPublicKeyFile())); + alipayStatus.put("alipayRootCert", getCertStatus("alipay", alipayConfig.getAlipayRootCertFile())); + status.put("alipay", alipayStatus); + + // 系统信息 + Map systemInfo = new HashMap<>(); + systemInfo.put("loadMode", certificateProperties.getLoadMode()); + systemInfo.put("certRootPath", certificateProperties.getCertRootPath()); + systemInfo.put("devCertPath", certificateProperties.getDevCertPath()); + status.put("system", systemInfo); + + return status; + } + + /** + * 获取单个证书状态 + */ + private Map getCertStatus(String certType, String fileName) { + Map status = new HashMap<>(); + status.put("fileName", fileName); + status.put("exists", certificateExists(certType, fileName)); + status.put("path", getCertificateFilePath(certType, fileName)); + + // 如果是.crt或.pem文件,尝试验证证书 + if (fileName.endsWith(".crt") || fileName.endsWith(".pem")) { + CertificateInfo certInfo = validateX509Certificate(certType, fileName); + status.put("certificateInfo", certInfo); + } + + return status; + } + + /** + * 检查日期是否有效 + */ + private boolean isValidDate(Date notBefore, Date notAfter) { + Date now = new Date(); + return now.after(notBefore) && now.before(notAfter); + } + + /** + * 将Date转换为LocalDateTime + */ + private LocalDateTime convertToLocalDateTime(Date date) { + if (date == null) { + return null; + } + return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); + } + + /** + * 证书信息类 + */ + public static class CertificateInfo { + private String subject; + private String issuer; + private LocalDateTime notBefore; + private LocalDateTime notAfter; + private String serialNumber; + private boolean valid; + + // Getters and Setters + public String getSubject() { return subject; } + public void setSubject(String subject) { this.subject = subject; } + + public String getIssuer() { return issuer; } + public void setIssuer(String issuer) { this.issuer = issuer; } + + public LocalDateTime getNotBefore() { return notBefore; } + public void setNotBefore(LocalDateTime notBefore) { this.notBefore = notBefore; } + + public LocalDateTime getNotAfter() { return notAfter; } + public void setNotAfter(LocalDateTime notAfter) { this.notAfter = notAfter; } + + public String getSerialNumber() { return serialNumber; } + public void setSerialNumber(String serialNumber) { this.serialNumber = serialNumber; } + + public boolean isValid() { return valid; } + public void setValid(boolean valid) { this.valid = valid; } + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/service/EnvironmentAwarePaymentService.java b/src/main/java/com/gxwebsoft/common/core/service/EnvironmentAwarePaymentService.java new file mode 100644 index 0000000..2155cc9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/service/EnvironmentAwarePaymentService.java @@ -0,0 +1,143 @@ +package com.gxwebsoft.common.core.service; + +import com.gxwebsoft.common.system.entity.Payment; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * 环境感知的支付配置服务 + * 根据不同环境自动切换支付回调地址 + * + * @author WebSoft + * @since 2025-01-15 + */ +@Slf4j +@Service +public class EnvironmentAwarePaymentService { + + @Autowired + private PaymentCacheService paymentCacheService; + + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + @Value("${config.server-url:}") + private String serverUrl; + + // 开发环境回调地址配置 + @Value("${payment.dev.notify-url:http://frps-10550.s209.websoft.top/api/shop/shop-order/notify}") + private String devNotifyUrl; + + // 生产环境回调地址配置 + @Value("${payment.prod.notify-url:https://cms-api.websoft.top/api/shop/shop-order/notify}") + private String prodNotifyUrl; + + /** + * 获取环境感知的支付配置 + * 根据当前环境自动调整回调地址 + * + * @param payType 支付类型 + * @param tenantId 租户ID + * @return 支付配置 + */ + public Payment getEnvironmentAwarePaymentConfig(Integer payType, Integer tenantId) { + // 获取原始支付配置 + Payment payment = paymentCacheService.getPaymentConfig(payType, tenantId); + + if (payment == null) { + return null; + } + + // 根据环境调整回调地址 + Payment envPayment = clonePayment(payment); + String notifyUrl = getEnvironmentNotifyUrl(); + + log.info("环境感知支付配置 - 环境: {}, 原始回调: {}, 调整后回调: {}", + activeProfile, payment.getNotifyUrl(), notifyUrl); + + envPayment.setNotifyUrl(notifyUrl); + + return envPayment; + } + + /** + * 根据当前环境获取回调地址 + */ + private String getEnvironmentNotifyUrl() { + if ("dev".equals(activeProfile) || "test".equals(activeProfile)) { + // 开发/测试环境使用本地回调地址 + return devNotifyUrl; + } else if ("prod".equals(activeProfile)) { + // 生产环境使用生产回调地址 + return prodNotifyUrl; + } else { + // 默认使用配置的服务器地址 + return serverUrl + "/shop/shop-order/notify"; + } + } + + /** + * 克隆支付配置对象 + */ + private Payment clonePayment(Payment original) { + Payment cloned = new Payment(); + cloned.setId(original.getId()); + cloned.setName(original.getName()); + cloned.setType(original.getType()); + cloned.setCode(original.getCode()); + cloned.setImage(original.getImage()); + cloned.setWechatType(original.getWechatType()); + cloned.setAppId(original.getAppId()); + cloned.setMchId(original.getMchId()); + cloned.setApiKey(original.getApiKey()); + cloned.setApiclientCert(original.getApiclientCert()); + cloned.setApiclientKey(original.getApiclientKey()); + cloned.setPubKey(original.getPubKey()); + cloned.setPubKeyId(original.getPubKeyId()); + cloned.setMerchantSerialNumber(original.getMerchantSerialNumber()); + cloned.setNotifyUrl(original.getNotifyUrl()); // 这个会被后续覆盖 + cloned.setComments(original.getComments()); + cloned.setSortNumber(original.getSortNumber()); + cloned.setStatus(original.getStatus()); + cloned.setDeleted(original.getDeleted()); + cloned.setTenantId(original.getTenantId()); + return cloned; + } + + /** + * 获取微信支付配置(环境感知) + */ + public Payment getWechatPayConfig(Integer tenantId) { + return getEnvironmentAwarePaymentConfig(0, tenantId); + } + + /** + * 获取支付宝配置(环境感知) + */ + public Payment getAlipayConfig(Integer tenantId) { + return getEnvironmentAwarePaymentConfig(1, tenantId); + } + + /** + * 检查当前环境 + */ + public String getCurrentEnvironment() { + return activeProfile; + } + + /** + * 是否为开发环境 + */ + public boolean isDevelopmentEnvironment() { + return "dev".equals(activeProfile) || "test".equals(activeProfile); + } + + /** + * 是否为生产环境 + */ + public boolean isProductionEnvironment() { + return "prod".equals(activeProfile); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java b/src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java new file mode 100644 index 0000000..17a8e32 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java @@ -0,0 +1,174 @@ +package com.gxwebsoft.common.core.service; + +import cn.hutool.core.util.ObjectUtil; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.param.PaymentParam; +import com.gxwebsoft.common.system.service.PaymentService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 支付配置缓存服务 + * 统一管理支付配置的缓存读取,支持 Payment:1* 格式 + * + * @author 科技小王子 + * @since 2025-07-27 + */ +@Slf4j +@Service +public class PaymentCacheService { + + @Autowired + private RedisUtil redisUtil; + + @Autowired + private PaymentService paymentService; + + /** + * 根据支付类型获取支付配置 + * 优先从 Payment:1{payType} 格式的缓存读取 + * + * @param payType 支付类型 (0=微信支付, 1=支付宝, 2=其他) + * @param tenantId 租户ID (用于兜底查询) + * @return Payment 支付配置 + */ + public Payment getPaymentConfig(Integer payType, Integer tenantId) { + // 1. 优先使用 Payment:1{payType} 格式的缓存键 + String primaryKey = "Payment:1:" + tenantId; + Payment payment = redisUtil.get(primaryKey, Payment.class); + + if (ObjectUtil.isNotEmpty(payment)) { + log.debug("从缓存获取支付配置成功: {}", primaryKey); + return payment; + } + + // 2. 如果 Payment:1* 格式不存在,尝试原有格式 + String fallbackKey = "Payment:" + payType + ":" + tenantId; + payment = redisUtil.get(fallbackKey, Payment.class); + + if (ObjectUtil.isNotEmpty(payment)) { + log.debug("从兜底缓存获取支付配置成功: {}", fallbackKey); + // 将查询结果缓存到 Payment:1* 格式 + redisUtil.set(primaryKey, payment); + return payment; + } + + // 3. 最后从数据库查询 + log.debug("从数据库查询支付配置, payType: {}, tenantId: {}", payType, tenantId); + PaymentParam paymentParam = new PaymentParam(); + paymentParam.setType(payType); + paymentParam.setTenantId(tenantId); // 设置租户ID进行过滤 + List payments = paymentService.listRel(paymentParam); + + if (payments.isEmpty()) { + throw new BusinessException("请完成支付配置,支付类型: " + payType); + } + + Payment dbPayment = payments.get(0); + + // 清理时间字段,避免序列化问题 + Payment cachePayment = cleanPaymentForCache(dbPayment); + + // 将查询结果缓存到 Payment:1* 格式 + redisUtil.set(primaryKey, cachePayment); + log.debug("支付配置已缓存到: {}", primaryKey); + + return dbPayment; // 返回原始对象,不影响业务逻辑 + } + + /** + * 缓存支付配置 + * 同时缓存到 Payment:1{payType} 和原有格式 + * + * @param payment 支付配置 + * @param tenantId 租户ID + */ + public void cachePaymentConfig(Payment payment, Integer tenantId) { + // 缓存到 Payment:1* 格式 + String primaryKey = "Payment:1" + payment.getCode(); + redisUtil.set(primaryKey, payment); + log.debug("支付配置已缓存到: {}", primaryKey); + + // 兼容原有格式 + String legacyKey = "Payment:" + payment.getCode() + ":" + tenantId; + redisUtil.set(legacyKey, payment); + log.debug("支付配置已缓存到兼容格式: {}", legacyKey); + } + + /** + * 删除支付配置缓存 + * 同时删除 Payment:1{payType} 和原有格式 + * + * @param paymentCode 支付代码 (可以是String或Integer) + * @param tenantId 租户ID + */ + public void removePaymentConfig(String paymentCode, Integer tenantId) { + // 删除 Payment:1* 格式缓存 + String primaryKey = "Payment:1" + paymentCode; + redisUtil.delete(primaryKey); + log.debug("已删除支付配置缓存: {}", primaryKey); + + // 删除原有格式缓存 + String legacyKey = "Payment:" + paymentCode + ":" + tenantId; + redisUtil.delete(legacyKey); + log.debug("已删除兼容格式缓存: {}", legacyKey); + } + + /** + * 获取微信支付配置 (payType = 0) + */ + public Payment getWechatPayConfig(Integer tenantId) { + return getPaymentConfig(0, tenantId); + } + + /** + * 获取支付宝配置 (payType = 1) + */ + public Payment getAlipayConfig(Integer tenantId) { + return getPaymentConfig(1, tenantId); + } + + /** + * 清理Payment对象用于缓存 + * 移除可能导致序列化问题的时间字段 + */ + private Payment cleanPaymentForCache(Payment original) { + if (original == null) { + return null; + } + + Payment cleaned = new Payment(); + // 复制所有业务相关字段 + cleaned.setId(original.getId()); + cleaned.setName(original.getName()); + cleaned.setType(original.getType()); + cleaned.setCode(original.getCode()); + cleaned.setImage(original.getImage()); + cleaned.setWechatType(original.getWechatType()); + cleaned.setAppId(original.getAppId()); + cleaned.setMchId(original.getMchId()); + cleaned.setApiKey(original.getApiKey()); + cleaned.setApiclientCert(original.getApiclientCert()); + cleaned.setApiclientKey(original.getApiclientKey()); + cleaned.setPubKey(original.getPubKey()); + cleaned.setPubKeyId(original.getPubKeyId()); + cleaned.setMerchantSerialNumber(original.getMerchantSerialNumber()); + cleaned.setNotifyUrl(original.getNotifyUrl()); + cleaned.setComments(original.getComments()); + cleaned.setSortNumber(original.getSortNumber()); + cleaned.setStatus(original.getStatus()); + cleaned.setDeleted(original.getDeleted()); + cleaned.setTenantId(original.getTenantId()); + + // 不设置时间字段,避免序列化问题 + // cleaned.setCreateTime(null); + // cleaned.setUpdateTime(null); + + return cleaned; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/AliYunSender.java b/src/main/java/com/gxwebsoft/common/core/utils/AliYunSender.java new file mode 100644 index 0000000..80fe4b1 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/AliYunSender.java @@ -0,0 +1,145 @@ +package com.gxwebsoft.common.core.utils; +import cn.hutool.core.codec.Base64; +import org.springframework.stereotype.Component; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.security.MessageDigest; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.UUID; + +@Component +public class AliYunSender { + /* + * 计算MD5+BASE64 + */ + public static String MD5Base64(String s) { + if (s == null) + return null; + String encodeStr = ""; + byte[] utfBytes = s.getBytes(); + MessageDigest mdTemp; + try { + mdTemp = MessageDigest.getInstance("MD5"); + mdTemp.update(utfBytes); + byte[] md5Bytes = mdTemp.digest(); + encodeStr = Base64.encode(md5Bytes); + } catch (Exception e) { + throw new Error("Failed to generate MD5 : " + e.getMessage()); + } + return encodeStr; + } + /* + * 计算 HMAC-SHA1 + */ + public static String HMACSha1(String data, String key) { + String result; + try { + SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1"); + Mac mac = Mac.getInstance("HmacSHA1"); + mac.init(signingKey); + byte[] rawHmac = mac.doFinal(data.getBytes()); + result = Base64.encode(rawHmac); + } catch (Exception e) { + throw new Error("Failed to generate HMAC : " + e.getMessage()); + } + return result; + } + /* + * 获取时间 + */ + public static String toGMTString(Date date) { + SimpleDateFormat df = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.UK); + df.setTimeZone(new java.util.SimpleTimeZone(0, "GMT")); + return df.format(date); + } + /* + * 发送POST请求 + */ + public static String sendPost(String url, String body, String ak_id, String ak_secret) { + PrintWriter out = null; + BufferedReader in = null; + String result = ""; + try { + URL realUrl = new URL(url); + /* + * http header 参数 + */ + String method = "POST"; + String accept = "application/json"; + String content_type = "application/json;chrset=utf-8"; + String path = realUrl.getFile(); + String date = toGMTString(new Date()); + String host = realUrl.getHost(); + // 1.对body做MD5+BASE64加密 + String bodyMd5 = MD5Base64(body); + String uuid = UUID.randomUUID().toString(); + String stringToSign = method + "\n" + accept + "\n" + bodyMd5 + "\n" + content_type + "\n" + date + "\n" + + "x-acs-signature-method:HMAC-SHA1\n" + + "x-acs-signature-nonce:" + uuid + "\n" + + "x-acs-version:2019-01-02\n" + + path; + // 2.计算 HMAC-SHA1 + String signature = HMACSha1(stringToSign, ak_secret); + // 3.得到 authorization header + String authHeader = "acs " + ak_id + ":" + signature; + // 打开和URL之间的连接 + URLConnection conn = realUrl.openConnection(); + // 设置通用的请求属性 + conn.setRequestProperty("Accept", accept); + conn.setRequestProperty("Content-Type", content_type); + conn.setRequestProperty("Content-MD5", bodyMd5); + conn.setRequestProperty("Date", date); + conn.setRequestProperty("Host", host); + conn.setRequestProperty("Authorization", authHeader); + conn.setRequestProperty("x-acs-signature-nonce", uuid); + conn.setRequestProperty("x-acs-signature-method", "HMAC-SHA1"); + conn.setRequestProperty("x-acs-version", "2019-01-02"); // 版本可选 + // 发送POST请求必须设置如下两行 + conn.setDoOutput(true); + conn.setDoInput(true); + // 获取URLConnection对象对应的输出流 + out = new PrintWriter(conn.getOutputStream()); + // 发送请求参数 + out.print(body); + // flush输出流的缓冲 + out.flush(); + // 定义BufferedReader输入流来读取URL的响应 + InputStream is; + HttpURLConnection httpconn = (HttpURLConnection) conn; + if (httpconn.getResponseCode() == 200) { + is = httpconn.getInputStream(); + } else { + is = httpconn.getErrorStream(); + } + in = new BufferedReader(new InputStreamReader(is)); + String line; + while ((line = in.readLine()) != null) { + result += line; + } + } catch (Exception e) { + System.out.println("发送 POST 请求出现异常!" + e); + e.printStackTrace(); + } + // 使用finally块来关闭输出流、输入流 + finally { + try { + if (out != null) { + out.close(); + } + if (in != null) { + in.close(); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + return result; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/AlipayConfigUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/AlipayConfigUtil.java new file mode 100644 index 0000000..42975ef --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/AlipayConfigUtil.java @@ -0,0 +1,110 @@ +package com.gxwebsoft.common.core.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayConstants; +import com.alipay.api.CertAlipayRequest; +import com.alipay.api.DefaultAlipayClient; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.exception.BusinessException; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 支付宝工具类 + * @author leng + * + */ +@Component +public class AlipayConfigUtil { + private final StringRedisTemplate stringRedisTemplate; + public Integer tenantId; + public String gateway; + public JSONObject config; + public String appId; + public String privateKey; + public String appCertPublicKey; + public String alipayCertPublicKey; + public String alipayRootCert; + + @Resource + private ConfigProperties pathConfig; + + public AlipayConfigUtil(StringRedisTemplate stringRedisTemplate){ + this.stringRedisTemplate = stringRedisTemplate; + } + + // 实例化客户端 + public DefaultAlipayClient alipayClient(Integer tenantId) throws AlipayApiException { + this.gateway = "https://openapi.alipay.com/gateway.do"; + this.tenantId = tenantId; + this.payment(tenantId); + CertAlipayRequest certAlipayRequest = new CertAlipayRequest(); + certAlipayRequest.setServerUrl(this.gateway); + certAlipayRequest.setAppId(this.appId); + certAlipayRequest.setPrivateKey(this.privateKey); + certAlipayRequest.setFormat(AlipayConstants.FORMAT_JSON); + certAlipayRequest.setCharset(AlipayConstants.CHARSET_UTF8); + certAlipayRequest.setSignType(AlipayConstants.SIGN_TYPE_RSA2); + certAlipayRequest.setCertPath(this.appCertPublicKey); + certAlipayRequest.setAlipayPublicCertPath(this.alipayCertPublicKey); + certAlipayRequest.setRootCertPath(this.alipayRootCert); +// System.out.println("this.appId = " + this.appId); +// System.out.println("this.appId = " + this.gateway); +// System.out.println("this.appId = " + this.privateKey); +// System.out.println("this.appId = " + this.appCertPublicKey); +// System.out.println("this.appId = " + this.alipayCertPublicKey); +// System.out.println("this.appId = " + this.alipayRootCert); +// System.out.println("this.config = " + this.config); + return new DefaultAlipayClient(certAlipayRequest); + } + + /** + * 获取支付宝秘钥 + */ + public JSONObject payment(Integer tenantId) { + System.out.println("tenantId = " + tenantId); + String key = "cache".concat(tenantId.toString()).concat(":setting:payment"); + System.out.println("key = " + key); + String cache = stringRedisTemplate.opsForValue().get(key); + if (cache == null) { + throw new BusinessException("支付方式未配置"); + } + // 解析json数据 + JSONObject payment = JSON.parseObject(cache.getBytes()); + this.config = payment; + this.appId = payment.getString("alipayAppId"); + this.privateKey = payment.getString("privateKey"); + this.appCertPublicKey = pathConfig.getUploadPath() + "file" + payment.getString("appCertPublicKey"); + this.alipayCertPublicKey = pathConfig.getUploadPath() + "file" + payment.getString("alipayCertPublicKey"); + this.alipayRootCert = pathConfig.getUploadPath() + "file" + payment.getString("alipayRootCert"); + return payment; + } + + public String appId(){ + return this.appId; + } + + public String privateKey(){ + return this.privateKey; + } + + public String appCertPublicKey(){ + return this.appCertPublicKey; + } + + public String alipayCertPublicKey(){ + return this.alipayCertPublicKey; + } + + public String alipayRootCert(){ + return this.alipayRootCert; + } + + + + +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/CacheClient.java b/src/main/java/com/gxwebsoft/common/core/utils/CacheClient.java new file mode 100644 index 0000000..62f063e --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/CacheClient.java @@ -0,0 +1,265 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.result.RedisResult; +import org.springframework.data.geo.Point; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +import static com.gxwebsoft.common.core.constants.RedisConstants.CACHE_NULL_TTL; + +@Component +public class CacheClient { + private final StringRedisTemplate stringRedisTemplate; + public static Integer tenantId; + + public CacheClient(StringRedisTemplate stringRedisTemplate){ + this.stringRedisTemplate = stringRedisTemplate; + } + + /** + * 写入redis缓存 + * @param key [表名]:id + * @param entity 实体类对象 + * 示例 cacheClient.set("merchant:"+id,merchant) + */ + public void set(String key, T entity){ + stringRedisTemplate.opsForValue().set(prefix(key), JSONUtil.toJSONString(entity)); + } + + /** + * 写入redis缓存 + * @param key [表名]:id + * @param entity 实体类对象 + * 示例 cacheClient.set("merchant:"+id,merchant,1L,TimeUnit.DAYS) + */ + public void set(String key, T entity, Long time, TimeUnit unit){ + stringRedisTemplate.opsForValue().set(prefix(key), JSONUtil.toJSONString(entity),time,unit); + } + + /** + * 读取redis缓存 + * @param key [表名]:id + * 示例 cacheClient.get(key) + * @return merchant + */ + public String get(String key) { + return stringRedisTemplate.opsForValue().get(prefix(key)); + } + + /** + * 读取redis缓存 + * @param key [表名]:id + * @param clazz Merchant.class + * @param + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + * @return merchant + */ + public T get(String key, Class clazz) { + String json = stringRedisTemplate.opsForValue().get(prefix(key)); + if(StrUtil.isNotBlank(json)){ + return JSONUtil.parseObject(json, clazz); + } + return null; + } + + /** + * 写redis缓存(哈希类型) + * @param key [表名]:id + * @param field 字段 + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + */ + public void hPut(String key, String field, T entity) { + stringRedisTemplate.opsForHash().put(prefix(key),field,JSONUtil.toJSONString(entity)); + } + + /** + * 写redis缓存(哈希类型) + * @param key [表名]:id + * @param map 字段 + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + */ + public void hPutAll(String key, Map map) { + stringRedisTemplate.opsForHash().putAll(prefix(key),map); + } + + /** + * 读取redis缓存(哈希类型) + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + * @param key [表名]:id + * @param field 字段 + * @return merchant + */ + public T hGet(String key, String field, Class clazz) { + Object obj = stringRedisTemplate.opsForHash().get(prefix(key), field); + return JSONUtil.parseObject(JSONUtil.toJSONString(obj),clazz); + } + + public List hValues(String key){ + return stringRedisTemplate.opsForHash().values(prefix(key)); + } + + public Long hSize(String key){ + return stringRedisTemplate.opsForHash().size(prefix(key)); + } + + // 逻辑过期方式写入redis + public void setWithLogicalExpire(String key, T value, Long time, TimeUnit unit){ + // 设置逻辑过期时间 + final RedisResult redisResult = new RedisResult<>(); + redisResult.setData(value); + redisResult.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time))); + stringRedisTemplate.opsForValue().set(prefix(key),JSONUtil.toJSONString(redisResult)); + } + + // 读取redis + public R query(String keyPrefix, ID id, Class clazz, Function dbFallback, Long time, TimeUnit unit){ + String key = keyPrefix + id; + // 1.从redis查询缓存 + final String json = stringRedisTemplate.opsForValue().get(prefix(key)); + // 2.判断是否存在 + if (StrUtil.isNotBlank(json)) { + // 3.存在,直接返回 + return JSONUtil.parseObject(json,clazz); + } + // 判断命中的是否为空值 + if (json != null) { + return null; + } + // 4. 不存在,跟进ID查询数据库 + R r = dbFallback.apply(id); + // 5. 数据库不存在,返回错误 + if(r == null){ + // 空值写入数据库 + this.set(prefix(key),"",CACHE_NULL_TTL,TimeUnit.MINUTES); + return null; + } + // 写入redis + this.set(prefix(key),r,time,unit); + return r; + } + + /** + * 添加商户定位点 + * @param key geo + * @param id + * 示例 cacheClient.geoAdd("merchant-geo",merchant) + */ + public void geoAdd(String key, Double x, Double y, String id){ + stringRedisTemplate.opsForGeo().add(prefix(key),new Point(x,y),id); + } + + /** + * 删除定位 + * @param key geo + * @param id + * 示例 cacheClient.geoRemove("merchant-geo",id) + */ + public void geoRemove(String key, Integer id){ + stringRedisTemplate.opsForGeo().remove(prefix(key),id.toString()); + } + + + + public void sAdd(String key, T entity){ + stringRedisTemplate.opsForSet().add(prefix(key),JSONUtil.toJSONString(entity)); + } + + public Set sMembers(String key){ + return stringRedisTemplate.opsForSet().members(prefix(key)); + } + + // 更新排行榜 + public void zAdd(String key, Integer userId, Double value) { + stringRedisTemplate.opsForZSet().add(prefix(key),userId.toString(),value); + } + // 增加元素的score值,并返回增加后的值 + public Double zIncrementScore(String key,Integer userId, Double delta){ + return stringRedisTemplate.opsForZSet().incrementScore(key, userId.toString(), delta); + } + // 获取排名榜 + public Set range(String key, Integer start, Integer end) { + return stringRedisTemplate.opsForZSet().range(prefix(key), start, end); + } + // 获取排名榜 + public Set reverseRange(String key, Integer start, Integer end){ + return stringRedisTemplate.opsForZSet().reverseRange(prefix(key), start, end); + } + // 获取分数 + public Double score(String key, Object value){ + return stringRedisTemplate.opsForZSet().score(prefix(key), value); + } + + public void delete(String key){ + stringRedisTemplate.delete(prefix(key)); + } + + // 存储在list头部 + public void leftPush(String key, String keyword){ + stringRedisTemplate.opsForList().leftPush(prefix(key),keyword); + } + + // 获取列表指定范围内的元素 + public List listRange(String key,Long start, Long end){ + return stringRedisTemplate.opsForList().range(prefix(key), start, end); + } + + // 获取列表长度 + public Long listSize(String key){ + return stringRedisTemplate.opsForList().size(prefix(key)); + } + + // 裁剪list + public void listTrim(String key){ + stringRedisTemplate.opsForList().trim(prefix(key), 0L, 100L); + } + + /** + * 读取后台系统设置信息 + * @param keyName 键名wx-word + * @param tenantId 租户ID + * @return + * key示例 cache10048:setting:wx-work + */ + public JSONObject getSettingInfo(String keyName,Integer tenantId){ + String key = "cache" + tenantId + ":setting:" + keyName; + final String cache = stringRedisTemplate.opsForValue().get(key); + assert cache != null; + return JSON.parseObject(cache); + } + + /** + * KEY前缀 + * cache[tenantId]:[key+id] + */ + public static String prefix(String key){ + String prefix = "cache"; + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null) { + Object object = authentication.getPrincipal(); + if (object instanceof User) { + final Integer tenantId = ((User) object).getTenantId(); + prefix = prefix.concat(tenantId.toString()).concat(":"); + } + } + return prefix.concat(key); + } + + // 组装key + public String key(String name,Integer id){ + return name.concat(":").concat(id.toString()); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/CertificateLoader.java b/src/main/java/com/gxwebsoft/common/core/utils/CertificateLoader.java new file mode 100644 index 0000000..a256e49 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/CertificateLoader.java @@ -0,0 +1,230 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.core.config.CertificateProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * 证书加载工具类 + * 支持多种证书加载方式,适配Docker容器化部署 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Slf4j +@Component +public class CertificateLoader { + + private final CertificateProperties certConfig; + + public CertificateLoader(CertificateProperties certConfig) { + this.certConfig = certConfig; + } + + @PostConstruct + public void init() { + log.info("证书加载器初始化,加载模式:{}", certConfig.getLoadMode()); + if (certConfig.getLoadMode() == CertificateProperties.LoadMode.VOLUME) { + log.info("Docker挂载卷证书路径:{}", certConfig.getCertRootPath()); + validateCertDirectory(); + } + } + + /** + * 验证证书目录是否存在 + */ + private void validateCertDirectory() { + File certDir = new File(certConfig.getCertRootPath()); + if (!certDir.exists()) { + log.warn("证书目录不存在:{},将尝试创建", certConfig.getCertRootPath()); + if (!certDir.mkdirs()) { + log.error("无法创建证书目录:{}", certConfig.getCertRootPath()); + } + } else { + log.info("证书目录验证成功:{}", certConfig.getCertRootPath()); + } + } + + /** + * 加载证书文件路径 + * + * @param certPath 证书路径(可能是相对路径、绝对路径或classpath路径) + * @return 实际的证书文件路径 + */ + public String loadCertificatePath(String certPath) { + if (!StringUtils.hasText(certPath)) { + throw new IllegalArgumentException("证书路径不能为空"); + } + + try { + switch (certConfig.getLoadMode()) { + case CLASSPATH: + return loadFromClasspath(certPath); + case VOLUME: + return loadFromVolume(certPath); + case FILESYSTEM: + default: + return loadFromFileSystem(certPath); + } + } catch (Exception e) { + log.error("加载证书失败,路径:{}", certPath, e); + throw new RuntimeException("证书加载失败:" + certPath, e); + } + } + + /** + * 从classpath加载证书 + */ + private String loadFromClasspath(String certPath) throws IOException { + String resourcePath = certPath.startsWith("classpath:") ? + certPath.substring("classpath:".length()) : certPath; + + ClassPathResource resource = new ClassPathResource(resourcePath); + if (!resource.exists()) { + throw new IOException("Classpath中找不到证书文件:" + resourcePath); + } + + // 将classpath中的文件复制到临时目录 + Path tempFile = Files.createTempFile("cert_", ".pem"); + try (InputStream inputStream = resource.getInputStream()) { + Files.copy(inputStream, tempFile, java.nio.file.StandardCopyOption.REPLACE_EXISTING); + } + + String tempPath = tempFile.toAbsolutePath().toString(); + log.debug("从classpath加载证书:{} -> {}", resourcePath, tempPath); + return tempPath; + } + + /** + * 从Docker挂载卷加载证书 + */ + private String loadFromVolume(String certPath) { + log.debug("尝试从Docker挂载卷加载证书:{}", certPath); + + // 如果是完整路径,直接使用 + if (certPath.startsWith("/") || certPath.contains(":")) { + File file = new File(certPath); + log.debug("检查完整路径文件是否存在:{}", certPath); + if (file.exists()) { + log.debug("使用完整路径加载证书:{}", certPath); + return certPath; + } else { + log.error("完整路径文件不存在:{}", certPath); + } + } + + // 否则拼接挂载卷路径 + String fullPath = Paths.get(certConfig.getCertRootPath(), certPath).toString(); + File file = new File(fullPath); + if (!file.exists()) { + throw new RuntimeException("Docker挂载卷中找不到证书文件:" + fullPath); + } + + log.debug("从Docker挂载卷加载证书:{}", fullPath); + return fullPath; + } + + /** + * 从文件系统加载证书 + */ + private String loadFromFileSystem(String certPath) { + File file = new File(certPath); + if (!file.exists()) { + throw new RuntimeException("文件系统中找不到证书文件:" + certPath); + } + + log.debug("从文件系统加载证书:{}", certPath); + return certPath; + } + + /** + * 检查证书文件是否存在 + * + * @param certPath 证书路径 + * @return 是否存在 + */ + public boolean certificateExists(String certPath) { + try { + switch (certConfig.getLoadMode()) { + case CLASSPATH: + String resourcePath = certPath.startsWith("classpath:") ? + certPath.substring("classpath:".length()) : certPath; + ClassPathResource resource = new ClassPathResource(resourcePath); + return resource.exists(); + case VOLUME: + String fullPath = certPath.startsWith("/") ? certPath : + Paths.get(certConfig.getCertRootPath(), certPath).toString(); + return new File(fullPath).exists(); + case FILESYSTEM: + default: + return new File(certPath).exists(); + } + } catch (Exception e) { + log.warn("检查证书文件存在性时出错:{}", certPath, e); + return false; + } + } + + /** + * 获取证书文件的输入流 + * + * @param certPath 证书路径 + * @return 输入流 + */ + public InputStream getCertificateInputStream(String certPath) throws IOException { + switch (certConfig.getLoadMode()) { + case CLASSPATH: + String resourcePath = certPath.startsWith("classpath:") ? + certPath.substring("classpath:".length()) : certPath; + ClassPathResource resource = new ClassPathResource(resourcePath); + return resource.getInputStream(); + case VOLUME: + case FILESYSTEM: + default: + String actualPath = loadCertificatePath(certPath); + return Files.newInputStream(Paths.get(actualPath)); + } + } + + /** + * 列出证书目录中的所有文件 + * + * @return 证书文件列表 + */ + public String[] listCertificateFiles() { + try { + switch (certConfig.getLoadMode()) { + case VOLUME: + File certDir = new File(certConfig.getCertRootPath()); + if (certDir.exists() && certDir.isDirectory()) { + return certDir.list(); + } + break; + case CLASSPATH: + // classpath模式下不支持列出文件 + log.warn("Classpath模式下不支持列出证书文件"); + break; + case FILESYSTEM: + default: + // 文件系统模式下证书可能分散在不同目录,不支持统一列出 + log.warn("文件系统模式下不支持列出证书文件"); + break; + } + } catch (Exception e) { + log.error("列出证书文件时出错", e); + } + return new String[0]; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/CommonUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/CommonUtil.java new file mode 100644 index 0000000..6435db6 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/CommonUtil.java @@ -0,0 +1,321 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.AES; +import cn.hutool.crypto.symmetric.SymmetricAlgorithm; +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.system.entity.Role; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * 常用工具方法 + * + * @author WebSoft + * @since 2017-06-10 10:10:22 + */ +public class CommonUtil { + + // 生成uuid的字符 + private static final String[] chars = new String[]{ + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", + "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" + }; + + /** + * 生成8位uuid + * + * @return String + */ + public static String randomUUID8() { + StringBuilder sb = new StringBuilder(); + String uuid = UUID.randomUUID().toString().replace("-", ""); + for (int i = 0; i < 8; i++) { + String str = uuid.substring(i * 4, i * 4 + 4); + int x = Integer.parseInt(str, 16); + sb.append(chars[x % 0x3E]); + } + return sb.toString(); + } + + /** + * 生成16位uuid + * + * @return String + */ + public static String randomUUID16() { + StringBuilder sb = new StringBuilder(); + String uuid = UUID.randomUUID().toString().replace("-", ""); + for (int i = 0; i < 16; i++) { + String str = uuid.substring(i * 2, i * 2 + 2); + int x = Integer.parseInt(str, 16); + sb.append(chars[x % 0x3E]); + } + return sb.toString(); + } + + /** + * 获取当前时间 + * + * @return String + */ + public static String currentTime() { + Date date = new Date(); + SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss"); + return sdf.format(date); + } + + /** + * 生成10位随机用户名 + * + * @return String + */ + public static String randomUsername(String prefix) { + Date date = new Date(); + SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss"); + String currentTime = sdf.format(date); + return prefix + currentTime; + } + + /** + * 生成订单号 + * 20233191166110426 + * 20230419135802391412 + * @return + */ + public static String createOrderNo() { + String prefix = DateTime.now().toString(DatePattern.PURE_DATETIME_PATTERN); + return prefix + RandomUtil.randomNumbers(2); + } + + /** + * 生成订单号 + * @param tenantId + * 20233191166110426 + * 20230419135802391412 + * @return + */ + public static String createOrderNo(String tenantId) { + String prefix = DateTime.now().toString(DatePattern.PURE_DATETIME_PATTERN); + return prefix + tenantId + RandomUtil.randomNumbers(2); + } + + /** + * 生成订单水流号 + * @param tenantId + * @return + */ + public static String serialNo(int tenantId) { + String prefix = DateTime.now().toString(DatePattern.PURE_DATETIME_PATTERN); + return prefix + tenantId + RandomUtil.randomNumbers(2); + } + + /** + * 生成会员卡号 + * @return + */ + public static String createCardNo() { + String prefix = DateTime.now().toString(DatePattern.PURE_TIME_PATTERN); + return "00" + prefix + RandomUtil.randomNumbers(2); + } + + /** + * 检查List是否有重复元素 + * + * @param list List + * @param mapper 获取需要检查的字段的Function + * @param 数据的类型 + * @param 需要检查的字段的类型 + * @return boolean + */ + public static boolean checkRepeat(List list, Function mapper) { + for (int i = 0; i < list.size(); i++) { + for (int j = 0; j < list.size(); j++) { + if (i != j && mapper.apply(list.get(i)).equals(mapper.apply(list.get(j)))) { + return true; + } + } + } + return false; + } + + /** + * List转为树形结构 + * + * @param data List + * @param parentId 顶级的parentId + * @param parentIdMapper 获取parentId的Function + * @param idMapper 获取id的Function + * @param consumer 赋值children的Consumer + * @param 数据的类型 + * @param parentId的类型 + * @return List + */ + public static List toTreeData(List data, R parentId, + Function parentIdMapper, + Function idMapper, + BiConsumer> consumer) { + List result = new ArrayList<>(); + for (T d : data) { + R dParentId = parentIdMapper.apply(d); + if (ObjectUtil.equals(parentId, dParentId)) { + R dId = idMapper.apply(d); + List children = toTreeData(data, dId, parentIdMapper, idMapper, consumer); + consumer.accept(d, children); + result.add(d); + } + } + return result; + } + + /** + * 遍历树形结构数据 + * + * @param data List + * @param consumer 回调 + * @param mapper 获取children的Function + * @param 数据的类型 + */ + public static void eachTreeData(List data, Consumer consumer, Function> mapper) { + for (T d : data) { + consumer.accept(d); + List children = mapper.apply(d); + if (children != null && children.size() > 0) { + eachTreeData(children, consumer, mapper); + } + } + } + + /** + * 获取集合中的第一条数据 + * + * @param records 集合 + * @return 第一条数据 + */ + public static T listGetOne(List records) { + return records == null || records.size() == 0 ? null : records.get(0); + } + + /** + * 支持跨域 + * + * @param response HttpServletResponse + */ + public static void addCrossHeaders(HttpServletResponse response) { + response.setHeader("Access-Control-Max-Age", "3600"); + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Methods", "*"); + response.setHeader("Access-Control-Allow-Headers", "*"); + response.setHeader("Access-Control-Expose-Headers", Constants.TOKEN_HEADER_NAME); + } + + /** + * 输出错误信息 + * + * @param response HttpServletResponse + * @param code 错误码 + * @param message 提示信息 + * @param error 错误信息 + */ + public static void responseError(HttpServletResponse response, Integer code, String message, String error) { + response.setContentType("application/json;charset=UTF-8"); + try { + PrintWriter out = response.getWriter(); + out.write(JSONUtil.toJSONString(new ApiResult<>(code, message, null, error))); + out.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static boolean hasRole(List array,String value){ + System.out.println("value = " + value); + if (value == null) { + return true; + } + if (array == null) { + return false; + } + if (!array.isEmpty()) { + final List collect = array.stream().map(Role::getRoleCode) + .collect(Collectors.toList()); + final boolean contains = collect.contains(value); + if (contains) { + return true; + } + } + return false; + } + + public static boolean hasRole(List array,List value){ + System.out.println("value = " + value); + if (value == null) { + return true; + } + if (array == null) { + return false; + } + if (!array.isEmpty()) { + final List collect = array.stream().map(Role::getRoleCode) + .collect(Collectors.toList()); + final boolean disjoint = Collections.disjoint(collect, value); + if (!disjoint) { + return true; + } + } + return false; + } + + public static AES aes(){ + // 随机生成密钥 + byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded(); + return SecureUtil.aes(key); + } + + // 机密文本 + public static String encrypt(String text){ + final AES aes = aes(); + return aes.encryptHex(text); + } + + // 解密 + public static String decrypt(String encrypt){ + final AES aes = aes(); + return aes.decryptStr(encrypt, CharsetUtil.CHARSET_UTF_8); + } + + /** + * 验证给定的字符串是否为有效的中国大陆手机号码。 + * + * @param phoneNumber 要验证的电话号码字符串 + * @return 如果字符串是有效的手机号码,则返回true;否则返回false + */ + public static boolean isValidPhoneNumber(String phoneNumber) { + // 定义手机号码的正则表达式 + String regex = "^1[3-9]\\d{9}$"; + + // 创建Pattern对象 + Pattern pattern = Pattern.compile(regex); + + // 使用matcher方法创建Matcher对象并进行匹配 + return pattern.matcher(phoneNumber).matches(); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/DateTimeUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/DateTimeUtil.java new file mode 100644 index 0000000..bde0280 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/DateTimeUtil.java @@ -0,0 +1,93 @@ +package com.gxwebsoft.common.core.utils; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * 时间格式化工具类 + * 用于统一处理LocalDateTime的格式化 + * + * @author WebSoft + * @since 2025-08-23 + */ +public class DateTimeUtil { + + /** + * 默认的日期时间格式 + */ + public static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + + /** + * 默认的日期格式 + */ + public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd"; + + /** + * 默认的时间格式 + */ + public static final String DEFAULT_TIME_PATTERN = "HH:mm:ss"; + + /** + * 默认的日期时间格式化器 + */ + private static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER = + DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN); + + /** + * 格式化LocalDateTime为字符串 + * 使用默认格式:yyyy-MM-dd HH:mm:ss + * + * @param dateTime 要格式化的时间 + * @return 格式化后的字符串,如果输入为null则返回null + */ + public static String formatDateTime(LocalDateTime dateTime) { + if (dateTime == null) { + return null; + } + return dateTime.format(DEFAULT_DATETIME_FORMATTER); + } + + /** + * 格式化LocalDateTime为字符串 + * 使用指定格式 + * + * @param dateTime 要格式化的时间 + * @param pattern 格式模式 + * @return 格式化后的字符串,如果输入为null则返回null + */ + public static String formatDateTime(LocalDateTime dateTime, String pattern) { + if (dateTime == null) { + return null; + } + return dateTime.format(DateTimeFormatter.ofPattern(pattern)); + } + + /** + * 解析字符串为LocalDateTime + * 使用默认格式:yyyy-MM-dd HH:mm:ss + * + * @param dateTimeStr 时间字符串 + * @return LocalDateTime对象,如果输入为null或空字符串则返回null + */ + public static LocalDateTime parseDateTime(String dateTimeStr) { + if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) { + return null; + } + return LocalDateTime.parse(dateTimeStr, DEFAULT_DATETIME_FORMATTER); + } + + /** + * 解析字符串为LocalDateTime + * 使用指定格式 + * + * @param dateTimeStr 时间字符串 + * @param pattern 格式模式 + * @return LocalDateTime对象,如果输入为null或空字符串则返回null + */ + public static LocalDateTime parseDateTime(String dateTimeStr, String pattern) { + if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) { + return null; + } + return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern(pattern)); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/EncryptedQrCodeUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/EncryptedQrCodeUtil.java new file mode 100644 index 0000000..ff66ddc --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/EncryptedQrCodeUtil.java @@ -0,0 +1,433 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.AES; +import cn.hutool.crypto.symmetric.SymmetricAlgorithm; +import cn.hutool.extra.qrcode.QrCodeUtil; +import cn.hutool.extra.qrcode.QrConfig; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.crypto.spec.SecretKeySpec; +import java.awt.*; +import java.io.ByteArrayOutputStream; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * 加密二维码工具类 + * 使用token作为密钥对二维码数据进行AES加密 + * + * @author WebSoft + * @since 2025-08-18 + */ +@Component +public class EncryptedQrCodeUtil { + + @Autowired + private RedisUtil redisUtil; + + private static final String QR_TOKEN_PREFIX = "qr_token:"; + private static final long DEFAULT_EXPIRE_MINUTES = 30; // 默认30分钟过期 + + /** + * 生成加密的二维码数据 + * + * @param originalData 原始数据 + * @param expireMinutes 过期时间(分钟) + * @return 包含token和加密数据的Map + */ + public Map generateEncryptedData(String originalData, Long expireMinutes) { + if (StrUtil.isBlank(originalData)) { + throw new IllegalArgumentException("原始数据不能为空"); + } + + if (expireMinutes == null || expireMinutes <= 0) { + expireMinutes = DEFAULT_EXPIRE_MINUTES; + } + + // 生成随机token作为密钥 + String token = RandomUtil.randomString(32); + + try { + // 使用token生成AES密钥 + AES aes = createAESFromToken(token); + + // 加密原始数据 + String encryptedData = aes.encryptHex(originalData); + + // 将token和原始数据存储到Redis中,设置过期时间 + String redisKey = QR_TOKEN_PREFIX + token; + redisUtil.set(redisKey, originalData, expireMinutes, TimeUnit.MINUTES); + + Map result = new HashMap<>(); + result.put("token", token); + result.put("encryptedData", encryptedData); + result.put("expireMinutes", expireMinutes.toString()); + + return result; + + } catch (Exception e) { + throw new RuntimeException("生成加密数据失败: " + e.getMessage(), e); + } + } + + /** + * 解密二维码数据 + * + * @param token 密钥token + * @param encryptedData 加密的数据 + * @return 解密后的原始数据 + */ + public String decryptData(String token, String encryptedData) { + if (StrUtil.isBlank(token) || StrUtil.isBlank(encryptedData)) { + throw new IllegalArgumentException("token和加密数据不能为空"); + } + + try { + // 从Redis验证token是否有效 + String redisKey = QR_TOKEN_PREFIX + token; + String originalData = redisUtil.get(redisKey); + + if (StrUtil.isBlank(originalData)) { + throw new RuntimeException("token已过期或无效"); + } + + // 使用token生成AES密钥 + AES aes = createAESFromToken(token); + + // 解密数据 + String decryptedData = aes.decryptStr(encryptedData, CharsetUtil.CHARSET_UTF_8); + + // 验证解密结果与Redis中存储的数据是否一致 + if (!originalData.equals(decryptedData)) { + throw new RuntimeException("数据验证失败"); + } + + return decryptedData; + + } catch (Exception e) { + throw new RuntimeException("解密数据失败: " + e.getMessage(), e); + } + } + + /** + * 生成加密的二维码图片(自包含模式) + * + * @param originalData 原始数据 + * @param width 二维码宽度 + * @param height 二维码高度 + * @param expireMinutes 过期时间(分钟) + * @param businessType 业务类型(可选,如:order、user、coupon等) + * @return 包含二维码图片Base64和token的Map + */ + public Map generateEncryptedQrCode(String originalData, int width, int height, Long expireMinutes, String businessType) { + try { + // 生成加密数据 + Map encryptedInfo = generateEncryptedData(originalData, expireMinutes); + + // 创建二维码内容(包含token、加密数据和业务类型) + Map qrContent = new HashMap<>(); + qrContent.put("token", encryptedInfo.get("token")); + qrContent.put("data", encryptedInfo.get("encryptedData")); + qrContent.put("type", "encrypted"); + + // 添加业务类型(如果提供) + if (StrUtil.isNotBlank(businessType)) { + qrContent.put("businessType", businessType); + } + + String qrDataJson = JSONObject.toJSONString(qrContent); + + // 配置二维码 + QrConfig config = new QrConfig(width, height); + config.setMargin(1); + config.setForeColor(Color.BLACK); + config.setBackColor(Color.WHITE); + + // 生成二维码图片 + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + QrCodeUtil.generate(qrDataJson, config, "png", outputStream); + + // 转换为Base64 + String base64Image = Base64.getEncoder().encodeToString(outputStream.toByteArray()); + + Map result = new HashMap<>(); + result.put("qrCodeBase64", base64Image); + result.put("token", encryptedInfo.get("token")); + result.put("originalData", originalData); + result.put("expireMinutes", encryptedInfo.get("expireMinutes")); + result.put("businessType", businessType); + + return result; + + } catch (Exception e) { + throw new RuntimeException("生成加密二维码失败: " + e.getMessage(), e); + } + } + + /** + * 生成加密的二维码图片(自包含模式,无业务类型) + * 向后兼容的重载方法 + * + * @param originalData 原始数据 + * @param width 二维码宽度 + * @param height 二维码高度 + * @param expireMinutes 过期时间(分钟) + * @return 包含二维码图片Base64和token的Map + */ + public Map generateEncryptedQrCode(String originalData, int width, int height, Long expireMinutes) { + return generateEncryptedQrCode(originalData, width, height, expireMinutes, null); + } + + /** + * 生成业务加密二维码(门店核销模式) + * 使用统一的业务密钥,门店可以直接解密 + * + * @param originalData 原始数据 + * @param width 二维码宽度 + * @param height 二维码高度 + * @param businessKey 业务密钥(如门店密钥) + * @param expireMinutes 过期时间(分钟) + * @param businessType 业务类型(如:order、coupon、ticket等) + * @return 包含二维码图片Base64的Map + */ + public Map generateBusinessEncryptedQrCode(String originalData, int width, int height, + String businessKey, Long expireMinutes, String businessType) { + try { + if (StrUtil.isBlank(businessKey)) { + throw new IllegalArgumentException("业务密钥不能为空"); + } + + if (expireMinutes == null || expireMinutes <= 0) { + expireMinutes = DEFAULT_EXPIRE_MINUTES; + } + + // 生成唯一的二维码ID + String qrId = RandomUtil.randomString(16); + + // 使用业务密钥加密数据 + AES aes = createAESFromToken(businessKey); + String encryptedData = aes.encryptHex(originalData); + + // 将二维码信息存储到Redis(用于验证和防重复使用) + String qrInfoKey = "qr_info:" + qrId; + Map qrInfo = new HashMap<>(); + qrInfo.put("originalData", originalData); + qrInfo.put("createTime", String.valueOf(System.currentTimeMillis())); + qrInfo.put("businessKey", businessKey); + redisUtil.set(qrInfoKey, JSONObject.toJSONString(qrInfo), expireMinutes, TimeUnit.MINUTES); + + // 创建二维码内容 + Map qrContent = new HashMap<>(); + qrContent.put("qrId", qrId); + qrContent.put("data", encryptedData); + qrContent.put("type", "business_encrypted"); + qrContent.put("expire", String.valueOf(System.currentTimeMillis() + expireMinutes * 60 * 1000)); + + // 添加业务类型(如果提供) + if (StrUtil.isNotBlank(businessType)) { + qrContent.put("businessType", businessType); + } + + String qrDataJson = JSONObject.toJSONString(qrContent); + + // 配置二维码 + QrConfig config = new QrConfig(width, height); + config.setMargin(1); + config.setForeColor(Color.BLACK); + config.setBackColor(Color.WHITE); + + // 生成二维码图片 + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + QrCodeUtil.generate(qrDataJson, config, "png", outputStream); + + // 转换为Base64 + String base64Image = Base64.getEncoder().encodeToString(outputStream.toByteArray()); + + Map result = new HashMap<>(); + result.put("qrCodeBase64", base64Image); + result.put("qrId", qrId); + result.put("originalData", originalData); + result.put("expireMinutes", expireMinutes.toString()); + result.put("businessType", businessType); + // 注意:出于安全考虑,不返回businessKey + + return result; + + } catch (Exception e) { + throw new RuntimeException("生成业务加密二维码失败: " + e.getMessage(), e); + } + } + + /** + * 生成业务加密二维码(门店核销模式,无业务类型) + * 向后兼容的重载方法 + * + * @param originalData 原始数据 + * @param width 二维码宽度 + * @param height 二维码高度 + * @param businessKey 业务密钥(如门店密钥) + * @param expireMinutes 过期时间(分钟) + * @return 包含二维码图片Base64的Map + */ + public Map generateBusinessEncryptedQrCode(String originalData, int width, int height, + String businessKey, Long expireMinutes) { + return generateBusinessEncryptedQrCode(originalData, width, height, businessKey, expireMinutes, null); + } + + /** + * 验证并解密二维码内容(自包含模式) + * 二维码包含token和加密数据,扫码方无需额外信息 + * + * @param qrContent 二维码扫描得到的内容 + * @return 解密后的原始数据 + */ + public String verifyAndDecryptQrCode(String qrContent) { + QrCodeDecryptResult result = verifyAndDecryptQrCodeWithResult(qrContent); + return result.getOriginalData(); + } + + /** + * 验证并解密二维码内容(自包含模式,返回完整结果) + * 包含业务类型等详细信息 + * + * @param qrContent 二维码扫描得到的内容 + * @return 包含解密数据和业务类型的完整结果 + */ + public QrCodeDecryptResult verifyAndDecryptQrCodeWithResult(String qrContent) { + try { + // 解析二维码内容 + @SuppressWarnings("unchecked") + Map contentMap = JSONObject.parseObject(qrContent, Map.class); + + String type = contentMap.get("type"); + + // 严格验证二维码类型,防止前端伪造 + if (!isValidQrCodeType(type, "encrypted")) { + throw new RuntimeException("无效的二维码类型或二维码已被篡改"); + } + + String token = contentMap.get("token"); + String encryptedData = contentMap.get("data"); + + // 验证必要字段 + if (StrUtil.isBlank(token) || StrUtil.isBlank(encryptedData)) { + throw new RuntimeException("二维码数据不完整"); + } + + String businessType = contentMap.get("businessType"); // 获取业务类型 + + // 解密数据(自包含模式:token就在二维码中) + String originalData = decryptData(token, encryptedData); + + // 返回包含业务类型的完整结果 + return QrCodeDecryptResult.createEncryptedResult(originalData, businessType); + + } catch (Exception e) { + throw new RuntimeException("验证和解密二维码失败: " + e.getMessage(), e); + } + } + + /** + * 验证并解密二维码内容(业务模式) + * 适用于门店核销场景:门店有统一的解密密钥 + * + * @param qrContent 二维码扫描得到的内容 + * @param businessKey 业务密钥(如门店密钥) + * @return 解密后的原始数据 + */ + public String verifyAndDecryptQrCodeWithBusinessKey(String qrContent, String businessKey) { + try { + // 解析二维码内容 + @SuppressWarnings("unchecked") + Map contentMap = JSONObject.parseObject(qrContent, Map.class); + + String type = contentMap.get("type"); + if (!"business_encrypted".equals(type)) { + throw new RuntimeException("不是业务加密类型的二维码"); + } + + String encryptedData = contentMap.get("data"); + String qrId = contentMap.get("qrId"); // 二维码唯一ID + + // 验证二维码是否已被使用(防止重复核销) + String usedKey = "qr_used:" + qrId; + if (StrUtil.isNotBlank(redisUtil.get(usedKey))) { + throw new RuntimeException("二维码已被使用"); + } + + // 使用业务密钥解密 + AES aes = createAESFromToken(businessKey); + String decryptedData = aes.decryptStr(encryptedData, CharsetUtil.CHARSET_UTF_8); + + // 标记二维码为已使用(24小时过期,防止重复使用) + redisUtil.set(usedKey, "used", 24L, TimeUnit.HOURS); + + return decryptedData; + + } catch (Exception e) { + throw new RuntimeException("业务验证和解密二维码失败: " + e.getMessage(), e); + } + } + + /** + * 删除token(使二维码失效) + * + * @param token 要删除的token + */ + public void invalidateToken(String token) { + if (StrUtil.isNotBlank(token)) { + String redisKey = QR_TOKEN_PREFIX + token; + redisUtil.delete(redisKey); + } + } + + /** + * 检查token是否有效 + * + * @param token 要检查的token + * @return true表示有效,false表示无效或过期 + */ + public boolean isTokenValid(String token) { + if (StrUtil.isBlank(token)) { + return false; + } + + String redisKey = QR_TOKEN_PREFIX + token; + String data = redisUtil.get(redisKey); + return StrUtil.isNotBlank(data); + } + + /** + * 验证二维码类型是否有效 + * + * @param actualType 实际的类型 + * @param expectedType 期望的类型 + * @return true表示有效,false表示无效 + */ + private boolean isValidQrCodeType(String actualType, String expectedType) { + return expectedType.equals(actualType); + } + + /** + * 根据token创建AES加密器 + * + * @param token 密钥token + * @return AES加密器 + */ + private AES createAESFromToken(String token) { + // 使用token生成固定长度的密钥 + String keyString = SecureUtil.md5(token); + // 取前16字节作为AES密钥 + byte[] keyBytes = keyString.substring(0, 16).getBytes(CharsetUtil.CHARSET_UTF_8); + SecretKeySpec secretKey = new SecretKeySpec(keyBytes, SymmetricAlgorithm.AES.getValue()); + return SecureUtil.aes(secretKey.getEncoded()); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/FileServerUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/FileServerUtil.java new file mode 100644 index 0000000..45201d2 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/FileServerUtil.java @@ -0,0 +1,401 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.img.ImgUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import org.apache.tika.Tika; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.MalformedURLException; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * 文件上传下载工具类 + * + * @author WebSoft + * @since 2018-12-14 08:38:53 + */ +public class FileServerUtil { + // 除 text/* 外也需要设置输出编码的 content-type + private final static List SET_CHARSET_CONTENT_TYPES = Arrays.asList( + "application/json", + "application/javascript" + ); + + /** + * 上传文件 + * + * @param file MultipartFile + * @param directory 文件保存的目录 + * @param uuidName 是否用uuid命名 + * @return File + */ + public static File upload(MultipartFile file, String directory, boolean uuidName) + throws IOException, IllegalStateException { + File outFile = getUploadFile(file.getOriginalFilename(), directory, uuidName); + if (!outFile.getParentFile().exists()) { + if (!outFile.getParentFile().mkdirs()) { + throw new RuntimeException("make directory fail"); + } + } + file.transferTo(outFile); + return outFile; + } + + /** + * 上传base64格式文件 + * + * @param base64 base64编码字符 + * @param fileName 文件名称, 为空使用uuid命名 + * @param directory 文件保存的目录 + * @return File + */ + public static File upload(String base64, String fileName, String directory) + throws FileNotFoundException, IORuntimeException { + if (StrUtil.isBlank(base64) || !base64.startsWith("data:image/") || !base64.contains(";base64,")) { + throw new RuntimeException("base64 data error"); + } + String suffix = "." + base64.substring(11, base64.indexOf(";")); // 获取文件后缀 + boolean uuidName = StrUtil.isBlank(fileName); + File outFile = getUploadFile(uuidName ? suffix : fileName, directory, uuidName); + byte[] bytes = Base64.getDecoder().decode(base64.substring(base64.indexOf(";") + 8).getBytes()); + IoUtil.write(new FileOutputStream(outFile), true, bytes); + return outFile; + } + + /** + * 获取上传文件位置 + * + * @param name 文件名称 + * @param directory 上传目录 + * @param uuidName 是否使用uuid命名 + * @return File + */ + public static File getUploadFile(String name, String directory, boolean uuidName) { + // 当前日期作为上传子目录 + String dir = new SimpleDateFormat("yyyyMMdd/").format(new Date()); + // 获取文件后缀 + String suffix = (name == null || !name.contains(".")) ? "" : name.substring(name.lastIndexOf(".")); + // 使用uuid命名 + if (uuidName || name == null) { + String uuid = UUID.randomUUID().toString().replaceAll("-", ""); + return new File(directory, dir + uuid + suffix); + } + // 使用原名称, 存在相同则加(1) + File file = new File(directory, dir + name); + String prefix = StrUtil.removeSuffix(name, suffix); + int sameSize = 2; + while (file.exists()) { + file = new File(directory, dir + prefix + "(" + sameSize + ")" + suffix); + sameSize++; + } + return file; + } + + /** + * 查看文件, 支持断点续传 + * + * @param file 文件 + * @param pdfDir office转pdf输出目录 + * @param officeHome openOffice安装目录 + * @param response HttpServletResponse + * @param request HttpServletRequest + */ + public static void preview(File file, String pdfDir, String officeHome, + HttpServletResponse response, HttpServletRequest request) { + preview(file, false, null, pdfDir, officeHome, response, request); + } + + /** + * 查看文件, 支持断点续传 + * + * @param file 文件 + * @param forceDownload 是否强制下载 + * @param fileName 强制下载的文件名称 + * @param pdfDir office转pdf输出目录 + * @param officeHome openOffice安装目录 + * @param response HttpServletResponse + * @param request HttpServletRequest + */ + public static void preview(File file, boolean forceDownload, String fileName, String pdfDir, String officeHome, + HttpServletResponse response, HttpServletRequest request) { + CommonUtil.addCrossHeaders(response); + if (file == null || !file.exists()) { + outNotFund(response); + return; + } + if (forceDownload) { + setDownloadHeader(response, StrUtil.isBlank(fileName) ? file.getName() : fileName); + } else { + // office转pdf预览 + if (OpenOfficeUtil.canConverter(file.getName())) { + File pdfFile = OpenOfficeUtil.converterToPDF(file.getAbsolutePath(), pdfDir, officeHome); + if (pdfFile != null) { + file = pdfFile; + } + } + // 获取文件类型 + String contentType = getContentType(file); + if (contentType != null) { + response.setContentType(contentType); + // 设置编码 + if (contentType.startsWith("text/") || SET_CHARSET_CONTENT_TYPES.contains(contentType)) { + try { + String charset = JChardetFacadeUtil.detectCodepage(file.toURI().toURL()); + if (charset != null) { + response.setCharacterEncoding(charset); + } + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + } else { + setDownloadHeader(response, file.getName()); + } + } + response.setHeader("Cache-Control", "public"); + output(file, response, request); + } + + /** + * 查看缩略图 + * + * @param file 原文件 + * @param thumbnail 缩略图文件 + * @param size 缩略图文件的最大值(kb) + * @param response HttpServletResponse + * @param request HttpServletRequest + */ + public static void previewThumbnail(File file, File thumbnail, Integer size, + HttpServletResponse response, HttpServletRequest request) { + // 如果是图片并且缩略图不存在则生成 + if (!thumbnail.exists() && isImage(file)) { + long fileSize = file.length(); + if ((fileSize / 1024) > size) { + try { + if (thumbnail.getParentFile().mkdirs()) { + System.out.println("生成缩略图1>>>>>>>>>>>>>>>> = " + thumbnail); + ImgUtil.scale(file, thumbnail, size / (fileSize / 1024f)); + if (thumbnail.exists() && thumbnail.length() > file.length()) { + FileUtil.copy(file, thumbnail, true); + } + }else{ + System.out.println("生成缩略图2>>>>>>>>>>>>>>>> = " + thumbnail); + ImgUtil.scale(file, thumbnail, size / (fileSize / 1024f)); + if (thumbnail.exists() && thumbnail.length() > file.length()) { + FileUtil.copy(file, thumbnail, true); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } else { + preview(file, null, null, response, request); + return; + } + } + preview(thumbnail.exists() ? thumbnail : file, null, null, response, request); + } + + /** + * 输出文件流, 支持断点续传 + * + * @param file 文件 + * @param response HttpServletResponse + * @param request HttpServletRequest + */ + public static void output(File file, HttpServletResponse response, HttpServletRequest request) { + long length = file.length(); // 文件总大小 + long start = 0, to = length - 1; // 开始读取位置, 结束读取位置 + long lastModified = file.lastModified(); // 文件修改时间 + response.setHeader("Accept-Ranges", "bytes"); + response.setHeader("ETag", "\"" + length + "-" + lastModified + "\""); + response.setHeader("Last-Modified", new Date(lastModified).toString()); + String range = request.getHeader("Range"); + if (range != null) { + response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); + String[] ranges = range.replace("bytes=", "").split("-"); + start = Long.parseLong(ranges[0].trim()); + if (ranges.length > 1) { + to = Long.parseLong(ranges[1].trim()); + } + response.setHeader("Content-Range", "bytes " + start + "-" + to + "/" + length); + } + response.setHeader("Content-Length", String.valueOf(to - start + 1)); + try { + output(file, response.getOutputStream(), 2048, start, to); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 输出文件流 + * + * @param file 文件 + * @param os 输出流 + */ + public static void output(File file, OutputStream os) { + output(file, os, null); + } + + /** + * 输出文件流 + * + * @param file 文件 + * @param os 输出流 + * @param size 读取缓冲区大小 + */ + public static void output(File file, OutputStream os, Integer size) { + output(file, os, size, null, null); + } + + /** + * 输出文件流, 支持分片 + * + * @param file 文件 + * @param os 输出流 + * @param size 读取缓冲区大小 + * @param start 开始位置 + * @param to 结束位置 + */ + public static void output(File file, OutputStream os, Integer size, Long start, Long to) { + BufferedInputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(file)); + if (start != null) { + long skip = is.skip(start); + if (skip < start) { + System.out.println("ERROR: skip fail[ skipped=" + skip + ", start= " + start + " ]"); + } + to = to - start + 1; + } + byte[] bytes = new byte[size == null ? 2048 : size]; + int len; + if (to == null) { + while ((len = is.read(bytes)) != -1) { + os.write(bytes, 0, len); + } + } else { + while (to > 0 && (len = is.read(bytes)) != -1) { + os.write(bytes, 0, to < len ? (int) ((long) to) : len); + to -= len; + } + } + os.flush(); + } catch (IOException ignored) { + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (os != null) { + try { + os.close(); + } catch (IOException ignored) { + } + } + if (is != null) { + try { + is.close(); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } + } + } + + /** + * 获取文件类型 + * + * @param file 文件 + * @return String + */ + public static String getContentType(File file) { + String contentType = null; + if (file.exists()) { + try { + contentType = new Tika().detect(file); + } catch (IOException e) { + e.printStackTrace(); + } + } + return contentType; + } + + /** + * 判断文件是否是图片类型 + * + * @param file 文件 + * @return boolean + */ + public static boolean isImage(File file) { + return isImage(getContentType(file)); + } + + /** + * 判断文件是否是图片类型 + * + * @param contentType 文件类型 + * @return boolean + */ + public static boolean isImage(String contentType) { + return contentType != null && contentType.startsWith("image/"); + } + + /** + * 设置下载文件的header + * + * @param response HttpServletResponse + * @param fileName 文件名称 + */ + public static void setDownloadHeader(HttpServletResponse response, String fileName) { + response.setContentType("application/force-download"); + try { + fileName = URLEncoder.encode(fileName, "utf-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + response.setHeader("Content-Disposition", "attachment;fileName=" + fileName); + } + + /** + * 输出404错误页面 + * + * @param response HttpServletResponse + */ + public static void outNotFund(HttpServletResponse response) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + outMessage("404 Not Found", null, response); + } + + /** + * 输出错误页面 + * + * @param title 标题 + * @param message 内容 + * @param response HttpServletResponse + */ + public static void outMessage(String title, String message, HttpServletResponse response) { + response.setContentType("text/html;charset=UTF-8"); + try { + PrintWriter writer = response.getWriter(); + writer.write(""); + writer.write("" + title + ""); + writer.write("

" + title + "

"); + if (message != null) { + writer.write(message); + } + writer.write("

WebSoft File Server

"); + writer.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/HttpUtils.java b/src/main/java/com/gxwebsoft/common/core/utils/HttpUtils.java new file mode 100644 index 0000000..888acc2 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/HttpUtils.java @@ -0,0 +1,311 @@ +package com.gxwebsoft.common.core.utils; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.message.BasicNameValuePair; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class HttpUtils { + + /** + * get + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @return + * @throws Exception + */ + public static HttpResponse doGet(String host, String path, String method, + Map headers, + Map querys) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpGet request = new HttpGet(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + return httpClient.execute(request); + } + + /** + * post form + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param bodys + * @return + * @throws Exception + */ + public static HttpResponse doPost(String host, String path, String method, + Map headers, + Map querys, + Map bodys) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPost request = new HttpPost(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (bodys != null) { + List nameValuePairList = new ArrayList(); + + for (String key : bodys.keySet()) { + nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key))); + } + UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8"); + formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8"); + request.setEntity(formEntity); + } + + return httpClient.execute(request); + } + + /** + * Post String + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param body + * @return + * @throws Exception + */ + public static HttpResponse doPost(String host, String path, String method, + Map headers, + Map querys, + String body) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPost request = new HttpPost(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (StringUtils.isNotBlank(body)) { + request.setEntity(new StringEntity(body, "utf-8")); + } + + return httpClient.execute(request); + } + + /** + * Post stream + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param body + * @return + * @throws Exception + */ + public static HttpResponse doPost(String host, String path, String method, + Map headers, + Map querys, + byte[] body) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPost request = new HttpPost(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (body != null) { + request.setEntity(new ByteArrayEntity(body)); + } + + return httpClient.execute(request); + } + + /** + * Put String + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param body + * @return + * @throws Exception + */ + public static HttpResponse doPut(String host, String path, String method, + Map headers, + Map querys, + String body) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPut request = new HttpPut(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (StringUtils.isNotBlank(body)) { + request.setEntity(new StringEntity(body, "utf-8")); + } + + return httpClient.execute(request); + } + + /** + * Put stream + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param body + * @return + * @throws Exception + */ + public static HttpResponse doPut(String host, String path, String method, + Map headers, + Map querys, + byte[] body) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPut request = new HttpPut(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (body != null) { + request.setEntity(new ByteArrayEntity(body)); + } + + return httpClient.execute(request); + } + + /** + * Delete + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @return + * @throws Exception + */ + public static HttpResponse doDelete(String host, String path, String method, + Map headers, + Map querys) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpDelete request = new HttpDelete(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + return httpClient.execute(request); + } + + private static String buildUrl(String host, String path, Map querys) throws UnsupportedEncodingException { + StringBuilder sbUrl = new StringBuilder(); + sbUrl.append(host); + if (!StringUtils.isBlank(path)) { + sbUrl.append(path); + } + if (null != querys) { + StringBuilder sbQuery = new StringBuilder(); + for (Map.Entry query : querys.entrySet()) { + if (0 < sbQuery.length()) { + sbQuery.append("&"); + } + if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) { + sbQuery.append(query.getValue()); + } + if (!StringUtils.isBlank(query.getKey())) { + sbQuery.append(query.getKey()); + if (!StringUtils.isBlank(query.getValue())) { + sbQuery.append("="); + sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8")); + } + } + } + if (0 < sbQuery.length()) { + sbUrl.append("?").append(sbQuery); + } + } + + return sbUrl.toString(); + } + + private static HttpClient wrapClient(String host) { + HttpClient httpClient = new DefaultHttpClient(); + if (host.startsWith("https://")) { + sslClient(httpClient); + } + + return httpClient; + } + + private static void sslClient(HttpClient httpClient) { + try { + SSLContext ctx = SSLContext.getInstance("TLS"); + X509TrustManager tm = new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + public void checkClientTrusted(X509Certificate[] xcs, String str) { + + } + public void checkServerTrusted(X509Certificate[] xcs, String str) { + + } + }; + ctx.init(null, new TrustManager[] { tm }, null); + SSLSocketFactory ssf = new SSLSocketFactory(ctx); + ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + ClientConnectionManager ccm = httpClient.getConnectionManager(); + SchemeRegistry registry = ccm.getSchemeRegistry(); + registry.register(new Scheme("https", 443, ssf)); + } catch (KeyManagementException ex) { + throw new RuntimeException(ex); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/common/core/utils/ImageUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/ImageUtil.java new file mode 100644 index 0000000..b345923 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/ImageUtil.java @@ -0,0 +1,96 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.codec.Base64Encoder; + +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Iterator; +import java.io.File; + +public class ImageUtil { + public static String ImageBase64(String imgUrl) { + URL url = null; + InputStream is = null; + ByteArrayOutputStream outStream = null; + HttpURLConnection httpUrl = null; + try{ + url = new URL(imgUrl); + httpUrl = (HttpURLConnection) url.openConnection(); + httpUrl.connect(); + httpUrl.getInputStream(); + is = httpUrl.getInputStream(); + + outStream = new ByteArrayOutputStream(); + //创建一个Buffer字符串 + byte[] buffer = new byte[1024]; + //每次读取的字符串长度,如果为-1,代表全部读取完毕 + int len = 0; + //使用一个输入流从buffer里把数据读取出来 + while( (len=is.read(buffer)) != -1 ){ + //用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度 + outStream.write(buffer, 0, len); + } + // 对字节数组Base64编码 + return new Base64Encoder().encode(outStream.toByteArray()); + }catch (Exception e) { + e.printStackTrace(); + } + finally{ + if(is != null) { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(outStream != null) { + try { + outStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(httpUrl != null) { + httpUrl.disconnect(); + } + } + return null; + } + + + public static void adjustQuality(File inputFile, File outputFile, float quality) throws IOException { + // 读取图片文件 + BufferedImage image = ImageIO.read(inputFile); + + // 获取JPEG ImageWriters的迭代器 + Iterator iter = ImageIO.getImageWritersByFormatName("jpeg"); + ImageWriter writer = iter.next(); + + // 创建输出文件 + ImageOutputStream ios = ImageIO.createImageOutputStream(outputFile); + writer.setOutput(ios); + + // 创建ImageWriteParam并设置压缩质量 + ImageWriteParam iwp = writer.getDefaultWriteParam(); + if (iwp.canWriteCompressed()) { + iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + iwp.setCompressionQuality(quality); // 设置质量,1.0为最好,0.0最差 + } + + // 写入图片 + writer.write(null, new IIOImage(image, null, null), iwp); + writer.dispose(); + ios.close(); + } + +} + diff --git a/src/main/java/com/gxwebsoft/common/core/utils/JChardetFacadeUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/JChardetFacadeUtil.java new file mode 100644 index 0000000..1b49fb7 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/JChardetFacadeUtil.java @@ -0,0 +1,2025 @@ +package com.gxwebsoft.common.core.utils; + +import java.io.*; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; + +/** + * 文件编码检测工具, 核心代码来自 cpDetector 和 jChardet, 可以检测大多数文件的编码 + * + * @author WebSoft + * @since 2020-09-15 09:24:20 + */ +public class JChardetFacadeUtil { + + public static String detectCodepage(URL url) { + try { + Charset ret = JChardetFacade.getInstance().detectCodepage(url); + return ret == null ? null : ret.name(); + } catch (Exception ignored) { + } + return null; + } + + /** + * 下面代码来自: https://github.com/r91987/cpdetector + */ + public static class JChardetFacade extends AbstractCodepageDetector implements nsICharsetDetectionObserver { + private static JChardetFacade instance = null; + private static nsDetector det; + private byte[] buf = new byte[4096]; + private Charset codpage = null; + private boolean m_guessing = true; + private int amountOfVerifiers = 0; + + private JChardetFacade() { + det = new nsDetector(0); + det.Init(this); + this.amountOfVerifiers = det.getProbableCharsets().length; + } + + public static JChardetFacade getInstance() { + if (instance == null) { + instance = new JChardetFacade(); + } + + return instance; + } + + public synchronized Charset detectCodepage(InputStream in, int length) throws IOException { + this.Reset(); + int read = 0; + boolean done = false; + boolean isAscii = true; + Charset ret = null; + + int len; + do { + len = in.read(this.buf, 0, Math.min(this.buf.length, length - read)); + if (len > 0) { + read += len; + } + + if (!done) { + done = det.DoIt(this.buf, len, false); + } + } while (len > 0 && !done); + + det.DataEnd(); + if (this.codpage == null) { + if (this.m_guessing) { + ret = this.guess(); + } + } else { + ret = this.codpage; + } + return ret; + } + + private Charset guess() { + Charset ret = null; + String[] possibilities = det.getProbableCharsets(); + if (possibilities.length == this.amountOfVerifiers) { + ret = Charset.forName("US-ASCII"); + } else { + String check = possibilities[0]; + if (!check.equalsIgnoreCase("nomatch")) { + for (int i = 0; ret == null && i < possibilities.length; ++i) { + try { + ret = Charset.forName(possibilities[i]); + } catch (UnsupportedCharsetException ignored) { + } + } + } + } + return ret; + } + + public void Notify(String charset) { + this.codpage = Charset.forName(charset); + } + + public void Reset() { + det.Reset(); + this.codpage = null; + } + + public boolean isGuessing() { + return this.m_guessing; + } + + public synchronized void setGuessing(boolean guessing) { + this.m_guessing = guessing; + } + } + + /** + * + */ + public static abstract class AbstractCodepageDetector implements ICodepageDetector { + public AbstractCodepageDetector() { + } + + public Charset detectCodepage(URL url) throws IOException { + BufferedInputStream in = new BufferedInputStream(url.openStream()); + Charset result = this.detectCodepage(in, 2147483647); + in.close(); + return result; + } + + public final Reader open(URL url) throws IOException { + Reader ret = null; + Charset cs = this.detectCodepage(url); + if (cs != null) { + ret = new InputStreamReader(new BufferedInputStream(url.openStream()), cs); + } + + return ret; + } + + public int compareTo(Object o) { + String other = o.getClass().getName(); + String mine = this.getClass().getName(); + return mine.compareTo(other); + } + } + + /** + * + */ + interface ICodepageDetector extends Serializable, Comparable { + Reader open(URL var1) throws IOException; + + Charset detectCodepage(URL var1) throws IOException; + + Charset detectCodepage(InputStream var1, int var2) throws IOException; + } + + /** + * 以下代码开始是由Mozilla组织提供的JChardet, 它可以检测大多数文件的编码 + * http://jchardet.sourceforge.net/ + */ + public static class nsDetector extends nsPSMDetector implements nsICharsetDetector { + nsICharsetDetectionObserver mObserver = null; + + public nsDetector() { + } + + public nsDetector(int var1) { + super(var1); + } + + public void Init(nsICharsetDetectionObserver var1) { + this.mObserver = var1; + } + + public boolean DoIt(byte[] var1, int var2, boolean var3) { + if (var1 != null && !var3) { + this.HandleData(var1, var2); + return this.mDone; + } else { + return false; + } + } + + public void Done() { + this.DataEnd(); + } + + public void Report(String var1) { + if (this.mObserver != null) { + this.mObserver.Notify(var1); + } + + } + + public boolean isAscii(byte[] var1, int var2) { + for (int var3 = 0; var3 < var2; ++var3) { + if ((128 & var1[var3]) != 0) { + return false; + } + } + + return true; + } + } + + /** + * + */ + public static abstract class nsPSMDetector { + public static final int ALL = 0; + public static final int JAPANESE = 1; + public static final int CHINESE = 2; + public static final int SIMPLIFIED_CHINESE = 3; + public static final int TRADITIONAL_CHINESE = 4; + public static final int KOREAN = 5; + public static final int NO_OF_LANGUAGES = 6; + public static final int MAX_VERIFIERS = 16; + nsVerifier[] mVerifier; + nsEUCStatistics[] mStatisticsData; + nsEUCSampler mSampler = new nsEUCSampler(); + byte[] mState = new byte[16]; + int[] mItemIdx = new int[16]; + int mItems; + int mClassItems; + boolean mDone; + boolean mRunSampler; + boolean mClassRunSampler; + + public nsPSMDetector() { + this.initVerifiers(0); + this.Reset(); + } + + public nsPSMDetector(int var1) { + this.initVerifiers(var1); + this.Reset(); + } + + public nsPSMDetector(int var1, nsVerifier[] var2, nsEUCStatistics[] var3) { + this.mClassRunSampler = var3 != null; + this.mStatisticsData = var3; + this.mVerifier = var2; + this.mClassItems = var1; + this.Reset(); + } + + public void Reset() { + this.mRunSampler = this.mClassRunSampler; + this.mDone = false; + this.mItems = this.mClassItems; + + for (int var1 = 0; var1 < this.mItems; this.mItemIdx[var1] = var1++) { + this.mState[var1] = 0; + } + + this.mSampler.Reset(); + } + + protected void initVerifiers(int var1) { + boolean var2 = false; + int var3; + if (var1 >= 0 && var1 < 6) { + var3 = var1; + } else { + var3 = 0; + } + + this.mVerifier = null; + this.mStatisticsData = null; + if (var3 == 4) { + this.mVerifier = new nsVerifier[]{new nsUTF8Verifier(), new nsBIG5Verifier(), new nsISO2022CNVerifier(), new nsEUCTWVerifier(), new nsCP1252Verifier(), new nsUCS2BEVerifier(), new nsUCS2LEVerifier()}; + this.mStatisticsData = new nsEUCStatistics[]{null, new Big5Statistics(), null, new EUCTWStatistics(), null, null, null}; + } else if (var3 == 5) { + this.mVerifier = new nsVerifier[]{new nsUTF8Verifier(), new nsEUCKRVerifier(), new nsISO2022KRVerifier(), new nsCP1252Verifier(), new nsUCS2BEVerifier(), new nsUCS2LEVerifier()}; + } else if (var3 == 3) { + this.mVerifier = new nsVerifier[]{new nsUTF8Verifier(), new nsGB2312Verifier(), new nsGB18030Verifier(), new nsISO2022CNVerifier(), new nsHZVerifier(), new nsCP1252Verifier(), new nsUCS2BEVerifier(), new nsUCS2LEVerifier()}; + } else if (var3 == 1) { + this.mVerifier = new nsVerifier[]{new nsUTF8Verifier(), new nsSJISVerifier(), new nsEUCJPVerifier(), new nsISO2022JPVerifier(), new nsCP1252Verifier(), new nsUCS2BEVerifier(), new nsUCS2LEVerifier()}; + } else if (var3 == 2) { + this.mVerifier = new nsVerifier[]{new nsUTF8Verifier(), new nsGB2312Verifier(), new nsGB18030Verifier(), new nsBIG5Verifier(), new nsISO2022CNVerifier(), new nsHZVerifier(), new nsEUCTWVerifier(), new nsCP1252Verifier(), new nsUCS2BEVerifier(), new nsUCS2LEVerifier()}; + this.mStatisticsData = new nsEUCStatistics[]{null, new GB2312Statistics(), null, new Big5Statistics(), null, null, new EUCTWStatistics(), null, null, null}; + } else if (var3 == 0) { + this.mVerifier = new nsVerifier[]{new nsUTF8Verifier(), new nsSJISVerifier(), new nsEUCJPVerifier(), new nsISO2022JPVerifier(), new nsEUCKRVerifier(), new nsISO2022KRVerifier(), new nsBIG5Verifier(), new nsEUCTWVerifier(), new nsGB2312Verifier(), new nsGB18030Verifier(), new nsISO2022CNVerifier(), new nsHZVerifier(), new nsCP1252Verifier(), new nsUCS2BEVerifier(), new nsUCS2LEVerifier()}; + this.mStatisticsData = new nsEUCStatistics[]{null, null, new EUCJPStatistics(), null, new EUCKRStatistics(), null, new Big5Statistics(), new EUCTWStatistics(), new GB2312Statistics(), null, null, null, null, null, null}; + } + + this.mClassRunSampler = this.mStatisticsData != null; + this.mClassItems = this.mVerifier.length; + } + + public abstract void Report(String var1); + + public boolean HandleData(byte[] var1, int var2) { + for (int var3 = 0; var3 < var2; ++var3) { + byte var5 = var1[var3]; + int var4 = 0; + + while (var4 < this.mItems) { + byte var6 = nsVerifier.getNextState(this.mVerifier[this.mItemIdx[var4]], var5, this.mState[var4]); + if (var6 == 2) { + this.Report(this.mVerifier[this.mItemIdx[var4]].charset()); + this.mDone = true; + return this.mDone; + } + + if (var6 == 1) { + --this.mItems; + if (var4 < this.mItems) { + this.mItemIdx[var4] = this.mItemIdx[this.mItems]; + this.mState[var4] = this.mState[this.mItems]; + } + } else { + this.mState[var4++] = var6; + } + } + + if (this.mItems <= 1) { + if (1 == this.mItems) { + this.Report(this.mVerifier[this.mItemIdx[0]].charset()); + } + + this.mDone = true; + return this.mDone; + } + + int var7 = 0; + int var8 = 0; + + for (var4 = 0; var4 < this.mItems; ++var4) { + if (!this.mVerifier[this.mItemIdx[var4]].isUCS2() && !this.mVerifier[this.mItemIdx[var4]].isUCS2()) { + ++var7; + var8 = var4; + } + } + + if (1 == var7) { + this.Report(this.mVerifier[this.mItemIdx[var8]].charset()); + this.mDone = true; + return this.mDone; + } + } + + if (this.mRunSampler) { + this.Sample(var1, var2); + } + + return this.mDone; + } + + public void DataEnd() { + if (!this.mDone) { + if (this.mItems == 2) { + if (this.mVerifier[this.mItemIdx[0]].charset().equals("GB18030")) { + this.Report(this.mVerifier[this.mItemIdx[1]].charset()); + this.mDone = true; + } else if (this.mVerifier[this.mItemIdx[1]].charset().equals("GB18030")) { + this.Report(this.mVerifier[this.mItemIdx[0]].charset()); + this.mDone = true; + } + } + + if (this.mRunSampler) { + this.Sample((byte[]) null, 0, true); + } + + } + } + + public void Sample(byte[] var1, int var2) { + this.Sample(var1, var2, false); + } + + public void Sample(byte[] var1, int var2, boolean var3) { + int var4 = 0; + int var6 = 0; + + int var5; + for (var5 = 0; var5 < this.mItems; ++var5) { + if (null != this.mStatisticsData[this.mItemIdx[var5]]) { + ++var6; + } + + if (!this.mVerifier[this.mItemIdx[var5]].isUCS2() && !this.mVerifier[this.mItemIdx[var5]].charset().equals("GB18030")) { + ++var4; + } + } + + this.mRunSampler = var6 > 1; + if (this.mRunSampler) { + this.mRunSampler = this.mSampler.Sample(var1, var2); + if ((var3 && this.mSampler.GetSomeData() || this.mSampler.EnoughData()) && var6 == var4) { + this.mSampler.CalFreq(); + int var7 = -1; + int var8 = 0; + float var9 = 0.0F; + + for (var5 = 0; var5 < this.mItems; ++var5) { + if (null != this.mStatisticsData[this.mItemIdx[var5]] && !this.mVerifier[this.mItemIdx[var5]].charset().equals("Big5")) { + float var10 = this.mSampler.GetScore(this.mStatisticsData[this.mItemIdx[var5]].mFirstByteFreq(), this.mStatisticsData[this.mItemIdx[var5]].mFirstByteWeight(), this.mStatisticsData[this.mItemIdx[var5]].mSecondByteFreq(), this.mStatisticsData[this.mItemIdx[var5]].mSecondByteWeight()); + if (0 == var8++ || var9 > var10) { + var9 = var10; + var7 = var5; + } + } + } + + if (var7 >= 0) { + this.Report(this.mVerifier[this.mItemIdx[var7]].charset()); + this.mDone = true; + } + } + } + + } + + public String[] getProbableCharsets() { + String[] var1; + if (this.mItems <= 0) { + var1 = new String[]{"nomatch"}; + return var1; + } else { + var1 = new String[this.mItems]; + + for (int var2 = 0; var2 < this.mItems; ++var2) { + var1[var2] = this.mVerifier[this.mItemIdx[var2]].charset(); + } + + return var1; + } + } + } + + /** + * + */ + public static interface nsICharsetDetectionObserver { + void Notify(String var1); + } + + /** + * + */ + public static interface nsICharsetDetector { + void Init(nsICharsetDetectionObserver var1); + + boolean DoIt(byte[] var1, int var2, boolean var3); + + void Done(); + } + + /** + * + */ + public static abstract class nsVerifier { + static final byte eStart = 0; + static final byte eError = 1; + static final byte eItsMe = 2; + static final int eidxSft4bits = 3; + static final int eSftMsk4bits = 7; + static final int eBitSft4bits = 2; + static final int eUnitMsk4bits = 15; + + nsVerifier() { + } + + public abstract String charset(); + + public abstract int stFactor(); + + public abstract int[] cclass(); + + public abstract int[] states(); + + public abstract boolean isUCS2(); + + public static byte getNextState(nsVerifier var0, byte var1, byte var2) { + return (byte) (255 & var0.states()[(var2 * var0.stFactor() + (var0.cclass()[(var1 & 255) >> 3] >> ((var1 & 7) << 2) & 15) & 255) >> 3] >> ((var2 * var0.stFactor() + (var0.cclass()[(var1 & 255) >> 3] >> ((var1 & 7) << 2) & 15) & 255 & 7) << 2) & 15); + } + } + + /** + * + */ + public static class nsEUCSampler { + int mTotal = 0; + int mThreshold = 200; + int mState = 0; + public int[] mFirstByteCnt = new int[94]; + public int[] mSecondByteCnt = new int[94]; + public float[] mFirstByteFreq = new float[94]; + public float[] mSecondByteFreq = new float[94]; + + public nsEUCSampler() { + this.Reset(); + } + + public void Reset() { + this.mTotal = 0; + this.mState = 0; + + for (int var1 = 0; var1 < 94; ++var1) { + this.mFirstByteCnt[var1] = this.mSecondByteCnt[var1] = 0; + } + + } + + boolean EnoughData() { + return this.mTotal > this.mThreshold; + } + + boolean GetSomeData() { + return this.mTotal > 1; + } + + boolean Sample(byte[] var1, int var2) { + if (this.mState == 1) { + return false; + } else { + int var3 = 0; + + for (int var4 = 0; var4 < var2 && 1 != this.mState; ++var3) { + int var10002; + switch (this.mState) { + case 0: + if ((var1[var3] & 128) != 0) { + if (255 != (255 & var1[var3]) && 161 <= (255 & var1[var3])) { + ++this.mTotal; + var10002 = this.mFirstByteCnt[(255 & var1[var3]) - 161]++; + this.mState = 2; + } else { + this.mState = 1; + } + } + case 1: + break; + case 2: + if ((var1[var3] & 128) != 0) { + if (255 != (255 & var1[var3]) && 161 <= (255 & var1[var3])) { + ++this.mTotal; + var10002 = this.mSecondByteCnt[(255 & var1[var3]) - 161]++; + this.mState = 0; + } else { + this.mState = 1; + } + } else { + this.mState = 1; + } + break; + default: + this.mState = 1; + } + + ++var4; + } + + return 1 != this.mState; + } + } + + void CalFreq() { + for (int var1 = 0; var1 < 94; ++var1) { + this.mFirstByteFreq[var1] = (float) this.mFirstByteCnt[var1] / (float) this.mTotal; + this.mSecondByteFreq[var1] = (float) this.mSecondByteCnt[var1] / (float) this.mTotal; + } + + } + + float GetScore(float[] var1, float var2, float[] var3, float var4) { + return var2 * this.GetScore(var1, this.mFirstByteFreq) + var4 * this.GetScore(var3, this.mSecondByteFreq); + } + + float GetScore(float[] var1, float[] var2) { + float var4 = 0.0F; + + for (int var5 = 0; var5 < 94; ++var5) { + float var3 = var1[var5] - var2[var5]; + var4 += var3 * var3; + } + + return (float) Math.sqrt((double) var4) / 94.0F; + } + } + + /** + * + */ + public static abstract class nsEUCStatistics { + public abstract float[] mFirstByteFreq(); + + public abstract float mFirstByteStdDev(); + + public abstract float mFirstByteMean(); + + public abstract float mFirstByteWeight(); + + public abstract float[] mSecondByteFreq(); + + public abstract float mSecondByteStdDev(); + + public abstract float mSecondByteMean(); + + public abstract float mSecondByteWeight(); + + public nsEUCStatistics() { + } + } + + /** + * + */ + public static class EUCJPStatistics extends nsEUCStatistics { + static float[] mFirstByteFreq; + static float mFirstByteStdDev; + static float mFirstByteMean; + static float mFirstByteWeight; + static float[] mSecondByteFreq; + static float mSecondByteStdDev; + static float mSecondByteMean; + static float mSecondByteWeight; + + public float[] mFirstByteFreq() { + return mFirstByteFreq; + } + + public float mFirstByteStdDev() { + return mFirstByteStdDev; + } + + public float mFirstByteMean() { + return mFirstByteMean; + } + + public float mFirstByteWeight() { + return mFirstByteWeight; + } + + public float[] mSecondByteFreq() { + return mSecondByteFreq; + } + + public float mSecondByteStdDev() { + return mSecondByteStdDev; + } + + public float mSecondByteMean() { + return mSecondByteMean; + } + + public float mSecondByteWeight() { + return mSecondByteWeight; + } + + public EUCJPStatistics() { + mFirstByteFreq = new float[]{0.364808F, 0.0F, 0.0F, 0.145325F, 0.304891F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.001835F, 0.010771F, 0.006462F, 0.001157F, 0.002114F, 0.003231F, 0.001356F, 0.00742F, 0.004189F, 0.003231F, 0.003032F, 0.03319F, 0.006303F, 0.006064F, 0.009973F, 0.002354F, 0.00367F, 0.009135F, 0.001675F, 0.002792F, 0.002194F, 0.01472F, 0.011928F, 8.78E-4F, 0.013124F, 0.001077F, 0.009295F, 0.003471F, 0.002872F, 0.002433F, 9.57E-4F, 0.001636F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 8.0E-5F, 2.79E-4F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 8.0E-5F, 0.0F}; + mFirstByteStdDev = 0.050407F; + mFirstByteMean = 0.010638F; + mFirstByteWeight = 0.640871F; + mSecondByteFreq = new float[]{0.002473F, 0.039134F, 0.152745F, 0.009694F, 3.59E-4F, 0.02218F, 7.58E-4F, 0.004308F, 1.6E-4F, 0.002513F, 0.003072F, 0.001316F, 0.00383F, 0.001037F, 0.00359F, 9.57E-4F, 1.6E-4F, 2.39E-4F, 0.006462F, 0.001596F, 0.031554F, 0.001316F, 0.002194F, 0.016555F, 0.003271F, 6.78E-4F, 5.98E-4F, 0.206438F, 7.18E-4F, 0.001077F, 0.00371F, 0.001356F, 0.001356F, 4.39E-4F, 0.004388F, 0.005704F, 8.78E-4F, 0.010172F, 0.007061F, 0.01468F, 6.38E-4F, 0.02573F, 0.002792F, 7.18E-4F, 0.001795F, 0.091551F, 7.58E-4F, 0.003909F, 5.58E-4F, 0.031195F, 0.007061F, 0.001316F, 0.022579F, 0.006981F, 0.00726F, 0.001117F, 2.39E-4F, 0.012127F, 8.78E-4F, 0.00379F, 0.001077F, 7.58E-4F, 0.002114F, 0.002234F, 6.78E-4F, 0.002992F, 0.003311F, 0.023416F, 0.001237F, 0.002753F, 0.005146F, 0.002194F, 0.007021F, 0.008497F, 0.013763F, 0.011768F, 0.006303F, 0.001915F, 6.38E-4F, 0.008776F, 9.18E-4F, 0.003431F, 0.057603F, 4.39E-4F, 4.39E-4F, 7.58E-4F, 0.002872F, 0.001675F, 0.01105F, 0.0F, 2.79E-4F, 0.012127F, 7.18E-4F, 0.00738F}; + mSecondByteStdDev = 0.028247F; + mSecondByteMean = 0.010638F; + mSecondByteWeight = 0.359129F; + } + } + + /** + * + */ + public static class nsEUCJPVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsEUCJPVerifier() { + cclass = new int[32]; + cclass[0] = 1145324612; + cclass[1] = 1430537284; + cclass[2] = 1145324612; + cclass[3] = 1145328708; + cclass[4] = 1145324612; + cclass[5] = 1145324612; + cclass[6] = 1145324612; + cclass[7] = 1145324612; + cclass[8] = 1145324612; + cclass[9] = 1145324612; + cclass[10] = 1145324612; + cclass[11] = 1145324612; + cclass[12] = 1145324612; + cclass[13] = 1145324612; + cclass[14] = 1145324612; + cclass[15] = 1145324612; + cclass[16] = 1431655765; + cclass[17] = 827675989; + cclass[18] = 1431655765; + cclass[19] = 1431655765; + cclass[20] = 572662309; + cclass[21] = 572662306; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662306; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 0; + cclass[29] = 0; + cclass[30] = 0; + cclass[31] = 1342177280; + states = new int[5]; + states[0] = 286282563; + states[1] = 572657937; + states[2] = 286265378; + states[3] = 319885329; + states[4] = 4371; + charset = "EUC-JP"; + stFactor = 6; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class EUCKRStatistics extends nsEUCStatistics { + static float[] mFirstByteFreq; + static float mFirstByteStdDev; + static float mFirstByteMean; + static float mFirstByteWeight; + static float[] mSecondByteFreq; + static float mSecondByteStdDev; + static float mSecondByteMean; + static float mSecondByteWeight; + + public float[] mFirstByteFreq() { + return mFirstByteFreq; + } + + public float mFirstByteStdDev() { + return mFirstByteStdDev; + } + + public float mFirstByteMean() { + return mFirstByteMean; + } + + public float mFirstByteWeight() { + return mFirstByteWeight; + } + + public float[] mSecondByteFreq() { + return mSecondByteFreq; + } + + public float mSecondByteStdDev() { + return mSecondByteStdDev; + } + + public float mSecondByteMean() { + return mSecondByteMean; + } + + public float mSecondByteWeight() { + return mSecondByteWeight; + } + + public EUCKRStatistics() { + mFirstByteFreq = new float[]{0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 4.12E-4F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.057502F, 0.033182F, 0.002267F, 0.016076F, 0.014633F, 0.032976F, 0.004122F, 0.011336F, 0.058533F, 0.024526F, 0.025969F, 0.054411F, 0.01958F, 0.063273F, 0.113974F, 0.029885F, 0.150041F, 0.059151F, 0.002679F, 0.009893F, 0.014839F, 0.026381F, 0.015045F, 0.069456F, 0.08986F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F}; + mFirstByteStdDev = 0.025593F; + mFirstByteMean = 0.010638F; + mFirstByteWeight = 0.647437F; + mSecondByteFreq = new float[]{0.016694F, 0.0F, 0.012778F, 0.030091F, 0.002679F, 0.006595F, 0.001855F, 8.24E-4F, 0.005977F, 0.00474F, 0.003092F, 8.24E-4F, 0.01958F, 0.037304F, 0.008244F, 0.014633F, 0.001031F, 0.0F, 0.003298F, 0.002061F, 0.006183F, 0.005977F, 8.24E-4F, 0.021847F, 0.014839F, 0.052968F, 0.017312F, 0.007626F, 4.12E-4F, 8.24E-4F, 0.011129F, 0.0F, 4.12E-4F, 0.001649F, 0.005977F, 0.065746F, 0.020198F, 0.021434F, 0.014633F, 0.004122F, 0.001649F, 8.24E-4F, 8.24E-4F, 0.051937F, 0.01958F, 0.023289F, 0.026381F, 0.040396F, 0.009068F, 0.001443F, 0.00371F, 0.00742F, 0.001443F, 0.01319F, 0.002885F, 4.12E-4F, 0.003298F, 0.025969F, 4.12E-4F, 4.12E-4F, 0.006183F, 0.003298F, 0.066983F, 0.002679F, 0.002267F, 0.011129F, 4.12E-4F, 0.010099F, 0.015251F, 0.007626F, 0.043899F, 0.00371F, 0.002679F, 0.001443F, 0.010923F, 0.002885F, 0.009068F, 0.019992F, 4.12E-4F, 0.00845F, 0.005153F, 0.0F, 0.010099F, 0.0F, 0.001649F, 0.01216F, 0.011542F, 0.006595F, 0.001855F, 0.010923F, 4.12E-4F, 0.023702F, 0.00371F, 0.001855F}; + mSecondByteStdDev = 0.013937F; + mSecondByteMean = 0.010638F; + mSecondByteWeight = 0.352563F; + } + } + + /** + * + */ + public static class nsEUCKRVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsEUCKRVerifier() { + cclass = new int[32]; + cclass[0] = 286331153; + cclass[1] = 1118481; + cclass[2] = 286331153; + cclass[3] = 286327057; + cclass[4] = 286331153; + cclass[5] = 286331153; + cclass[6] = 286331153; + cclass[7] = 286331153; + cclass[8] = 286331153; + cclass[9] = 286331153; + cclass[10] = 286331153; + cclass[11] = 286331153; + cclass[12] = 286331153; + cclass[13] = 286331153; + cclass[14] = 286331153; + cclass[15] = 286331153; + cclass[16] = 0; + cclass[17] = 0; + cclass[18] = 0; + cclass[19] = 0; + cclass[20] = 572662304; + cclass[21] = 858923554; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662322; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 572662306; + cclass[29] = 572662306; + cclass[30] = 572662306; + cclass[31] = 35791394; + states = new int[2]; + states[0] = 286331649; + states[1] = 1122850; + charset = "EUC-KR"; + stFactor = 4; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class EUCTWStatistics extends nsEUCStatistics { + static float[] mFirstByteFreq; + static float mFirstByteStdDev; + static float mFirstByteMean; + static float mFirstByteWeight; + static float[] mSecondByteFreq; + static float mSecondByteStdDev; + static float mSecondByteMean; + static float mSecondByteWeight; + + public float[] mFirstByteFreq() { + return mFirstByteFreq; + } + + public float mFirstByteStdDev() { + return mFirstByteStdDev; + } + + public float mFirstByteMean() { + return mFirstByteMean; + } + + public float mFirstByteWeight() { + return mFirstByteWeight; + } + + public float[] mSecondByteFreq() { + return mSecondByteFreq; + } + + public float mSecondByteStdDev() { + return mSecondByteStdDev; + } + + public float mSecondByteMean() { + return mSecondByteMean; + } + + public float mSecondByteWeight() { + return mSecondByteWeight; + } + + public EUCTWStatistics() { + mFirstByteFreq = new float[]{0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.119286F, 0.052233F, 0.044126F, 0.052494F, 0.045906F, 0.019038F, 0.032465F, 0.026252F, 0.025502F, 0.015963F, 0.052493F, 0.019256F, 0.015137F, 0.031782F, 0.01737F, 0.018494F, 0.015575F, 0.016621F, 0.007444F, 0.011642F, 0.013916F, 0.019159F, 0.016445F, 0.007851F, 0.011079F, 0.022842F, 0.015513F, 0.010033F, 0.00995F, 0.010347F, 0.013103F, 0.015371F, 0.012502F, 0.007436F, 0.018253F, 0.014134F, 0.008907F, 0.005411F, 0.00957F, 0.013598F, 0.006092F, 0.007409F, 0.008432F, 0.005816F, 0.009349F, 0.005472F, 0.00717F, 0.00742F, 0.003681F, 0.007523F, 0.00461F, 0.006154F, 0.003348F, 0.005074F, 0.005922F, 0.005254F, 0.004682F, 0.002093F, 0.0F}; + mFirstByteStdDev = 0.016681F; + mFirstByteMean = 0.010638F; + mFirstByteWeight = 0.715599F; + mSecondByteFreq = new float[]{0.028933F, 0.011371F, 0.011053F, 0.007232F, 0.010192F, 0.004093F, 0.015043F, 0.011752F, 0.022387F, 0.00841F, 0.012448F, 0.007473F, 0.003594F, 0.007139F, 0.018912F, 0.006083F, 0.003302F, 0.010215F, 0.008791F, 0.024236F, 0.014107F, 0.014108F, 0.010303F, 0.009728F, 0.007877F, 0.009719F, 0.007952F, 0.021028F, 0.005764F, 0.009341F, 0.006591F, 0.012517F, 0.005921F, 0.008982F, 0.008771F, 0.012802F, 0.005926F, 0.008342F, 0.003086F, 0.006843F, 0.007576F, 0.004734F, 0.016404F, 0.008803F, 0.008071F, 0.005349F, 0.008566F, 0.01084F, 0.015401F, 0.031904F, 0.00867F, 0.011479F, 0.010936F, 0.007617F, 0.008995F, 0.008114F, 0.008658F, 0.005934F, 0.010452F, 0.009142F, 0.004519F, 0.008339F, 0.007476F, 0.007027F, 0.006025F, 0.021804F, 0.024248F, 0.015895F, 0.003768F, 0.010171F, 0.010007F, 0.010178F, 0.008316F, 0.006832F, 0.006364F, 0.009141F, 0.009148F, 0.012081F, 0.011914F, 0.004464F, 0.014257F, 0.006907F, 0.011292F, 0.018622F, 0.008149F, 0.004636F, 0.006612F, 0.013478F, 0.012614F, 0.005186F, 0.048285F, 0.006816F, 0.006743F, 0.008671F}; + mSecondByteStdDev = 0.00663F; + mSecondByteMean = 0.010638F; + mSecondByteWeight = 0.284401F; + } + } + + /** + * + */ + public static class nsEUCTWVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsEUCTWVerifier() { + cclass = new int[32]; + cclass[0] = 572662306; + cclass[1] = 2236962; + cclass[2] = 572662306; + cclass[3] = 572654114; + cclass[4] = 572662306; + cclass[5] = 572662306; + cclass[6] = 572662306; + cclass[7] = 572662306; + cclass[8] = 572662306; + cclass[9] = 572662306; + cclass[10] = 572662306; + cclass[11] = 572662306; + cclass[12] = 572662306; + cclass[13] = 572662306; + cclass[14] = 572662306; + cclass[15] = 572662306; + cclass[16] = 0; + cclass[17] = 100663296; + cclass[18] = 0; + cclass[19] = 0; + cclass[20] = 1145324592; + cclass[21] = 286331221; + cclass[22] = 286331153; + cclass[23] = 286331153; + cclass[24] = 858985233; + cclass[25] = 858993459; + cclass[26] = 858993459; + cclass[27] = 858993459; + cclass[28] = 858993459; + cclass[29] = 858993459; + cclass[30] = 858993459; + cclass[31] = 53687091; + states = new int[6]; + states[0] = 338898961; + states[1] = 571543825; + states[2] = 269623842; + states[3] = 286330880; + states[4] = 1052949; + states[5] = 16; + charset = "x-euc-tw"; + stFactor = 7; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class Big5Statistics extends nsEUCStatistics { + static float[] mFirstByteFreq; + static float mFirstByteStdDev; + static float mFirstByteMean; + static float mFirstByteWeight; + static float[] mSecondByteFreq; + static float mSecondByteStdDev; + static float mSecondByteMean; + static float mSecondByteWeight; + + public float[] mFirstByteFreq() { + return mFirstByteFreq; + } + + public float mFirstByteStdDev() { + return mFirstByteStdDev; + } + + public float mFirstByteMean() { + return mFirstByteMean; + } + + public float mFirstByteWeight() { + return mFirstByteWeight; + } + + public float[] mSecondByteFreq() { + return mSecondByteFreq; + } + + public float mSecondByteStdDev() { + return mSecondByteStdDev; + } + + public float mSecondByteMean() { + return mSecondByteMean; + } + + public float mSecondByteWeight() { + return mSecondByteWeight; + } + + public Big5Statistics() { + mFirstByteFreq = new float[]{0.0F, 0.0F, 0.0F, 0.114427F, 0.061058F, 0.075598F, 0.048386F, 0.063966F, 0.027094F, 0.095787F, 0.029525F, 0.031331F, 0.036915F, 0.021805F, 0.019349F, 0.037496F, 0.018068F, 0.01276F, 0.030053F, 0.017339F, 0.016731F, 0.019501F, 0.01124F, 0.032973F, 0.016658F, 0.015872F, 0.021458F, 0.012378F, 0.017003F, 0.020802F, 0.012454F, 0.009239F, 0.012829F, 0.007922F, 0.010079F, 0.009815F, 0.010104F, 0.0F, 0.0F, 0.0F, 5.3E-5F, 3.5E-5F, 1.05E-4F, 3.1E-5F, 8.8E-5F, 2.7E-5F, 2.7E-5F, 2.6E-5F, 3.5E-5F, 2.4E-5F, 3.4E-5F, 3.75E-4F, 2.5E-5F, 2.8E-5F, 2.0E-5F, 2.4E-5F, 2.8E-5F, 3.1E-5F, 5.9E-5F, 4.0E-5F, 3.0E-5F, 7.9E-5F, 3.7E-5F, 4.0E-5F, 2.3E-5F, 3.0E-5F, 2.7E-5F, 6.4E-5F, 2.0E-5F, 2.7E-5F, 2.5E-5F, 7.4E-5F, 1.9E-5F, 2.3E-5F, 2.1E-5F, 1.8E-5F, 1.7E-5F, 3.5E-5F, 2.1E-5F, 1.9E-5F, 2.5E-5F, 1.7E-5F, 3.7E-5F, 1.8E-5F, 1.8E-5F, 1.9E-5F, 2.2E-5F, 3.3E-5F, 3.2E-5F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F}; + mFirstByteStdDev = 0.020606F; + mFirstByteMean = 0.010638F; + mFirstByteWeight = 0.675261F; + mSecondByteFreq = new float[]{0.020256F, 0.003293F, 0.045811F, 0.01665F, 0.007066F, 0.004146F, 0.009229F, 0.007333F, 0.003296F, 0.005239F, 0.008282F, 0.003791F, 0.006116F, 0.003536F, 0.004024F, 0.016654F, 0.009334F, 0.005429F, 0.033392F, 0.006121F, 0.008983F, 0.002801F, 0.004221F, 0.010357F, 0.014695F, 0.077937F, 0.006314F, 0.00402F, 0.007331F, 0.00715F, 0.005341F, 0.009195F, 0.00535F, 0.005698F, 0.004472F, 0.007242F, 0.004039F, 0.011154F, 0.016184F, 0.004741F, 0.012814F, 0.007679F, 0.008045F, 0.016631F, 0.009451F, 0.016487F, 0.007287F, 0.012688F, 0.017421F, 0.013205F, 0.03148F, 0.003404F, 0.009149F, 0.008921F, 0.007514F, 0.008683F, 0.008203F, 0.031403F, 0.011733F, 0.015617F, 0.015306F, 0.004004F, 0.010899F, 0.009961F, 0.008388F, 0.01092F, 0.003925F, 0.008585F, 0.009108F, 0.015546F, 0.004659F, 0.006934F, 0.007023F, 0.020252F, 0.005387F, 0.024704F, 0.006963F, 0.002625F, 0.009512F, 0.002971F, 0.008233F, 0.01F, 0.011973F, 0.010553F, 0.005945F, 0.006349F, 0.009401F, 0.008577F, 0.008186F, 0.008159F, 0.005033F, 0.008714F, 0.010614F, 0.006554F}; + mSecondByteStdDev = 0.009909F; + mSecondByteMean = 0.010638F; + mSecondByteWeight = 0.324739F; + } + } + + /** + * + */ + public static class nsBIG5Verifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsBIG5Verifier() { + cclass = new int[32]; + cclass[0] = 286331153; + cclass[1] = 1118481; + cclass[2] = 286331153; + cclass[3] = 286327057; + cclass[4] = 286331153; + cclass[5] = 286331153; + cclass[6] = 286331153; + cclass[7] = 286331153; + cclass[8] = 572662306; + cclass[9] = 572662306; + cclass[10] = 572662306; + cclass[11] = 572662306; + cclass[12] = 572662306; + cclass[13] = 572662306; + cclass[14] = 572662306; + cclass[15] = 304226850; + cclass[16] = 1145324612; + cclass[17] = 1145324612; + cclass[18] = 1145324612; + cclass[19] = 1145324612; + cclass[20] = 858993460; + cclass[21] = 858993459; + cclass[22] = 858993459; + cclass[23] = 858993459; + cclass[24] = 858993459; + cclass[25] = 858993459; + cclass[26] = 858993459; + cclass[27] = 858993459; + cclass[28] = 858993459; + cclass[29] = 858993459; + cclass[30] = 858993459; + cclass[31] = 53687091; + states = new int[3]; + states[0] = 286339073; + states[1] = 304226833; + states[2] = 1; + charset = "Big5"; + stFactor = 5; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class GB2312Statistics extends nsEUCStatistics { + static float[] mFirstByteFreq; + static float mFirstByteStdDev; + static float mFirstByteMean; + static float mFirstByteWeight; + static float[] mSecondByteFreq; + static float mSecondByteStdDev; + static float mSecondByteMean; + static float mSecondByteWeight; + + public float[] mFirstByteFreq() { + return mFirstByteFreq; + } + + public float mFirstByteStdDev() { + return mFirstByteStdDev; + } + + public float mFirstByteMean() { + return mFirstByteMean; + } + + public float mFirstByteWeight() { + return mFirstByteWeight; + } + + public float[] mSecondByteFreq() { + return mSecondByteFreq; + } + + public float mSecondByteStdDev() { + return mSecondByteStdDev; + } + + public float mSecondByteMean() { + return mSecondByteMean; + } + + public float mSecondByteWeight() { + return mSecondByteWeight; + } + + public GB2312Statistics() { + mFirstByteFreq = new float[]{0.011628F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.011628F, 0.012403F, 0.009302F, 0.003876F, 0.017829F, 0.037209F, 0.008527F, 0.010078F, 0.01938F, 0.054264F, 0.010078F, 0.041085F, 0.02093F, 0.018605F, 0.010078F, 0.013178F, 0.016279F, 0.006202F, 0.009302F, 0.017054F, 0.011628F, 0.008527F, 0.004651F, 0.006202F, 0.017829F, 0.024806F, 0.020155F, 0.013953F, 0.032558F, 0.035659F, 0.068217F, 0.010853F, 0.036434F, 0.117054F, 0.027907F, 0.100775F, 0.010078F, 0.017829F, 0.062016F, 0.012403F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.00155F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F}; + mFirstByteStdDev = 0.020081F; + mFirstByteMean = 0.010638F; + mFirstByteWeight = 0.586533F; + mSecondByteFreq = new float[]{0.006202F, 0.031008F, 0.005426F, 0.003101F, 0.00155F, 0.003101F, 0.082171F, 0.014729F, 0.006977F, 0.00155F, 0.013953F, 0.0F, 0.013953F, 0.010078F, 0.008527F, 0.006977F, 0.004651F, 0.003101F, 0.003101F, 0.003101F, 0.008527F, 0.003101F, 0.005426F, 0.005426F, 0.005426F, 0.003101F, 0.00155F, 0.006202F, 0.014729F, 0.010853F, 0.0F, 0.011628F, 0.0F, 0.031783F, 0.013953F, 0.030233F, 0.039535F, 0.008527F, 0.015504F, 0.0F, 0.003101F, 0.008527F, 0.016279F, 0.005426F, 0.00155F, 0.013953F, 0.013953F, 0.044961F, 0.003101F, 0.004651F, 0.006977F, 0.00155F, 0.005426F, 0.012403F, 0.00155F, 0.015504F, 0.0F, 0.006202F, 0.00155F, 0.0F, 0.007752F, 0.006977F, 0.00155F, 0.009302F, 0.011628F, 0.004651F, 0.010853F, 0.012403F, 0.017829F, 0.005426F, 0.024806F, 0.0F, 0.006202F, 0.0F, 0.082171F, 0.015504F, 0.004651F, 0.0F, 0.006977F, 0.004651F, 0.0F, 0.008527F, 0.012403F, 0.004651F, 0.003876F, 0.003101F, 0.022481F, 0.024031F, 0.00155F, 0.047287F, 0.009302F, 0.00155F, 0.005426F, 0.017054F}; + mSecondByteStdDev = 0.014156F; + mSecondByteMean = 0.010638F; + mSecondByteWeight = 0.413467F; + } + } + + /** + * + */ + public static class nsGB2312Verifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsGB2312Verifier() { + cclass = new int[32]; + cclass[0] = 286331153; + cclass[1] = 1118481; + cclass[2] = 286331153; + cclass[3] = 286327057; + cclass[4] = 286331153; + cclass[5] = 286331153; + cclass[6] = 286331153; + cclass[7] = 286331153; + cclass[8] = 286331153; + cclass[9] = 286331153; + cclass[10] = 286331153; + cclass[11] = 286331153; + cclass[12] = 286331153; + cclass[13] = 286331153; + cclass[14] = 286331153; + cclass[15] = 286331153; + cclass[16] = 0; + cclass[17] = 0; + cclass[18] = 0; + cclass[19] = 0; + cclass[20] = 572662304; + cclass[21] = 858993442; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662306; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 572662306; + cclass[29] = 572662306; + cclass[30] = 572662306; + cclass[31] = 35791394; + states = new int[2]; + states[0] = 286331649; + states[1] = 1122850; + charset = "GB2312"; + stFactor = 4; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsGB18030Verifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsGB18030Verifier() { + cclass = new int[32]; + cclass[0] = 286331153; + cclass[1] = 1118481; + cclass[2] = 286331153; + cclass[3] = 286327057; + cclass[4] = 286331153; + cclass[5] = 286331153; + cclass[6] = 858993459; + cclass[7] = 286331187; + cclass[8] = 572662306; + cclass[9] = 572662306; + cclass[10] = 572662306; + cclass[11] = 572662306; + cclass[12] = 572662306; + cclass[13] = 572662306; + cclass[14] = 572662306; + cclass[15] = 1109533218; + cclass[16] = 1717986917; + cclass[17] = 1717986918; + cclass[18] = 1717986918; + cclass[19] = 1717986918; + cclass[20] = 1717986918; + cclass[21] = 1717986918; + cclass[22] = 1717986918; + cclass[23] = 1717986918; + cclass[24] = 1717986918; + cclass[25] = 1717986918; + cclass[26] = 1717986918; + cclass[27] = 1717986918; + cclass[28] = 1717986918; + cclass[29] = 1717986918; + cclass[30] = 1717986918; + cclass[31] = 107374182; + states = new int[6]; + states[0] = 318767105; + states[1] = 571543825; + states[2] = 17965602; + states[3] = 286326804; + states[4] = 303109393; + states[5] = 17; + charset = "GB18030"; + stFactor = 7; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsISO2022CNVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsISO2022CNVerifier() { + cclass = new int[32]; + cclass[0] = 2; + cclass[1] = 0; + cclass[2] = 0; + cclass[3] = 4096; + cclass[4] = 0; + cclass[5] = 48; + cclass[6] = 0; + cclass[7] = 0; + cclass[8] = 16384; + cclass[9] = 0; + cclass[10] = 0; + cclass[11] = 0; + cclass[12] = 0; + cclass[13] = 0; + cclass[14] = 0; + cclass[15] = 0; + cclass[16] = 572662306; + cclass[17] = 572662306; + cclass[18] = 572662306; + cclass[19] = 572662306; + cclass[20] = 572662306; + cclass[21] = 572662306; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662306; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 572662306; + cclass[29] = 572662306; + cclass[30] = 572662306; + cclass[31] = 572662306; + states = new int[8]; + states[0] = 304; + states[1] = 286331152; + states[2] = 572662289; + states[3] = 336663074; + states[4] = 286335249; + states[5] = 286331237; + states[6] = 286335249; + states[7] = 18944273; + charset = "ISO-2022-CN"; + stFactor = 9; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsISO2022JPVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsISO2022JPVerifier() { + cclass = new int[32]; + cclass[0] = 2; + cclass[1] = 570425344; + cclass[2] = 0; + cclass[3] = 4096; + cclass[4] = 458752; + cclass[5] = 3; + cclass[6] = 0; + cclass[7] = 0; + cclass[8] = 1030; + cclass[9] = 1280; + cclass[10] = 0; + cclass[11] = 0; + cclass[12] = 0; + cclass[13] = 0; + cclass[14] = 0; + cclass[15] = 0; + cclass[16] = 572662306; + cclass[17] = 572662306; + cclass[18] = 572662306; + cclass[19] = 572662306; + cclass[20] = 572662306; + cclass[21] = 572662306; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662306; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 572662306; + cclass[29] = 572662306; + cclass[30] = 572662306; + cclass[31] = 572662306; + states = new int[6]; + states[0] = 304; + states[1] = 286331153; + states[2] = 572662306; + states[3] = 1091653905; + states[4] = 303173905; + states[5] = 287445265; + charset = "ISO-2022-JP"; + stFactor = 8; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsISO2022KRVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsISO2022KRVerifier() { + cclass = new int[32]; + cclass[0] = 2; + cclass[1] = 0; + cclass[2] = 0; + cclass[3] = 4096; + cclass[4] = 196608; + cclass[5] = 64; + cclass[6] = 0; + cclass[7] = 0; + cclass[8] = 20480; + cclass[9] = 0; + cclass[10] = 0; + cclass[11] = 0; + cclass[12] = 0; + cclass[13] = 0; + cclass[14] = 0; + cclass[15] = 0; + cclass[16] = 572662306; + cclass[17] = 572662306; + cclass[18] = 572662306; + cclass[19] = 572662306; + cclass[20] = 572662306; + cclass[21] = 572662306; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662306; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 572662306; + cclass[29] = 572662306; + cclass[30] = 572662306; + cclass[31] = 572662306; + states = new int[5]; + states[0] = 285212976; + states[1] = 572657937; + states[2] = 289476898; + states[3] = 286593297; + states[4] = 8465; + charset = "ISO-2022-KR"; + stFactor = 6; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsUCS2BEVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsUCS2BEVerifier() { + cclass = new int[32]; + cclass[0] = 0; + cclass[1] = 2097408; + cclass[2] = 0; + cclass[3] = 12288; + cclass[4] = 0; + cclass[5] = 3355440; + cclass[6] = 0; + cclass[7] = 0; + cclass[8] = 0; + cclass[9] = 0; + cclass[10] = 0; + cclass[11] = 0; + cclass[12] = 0; + cclass[13] = 0; + cclass[14] = 0; + cclass[15] = 0; + cclass[16] = 0; + cclass[17] = 0; + cclass[18] = 0; + cclass[19] = 0; + cclass[20] = 0; + cclass[21] = 0; + cclass[22] = 0; + cclass[23] = 0; + cclass[24] = 0; + cclass[25] = 0; + cclass[26] = 0; + cclass[27] = 0; + cclass[28] = 0; + cclass[29] = 0; + cclass[30] = 0; + cclass[31] = 1409286144; + states = new int[7]; + states[0] = 288626549; + states[1] = 572657937; + states[2] = 291923490; + states[3] = 1713792614; + states[4] = 393569894; + states[5] = 1717659269; + states[6] = 1140326; + charset = "UTF-16BE"; + stFactor = 6; + } + + public boolean isUCS2() { + return true; + } + } + + /** + * + */ + public static class nsUCS2LEVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsUCS2LEVerifier() { + cclass = new int[32]; + cclass[0] = 0; + cclass[1] = 2097408; + cclass[2] = 0; + cclass[3] = 12288; + cclass[4] = 0; + cclass[5] = 3355440; + cclass[6] = 0; + cclass[7] = 0; + cclass[8] = 0; + cclass[9] = 0; + cclass[10] = 0; + cclass[11] = 0; + cclass[12] = 0; + cclass[13] = 0; + cclass[14] = 0; + cclass[15] = 0; + cclass[16] = 0; + cclass[17] = 0; + cclass[18] = 0; + cclass[19] = 0; + cclass[20] = 0; + cclass[21] = 0; + cclass[22] = 0; + cclass[23] = 0; + cclass[24] = 0; + cclass[25] = 0; + cclass[26] = 0; + cclass[27] = 0; + cclass[28] = 0; + cclass[29] = 0; + cclass[30] = 0; + cclass[31] = 1409286144; + states = new int[7]; + states[0] = 288647014; + states[1] = 572657937; + states[2] = 303387938; + states[3] = 1712657749; + states[4] = 357927015; + states[5] = 1427182933; + states[6] = 1381717; + charset = "UTF-16LE"; + stFactor = 6; + } + + public boolean isUCS2() { + return true; + } + } + + /** + * + */ + public static class nsCP1252Verifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsCP1252Verifier() { + cclass = new int[32]; + cclass[0] = 572662305; + cclass[1] = 2236962; + cclass[2] = 572662306; + cclass[3] = 572654114; + cclass[4] = 572662306; + cclass[5] = 572662306; + cclass[6] = 572662306; + cclass[7] = 572662306; + cclass[8] = 572662306; + cclass[9] = 572662306; + cclass[10] = 572662306; + cclass[11] = 572662306; + cclass[12] = 572662306; + cclass[13] = 572662306; + cclass[14] = 572662306; + cclass[15] = 572662306; + cclass[16] = 572662274; + cclass[17] = 16851234; + cclass[18] = 572662304; + cclass[19] = 285286690; + cclass[20] = 572662306; + cclass[21] = 572662306; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 286331153; + cclass[25] = 286331153; + cclass[26] = 554766609; + cclass[27] = 286331153; + cclass[28] = 286331153; + cclass[29] = 286331153; + cclass[30] = 554766609; + cclass[31] = 286331153; + states = new int[3]; + states[0] = 571543601; + states[1] = 340853778; + states[2] = 65; + charset = "windows-1252"; + stFactor = 3; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsHZVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsHZVerifier() { + cclass = new int[32]; + cclass[0] = 1; + cclass[1] = 0; + cclass[2] = 0; + cclass[3] = 4096; + cclass[4] = 0; + cclass[5] = 0; + cclass[6] = 0; + cclass[7] = 0; + cclass[8] = 0; + cclass[9] = 0; + cclass[10] = 0; + cclass[11] = 0; + cclass[12] = 0; + cclass[13] = 0; + cclass[14] = 0; + cclass[15] = 38813696; + cclass[16] = 286331153; + cclass[17] = 286331153; + cclass[18] = 286331153; + cclass[19] = 286331153; + cclass[20] = 286331153; + cclass[21] = 286331153; + cclass[22] = 286331153; + cclass[23] = 286331153; + cclass[24] = 286331153; + cclass[25] = 286331153; + cclass[26] = 286331153; + cclass[27] = 286331153; + cclass[28] = 286331153; + cclass[29] = 286331153; + cclass[30] = 286331153; + cclass[31] = 286331153; + states = new int[6]; + states[0] = 285213456; + states[1] = 572657937; + states[2] = 335548706; + states[3] = 341120533; + states[4] = 336872468; + states[5] = 36; + charset = "HZ-GB-2312"; + stFactor = 6; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsSJISVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsSJISVerifier() { + cclass = new int[32]; + cclass[0] = 286331152; + cclass[1] = 1118481; + cclass[2] = 286331153; + cclass[3] = 286327057; + cclass[4] = 286331153; + cclass[5] = 286331153; + cclass[6] = 286331153; + cclass[7] = 286331153; + cclass[8] = 572662306; + cclass[9] = 572662306; + cclass[10] = 572662306; + cclass[11] = 572662306; + cclass[12] = 572662306; + cclass[13] = 572662306; + cclass[14] = 572662306; + cclass[15] = 304226850; + cclass[16] = 858993459; + cclass[17] = 858993459; + cclass[18] = 858993459; + cclass[19] = 858993459; + cclass[20] = 572662308; + cclass[21] = 572662306; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662306; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 858993459; + cclass[29] = 1145393971; + cclass[30] = 1145324612; + cclass[31] = 279620; + states = new int[3]; + states[0] = 286339073; + states[1] = 572657937; + states[2] = 4386; + charset = "Shift_JIS"; + stFactor = 6; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsUTF8Verifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsUTF8Verifier() { + cclass = new int[32]; + cclass[0] = 286331153; + cclass[1] = 1118481; + cclass[2] = 286331153; + cclass[3] = 286327057; + cclass[4] = 286331153; + cclass[5] = 286331153; + cclass[6] = 286331153; + cclass[7] = 286331153; + cclass[8] = 286331153; + cclass[9] = 286331153; + cclass[10] = 286331153; + cclass[11] = 286331153; + cclass[12] = 286331153; + cclass[13] = 286331153; + cclass[14] = 286331153; + cclass[15] = 286331153; + cclass[16] = 858989090; + cclass[17] = 1145324612; + cclass[18] = 1145324612; + cclass[19] = 1145324612; + cclass[20] = 1431655765; + cclass[21] = 1431655765; + cclass[22] = 1431655765; + cclass[23] = 1431655765; + cclass[24] = 1717986816; + cclass[25] = 1717986918; + cclass[26] = 1717986918; + cclass[27] = 1717986918; + cclass[28] = -2004318073; + cclass[29] = -2003269496; + cclass[30] = -1145324614; + cclass[31] = 16702940; + states = new int[26]; + states[0] = -1408167679; + states[1] = 878082233; + states[2] = 286331153; + states[3] = 286331153; + states[4] = 572662306; + states[5] = 572662306; + states[6] = 290805009; + states[7] = 286331153; + states[8] = 290803985; + states[9] = 286331153; + states[10] = 293041937; + states[11] = 286331153; + states[12] = 293015825; + states[13] = 286331153; + states[14] = 295278865; + states[15] = 286331153; + states[16] = 294719761; + states[17] = 286331153; + states[18] = 298634257; + states[19] = 286331153; + states[20] = 297865489; + states[21] = 286331153; + states[22] = 287099921; + states[23] = 286331153; + states[24] = 285212689; + states[25] = 286331153; + charset = "UTF-8"; + stFactor = 16; + } + + public boolean isUCS2() { + return false; + } + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/JSONUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/JSONUtil.java new file mode 100644 index 0000000..8d63168 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/JSONUtil.java @@ -0,0 +1,69 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; + +/** + * JSON解析工具类 + * + * @author WebSoft + * @since 2017-06-10 10:10:39 + */ +public class JSONUtil { + private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final ObjectWriter objectWriter = objectMapper.writerWithDefaultPrettyPrinter(); + + /** + * 对象转json字符串 + * + * @param value 对象 + * @return String + */ + public static String toJSONString(Object value) { + return toJSONString(value, false); + } + + /** + * 对象转json字符串 + * + * @param value 对象 + * @param pretty 是否格式化输出 + * @return String + */ + public static String toJSONString(Object value, boolean pretty) { + if (value != null) { + if (value instanceof String) { + return (String) value; + } + try { + if (pretty) { + return objectWriter.writeValueAsString(value); + } + return objectMapper.writeValueAsString(value); + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + + /** + * json字符串转对象 + * + * @param json String + * @param clazz Class + * @return T + */ + public static T parseObject(String json, Class clazz) { + if (StrUtil.isNotBlank(json) && clazz != null) { + try { + return objectMapper.readValue(json, clazz); + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/MyQrCodeUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/MyQrCodeUtil.java new file mode 100644 index 0000000..933deac --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/MyQrCodeUtil.java @@ -0,0 +1,85 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.extra.qrcode.QrCodeUtil; +import cn.hutool.extra.qrcode.QrConfig; +import org.springframework.beans.factory.annotation.Value; + +import javax.annotation.Resource; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.net.URL; +import java.util.HashMap; + +import static com.gxwebsoft.common.core.constants.QRCodeConstants.*; + +/** + * 常用工具方法 + * + * @author WebSoft + * @since 2017-06-10 10:10:22 + */ +public class MyQrCodeUtil { + + @Value("${config.upload-path}") + private static String uploadPath; + + private static final String logoUrl = "https://file.wsdns.cn/20230430/6fa31aca3b0d47af98a149cf2dd26a4f.jpeg"; + + /** + * 生成用户二维码 + */ + public static String getUserCode(Integer userId, String content) throws IOException { + return createQrCode(USER_QRCODE,userId,content); + } + + /** + * 生成工单二维码 + */ + public static String getTaskCode(Integer taskId, String content) throws IOException { + return createQrCode(TASK_QRCODE,taskId,content); + } + + /** + * 生成商品二维码 + */ + public static String getGoodsCode(Integer goodsId, String content) throws IOException { + return createQrCode(GOODS_QRCODE,goodsId,content); + } + + /** + * 生成自定义二维码 + */ + public static String getCodeMap(HashMap map) throws IOException { + return ""; + } + + /** + * 生成带水印的二维码 + * @param type 类型 + * @param id 实体ID + * @param content 二维码内容 + * @return 二维码图片地址 + */ + public static String createQrCode(String type,Integer id, String content) throws IOException { + String filePath = uploadPath + "/file/qrcode/".concat(type).concat("/"); + String qrcodeUrl = "https://file.websoft.top/qrcode/".concat(type).concat("/"); + // 将URL转为BufferedImage + BufferedImage bufferedImage = ImageIO.read(new URL(logoUrl)); + // 生成二维码 + QrConfig config = new QrConfig(300, 300); + // 设置边距,既二维码和背景之间的边距 + config.setMargin(1); + // 附带小logo + config.setImg(bufferedImage); + // 保存路径 + filePath = filePath.concat(id + ".jpg"); + qrcodeUrl = qrcodeUrl.concat(id + ".jpg") + "?v=" + DateUtil.current(); + + // 生成二维码 + QrCodeUtil.generate(content, config, FileUtil.file(filePath)); + return qrcodeUrl; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/OpenOfficeUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/OpenOfficeUtil.java new file mode 100644 index 0000000..cca3990 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/OpenOfficeUtil.java @@ -0,0 +1,124 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.StrUtil; +import org.artofsolving.jodconverter.OfficeDocumentConverter; +import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration; +import org.artofsolving.jodconverter.office.OfficeManager; + +import java.io.File; +import java.util.Arrays; +import java.util.Base64; + +/** + * OpenOfficeUtil + * + * @author WebSoft + * @since 2018-12-14 08:38:19 + */ +public class OpenOfficeUtil { + // 支持转换pdf的文件后缀列表 + private static final String[] CAN_CONVERTER_FILES = new String[]{ + "doc", "docx", "xls", "xlsx", "ppt", "pptx" + }; + + /** + * 文件转pdf + * + * @param filePath 源文件路径 + * @param outDir 输出目录 + * @param officeHome OpenOffice安装路径 + * @return File + */ + public static File converterToPDF(String filePath, String outDir, String officeHome) { + return converterToPDF(filePath, outDir, officeHome, true); + } + + /** + * 文件转pdf + * + * @param filePath 源文件路径 + * @param outDir 输出目录 + * @param officeHome OpenOffice安装路径 + * @param cache 是否使用上次转换过的文件 + * @return File + */ + public static File converterToPDF(String filePath, String outDir, String officeHome, boolean cache) { + if (StrUtil.isBlank(filePath)) { + return null; + } + File srcFile = new File(filePath); + if (!srcFile.exists()) { + return null; + } + // 是否转换过 + String outPath = Base64.getEncoder().encodeToString(filePath.getBytes()) + .replace("/", "-").replace("+", "-"); + File outFile = new File(outDir, outPath + ".pdf"); + if (cache && outFile.exists()) { + return outFile; + } + // 转换 + OfficeManager officeManager = null; + try { + officeManager = getOfficeManager(officeHome); + OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager); + return converterFile(srcFile, outFile, converter); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (officeManager != null) { + officeManager.stop(); + } + } + return null; + } + + /** + * 转换文件 + * + * @param inFile 源文件 + * @param outFile 输出文件 + * @param converter OfficeDocumentConverter + * @return File + */ + public static File converterFile(File inFile, File outFile, OfficeDocumentConverter converter) { + if (!outFile.getParentFile().exists()) { + if (!outFile.getParentFile().mkdirs()) { + return outFile; + } + } + converter.convert(inFile, outFile); + return outFile; + } + + /** + * 判断文件后缀是否可以转换pdf + * + * @param path 文件路径 + * @return boolean + */ + public static boolean canConverter(String path) { + try { + String suffix = path.substring(path.lastIndexOf(".") + 1); + return Arrays.asList(CAN_CONVERTER_FILES).contains(suffix); + } catch (Exception e) { + return false; + } + } + + /** + * 连接并启动OpenOffice + * + * @param officeHome OpenOffice安装路径 + * @return OfficeManager + */ + public static OfficeManager getOfficeManager(String officeHome) { + if (officeHome == null || officeHome.trim().isEmpty()) return null; + DefaultOfficeManagerConfiguration config = new DefaultOfficeManagerConfiguration(); + config.setOfficeHome(officeHome); // 设置OpenOffice安装目录 + OfficeManager officeManager = config.buildOfficeManager(); + officeManager.start(); // 启动OpenOffice服务 + return officeManager; + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/QrCodeDecryptResult.java b/src/main/java/com/gxwebsoft/common/core/utils/QrCodeDecryptResult.java new file mode 100644 index 0000000..bbfe3b6 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/QrCodeDecryptResult.java @@ -0,0 +1,93 @@ +package com.gxwebsoft.common.core.utils; + +import lombok.Data; + +/** + * 二维码解密结果类 + * 包含解密后的数据和业务类型信息 + * + * @author WebSoft + * @since 2025-08-18 + */ +@Data +public class QrCodeDecryptResult { + + /** + * 解密后的原始数据 + */ + private String originalData; + + /** + * 业务类型(如:order、user、coupon、ticket等) + */ + private String businessType; + + /** + * 二维码类型(encrypted 或 business_encrypted) + */ + private String qrType; + + /** + * 二维码ID(仅业务模式有) + */ + private String qrId; + + /** + * 过期时间戳(仅业务模式有) + */ + private Long expireTime; + + /** + * 是否已过期 + */ + private Boolean expired; + + public QrCodeDecryptResult() {} + + public QrCodeDecryptResult(String originalData, String businessType, String qrType) { + this.originalData = originalData; + this.businessType = businessType; + this.qrType = qrType; + this.expired = false; + } + + /** + * 创建自包含模式的解密结果 + */ + public static QrCodeDecryptResult createEncryptedResult(String originalData, String businessType) { + return new QrCodeDecryptResult(originalData, businessType, "encrypted"); + } + + /** + * 创建业务模式的解密结果 + */ + public static QrCodeDecryptResult createBusinessResult(String originalData, String businessType, + String qrId, Long expireTime) { + QrCodeDecryptResult result = new QrCodeDecryptResult(originalData, businessType, "business_encrypted"); + result.setQrId(qrId); + result.setExpireTime(expireTime); + result.setExpired(expireTime != null && System.currentTimeMillis() > expireTime); + return result; + } + + /** + * 检查是否有业务类型 + */ + public boolean hasBusinessType() { + return businessType != null && !businessType.trim().isEmpty(); + } + + /** + * 检查是否为业务模式 + */ + public boolean isBusinessMode() { + return "business_encrypted".equals(qrType); + } + + /** + * 检查是否为自包含模式 + */ + public boolean isEncryptedMode() { + return "encrypted".equals(qrType); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/RedisUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/RedisUtil.java new file mode 100644 index 0000000..f02ce42 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/RedisUtil.java @@ -0,0 +1,279 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.result.RedisResult; +import org.springframework.data.geo.Point; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +import static com.gxwebsoft.common.core.constants.RedisConstants.CACHE_NULL_TTL; + +@Component +public class RedisUtil { + private final StringRedisTemplate stringRedisTemplate; + public static Integer tenantId; + + public RedisUtil(StringRedisTemplate stringRedisTemplate){ + this.stringRedisTemplate = stringRedisTemplate; + } + + /** + * 写入redis缓存 + * @param key [表名]:id + * @param entity 实体类对象 + * 示例 cacheClient.set("merchant:"+id,merchant) + */ + public void set(String key, T entity){ + stringRedisTemplate.opsForValue().set(key, JSONUtil.toJSONString(entity)); + } + + /** + * 写入redis缓存 + * @param key [表名]:id + * @param entity 实体类对象 + * 示例 cacheClient.set("merchant:"+id,merchant,1L,TimeUnit.DAYS) + */ + public void set(String key, T entity, Long time, TimeUnit unit){ + stringRedisTemplate.opsForValue().set(key, JSONUtil.toJSONString(entity),time,unit); + } + + /** + * 读取redis缓存 + * @param key [表名]:id + * 示例 cacheClient.get(key) + * @return merchant + */ + public String get(String key) { + return stringRedisTemplate.opsForValue().get(key); + } + + /** + * 读取redis缓存 + * @param key [表名]:id + * @param clazz Merchant.class + * @param + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + * @return merchant + */ + public T get(String key, Class clazz) { + String json = stringRedisTemplate.opsForValue().get(key); + if(StrUtil.isNotBlank(json)){ + return JSONUtil.parseObject(json, clazz); + } + return null; + } + + /** + * 写redis缓存(哈希类型) + * @param key [表名]:id + * @param field 字段 + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + */ + public void hPut(String key, String field, T entity) { + stringRedisTemplate.opsForHash().put(key,field,JSONUtil.toJSONString(entity)); + } + + /** + * 写redis缓存(哈希类型) + * @param key [表名]:id + * @param map 字段 + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + */ + public void hPutAll(String key, Map map) { + stringRedisTemplate.opsForHash().putAll(key,map); + } + + /** + * 读取redis缓存(哈希类型) + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + * @param key [表名]:id + * @param field 字段 + * @return merchant + */ + public T hGet(String key, String field, Class clazz) { + Object obj = stringRedisTemplate.opsForHash().get(key, field); + return JSONUtil.parseObject(JSONUtil.toJSONString(obj),clazz); + } + + public List hValues(String key){ + return stringRedisTemplate.opsForHash().values(key); + } + + public Long hSize(String key){ + return stringRedisTemplate.opsForHash().size(key); + } + + // 逻辑过期方式写入redis + public void setWithLogicalExpire(String key, T value, Long time, TimeUnit unit){ + // 设置逻辑过期时间 + final RedisResult redisResult = new RedisResult<>(); + redisResult.setData(value); + redisResult.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time))); + stringRedisTemplate.opsForValue().set(key,JSONUtil.toJSONString(redisResult)); + } + + // 读取redis + public R query(String keyPrefix, ID id, Class clazz, Function dbFallback, Long time, TimeUnit unit){ + String key = keyPrefix + id; + // 1.从redis查询缓存 + final String json = stringRedisTemplate.opsForValue().get(key); + // 2.判断是否存在 + if (StrUtil.isNotBlank(json)) { + // 3.存在,直接返回 + return JSONUtil.parseObject(json,clazz); + } + // 判断命中的是否为空值 + if (json != null) { + return null; + } + // 4. 不存在,跟进ID查询数据库 + R r = dbFallback.apply(id); + // 5. 数据库不存在,返回错误 + if(r == null){ + // 空值写入数据库 + this.set(key,"",CACHE_NULL_TTL,TimeUnit.MINUTES); + return null; + } + // 写入redis + this.set(key,r,time,unit); + return r; + } + + /** + * 添加商户定位点 + * @param key geo + * @param id + * 示例 cacheClient.geoAdd("merchant-geo",merchant) + */ + public void geoAdd(String key, Double x, Double y, String id){ + stringRedisTemplate.opsForGeo().add(key,new Point(x,y),id); + } + + /** + * 删除定位 + * @param key geo + * @param id + * 示例 cacheClient.geoRemove("merchant-geo",id) + */ + public void geoRemove(String key, Integer id){ + stringRedisTemplate.opsForGeo().remove(key,id.toString()); + } + + + + public void sAdd(String key, T entity){ + stringRedisTemplate.opsForSet().add(key,JSONUtil.toJSONString(entity)); + } + + public Set sMembers(String key){ + return stringRedisTemplate.opsForSet().members(key); + } + + // 更新排行榜 + public void zAdd(String key, Integer userId, Double value) { + stringRedisTemplate.opsForZSet().add(key,userId.toString(),value); + } + // 增加元素的score值,并返回增加后的值 + public Double zIncrementScore(String key,Integer userId, Double delta){ + return stringRedisTemplate.opsForZSet().incrementScore(key, userId.toString(), delta); + } + // 获取排名榜 + public Set range(String key, Integer start, Integer end) { + return stringRedisTemplate.opsForZSet().range(key, start, end); + } + // 获取排名榜 + public Set reverseRange(String key, Integer start, Integer end){ + return stringRedisTemplate.opsForZSet().reverseRange(key, start, end); + } + // 获取分数 + public Double score(String key, Object value){ + return stringRedisTemplate.opsForZSet().score(key, value); + } + + public void delete(String key){ + stringRedisTemplate.delete(key); + } + + // 存储在list头部 + public void leftPush(String key, String keyword){ + stringRedisTemplate.opsForList().leftPush(key,keyword); + } + + // 获取列表指定范围内的元素 + public List listRange(String key,Long start, Long end){ + return stringRedisTemplate.opsForList().range(key, start, end); + } + + // 获取列表长度 + public Long listSize(String key){ + return stringRedisTemplate.opsForList().size(key); + } + + // 裁剪list + public void listTrim(String key){ + stringRedisTemplate.opsForList().trim(key, 0L, 100L); + } + + /** + * 读取后台系统设置信息 + * @param keyName 键名wx-word + * @param tenantId 租户ID + * @return + * key示例 cache10048:setting:wx-work + */ + public JSONObject getSettingInfo(String keyName,Integer tenantId){ + String key = "cache" + tenantId + ":setting:" + keyName; + final String cache = stringRedisTemplate.opsForValue().get(key); + assert cache != null; + return JSON.parseObject(cache); + } + + /** + * KEY前缀 + * cache[tenantId]:[key+id] + */ + public static String prefix(String key){ + String prefix = "cache"; + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null) { + Object object = authentication.getPrincipal(); + if (object instanceof User) { + final Integer tenantId = ((User) object).getTenantId(); + prefix = prefix.concat(tenantId.toString()).concat(":"); + } + } + return prefix.concat(key); + } + + // 组装key + public String key(String name,Integer id){ + return name.concat(":").concat(id.toString()); + } + + // 获取上传配置 + public HashMap getUploadConfig(Integer tenantId){ + String key = "setting:upload:" + tenantId; + final String s = get(key); + final JSONObject jsonObject = JSONObject.parseObject(s); + final String uploadMethod = jsonObject.getString("uploadMethod"); + final String bucketDomain = jsonObject.getString("bucketDomain"); + + final HashMap map = new HashMap<>(); + map.put("uploadMethod",uploadMethod); + map.put("bucketDomain",bucketDomain); + return map; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/SignCheckUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/SignCheckUtil.java new file mode 100644 index 0000000..b09cd9a --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/SignCheckUtil.java @@ -0,0 +1,197 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.crypto.SecureUtil; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.system.entity.KVEntity; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; + +/** + * 签名检查和获取签名 + * https://blog.csdn.net/u011628753/article/details/110251445 + * @author leng + * + */ +public class SignCheckUtil { + // 签名字段 + public final static String SIGN = "sign"; + + /** + * 签名检查,签名参数中,sign是用于校验的加密值,其他参数按照字母顺序排序,加密,并将其内容链接起来 + * + * @param params + * @param key + * @return + */ + public static boolean signCheck(JSONObject params, String key) { + if (null != params) { + Map map = new HashMap<>(); + + params.forEach((k, v) -> { + map.put(k, v.toString()); + }); + return signCheck(map, key); + } + + return false; + } + + /** + * 签名检查,签名参数中,sign是用于校验的加密值,其他参数按照字母顺序排序,加密,并将其内容链接起来 + * + * @param params + * @param key + * 签名key不允许为空 + * @return + */ + public static boolean signCheck(Map params, String key) { + String sign = params.get(SIGN);// 签名 + if (null == sign) { + return false; + } + String signTemp = getSignString(params,key); + if (null == signTemp) { + return false; + } + return signTemp.equals(sign); + } + + /** + * 获取签名的字符串 + * + * @param params + * @param key + * @return + */ + public static String getSignString(JSONObject params, String key) { + if (null != params) { + Map map = new HashMap<>(); + + params.forEach((k, v) -> { + map.put(k, v.toString()); + }); + return getSignString(map, key); + } + + return null; + } + + /** + * 获取签名的字符串 + * + * @param params + * @param key + * @return + */ + public static String getSignString(Map params, String key) { + // 签名 + if (null == params || params.size() == 0) { + return null; + } + key = (null == key) ? "" : key; + List> list = new ArrayList<>(params.size() - 1); + + params.forEach((k, v) -> { + if (!SIGN.equals(k)) { + list.add(KVEntity.build(k, v)); + } + }); + + Collections.sort(list, (obj1, obj2) -> { + return obj1.getK().compareTo(obj2.getK()); + }); + + StringBuffer sb = new StringBuffer(); + for (KVEntity kv : list) { + String value = kv.getV(); + if (!StringUtils.isEmpty(value)) { + sb.append(kv.getV()).append("-"); + } + } + sb.append(key); + System.out.println("md5加密前的字符串 = " + sb + key); + String signTemp = SecureUtil.md5(sb.toString()).toLowerCase(); + return signTemp; + } + + /** + * 获取微信签名的字符串 + * + * 注意签名(sign)的生成方式,具体见官方文档(传参都要参与生成签名,且参数名按照字典序排序,最后接上APP_KEY,转化成大写) + * + * @param params + * @param key + * @return + */ + public static String getWXSignString(Map params, String key) { + // 签名 + if (null == params || params.size() == 0 || StringUtils.isEmpty(key)) { + return null; + } + + List> list = new ArrayList<>(params.size() - 1); + + params.forEach((k, v) -> { + if (!SIGN.equals(k)) { + list.add(KVEntity.build(k, v)); + } + }); + + Collections.sort(list, (obj1, obj2) -> { + return obj1.getK().compareTo(obj2.getK()); + }); + + StringBuffer sb = new StringBuffer(); + for (KVEntity kv : list) { + String value = kv.getV(); + if (!StringUtils.isEmpty(value)) { + sb.append(kv.getK() + "=" + value + "&"); + } + } + + sb.append("key=" + key); + String signTemp = SecureUtil.md5(sb.toString()).toLowerCase(); + return signTemp; + } + + /** + * 微信签名验证 + * @param params + * @param key + * @return + */ + public static boolean WXsignCheck(Map params, String key) { + String sign = params.get(SIGN); + if (StringUtils.isEmpty(sign)) { + return false; + } + return sign.equals(getWXSignString(params, key)); + } + + + /** + * 白名单校验 + * @param domainName abc.com + * @return true + */ + public boolean checkWhiteDomains(List whiteDomains, String domainName) { + if(whiteDomains == null){ + return true; + } + if (whiteDomains.isEmpty()) { + return true; + } + // 服务器域名白名单列表 + whiteDomains.add("server.websoft.top"); + System.out.println("whiteDomains = " + whiteDomains); + System.out.println(">>> domainName = " + domainName); + for(String item: whiteDomains){ + if(Objects.equals(item, domainName)){ + return true; + } + } + return false; + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WechatCertAutoConfig.java b/src/main/java/com/gxwebsoft/common/core/utils/WechatCertAutoConfig.java new file mode 100644 index 0000000..75b0a22 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/WechatCertAutoConfig.java @@ -0,0 +1,171 @@ +package com.gxwebsoft.common.core.utils; + +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAAutoCertificateConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import com.gxwebsoft.common.core.config.ConfigProperties; + +import javax.annotation.Resource; + +/** + * 微信支付证书自动配置工具类 + * 使用RSAAutoCertificateConfig实现证书自动管理 + * + * @author 科技小王子 + * @since 2024-07-26 + */ +@Slf4j +@Component +public class WechatCertAutoConfig { + + @Value("${spring.profiles.active:prod}") + private String activeProfile; + + @Resource + private ConfigProperties configProperties; + + /** + * 创建微信支付自动证书配置 + * + * @param merchantId 商户号 + * @param privateKeyPath 私钥文件路径 + * @param merchantSerialNumber 商户证书序列号 + * @param apiV3Key APIv3密钥 + * @return 微信支付配置对象 + */ + public Config createAutoConfig(String merchantId, String privateKeyPath, + String merchantSerialNumber, String apiV3Key) { + try { + log.info("创建微信支付自动证书配置..."); + log.info("商户号: {}", merchantId); + log.info("私钥路径: {}", privateKeyPath); + log.info("证书序列号: {}", merchantSerialNumber); + + Config config = new RSAAutoCertificateConfig.Builder() + .merchantId(merchantId) + .privateKeyFromPath(privateKeyPath) + .merchantSerialNumber(merchantSerialNumber) + .apiV3Key(apiV3Key) + .build(); + + log.info("✅ 微信支付自动证书配置创建成功"); + log.info("🔄 系统将自动管理平台证书的下载和更新"); + + return config; + + } catch (Exception e) { + log.error("❌ 创建微信支付自动证书配置失败: {}", e.getMessage(), e); + + // 提供详细的错误诊断信息 + log.error("🔍 错误诊断:"); + log.error("1. 请检查商户平台是否已开启API安全功能"); + log.error("2. 请确认已申请使用微信支付公钥"); + log.error("3. 请验证APIv3密钥和证书序列号是否正确"); + log.error("4. 请检查网络连接是否正常"); + log.error("5. 请确认私钥文件路径是否正确: {}", privateKeyPath); + + throw new RuntimeException("微信支付自动证书配置失败: " + e.getMessage(), e); + } + } + + /** + * 使用默认开发环境配置创建自动证书配置 + * 根据当前环境自动选择证书路径 + * 开发环境拼接规则:配置文件upload-path + dev/wechat/ + 租户ID + * + * @return 微信支付配置对象 + */ + public Config createDefaultDevConfig() { + String merchantId = "1723321338"; + String privateKeyPath; + String merchantSerialNumber = "2B933F7C35014A1C363642623E4A62364B34C4EB"; + String apiV3Key = "0kF5OlPr482EZwtn9zGufUcqa7ovgxRL"; + + // 根据环境选择证书路径 + if ("dev".equals(activeProfile)) { + // 开发环境:使用配置文件upload-path拼接证书路径 + String uploadPath = configProperties.getUploadPath(); // 配置文件路径 + String tenantId = "10550"; // 租户ID + String certPath = uploadPath + "dev/wechat/" + tenantId + "/"; + privateKeyPath = certPath + "apiclient_key.pem"; + + log.info("开发环境:使用配置文件upload-path拼接证书路径"); + log.info("配置文件upload-path: {}", uploadPath); + log.info("证书基础路径: {}", certPath); + log.info("私钥文件路径: {}", privateKeyPath); + } else { + // 生产环境:使用相对路径,由系统动态解析 + privateKeyPath = "src/main/resources/certs/dev/wechat/apiclient_key.pem"; + log.info("生产环境:使用相对证书路径 - {}", privateKeyPath); + } + + return createAutoConfig(merchantId, privateKeyPath, merchantSerialNumber, apiV3Key); + } + + /** + * 测试证书配置是否正常 + * + * @param config 微信支付配置 + * @return 是否配置成功 + */ + public boolean testConfig(Config config) { + try { + // 这里可以添加一些基本的配置验证逻辑 + log.info("🧪 测试微信支付证书配置..."); + + if (config == null) { + log.error("配置对象为空"); + return false; + } + + log.info("✅ 证书配置测试通过"); + return true; + + } catch (Exception e) { + log.error("❌ 证书配置测试失败: {}", e.getMessage(), e); + return false; + } + } + + /** + * 获取配置使用说明 + * + * @return 使用说明 + */ + public String getUsageInstructions() { + return """ + 🚀 微信支付自动证书配置使用说明 + ================================ + + ✅ 优势: + 1. 自动下载微信支付平台证书 + 2. 证书过期时自动更新 + 3. 无需手动管理 wechatpay_cert.pem 文件 + 4. 符合微信支付官方最佳实践 + + 📝 使用方法: + + // 方法1: 使用默认开发环境配置 + Config config = wechatCertAutoConfig.createDefaultDevConfig(); + + // 方法2: 自定义配置 + Config config = wechatCertAutoConfig.createAutoConfig( + "商户号", + "私钥路径", + "证书序列号", + "APIv3密钥" + ); + + 🔧 前置条件: + 1. 微信商户平台已开启API安全功能 + 2. 已申请使用微信支付公钥 + 3. 私钥文件存在且路径正确 + 4. 网络连接正常 + + 📚 更多信息: + https://pay.weixin.qq.com/doc/v3/merchant/4012153196 + """; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateDiagnostic.java b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateDiagnostic.java new file mode 100644 index 0000000..ebe8189 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateDiagnostic.java @@ -0,0 +1,314 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.system.entity.Payment; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + + +/** + * 微信支付证书诊断工具 + * 专门用于诊断和解决证书相关问题 + * + * @author 科技小王子 + * @since 2025-07-29 + */ +@Slf4j +@Component +public class WechatPayCertificateDiagnostic { + + private final CertificateProperties certConfig; + private final CertificateLoader certificateLoader; + + public WechatPayCertificateDiagnostic(CertificateProperties certConfig, CertificateLoader certificateLoader) { + this.certConfig = certConfig; + this.certificateLoader = certificateLoader; + } + + /** + * 全面诊断微信支付证书配置 + * + * @param payment 支付配置 + * @param tenantId 租户ID + * @param environment 环境(dev/prod) + * @return 诊断结果 + */ + public DiagnosticResult diagnoseCertificateConfig(Payment payment, Integer tenantId, String environment) { + DiagnosticResult result = new DiagnosticResult(); + + log.info("=== 开始微信支付证书诊断 ==="); + log.info("租户ID: {}, 环境: {}", tenantId, environment); + + try { + // 1. 检查基本配置 + checkBasicConfig(payment, result); + + // 2. 检查证书文件 + checkCertificateFiles(payment, tenantId, environment, result); + + // 3. 检查证书内容 + validateCertificateContent(payment, tenantId, environment, result); + + // 4. 生成建议 + generateRecommendations(result); + + } catch (Exception e) { + result.addError("诊断过程中发生异常: " + e.getMessage()); + log.error("证书诊断异常", e); + } + + log.info("=== 证书诊断完成 ==="); + return result; + } + + /** + * 检查基本配置 + */ + private void checkBasicConfig(Payment payment, DiagnosticResult result) { + if (payment == null) { + result.addError("支付配置为空"); + return; + } + + if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) { + result.addError("商户号未配置"); + } else { + result.addInfo("商户号: " + payment.getMchId()); + } + + if (payment.getAppId() == null || payment.getAppId().trim().isEmpty()) { + result.addError("应用ID未配置"); + } else { + result.addInfo("应用ID: " + payment.getAppId()); + } + + if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { + result.addError("商户证书序列号未配置"); + } else { + result.addInfo("商户证书序列号: " + payment.getMerchantSerialNumber()); + } + + if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) { + result.addWarning("数据库中APIv3密钥未配置,将使用配置文件默认值"); + } else { + result.addInfo("APIv3密钥: 已配置(" + payment.getApiKey().length() + "位)"); + } + } + + /** + * 检查证书文件 + */ + private void checkCertificateFiles(Payment payment, Integer tenantId, String environment, DiagnosticResult result) { + if ("dev".equals(environment)) { + // 开发环境证书检查 + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); + + // 检查私钥文件 + if (certificateLoader.certificateExists(privateKeyPath)) { + result.addInfo("✅ 私钥文件存在: " + privateKeyPath); + try { + String privateKeyFile = certificateLoader.loadCertificatePath(privateKeyPath); + result.addInfo("私钥文件路径: " + privateKeyFile); + } catch (Exception e) { + result.addError("私钥文件加载失败: " + e.getMessage()); + } + } else { + result.addError("❌ 私钥文件不存在: " + privateKeyPath); + } + + // 检查商户证书文件 + if (certificateLoader.certificateExists(apiclientCertPath)) { + result.addInfo("✅ 商户证书文件存在: " + apiclientCertPath); + } else { + result.addWarning("⚠️ 商户证书文件不存在: " + apiclientCertPath + " (自动证书配置不需要此文件)"); + } + + } else { + // 生产环境证书检查 + if (payment.getApiclientKey() != null) { + result.addInfo("私钥文件配置: " + payment.getApiclientKey()); + } else { + result.addError("生产环境私钥文件路径未配置"); + } + + if (payment.getApiclientCert() != null) { + result.addInfo("商户证书文件配置: " + payment.getApiclientCert()); + } else { + result.addWarning("生产环境商户证书文件路径未配置 (自动证书配置不需要此文件)"); + } + } + } + + /** + * 验证证书内容 + */ + private void validateCertificateContent(Payment payment, Integer tenantId, String environment, DiagnosticResult result) { + try { + if ("dev".equals(environment)) { + String tenantCertPath = "dev/wechat/" + tenantId; + String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); + + if (certificateLoader.certificateExists(apiclientCertPath)) { + validateX509Certificate(apiclientCertPath, payment.getMerchantSerialNumber(), result); + } + } + } catch (Exception e) { + result.addWarning("证书内容验证失败: " + e.getMessage()); + } + } + + /** + * 验证X509证书 + */ + private void validateX509Certificate(String certPath, String expectedSerialNumber, DiagnosticResult result) { + try { + String actualCertPath = certificateLoader.loadCertificatePath(certPath); + + try (InputStream inputStream = new FileInputStream(new File(actualCertPath))) { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); + + if (cert != null) { + String actualSerialNumber = cert.getSerialNumber().toString(16).toUpperCase(); + result.addInfo("证书序列号: " + actualSerialNumber); + result.addInfo("证书有效期: " + cert.getNotBefore() + " 至 " + cert.getNotAfter()); + result.addInfo("证书主体: " + cert.getSubjectX500Principal().toString()); + + // 检查序列号是否匹配 + if (expectedSerialNumber != null && !expectedSerialNumber.equalsIgnoreCase(actualSerialNumber)) { + result.addError("证书序列号不匹配! 配置: " + expectedSerialNumber + ", 实际: " + actualSerialNumber); + } else { + result.addInfo("✅ 证书序列号匹配"); + } + + // 检查证书是否过期 + long now = System.currentTimeMillis(); + if (now < cert.getNotBefore().getTime()) { + result.addError("证书尚未生效"); + } else if (now > cert.getNotAfter().getTime()) { + result.addError("证书已过期"); + } else { + result.addInfo("✅ 证书在有效期内"); + } + } else { + result.addError("无法解析证书文件"); + } + } + } catch (Exception e) { + result.addError("证书验证失败: " + e.getMessage()); + } + } + + /** + * 生成建议 + */ + private void generateRecommendations(DiagnosticResult result) { + if (result.hasErrors()) { + result.addRecommendation("🔧 修复建议:"); + + String errorText = result.getErrors(); + if (errorText.contains("商户号")) { + result.addRecommendation("1. 请在支付配置中设置正确的商户号"); + } + + if (errorText.contains("序列号")) { + result.addRecommendation("2. 请检查商户证书序列号是否正确,可在微信商户平台查看"); + } + + if (errorText.contains("证书文件")) { + result.addRecommendation("3. 请确保证书文件已正确放置在指定目录"); + } + + if (errorText.contains("过期")) { + result.addRecommendation("4. 请更新过期的证书文件"); + } + + result.addRecommendation("5. 建议使用RSAAutoCertificateConfig自动证书配置,可避免手动管理证书"); + result.addRecommendation("6. 确保在微信商户平台开启API安全功能并申请使用微信支付公钥"); + } else { + result.addRecommendation("✅ 证书配置正常,建议使用自动证书配置以获得最佳体验"); + } + } + + /** + * 诊断结果类 + */ + public static class DiagnosticResult { + private final StringBuilder errors = new StringBuilder(); + private final StringBuilder warnings = new StringBuilder(); + private final StringBuilder info = new StringBuilder(); + private final StringBuilder recommendations = new StringBuilder(); + + public void addError(String error) { + if (errors.length() > 0) errors.append("\n"); + errors.append(error); + } + + public void addWarning(String warning) { + if (warnings.length() > 0) warnings.append("\n"); + warnings.append(warning); + } + + public void addInfo(String information) { + if (info.length() > 0) info.append("\n"); + info.append(information); + } + + public void addRecommendation(String recommendation) { + if (recommendations.length() > 0) recommendations.append("\n"); + recommendations.append(recommendation); + } + + public boolean hasErrors() { + return errors.length() > 0; + } + + public String getErrors() { + return errors.toString(); + } + + public String getWarnings() { + return warnings.toString(); + } + + public String getInfo() { + return info.toString(); + } + + public String getRecommendations() { + return recommendations.toString(); + } + + public String getFullReport() { + StringBuilder report = new StringBuilder(); + report.append("=== 微信支付证书诊断报告 ===\n\n"); + + if (info.length() > 0) { + report.append("📋 基本信息:\n").append(info).append("\n\n"); + } + + if (warnings.length() > 0) { + report.append("⚠️ 警告:\n").append(warnings).append("\n\n"); + } + + if (errors.length() > 0) { + report.append("❌ 错误:\n").append(errors).append("\n\n"); + } + + if (recommendations.length() > 0) { + report.append("💡 建议:\n").append(recommendations).append("\n\n"); + } + + report.append("=== 诊断报告结束 ==="); + return report.toString(); + } + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateFixer.java b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateFixer.java new file mode 100644 index 0000000..af6e357 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateFixer.java @@ -0,0 +1,312 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.system.entity.Payment; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; + +/** + * 微信支付证书修复工具 + * 自动检测和修复常见的证书配置问题 + * + * @author 科技小王子 + * @since 2025-07-29 + */ +@Slf4j +@Component +public class WechatPayCertificateFixer { + + private final CertificateProperties certConfig; + private final CertificateLoader certificateLoader; + + public WechatPayCertificateFixer(CertificateProperties certConfig, CertificateLoader certificateLoader) { + this.certConfig = certConfig; + this.certificateLoader = certificateLoader; + } + + /** + * 自动修复证书配置问题 + * + * @param payment 支付配置 + * @param tenantId 租户ID + * @param environment 环境 + * @return 修复结果 + */ + public FixResult autoFixCertificateIssues(Payment payment, Integer tenantId, String environment) { + FixResult result = new FixResult(); + + log.info("开始自动修复租户 {} 的证书配置问题", tenantId); + + try { + // 1. 检查并修复基本配置 + fixBasicConfiguration(payment, result); + + // 2. 检查并修复证书文件问题 + fixCertificateFiles(payment, tenantId, environment, result); + + // 3. 检查并修复序列号问题 + fixSerialNumberIssues(payment, tenantId, environment, result); + + // 4. 生成修复建议 + generateFixRecommendations(result); + + } catch (Exception e) { + result.addError("修复过程中发生异常: " + e.getMessage()); + log.error("证书修复异常", e); + } + + log.info("证书配置修复完成,成功修复 {} 个问题", result.getFixedIssues().size()); + return result; + } + + /** + * 修复基本配置问题 + */ + private void fixBasicConfiguration(Payment payment, FixResult result) { + if (payment == null) { + result.addError("支付配置为空,无法修复"); + return; + } + + // 检查商户号 + if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) { + result.addError("商户号未配置,需要手动设置"); + } + + // 检查应用ID + if (payment.getAppId() == null || payment.getAppId().trim().isEmpty()) { + result.addError("应用ID未配置,需要手动设置"); + } + + // 检查APIv3密钥 + if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) { + result.addWarning("APIv3密钥未配置,将使用配置文件默认值"); + } else if (payment.getApiKey().length() != 32) { + result.addError("APIv3密钥长度错误,应为32位,实际为: " + payment.getApiKey().length()); + } + + // 检查商户证书序列号 + if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { + result.addError("商户证书序列号未配置,需要手动设置"); + } + } + + /** + * 修复证书文件问题 + */ + private void fixCertificateFiles(Payment payment, Integer tenantId, String environment, FixResult result) { + if ("dev".equals(environment)) { + fixDevCertificateFiles(tenantId, result); + } else { + fixProdCertificateFiles(payment, result); + } + } + + /** + * 修复开发环境证书文件问题 + */ + private void fixDevCertificateFiles(Integer tenantId, FixResult result) { + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); + + // 检查私钥文件 + if (!certificateLoader.certificateExists(privateKeyPath)) { + result.addError("私钥文件不存在: " + privateKeyPath); + result.addRecommendation("请将 apiclient_key.pem 文件放置到 src/main/resources/" + privateKeyPath); + } else { + result.addFixed("私钥文件存在: " + privateKeyPath); + + // 尝试加载私钥文件 + try { + String privateKeyFile = certificateLoader.loadCertificatePath(privateKeyPath); + result.addFixed("私钥文件加载成功: " + privateKeyFile); + } catch (Exception e) { + result.addError("私钥文件加载失败: " + e.getMessage()); + } + } + + // 检查商户证书文件(可选) + if (!certificateLoader.certificateExists(apiclientCertPath)) { + result.addWarning("商户证书文件不存在: " + apiclientCertPath + " (自动证书配置不需要此文件)"); + } else { + result.addFixed("商户证书文件存在: " + apiclientCertPath); + } + } + + /** + * 修复生产环境证书文件问题 + */ + private void fixProdCertificateFiles(Payment payment, FixResult result) { + if (payment.getApiclientKey() == null || payment.getApiclientKey().trim().isEmpty()) { + result.addError("生产环境私钥文件路径未配置"); + } else { + result.addFixed("生产环境私钥文件路径已配置: " + payment.getApiclientKey()); + } + + if (payment.getApiclientCert() == null || payment.getApiclientCert().trim().isEmpty()) { + result.addWarning("生产环境商户证书文件路径未配置 (自动证书配置不需要此文件)"); + } else { + result.addFixed("生产环境商户证书文件路径已配置: " + payment.getApiclientCert()); + } + } + + /** + * 修复序列号问题 + */ + private void fixSerialNumberIssues(Payment payment, Integer tenantId, String environment, FixResult result) { + if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { + result.addError("商户证书序列号未配置"); + return; + } + + // 在开发环境中,尝试从证书文件中提取序列号进行验证 + if ("dev".equals(environment)) { + try { + String tenantCertPath = "dev/wechat/" + tenantId; + String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); + + if (certificateLoader.certificateExists(apiclientCertPath)) { + String actualCertPath = certificateLoader.loadCertificatePath(apiclientCertPath); + + try (InputStream inputStream = new FileInputStream(new File(actualCertPath))) { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); + + if (cert != null) { + String actualSerialNumber = cert.getSerialNumber().toString(16).toUpperCase(); + String configuredSerialNumber = payment.getMerchantSerialNumber(); + + if (!configuredSerialNumber.equalsIgnoreCase(actualSerialNumber)) { + result.addError("证书序列号不匹配! 配置: " + configuredSerialNumber + ", 实际: " + actualSerialNumber); + result.addRecommendation("建议将商户证书序列号更新为: " + actualSerialNumber); + } else { + result.addFixed("证书序列号匹配: " + actualSerialNumber); + } + } + } + } + } catch (Exception e) { + result.addWarning("无法验证证书序列号: " + e.getMessage()); + } + } + } + + /** + * 生成修复建议 + */ + private void generateFixRecommendations(FixResult result) { + if (result.hasErrors()) { + result.addRecommendation("=== 修复建议 ==="); + + if (result.getErrors().stream().anyMatch(e -> e.contains("商户号"))) { + result.addRecommendation("1. 请在微信商户平台获取商户号并在系统中配置"); + } + + if (result.getErrors().stream().anyMatch(e -> e.contains("应用ID"))) { + result.addRecommendation("2. 请在微信开放平台获取应用ID并在系统中配置"); + } + + if (result.getErrors().stream().anyMatch(e -> e.contains("APIv3密钥"))) { + result.addRecommendation("3. 请在微信商户平台设置32位APIv3密钥"); + } + + if (result.getErrors().stream().anyMatch(e -> e.contains("证书序列号"))) { + result.addRecommendation("4. 请在微信商户平台查看正确的商户证书序列号"); + } + + if (result.getErrors().stream().anyMatch(e -> e.contains("私钥文件"))) { + result.addRecommendation("5. 请从微信商户平台下载私钥文件并放置到正确位置"); + } + + result.addRecommendation("6. 建议使用RSAAutoCertificateConfig自动证书配置"); + result.addRecommendation("7. 确保在微信商户平台开启API安全功能"); + } + } + + /** + * 修复结果类 + */ + public static class FixResult { + private final List errors = new ArrayList<>(); + private final List warnings = new ArrayList<>(); + private final List fixedIssues = new ArrayList<>(); + private final List recommendations = new ArrayList<>(); + + public void addError(String error) { + errors.add(error); + } + + public void addWarning(String warning) { + warnings.add(warning); + } + + public void addFixed(String fixed) { + fixedIssues.add(fixed); + } + + public void addRecommendation(String recommendation) { + recommendations.add(recommendation); + } + + public boolean hasErrors() { + return !errors.isEmpty(); + } + + public List getErrors() { + return errors; + } + + public List getWarnings() { + return warnings; + } + + public List getFixedIssues() { + return fixedIssues; + } + + public List getRecommendations() { + return recommendations; + } + + public String getFullReport() { + StringBuilder report = new StringBuilder(); + report.append("=== 微信支付证书修复报告 ===\n\n"); + + if (!fixedIssues.isEmpty()) { + report.append("✅ 已修复的问题:\n"); + fixedIssues.forEach(issue -> report.append(" - ").append(issue).append("\n")); + report.append("\n"); + } + + if (!warnings.isEmpty()) { + report.append("⚠️ 警告:\n"); + warnings.forEach(warning -> report.append(" - ").append(warning).append("\n")); + report.append("\n"); + } + + if (!errors.isEmpty()) { + report.append("❌ 需要手动修复的问题:\n"); + errors.forEach(error -> report.append(" - ").append(error).append("\n")); + report.append("\n"); + } + + if (!recommendations.isEmpty()) { + report.append("💡 修复建议:\n"); + recommendations.forEach(rec -> report.append(" ").append(rec).append("\n")); + report.append("\n"); + } + + report.append("=== 修复报告结束 ==="); + return report.toString(); + } + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigChecker.java b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigChecker.java new file mode 100644 index 0000000..74a6fa4 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigChecker.java @@ -0,0 +1,243 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.core.service.PaymentCacheService; +import com.gxwebsoft.common.system.entity.Payment; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * 微信支付配置检查器 + * 用于快速检查和验证微信支付配置状态 + * + * @author 科技小王子 + * @since 2025-07-29 + */ +@Slf4j +@Component +public class WechatPayConfigChecker { + + @Autowired + private PaymentCacheService paymentCacheService; + + @Autowired + private CertificateLoader certificateLoader; + + @Autowired + private CertificateProperties certConfig; + + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + /** + * 检查租户的微信支付配置状态 + * + * @param tenantId 租户ID + * @return 配置状态报告 + */ + public ConfigStatus checkTenantConfig(Integer tenantId) { + ConfigStatus status = new ConfigStatus(); + status.tenantId = tenantId; + status.environment = activeProfile; + + try { + // 获取支付配置 + Payment payment = paymentCacheService.getWechatPayConfig(tenantId); + if (payment == null) { + status.hasError = true; + status.errorMessage = "支付配置不存在"; + return status; + } + + status.merchantId = payment.getMchId(); + status.appId = payment.getAppId(); + status.serialNumber = payment.getMerchantSerialNumber(); + status.hasApiKey = payment.getApiKey() != null && !payment.getApiKey().isEmpty(); + status.apiKeyLength = payment.getApiKey() != null ? payment.getApiKey().length() : 0; + + // 检查公钥配置 + if (payment.getPubKey() != null && !payment.getPubKey().isEmpty() && + payment.getPubKeyId() != null && !payment.getPubKeyId().isEmpty()) { + + status.hasPublicKey = true; + status.publicKeyFile = payment.getPubKey(); + status.publicKeyId = payment.getPubKeyId(); + status.configMode = "公钥模式"; + + // 检查公钥文件是否存在 + String tenantCertPath = "dev/wechat/" + tenantId; + String pubKeyPath = tenantCertPath + "/" + payment.getPubKey(); + status.publicKeyExists = certificateLoader.certificateExists(pubKeyPath); + + } else { + status.hasPublicKey = false; + status.configMode = "自动证书模式"; + } + + // 检查私钥文件 + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + status.privateKeyExists = certificateLoader.certificateExists(privateKeyPath); + + // 检查商户证书文件 + String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); + status.merchantCertExists = certificateLoader.certificateExists(apiclientCertPath); + + // 评估配置完整性 + evaluateConfigCompleteness(status); + + } catch (Exception e) { + status.hasError = true; + status.errorMessage = "检查配置时发生异常: " + e.getMessage(); + log.error("检查租户 {} 配置时发生异常", tenantId, e); + } + + return status; + } + + /** + * 评估配置完整性 + */ + private void evaluateConfigCompleteness(ConfigStatus status) { + if (status.hasError) { + return; + } + + // 基本配置检查 + if (status.merchantId == null || status.merchantId.isEmpty()) { + status.addIssue("商户号未配置"); + } + + if (status.appId == null || status.appId.isEmpty()) { + status.addIssue("应用ID未配置"); + } + + if (status.serialNumber == null || status.serialNumber.isEmpty()) { + status.addIssue("商户证书序列号未配置"); + } + + if (!status.hasApiKey) { + status.addIssue("APIv3密钥未配置"); + } else if (status.apiKeyLength != 32) { + status.addIssue("APIv3密钥长度错误,应为32位,实际为" + status.apiKeyLength + "位"); + } + + if (!status.privateKeyExists) { + status.addIssue("私钥文件不存在"); + } + + // 公钥模式特定检查 + if (status.hasPublicKey) { + if (!status.publicKeyExists) { + status.addIssue("公钥文件不存在"); + } + } + + // 设置配置状态 + if (status.issues.isEmpty()) { + status.configComplete = true; + status.recommendation = "✅ 配置完整,建议使用当前配置"; + } else { + status.configComplete = false; + if (status.hasPublicKey) { + status.recommendation = "⚠️ 公钥配置不完整,建议修复问题或回退到自动证书模式"; + } else { + status.recommendation = "⚠️ 自动证书配置不完整,建议配置公钥模式或修复当前问题"; + } + } + } + + /** + * 生成配置建议 + */ + public String generateConfigAdvice(Integer tenantId) { + ConfigStatus status = checkTenantConfig(tenantId); + + StringBuilder advice = new StringBuilder(); + advice.append("=== 租户 ").append(tenantId).append(" 微信支付配置建议 ===\n\n"); + + advice.append("当前配置模式: ").append(status.configMode).append("\n"); + advice.append("配置完整性: ").append(status.configComplete ? "完整" : "不完整").append("\n\n"); + + if (status.hasError) { + advice.append("❌ 错误: ").append(status.errorMessage).append("\n\n"); + return advice.toString(); + } + + // 基本信息 + advice.append("📋 基本信息:\n"); + advice.append(" 商户号: ").append(status.merchantId).append("\n"); + advice.append(" 应用ID: ").append(status.appId).append("\n"); + advice.append(" 序列号: ").append(status.serialNumber).append("\n"); + advice.append(" API密钥: ").append(status.hasApiKey ? "已配置(" + status.apiKeyLength + "位)" : "未配置").append("\n\n"); + + // 证书文件状态 + advice.append("📁 证书文件状态:\n"); + advice.append(" 私钥文件: ").append(status.privateKeyExists ? "✅ 存在" : "❌ 不存在").append("\n"); + advice.append(" 商户证书: ").append(status.merchantCertExists ? "✅ 存在" : "⚠️ 不存在").append("\n"); + + if (status.hasPublicKey) { + advice.append(" 公钥文件: ").append(status.publicKeyExists ? "✅ 存在" : "❌ 不存在").append("\n"); + advice.append(" 公钥ID: ").append(status.publicKeyId).append("\n"); + } + advice.append("\n"); + + // 问题列表 + if (!status.issues.isEmpty()) { + advice.append("⚠️ 发现的问题:\n"); + for (String issue : status.issues) { + advice.append(" - ").append(issue).append("\n"); + } + advice.append("\n"); + } + + // 建议 + advice.append("💡 建议:\n"); + advice.append(" ").append(status.recommendation).append("\n\n"); + + if (!status.hasPublicKey) { + advice.append("🔧 配置公钥模式的步骤:\n"); + advice.append(" 1. 获取微信支付平台公钥文件和公钥ID\n"); + advice.append(" 2. 将公钥文件放置到: src/main/resources/dev/wechat/").append(tenantId).append("/\n"); + advice.append(" 3. 执行SQL更新数据库配置:\n"); + advice.append(" UPDATE sys_payment SET \n"); + advice.append(" pub_key = 'wechatpay_public_key.pem',\n"); + advice.append(" pub_key_id = 'YOUR_PUBLIC_KEY_ID'\n"); + advice.append(" WHERE tenant_id = ").append(tenantId).append(" AND type = 0;\n\n"); + } + + advice.append("=== 配置建议结束 ==="); + return advice.toString(); + } + + /** + * 配置状态类 + */ + public static class ConfigStatus { + public Integer tenantId; + public String environment; + public String merchantId; + public String appId; + public String serialNumber; + public boolean hasApiKey; + public int apiKeyLength; + public boolean hasPublicKey; + public String publicKeyFile; + public String publicKeyId; + public boolean publicKeyExists; + public boolean privateKeyExists; + public boolean merchantCertExists; + public String configMode; + public boolean configComplete; + public boolean hasError; + public String errorMessage; + public String recommendation; + public java.util.List issues = new java.util.ArrayList<>(); + + public void addIssue(String issue) { + issues.add(issue); + } + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java new file mode 100644 index 0000000..23326d2 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java @@ -0,0 +1,223 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.system.entity.Payment; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +/** + * 微信支付配置验证工具 + * + * @author 科技小王子 + * @since 2025-07-27 + */ +@Slf4j +@Component +public class WechatPayConfigValidator { + + private final CertificateProperties certConfig; + private final CertificateLoader certificateLoader; + + @Value("${spring.profiles.active}") + private String activeProfile; + + public WechatPayConfigValidator(CertificateProperties certConfig, CertificateLoader certificateLoader) { + this.certConfig = certConfig; + this.certificateLoader = certificateLoader; + } + + /** + * 验证微信支付配置 + * + * @param payment 支付配置 + * @param tenantId 租户ID + * @return 验证结果 + */ + public ValidationResult validateWechatPayConfig(Payment payment, Integer tenantId) { + ValidationResult result = new ValidationResult(); + + log.info("开始验证微信支付配置 - 租户ID: {}", tenantId); + + // 1. 验证基本配置 + if (payment == null) { + result.addError("支付配置为空"); + return result; + } + + if (!StringUtils.hasText(payment.getMchId())) { + result.addError("商户号未配置"); + } + + if (!StringUtils.hasText(payment.getAppId())) { + result.addError("应用ID未配置"); + } + + if (!StringUtils.hasText(payment.getMerchantSerialNumber())) { + result.addError("商户证书序列号未配置"); + } + + // 2. 验证 APIv3 密钥 + String apiV3Key = getValidApiV3Key(payment); + if (!StringUtils.hasText(apiV3Key)) { + result.addError("APIv3密钥未配置"); + } else { + validateApiV3Key(apiV3Key, result); + } + + // 3. 验证证书文件 + validateCertificateFiles(tenantId, result); + + // 4. 记录验证结果 + if (result.isValid()) { + log.info("✅ 微信支付配置验证通过 - 租户ID: {}", tenantId); + } else { + log.error("❌ 微信支付配置验证失败 - 租户ID: {}, 错误: {}", tenantId, result.getErrors()); + } + + return result; + } + + /** + * 获取有效的 APIv3 密钥 + * 优先使用数据库配置,如果为空则使用配置文件默认值 + */ + public String getValidApiV3Key(Payment payment) { + String apiV3Key = payment.getApiKey(); + + if (!StringUtils.hasText(apiV3Key)) { + apiV3Key = certConfig.getWechatPay().getDev().getApiV3Key(); + log.warn("数据库中APIv3密钥为空,使用配置文件默认值"); + } + + return apiV3Key; + } + + /** + * 验证 APIv3 密钥格式 + */ + private void validateApiV3Key(String apiV3Key, ValidationResult result) { + if (apiV3Key.length() != 32) { + result.addError("APIv3密钥长度错误,应为32位,实际为: " + apiV3Key.length()); + } + + if (!apiV3Key.matches("^[a-zA-Z0-9]+$")) { + result.addError("APIv3密钥格式错误,应仅包含字母和数字"); + } + + log.info("APIv3密钥验证 - 长度: {}, 格式: {}", + apiV3Key.length(), + apiV3Key.matches("^[a-zA-Z0-9]+$") ? "正确" : "错误"); + } + + /** + * 验证证书文件 + */ + private void validateCertificateFiles(Integer tenantId, ValidationResult result) { + if ("dev".equals(activeProfile)) { + // 开发环境证书验证 + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + + if (!certificateLoader.certificateExists(privateKeyPath)) { + result.addError("证书文件不存在: " + privateKeyPath); + return; + } + + try { + certificateLoader.loadCertificatePath(privateKeyPath); + log.info("✅ 开发环境证书文件验证通过: {}", privateKeyPath); + } catch (Exception e) { + result.addError("证书文件加载失败: " + e.getMessage()); + } + } else { + // 生产环境证书验证 - 跳过文件存在性检查,因为证书路径来自数据库 + log.info("✅ 生产环境跳过证书文件存在性验证,使用数据库配置的证书路径"); + } + } + + /** + * 验证结果类 + */ + public static class ValidationResult { + private boolean valid = true; + private StringBuilder errors = new StringBuilder(); + + public void addError(String error) { + this.valid = false; + if (errors.length() > 0) { + errors.append("; "); + } + errors.append(error); + } + + public boolean isValid() { + return valid; + } + + public String getErrors() { + return errors.toString(); + } + + public void logErrors() { + if (!valid) { + log.error("配置验证失败: {}", errors.toString()); + } + } + } + + /** + * 生成配置诊断报告 + */ + public String generateDiagnosticReport(Payment payment, Integer tenantId) { + StringBuilder report = new StringBuilder(); + report.append("=== 微信支付配置诊断报告 ===\n"); + report.append("租户ID: ").append(tenantId).append("\n"); + + if (payment != null) { + report.append("商户号: ").append(payment.getMchId()).append("\n"); + report.append("应用ID: ").append(payment.getAppId()).append("\n"); + report.append("商户证书序列号: ").append(payment.getMerchantSerialNumber()).append("\n"); + + String dbApiKey = payment.getApiKey(); + String configApiKey = certConfig.getWechatPay().getDev().getApiV3Key(); + + report.append("数据库APIv3密钥: ").append(dbApiKey != null ? "已配置(" + dbApiKey.length() + "位)" : "未配置").append("\n"); + report.append("配置文件APIv3密钥: ").append(configApiKey != null ? "已配置(" + configApiKey.length() + "位)" : "未配置").append("\n"); + + String finalApiKey = getValidApiV3Key(payment); + report.append("最终使用APIv3密钥: ").append(finalApiKey != null ? "已配置(" + finalApiKey.length() + "位)" : "未配置").append("\n"); + + } else { + report.append("❌ 支付配置为空\n"); + } + + // 证书文件检查 + report.append("当前环境: ").append(activeProfile).append("\n"); + if ("dev".equals(activeProfile)) { + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + boolean certExists = certificateLoader.certificateExists(privateKeyPath); + + report.append("开发环境证书文件路径: ").append(privateKeyPath).append("\n"); + report.append("证书文件存在: ").append(certExists ? "是" : "否").append("\n"); + } else { + report.append("生产环境证书路径: 从数据库配置获取\n"); + if (payment != null) { + report.append("私钥文件: ").append(payment.getApiclientKey()).append("\n"); + report.append("证书文件: ").append(payment.getApiclientCert()).append("\n"); + } + } + + ValidationResult validation = validateWechatPayConfig(payment, tenantId); + report.append("配置验证结果: ").append(validation.isValid() ? "通过" : "失败").append("\n"); + if (!validation.isValid()) { + report.append("验证错误: ").append(validation.getErrors()).append("\n"); + } + + report.append("=== 诊断报告结束 ==="); + + return report.toString(); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WechatPayDiagnostic.java b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayDiagnostic.java new file mode 100644 index 0000000..620d506 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayDiagnostic.java @@ -0,0 +1,222 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.common.system.entity.Payment; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * 微信支付配置诊断工具 + * 用于排查微信支付签名验证失败等问题 + * + * @author 科技小王子 + * @since 2025-07-27 + */ +@Slf4j +@Component +public class WechatPayDiagnostic { + + /** + * 诊断微信支付配置 + * + * @param payment 支付配置 + * @param privateKeyPath 私钥路径 + * @param environment 环境标识 + */ + public void diagnosePaymentConfig(Payment payment, String privateKeyPath, String environment) { + log.info("=== 微信支付配置诊断开始 ==="); + log.info("环境: {}", environment); + + // 1. 检查支付配置基本信息 + checkBasicConfig(payment); + + // 2. 检查证书文件 + checkCertificateFiles(payment, privateKeyPath, environment); + + // 3. 检查配置完整性 + checkConfigCompleteness(payment); + + log.info("=== 微信支付配置诊断结束 ==="); + } + + /** + * 检查基本配置信息 + */ + private void checkBasicConfig(Payment payment) { + log.info("--- 基本配置检查 ---"); + + if (payment == null) { + log.error("❌ 支付配置为空"); + return; + } + + log.info("支付配置ID: {}", payment.getId()); + log.info("支付方式名称: {}", payment.getName()); + log.info("支付类型: {}", payment.getType()); + log.info("支付代码: {}", payment.getCode()); + log.info("状态: {}", payment.getStatus()); + + // 检查关键字段 + checkField("应用ID", payment.getAppId()); + checkField("商户号", payment.getMchId()); + checkField("商户证书序列号", payment.getMerchantSerialNumber()); + checkField("API密钥", payment.getApiKey(), true); + } + + /** + * 检查证书文件 + */ + private void checkCertificateFiles(Payment payment, String privateKeyPath, String environment) { + log.info("--- 证书文件检查 ---"); + + // 检查私钥文件 + if (privateKeyPath != null) { + checkFileExists("私钥文件", privateKeyPath); + } + + // 生产环境检查证书文件 + if (!"dev".equals(environment)) { + if (payment.getApiclientCert() != null) { + log.info("商户证书文件配置: {}", payment.getApiclientCert()); + } + + if (payment.getPubKey() != null) { + log.info("公钥文件配置: {}", payment.getPubKey()); + log.info("公钥ID: {}", payment.getPubKeyId()); + } + } + } + + /** + * 检查配置完整性 + */ + private void checkConfigCompleteness(Payment payment) { + log.info("--- 配置完整性检查 ---"); + + boolean isComplete = true; + + if (isEmpty(payment.getMchId())) { + log.error("❌ 商户号未配置"); + isComplete = false; + } + + if (isEmpty(payment.getMerchantSerialNumber())) { + log.error("❌ 商户证书序列号未配置"); + isComplete = false; + } + + if (isEmpty(payment.getApiKey())) { + log.error("❌ API密钥未配置"); + isComplete = false; + } + + if (isEmpty(payment.getAppId())) { + log.error("❌ 应用ID未配置"); + isComplete = false; + } + + if (isComplete) { + log.info("✅ 配置完整性检查通过"); + } else { + log.error("❌ 配置不完整,请补充缺失的配置项"); + } + } + + /** + * 检查字段是否为空 + */ + private void checkField(String fieldName, String value) { + checkField(fieldName, value, false); + } + + /** + * 检查字段是否为空 + */ + private void checkField(String fieldName, String value, boolean isSensitive) { + if (isEmpty(value)) { + log.warn("⚠️ {}: 未配置", fieldName); + } else { + if (isSensitive) { + log.info("✅ {}: 已配置(长度:{})", fieldName, value.length()); + } else { + log.info("✅ {}: {}", fieldName, value); + } + } + } + + /** + * 检查文件是否存在 + */ + private void checkFileExists(String fileName, String filePath) { + try { + File file = new File(filePath); + if (file.exists() && file.isFile()) { + log.info("✅ {}: 文件存在 - {}", fileName, filePath); + log.info(" 文件大小: {} bytes", file.length()); + + // 检查文件内容格式 + if (filePath.endsWith(".pem")) { + checkPemFileFormat(fileName, filePath); + } + } else { + log.error("❌ {}: 文件不存在 - {}", fileName, filePath); + } + } catch (Exception e) { + log.error("❌ {}: 检查文件时出错 - {} ({})", fileName, filePath, e.getMessage()); + } + } + + /** + * 检查PEM文件格式 + */ + private void checkPemFileFormat(String fileName, String filePath) { + try { + String content = Files.readString(Paths.get(filePath)); + if (content.contains("-----BEGIN") && content.contains("-----END")) { + log.info("✅ {}: PEM格式正确", fileName); + } else { + log.warn("⚠️ {}: PEM格式可能有问题", fileName); + } + } catch (Exception e) { + log.warn("⚠️ {}: 无法读取文件内容进行格式检查 ({})", fileName, e.getMessage()); + } + } + + /** + * 检查字符串是否为空 + */ + private boolean isEmpty(String str) { + return str == null || str.trim().isEmpty(); + } + + /** + * 生成诊断报告 + */ + public String generateDiagnosticReport(Payment payment, String environment) { + StringBuilder report = new StringBuilder(); + report.append("🔍 微信支付配置诊断报告\n"); + report.append("========================\n\n"); + + report.append("环境: ").append(environment).append("\n"); + report.append("租户ID: ").append(payment != null ? payment.getTenantId() : "未知").append("\n"); + report.append("商户号: ").append(payment != null ? payment.getMchId() : "未配置").append("\n"); + report.append("应用ID: ").append(payment != null ? payment.getAppId() : "未配置").append("\n\n"); + + report.append("🚨 常见问题排查:\n"); + report.append("1. 商户证书序列号是否正确\n"); + report.append("2. APIv3密钥是否正确\n"); + report.append("3. 私钥文件是否正确\n"); + report.append("4. 微信支付平台证书是否过期\n"); + report.append("5. 网络连接是否正常\n\n"); + + report.append("💡 建议解决方案:\n"); + report.append("1. 使用自动证书配置(RSAAutoCertificateConfig)\n"); + report.append("2. 在微信商户平台重新下载证书\n"); + report.append("3. 检查商户平台API安全设置\n"); + + return report.toString(); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WechatPayUtils.java b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayUtils.java new file mode 100644 index 0000000..14a31e9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayUtils.java @@ -0,0 +1,111 @@ +package com.gxwebsoft.common.core.utils; + +import java.nio.charset.StandardCharsets; + +/** + * 微信支付工具类 + * 处理微信支付API的字段限制和格式要求 + * + * @author 科技小王子 + * @since 2025-01-11 + */ +public class WechatPayUtils { + + /** + * 微信支付description字段的最大字节数限制 + */ + public static final int DESCRIPTION_MAX_BYTES = 127; + + /** + * 微信支付attach字段的最大字节数限制 + */ + public static final int ATTACH_MAX_BYTES = 127; + + /** + * 截断字符串以确保字节数不超过指定限制 + * 主要用于微信支付API的字段限制处理 + * + * @param text 原始文本 + * @param maxBytes 最大字节数 + * @return 截断后的文本,确保UTF-8字符完整性 + */ + public static String truncateToByteLimit(String text, int maxBytes) { + if (text == null || text.isEmpty()) { + return text; + } + + byte[] bytes = text.getBytes(StandardCharsets.UTF_8); + if (bytes.length <= maxBytes) { + return text; + } + + // 截断字节数组,但要确保不会截断UTF-8字符的中间 + int truncateLength = maxBytes; + while (truncateLength > 0) { + byte[] truncated = new byte[truncateLength]; + System.arraycopy(bytes, 0, truncated, 0, truncateLength); + + try { + String result = new String(truncated, StandardCharsets.UTF_8); + // 检查是否有无效字符(被截断的UTF-8字符) + if (!result.contains("\uFFFD")) { + return result; + } + } catch (Exception e) { + // 继续尝试更短的长度 + } + truncateLength--; + } + + return ""; // 如果无法安全截断,返回空字符串 + } + + /** + * 处理微信支付商品描述字段 + * 确保字节数不超过127字节 + * + * @param description 商品描述 + * @return 处理后的描述,符合微信支付要求 + */ + public static String processDescription(String description) { + return truncateToByteLimit(description, DESCRIPTION_MAX_BYTES); + } + + /** + * 处理微信支付附加数据字段 + * 确保字节数不超过127字节 + * + * @param attach 附加数据 + * @return 处理后的附加数据,符合微信支付要求 + */ + public static String processAttach(String attach) { + return truncateToByteLimit(attach, ATTACH_MAX_BYTES); + } + + /** + * 验证字符串是否符合微信支付字段的字节限制 + * + * @param text 待验证的文本 + * @param maxBytes 最大字节数限制 + * @return true如果符合限制,false如果超出限制 + */ + public static boolean isWithinByteLimit(String text, int maxBytes) { + if (text == null) { + return true; + } + return text.getBytes(StandardCharsets.UTF_8).length <= maxBytes; + } + + /** + * 获取字符串的UTF-8字节数 + * + * @param text 文本 + * @return 字节数 + */ + public static int getByteLength(String text) { + if (text == null) { + return 0; + } + return text.getBytes(StandardCharsets.UTF_8).length; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WxNativeUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/WxNativeUtil.java new file mode 100644 index 0000000..52a8d2c --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/WxNativeUtil.java @@ -0,0 +1,20 @@ +package com.gxwebsoft.common.core.utils; + +import com.wechat.pay.java.core.Config; + +import java.util.HashMap; +import java.util.Map; + + +public class WxNativeUtil { + + private static final Map tenantConfigs = new HashMap<>(); + + public static void addConfig(Integer tenantId, Config config) { + tenantConfigs.put(tenantId, config); + } + + public static Config getConfig(Integer tenantId) { + return tenantConfigs.get(tenantId); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java new file mode 100644 index 0000000..4f10747 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java @@ -0,0 +1,106 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.system.service.SettingService; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +/** + * 微信公众号工具类 + * @author 科技小王子 + * + */ +@Component +public class WxOfficialUtil { + private final StringRedisTemplate stringRedisTemplate; + private Integer tenantId; + public String appId; + public String appSecret; + public String openid; + public String unionid; + public String access_token; + public String expires_in; + public String nickname; + + + @Resource + private SettingService settingService; + @Resource + private ConfigProperties pathConfig; + @Resource + private CacheClient cacheClient; + + public WxOfficialUtil(StringRedisTemplate stringRedisTemplate){ + this.stringRedisTemplate = stringRedisTemplate; + } + + // 实例化客户端 + public WxOfficialUtil client(Integer tenantId) { + if(tenantId > 0){ + throw new BusinessException(tenantId + "123123"); + } + this.tenantId = tenantId; + this.config(); + System.out.println("this.tenantId = " + this.tenantId); + return this; + } + + // 开发者ID和秘钥 + private void config() { + String key = "cache"+ this.tenantId +":setting:wx-official"; + String wxOfficial = stringRedisTemplate.opsForValue().get(key); + JSONObject data = JSONObject.parseObject(wxOfficial); + if(data != null){ + this.appId = data.getString("appId"); + this.appSecret = data.getString("appSecret"); + } + System.out.println("this.appId = " + this.appId); + System.out.println("this.appSecret = " + this.appSecret); + } + + // 获取appId + public String getAppSecret(){ + return this.appSecret; + } + + public String getCodeUrl() throws UnsupportedEncodingException { + String encodedReturnUrl = URLEncoder.encode(pathConfig.getServerUrl() + "/open/wx-official/accessToken","UTF-8"); + return "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+ this.appId +"&redirect_uri=" + encodedReturnUrl + "&response_type=code&scope=snsapi_userinfo&state="+ this.tenantId +"#wechat_redirect"; + } + + // 获取access_token + public String getAccessToken(String code) { + String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ this.appId +"&secret="+ this.appSecret +"&code="+ code +"&grant_type=authorization_code"; + System.out.println("url = " + url); + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + final JSONObject jsonObject = JSONObject.parseObject(response); + access_token = jsonObject.getString("access_token"); + if(access_token == null){ + throw new BusinessException("获取access_token失败"); + } + this.openid = jsonObject.getString("openid"); + this.unionid = jsonObject.getString("unionid"); + this.expires_in = jsonObject.getString("expires_in"); + return access_token; + } + + // 获取userinfo + public JSONObject getUserInfo(String access_token) { + String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+ access_token +"&openid="+ this.openid +"&lang=zh_CN"; + System.out.println("url2 = " + url); + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + System.out.println("response = " + response); + if(response == null){ + throw new BusinessException("获取userinfo失败"); + } + return JSONObject.parseObject(response); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WxUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/WxUtil.java new file mode 100644 index 0000000..035ce91 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/WxUtil.java @@ -0,0 +1,132 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.exception.BusinessException; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +/** + * 微信小程序工具类 + * @author 科技小王子 + * + */ +@Component +public class WxUtil { + private final StringRedisTemplate stringRedisTemplate; + private Integer tenantId; + public String appId; + public String appSecret; + public String access_token; + public String expires_in; + public String nickname; + public String userid; + public String user_ticket; + public String openid; + public String external_userid; + public String name; + public String position; + public String mobile; + public String gender; + public String email; + public String avatar; + public String thumb_avatar; + public String telephone; + public String address; + public String alias; + public String qr_code; + public String open_userid; + + @Resource + private CacheClient cacheClient; + + + public WxUtil(StringRedisTemplate stringRedisTemplate){ + this.stringRedisTemplate = stringRedisTemplate; + } + + + // 实例化客户端 + public WxUtil client(Integer tenantId) { + this.tenantId = tenantId; + this.config(); + return this; + } + + // 开发者ID和秘钥 + private void config() { + JSONObject settingInfo = cacheClient.getSettingInfo("wx-work", this.tenantId); + if(settingInfo == null){ + throw new BusinessException("微信小程序未配置"); + } + this.appId = settingInfo.getString("corpId"); + this.appSecret = settingInfo.getString("secret"); + System.out.println("this.appId = " + this.appId); + System.out.println("this.appSecret = " + this.appSecret); + } + + // 获取access_token + public void getAccessToken(String code) { + String key = "cache"+ this.tenantId +":ww:access_token"; + final String access_token = stringRedisTemplate.opsForValue().get(key); + if(access_token != null){ + this.getUserInfo(code,access_token); + }else { + String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" +this.appId+ "&corpsecret="+ this.appSecret; + System.out.println("url = " + url); + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + System.out.println("response = " + response); + final JSONObject jsonObject = JSONObject.parseObject(response); + // 获取成功 + if(jsonObject.getString("access_token") != null){ + this.access_token = jsonObject.getString("access_token"); + this.expires_in = jsonObject.getString("expires_in"); + stringRedisTemplate.opsForValue().set(key,this.access_token,7000, TimeUnit.SECONDS); + System.out.println("获取access_token成功 = " + this.access_token); + this.getUserInfo(code,this.access_token); + } + } + } + + // 获取userinfo + public void getUserInfo(String code, String access_token) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=" +access_token+ "&code=" + code; + System.out.println("url2 = " + url); + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + JSONObject jsonObject = JSONObject.parseObject(response); + final String errcode = jsonObject.getString("errcode"); + final String errmsg = jsonObject.getString("errmsg"); + if(!StrUtil.equals(errcode,"0")){ + throw new BusinessException(errmsg); + } + this.userid = jsonObject.getString("userid"); + this.user_ticket = jsonObject.getString("user_ticket"); + this.openid = jsonObject.getString("openid"); + this.external_userid = jsonObject.getString("external_userid"); + } + + public void getUserProfile(String userid, String access_token) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token="+ access_token +"&userid=" + userid; + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + JSONObject jsonObject = JSONObject.parseObject(response); + + this.name = jsonObject.getString("name"); + this.position = jsonObject.getString("position"); + this.gender = jsonObject.getString("gender"); + this.email = jsonObject.getString("email"); + this.avatar = jsonObject.getString("avatar"); + this.thumb_avatar = jsonObject.getString("thumb_avatar"); + this.telephone = jsonObject.getString("telephone"); + this.address = jsonObject.getString("address"); + this.alias = jsonObject.getString("alias"); + this.qr_code = jsonObject.getString("qr_code"); + this.open_userid = jsonObject.getString("open_userid"); + } + + +} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WxWorkUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/WxWorkUtil.java new file mode 100644 index 0000000..5a4e449 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/utils/WxWorkUtil.java @@ -0,0 +1,134 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.exception.BusinessException; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +/** + * 企业微信工具类 + * @author 科技小王子 + * + */ +@Component +public class WxWorkUtil { + private final StringRedisTemplate stringRedisTemplate; + private Integer tenantId; + public String appId; + public String appSecret; + public String access_token; + public String expires_in; + public String nickname; + public String userid; + public String user_ticket; + public String openid; + public String external_userid; + public String name; + public String position; + public String mobile; + public String gender; + public String email; + public String avatar; + public String thumb_avatar; + public String telephone; + public String address; + public String alias; + public String qr_code; + public String open_userid; + + @Resource + private CacheClient cacheClient; + + + public WxWorkUtil(StringRedisTemplate stringRedisTemplate){ + this.stringRedisTemplate = stringRedisTemplate; + } + + + // 实例化客户端 + public WxWorkUtil client(Integer tenantId) { + this.tenantId = tenantId; + this.config(); + return this; + } + + // 开发者ID和秘钥 + private void config() { + JSONObject settingInfo = cacheClient.getSettingInfo("wx-work", this.tenantId); + if(settingInfo == null){ + throw new BusinessException("企业微信未配置"); + } + this.appId = settingInfo.getString("corpId"); + this.appSecret = settingInfo.getString("secret"); + System.out.println("this.appId = " + this.appId); + System.out.println("this.appSecret = " + this.appSecret); + } + + // 获取access_token + public void getAccessToken(String code) { + String key = "cache"+ this.tenantId +":ww:access_token"; + final String access_token = stringRedisTemplate.opsForValue().get(key); + if(access_token != null){ + this.getUserInfo(code,access_token); + }else { + String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" +this.appId+ "&corpsecret="+ this.appSecret; + System.out.println("url = " + url); + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + System.out.println("response = " + response); + final JSONObject jsonObject = JSONObject.parseObject(response); + // 获取成功 + if(jsonObject.getString("access_token") != null){ + this.access_token = jsonObject.getString("access_token"); + this.expires_in = jsonObject.getString("expires_in"); + stringRedisTemplate.opsForValue().set(key,this.access_token,7000, TimeUnit.SECONDS); + System.out.println("获取access_token成功 = " + this.access_token); + this.getUserInfo(code,this.access_token); + } + } + } + + // 获取userinfo + public void getUserInfo(String code, String access_token) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=" +access_token+ "&code=" + code; + System.out.println("url2 = " + url); + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + System.out.println("response = " + response); + JSONObject jsonObject = JSONObject.parseObject(response); + final String errcode = jsonObject.getString("errcode"); + final String errmsg = jsonObject.getString("errmsg"); + if(!StrUtil.equals(errcode,"0")){ + throw new BusinessException(errmsg); + } + this.userid = jsonObject.getString("userid"); + this.user_ticket = jsonObject.getString("user_ticket"); + this.openid = jsonObject.getString("openid"); + this.external_userid = jsonObject.getString("external_userid"); + System.out.println("获取用户信息成功 = " + jsonObject); + } + + public void getUserProfile(String userid, String access_token) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token="+ access_token +"&userid=" + userid; + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + System.out.println("response3 = " + response); + JSONObject jsonObject = JSONObject.parseObject(response); + System.out.println("读取用户详细信息 = " + jsonObject); + + this.name = jsonObject.getString("name"); + this.position = jsonObject.getString("position"); + this.gender = jsonObject.getString("gender"); + this.email = jsonObject.getString("email"); + this.avatar = jsonObject.getString("avatar"); + this.thumb_avatar = jsonObject.getString("thumb_avatar"); + this.telephone = jsonObject.getString("telephone"); + this.address = jsonObject.getString("address"); + this.alias = jsonObject.getString("alias"); + this.qr_code = jsonObject.getString("qr_code"); + this.open_userid = jsonObject.getString("open_userid"); + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/web/ApiResult.java b/src/main/java/com/gxwebsoft/common/core/web/ApiResult.java new file mode 100644 index 0000000..0313839 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/web/ApiResult.java @@ -0,0 +1,87 @@ +package com.gxwebsoft.common.core.web; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; + +import java.io.Serializable; + +/** + * 返回结果 + * + * @author WebSoft + * @since 2017-06-10 10:10:50 + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ApiResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "状态码") + private Integer code; + + @Schema(description = "状态信息") + private String message; + + @Schema(description = "返回数据") + private T data; + + @Schema(description = "错误信息") + private String error; + + public ApiResult() {} + + public ApiResult(Integer code) { + this(code, null); + } + + public ApiResult(Integer code, String message) { + this(code, message, null); + } + + public ApiResult(Integer code, String message, T data) { + this(code, message, data, null); + } + + public ApiResult(Integer code, String message, T data, String error) { + setCode(code); + setMessage(message); + setData(data); + setError(error); + } + + public Integer getCode() { + return this.code; + } + + public ApiResult setCode(Integer code) { + this.code = code; + return this; + } + + public String getMessage() { + return this.message; + } + + public ApiResult setMessage(String message) { + this.message = message; + return this; + } + + public T getData() { + return this.data; + } + + public ApiResult setData(T data) { + this.data = data; + return this; + } + + public String getError() { + return this.error; + } + + public ApiResult setError(String error) { + this.error = error; + return this; + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/web/BaseController.java b/src/main/java/com/gxwebsoft/common/core/web/BaseController.java new file mode 100644 index 0000000..46542ac --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/web/BaseController.java @@ -0,0 +1,333 @@ +package com.gxwebsoft.common.core.web; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.utils.SignCheckUtil; +import com.gxwebsoft.common.system.entity.User; +import org.springframework.beans.propertyeditors.StringTrimmerEditor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Controller基类 + * + * @author WebSoft + * @since 2017-06-10 10:10:19 + */ +public class BaseController { + @Resource + private HttpServletRequest request; + @Resource + private RedisUtil redisUtil; + + /** + * 获取当前登录的user + * + * @return User + */ + public User getLoginUser() { + try { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null) { + Object object = authentication.getPrincipal(); + if (object instanceof User) { + return (User) object; + } + } + } catch (Exception e) { + System.out.println(e.getMessage()); + } + return null; + } + + /** + * 获取当前登录的userId + * + * @return userId + */ + public Integer getLoginUserId() { + User loginUser = getLoginUser(); + return loginUser == null ? null : loginUser.getUserId(); + } + + /** + * 获取当前登录的tenantId + * + * @return tenantId + */ + public Integer getTenantId() { + String tenantId; + // 2 从请求头拿ID + tenantId = request.getHeader("tenantId"); + if(StrUtil.isNotBlank(tenantId)){ + return Integer.valueOf(tenantId); + } + // 3 从登录用户拿tenantId + User loginUser = getLoginUser(); + if (loginUser != null) { + return loginUser.getTenantId(); + } + // 1 从域名拿ID + String Domain = request.getHeader("Domain"); + if (StrUtil.isNotBlank(Domain)) { + String key = "Domain:" + Domain; + tenantId = redisUtil.get(key); + if(tenantId != null){ + System.out.println("从域名拿ID = " + tenantId); + return Integer.valueOf(tenantId); + } + } + return null; + } + + /** + * 返回成功 + * + * @return ApiResult + */ + public ApiResult success() { + return new ApiResult<>(Constants.RESULT_OK_CODE, Constants.RESULT_OK_MSG); + } + + /** + * 返回成功 + * + * @param message 状态信息 + * @return ApiResult + */ + public ApiResult success(String message) { + return success().setMessage(message); + } + + /** + * 返回成功 + * + * @param data 返回数据 + * @return ApiResult + */ + public ApiResult success(T data) { + return new ApiResult<>(Constants.RESULT_OK_CODE, Constants.RESULT_OK_MSG, data); + } + + /** + * 返回成功 + * + * @param message 状态信息 + * @return ApiResult + */ + public ApiResult success(String message, T data) { + return success(data).setMessage(message); + } + + /** + * 返回分页查询数据 + * + * @param list 当前页数据 + * @param count 总数量 + * @return ApiResult + */ + public ApiResult> success(List list, Long count) { + return success(new PageResult<>(list, count)); + } + + /** + * 返回分页查询数据 + * + * @param iPage IPage + * @return ApiResult + */ + public ApiResult> success(IPage iPage) { + return success(iPage.getRecords(), iPage.getTotal()); + } + + /** + * 返回失败 + * + * @return ApiResult + */ + public ApiResult fail() { + return new ApiResult<>(Constants.RESULT_ERROR_CODE, Constants.RESULT_ERROR_MSG); + } + + /** + * 返回失败 + * + * @param message 状态信息 + * @return ApiResult + */ + public ApiResult fail(String message) { + return fail().setMessage(message); + } + + /** + * 返回失败 + * + * @param data 返回数据 + * @return ApiResult + */ + public ApiResult fail(T data) { + return fail(Constants.RESULT_ERROR_MSG, data); + } + + /** + * 返回失败 + * + * @param message 状态信息 + * @param data 返回数据 + * @return ApiResult + */ + public ApiResult fail(String message, T data) { + return new ApiResult<>(Constants.RESULT_ERROR_CODE, message, data); + } + + /** + * 请求参数的空字符串转为null + */ + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.registerCustomEditor(String.class, new StringTrimmerEditor(true)); + } + + // 自定义函数 + public String getAuthorization(){ + return request.getHeader("Authorization"); + } + + public String getAppId() { + // 兼容小写 + if(request.getHeader("appid") != null){ + return request.getHeader("appid"); + } + return request.getHeader("AppId"); + } + + public String getSign() { + return request.getParameter("sign"); + } + + /** + * 是否校验签名信息 + * 存在签名信息则需要验证 + */ + public void isCheckSign() { + if (StrUtil.isNotBlank(getSign())) { + if(getTenantId() == null){ + throw new BusinessException("签名失败:TenantId不能为空"); + } + + String timestamp1 = request.getParameter("timestamp"); + long timestamp2 = System.currentTimeMillis(); + long time = timestamp2 - Long.parseLong(timestamp1); + if(time > 600000L){ + throw new BusinessException("签名失败:请求超时"); + } + + Enumeration names = request.getParameterNames(); + //2.遍历正文名称的枚举获得请求参数 + Map params = new HashMap<>(); + while(names.hasMoreElements()){ + String name = names.nextElement(); + String value = request.getParameter(name); + params.put(name,value); + } + String signString = SignCheckUtil.getSignString(params, getAppSecret()); + System.out.println("请求的参数 = " + params); + System.out.println("正确的签名 = " + signString); + System.out.println("签名是否正确 = " + SignCheckUtil.signCheck(params, getAppSecret())); + + if (!SignCheckUtil.signCheck(params, getAppSecret())) { + throw new BusinessException("签名失败"); + } + } + + // 模拟提交参数 + // String key = "FRbMx1FkG4Qz6GZxY"; + // Map param0 = new HashMap<>(); + // param0.put("orderId", "D2018062976332656413"); + // param0.put("MainAccountID", "DC3NHPJ73S"); + // param0.put("MainAccountSN", "320"); + // param0.put("payStatus", "2"); + // param0.put("title","测试"); + // System.out.println("请求的参数 = " + param0); + // String signString0 = SignCheckUtil.getSignString(param0, key); + // System.out.println("signString0 = " + signString0); + + // return SignCheckUtil.signCheck(params, getAppSecret()); + } + + /** + * 获取当前请求租户的AppSecret + * + * @return AppSecret + */ + public String getAppSecret() { + String key = "cache5:AppSecret:" + Integer.valueOf(getAppId()); + return redisUtil.get(key); + } + + /** + * 根据账号|手机号码|邮箱查找用户ID + * @return userId + */ +// public Integer getUserIdByUsername(String username, Integer tenantId){ +// // 按账号搜素 +// User user = userService.getOne(new LambdaQueryWrapper().eq(User::getUsername, username).eq(User::getTenantId,tenantId)); +// if (user != null && user.getUserId() > 0) { +// return user.getUserId(); +// } +// // 按手机号码搜索 +// User userByPhone = userService.getOne(new LambdaQueryWrapper().eq(User::getPhone, username).eq(User::getTenantId, tenantId)); +// if (userByPhone != null && userByPhone.getUserId() > 0) { +// return userByPhone.getUserId(); +// } +// // 按邮箱搜索 +// User userByEmail = userService.getOne(new LambdaQueryWrapper().eq(User::getEmail, username).eq(User::getTenantId, tenantId)); +// if (userByEmail != null && userByEmail.getUserId() > 0) { +// return userByEmail.getUserId(); +// } +// throw new BusinessException("找不到该用户"); +// } + + /** + * 处理方法参数类型转换异常 + * 主要处理URL路径参数中传入"NaN"等无法转换为Integer的情况 + * + * @param ex 方法参数类型不匹配异常 + * @return ApiResult + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + public ApiResult handleMethodArgumentTypeMismatch(MethodArgumentTypeMismatchException ex) { + String parameterName = ex.getName(); + Object value = ex.getValue(); + Class requiredType = ex.getRequiredType(); + + // 记录错误日志 + System.err.println("参数类型转换异常: 参数名=" + parameterName + + ", 传入值=" + value + + ", 期望类型=" + (requiredType != null ? requiredType.getSimpleName() : "unknown")); + + // 如果是ID参数且传入的是"NaN",返回友好的错误信息 + if ("id".equals(parameterName) && "NaN".equals(String.valueOf(value))) { + return fail("无效的ID参数,请检查传入的ID值"); + } + + // 其他类型转换错误的通用处理 + return fail("参数格式错误: " + parameterName + " 的值 '" + value + "' 无法转换为 " + + (requiredType != null ? requiredType.getSimpleName() : "目标类型")); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/web/BaseParam.java b/src/main/java/com/gxwebsoft/common/core/web/BaseParam.java new file mode 100644 index 0000000..9661fd8 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/web/BaseParam.java @@ -0,0 +1,98 @@ +package com.gxwebsoft.common.core.web; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.utils.CommonUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 查询参数基本字段 + * + * @author WebSoft + * @since 2021-08-26 22:14:43 + */ +@Data +public class BaseParam implements Serializable { + private static final long serialVersionUID = 1L; + + @TableField(exist = false) + @Schema(description = "分页查询页码") + private Long page; + + @TableField(exist = false) + @Schema(description = "分页查询每页数量") + private Long limit; + + @TableField(exist = false) + @Schema(description = "国际化") + private String lang; + + @TableField(exist = false) + @Schema(description = "排序字段", example = "id asc, name desc") + private String sort; + + @TableField(exist = false) + @Schema(description = "排序方式", example = "asc或desc") + private String order; + + @QueryField(value = "create_time", type = QueryType.GE) + @TableField(exist = false) + @Schema(description = "创建时间起始值") + private String createTimeStart; + + @QueryField(value = "create_time", type = QueryType.LE) + @TableField(exist = false) + @Schema(description = "创建时间结束值") + private String createTimeEnd; + + @QueryField(value = "create_time", type = QueryType.GE) + @Schema(description = "搜索场景") + @TableField(exist = false) + private String sceneType; + + @Schema(description = "模糊搜素") + @TableField(exist = false) + private String keywords; + + @Schema(description = "token") + @TableField(exist = false) + private String token; + + @Schema(description = "租户ID") + @TableField(exist = false) + private Integer tenantId; + + @Schema(description = "商户ID") + @TableField(exist = false) + private Long merchantId; + + /** + * 获取集合中的第一条数据 + * + * @param records 集合 + * @return 第一条数据 + */ + public T getOne(List records) { + return CommonUtil.listGetOne(records); + } + + /** + * 国际化参数 + */ + public String getLang(){ + if(StrUtil.isBlank(this.lang)){ + return null; + } + if(this.lang.equals("zh")){ + return "zh_CN"; + } + return this.lang; + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/web/BatchParam.java b/src/main/java/com/gxwebsoft/common/core/web/BatchParam.java new file mode 100644 index 0000000..cc69572 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/web/BatchParam.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.common.core.web; + +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.baomidou.mybatisplus.extension.service.IService; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 批量修改通用参数 + * + * @author WebSoft + * @since 2020-03-13 00:11:06 + */ +@Data +public class BatchParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "需要修改的数据id集合") + private List ids; + + @Schema(description = "需要修改的字段和值") + private T data; + + /** + * 通用批量修改方法 + * + * @param service IService + * @param idField id字段名称 + * @return boolean + */ + public boolean update(IService service, String idField) { + if (this.data == null) { + return false; + } + return service.update(this.data, new UpdateWrapper().in(idField, this.ids)); + } + + /** + * 通用批量修改方法 + * + * @param service IService + * @param idField id字段名称 + * @return boolean + */ + public boolean update(IService service, SFunction idField) { + if (this.data == null) { + return false; + } + return service.update(this.data, new LambdaUpdateWrapper().in(idField, this.ids)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/web/ExistenceParam.java b/src/main/java/com/gxwebsoft/common/core/web/ExistenceParam.java new file mode 100644 index 0000000..8c51268 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/web/ExistenceParam.java @@ -0,0 +1,96 @@ +package com.gxwebsoft.common.core.web; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.baomidou.mybatisplus.extension.service.IService; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 检查是否存在通用参数 + * + * @author WebSoft + * @since 2021-09-07 22:24:39 + */ +@Data +public class ExistenceParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "检查的字段") + private String field; + + @Schema(description = "字段的值") + private String value; + + @Schema(description = "修改时的主键") + private Integer id; + + /** + * 检查是否存在 + * + * @param service IService + * @param idField 修改时的主键字段 + * @return boolean + */ + public boolean isExistence(IService service, String idField) { + return isExistence(service, idField, true); + } + + /** + * 检查是否存在 + * + * @param service IService + * @param idField 修改时的主键字段 + * @param isToUnderlineCase 是否需要把field转为下划线格式 + * @return boolean + */ + public boolean isExistence(IService service, String idField, boolean isToUnderlineCase) { + if (StrUtil.hasBlank(this.field, this.value)) { + return false; + } + String fieldName = isToUnderlineCase ? StrUtil.toUnderlineCase(field) : field; + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq(fieldName, value); + if (id != null) { + wrapper.ne(idField, id); + } + return service.count(wrapper) > 0; + } + + /** + * 检查是否存在 + * + * @param service IService + * @param idField 修改时的主键字段 + * @return boolean + */ + public boolean isExistence(IService service, SFunction idField) { + return isExistence(service, idField, true); + } + + /** + * 检查是否存在 + * + * @param service IService + * @param idField 修改时的主键字段 + * @param isToUnderlineCase 是否需要把field转为下划线格式 + * @return boolean + */ + public boolean isExistence(IService service, SFunction idField, boolean isToUnderlineCase) { + if (StrUtil.hasBlank(this.field, this.value)) { + return false; + } + String fieldName = isToUnderlineCase ? StrUtil.toUnderlineCase(field) : field; + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.apply(fieldName + " = {0}", value); + if (id != null) { + wrapper.ne(idField, id); + } + return service.count(wrapper) > 0; + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/web/PageParam.java b/src/main/java/com/gxwebsoft/common/core/web/PageParam.java new file mode 100644 index 0000000..596ea58 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/web/PageParam.java @@ -0,0 +1,343 @@ +package com.gxwebsoft.common.core.web; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.utils.CommonUtil; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 分页、排序、搜索参数封装 + * + * @author WebSoft + * @since 2019-04-26 10:34:35 + */ +public class PageParam extends Page { + private static final long serialVersionUID = 1L; + + /** + * 租户id字段名称 + */ + private static final String TENANT_ID_FIELD = "tenantId"; + + /** + * 查询条件 + */ + private final U where; + + /** + * 是否把字段名称驼峰转下划线 + */ + private final boolean isToUnderlineCase; + + public PageParam() { + this(null); + } + + public PageParam(U where) { + this(where, true); + } + + public PageParam(U where, boolean isToUnderlineCase) { + super(); + this.where = where; + this.isToUnderlineCase = isToUnderlineCase; + if (where != null) { + // 获取分页页码 + if (where.getPage() != null) { + setCurrent(where.getPage()); + } + // 获取分页每页数量 + if (where.getLimit() != null) { + setSize(where.getLimit()); + } + // 获取排序方式 + if (where.getSort() != null) { + if (sortIsSQL(where.getSort())) { + setOrders(parseOrderSQL(where.getSort())); + } else { + List orderItems = new ArrayList<>(); + String column = this.isToUnderlineCase ? StrUtil.toUnderlineCase(where.getSort()) : where.getSort(); + boolean asc = !Constants.ORDER_DESC_VALUE.equals(where.getOrder()); + orderItems.add(new OrderItem(column, asc)); + setOrders(orderItems); + } + } + } + } + + /** + * 排序字段是否是sql + */ + private boolean sortIsSQL(String sort) { + return sort != null && (sort.contains(",") || sort.trim().contains(" ")); + } + + /** + * 解析排序sql + */ + private List parseOrderSQL(String orderSQL) { + List orders = new ArrayList<>(); + if (StrUtil.isNotBlank(orderSQL)) { + for (String item : orderSQL.split(",")) { + String[] temp = item.trim().split(" "); + if (!temp[0].isEmpty()) { + String column = this.isToUnderlineCase ? StrUtil.toUnderlineCase(temp[0]) : temp[0]; + boolean asc = temp.length == 1 || !temp[temp.length - 1].equals(Constants.ORDER_DESC_VALUE); + orders.add(new OrderItem(column, asc)); + } + } + } + return orders; + } + + /** + * 设置默认排序方式 + * + * @param orderItems 排序方式 + * @return PageParam + */ + public PageParam setDefaultOrder(List orderItems) { + if (orders() == null || orders().size() == 0) { + setOrders(orderItems); + } + return this; + } + + /** + * 设置默认排序方式 + * + * @param orderSQL 排序方式 + * @return PageParam + */ + public PageParam setDefaultOrder(String orderSQL) { + setDefaultOrder(parseOrderSQL(orderSQL)); + return this; + } + + /** + * 获取查询条件 + * + * @param excludes 不包含的字段 + * @return QueryWrapper + */ + public QueryWrapper getWrapper(String... excludes) { + return buildWrapper(null, Arrays.asList(excludes)); + } + + /** + * 获取查询条件 + * + * @param columns 只包含的字段 + * @return QueryWrapper + */ + public QueryWrapper getWrapperWith(String... columns) { + return buildWrapper(Arrays.asList(columns), null); + } + + /** + * 构建QueryWrapper + * + * @param columns 包含的字段 + * @param excludes 排除的字段 + * @return QueryWrapper + */ + private QueryWrapper buildWrapper(List columns, List excludes) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + Map map = BeanUtil.beanToMap(where, false, true); + for (String fieldName : map.keySet()) { + Object fieldValue = map.get(fieldName); + Field field = ReflectUtil.getField(where.getClass(), fieldName); + + // 过滤不包含的字段 + if (columns != null && !columns.contains(fieldName)) { + continue; + } + + // 过滤排除的字段 + if (excludes != null && excludes.contains(fieldName)) { + continue; + } + + // 过滤逻辑删除字段 + if (field.getAnnotation(TableLogic.class) != null) { + continue; + } + + // 过滤租户id字段 + if (fieldName.equals(TENANT_ID_FIELD)) { + continue; + } + + // 获取注解指定的查询字段及查询方式 + QueryType queryType = QueryType.LIKE; + QueryField queryField = field.getAnnotation(QueryField.class); + if (queryField != null) { + if (StrUtil.isNotEmpty(queryField.value())) { + fieldName = queryField.value(); + } + if (queryField.type() != null) { + queryType = queryField.type(); + } + } else { + // 过滤非本表的字段 + TableField tableField = field.getAnnotation(TableField.class); + if (tableField != null && !tableField.exist()) { + continue; + } + } + + // 字段名驼峰转下划线 + if (this.isToUnderlineCase) { + fieldName = StrUtil.toUnderlineCase(fieldName); + } + + // + switch (queryType) { + case EQ: + queryWrapper.eq(fieldName, fieldValue); + break; + case NE: + queryWrapper.ne(fieldName, fieldValue); + break; + case GT: + queryWrapper.gt(fieldName, fieldValue); + break; + case GE: + queryWrapper.ge(fieldName, fieldValue); + break; + case LT: + queryWrapper.lt(fieldName, fieldValue); + break; + case LE: + queryWrapper.le(fieldName, fieldValue); + break; + case LIKE: + queryWrapper.like(fieldName, fieldValue); + break; + case NOT_LIKE: + queryWrapper.notLike(fieldName, fieldValue); + break; + case LIKE_LEFT: + queryWrapper.likeLeft(fieldName, fieldValue); + break; + case LIKE_RIGHT: + queryWrapper.likeRight(fieldName, fieldValue); + break; + case IS_NULL: + queryWrapper.isNull(fieldName); + break; + case IS_NOT_NULL: + queryWrapper.isNotNull(fieldName); + break; + case IN: + queryWrapper.in(fieldName, fieldValue); + break; + case NOT_IN: + queryWrapper.notIn(fieldName, fieldValue); + break; + case IN_STR: + if (fieldValue instanceof String) { + queryWrapper.in(fieldName, Arrays.asList(((String) fieldValue).split(","))); + } + break; + case NOT_IN_STR: + if (fieldValue instanceof String) { + queryWrapper.notIn(fieldName, Arrays.asList(((String) fieldValue).split(","))); + } + break; + } + } + return queryWrapper; + } + + /** + * 获取包含排序的查询条件 + * + * @return 包含排序的QueryWrapper + */ + public QueryWrapper getOrderWrapper() { + return getOrderWrapper(getWrapper()); + } + + /** + * 获取包含排序的查询条件 + * + * @param queryWrapper 不含排序的QueryWrapper + * @return 包含排序的QueryWrapper + */ + public QueryWrapper getOrderWrapper(QueryWrapper queryWrapper) { + if (queryWrapper == null) { + queryWrapper = new QueryWrapper<>(); + } + for (OrderItem orderItem : orders()) { + if (orderItem.isAsc()) { + queryWrapper.orderByAsc(orderItem.getColumn()); + } else { + queryWrapper.orderByDesc(orderItem.getColumn()); + } + } + return queryWrapper; + } + + /** + * 获取集合中的第一条数据 + * + * @param records 集合 + * @return 第一条数据 + */ + public T getOne(List records) { + return CommonUtil.listGetOne(records); + } + + /** + * 代码排序集合 + * + * @param records 集合 + * @return 排序后的集合 + */ + public List sortRecords(List records) { + List orderItems = orders(); + if (records == null || records.size() < 2 || orderItems == null || orderItems.size() == 0) { + return records; + } + Comparator comparator = null; + for (OrderItem item : orderItems) { + if (item.getColumn() == null) { + continue; + } + String field = this.isToUnderlineCase ? StrUtil.toCamelCase(item.getColumn()) : item.getColumn(); + Function keyExtractor = t -> ReflectUtil.getFieldValue(t, field); + if (comparator == null) { + if (item.isAsc()) { + comparator = Comparator.comparing(keyExtractor); + } else { + comparator = Comparator.comparing(keyExtractor, Comparator.reverseOrder()); + } + } else { + if (item.isAsc()) { + comparator.thenComparing(keyExtractor); + } else { + comparator.thenComparing(keyExtractor, Comparator.reverseOrder()); + } + } + } + if (comparator != null) { + return records.stream().sorted(comparator).collect(Collectors.toList()); + } + return records; + } + +} diff --git a/src/main/java/com/gxwebsoft/common/core/web/PageResult.java b/src/main/java/com/gxwebsoft/common/core/web/PageResult.java new file mode 100644 index 0000000..a9bc057 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/web/PageResult.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.common.core.web; + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.io.Serializable; +import java.util.List; + +/** + * 分页查询返回结果 + * + * @author WebSoft + * @since 2017-06-10 10:10:02 + */ +public class PageResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "当前页数据") + private List list; + + @Schema(description = "总数量") + private Long count; + + public PageResult() { + } + + public PageResult(List list) { + this(list, null); + } + + public PageResult(List list, Long count) { + setList(list); + setCount(count); + } + + public List getList() { + return this.list; + } + + public void setList(List list) { + this.list = list; + } + + public Long getCount() { + return this.count; + } + + public void setCount(Long count) { + this.count = count; + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/AiController.java b/src/main/java/com/gxwebsoft/common/system/controller/AiController.java new file mode 100644 index 0000000..8525a3b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/AiController.java @@ -0,0 +1,139 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.http.HttpRequest; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.websocket.WebSocketServer; +import com.gxwebsoft.common.system.entity.ChatMessage; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +@Tag(name = "AI") +@RestController +@RequestMapping("/api/chat") +public class AiController extends BaseController { + @Resource + private WebSocketServer webSocketServer; + + @PostMapping("/message") + public ApiResult message(@RequestBody ChatMessage message) throws IOException { + Map paramsJsonStr = new HashMap<>(); + paramsJsonStr.put("query", message.getQuery()); + paramsJsonStr.put("opsType", "0"); + + Map formData = new HashMap<>(); + formData.put("user", message.getUser()); + formData.put("responseMode", "streaming"); + formData.put("paramsJsonStr", JSONUtil.toJSONString(paramsJsonStr)); + formData.put("authCode", "a8cc4a0a-aea3-4ea5-811a-80316520a3d3"); + // 使用 Java 自带的 HttpURLConnection 发送流式请求 + try { + URL url = new URL("https://ai-console.gxshucheng.com/ai-console-api/run/v1"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); + connection.setDoOutput(true); + connection.setConnectTimeout(600000); + connection.setReadTimeout(600000); + + // 写入请求体 + try (OutputStream os = connection.getOutputStream(); + PrintWriter writer = new PrintWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))) { + for (Map.Entry entry : formData.entrySet()) { + writeFormField(writer, entry.getKey(), entry.getValue()); + } + // 添加文件上传部分(可选) + // writeFilePart(writer, "file", "test.txt", "text/plain", "This is the file content."); + writer.append("--").append(boundary).append("--").append("\r\n"); + writer.flush(); + } + + StringBuilder responseStr = new StringBuilder(); + // 读取响应流 + try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { + String line; + while ((line = br.readLine()) != null) { + System.out.println("Received chunk: " + line); // 打印接收到的每一部分数据 + // 这里可以对每一部分数据进行处理,例如解析或发送给前端 + if (!line.isEmpty()) { + String[] dataList = line.split("data: "); + if (dataList.length == 2) { +// System.out.println(dataList[1]); + Map data = JSONUtil.parseObject(dataList[1], Map.class); + if (data.get("event") != null && data.get("event").equals("message")) { + String answer = (String) data.get("answer"); + String task_id = (String) data.get("task_id"); + if (answer != null && !answer.isEmpty()) { + HashMap answerData = new HashMap<>(); + answerData.put("answer", answer); + answerData.put("taskId", task_id); + webSocketServer.sendMessage(message.getUser(), JSONUtil.toJSONString(answerData)); + } + System.out.println("answer: " + answer); + responseStr.append(answer); + }else if (data.get("event") != null && data.get("event").equals("message_end")) { + String task_id = (String) data.get("task_id"); + HashMap answerData = new HashMap<>(); + answerData.put("answer", "__END__"); + answerData.put("taskId", task_id); + + webSocketServer.sendMessage(message.getUser(), JSONUtil.toJSONString(answerData)); + } + } + } + } + } + } catch (Exception e) { + System.out.println(e.getMessage()); + for (StackTraceElement stackTraceElement : e.getStackTrace()) { + System.out.println(stackTraceElement); + } + webSocketServer.sendMessage(message.getUser(), "出错了,请晚点再来提问吧~"); + return fail("出错了,请晚点再来提问吧~"); + } + + // 返回成功响应 + return success("Stream processing completed"); + } + + private static final String boundary = "---" + System.currentTimeMillis() + "---"; + + private static void writeFormField(PrintWriter writer, String fieldName, String value) { + writer.append("--").append(boundary).append("\r\n"); + writer.append("Content-Disposition: form-data; name=\"").append(fieldName).append("\"\r\n"); + writer.append("\r\n"); + writer.append(value).append("\r\n"); + } + + @PostMapping("/messageStop") + public ApiResult stop(@RequestBody Map data) { + if (data.get("taskId") == null) return success(); + String taskId = data.get("taskId").toString(); + Map postData = new HashMap<>(); + postData.put("user", getLoginUserId()); + String token = "Bearer app-UxV82WXIRrScpf53exkJ7dIw"; + if (data.get("type") != null) { + token = "Bearer app-7AFseF5UTEJpZGkW93S0wybh"; + } + String res = HttpRequest.post("http://workflow.gxshucheng.com:8010/v1/chat-messages/" + taskId + "/stop") + .header("Authorization", token) + .header("Content-Type", "application/json") + .body(JSONObject.toJSONString(postData)) + .execute().body(); + System.out.println("stop res:" + res); + return success(); + } +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/CacheController.java b/src/main/java/com/gxwebsoft/common/system/controller/CacheController.java new file mode 100644 index 0000000..d95357d --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/CacheController.java @@ -0,0 +1,117 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.utils.CacheClient; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.Cache; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.SettingService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * 缓存控制器 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Tag(name = "缓存管理") +@RestController +@RequestMapping("/api/system/cache") +public class CacheController extends BaseController { + @Resource + private SettingService settingService; + @Resource + private CacheClient cacheClient; + @Resource + private RedisUtil redisUtil; + @Resource + private StringRedisTemplate stringRedisTemplate; + + @PreAuthorize("hasAuthority('sys:cache:list')") + @Operation(summary = "查询全部缓存") + @GetMapping() + public ApiResult> list() { + String key = "cache".concat(getTenantId().toString()).concat("*"); + final Set keys = stringRedisTemplate.keys(key); + final HashMap map = new HashMap<>(); + final ArrayList list = new ArrayList<>(); + assert keys != null; + keys.forEach(d -> { + final Cache cache = new Cache(); + cache.setKey(d); + try { + final String content = stringRedisTemplate.opsForValue().get(d); + if(content != null){ + cache.setContent(stringRedisTemplate.opsForValue().get(d)); + } + } catch (Exception e) { + e.printStackTrace(); + } + list.add(cache); + }); + map.put("count",keys.size()); + map.put("list",list); + return success(map); + } + + @PreAuthorize("hasAuthority('sys:cache:list')") + @Operation(summary = "根据key查询缓存信息") + @GetMapping("/{key}") + public ApiResult get(@PathVariable("key") String key) { + final String s = redisUtil.get(key + getTenantId()); + if(StrUtil.isNotBlank(s)){ + return success("读取成功", JSONObject.parseObject(s)); + } + return fail("缓存不存在!"); + } + + @PreAuthorize("hasAuthority('sys:cache:save')") + @Operation(summary = "添加缓存") + @PostMapping() + public ApiResult add(@RequestBody Cache cache) { + if (cache.getExpireTime() != null) { + redisUtil.set(cache.getKey() + ":" + getTenantId(),cache.getContent(),cache.getExpireTime(), TimeUnit.MINUTES); + return success("缓存成功"); + } + redisUtil.set(cache.getKey() + ":" + getTenantId(),cache.getContent()); + return success("缓存成功"); + } + + @PreAuthorize("hasAuthority('sys:cache:save')") + @Operation(summary = "删除缓存") + @DeleteMapping("/{key}") + public ApiResult remove(@PathVariable("key") String key) { + if (Boolean.TRUE.equals(stringRedisTemplate.delete(key))) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:cache:save')") + @Operation(summary = "缓存皮肤") + @PostMapping("/theme") + public ApiResult saveTheme(@RequestBody Cache cache) { + final User loginUser = getLoginUser(); + final String username = loginUser.getUsername(); + if (username.equals("admin")) { + redisUtil.set(cache.getKey() + ":" + getTenantId(),cache.getContent()); + return success("缓存成功"); + } + return success("缓存失败"); + } + + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/DictController.java b/src/main/java/com/gxwebsoft/common/system/controller/DictController.java new file mode 100644 index 0000000..27fb3fe --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/DictController.java @@ -0,0 +1,177 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Dict; +import com.gxwebsoft.common.system.entity.DictData; +import com.gxwebsoft.common.system.param.DictDataParam; +import com.gxwebsoft.common.system.param.DictParam; +import com.gxwebsoft.common.system.service.DictDataService; +import com.gxwebsoft.common.system.service.DictService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 字典控制器 + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +@Tag(name = "字典管理(业务类)") +@RestController +@RequestMapping("/api/system/dict") +public class DictController extends BaseController { + @Resource + private DictService dictService; + @Resource + private DictDataService dictDataService; + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "分页查询字典") + @GetMapping("/page") + public ApiResult> page(DictParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return success(dictService.page(page, page.getWrapper())); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "查询全部字典") + @GetMapping() + public ApiResult> list(DictParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return success(dictService.list(page.getOrderWrapper())); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "查询全部字典") + @GetMapping("/tree") + public ApiResult tree() { + final HashMap result = new HashMap<>(); + final List dictData = dictDataService.listRel(new DictDataParam()); + final Map> dataCollect = dictData.stream().collect(Collectors.groupingBy(DictData::getDictCode)); + for (String code : dataCollect.keySet()) { + Dict dict = new Dict(); + dict.setDictCode(code); + final Set> list = new LinkedHashSet<>(); + Set codes = new LinkedHashSet<>(); + for(DictData item : dictData){ + if (item.getDictCode().equals(code)) { + codes.add(item.getDictDataCode()); + } + } + list.add(codes); + dict.setItems(list); + result.put(code,dict.getItems()); + } + return success(result); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "根据id查询字典") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(dictService.getById(id)); + } + + @PreAuthorize("hasAuthority('sys:dict:save')") + @Operation(summary = "添加字典") + @PostMapping() + public ApiResult add(@RequestBody Dict dict) { + if (dictService.count(new LambdaQueryWrapper() + .eq(Dict::getDictCode, dict.getDictCode())) > 0) { + return fail("字典标识已存在"); + } + if (dictService.count(new LambdaQueryWrapper() + .eq(Dict::getDictName, dict.getDictName())) > 0) { + return fail("字典名称已存在"); + } + if (dictService.save(dict)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:update')") + @Operation(summary = "修改字典") + @PutMapping() + public ApiResult update(@RequestBody Dict dict) { + if (dictService.count(new LambdaQueryWrapper() + .eq(Dict::getDictCode, dict.getDictCode()) + .ne(Dict::getDictId, dict.getDictId())) > 0) { + return fail("字典标识已存在"); + } + if (dictService.count(new LambdaQueryWrapper() + .eq(Dict::getDictName, dict.getDictName()) + .ne(Dict::getDictId, dict.getDictId())) > 0) { + return fail("字典名称已存在"); + } + if (dictService.updateById(dict)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:remove')") + @Operation(summary = "删除字典") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (dictService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:save')") + @Operation(summary = "批量添加字典") + @PostMapping("/batch") + public ApiResult> saveBatch(@RequestBody List list) { + if (CommonUtil.checkRepeat(list, Dict::getDictCode)) { + return fail("字典标识不能重复", null); + } + if (CommonUtil.checkRepeat(list, Dict::getDictName)) { + return fail("字典名称不能重复", null); + } + List codeExists = dictService.list(new LambdaQueryWrapper() + .in(Dict::getDictCode, list.stream().map(Dict::getDictCode) + .collect(Collectors.toList()))); + if (codeExists.size() > 0) { + return fail("字典标识已存在", codeExists.stream().map(Dict::getDictCode) + .collect(Collectors.toList())).setCode(2); + } + List nameExists = dictService.list(new LambdaQueryWrapper() + .in(Dict::getDictName, list.stream().map(Dict::getDictCode) + .collect(Collectors.toList()))); + if (nameExists.size() > 0) { + return fail("字典名称已存在", nameExists.stream().map(Dict::getDictName) + .collect(Collectors.toList())).setCode(3); + } + if (dictService.saveBatch(list)) { + return success("添加成功", null); + } + return fail("添加失败", null); + } + + @PreAuthorize("hasAuthority('sys:dict:remove')") + @Operation(summary = "批量删除字典") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (dictService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/DictDataController.java b/src/main/java/com/gxwebsoft/common/system/controller/DictDataController.java new file mode 100644 index 0000000..1942f67 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/DictDataController.java @@ -0,0 +1,124 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.DictData; +import com.gxwebsoft.common.system.param.DictDataParam; +import com.gxwebsoft.common.system.service.DictDataService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 字典数据控制器 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Tag(name = "字典数据管理(业务类)") +@RestController +@RequestMapping("/api/system/dict-data") +public class DictDataController extends BaseController { + @Resource + private DictDataService dictDataService; + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "分页查询字典数据") + @GetMapping("/page") + public ApiResult> page(DictDataParam param) { + return success(dictDataService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "查询全部字典数据") + @GetMapping() + public ApiResult> list(DictDataParam param) { + return success(dictDataService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "根据id查询字典数据") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(dictDataService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:dict:save')") + @Operation(summary = "添加字典数据") + @PostMapping() + public ApiResult add(@RequestBody DictData dictData) { + if (dictDataService.count(new LambdaQueryWrapper() + .eq(DictData::getDictId, dictData.getDictId()) + .eq(DictData::getDictDataName, dictData.getDictDataName())) > 0) { + return fail("字典数据名称已存在"); + } + if (dictDataService.count(new LambdaQueryWrapper() + .eq(DictData::getDictId, dictData.getDictId()) + .eq(DictData::getDictDataCode, dictData.getDictDataCode())) > 0) { + return fail("字典数据标识已存在"); + } + if (dictDataService.save(dictData)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:update')") + @Operation(summary = "修改字典数据") + @PutMapping() + public ApiResult update(@RequestBody DictData dictData) { + if (dictDataService.count(new LambdaQueryWrapper() + .eq(DictData::getDictId, dictData.getDictId()) + .eq(DictData::getDictDataName, dictData.getDictDataName()) + .ne(DictData::getDictDataId, dictData.getDictDataId())) > 0) { + return fail("字典数据名称已存在"); + } + if (dictDataService.count(new LambdaQueryWrapper() + .eq(DictData::getDictId, dictData.getDictId()) + .eq(DictData::getDictDataCode, dictData.getDictDataCode()) + .ne(DictData::getDictDataId, dictData.getDictDataId())) > 0) { + return fail("字典数据标识已存在"); + } + if (dictDataService.updateById(dictData)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:remove')") + @Operation(summary = "删除字典数据") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (dictDataService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:save')") + @Operation(summary = "批量添加字典数据") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List dictDataList) { + if (dictDataService.saveBatch(dictDataList)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:remove')") + @Operation(summary = "批量删除字典数据") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (dictDataService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/DictionaryController.java b/src/main/java/com/gxwebsoft/common/system/controller/DictionaryController.java new file mode 100644 index 0000000..ecbeb6d --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/DictionaryController.java @@ -0,0 +1,148 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Dictionary; +import com.gxwebsoft.common.system.param.DictionaryParam; +import com.gxwebsoft.common.system.service.DictionaryService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 字典控制器 + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +@Tag(name = "字典管理(系统类)") +@RestController +@RequestMapping("/api/system/dictionary") +public class DictionaryController extends BaseController { + @Resource + private DictionaryService dictionaryService; + + @PreAuthorize("hasAuthority('sys:dictionary:list')") + @Operation(summary = "分页查询字典") + @GetMapping("/page") + public ApiResult> page(DictionaryParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return success(dictionaryService.page(page, page.getWrapper())); + } + + @PreAuthorize("hasAuthority('sys:dictionary:list')") + @Operation(summary = "查询全部字典") + @GetMapping() + public ApiResult> list(DictionaryParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return success(dictionaryService.list(page.getOrderWrapper())); + } + + @PreAuthorize("hasAuthority('sys:dictionary:list')") + @Operation(summary = "根据id查询字典") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(dictionaryService.getById(id)); + } + + @PreAuthorize("hasAuthority('sys:dictionary:save')") + @Operation(summary = "添加字典") + @PostMapping() + public ApiResult add(@RequestBody Dictionary dictionary) { + if (dictionaryService.count(new LambdaQueryWrapper() + .eq(Dictionary::getDictCode, dictionary.getDictCode())) > 0) { + return fail("字典标识已存在"); + } + if (dictionaryService.count(new LambdaQueryWrapper() + .eq(Dictionary::getDictName, dictionary.getDictName())) > 0) { + return fail("字典名称已存在"); + } + if (dictionaryService.save(dictionary)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:dictionary:update')") + @Operation(summary = "修改字典") + @PutMapping() + public ApiResult update(@RequestBody Dictionary dictionary) { + if (dictionaryService.count(new LambdaQueryWrapper() + .eq(Dictionary::getDictCode, dictionary.getDictCode()) + .ne(Dictionary::getDictId, dictionary.getDictId())) > 0) { + return fail("字典标识已存在"); + } + if (dictionaryService.count(new LambdaQueryWrapper() + .eq(Dictionary::getDictName, dictionary.getDictName()) + .ne(Dictionary::getDictId, dictionary.getDictId())) > 0) { + return fail("字典名称已存在"); + } + if (dictionaryService.updateById(dictionary)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:dictionary:remove')") + @Operation(summary = "删除字典") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (dictionaryService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:dictionary:save')") + @Operation(summary = "批量添加字典") + @PostMapping("/batch") + public ApiResult> saveBatch(@RequestBody List list) { + if (CommonUtil.checkRepeat(list, Dictionary::getDictCode)) { + return fail("字典标识不能重复", null); + } + if (CommonUtil.checkRepeat(list, Dictionary::getDictName)) { + return fail("字典名称不能重复", null); + } + List codeExists = dictionaryService.list(new LambdaQueryWrapper() + .in(Dictionary::getDictCode, list.stream().map(Dictionary::getDictCode) + .collect(Collectors.toList()))); + if (codeExists.size() > 0) { + return fail("字典标识已存在", codeExists.stream().map(Dictionary::getDictCode) + .collect(Collectors.toList())).setCode(2); + } + List nameExists = dictionaryService.list(new LambdaQueryWrapper() + .in(Dictionary::getDictName, list.stream().map(Dictionary::getDictCode) + .collect(Collectors.toList()))); + if (nameExists.size() > 0) { + return fail("字典名称已存在", nameExists.stream().map(Dictionary::getDictName) + .collect(Collectors.toList())).setCode(3); + } + if (dictionaryService.saveBatch(list)) { + return success("添加成功", null); + } + return fail("添加失败", null); + } + + @PreAuthorize("hasAuthority('sys:dictionary:remove')") + @Operation(summary = "批量删除字典") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (dictionaryService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/DictionaryDataController.java b/src/main/java/com/gxwebsoft/common/system/controller/DictionaryDataController.java new file mode 100644 index 0000000..df16554 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/DictionaryDataController.java @@ -0,0 +1,123 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.DictionaryData; +import com.gxwebsoft.common.system.param.DictionaryDataParam; +import com.gxwebsoft.common.system.service.DictionaryDataService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 字典数据控制器 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Tag(name = "字典数据管理(系统类)") +@RestController +@RequestMapping("/api/system/dictionary-data") +public class DictionaryDataController extends BaseController { + @Resource + private DictionaryDataService dictionaryDataService; + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "分页查询字典数据") + @GetMapping("/page") + public ApiResult> page(DictionaryDataParam param) { + return success(dictionaryDataService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "查询全部字典数据") + @GetMapping() + public ApiResult> list(DictionaryDataParam param) { + return success(dictionaryDataService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "根据id查询字典数据") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(dictionaryDataService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:dict:save')") + @Operation(summary = "添加字典数据") + @PostMapping() + public ApiResult add(@RequestBody DictionaryData dictionaryData) { + if (dictionaryDataService.count(new LambdaQueryWrapper() + .eq(DictionaryData::getDictId, dictionaryData.getDictId()) + .eq(DictionaryData::getDictDataName, dictionaryData.getDictDataName())) > 0) { + return fail("字典数据名称已存在"); + } + if (dictionaryDataService.count(new LambdaQueryWrapper() + .eq(DictionaryData::getDictId, dictionaryData.getDictId()) + .eq(DictionaryData::getDictDataCode, dictionaryData.getDictDataCode())) > 0) { + return fail("字典数据标识已存在"); + } + if (dictionaryDataService.save(dictionaryData)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:update')") + @Operation(summary = "修改字典数据") + @PutMapping() + public ApiResult update(@RequestBody DictionaryData dictionaryData) { + if (dictionaryDataService.count(new LambdaQueryWrapper() + .eq(DictionaryData::getDictId, dictionaryData.getDictId()) + .eq(DictionaryData::getDictDataName, dictionaryData.getDictDataName()) + .ne(DictionaryData::getDictDataId, dictionaryData.getDictDataId())) > 0) { + return fail("字典数据名称已存在"); + } + if (dictionaryDataService.count(new LambdaQueryWrapper() + .eq(DictionaryData::getDictId, dictionaryData.getDictId()) + .eq(DictionaryData::getDictDataCode, dictionaryData.getDictDataCode()) + .ne(DictionaryData::getDictDataId, dictionaryData.getDictDataId())) > 0) { + return fail("字典数据标识已存在"); + } + if (dictionaryDataService.updateById(dictionaryData)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:remove')") + @Operation(summary = "删除字典数据") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (dictionaryDataService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:save')") + @Operation(summary = "批量添加字典数据") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List dictDataList) { + if (dictionaryDataService.saveBatch(dictDataList)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:remove')") + @Operation(summary = "批量删除字典数据") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (dictionaryDataService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/DomainController.java b/src/main/java/com/gxwebsoft/common/system/controller/DomainController.java new file mode 100644 index 0000000..66b95cb --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/DomainController.java @@ -0,0 +1,127 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Domain; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.DomainParam; +import com.gxwebsoft.common.system.service.DomainService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 授权域名控制器 + * + * @author 科技小王子 + * @since 2024-09-19 23:56:33 + */ +@Tag(name = "授权域名管理") +@RestController +@RequestMapping("/api/system/domain") +public class DomainController extends BaseController { + @Resource + private DomainService domainService; + + @Operation(summary = "分页查询授权域名") + @GetMapping("/page") + public ApiResult> page(DomainParam param) { + // 使用关联查询 + return success(domainService.pageRel(param)); + } + + @Operation(summary = "查询全部授权域名") + @GetMapping() + public ApiResult> list(DomainParam param) { + // 使用关联查询 + return success(domainService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:domain:list')") + @OperationLog + @Operation(summary = "根据id查询授权域名") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(domainService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:domain:save')") + @OperationLog + @Operation(summary = "添加授权域名") + @PostMapping() + public ApiResult save(@RequestBody Domain domain) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + domain.setUserId(loginUser.getUserId()); + } + if (domainService.save(domain)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:domain:update')") + @OperationLog + @Operation(summary = "修改授权域名") + @PutMapping() + public ApiResult update(@RequestBody Domain domain) { + if (domainService.updateById(domain)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:domain:remove')") + @OperationLog + @Operation(summary = "删除授权域名") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (domainService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:domain:save')") + @OperationLog + @Operation(summary = "批量添加授权域名") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (domainService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:domain:update')") + @OperationLog + @Operation(summary = "批量修改授权域名") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(domainService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:domain:remove')") + @OperationLog + @Operation(summary = "批量删除授权域名") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (domainService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/EmailController.java b/src/main/java/com/gxwebsoft/common/system/controller/EmailController.java new file mode 100644 index 0000000..cf1f9cc --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/EmailController.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.EmailRecord; +import com.gxwebsoft.common.system.service.EmailRecordService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.mail.MessagingException; + +/** + * 邮件功能控制器 + * + * @author WebSoft + * @since 2020-03-21 00:37:11 + */ +@Tag(name = "邮件功能") +@RestController +@RequestMapping("/api/system/email") +public class EmailController extends BaseController { + @Resource + private EmailRecordService emailRecordService; + + @PreAuthorize("hasAuthority('sys:email:send')") + @Operation(summary = "发送邮件") + @PostMapping() + public ApiResult send(@RequestBody EmailRecord emailRecord) { + try { + emailRecordService.sendFullTextEmail(emailRecord.getTitle(), emailRecord.getContent(), + emailRecord.getReceiver().split(",")); + emailRecord.setCreateUserId(getLoginUserId()); + emailRecordService.save(emailRecord); + return success("发送成功"); + } catch (MessagingException e) { + e.printStackTrace(); + } + return fail("发送失败"); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/LoginRecordController.java b/src/main/java/com/gxwebsoft/common/system/controller/LoginRecordController.java new file mode 100644 index 0000000..91175ca --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/LoginRecordController.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.LoginRecord; +import com.gxwebsoft.common.system.param.LoginRecordParam; +import com.gxwebsoft.common.system.service.LoginRecordService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 登录日志控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:31 + */ +@Tag(name = "登录日志") +@RestController +@RequestMapping("/api/system/login-record") +public class LoginRecordController extends BaseController { + @Resource + private LoginRecordService loginRecordService; + + @PreAuthorize("hasAuthority('sys:login-record:list')") + @Operation(summary = "分页查询登录日志") + @GetMapping("/page") + public ApiResult> page(LoginRecordParam param) { + return success(loginRecordService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:login-record:list')") + @Operation(summary = "查询全部登录日志") + @GetMapping() + public ApiResult> list(LoginRecordParam param) { + return success(loginRecordService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:login-record:list')") + @Operation(summary = "根据id查询登录日志") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(loginRecordService.getByIdRel(id)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/MainController.java b/src/main/java/com/gxwebsoft/common/system/controller/MainController.java new file mode 100644 index 0000000..07ab5b3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/MainController.java @@ -0,0 +1,314 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.aliyuncs.CommonRequest; +import com.aliyuncs.CommonResponse; +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.exceptions.ServerException; +import com.aliyuncs.http.MethodType; +import com.aliyuncs.profile.DefaultProfile; +import com.google.gson.Gson; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.security.JwtSubject; +import com.gxwebsoft.common.core.security.JwtUtil; +import com.gxwebsoft.common.core.utils.CacheClient; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.ExistenceParam; +import com.gxwebsoft.common.system.entity.LoginRecord; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.LoginParam; +import com.gxwebsoft.common.system.param.SmsCaptchaParam; +import com.gxwebsoft.common.system.param.UpdatePasswordParam; +import com.gxwebsoft.common.system.result.CaptchaResult; +import com.gxwebsoft.common.system.result.LoginResult; +import com.gxwebsoft.common.system.service.*; +import com.wf.captcha.SpecCaptcha; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +/** + * 登录认证控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:11 + */ +@Tag(name = "登录认证") +@RestController +@RequestMapping("/api") +public class MainController extends BaseController { + @Resource + private ConfigProperties configProperties; + @Resource + private UserService userService; + @Resource + private RoleMenuService roleMenuService; + @Resource + private LoginRecordService loginRecordService; + @Resource + private CacheClient cacheClient; + @Resource + private RedisUtil redisUtil; + + @Operation(summary = "检查用户是否存在") + @GetMapping("/existence") + public ApiResult existence(ExistenceParam param) { + if (param.isExistence(userService, User::getUserId)) { + return success("已存在", param.getValue()); + } + return fail("不存在"); + } + + @Operation(summary = "获取登录用户信息") + @GetMapping("/auth/user") + public ApiResult userInfo() { + final Integer loginUserId = getLoginUserId(); + if(loginUserId != null){ + return success(userService.getByIdRel(getLoginUserId())); + } + return fail("loginUserId不存在",null); + } + + @Operation(summary = "获取登录用户菜单") + @GetMapping("/auth/menu") + public ApiResult> userMenu() { + List menus = roleMenuService.listMenuByUserId(getLoginUserId(), Menu.TYPE_MENU); + return success(CommonUtil.toTreeData(menus, 0, Menu::getParentId, Menu::getMenuId, Menu::setChildren)); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "修改个人信息") + @PutMapping("/auth/user") + public ApiResult updateInfo(@RequestBody User user) { + user.setUserId(getLoginUserId()); + // 不能修改的字段 + user.setUsername(null); + user.setPassword(null); + user.setEmailVerified(null); + user.setOrganizationId(null); + user.setStatus(null); + if (userService.updateById(user)) { + return success(userService.getByIdRel(user.getUserId())); + } + return fail("保存失败", null); + } + + @PreAuthorize("hasAuthority('sys:auth:password')") + @Operation(summary = "修改自己密码") + @PutMapping("/auth/password") + public ApiResult updatePassword(@RequestBody UpdatePasswordParam param) { + if (StrUtil.hasBlank(param.getOldPassword(), param.getPassword())) { + return fail("参数不能为空"); + } + Integer userId = getLoginUserId(); + if (userId == null) { + return fail("未登录"); + } + if (!userService.comparePassword(userService.getById(userId).getPassword(), param.getOldPassword())) { + return fail("原密码输入不正确"); + } + User user = new User(); + user.setUserId(userId); + user.setPassword(userService.encodePassword(param.getPassword())); + if (userService.updateById(user)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "图形验证码") + @GetMapping("/captcha") + public ApiResult captcha() { + SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5); + return success(new CaptchaResult(specCaptcha.toBase64(), specCaptcha.text().toLowerCase())); + } + + @Operation(summary = "企业微信登录链接") + @GetMapping("/wxWorkQrConnect") + public ApiResult wxWorkQrConnect() throws UnsupportedEncodingException { + final JSONObject settingInfo = cacheClient.getSettingInfo("wx-work", 10048); + final String corpId = settingInfo.getString("corpId"); + String encodedReturnUrl = URLEncoder.encode("https://oa.gxwebsoft.com/api/open/wx-work/login","UTF-8"); + String url = "https://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect?appid=" +corpId+ "&redirect_uri=" +encodedReturnUrl+ "&state=ww_login@gxwebsoft&usertype=admin"; + return success("获取成功",url); + } + + @Operation(summary = "短信验证码") + @PostMapping("/sendSmsCaptcha") + public ApiResult sendSmsCaptcha(@RequestBody SmsCaptchaParam param) { + // 读取短信配置信息 + String string = redisUtil.get("setting:sms:" + getTenantId()); + JSONObject jsonObject = JSONObject.parseObject(string); + String accessKeyId = jsonObject.getString("accessKeyId"); + String accessKeySecret = jsonObject.getString("accessKeySecret"); + String userTemplateId = jsonObject.getString("userTemplateId"); + String sign = jsonObject.getString("sign"); + if(accessKeyId != null){ + DefaultProfile profile = DefaultProfile.getProfile("regionld", accessKeyId, accessKeySecret); + IAcsClient client = new DefaultAcsClient(profile); + CommonRequest request = new CommonRequest(); + request.setSysMethod(MethodType.POST); + request.setSysDomain("dysmsapi.aliyuncs.com"); + request.setSysVersion("2017-05-25"); + request.setSysAction("SendSms"); + request.putQueryParameter("RegionId", "cn-hangzhou"); + request.putQueryParameter("PhoneNumbers", param.getPhone()); + request.putQueryParameter("SignName", sign); + request.putQueryParameter("TemplateCode", userTemplateId); + // 生成短信验证码 + Random randObj = new Random(); + String code = Integer.toString(100000 + randObj.nextInt(900000)); + request.putQueryParameter("TemplateParam", "{\"code\":" + code + "}"); + try { + CommonResponse response = client.getCommonResponse(request); + System.out.println("response = " + response); + String json = response.getData(); + System.out.println("json = " + json); + Gson g = new Gson(); + HashMap result = g.fromJson(json, HashMap.class); + System.out.println("result = " + result); + if("OK".equals(result.get("Message"))) { + System.out.println("======================== = " + result); + cacheClient.set(param.getPhone(),code,5L,TimeUnit.MINUTES); + String key = "code:" + param.getPhone(); + redisUtil.set(key,code,5L,TimeUnit.MINUTES); + return success("发送成功",result.get("Message")); + }else{ + return fail("发送失败"); + } + } catch (ServerException e) { + e.printStackTrace(); + } catch (ClientException e) { + e.printStackTrace(); + } + } + return fail("发送失败"); + } + + @Operation(summary = "重置密码") + @PutMapping("/password") + public ApiResult resetPassword(@RequestBody User user) { + if (user.getPassword() == null) { + return fail("参数不正确"); + } + if (user.getCode() == null) { + return fail("验证码不能为空"); + } + // 短信验证码校验 + String code = cacheClient.get(user.getPhone(), String.class); + if (!StrUtil.equals(code,user.getCode())) { + return fail("验证码不正确"); + } + + user.setUserId(getLoginUserId()); + user.setPassword(userService.encodePassword(user.getPassword())); + if (userService.updateById(user)) { + return success("密码修改成功"); + } else { + return fail("密码修改失败"); + } + } + + @Operation(summary = "短信验证码登录") + @PostMapping("/loginBySms") + public ApiResult loginBySms(@RequestBody LoginParam param, HttpServletRequest request) { + final String phone = param.getPhone(); + final Integer tenantId = param.getTenantId(); + final String code = param.getCode(); + + User user = userService.getByUsername(phone, tenantId); + // 验证码校验 + String key = "code:" + param.getPhone(); + if(!code.equals(redisUtil.get(key))){ + String message = "验证码不正确"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, tenantId,request); + return fail(message, null); + } + if (user == null) { + String message = "账号不存在"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, tenantId,request); + return fail(message, null); + } + if (!user.getStatus().equals(0)) { + String message = "账号被冻结"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, tenantId, request); + return fail(message, null); + } + loginRecordService.saveAsync(phone, LoginRecord.TYPE_LOGIN, null, tenantId, request); + + // 设置过期时间 + Long tokenExpireTime = configProperties.getTokenExpireTime(); + final JSONObject register = cacheClient.getSettingInfo("register", tenantId); + if(register != null){ + final String ExpireTime = register.getString("tokenExpireTime"); + if (ExpireTime != null) { + tokenExpireTime = Long.valueOf(ExpireTime); + } + } + + // 签发token + String access_token = JwtUtil.buildToken(new JwtSubject(phone, tenantId), + tokenExpireTime, configProperties.getTokenKey()); + return success("登录成功", new LoginResult(access_token, user)); + } + + @Operation(summary = "会员注册") + @PostMapping("/register") + public ApiResult register(@RequestBody LoginParam param, HttpServletRequest request) { + final String phone = param.getPhone(); + final Integer tenantId = param.getTenantId(); + final String code = param.getCode(); + + User user = userService.getByUsername(phone, tenantId); + // 验证码校验 + String key = "code:" + param.getPhone(); + if(!code.equals(redisUtil.get(key))){ + String message = "验证码不正确"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, tenantId,request); + return fail(message, null); + } + if (user == null) { + String message = "账号不存在"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, tenantId,request); + return fail(message, null); + } + if (!user.getStatus().equals(0)) { + String message = "账号被冻结"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, tenantId, request); + return fail(message, null); + } + loginRecordService.saveAsync(phone, LoginRecord.TYPE_LOGIN, null, tenantId, request); + + // 设置过期时间 + Long tokenExpireTime = configProperties.getTokenExpireTime(); + final JSONObject register = cacheClient.getSettingInfo("register", tenantId); + if(register != null){ + final String ExpireTime = register.getString("tokenExpireTime"); + if (ExpireTime != null) { + tokenExpireTime = Long.valueOf(ExpireTime); + } + } + + // 签发token + String access_token = JwtUtil.buildToken(new JwtSubject(phone, tenantId), + tokenExpireTime, configProperties.getTokenKey()); + return success("登录成功", new LoginResult(access_token, user)); + } +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/MenuController.java b/src/main/java/com/gxwebsoft/common/system/controller/MenuController.java new file mode 100644 index 0000000..ba11820 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/MenuController.java @@ -0,0 +1,145 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.Plug; +import com.gxwebsoft.common.system.param.MenuParam; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.PlugService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 菜单控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:23 + */ +@Tag(name = "菜单管理") +@RestController +@RequestMapping("/api/system/menu") +public class MenuController extends BaseController { + @Resource + private MenuService menuService; + @Resource + private PlugService plugService; + + @PreAuthorize("hasAuthority('sys:menu:list')") + @Operation(summary = "分页查询菜单") + @GetMapping("/page") + public ApiResult> page(MenuParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return success(menuService.page(page, page.getWrapper())); + } + + @PreAuthorize("hasAuthority('sys:menu:list')") + @Operation(summary = "查询全部菜单") + @GetMapping() + public ApiResult> list(MenuParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return success(menuService.list(page.getOrderWrapper())); + } + + @PreAuthorize("hasAuthority('sys:menu:list')") + @Operation(summary = "根据id查询菜单") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(menuService.getById(id)); + } + + @PreAuthorize("hasAuthority('sys:menu:save')") + @Operation(summary = "添加菜单") + @PostMapping() + public ApiResult add(@RequestBody Menu menu) { + if (menu.getParentId() == null) { + menu.setParentId(0); + } + if (menuService.save(menu)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:update')") + @Operation(summary = "修改菜单") + @PutMapping() + public ApiResult update(@RequestBody Menu menu) { + if (menuService.updateById(menu)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:remove')") + @Operation(summary = "删除菜单") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (menuService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:save')") + @Operation(summary = "批量添加菜单") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List menus) { + if (menuService.saveBatch(menus)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:update')") + @Operation(summary = "批量修改菜单") + @PutMapping("/batch") + public ApiResult updateBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(menuService, "menu_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:remove')") + @Operation(summary = "批量删除菜单") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (menuService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:update')") + @Operation(summary = "菜单克隆") + @PostMapping("/clone") + public ApiResult onClone(@RequestBody MenuParam param){ + if(menuService.cloneMenu(param)){ + return success("克隆成功,请刷新"); + } + return fail("克隆失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:update')") + @Operation(summary = "安装插件") + @GetMapping("/install/{id}") + public ApiResult install(@PathVariable("id") Integer id){ + if(menuService.install(id)){ + // 更新安装次数 + final Plug plug = plugService.getOne(new LambdaQueryWrapper().eq(Plug::getMenuId, id)); + plug.setInstalls(plug.getInstalls() + 1); + plugService.updateById(plug); + return success("安装成功"); + } + return fail("安装失败",id); + } +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/OperationRecordController.java b/src/main/java/com/gxwebsoft/common/system/controller/OperationRecordController.java new file mode 100644 index 0000000..ec54bc4 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/OperationRecordController.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.OperationRecord; +import com.gxwebsoft.common.system.param.OperationRecordParam; +import com.gxwebsoft.common.system.service.OperationRecordService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 操作日志控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:12 + */ +@Tag(name = "操作日志") +@RestController +@RequestMapping("/api/system/operation-record") +public class OperationRecordController extends BaseController { + @Resource + private OperationRecordService operationRecordService; + + /** + * 分页查询操作日志 + */ + @PreAuthorize("hasAuthority('sys:operation-record:list')") + @Operation(summary = "分页查询操作日志") + @GetMapping("/page") + public ApiResult> page(OperationRecordParam param) { + return success(operationRecordService.pageRel(param)); + } + + /** + * 查询全部操作日志 + */ + @PreAuthorize("hasAuthority('sys:operation-record:list')") + @Operation(summary = "查询全部操作日志") + @GetMapping() + public ApiResult> list(OperationRecordParam param) { + return success(operationRecordService.listRel(param)); + } + + /** + * 根据id查询操作日志 + */ + @PreAuthorize("hasAuthority('sys:operation-record:list')") + @Operation(summary = "根据id查询操作日志") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(operationRecordService.getByIdRel(id)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/OrganizationController.java b/src/main/java/com/gxwebsoft/common/system/controller/OrganizationController.java new file mode 100644 index 0000000..4174b04 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/OrganizationController.java @@ -0,0 +1,130 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.Organization; +import com.gxwebsoft.common.system.param.OrganizationParam; +import com.gxwebsoft.common.system.service.OrganizationService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 组织机构控制器 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Tag(name = "组织机构管理") +@RestController +@RequestMapping("/api/system/organization") +public class OrganizationController extends BaseController { + @Resource + private OrganizationService organizationService; + + @PreAuthorize("hasAuthority('sys:org:list')") + @Operation(summary = "分页查询组织机构") + @GetMapping("/page") + public ApiResult> page(OrganizationParam param) { + return success(organizationService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:org:list')") + @Operation(summary = "查询全部组织机构") + @GetMapping() + public ApiResult> list(OrganizationParam param) { + return success(organizationService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:org:list')") + @Operation(summary = "根据id查询组织机构") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(organizationService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:org:save')") + @Operation(summary = "添加组织机构") + @PostMapping() + public ApiResult add(@RequestBody Organization organization) { + if (organization.getParentId() == null) { + organization.setParentId(0); + } + if (organizationService.count(new LambdaQueryWrapper() + .eq(Organization::getOrganizationName, organization.getOrganizationName()) + .eq(Organization::getParentId, organization.getParentId())) > 0) { + return fail("机构名称已存在"); + } + if (organizationService.save(organization)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:org:update')") + @Operation(summary = "修改组织机构") + @PutMapping() + public ApiResult update(@RequestBody Organization organization) { + if (organization.getOrganizationName() != null) { + if (organization.getParentId() == null) { + organization.setParentId(0); + } + if (organizationService.count(new LambdaQueryWrapper() + .eq(Organization::getOrganizationName, organization.getOrganizationName()) + .eq(Organization::getParentId, organization.getParentId()) + .ne(Organization::getOrganizationId, organization.getOrganizationId())) > 0) { + return fail("机构名称已存在"); + } + } + if (organizationService.updateById(organization)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:org:remove')") + @Operation(summary = "删除组织机构") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (organizationService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:org:save')") + @Operation(summary = "批量添加组织机构") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List organizationList) { + if (organizationService.saveBatch(organizationList)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:org:update')") + @Operation(summary = "批量修改组织机构") + @PutMapping("/batch") + public ApiResult updateBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(organizationService, Organization::getOrganizationId)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:org:remove')") + @Operation(summary = "批量删除组织机构") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (organizationService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/PlugController.java b/src/main/java/com/gxwebsoft/common/system/controller/PlugController.java new file mode 100644 index 0000000..2429e99 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/PlugController.java @@ -0,0 +1,161 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.Plug; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.PlugParam; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.PlugService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 插件扩展控制器 + * + * @author 科技小王子 + * @since 2023-05-18 11:57:37 + */ +@Tag(name = "插件扩展管理") +@RestController +@RequestMapping("/api/system/plug") +public class PlugController extends BaseController { + @Resource + private PlugService plugService; + @Resource + private MenuService menuService; + + @PreAuthorize("hasAuthority('sys:plug:list')") + @Operation(summary = "分页查询插件扩展") + @GetMapping("/page") + public ApiResult> page(PlugParam param) { + // 如果不传userId,只显示审核通过的插件 + if (param.getUserId() == null) { + param.setStatus(20); + } + // 使用关联查询 + return success(plugService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:plug:list')") + @Operation(summary = "查询全部插件扩展") + @GetMapping() + public ApiResult> list(PlugParam param) { + // 使用关联查询 + return success(plugService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:plug:list')") + @Operation(summary = "根据id查询插件扩展") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(plugService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:plug:save')") + @Operation(summary = "添加插件扩展") + @PostMapping() + public ApiResult save(@RequestBody Plug plug) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + plug.setUserId(loginUser.getUserId()); + } + if (plugService.save(plug)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:plug:update')") + @Operation(summary = "修改插件扩展") + @PutMapping() + public ApiResult update(@RequestBody Plug plug) { + if (plugService.updateById(plug)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:plug:remove')") + @Operation(summary = "删除插件扩展") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (plugService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:plug:save')") + @Operation(summary = "批量添加插件扩展") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (plugService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:plug:update')") + @Operation(summary = "批量修改插件扩展") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(plugService, "menu_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:plug:remove')") + @Operation(summary = "批量删除插件扩展") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (plugService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:plug:save')") + @Operation(summary = "发布插件") + @PostMapping("/plug") + public ApiResult plug(@RequestBody Plug plug){ + final Integer menuId = plug.getParentId(); + // 查重 + final long count = plugService.count(new LambdaQueryWrapper().eq(Plug::getMenuId, menuId)); + if(count > 0){ + return fail("请勿重复发布"); + } + // 准备数据 + final Menu menu = menuService.getById(menuId); + plug.setUserId(getLoginUserId()); + plug.setMenuId(menuId); + plug.setTenantId(getTenantId()); + plug.setIcon(menu.getIcon()); + plug.setPath(menu.getPath()); + plug.setComponent(menu.getComponent()); + plug.setAuthority(menu.getAuthority()); + plug.setTitle(menu.getTitle()); + plug.setMenuType(menu.getMenuType()); + plug.setMeta(menu.getMeta()); + plug.setParentId(menu.getParentId()); + plug.setHide(menu.getHide()); + plug.setSortNumber(menu.getSortNumber()); + if(plugService.save(plug)){ + return success("发布成功"); + } + return fail("发布失败"); + } +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/RedisUtilController.java b/src/main/java/com/gxwebsoft/common/system/controller/RedisUtilController.java new file mode 100644 index 0000000..3e1cac5 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/RedisUtilController.java @@ -0,0 +1,77 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.utils.CacheClient; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/redis-util") +@Tag(name = "Redis缓存工具接口") +public class RedisUtilController extends BaseController { + private CacheClient cacheClient; + private final StringRedisTemplate redisTemplate; + private static final String SPLIT = ":"; + private static final String PREFIX_ENTITY_LIKE = "focus:user"; + private static final String PREFIX_USER_LIKE = "like:user"; + private static final String PREFIX_FOLLOWEE = "followee"; + private static final String PREFIX_FOLLOWER = "follower"; + + + public RedisUtilController(StringRedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + @Operation(summary = "添加关注") + @PostMapping("/addFocus") + public ApiResult addFocus(@RequestBody User user) { + final Integer userId = user.getUserId(); + redisTemplate.opsForZSet().incrementScore(getFocusKey(userId), userId.toString(), 1); + return success("关注成功"); + } + + /** + * 某个用户的关注数 + * @return like:entity:[entityId] ->set(userId) + */ + public static String getFocusKey(Integer userId) { + return PREFIX_ENTITY_LIKE + SPLIT + userId; + } + + /** + * 某个用户的赞 + * @return like:entity:[entityId] ->set(userId) + */ + public static String getEntityLikeKey(int entityType, int entityId) { + return PREFIX_ENTITY_LIKE + SPLIT + entityType + SPLIT + entityId; + } + + /** + * 某个用户的赞 + * @return like:user:[userId] ->int + */ + public static String getUserLikeKey(int userId) { + return PREFIX_USER_LIKE + SPLIT + userId; + } + + /** + * 某个用户关注的实体(键:用户Id,值:实体Id) + * @return followee:[userId:entityType] ->zSet(entityId,now) + */ + public static String getFolloweeKey(int userId, int entityType) { + return PREFIX_FOLLOWEE + SPLIT + userId + SPLIT + entityType; + } + + /** + * 某个实体拥有的粉丝(键:实体Id,值:用户Id) + * @return follower:[entityType:entityId] ->zSet(entityId,now) + */ + public static String getFollowerKey(int entityType, int entityId) { + return PREFIX_FOLLOWER + SPLIT + entityType + SPLIT + entityId; + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/RoleController.java b/src/main/java/com/gxwebsoft/common/system/controller/RoleController.java new file mode 100644 index 0000000..eece032 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/RoleController.java @@ -0,0 +1,144 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.param.RoleParam; +import com.gxwebsoft.common.system.service.RoleService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 角色控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:02 + */ +@Tag(name = "角色管理") +@RestController +@RequestMapping("/api/system/role") +public class RoleController extends BaseController { + @Resource + private RoleService roleService; + + @PreAuthorize("hasAuthority('sys:role:list')") + @Operation(summary = "分页查询角色") + @GetMapping("/page") + public ApiResult> page(RoleParam param) { + PageParam page = new PageParam<>(param); + return success(roleService.page(page, page.getWrapper())); + } + + @PreAuthorize("hasAuthority('sys:role:list')") + @Operation(summary = "查询全部角色") + @GetMapping() + public ApiResult> list(RoleParam param) { + PageParam page = new PageParam<>(param); + return success(roleService.list(page.getOrderWrapper())); + } + + @PreAuthorize("hasAuthority('sys:role:list')") + @Operation(summary = "根据id查询角色") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(roleService.getById(id)); + } + + @PreAuthorize("hasAuthority('sys:role:save')") + @Operation(summary = "添加角色") + @PostMapping() + public ApiResult save(@RequestBody Role role) { + if (roleService.count(new LambdaQueryWrapper().eq(Role::getRoleCode, role.getRoleCode())) > 0) { + return fail("角色标识已存在"); + } + if (roleService.count(new LambdaQueryWrapper().eq(Role::getRoleName, role.getRoleName())) > 0) { + return fail("角色名称已存在"); + } + if (roleService.save(role)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:role:update')") + @Operation(summary = "修改角色") + @PutMapping() + public ApiResult update(@RequestBody Role role) { + if (role.getRoleCode() != null && roleService.count(new LambdaQueryWrapper() + .eq(Role::getRoleCode, role.getRoleCode()) + .ne(Role::getRoleId, role.getRoleId())) > 0) { + return fail("角色标识已存在"); + } + if (role.getRoleName() != null && roleService.count(new LambdaQueryWrapper() + .eq(Role::getRoleName, role.getRoleName()) + .ne(Role::getRoleId, role.getRoleId())) > 0) { + return fail("角色名称已存在"); + } + if (roleService.updateById(role)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:role:remove')") + @Operation(summary = "删除角色") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (roleService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:role:save')") + @Operation(summary = "批量添加角色") + @PostMapping("/batch") + public ApiResult> saveBatch(@RequestBody List list) { + // 校验是否重复 + if (CommonUtil.checkRepeat(list, Role::getRoleName)) { + return fail("角色名称存在重复", null); + } + if (CommonUtil.checkRepeat(list, Role::getRoleCode)) { + return fail("角色标识存在重复", null); + } + // 校验是否存在 + List codeExists = roleService.list(new LambdaQueryWrapper().in(Role::getRoleCode, + list.stream().map(Role::getRoleCode).collect(Collectors.toList()))); + if (codeExists.size() > 0) { + return fail("角色标识已存在", codeExists.stream().map(Role::getRoleCode) + .collect(Collectors.toList())).setCode(2); + } + List nameExists = roleService.list(new LambdaQueryWrapper().in(Role::getRoleName, + list.stream().map(Role::getRoleCode).collect(Collectors.toList()))); + if (nameExists.size() > 0) { + return fail("角色标识已存在", nameExists.stream().map(Role::getRoleCode) + .collect(Collectors.toList())).setCode(3); + } + if (roleService.saveBatch(list)) { + return success("添加成功", null); + } + return fail("添加失败", null); + } + + @PreAuthorize("hasAuthority('sys:role:remove')") + @Operation(summary = "批量删除角色") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (roleService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/RoleMenuController.java b/src/main/java/com/gxwebsoft/common/system/controller/RoleMenuController.java new file mode 100644 index 0000000..fdc186a --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/RoleMenuController.java @@ -0,0 +1,96 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.RoleMenu; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.RoleMenuService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +/** + * 角色菜单控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:01 + */ +@Tag(name = "角色菜单管理") +@RestController +@RequestMapping("/api/system/role-menu") +public class RoleMenuController extends BaseController { + @Resource + private RoleMenuService roleMenuService; + @Resource + private MenuService menuService; + + @PreAuthorize("hasAuthority('sys:role:list')") + @Operation(summary = "查询角色菜单") + @GetMapping("/{id}") + public ApiResult> list(@PathVariable("id") Integer roleId) { + List menus = menuService.list(new LambdaQueryWrapper().orderByAsc(Menu::getSortNumber)); + List roleMenus = roleMenuService.list(new LambdaQueryWrapper() + .eq(RoleMenu::getRoleId, roleId)); + for (Menu menu : menus) { + menu.setChecked(roleMenus.stream().anyMatch((d) -> d.getMenuId().equals(menu.getMenuId()))); + } + return success(menus); + } + + @Transactional(rollbackFor = {Exception.class}) + @PreAuthorize("hasAuthority('sys:role:update')") + @Operation(summary = "修改角色菜单") + @PutMapping("/{id}") + public ApiResult update(@PathVariable("id") Integer roleId, @RequestBody List menuIds) { + roleMenuService.remove(new LambdaUpdateWrapper().eq(RoleMenu::getRoleId, roleId)); + if (menuIds != null && menuIds.size() > 0) { + List roleMenuList = new ArrayList<>(); + for (Integer menuId : menuIds) { + RoleMenu roleMenu = new RoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(menuId); + roleMenuList.add(roleMenu); + } + if (!roleMenuService.saveBatch(roleMenuList)) { + throw new BusinessException("保存失败"); + } + } + return success("保存成功"); + } + + @PreAuthorize("hasAuthority('sys:role:update')") + @Operation(summary = "添加角色菜单") + @PostMapping("/{id}") + public ApiResult addRoleAuth(@PathVariable("id") Integer roleId, @RequestBody Integer menuId) { + RoleMenu roleMenu = new RoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(menuId); + if (roleMenuService.save(roleMenu)) { + return success(); + } + return fail(); + } + + @PreAuthorize("hasAuthority('sys:role:update')") + @Operation(summary = "移除角色菜单") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer roleId, @RequestBody Integer menuId) { + if (roleMenuService.remove(new LambdaUpdateWrapper() + .eq(RoleMenu::getRoleId, roleId).eq(RoleMenu::getMenuId, menuId))) { + return success(); + } + return fail(); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/SettingController.java b/src/main/java/com/gxwebsoft/common/system/controller/SettingController.java new file mode 100644 index 0000000..51e670d --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/SettingController.java @@ -0,0 +1,178 @@ +package com.gxwebsoft.common.system.controller; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.Setting; +import com.gxwebsoft.common.system.entity.Tenant; +import com.gxwebsoft.common.system.param.SettingParam; +import com.gxwebsoft.common.system.service.SettingService; +import com.gxwebsoft.common.system.service.TenantService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 系统设置控制器 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Tag(name = "系统设置管理") +@RestController +@RequestMapping("/api/system/setting") +public class SettingController extends BaseController { + @Resource + private SettingService settingService; + @Resource + private TenantService tenantService; + @Resource + private RedisUtil redisUtil; + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "分页查询系统设置") + @GetMapping("/page") + public ApiResult> page(SettingParam param) { + // 使用关联查询 + return success(settingService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "查询全部系统设置") + @GetMapping() + public ApiResult> list(SettingParam param) { + // 使用关联查询 + return success(settingService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "根据id查询系统设置") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(settingService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "添加系统设置") + @PostMapping() + public ApiResult save(@RequestBody Setting setting) { + if (settingService.save(setting)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "修改系统设置") + @PutMapping() + public ApiResult update(@RequestBody Setting setting) { + if (settingService.updateById(setting)) { + // 更新系统设置信息到缓存 + String key = "setting:" + setting.getSettingKey() + ":" + getTenantId(); + System.out.println("key = " + key); + redisUtil.set(key, JSON.parseObject(setting.getContent())); + // 创建微信支付Bean +// settingService.initConfig(setting); + // 更新租户信息 + if (setting.getSettingKey().equals("setting")) { + System.out.println("修改系统设置 = " + setting.getContent()); + final String content = setting.getContent(); + final JSONObject jsonObject = JSONObject.parseObject(content); + final String siteName = jsonObject.getString("siteName"); + final String logo = jsonObject.getString("logo"); + System.out.println("siteName = " + siteName); + final Tenant tenant = new Tenant(); + tenant.setTenantName(siteName); + tenant.setTenantId(getTenantId()); + tenant.setLogo(logo); + tenantService.updateById(tenant); + } + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:setting:remove')") + @Operation(summary = "删除系统设置") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (settingService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "批量添加系统设置") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (settingService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:setting:update')") + @Operation(summary = "批量修改系统设置") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(settingService, "setting_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:setting:remove')") + @Operation(summary = "批量删除系统设置") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (settingService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:setting:data')") + @Operation(summary = "查询租户设置信息") + @GetMapping("/data") + public ApiResult data() { + return success(settingService.getData("setting")); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "更新主题皮肤") + @PutMapping("/theme") + public ApiResult theme(@RequestBody Setting setting) { + String key = "theme:".concat(getTenantId().toString()); + // 新增 + final Setting one = settingService.getOne(new LambdaQueryWrapper().eq(Setting::getSettingKey, setting.getSettingKey())); + if(one == null){ + settingService.save(setting); + redisUtil.set(key,setting.getContent()); + return success("保存成功"); + } + // 更新 + final Setting update = settingService.getOne(new LambdaQueryWrapper().eq(Setting::getSettingKey, setting.getSettingKey())); + update.setContent(setting.getContent()); + if (settingService.updateById(update)) { + redisUtil.set(key,setting.getContent()); + return success("更新成功"); + } + return fail("更新失败"); + } + + @Operation(summary = "更新主题皮肤") + @GetMapping("/getTheme") + public ApiResult getTheme() { + String key = "theme:".concat(getTenantId().toString()); + return success("获取成功",redisUtil.get(key)); + } +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/TenantController.java b/src/main/java/com/gxwebsoft/common/system/controller/TenantController.java new file mode 100644 index 0000000..4114e04 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/TenantController.java @@ -0,0 +1,158 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.RoleMenu; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.RoleMenuService; +import com.gxwebsoft.common.system.service.TenantService; +import com.gxwebsoft.common.system.entity.Tenant; +import com.gxwebsoft.common.system.param.TenantParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 租户控制器 + * + * @author 科技小王子 + * @since 2023-07-17 17:49:53 + */ +@Tag(name = "租户管理") +@RestController +@RequestMapping("/api/system/tenant") +public class TenantController extends BaseController { + @Resource + private TenantService tenantService; + @Resource + private MenuService menuService; + @Resource + private RoleMenuService roleMenuService; + + @PreAuthorize("hasAuthority('sys:tenant:list')") + @Operation(summary = "分页查询租户") + @GetMapping("/page") + public ApiResult> page(TenantParam param) { + // 使用关联查询 + return success(tenantService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:tenant:list')") + @Operation(summary = "查询全部租户") + @GetMapping() + public ApiResult> list(TenantParam param) { + // 使用关联查询 + return success(tenantService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:tenant:list')") + @Operation(summary = "根据id查询租户") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(tenantService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:tenant:save')") + @Operation(summary = "添加租户") + @PostMapping() + public ApiResult save(@RequestBody Tenant tenant) { + System.out.println("tenant = " + tenant); + if (tenantService.save(tenant)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:tenant:update')") + @Operation(summary = "修改租户") + @PutMapping() + public ApiResult update(@RequestBody Tenant tenant) { + if (tenantService.updateById(tenant)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:tenant:remove')") + @Operation(summary = "删除租户") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (tenantService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:tenant:save')") + @Operation(summary = "批量添加租户") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (tenantService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:tenant:update')") + @Operation(summary = "批量修改租户") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(tenantService, "tenant_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:tenant:remove')") + @Operation(summary = "批量删除租户") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (tenantService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "租户角色权限初始化") + @GetMapping("/role-menu/{id}") + public ApiResult> initialization(@PathVariable("id") Integer roleId) { + List menus = menuService.list(new LambdaQueryWrapper().orderByAsc(Menu::getSortNumber)); + List roleMenus = roleMenuService.list(new LambdaQueryWrapper() + .eq(RoleMenu::getRoleId, roleId)); + for (Menu menu : menus) { + menu.setChecked(roleMenus.stream().anyMatch((d) -> d.getMenuId().equals(menu.getMenuId()))); + } + List menuIds = menus.stream().map(Menu::getMenuId).collect(Collectors.toList()); + roleMenuService.remove(new LambdaUpdateWrapper().eq(RoleMenu::getRoleId, roleId)); + if (menuIds.size() > 0) { + List roleMenuList = new ArrayList<>(); + for (Integer menuId : menuIds) { + RoleMenu roleMenu = new RoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(menuId); + roleMenuList.add(roleMenu); + } + if (!roleMenuService.saveBatch(roleMenuList)) { + throw new BusinessException("保存失败"); + } + } + return success(menus); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/UserCollectionController.java b/src/main/java/com/gxwebsoft/common/system/controller/UserCollectionController.java new file mode 100644 index 0000000..0585272 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/UserCollectionController.java @@ -0,0 +1,135 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserCollection; +import com.gxwebsoft.common.system.param.UserCollectionParam; +import com.gxwebsoft.common.system.service.UserCollectionService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 我的收藏控制器 + * + * @author 科技小王子 + * @since 2024-04-28 18:08:32 + */ +@Tag(name = "用户收藏") +@RestController +@RequestMapping("/api/system/user-collection") +public class UserCollectionController extends BaseController { + @Resource + private UserCollectionService userCollectionService; + + @PreAuthorize("hasAuthority('sys:userCollection:list')") + @Operation(summary = "分页查询我的收藏") + @GetMapping("/page") + public ApiResult> page(UserCollectionParam param) { + // 使用关联查询 + return success(userCollectionService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userCollection:list')") + @Operation(summary = "查询全部我的收藏") + @GetMapping() + public ApiResult> list(UserCollectionParam param) { + // 使用关联查询 + return success(userCollectionService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userCollection:list')") + @Operation(summary = "根据id查询我的收藏") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(userCollectionService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:userCollection:save')") + @OperationLog + @Operation(summary = "添加和取消收藏") + @PostMapping() + public ApiResult save(@RequestBody UserCollection userCollection) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + userCollection.setUserId(loginUser.getUserId()); + userCollection.setTid(userCollection.getTid()); + final UserCollection one = userCollectionService.getOne(new LambdaQueryWrapper().eq(UserCollection::getUserId, loginUser.getUserId()).eq(UserCollection::getTid, userCollection.getTid()).last("limit 1")); + if (one != null) { + userCollectionService.removeById(one.getId()); + return success("已取消收藏"); + } + if (userCollectionService.save(userCollection)) { + return success("已添加收藏"); + } + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userCollection:update')") + @OperationLog + @Operation(summary = "修改我的收藏") + @PutMapping() + public ApiResult update(@RequestBody UserCollection userCollection) { + if (userCollectionService.updateById(userCollection)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userCollection:remove')") + @OperationLog + @Operation(summary = "删除我的收藏") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userCollectionService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:userCollection:save')") + @OperationLog + @Operation(summary = "批量添加我的收藏") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (userCollectionService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userCollection:update')") + @OperationLog + @Operation(summary = "批量修改我的收藏") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(userCollectionService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userCollection:remove')") + @OperationLog + @Operation(summary = "批量删除我的收藏") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (userCollectionService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/UserController.java b/src/main/java/com/gxwebsoft/common/system/controller/UserController.java new file mode 100644 index 0000000..19b99bc --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/UserController.java @@ -0,0 +1,401 @@ +package com.gxwebsoft.common.system.controller; + +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.*; +import com.gxwebsoft.common.system.param.UserImportParam; +import com.gxwebsoft.common.system.param.UserParam; +import com.gxwebsoft.common.system.service.DictionaryDataService; +import com.gxwebsoft.common.system.service.OrganizationService; +import com.gxwebsoft.common.system.service.RoleService; +import com.gxwebsoft.common.system.service.UserService; +import io.swagger.v3.oas.annotations.tags.Tag; + +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 用户控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:41 + */ +@Tag(name = "用户管理") +@RestController +@RequestMapping("/api/system/user") +public class UserController extends BaseController { + @Resource + private UserService userService; + @Resource + private RoleService roleService; + @Resource + private OrganizationService organizationService; + @Resource + private DictionaryDataService dictionaryDataService; + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "分页查询用户") + @GetMapping("/page") + public ApiResult> page(UserParam param) { + return success(userService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "分页查询用户") + @GetMapping("/pageAdminByPhone") + public ApiResult> pageAdminByPhone(UserParam param) { + return success(userService.pageAdminByPhone(param)); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "查询全部用户") + @GetMapping() + public ApiResult> list(UserParam param) { + return success(userService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "根据id查询用户") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(userService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "根据手机号码查询用户") + @GetMapping("/getByPhone/{phone}") + public ApiResult getByPhone(@PathVariable("phone") String phone) { + return success(userService.getByPhone(phone)); + } + + @PreAuthorize("hasAuthority('sys:user:save')") + @Operation(summary = "添加用户") + @PostMapping() + public ApiResult add(@RequestBody User user) { + user.setStatus(0); + user.setPassword(userService.encodePassword(user.getPassword())); + if (userService.saveUser(user)) { + return success("添加成功",user.getUserId()); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:user:save')") + @Operation(summary = "批量添加用户") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List userList) { + userList.forEach(d -> { + d.setStatus(0); + if (d.getPassword() != null) { + d.setPassword(userService.encodePassword(d.getPassword())); + } + }); + if (userService.saveBatch(userList)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:user:save')") + @Operation(summary = "批量添加用户并返回userId") + @PostMapping("/batchBackUserId") + public ApiResult saveBatchBackUserId(@RequestBody List userList) { + userList.forEach(d -> { + d.setStatus(0); + d.setPassword(userService.encodePassword(d.getPassword())); + }); + final Set phones = userList.stream().map(User::getPhone).collect(Collectors.toSet()); + if (userService.saveBatch(userList)) { + final UserParam userParam = new UserParam(); + userParam.setPhones(phones); + userParam.setLimit(500L); + final PageResult result = userService.pageRel(userParam); + final Set collect = result.getList().stream().map(User::getUserId).collect(Collectors.toSet()); + return success("添加成功",collect); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "修改用户") + @PutMapping() + public ApiResult update(@RequestBody User user) { + user.setStatus(null); + user.setUsername(null); + user.setPassword(null); + if (userService.updateUser(user)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:user:remove')") + @OperationLog + @Operation(summary = "删除用户") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "批量修改用户") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(userService, User::getUserId)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:user:remove')") + @OperationLog + @Operation(summary = "批量删除用户") + @Transactional(rollbackFor = {Exception.class}) + @DeleteMapping("/batch") + public ApiResult deleteBatch(@RequestBody List ids) { + if (userService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "修改用户状态") + @PutMapping("/status") + public ApiResult updateStatus(@RequestBody User user) { + if (user.getUserId() == null || user.getStatus() == null || !Arrays.asList(0, 1).contains(user.getStatus())) { + return fail("参数不正确"); + } + User u = new User(); + u.setUserId(user.getUserId()); + u.setStatus(user.getStatus()); + if (userService.updateById(u)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "修改推荐状态") + @PutMapping("/recommend") + public ApiResult updateRecommend(@RequestBody User user) { + if (user.getUserId() == null || user.getRecommend() == null || !Arrays.asList(0, 1).contains(user.getRecommend())) { + return fail("参数不正确"); + } + User u = new User(); + u.setUserId(user.getUserId()); + u.setRecommend(user.getRecommend()); + if (userService.updateById(u)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "批量修改用户状态") + @PutMapping("/status/batch") + public ApiResult updateStatusBatch(@RequestBody BatchParam batchParam) { + if (!Arrays.asList(0, 1).contains(batchParam.getData())) { + return fail("状态值不正确"); + } + if (userService.update(new LambdaUpdateWrapper() + .in(User::getUserId, batchParam.getIds()) + .set(User::getStatus, batchParam.getData()))) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "重置密码") + @PutMapping("/password") + public ApiResult resetPassword(@RequestBody User user) { + if (user.getUserId() == null || StrUtil.isBlank(user.getPassword())) { + return fail("参数不正确"); + } + User u = new User(); + u.setUserId(user.getUserId()); + u.setPassword(userService.encodePassword(user.getPassword())); + if (userService.updateById(u)) { + return success("重置成功"); + } else { + return fail("重置失败"); + } + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "批量重置密码") + @PutMapping("/password/batch") + public ApiResult resetPasswordBatch(@RequestBody BatchParam batchParam) { + if (batchParam.getIds() == null || batchParam.getIds().size() == 0) { + return fail("请选择用户"); + } + if (batchParam.getData() == null) { + return fail("请输入密码"); + } + if (userService.update(new LambdaUpdateWrapper() + .in(User::getUserId, batchParam.getIds()) + .set(User::getPassword, userService.encodePassword(batchParam.getData())))) { + return success("重置成功"); + } else { + return fail("重置失败"); + } + } + + @Operation(summary = "检查用户是否存在") + @GetMapping("/existence") + public ApiResult existence(ExistenceParam param) { + if (param.isExistence(userService, User::getUserId)) { + return success(param.getValue() + "已存在"); + } + return fail(param.getValue() + "不存在"); + } + + /** + * excel导入用户 + */ + @PreAuthorize("hasAuthority('sys:user:save')") + @Operation(summary = "导入用户") + @Transactional(rollbackFor = {Exception.class}) + @PostMapping("/import") + public ApiResult> importBatch(MultipartFile file) { + ImportParams importParams = new ImportParams(); + try { + List list = ExcelImportUtil.importExcel(file.getInputStream(), + UserImportParam.class, importParams); + // 校验是否重复 + if (CommonUtil.checkRepeat(list, UserImportParam::getUsername)) { + return fail("账号存在重复", null); + } + if (CommonUtil.checkRepeat(list, UserImportParam::getPhone)) { + return fail("手机号存在重复", null); + } + // 校验是否存在 + List usernameExists = userService.list(new LambdaQueryWrapper().in(User::getUsername, + list.stream().map(UserImportParam::getUsername).collect(Collectors.toList()))); + if (usernameExists.size() > 0) { + return fail("账号已经存在", + usernameExists.stream().map(User::getUsername).collect(Collectors.toList())); + } + List phoneExists = userService.list(new LambdaQueryWrapper().in(User::getPhone, + list.stream().map(UserImportParam::getPhone).collect(Collectors.toList()))); + if (phoneExists.size() > 0) { + return fail("手机号已经存在", + phoneExists.stream().map(User::getPhone).collect(Collectors.toList())); + } + // 添加 + List users = new ArrayList<>(); + for (UserImportParam one : list) { + User u = new User(); + u.setStatus(0); + u.setUsername(one.getUsername()); + u.setPassword(userService.encodePassword(one.getPassword())); + u.setNickname(one.getNickname()); + u.setPhone(one.getPhone()); + Role role = roleService.getOne(new QueryWrapper() + .eq("role_name", one.getRoleName()), false); + if (role == null) { + return fail("角色不存在", Collections.singletonList(one.getRoleName())); + } else { + u.setRoles(Collections.singletonList(role)); + } + Organization organization = organizationService.getOne(new QueryWrapper() + .eq("organization_full_name", one.getOrganizationName()), false); + if (organization == null) { + return fail("机构不存在", Collections.singletonList(one.getOrganizationName())); + } else { + u.setOrganizationId(organization.getOrganizationId()); + } + DictionaryData sex = dictionaryDataService.getByDictCodeAndName("sex", one.getSexName()); + if (sex == null) { + return fail("性别不存在", Collections.singletonList(one.getSexName())); + } else { + u.setSex(sex.getDictDataCode()); + } + } + if (userService.saveBatch(users)) { + return success("导入成功", null); + } + } catch (Exception e) { + e.printStackTrace(); + } + return fail("导入失败", null); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @PostMapping("/getAvatarByMpWx") + @Operation(summary = "更新微信头像") + public ApiResult getAvatarByMpWx(@RequestBody User user){ + user.setAvatar("https://oa.gxwebsoft.com/assets/logo.7ccfefb9.svg"); + if (userService.updateUser(user)) { + return success("更新成功"); + } + return fail("更新失败"); + } + + @PostMapping("/updatePointsBySign") + @Operation(summary = "签到成功累加积分") + public ApiResult updatePointsBySign(){ + final User loginUser = getLoginUser(); + loginUser.setPoints(loginUser.getPoints() + 1); + if (userService.updateUser(loginUser)) { + return success("签到成功"); + } + return fail("签到失败"); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @PutMapping("/updateUserBalance") + @Operation(summary = "更新用户余额") + public ApiResult updateUserBalance(@RequestBody User user){ + if (getLoginUser() == null) { + return fail("请先登录"); + } + if (userService.updateUser(user)) { + return success("操作成功"); + } + return fail("操作失败"); + } + + @PreAuthorize("hasAuthority('sys:user:list')") + @OperationLog + @Operation(summary = "统计用户余额") + @GetMapping("/countUserBalance") + public ApiResult countUserBalance(User param) { + final LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.gt(User::getBalance, 0); + if (!param.getOrganizationId().equals(0)) { + wrapper.eq(User::getOrganizationId,param.getOrganizationId()); + } + final List list = userService.list(wrapper); + final BigDecimal totalBalance = list.stream().map(User::getBalance).reduce(BigDecimal.ZERO, BigDecimal::add); + // System.out.println("统计用户余额 = " + totalBalance); + return success("统计成功",totalBalance); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/UserFileController.java b/src/main/java/com/gxwebsoft/common/system/controller/UserFileController.java new file mode 100644 index 0000000..b56214d --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/UserFileController.java @@ -0,0 +1,158 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.utils.FileServerUtil; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.service.UserFileService; +import com.gxwebsoft.common.system.entity.UserFile; +import com.gxwebsoft.common.system.param.UserFileParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 用户文件控制器 + * + * @author WebSoft + * @since 2022-07-21 14:34:40 + */ +@Tag(name = "用户文件管理") +@RestController +@RequestMapping("/api/system/user-file") +public class UserFileController extends BaseController { + @Resource + private UserFileService userFileService; + + @Operation(summary = "分页查询用户文件") + @GetMapping("/page") + public ApiResult> page(UserFileParam param, HttpServletRequest request) { + param.setUserId(getLoginUserId()); + PageParam page = new PageParam<>(param); + page.setDefaultOrder("is_directory desc"); + PageParam result = userFileService.page(page, page.getWrapper()); + List records = result.getRecords(); + String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/system/user-file") + "/file"; + for (UserFile record : records) { + if (StrUtil.isNotBlank(record.getPath())) { + record.setUrl(requestURL + "/" + record.getPath()); + if (FileServerUtil.isImage(record.getContentType())) { + record.setThumbnail(requestURL + "/thumbnail/" + record.getPath()); + } + record.setDownloadUrl(requestURL + "/download/" + record.getPath()); + } + } + return success(records, result.getTotal()); + } + + @Operation(summary = "查询全部用户文件") + @GetMapping() + public ApiResult> list(UserFileParam param, HttpServletRequest request) { + param.setUserId(getLoginUserId()); + PageParam page = new PageParam<>(param); + page.setDefaultOrder("is_directory desc"); + List records = userFileService.list(page.getOrderWrapper()); + String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/system/user-file") + "/file"; + for (UserFile record : records) { + if (StrUtil.isNotBlank(record.getPath())) { + record.setUrl(requestURL + "/" + record.getPath()); + if (FileServerUtil.isImage(record.getContentType())) { + record.setThumbnail(requestURL + "/thumbnail/" + record.getPath()); + } + record.setDownloadUrl(requestURL + "/download/" + record.getPath()); + } + } + return success(records); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "添加用户文件") + @PostMapping() + public ApiResult save(@RequestBody UserFile userFile) { + userFile.setUserId(getLoginUserId()); + if (userFile.getParentId() == null) { + userFile.setParentId(0); + } + if (userFile.getIsDirectory() != null && userFile.getIsDirectory().equals(1)) { + if (userFileService.count(new LambdaQueryWrapper() + .eq(UserFile::getName, userFile.getName()) + .eq(UserFile::getParentId, userFile.getParentId()) + .eq(UserFile::getUserId, userFile.getUserId())) > 0) { + return fail("文件夹名称已存在"); + } + } + if (userFileService.save(userFile)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "修改用户文件") + @PutMapping() + public ApiResult update(@RequestBody UserFile userFile) { + Integer loginUserId = getLoginUserId(); + UserFile old = userFileService.getById(userFile.getId()); + UserFile entity = new UserFile(); + if (StrUtil.isNotBlank(userFile.getName())) { + entity.setName(userFile.getName()); + } + if (userFile.getParentId() != null) { + entity.setParentId(userFile.getParentId()); + } + if (!old.getUserId().equals(loginUserId) || + (entity.getName() == null && entity.getParentId() == null)) { + return fail("修改失败"); + } + if (old.getIsDirectory() != null && old.getIsDirectory().equals(1)) { + if (userFileService.count(new LambdaQueryWrapper() + .eq(UserFile::getName, entity.getName() == null ? old.getName() : entity.getName()) + .eq(UserFile::getParentId, entity.getParentId() == null ? old.getParentId() : entity.getParentId()) + .eq(UserFile::getUserId, loginUserId) + .ne(UserFile::getId, old.getId())) > 0) { + return fail("文件夹名称已存在"); + } + } + if (userFileService.update(entity, new LambdaUpdateWrapper() + .eq(UserFile::getId, userFile.getId()) + .eq(UserFile::getUserId, loginUserId))) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "删除用户文件") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userFileService.remove(new LambdaUpdateWrapper() + .eq(UserFile::getId, id) + .eq(UserFile::getUserId, getLoginUserId()))) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "批量删除用户文件") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (userFileService.remove(new LambdaUpdateWrapper() + .in(UserFile::getId, ids) + .eq(UserFile::getUserId, getLoginUserId()))) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/controller/UserRefereeController.java b/src/main/java/com/gxwebsoft/common/system/controller/UserRefereeController.java new file mode 100644 index 0000000..6cd1463 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/controller/UserRefereeController.java @@ -0,0 +1,183 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserReferee; +import com.gxwebsoft.common.system.param.UserRefereeParam; +import com.gxwebsoft.common.system.service.UserRefereeService; +import com.gxwebsoft.common.system.service.UserService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用户推荐关系表控制器 + * + * @author 科技小王子 + * @since 2023-10-07 22:56:36 + */ +@Tag(name = "用户") +@RestController +@RequestMapping("/api/system/user-referee") +public class UserRefereeController extends BaseController { + @Resource + private UserRefereeService userRefereeService; + @Resource + private UserService userService; + + @PreAuthorize("hasAuthority('sys:userReferee:list')") + @OperationLog + @Operation(summary = "分页查询用户推荐关系表") + @GetMapping("/page") + public ApiResult> page(UserRefereeParam param) { + // 使用关联查询 + return success(userRefereeService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userReferee:list')") + @OperationLog + @Operation(summary = "查询全部用户推荐关系表") + @GetMapping() + public ApiResult> list(UserRefereeParam param) { + // 使用关联查询 + return success(userRefereeService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userReferee:list')") + @OperationLog + @Operation(summary = "根据id查询用户推荐关系表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(userRefereeService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:userReferee:save')") + @OperationLog + @Operation(summary = "添加用户推荐关系表") + @PostMapping() + public ApiResult save(@RequestBody UserReferee userReferee) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + userReferee.setUserId(loginUser.getUserId()); + } + if (userRefereeService.save(userReferee)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userReferee:update')") + @OperationLog + @Operation(summary = "修改用户推荐关系表") + @PutMapping() + public ApiResult update(@RequestBody UserReferee userReferee) { + if (userRefereeService.updateById(userReferee)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userReferee:remove')") + @OperationLog + @Operation(summary = "删除用户推荐关系表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userRefereeService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:userReferee:save')") + @OperationLog + @Operation(summary = "批量添加用户推荐关系表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (userRefereeService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userReferee:update')") + @OperationLog + @Operation(summary = "批量修改用户推荐关系表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(userRefereeService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userReferee:remove')") + @OperationLog + @Operation(summary = "批量删除用户推荐关系表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (userRefereeService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "查询推荐人信息") + @GetMapping("/getReferee/{id}") + public ApiResult getReferee(@PathVariable("id") Integer id) { + if (id == null) { + return fail("参数错误", null); + } + + final UserReferee referee = userRefereeService.getOne(new LambdaQueryWrapper() + .eq(UserReferee::getUserId, id) + .eq(UserReferee::getDeleted, 0)); + + if (ObjectUtil.isEmpty(referee)) { + return fail("查询失败", null); + } + + final User user = userService.getByIdRel(referee.getDealerId()); + if (ObjectUtil.isNotEmpty(user)) { + return success(user); + } + return fail("查询失败", null); + } + + @Operation(summary = "查询推荐人列表") + @GetMapping("/getRefereeList/{id}") + public ApiResult> getRefereeList(@PathVariable("id") Integer id) { + if (id == null) { + return fail("参数错误", null); + } + + final List refereeList = userRefereeService.list(new LambdaQueryWrapper() + .eq(UserReferee::getDealerId, id) + .eq(UserReferee::getDeleted, 0)); + + if (ObjectUtil.isEmpty(refereeList)) { + return fail("查询失败", null); + } + + final List users = userService.list( + new LambdaQueryWrapper() + .in(User::getUserId, refereeList.stream().map(UserReferee::getUserId).toList()) + ); + if (ObjectUtil.isNotEmpty(users)) { + return success(users); + } + return fail("查询失败", null); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/dto/PaymentCacheDTO.java b/src/main/java/com/gxwebsoft/common/system/dto/PaymentCacheDTO.java new file mode 100644 index 0000000..8a0cab9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/dto/PaymentCacheDTO.java @@ -0,0 +1,39 @@ +package com.gxwebsoft.common.system.dto; + +import lombok.Data; +import java.io.Serializable; + +/** + * 支付配置缓存DTO + * 专门用于Redis缓存,不包含时间字段,避免序列化问题 + * + * @author 科技小王子 + * @since 2025-01-13 + */ +@Data +public class PaymentCacheDTO implements Serializable { + private static final long serialVersionUID = 1L; + + private Integer id; + private String name; + private Integer type; + private String code; + private String image; + private Integer wechatType; + private String appId; + private String mchId; + private String apiKey; + private String apiclientCert; + private String apiclientKey; + private String pubKey; + private String pubKeyId; + private String merchantSerialNumber; + private String notifyUrl; + private String comments; + private Integer sortNumber; + private Boolean status; + private Integer deleted; + private Integer tenantId; + + // 不包含 createTime 和 updateTime 字段,避免序列化问题 +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/Cache.java b/src/main/java/com/gxwebsoft/common/system/entity/Cache.java new file mode 100644 index 0000000..232c183 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/Cache.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.common.system.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + * 缓存管理 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Setting对象", description = "缓存管理") +public class Cache implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "key") + private String key; + + @Schema(description = "设置内容(json格式)") + private String content; + + @Schema(description = "过期时间(秒)") + private Long expireTime; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/ChatMessage.java b/src/main/java/com/gxwebsoft/common/system/entity/ChatMessage.java new file mode 100644 index 0000000..2102b4d --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/ChatMessage.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Map; + +/** + * 机构 + * + * @author LX + * @since 2025-04-14 00:35:34 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "LawOrg对象", description = "机构") +@TableName("law_org") +public class ChatMessage implements Serializable { + private static final long serialVersionUID = 1L; + + @TableField(exist = false) + private String query; + + @TableField(exist = false) + private String inputs; + + @TableField(exist = false) + private String responseMode; + + @TableField(exist = false) + private String user; + + @TableField(exist = false) + private String conversationId; + + @TableField(exist = false) + private String type; + + @TableField(exist = false) + private Integer requestType; + + @TableField(exist = false) + private Map files; +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/Company.java b/src/main/java/com/gxwebsoft/common/system/entity/Company.java new file mode 100644 index 0000000..9e37455 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/Company.java @@ -0,0 +1,337 @@ +package com.gxwebsoft.common.system.entity; + +import cn.hutool.core.util.DesensitizedUtil; +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.util.List; + +/** + * 企业信息 + * + * @author 科技小王子 + * @since 2023-05-27 14:57:34 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Company对象", description = "企业信息") +@TableName("sys_company") +public class Company implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "企业id") + @TableId(value = "company_id", type = IdType.AUTO) + private Integer companyId; + + @Schema(description = "应用类型") + private Integer type; + + @Schema(description = "企业简称") + private String shortName; + + @Schema(description = "企业全称") + @TableField(exist = false) + private String companyName; + + @Schema(description = "企业标识") + private String companyCode; + + @Schema(description = "企业类型") + private String companyType; + + @Schema(description = "是否官方") + private Boolean official; + + @Schema(description = "企业类型 多选") + private String companyTypeMultiple; + + @Schema(description = "应用标识") + private String companyLogo; + + @Schema(description = "封面图") + private String image; + + @Schema(description = "应用详情") + @TableField(exist = false) + private String content; + + @Schema(description = "栏目分类") + private Integer categoryId; + + @Schema(description = "栏目名称") + @TableField(exist = false) + private String categoryName; + + @Schema(description = "应用截图") + private String files; + + @Schema(description = "顶级域名") + private String domain; + + @Schema(description = "免费域名") + private String freeDomain; + + @Schema(description = "销售价格") + private BigDecimal price; + + @Schema(description = "计费方式") + private Integer chargingMethod; + + @Schema(description = "联系电话") + private String phone; + + @Schema(description = "公司座机") + private String tel; + + @Schema(description = "电子邮箱") + private String email; + + @Schema(description = "企业法人") + private String businessEntity; + + @Schema(description = "发票抬头") + @TableField("Invoice_header") + private String invoiceHeader; + + @Schema(description = "服务开始时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime startTime; + + @Schema(description = "服务到期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime expirationTime; + + @Schema(description = "即将过期") + private Integer soon; + + @Schema(description = "应用版本 10体验版 20授权版 30旗舰版") + private Integer version; + + @Schema(description = "版本名称") + private String versionName; + + @Schema(description = "版本号") + private String versionCode; + + @Schema(description = "评分") + private BigDecimal rate; + + @Schema(description = "企业成员(当前)") + private Integer users; + + @Schema(description = "成员数量(上限)") + private Integer members; + + @Schema(description = "浏览数量") + private Long clicks; + + @Schema(description = "点赞数量") + private Long likes; + + @Schema(description = "购买数量") + private Long buys; + + @Schema(description = "存储空间") + private Long storage; + + @Schema(description = "存储空间(上限)") + private Long storageMax; + + @Schema(description = "行业类型(父级)") + private String industryParent; + + @Schema(description = "行业类型(子级)") + private String industryChild; + + @Schema(description = "部门数量") + private Integer departments; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否实名认证") + private Integer authentication; + + @Schema(description = "主控端节点") + private String serverUrl; + + @Schema(description = "模块节点") + private String modulesUrl; + + @Schema(description = "重定向节点") + private String redirectUrl; + + @Schema(description = "request合法域名") + private String requestUrl; + + @Schema(description = "socket合法域名") + private String socketUrl; + + @Schema(description = "总后台管理入口") + private String adminUrl; + + @Schema(description = "商户端管理入口") + private String merchantUrl; + + @Schema(description = "默认网站URL") + private String websiteUrl; + + @Schema(description = "微信小程序二维码") + private String mpWeixinCode; + + @Schema(description = "支付宝小程序二维码") + private String mpAlipayCode; + + @Schema(description = "H5端应用二维码") + private String h5Code; + + @Schema(description = "安卓APP二维码") + private String androidUrl; + + @Schema(description = "苹果APP二维码") + private String iosUrl; + + @Schema(description = "应用类型") + private String appType; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序") + private Integer sortNumber; + + @Schema(description = "插件ID(菜单根节点)") + private Integer menuId; + + @Schema(description = "当前使用的租户模板") + private Integer planId; + + @Schema(description = "是否开启网站") + private Boolean websiteStatus; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "是否含税") + private Boolean isTax; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "是否默认企业主体") + private Boolean authoritative; + + @Schema(description = "是否推荐") + private Boolean recommend; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "租户ID") + private Integer tid; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "租户名称") + @TableField(exist = false) + private String tenantName; + + @Schema(description = "租户编号") + @TableField(exist = false) + private String tenantCode; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "配置信息") + @TableField(exist = false) + private Object config; + + @Schema(description = "是否已收藏") + @TableField(exist = false) + private Boolean collection; + + @Schema(description = "新注册的密码") + @TableField(exist = false) + private String password; + + @Schema(description = "手机号(脱敏)") + @TableField(exist = false) + private String mobile; + + @Schema(description = "是否已购买") + @TableField(exist = false) + private Boolean isBuy; + + @Schema(description = "用户是否已安装了该插件") + @TableField(exist = false) + private Boolean installed; + + @Schema(description = "产品参数") + @TableField(exist = false) + private List parameters; + + @Schema(description = "产品按钮及链接") + @TableField(exist = false) + private List links; + + @Schema(description = "购买数量") + @TableField(exist = false) + private Integer num; + + @Schema(description = "角色列表") + @TableField(exist = false) + private List roles; + + @Schema(description = "权限列表") + @TableField(exist = false) + private List authorities; + + @Schema(description = "记录克隆的模板ID") + @TableField(exist = false) + private Integer templateId; + + public String getMobile() { + return DesensitizedUtil.mobilePhone(this.phone); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/CompanyComment.java b/src/main/java/com/gxwebsoft/common/system/entity/CompanyComment.java new file mode 100644 index 0000000..5ad0b6b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/CompanyComment.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 应用评论 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CompanyComment对象", description = "应用评论") +@TableName("sys_company_comment") +public class CompanyComment implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "父级ID") + private Integer parentId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "评分") + private BigDecimal rate; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "评论内容") + private String comments; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/CompanyContent.java b/src/main/java/com/gxwebsoft/common/system/entity/CompanyContent.java new file mode 100644 index 0000000..1230838 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/CompanyContent.java @@ -0,0 +1,44 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 应用详情 + * + * @author 科技小王子 + * @since 2024-10-16 13:41:21 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CompanyContent对象", description = "应用详情") +@TableName("sys_company_content") +public class CompanyContent implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "详细内容") + private String content; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/CompanyGit.java b/src/main/java/com/gxwebsoft/common/system/entity/CompanyGit.java new file mode 100644 index 0000000..b8d482b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/CompanyGit.java @@ -0,0 +1,142 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 代码仓库 + * + * @author 科技小王子 + * @since 2024-10-19 18:08:51 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CompanyGit对象", description = "代码仓库") +@TableName("sys_company_git") +public class CompanyGit implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "仓库名称") + private String title; + + @Schema(description = "厂商") + private String brand; + + @Schema(description = "图标") + private String icon; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "仓库地址") + private String domain; + + @Schema(description = "账号") + private String account; + + @Schema(description = "密码") + private String password; + + @Schema(description = "仓库描述") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1待确认") + private Integer status; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "租户id") + private Integer tenantId; + + /** + * 用户余额变动明细表 + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ + @Data + @EqualsAndHashCode(callSuper = false) + @Schema(name = "UserBalanceLog对象", description = "用户余额变动明细表") + @TableName("sys_user_balance_log") + public static class UserBalanceLog implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "log_id", type = IdType.AUTO) + private Integer logId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "余额变动场景(10用户充值 20用户消费 30管理员操作 40订单退款)") + private Integer scene; + + @Schema(description = "变动金额") + private BigDecimal money; + + @Schema(description = "变动后余额") + private BigDecimal balance; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "支付流水号") + private String transactionId; + + @Schema(description = "管理员备注") + private String remark; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "用户头像") + @TableField(exist = false) + private String avatar; + + } +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/CompanyParameter.java b/src/main/java/com/gxwebsoft/common/system/entity/CompanyParameter.java new file mode 100644 index 0000000..e2c0718 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/CompanyParameter.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 应用参数 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CompanyParameter对象", description = "应用参数") +@TableName("sys_company_parameter") +public class CompanyParameter implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "参数名称") + private String name; + + @Schema(description = "参数内容") + private String value; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1待确认") + private Integer status; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/CompanyUrl.java b/src/main/java/com/gxwebsoft/common/system/entity/CompanyUrl.java new file mode 100644 index 0000000..1bee66a --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/CompanyUrl.java @@ -0,0 +1,66 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 应用域名 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CompanyUrl对象", description = "应用域名") +@TableName("sys_company_url") +public class CompanyUrl implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "域名类型") + private String type; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "账号") + private String account; + + @Schema(description = "密码") + private String password; + + @Schema(description = "二维码") + private String qrcode; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1待确认") + private Integer status; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/Dict.java b/src/main/java/com/gxwebsoft/common/system/entity/Dict.java new file mode 100644 index 0000000..35f9c61 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/Dict.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.util.Set; + +/** + * 字典 + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +@Data +@Schema(description = "字典(业务类)") +@TableName("sys_dict") +public class Dict implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典id") + @TableId(type = IdType.AUTO) + private Integer dictId; + + @Schema(description = "字典标识") + private String dictCode; + + @Schema(description = "字典名称") + private String dictName; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "字典项列表") + @TableField(exist = false) + private Set> items; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/DictData.java b/src/main/java/com/gxwebsoft/common/system/entity/DictData.java new file mode 100644 index 0000000..e9bf6e9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/DictData.java @@ -0,0 +1,66 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 字典数据 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Data +@Schema(description = "字典数据(业务类)") +@TableName("sys_dict_data") +public class DictData implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典数据id") + @TableId(type = IdType.AUTO) + private Integer dictDataId; + + @Schema(description = "字典id") + private Integer dictId; + + @Schema(description = "字典数据标识") + private String dictDataCode; + + @Schema(description = "字典数据名称") + private String dictDataName; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "字典代码") + @TableField(exist = false) + private String dictCode; + + @Schema(description = "字典名称") + @TableField(exist = false) + private String dictName; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/Dictionary.java b/src/main/java/com/gxwebsoft/common/system/entity/Dictionary.java new file mode 100644 index 0000000..b184758 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/Dictionary.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; + +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 字典 + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +@Data +@Schema(description = "字典(系统类)") +@TableName("sys_dictionary") +public class Dictionary implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典id") + @TableId(type = IdType.AUTO) + private Integer dictId; + + @Schema(description = "字典标识") + private String dictCode; + + @Schema(description = "字典名称") + private String dictName; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/DictionaryData.java b/src/main/java/com/gxwebsoft/common/system/entity/DictionaryData.java new file mode 100644 index 0000000..9f9ed86 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/DictionaryData.java @@ -0,0 +1,67 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; + +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 字典数据 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Data +@Schema(description = "字典数据(系统类)") +@TableName("sys_dictionary_data") +public class DictionaryData implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典数据id") + @TableId(type = IdType.AUTO) + private Integer dictDataId; + + @Schema(description = "字典id") + private Integer dictId; + + @Schema(description = "字典数据标识") + private String dictDataCode; + + @Schema(description = "字典数据名称") + private String dictDataName; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "字典代码") + @TableField(exist = false) + private String dictCode; + + @Schema(description = "字典名称") + @TableField(exist = false) + private String dictName; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/Domain.java b/src/main/java/com/gxwebsoft/common/system/entity/Domain.java new file mode 100644 index 0000000..c9fc263 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/Domain.java @@ -0,0 +1,75 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 授权域名 + * + * @author 科技小王子 + * @since 2024-09-19 23:56:33 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Domain对象", description = "授权域名") +@TableName("sys_domain") +public class Domain implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "主机记录") + private String hostName; + + @Schema(description = "记录值") + private String hostValue; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "类型 0常规 1后台 2商家端") + private Integer type; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/EmailRecord.java b/src/main/java/com/gxwebsoft/common/system/entity/EmailRecord.java new file mode 100644 index 0000000..1831835 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/EmailRecord.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 邮件发送记录 + * + * @author WebSoft + * @since 2021-08-29 12:36:35 + */ +@Data +@Schema(description = "邮件发送记录") +@TableName("sys_email_record") +public class EmailRecord implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(type = IdType.AUTO) + private Integer id; + + @Schema(description = "邮件标题") + private String title; + + @Schema(description = "邮件内容") + private String content; + + @Schema(description = "收件邮箱") + private String receiver; + + @Schema(description = "发件邮箱") + private String sender; + + @Schema(description = "创建人") + private Integer createUserId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/FileRecord.java b/src/main/java/com/gxwebsoft/common/system/entity/FileRecord.java new file mode 100644 index 0000000..f846af5 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/FileRecord.java @@ -0,0 +1,94 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 文件上传记录 + * + * @author WebSoft + * @since 2021-08-29 12:36:32 + */ +@Data +@Schema(description = "文件上传记录") +@TableName("sys_file_record") +public class FileRecord implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(type = IdType.AUTO) + private Integer id; + + @Schema(description = "分组ID") + private String groupId; + + @Schema(description = "文件名称") + private String name; + + @Schema(description = "文件存储路径") + private String path; + + @Schema(description = "文件大小") + private Long length; + + @Schema(description = "文件类型") + private String contentType; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "创建人") + private Integer createUserId; + + @Schema(description = "AppId") + private Integer appId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "商户编号") + private String merchantCode; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "文件访问地址") + @TableField(exist = false) + private String url; + + @Schema(description = "文件缩略图访问地址") + @TableField(exist = false) + private String thumbnail; + + @Schema(description = "文件下载地址") + @TableField(exist = false) + private String downloadUrl; + + @Schema(description = "创建人账号") + @TableField(exist = false) + private String createUsername; + + @Schema(description = "创建人名称") + @TableField(exist = false) + private String createNickname; + + @Schema(description = "用户头像") + @TableField(exist = false) + private String avatar; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/KVEntity.java b/src/main/java/com/gxwebsoft/common/system/entity/KVEntity.java new file mode 100644 index 0000000..c1fa9ab --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/KVEntity.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 租户 + * + * @author WebSoft + * @since 2021-08-28 11:31:06 + */ +@Data +@Schema(description = "实体") +public class KVEntity implements Serializable { + private static final long serialVersionUID = 1L; + protected K k; + protected V v; + public KVEntity() { + super(); + } + + public KVEntity(K k, V v) { + super(); + this.k = k; + this.v = v; + } + + public static KVEntity build(K k, V v) { + return new KVEntity<>(k, v); + } + + public K getK() { + return k; + } + + public void setK(K k) { + this.k = k; + } + + public V getV() { + return v; + } + + public void setV(V v) { + this.v = v; + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/LoginRecord.java b/src/main/java/com/gxwebsoft/common/system/entity/LoginRecord.java new file mode 100644 index 0000000..b516166 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/LoginRecord.java @@ -0,0 +1,76 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 登录日志 + * + * @author WebSoft + * @since 2018-12-24 16:10:41 + */ +@Data +@Schema(description = "登录日志") +@TableName("sys_login_record") +public class LoginRecord implements Serializable { + private static final long serialVersionUID = 1L; + public static final int TYPE_LOGIN = 0; // 登录成功 + public static final int TYPE_ERROR = 1; // 登录失败 + public static final int TYPE_LOGOUT = 2; // 退出登录 + public static final int TYPE_REFRESH = 3; // 续签token + public static final int TYPE_REGISTER = 4; // 注册成功 + + @Schema(description = "主键id") + @TableId(type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户账号") + private String username; + + @Schema(description = "操作系统") + private String os; + + @Schema(description = "设备名称") + private String device; + + @Schema(description = "浏览器类型") + private String browser; + + @Schema(description = "ip地址") + private String ip; + + @Schema(description = "操作类型, 0登录成功, 1登录失败, 2退出登录, 3续签token") + private Integer loginType; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "操作时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "用户id") + @TableField(exist = false) + private Integer userId; + + @Schema(description = "用户昵称") + @TableField(exist = false) + private String nickname; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/Menu.java b/src/main/java/com/gxwebsoft/common/system/entity/Menu.java new file mode 100644 index 0000000..479e2f4 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/Menu.java @@ -0,0 +1,87 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.security.core.GrantedAuthority; + +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.util.List; + +/** + * 菜单 + * + * @author WebSoft + * @since 2018-12-24 16:10:17 + */ +@Data +@Schema(description = "菜单") +@TableName("sys_menu") +public class Menu implements GrantedAuthority { + private static final long serialVersionUID = 1L; + public static final int TYPE_MENU = 0; // 菜单类型 + public static final int TYPE_BTN = 1; // 按钮类型 + + @Schema(description = "菜单id") + @TableId(type = IdType.AUTO) + private Integer menuId; + + @Schema(description = "上级id, 0是顶级") + private Integer parentId; + + @Schema(description = "菜单名称") + private String title; + + @Schema(description = "菜单路由地址") + private String path; + + @Schema(description = "菜单组件地址") + private String component; + + @Schema(description = "菜单类型, 0菜单, 1按钮") + private Integer menuType; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "权限标识") + private String authority; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示左侧菜单)") + private Integer hide; + + @Schema(description = "路由元信息") + private String meta; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "关联应用") + private Integer appId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "子菜单") + @TableField(exist = false) + private List children; + + @Schema(description = "角色权限树选中状态") + @TableField(exist = false) + private Boolean checked; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/OperationRecord.java b/src/main/java/com/gxwebsoft/common/system/entity/OperationRecord.java new file mode 100644 index 0000000..8ffb3bf --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/OperationRecord.java @@ -0,0 +1,98 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 操作日志 + * + * @author WebSoft + * @since 2018-12-24 16:10:33 + */ +@Data +@Schema(description = "操作日志") +@TableName("sys_operation_record") +public class OperationRecord implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "操作模块") + private String module; + + @Schema(description = "操作功能") + private String description; + + @Schema(description = "请求地址") + private String url; + + @Schema(description = "请求方式") + private String requestMethod; + + @Schema(description = "调用方法") + private String method; + + @Schema(description = "请求参数") + private String params; + + @Schema(description = "返回结果") + private String result; + + @Schema(description = "异常信息") + private String error; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "消耗时间, 单位毫秒") + private Long spendTime; + + @Schema(description = "操作系统") + private String os; + + @Schema(description = "设备名称") + private String device; + + @Schema(description = "浏览器类型") + private String browser; + + @Schema(description = "ip地址") + private String ip; + + @Schema(description = "状态, 0成功, 1异常") + private Integer status; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "操作时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "用户昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "用户账号") + @TableField(exist = false) + private String username; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/Organization.java b/src/main/java/com/gxwebsoft/common/system/entity/Organization.java new file mode 100644 index 0000000..215a64c --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/Organization.java @@ -0,0 +1,92 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; + +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 组织机构 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Data +@Schema(description = "组织机构") +@TableName("sys_organization") +public class Organization implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "机构id") + @TableId(type = IdType.AUTO) + private Integer organizationId; + + @Schema(description = "上级id, 0是顶级") + private Integer parentId; + + @Schema(description = "机构名称") + private String organizationName; + + @Schema(description = "机构全称") + private String organizationFullName; + + @Schema(description = "机构代码") + private String organizationCode; + + @Schema(description = "机构类型, 字典标识") + private String organizationType; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "邮政编码") + private String zipCode; + + @Schema(description = "负责人id") + private Integer leaderId; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "机构类型名称") + @TableField(exist = false) + private String organizationTypeName; + + @Schema(description = "负责人姓名") + @TableField(exist = false) + private String leaderNickname; + + @Schema(description = "负责人账号") + @TableField(exist = false) + private String leaderUsername; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/Payment.java b/src/main/java/com/gxwebsoft/common/system/entity/Payment.java new file mode 100644 index 0000000..819ff36 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/Payment.java @@ -0,0 +1,100 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; + +/** + * 支付方式 + * + * @author 科技小王子 + * @since 2024-05-11 12:39:11 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Payment对象", description = "支付方式") +@TableName("sys_payment") +public class Payment implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "支付方式") + private String name; + + @Schema(description = "类型") + private Integer type; + + @Schema(description = "标识") + private String code; + + @Schema(description = "支付图标") + private String image; + + @Schema(description = "微信商户号类型 1普通商户2子商户") + private Integer wechatType; + + @Schema(description = "应用ID") + private String appId; + + @Schema(description = "商户号") + private String mchId; + + @Schema(description = "设置APIv3密钥") + private String apiKey; + + @Schema(description = "证书文件 (CERT)") + private String apiclientCert; + + @Schema(description = "证书文件 (KEY)") + private String apiclientKey; + + @Schema(description = "公钥文件 (KEY)") + private String pubKey; + + @Schema(description = "公钥ID") + private String pubKeyId; + + @Schema(description = "商户证书序列号") + private String merchantSerialNumber; + + @Schema(description = "支付结果通知") + private String notifyUrl; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "文章排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0未启用, 1启用") + private Boolean status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonIgnore // 缓存时忽略此字段 + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonIgnore // 缓存时忽略此字段 + private LocalDateTime updateTime; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/Plug.java b/src/main/java/com/gxwebsoft/common/system/entity/Plug.java new file mode 100644 index 0000000..b8ef784 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/Plug.java @@ -0,0 +1,144 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.util.List; + +/** + * 插件扩展 + * + * @author 科技小王子 + * @since 2023-05-18 11:57:37 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Plug对象", description = "插件扩展") +@TableName("sys_plug") +public class Plug implements Serializable { + private static final long serialVersionUID = 1L; + public static final int TYPE_MENU = 0; // 菜单类型 + public static final int TYPE_BTN = 1; // 按钮类型 + + @Schema(description = "插件id") + @TableId(value = "plug_id", type = IdType.AUTO) + private Integer plugId; + + @Schema(description = "菜单ID") + private Integer menuId; + + @Schema(description = "上级id, 0是顶级") + private Integer parentId; + + @Schema(description = "菜单名称") + private String title; + + @Schema(description = "菜单路由地址") + private String path; + + @Schema(description = "菜单组件地址, 目录可为空") + private String component; + + @Schema(description = "类型, 0菜单, 1按钮") + private Integer menuType; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "权限标识") + private String authority; + + @Schema(description = "打开位置") + private String target; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "图标颜色") + private String color; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") + private Integer hide; + + @Schema(description = "菜单侧栏选中的path") + private String active; + + @Schema(description = "其它路由元信息") + private String meta; + + @Schema(description = "插件描述") + private String comments; + + @Schema(description = "插件详情") + private String content; + + @Schema(description = "评分") + private BigDecimal score; + + @Schema(description = "插件价格") + private BigDecimal price; + + @Schema(description = "浏览次数") + private Integer clicks; + + @Schema(description = "安装次数") + private Integer installs; + + @Schema(description = "关联应用ID") + private Integer appId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "子菜单") + @TableField(exist = false) + private List children; + + @Schema(description = "角色权限树选中状态") + @TableField(exist = false) + private Boolean checked; + + @Schema(description = "租户名称") + @TableField(exist = false) + private String tenantName; + + @Schema(description = "企业名称") + @TableField(exist = false) + private String companyName; + + @Schema(description = "企业简称") + @TableField(exist = false) + private String shortName; + + @Schema(description = "企业域名") + @TableField(exist = false) + private String domain; +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/Role.java b/src/main/java/com/gxwebsoft/common/system/entity/Role.java new file mode 100644 index 0000000..2859ce9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/Role.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 角色 + * + * @author WebSoft + * @since 2018-12-24 16:10:01 + */ +@Data +@Schema(description = "角色") +@TableName("sys_role") +public class Role implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "角色id") + @TableId(type = IdType.AUTO) + private Integer roleId; + + @Schema(description = "角色标识") + private String roleCode; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(hidden = true) + @TableField(exist = false) + private Integer userId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/RoleMenu.java b/src/main/java/com/gxwebsoft/common/system/entity/RoleMenu.java new file mode 100644 index 0000000..14781c7 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/RoleMenu.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 角色菜单 + * + * @author WebSoft + * @since 2018-12-24 16:10:54 + */ +@Data +@Schema(description = "角色权限") +@TableName("sys_role_menu") +public class RoleMenu implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(type = IdType.AUTO) + private Integer id; + + @Schema(description = "角色id") + private Integer roleId; + + @Schema(description = "菜单id") + private Integer menuId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/Setting.java b/src/main/java/com/gxwebsoft/common/system/entity/Setting.java new file mode 100644 index 0000000..336bc2e --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/Setting.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 系统设置 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Setting对象", description = "系统设置") +@TableName("sys_setting") +public class Setting implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @TableId(value = "setting_id", type = IdType.AUTO) + private Integer settingId; + + @Schema(description = "设置项标示") + private String settingKey; + + @Schema(description = "设置内容(json格式)") + private String content; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "修改租户名称") + @TableField(exist = false) + private String tenantName; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/Tenant.java b/src/main/java/com/gxwebsoft/common/system/entity/Tenant.java new file mode 100644 index 0000000..fc5f804 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/Tenant.java @@ -0,0 +1,78 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.util.List; + +/** + * 租户 + * + * @author 科技小王子 + * @since 2023-07-17 17:49:53 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Tenant对象", description = "租户") +@TableName("sys_tenant") +public class Tenant implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "租户id") + @TableId(value = "tenant_id", type = IdType.AUTO) + private Integer tenantId; + + @Schema(description = "租户名称") + private String tenantName; + + @Schema(description = "租户编号") + private String tenantCode; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "logo") + @TableField(exist = false) + private String logo; + + @Schema(description = "游客") + @TableField(exist = false) + private String username; + + @Schema(description = "游客身份") + @TableField(exist = false) + private String token; + + @Schema(description = "当前登录用户") + @TableField(exist = false) + private User loginUser; + + @Schema(description = "菜单信息") + @TableField(exist = false) + private List menu; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/User.java b/src/main/java/com/gxwebsoft/common/system/entity/User.java new file mode 100644 index 0000000..e69de43 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/User.java @@ -0,0 +1,310 @@ +package com.gxwebsoft.common.system.entity; + +import cn.hutool.core.util.DesensitizedUtil; +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.security.core.userdetails.UserDetails; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 用户 + * + * @author WebSoft + * @since 2018-12-24 16:10:13 + */ +@Data +@Schema(description = "用户") +@TableName("sys_user") +public class User implements UserDetails { + private static final long serialVersionUID = 1L; + + @Schema(description = "用户id") + @TableId(type = IdType.AUTO) + private Integer userId; + + @Schema(description = "用户类型, 0普通用户") + private Integer type; + + @Schema(description = "用户编码") + private String userCode; + + @Schema(description = "账号") + private String username; + + @Schema(description = "密码") + private String password; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "头像") + private String bgImage; + + @Schema(description = "性别, 字典标识") + private String sex; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "支付密码") + private String payPassword; + + @Schema(description = "职务") + private String position; + + @Schema(description = "邮箱是否验证, 0否, 1是") + private Integer emailVerified; + + @Schema(description = "别名") + private String alias; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "身份证号(脱敏)") + private String idCard; + + @Schema(description = "身份证号") + @TableField(exist = false) + private String idCardNo; + + @Schema(description = "出生日期") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime birthday; + + @Schema(description = "年龄") + private Integer age; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "用户可用余额") + private BigDecimal balance; + + @Schema(description = "用户可用积分") + private Integer points; + + @Schema(description = "用户总支付的金额") + private String payMoney; + + @Schema(description = "实际消费的金额(不含退款)") + private BigDecimal expendMoney; + + @Schema(description = "会员等级ID") + private Integer gradeId; + + @Schema(description = "个人简介") + private String introduction; + + @Schema(description = "机构ID") + private Integer organizationId; + + @Schema(description = "会员分组ID") + private Integer groupId; + + @Schema(description = "会员分组") + @TableField(exist = false) + private String groupName; + + @Schema(description = "客户ID") + @TableField(exist = false) + private Integer customerId; + + @Schema(description = "企业ID") + @TableField(exist = false) + private Integer companyId; + + @Schema(description = "模板ID") + @TableField(exist = false) + private Integer templateId; + + @Schema(description = "注册来源客户端") + private String platform; + + @Schema(description = "是否下线会员") + private Integer offline; + + @Schema(description = "关注数") + private Integer followers; + + @Schema(description = "粉丝数") + private Integer fans; + + @Schema(description = "获赞数") + private Integer likes; + + @Schema(description = "客户端ID") + private String clientId; + + @Schema(description = "可管理的商户") + private String merchants; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "是否管理员") + private Boolean isAdmin; + + @Schema(description = "评论数") + private Integer commentNumbers; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "租户名称") + @TableField(exist = false) + private String tenantName; + + @Schema(description = "最后结算时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime settlementTime; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "公司名称") + @TableField(exist = false) + private String companyName; + + @Schema(description = "是否已实名认证") + private Integer certification; + + @Schema(description = "机构名称") + @TableField(exist = false) + private String organizationName; + + @Schema(description = "性别名称") + @TableField(exist = false) + private String sexName; + + @Schema(description = "会员等级") + @TableField(exist = false) + private String gradeName; + + @Schema(description = "默认注册的角色ID") + @TableField(exist = false) + private Integer roleId; + + @Schema(description = "角色列表") + @TableField(exist = false) + private List roles; + + @Schema(description = "权限列表") + @TableField(exist = false) + private List authorities; + + @Schema(description = "微信凭证") + @TableField(exist = false) + private String code; + + @Schema(description = "推荐人ID") + @TableField(exist = false) + private Integer dealerId; + + @Schema(description = "微信openid") + private String openid; + + @Schema(description = "公众号openid") + private String officeOpenid; + + @Schema(description = "微信unionid") + private String unionid; + + @Schema(description = "关联用户ID") + @TableField(exist = false) + private Integer sysUserId; + + @Schema(description = "ico文件") + @TableField(exist = false) + private String logo; + + @Schema(description = "创建的应用数量") + @TableField(exist = false) + private Double apps; + + @Schema(description = "租户设置信息") + @TableField(exist = false) + private String setting; + + @Schema(description = "手机号(脱敏)") + @TableField(exist = false) + private String mobile; + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return this.status != null && this.status == 0; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + public String getMobile(){ + return DesensitizedUtil.mobilePhone(this.phone); + } + + public String getIdCardNo(){ + return DesensitizedUtil.idCardNum(this.idCard,4,4); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/UserBalanceLog.java b/src/main/java/com/gxwebsoft/common/system/entity/UserBalanceLog.java new file mode 100644 index 0000000..bd62f51 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/UserBalanceLog.java @@ -0,0 +1,87 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 用户余额变动明细表 + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "UserBalanceLog对象", description = "用户余额变动明细表") +@TableName("sys_user_balance_log") +public class UserBalanceLog implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "log_id", type = IdType.AUTO) + private Integer logId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "余额变动场景(10用户充值 20用户消费 30管理员操作 40订单退款)") + private Integer scene; + + @Schema(description = "变动金额") + private BigDecimal money; + + @Schema(description = "变动后余额") + private BigDecimal balance; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "支付流水号") + private String transactionId; + + @Schema(description = "管理员备注") + private String remark; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "用户头像") + @TableField(exist = false) + private String avatar; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/UserCollection.java b/src/main/java/com/gxwebsoft/common/system/entity/UserCollection.java new file mode 100644 index 0000000..89133e9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/UserCollection.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 我的收藏 + * + * @author 科技小王子 + * @since 2024-04-28 18:08:32 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "UserCollection对象", description = "我的收藏") +@TableName("sys_user_collection") +public class UserCollection implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "租户ID") + private Integer tid; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/UserFile.java b/src/main/java/com/gxwebsoft/common/system/entity/UserFile.java new file mode 100644 index 0000000..f99ec96 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/UserFile.java @@ -0,0 +1,79 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户文件 + * + * @author WebSoft + * @since 2022-07-21 14:34:40 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "UserFile对象", description = "用户文件") +@TableName("sys_user_file") +public class UserFile implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "文件名称") + private String name; + + @Schema(description = "是否是文件夹, 0否, 1是") + private Integer isDirectory; + + @Schema(description = "上级id") + private Integer parentId; + + @Schema(description = "文件路径") + private String path; + + @Schema(description = "文件大小") + private Integer length; + + @Schema(description = "文件类型") + private String contentType; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "文件访问地址") + @TableField(exist = false) + private String url; + + @Schema(description = "文件缩略图访问地址") + @TableField(exist = false) + private String thumbnail; + + @Schema(description = "文件下载地址") + @TableField(exist = false) + private String downloadUrl; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/UserInfo.java b/src/main/java/com/gxwebsoft/common/system/entity/UserInfo.java new file mode 100644 index 0000000..ecf46eb --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/UserInfo.java @@ -0,0 +1,260 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 用户 + * + * @author WebSoft + * @since 2018-12-24 16:10:13 + */ +@Data +@Schema(description = "用户") +@TableName("sys_user") +public class UserInfo { + private static final long serialVersionUID = 1L; + + @Schema(description = "用户id") + @TableId(type = IdType.AUTO) + private Integer userId; + + @Schema(description = "用户类型, 0普通用户 6开发者 10企业用户") + private Integer type; + + @Schema(description = "用户编码") + private String userCode; + + @Schema(description = "账号") + private String username; + + @Schema(description = "密码") + private String password; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "头像") + private String bgImage; + + @Schema(description = "性别, 字典标识") + private String sex; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "职务") + private String position; + + @Schema(description = "邮箱是否验证, 0否, 1是") + private Integer emailVerified; + + @Schema(description = "别名") + private String alias; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "身份证号") + private String idCard; + + @Schema(description = "出生日期") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime birthday; + + @Schema(description = "年龄") + private Integer age; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "用户可用余额") + private BigDecimal balance; + + @Schema(description = "用户可用积分") + private Integer points; + + @Schema(description = "用户总支付的金额") + private String payMoney; + + @Schema(description = "实际消费的金额(不含退款)") + private String expendMoney; + + @Schema(description = "会员等级ID") + private Integer gradeId; + + @Schema(description = "个人简介") + private String introduction; + + @Schema(description = "机构ID") + private Integer organizationId; + + @Schema(description = "客户ID") + private Integer customerId; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "注册来源客户端") + private String platform; + + @Schema(description = "兴趣爱好") + private String interest; + + @Schema(description = "身高") + private String height; + + @Schema(description = "体重") + private String weight; + + @Schema(description = "学历") + private String education; + + @Schema(description = "月薪") + private String monthlyPay; + + @Schema(description = "是否下线会员") + private Integer offline; + + @Schema(description = "关注数") + private Integer followers; + + @Schema(description = "粉丝数") + private Integer fans; + + @Schema(description = "获赞数") + private Integer likes; + + @Schema(description = "评论数") + private Integer commentNumbers; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "租户名称") + @TableField(exist = false) + private String tenantName; + + @Schema(description = "最后结算时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime settlementTime; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "公司名称") + private String companyName; + + @Schema(description = "是否已实名认证") + private Integer certification; + + @Schema(description = "机构名称") + @TableField(exist = false) + private String organizationName; + + @Schema(description = "性别名称") + @TableField(exist = false) + private String sexName; + + @Schema(description = "会员等级") + @TableField(exist = false) + private String gradeName; + + @Schema(description = "默认注册的角色ID") + @TableField(exist = false) + private Integer roleId; + + @Schema(description = "角色列表") + @TableField(exist = false) + private List roles; + + @Schema(description = "权限列表") + @TableField(exist = false) + private List authorities; + + @Schema(description = "微信凭证") + @TableField(exist = false) + private String code; + + @Schema(description = "推荐人ID") + @TableField(exist = false) + private Integer dealerId; + + @Schema(description = "微信openid") + @TableField(exist = false) + private String openid; + + @Schema(description = "微信unionid") + @TableField(exist = false) + private String unionid; + + @Schema(description = "所属商户名称") + @TableField(exist = false) + private String merchantName; + + @Schema(description = "ico文件") + @TableField(exist = false) + private String logo; + + @Schema(description = "创建的应用数量") + @TableField(exist = false) + private Double apps; + + @Schema(description = "租户设置信息") + @TableField(exist = false) + private String setting; + + @Schema(description = "手机号(脱敏)") + @TableField(exist = false) + private String mobile; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/UserReferee.java b/src/main/java/com/gxwebsoft/common/system/entity/UserReferee.java new file mode 100644 index 0000000..b836af8 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/UserReferee.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 用户推荐关系表 + * + * @author 科技小王子 + * @since 2023-10-07 22:56:36 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "UserReferee对象", description = "用户推荐关系表") +@TableName("sys_user_referee") +public class UserReferee implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "推荐人ID") + private Integer dealerId; + + @Schema(description = "用户id(被推荐人)") + private Integer userId; + + @Schema(description = "推荐关系层级(1,2,3)") + private Integer level; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @TableField(exist = false) + private User user; +} diff --git a/src/main/java/com/gxwebsoft/common/system/entity/UserRole.java b/src/main/java/com/gxwebsoft/common/system/entity/UserRole.java new file mode 100644 index 0000000..9308dd9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/entity/UserRole.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 用户角色 + * + * @author WebSoft + * @since 2018-12-24 16:10:23 + */ +@Data +@Schema(description = "用户角色") +@TableName("sys_user_role") +public class UserRole implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "角色id") + private Integer roleId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "角色名称") + @TableField(exist = false) + private String roleName; + + @Schema(description = "租户ID") + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/CompanyCommentMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/CompanyCommentMapper.java new file mode 100644 index 0000000..d80c603 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/CompanyCommentMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.CompanyComment; +import com.gxwebsoft.common.system.param.CompanyCommentParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用评论Mapper + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +public interface CompanyCommentMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CompanyCommentParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CompanyCommentParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/CompanyContentMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/CompanyContentMapper.java new file mode 100644 index 0000000..3a75de9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/CompanyContentMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.CompanyContent; +import com.gxwebsoft.common.system.param.CompanyContentParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用详情Mapper + * + * @author 科技小王子 + * @since 2024-10-16 13:41:21 + */ +public interface CompanyContentMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CompanyContentParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CompanyContentParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/CompanyGitMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/CompanyGitMapper.java new file mode 100644 index 0000000..345650f --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/CompanyGitMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.CompanyGit; +import com.gxwebsoft.common.system.param.CompanyGitParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 代码仓库Mapper + * + * @author 科技小王子 + * @since 2024-10-19 18:08:51 + */ +public interface CompanyGitMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CompanyGitParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CompanyGitParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/CompanyMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/CompanyMapper.java new file mode 100644 index 0000000..28b534f --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/CompanyMapper.java @@ -0,0 +1,62 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.system.entity.Company; +import com.gxwebsoft.common.system.param.CompanyParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 企业信息Mapper + * + * @author 科技小王子 + * @since 2023-05-27 14:57:34 + */ +public interface CompanyMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CompanyParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CompanyParam param); + + @InterceptorIgnore(tenantLine = "true") + List getCount(@Param("param") CompanyParam param); + + @InterceptorIgnore(tenantLine = "true") + List selectPageRelAll(PageParam page, CompanyParam param); + + @InterceptorIgnore(tenantLine = "true") + Company getCompanyAll(@Param("companyId") Integer companyId); + + @InterceptorIgnore(tenantLine = "true") + void updateByCompanyId(@Param("param") Company company); + + @InterceptorIgnore(tenantLine = "true") + boolean removeCompanyAll(Integer id); + + @InterceptorIgnore(tenantLine = "true") + boolean undeleteAll(Integer id); + + @InterceptorIgnore(tenantLine = "true") + boolean updateByIdAll(Company company); + + @InterceptorIgnore(tenantLine = "true") + Company getByTenantId(Integer tenantId); +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/CompanyParameterMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/CompanyParameterMapper.java new file mode 100644 index 0000000..c55b5f0 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/CompanyParameterMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.CompanyParameter; +import com.gxwebsoft.common.system.param.CompanyParameterParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用参数Mapper + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +public interface CompanyParameterMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CompanyParameterParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CompanyParameterParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/CompanyUrlMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/CompanyUrlMapper.java new file mode 100644 index 0000000..117ed2b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/CompanyUrlMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.CompanyUrl; +import com.gxwebsoft.common.system.param.CompanyUrlParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用域名Mapper + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +public interface CompanyUrlMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CompanyUrlParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CompanyUrlParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/DictDataMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/DictDataMapper.java new file mode 100644 index 0000000..f36039f --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/DictDataMapper.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.DictData; +import com.gxwebsoft.common.system.param.DictDataParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 字典数据Mapper + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface DictDataMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") DictDataParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") DictDataParam param); + + /** + * 根据dictCode和dictDataName查询 + * + * @param dictCode 字典标识 + * @param dictDataName 字典项名称 + * @return List + */ + List getByDictCodeAndName(@Param("dictCode") String dictCode, + @Param("dictDataName") String dictDataName); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/DictMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/DictMapper.java new file mode 100644 index 0000000..ce19779 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/DictMapper.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.Dict; + +/** + * 字典Mapper + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +public interface DictMapper extends BaseMapper { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/DictionaryDataMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/DictionaryDataMapper.java new file mode 100644 index 0000000..519c2ba --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/DictionaryDataMapper.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.DictionaryData; +import com.gxwebsoft.common.system.param.DictionaryDataParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 字典数据Mapper + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface DictionaryDataMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") DictionaryDataParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") DictionaryDataParam param); + + /** + * 根据dictCode和dictDataName查询 + * + * @param dictCode 字典标识 + * @param dictDataName 字典项名称 + * @return List + */ + List getByDictCodeAndName(@Param("dictCode") String dictCode, + @Param("dictDataName") String dictDataName); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/DictionaryMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/DictionaryMapper.java new file mode 100644 index 0000000..7c2cbac --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/DictionaryMapper.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.Dictionary; + +/** + * 字典Mapper + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +public interface DictionaryMapper extends BaseMapper { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/DomainMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/DomainMapper.java new file mode 100644 index 0000000..2853001 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/DomainMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Domain; +import com.gxwebsoft.common.system.param.DomainParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 授权域名Mapper + * + * @author 科技小王子 + * @since 2024-09-19 23:56:33 + */ +public interface DomainMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") DomainParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") DomainParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/EmailRecordMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/EmailRecordMapper.java new file mode 100644 index 0000000..02611c9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/EmailRecordMapper.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.EmailRecord; + +/** + * 邮件记录Mapper + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface EmailRecordMapper extends BaseMapper { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/FileRecordMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/FileRecordMapper.java new file mode 100644 index 0000000..fe9f0b8 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/FileRecordMapper.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.FileRecord; +import com.gxwebsoft.common.system.param.FileRecordParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 文件上传记录Mapper + * + * @author WebSoft + * @since 2021-08-30 11:18:04 + */ +public interface FileRecordMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") FileRecordParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") FileRecordParam param); + + /** + * 根据path查询 + * + * @param path 文件路径 + * @return FileRecord + */ + @InterceptorIgnore(tenantLine = "true") + List getByIdPath(@Param("path") String path); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/LoginRecordMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/LoginRecordMapper.java new file mode 100644 index 0000000..4409fdd --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/LoginRecordMapper.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.LoginRecord; +import com.gxwebsoft.common.system.param.LoginRecordParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 登录日志Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:11 + */ +public interface LoginRecordMapper extends BaseMapper { + + /** + * 添加, 排除租户拦截 + * + * @param entity LoginRecord + * @return int + */ + @Override + @InterceptorIgnore(tenantLine = "true") + int insert(LoginRecord entity); + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") LoginRecordParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") LoginRecordParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/MenuMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/MenuMapper.java new file mode 100644 index 0000000..938ef17 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/MenuMapper.java @@ -0,0 +1,22 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.param.MenuParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 菜单Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:32 + */ +public interface MenuMapper extends BaseMapper { + @InterceptorIgnore(tenantLine = "true") + List getMenuByClone(@Param("param") MenuParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/OperationRecordMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/OperationRecordMapper.java new file mode 100644 index 0000000..8750c2a --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/OperationRecordMapper.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.OperationRecord; +import com.gxwebsoft.common.system.param.OperationRecordParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 操作日志Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:03 + */ +public interface OperationRecordMapper extends BaseMapper { + + /** + * 添加, 排除租户拦截 + * + * @param entity OperationRecord + * @return int + */ + @Override + @InterceptorIgnore(tenantLine = "true") + int insert(OperationRecord entity); + + /** + * 分页查询 + * + * @param page 分页参数 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") OperationRecordParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") OperationRecordParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/OrganizationMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/OrganizationMapper.java new file mode 100644 index 0000000..6f06689 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/OrganizationMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Organization; +import com.gxwebsoft.common.system.param.OrganizationParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 组织机构Mapper + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface OrganizationMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") OrganizationParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") OrganizationParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/PaymentMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/PaymentMapper.java new file mode 100644 index 0000000..c58aeb8 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/PaymentMapper.java @@ -0,0 +1,40 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.param.PaymentParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 支付方式Mapper + * + * @author 科技小王子 + * @since 2024-05-11 12:39:11 + */ +public interface PaymentMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") PaymentParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") PaymentParam param); + + @InterceptorIgnore(tenantLine = "true") + Payment getByType(@Param("param") PaymentParam paymentParam); +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/PlugMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/PlugMapper.java new file mode 100644 index 0000000..600b1a2 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/PlugMapper.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Plug; +import com.gxwebsoft.common.system.param.PlugParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 插件扩展Mapper + * + * @author 科技小王子 + * @since 2023-05-18 11:57:37 + */ +public interface PlugMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + @InterceptorIgnore(tenantLine = "true") + List selectPageRel(@Param("page") IPage page, + @Param("param") PlugParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") PlugParam param); + + @InterceptorIgnore(tenantLine = "true") + List getMenuByClone(@Param("param") PlugParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/RoleMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/RoleMapper.java new file mode 100644 index 0000000..b00f275 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/RoleMapper.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.Role; + +/** + * 角色Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:44 + */ +public interface RoleMapper extends BaseMapper { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/RoleMenuMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/RoleMenuMapper.java new file mode 100644 index 0000000..a225765 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/RoleMenuMapper.java @@ -0,0 +1,39 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.RoleMenu; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 角色菜单Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:21 + */ +public interface RoleMenuMapper extends BaseMapper { + + /** + * 查询用户的菜单 + * + * @param userId 用户id + * @param menuType 菜单类型 + * @return List + */ + @InterceptorIgnore(tenantLine = "true") + List listMenuByUserId(@Param("userId") Integer userId, @Param("menuType") Integer menuType); + + /** + * 根据角色id查询菜单 + * + * @param roleIds 角色id + * @param menuType 菜单类型 + * @return List + */ + @InterceptorIgnore(tenantLine = "true") + List listMenuByRoleIds(@Param("roleIds") List roleIds, @Param("menuType") Integer menuType); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/SettingMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/SettingMapper.java new file mode 100644 index 0000000..ffc7f55 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/SettingMapper.java @@ -0,0 +1,40 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Setting; +import com.gxwebsoft.common.system.param.SettingParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 系统设置Mapper + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +public interface SettingMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") SettingParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") SettingParam param); + + @InterceptorIgnore(tenantLine = "true") + Setting getBySettingKeyIgnore(@Param("param") SettingParam param); +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/TenantMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/TenantMapper.java new file mode 100644 index 0000000..17f4a25 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/TenantMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Tenant; +import com.gxwebsoft.common.system.param.TenantParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 租户Mapper + * + * @author 科技小王子 + * @since 2023-07-17 17:49:53 + */ +public interface TenantMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") TenantParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") TenantParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/UserBalanceLogMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/UserBalanceLogMapper.java new file mode 100644 index 0000000..f986c44 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/UserBalanceLogMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.UserBalanceLog; +import com.gxwebsoft.common.system.param.UserBalanceLogParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户余额变动明细表Mapper + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ +public interface UserBalanceLogMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") UserBalanceLogParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") UserBalanceLogParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/UserCollectionMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/UserCollectionMapper.java new file mode 100644 index 0000000..b7330da --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/UserCollectionMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.UserCollection; +import com.gxwebsoft.common.system.param.UserCollectionParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 我的收藏Mapper + * + * @author 科技小王子 + * @since 2024-04-28 18:08:32 + */ +public interface UserCollectionMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") UserCollectionParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") UserCollectionParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/UserFileMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/UserFileMapper.java new file mode 100644 index 0000000..d9e4bb4 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/UserFileMapper.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.UserFile; + +/** + * 用户文件Mapper + * + * @author WebSoft + * @since 2022-07-21 14:34:40 + */ +public interface UserFileMapper extends BaseMapper { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/UserMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/UserMapper.java new file mode 100644 index 0000000..b5935a6 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/UserMapper.java @@ -0,0 +1,69 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.UserParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:14 + */ +public interface UserMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") UserParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") UserParam param); + + /** + * 根据账号查询 + * + * @param username 账号 + * @param tenantId 租户id + * @return User + */ + @InterceptorIgnore(tenantLine = "true") + User selectByUsername(@Param("username") String username, @Param("tenantId") Integer tenantId); + + @InterceptorIgnore(tenantLine = "true") + List getOne(@Param("param") UserParam param); + + List selectListStatisticsRel(@Param("param") UserParam param); + + @InterceptorIgnore(tenantLine = "true") + void updateByUserId(@Param("param") User param); + + /** + * 根据用户ID查询用户(忽略租户隔离) + * @param userId 用户ID + * @return User + */ + @InterceptorIgnore(tenantLine = "true") + User selectByIdIgnoreTenant(@Param("userId") Integer userId); + + @InterceptorIgnore(tenantLine = "true") + List pageAdminByPhone(@Param("param") UserParam param); + + @InterceptorIgnore(tenantLine = "true") + List listByAlert(); +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/UserRefereeMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/UserRefereeMapper.java new file mode 100644 index 0000000..e729045 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/UserRefereeMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.UserReferee; +import com.gxwebsoft.common.system.param.UserRefereeParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户推荐关系表Mapper + * + * @author 科技小王子 + * @since 2023-10-07 22:56:36 + */ +public interface UserRefereeMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") UserRefereeParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") UserRefereeParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/UserRoleMapper.java b/src/main/java/com/gxwebsoft/common/system/mapper/UserRoleMapper.java new file mode 100644 index 0000000..51b38c8 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/UserRoleMapper.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.entity.UserRole; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户角色Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:02 + */ +public interface UserRoleMapper extends BaseMapper { + + /** + * 批量添加用户角色 + * + * @param userId 用户id + * @param roleIds 角色id集合 + * @return int + */ + int insertBatch(@Param("userId") Integer userId, @Param("roleIds") List roleIds); + + /** + * 根据用户id查询角色 + * + * @param userId 用户id + * @return List + */ + @InterceptorIgnore(tenantLine = "true") + List selectByUserId(@Param("userId") Integer userId); + + /** + * 批量根据用户id查询角色 + * + * @param userIds 用户id集合 + * @return List + */ + List selectByUserIds(@Param("userIds") List userIds); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyCommentMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyCommentMapper.xml new file mode 100644 index 0000000..0e04c48 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyCommentMapper.xml @@ -0,0 +1,53 @@ + + + + + + + SELECT a.* + FROM sys_company_comment a + + + AND a.id = #{param.id} + + + AND a.parent_id = #{param.parentId} + + + AND a.user_id = #{param.userId} + + + AND a.company_id = #{param.companyId} + + + AND a.rate = #{param.rate} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyContentMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyContentMapper.xml new file mode 100644 index 0000000..06207e5 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyContentMapper.xml @@ -0,0 +1,38 @@ + + + + + + + SELECT a.* + FROM sys_company_content a + + + AND a.id = #{param.id} + + + AND a.company_id = #{param.companyId} + + + AND a.content LIKE CONCAT('%', #{param.content}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyGitMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyGitMapper.xml new file mode 100644 index 0000000..bf8c616 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyGitMapper.xml @@ -0,0 +1,65 @@ + + + + + + + SELECT a.* + FROM sys_company_git a + + + AND a.id = #{param.id} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.brand = #{param.brand} + + + AND a.company_id = #{param.companyId} + + + AND a.domain LIKE CONCAT('%', #{param.domain}, '%') + + + AND a.account LIKE CONCAT('%', #{param.account}, '%') + + + AND a.password LIKE CONCAT('%', #{param.password}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND ( + a.title LIKE CONCAT('%', #{param.keywords}, '%') + OR a.domain LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyMapper.xml new file mode 100644 index 0000000..ad61d39 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyMapper.xml @@ -0,0 +1,198 @@ + + + + + + + SELECT a.*,b.tenant_id,b.tenant_name,b.tenant_code,c.title as categoryName + FROM gxwebsoft_core.sys_company a + LEFT JOIN gxwebsoft_core.sys_tenant b ON a.tenant_id = b.tenant_id + LEFT JOIN gxwebsoft_core.cms_navigation c ON a.category_id = c.navigation_id + + + AND a.company_id = #{param.companyId} + + + AND a.type = #{param.type} + + + AND a.official = #{param.official} + + + AND a.category_id = #{param.categoryId} + + + AND a.short_name LIKE CONCAT('%', #{param.shortName}, '%') + + + AND a.company_name LIKE CONCAT('%', #{param.companyName}, '%') + + + AND a.company_type = #{param.companyType} + + + AND a.company_logo LIKE CONCAT('%', #{param.companyLogo}, '%') + + + AND a.domain LIKE CONCAT('%', #{param.domain}, '%') + + + AND a.phone = #{param.phone} + + + AND a.Invoice_header LIKE CONCAT('%', #{param.invoiceHeader}, '%') + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.expiration_time LIKE CONCAT('%', #{param.expirationTime}, '%') + + + AND a.version = #{param.version} + + + AND a.members = #{param.members} + + + AND a.industry_parent LIKE CONCAT('%', #{param.industryParent}, '%') + + + AND a.industry_child LIKE CONCAT('%', #{param.industryChild}, '%') + + + AND a.departments = #{param.departments} + + + AND a.country LIKE CONCAT('%', #{param.country}, '%') + + + AND a.province LIKE CONCAT('%', #{param.province}, '%') + + + AND a.city LIKE CONCAT('%', #{param.city}, '%') + + + AND a.region LIKE CONCAT('%', #{param.region}, '%') + + + AND a.address LIKE CONCAT('%', #{param.address}, '%') + + + AND a.longitude LIKE CONCAT('%', #{param.longitude}, '%') + + + AND a.latitude LIKE CONCAT('%', #{param.latitude}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.authentication = #{param.authentication} + + + AND a.status = #{param.status} + + + AND a.app_type = #{param.appType} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.authoritative = #{param.authoritative} + + + AND a.recommend = 1 + + + AND a.short_name = #{param.appName} + + + AND a.email = #{param.email} + + + AND a.merchant_id = #{param.merchantId} + + + AND a.company_id IN + + #{item} + + + + AND (a.company_name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.short_name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.tenant_id = #{param.keywords} + OR a.phone = #{param.keywords} + OR a.domain LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + + + + + + + + + + UPDATE sys_company SET storage = #{param.storage} WHERE company_id = #{param.companyId} + + + + + UPDATE sys_company SET deleted = 1 WHERE company_id = #{param.companyId} + + + + UPDATE sys_company SET deleted = 0 WHERE company_id = #{param.companyId} + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyParameterMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyParameterMapper.xml new file mode 100644 index 0000000..eabfba2 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyParameterMapper.xml @@ -0,0 +1,50 @@ + + + + + + + SELECT a.* + FROM sys_company_parameter a + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.value LIKE CONCAT('%', #{param.value}, '%') + + + AND a.company_id = #{param.companyId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyUrlMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyUrlMapper.xml new file mode 100644 index 0000000..6db9462 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyUrlMapper.xml @@ -0,0 +1,59 @@ + + + + + + + SELECT a.* + FROM sys_company_url a + + + AND a.id = #{param.id} + + + AND a.type LIKE CONCAT('%', #{param.type}, '%') + + + AND a.company_id = #{param.companyId} + + + AND a.domain LIKE CONCAT('%', #{param.domain}, '%') + + + AND a.account LIKE CONCAT('%', #{param.account}, '%') + + + AND a.password LIKE CONCAT('%', #{param.password}, '%') + + + AND a.qrcode LIKE CONCAT('%', #{param.qrcode}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictDataMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictDataMapper.xml new file mode 100644 index 0000000..a831629 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictDataMapper.xml @@ -0,0 +1,71 @@ + + + + + + + SELECT a.*, + b.dict_code, + b.dict_name + FROM gxwebsoft_core.sys_dict_data a + LEFT JOIN gxwebsoft_core.sys_dict b ON a.dict_id = b.dict_id + + AND a.deleted = 0 + + AND a.dict_data_id = #{param.dictDataId} + + + AND a.dict_id = #{param.dictId} + + + AND a.dict_data_code LIKE CONCAT('%', #{param.dictDataCode}, '%') + + + AND a.dict_data_name LIKE CONCAT('%', #{param.dictDataName}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND b.dict_code = #{param.dictCode} + + + AND b.dict_name = #{param.dictName} + + + AND ( + a.dict_data_code LIKE CONCAT('%', #{param.keywords}, '%') + OR a.dict_data_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictMapper.xml new file mode 100644 index 0000000..db709ae --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryDataMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryDataMapper.xml new file mode 100644 index 0000000..886303b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryDataMapper.xml @@ -0,0 +1,71 @@ + + + + + + + SELECT a.*, + b.dict_code, + b.dict_name + FROM sys_dictionary_data a + LEFT JOIN gxwebsoft_core.sys_dictionary b ON a.dict_id = b.dict_id + + AND a.deleted = 0 + + AND a.dict_data_id = #{param.dictDataId} + + + AND a.dict_id = #{param.dictId} + + + AND a.dict_data_code LIKE CONCAT('%', #{param.dictDataCode}, '%') + + + AND a.dict_data_name LIKE CONCAT('%', #{param.dictDataName}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND b.dict_code = #{param.dictCode} + + + AND b.dict_name = #{param.dictName} + + + AND ( + a.dict_data_code LIKE CONCAT('%', #{param.keywords}, '%') + OR a.dict_data_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryMapper.xml new file mode 100644 index 0000000..8cd0cff --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/DomainMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/DomainMapper.xml new file mode 100644 index 0000000..1299cf7 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/DomainMapper.xml @@ -0,0 +1,62 @@ + + + + + + + SELECT a.* + FROM sys_domain a + + + AND a.id = #{param.id} + + + AND a.domain LIKE CONCAT('%', #{param.domain}, '%') + + + AND a.host_name LIKE CONCAT('%', #{param.hostName}, '%') + + + AND a.host_value LIKE CONCAT('%', #{param.hostValue}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.type = #{param.type} + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/EmailRecordMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/EmailRecordMapper.xml new file mode 100644 index 0000000..7b5ad62 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/EmailRecordMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/FileRecordMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/FileRecordMapper.xml new file mode 100644 index 0000000..1a7dd22 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/FileRecordMapper.xml @@ -0,0 +1,76 @@ + + + + + + + SELECT a.*, + b.username create_username, + b.nickname create_nickname, + b.avatar, + c.merchant_code + FROM sys_file_record a + LEFT JOIN gxwebsoft_core.sys_user b ON a.create_user_id = b.user_id + LEFT JOIN shop_merchant c ON a.merchant_code = c.merchant_code + + + AND a.id = #{param.id} + + + AND a.`name` LIKE CONCAT('%', #{param.name}, '%') + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.create_user_id = #{param.createUserId} + + + AND a.group_id = #{param.groupId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND b.username = #{param.createUsername} + + + AND b.nickname LIKE CONCAT('%', #{param.createNickname}, '%') + + + AND a.content_type LIKE CONCAT('%', #{param.contentType}, '%') + + + + + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/LoginRecordMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/LoginRecordMapper.xml new file mode 100644 index 0000000..397c525 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/LoginRecordMapper.xml @@ -0,0 +1,62 @@ + + + + + + + SELECT a.*, + b.user_id, + b.nickname + FROM sys_login_record a + LEFT JOIN gxwebsoft_core.sys_user b ON a.username = b.username + + + AND a.id = #{param.id} + + + AND a.username LIKE CONCAT('%', #{param.username}, '%') + + + AND a.os LIKE CONCAT('%', #{param.os}, '%') + + + AND a.device LIKE CONCAT('%', #{param.device}, '%') + + + AND a.browser LIKE CONCAT('%', #{param.browser}, '%') + + + AND a.ip LIKE CONCAT('%', #{param.ip}, '%') + + + AND a.login_type LIKE CONCAT('%', #{param.loginType}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND b.user_id = #{param.userId} + + + AND b.nickname LIKE CONCAT('%', #{param.nickname}, '%') + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/MenuMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/MenuMapper.xml new file mode 100644 index 0000000..0897489 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/MenuMapper.xml @@ -0,0 +1,32 @@ + + + + + + + SELECT a.* + FROM sys_menu a + + + AND a.menu_id = #{param.menuId} + + + AND a.parent_id = #{param.parentId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.tenant_id = #{param.tenantId} + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/OperationRecordMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/OperationRecordMapper.xml new file mode 100644 index 0000000..56b7fad --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/OperationRecordMapper.xml @@ -0,0 +1,71 @@ + + + + + + + SELECT a.*, + b.nickname, + b.username + FROM gxwebsoft_core.sys_operation_record a + LEFT JOIN gxwebsoft_core.sys_user b ON a.user_id = b.user_id + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND a.module LIKE CONCAT('%', #{param.module}, '%') + + + AND a.description LIKE CONCAT('%', #{param.description}, '%') + + + AND a.url LIKE CONCAT('%', #{param.url}, '%') + + + AND a.request_method = #{param.requestMethod} + + + AND a.method LIKE CONCAT('%', #{param.method}, '%') + + + AND a.description LIKE CONCAT('%', #{param.description}, '%') + + + AND a.ip LIKE CONCAT('%', #{param.ip}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.`status` = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND b.username LIKE CONCAT('%', #{param.username}, '%') + + + AND b.nickname LIKE CONCAT('%', #{param.nickname}, '%') + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrganizationMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrganizationMapper.xml new file mode 100644 index 0000000..ed5d3c8 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrganizationMapper.xml @@ -0,0 +1,98 @@ + + + + + + + SELECT ta.* + FROM sys_dictionary_data ta + LEFT JOIN gxwebsoft_core.sys_dictionary tb + ON ta.dict_id = tb.dict_id + AND tb.deleted = 0 + WHERE ta.deleted = 0 + AND tb.dict_code = 'organization_type' + + + + + SELECT a.*, + b.dict_data_name organization_type_name, + c.nickname leader_nickname, + c.username leader_username + FROM sys_organization a + LEFT JOIN ( + + ) b ON a.organization_type = b.dict_data_code + LEFT JOIN gxwebsoft_core.sys_user c ON a.leader_id = c.user_id + + AND a.deleted = 0 + + AND a.organization_id = #{param.organizationId} + + + AND a.parent_id = #{param.parentId} + + + AND a.organization_name LIKE CONCAT('%', #{param.organizationName}, '%') + + + AND a.organization_full_name LIKE CONCAT('%', #{param.organizationFullName}, '%') + + + AND a.organization_code LIKE CONCAT('%', #{param.organizationCode}, '%') + + + AND a.organization_type = #{param.organizationType} + + + AND a.province = #{param.province} + + + AND a.city = #{param.city} + + + AND a.region = #{param.province} + + + AND a.zip_code = #{param.zipCode} + + + AND a.leader_id = #{param.leaderId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND b.dict_data_name LIKE CONCAT('%', #{param.organizationTypeName}, '%') + + + AND c.nickname LIKE CONCAT('%', #{param.leaderNickname}, '%') + + + AND c.username LIKE CONCAT('%', #{param.leaderUsername}, '%') + + + AND ( + a.organization_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/PaymentMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/PaymentMapper.xml new file mode 100644 index 0000000..d54c4bc --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/PaymentMapper.xml @@ -0,0 +1,90 @@ + + + + + + + SELECT a.* + FROM gxwebsoft_core.sys_payment a + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.type = #{param.type} + + + AND a.code = #{param.code} + + + AND a.wechat_type = #{param.wechatType} + + + AND a.app_id LIKE CONCAT('%', #{param.appId}, '%') + + + AND a.mch_id LIKE CONCAT('%', #{param.mchId}, '%') + + + AND a.api_key LIKE CONCAT('%', #{param.apiKey}, '%') + + + AND a.apiclient_cert LIKE CONCAT('%', #{param.apiclientCert}, '%') + + + AND a.apiclient_key LIKE CONCAT('%', #{param.apiclientKey}, '%') + + + AND a.merchant_serial_number LIKE CONCAT('%', #{param.merchantSerialNumber}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.tenant_id = #{param.tenantId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/PlugMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/PlugMapper.xml new file mode 100644 index 0000000..45e3aac --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/PlugMapper.xml @@ -0,0 +1,105 @@ + + + + + + + SELECT a.*,b.tenant_name,c.company_name,c.short_name,c.domain + FROM sys_plug a + LEFT JOIN gxwebsoft_core.sys_tenant b ON a.tenant_id = b.tenant_id + LEFT JOIN gxwebsoft_core.sys_company c ON a.tenant_id = c.tenant_id + + + AND a.plug_id = #{param.plugId} + + + AND a.menu_id = #{param.menuId} + + + AND a.parent_id = #{param.parentId} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.component LIKE CONCAT('%', #{param.component}, '%') + + + AND a.menu_type = #{param.menuType} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.authority LIKE CONCAT('%', #{param.authority}, '%') + + + AND a.target LIKE CONCAT('%', #{param.target}, '%') + + + AND a.icon LIKE CONCAT('%', #{param.icon}, '%') + + + AND a.color LIKE CONCAT('%', #{param.color}, '%') + + + AND a.hide = #{param.hide} + + + AND a.active LIKE CONCAT('%', #{param.active}, '%') + + + AND a.meta LIKE CONCAT('%', #{param.meta}, '%') + + + AND a.app_id = #{param.appId} + + + AND a.user_id = #{param.userId} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.merchant_code LIKE CONCAT('%', #{param.merchantCode}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.title LIKE CONCAT('%', #{param.keywords}, '%') + OR a.menu_id = #{param.keywords} + OR c.company_name LIKE CONCAT('%', #{param.keywords}, '%') + OR c.short_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMapper.xml new file mode 100644 index 0000000..9f6facc --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMenuMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMenuMapper.xml new file mode 100644 index 0000000..141c53c --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMenuMapper.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/SettingMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/SettingMapper.xml new file mode 100644 index 0000000..f99a88f --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/SettingMapper.xml @@ -0,0 +1,33 @@ + + + + + + + SELECT a.* + FROM gxwebsoft_core.sys_setting a + + + AND a.setting_key = #{param.settingKey} + + + AND a.setting_id = #{param.settingId} + + + AND a.tenant_id = #{param.tenantId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantMapper.xml new file mode 100644 index 0000000..83ba5b2 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantMapper.xml @@ -0,0 +1,56 @@ + + + + + + + SELECT a.* + FROM sys_tenant a + + + AND a.tenant_id = #{param.tenantId} + + + AND a.tenant_name LIKE CONCAT('%', #{param.tenantName}, '%') + + + AND a.tenant_code LIKE CONCAT('%', #{param.tenantCode}, '%') + + + AND a.logo LIKE CONCAT('%', #{param.logo}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserCollectionMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserCollectionMapper.xml new file mode 100644 index 0000000..9b60a69 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserCollectionMapper.xml @@ -0,0 +1,38 @@ + + + + + + + SELECT a.* + FROM sys_user_collection a + + + AND a.id = #{param.id} + + + AND a.tid = #{param.tid} + + + AND a.user_id = #{param.userId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserFileMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserFileMapper.xml new file mode 100644 index 0000000..872b232 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserFileMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml new file mode 100644 index 0000000..c16fae8 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml @@ -0,0 +1,264 @@ + + + + + + + SELECT ta.* + FROM gxwebsoft_core.sys_dictionary_data ta + LEFT JOIN gxwebsoft_core.sys_dictionary tb + ON ta.dict_id = tb.dict_id + AND tb.deleted = 0 + WHERE ta.deleted = 0 + AND tb.dict_code = 'sex' + + + + + SELECT a.user_id, + GROUP_CONCAT(b.role_name) role_name + FROM gxwebsoft_core.sys_user_role a + LEFT JOIN gxwebsoft_core.sys_role b ON a.role_id = b.role_id + GROUP BY a.user_id + + + + + SELECT a.*, + c.dict_data_name sex_name, + e.tenant_name, + h.dealer_id + FROM gxwebsoft_core.sys_user a + LEFT JOIN ( + + ) c ON a.sex = c.dict_data_code + LEFT JOIN( + + ) d ON a.user_id = d.user_id + LEFT JOIN gxwebsoft_core.sys_tenant e ON a.tenant_id = e.tenant_id + LEFT JOIN gxwebsoft_core.sys_user_referee h ON a.user_id = h.user_id and h.deleted = 0 + + + AND a.user_id = #{param.userId} + + + AND a.username LIKE CONCAT('%', #{param.username}, '%') + + + AND a.nickname LIKE CONCAT('%', #{param.nickname}, '%') + + + AND a.type = #{param.type} + + + AND a.sex = #{param.sex} + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.email LIKE CONCAT('%', #{param.email}, '%') + + + AND a.email_verified = #{param.emailVerified} + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.company_name LIKE CONCAT('%', #{param.companyName}, '%') + + + AND a.id_card LIKE CONCAT('%', #{param.idCard}, '%') + + + AND a.birthday LIKE CONCAT('%', #{param.birthday}, '%') + + + AND a.organization_id = #{param.organizationId} + + + AND a.organization_id > 0 + + + AND a.platform = #{param.platform} + + + AND a.`status` = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.recommend = #{param.recommend} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.user_id IN (SELECT user_id FROM sys_user_role WHERE role_id=#{param.roleId}) + + + AND a.user_id IN + + #{item} + + + + AND a.phones IN + + #{item} + + + + AND a.province LIKE CONCAT('%', #{param.province}, '%') + + + AND a.city LIKE CONCAT('%', #{param.city}, '%') + + + AND i.city_mate LIKE CONCAT('%', #{param.cityMate}, '%') + + + AND a.region LIKE CONCAT('%', #{param.region}, '%') + + + AND c.dict_data_name = #{param.sexName} + + + AND ( + a.username LIKE CONCAT('%', #{param.keywords}, '%') + OR a.user_id = #{param.keywords} + OR a.nickname LIKE CONCAT('%', #{param.keywords}, '%') + OR a.real_name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.alias LIKE CONCAT('%', #{param.keywords}, '%') + OR a.phone LIKE CONCAT('%', #{param.keywords}, '%') + OR a.email LIKE CONCAT('%', #{param.keywords}, '%') + OR c.dict_data_name LIKE CONCAT('%', #{param.keywords}, '%') + OR d.role_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + AND a.organization_id IN (SELECT organization_id FROM sys_organization WHERE parent_id=#{param.parentId}) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UPDATE gxwebsoft_core.sys_user SET grade_id = #{param.gradeId} WHERE user_id = #{param.userId} + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRefereeMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRefereeMapper.xml new file mode 100644 index 0000000..67943f7 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRefereeMapper.xml @@ -0,0 +1,50 @@ + + + + + + + SELECT a.* + FROM sys_user_referee a + + + AND a.id = #{param.id} + + + AND a.dealer_id = #{param.dealerId} + + + AND a.user_id = #{param.userId} + + + AND a.level = #{param.level} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRoleMapper.xml b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRoleMapper.xml new file mode 100644 index 0000000..78e3a87 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRoleMapper.xml @@ -0,0 +1,35 @@ + + + + + + INSERT INTO sys_user_role(user_id, role_id) VALUES + + (#{userId}, #{roleId}) + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/common/system/param/AlipayParam.java b/src/main/java/com/gxwebsoft/common/system/param/AlipayParam.java new file mode 100644 index 0000000..9888a3c --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/AlipayParam.java @@ -0,0 +1,31 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 登录参数 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "登录参数") +public class AlipayParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "支付宝授权码") + private String authCode; + + @Schema(description = "登录账号") + private String username; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/CacheParam.java b/src/main/java/com/gxwebsoft/common/system/param/CacheParam.java new file mode 100644 index 0000000..082e278 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/CacheParam.java @@ -0,0 +1,25 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 缓存管理 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "缓存管理") +public class CacheParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "key") + private String key; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/CompanyCommentParam.java b/src/main/java/com/gxwebsoft/common/system/param/CompanyCommentParam.java new file mode 100644 index 0000000..b2fdcf8 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/CompanyCommentParam.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 应用评论查询参数 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CompanyCommentParam对象", description = "应用评论查询参数") +public class CompanyCommentParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "父级ID") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "企业ID") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "评分") + @QueryField(type = QueryType.EQ) + private BigDecimal rate; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "评论内容") + private String comments; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/CompanyContentParam.java b/src/main/java/com/gxwebsoft/common/system/param/CompanyContentParam.java new file mode 100644 index 0000000..1a5ff5e --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/CompanyContentParam.java @@ -0,0 +1,35 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用详情查询参数 + * + * @author 科技小王子 + * @since 2024-10-16 13:41:21 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CompanyContentParam对象", description = "应用详情查询参数") +public class CompanyContentParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "企业ID") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "详细内容") + private String content; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/CompanyGitParam.java b/src/main/java/com/gxwebsoft/common/system/param/CompanyGitParam.java new file mode 100644 index 0000000..7786857 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/CompanyGitParam.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 代码仓库查询参数 + * + * @author 科技小王子 + * @since 2024-10-19 18:08:51 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CompanyGitParam对象", description = "代码仓库查询参数") +public class CompanyGitParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "仓库名称") + private String title; + + @Schema(description = "厂商") + @QueryField(type = QueryType.EQ) + private String brand; + + @Schema(description = "企业ID") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "仓库地址") + private String domain; + + @Schema(description = "账号") + private String account; + + @Schema(description = "密码") + private String password; + + @Schema(description = "仓库描述") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1待确认") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/CompanyParam.java b/src/main/java/com/gxwebsoft/common/system/param/CompanyParam.java new file mode 100644 index 0000000..6c48c51 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/CompanyParam.java @@ -0,0 +1,167 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Set; + +/** + * 企业信息查询参数 + * + * @author 科技小王子 + * @since 2023-05-27 14:57:34 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CompanyParam对象", description = "企业信息查询参数") +public class CompanyParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "企业id") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "应用类型") + private Integer type; + + @Schema(description = "是否官方") + private Boolean official; + + @Schema(description = "企业简称") + private String shortName; + + @Schema(description = "企业全称") + private String companyName; + + @Schema(description = "企业标识") + private String companyCode; + + @Schema(description = "类型 10企业 20政府单位") + @QueryField(type = QueryType.EQ) + private String companyType; + + @Schema(description = "企业类型 多选") + private String companyTypeMultiple; + + @Schema(description = "应用标识") + private String companyLogo; + + @Schema(description = "栏目分类") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @Schema(description = "企业域名") + private String domain; + + @Schema(description = "联系电话") + private String phone; + + @Schema(description = "电子邮箱") + @QueryField(type = QueryType.EQ) + private String email; + + @Schema(description = "企业法人") + private String businessEntity; + + @Schema(description = "发票抬头") + private String invoiceHeader; + + @Schema(description = "服务开始时间") + private String startTime; + + @Schema(description = "服务到期时间") + private String expirationTime; + + @Schema(description = "应用版本 10体验版 20授权版 30旗舰版") + @QueryField(type = QueryType.EQ) + private Integer version; + + @Schema(description = "成员数量") + @QueryField(type = QueryType.EQ) + private Integer members; + + @Schema(description = "行业类型(父级)") + private String industryParent; + + @Schema(description = "行业类型(子级)") + private String industryChild; + + @Schema(description = "部门数量") + @QueryField(type = QueryType.EQ) + private Integer departments; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否实名认证") + @QueryField(type = QueryType.EQ) + private Integer authentication; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Boolean recommend; + + @Schema(description = "应用类型 app应用 plug插件") + private String appType; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "是否默认企业主体") + @QueryField(type = QueryType.EQ) + private Boolean authoritative; + + @Schema(description = "租户号") + private Integer tenantId; + + @Schema(description = "应用名称") + @QueryField(type = QueryType.EQ) + private String appName; + + @Schema(description = "企业id集合") + @TableField(exist = false) + private Set companyIds; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/CompanyParameterParam.java b/src/main/java/com/gxwebsoft/common/system/param/CompanyParameterParam.java new file mode 100644 index 0000000..91c97b0 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/CompanyParameterParam.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用参数查询参数 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CompanyParameterParam对象", description = "应用参数查询参数") +public class CompanyParameterParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "参数名称") + private String name; + + @Schema(description = "参数内容") + private String value; + + @Schema(description = "企业ID") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1待确认") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/CompanyUrlParam.java b/src/main/java/com/gxwebsoft/common/system/param/CompanyUrlParam.java new file mode 100644 index 0000000..e0576e4 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/CompanyUrlParam.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用域名查询参数 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CompanyUrlParam对象", description = "应用域名查询参数") +public class CompanyUrlParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "域名类型") + private String type; + + @Schema(description = "企业ID") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "账号") + private String account; + + @Schema(description = "密码") + private String password; + + @Schema(description = "二维码") + private String qrcode; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1待确认") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/DictDataParam.java b/src/main/java/com/gxwebsoft/common/system/param/DictDataParam.java new file mode 100644 index 0000000..19e4c0a --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/DictDataParam.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典数据查询参数 + * + * @author WebSoft + * @since 2021-08-28 22:12:02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "字典数据查询参数") +public class DictDataParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典数据id") + @QueryField(type = QueryType.EQ) + private Integer dictDataId; + + @Schema(description = "字典id") + @QueryField(type = QueryType.EQ) + private Integer dictId; + + @Schema(description = "字典数据标识") + private String dictDataCode; + + @Schema(description = "字典数据名称") + private String dictDataName; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "字典代码") + @TableField(exist = false) + private String dictCode; + + @Schema(description = "字典名称") + @TableField(exist = false) + private String dictName; + + @Schema(description = "字典数据代码或字典数据名称") + @TableField(exist = false) + private String keywords; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/DictParam.java b/src/main/java/com/gxwebsoft/common/system/param/DictParam.java new file mode 100644 index 0000000..5bee1fa --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/DictParam.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典查询参数 + * + * @author WebSoft + * @since 2021-08-28 22:12:01 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "字典查询参数") +public class DictParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典id") + private Integer dictId; + + @Schema(description = "字典标识") + private String dictCode; + + @Schema(description = "字典名称") + private String dictName; + + @Schema(description = "备注") + private String comments; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/DictionaryDataParam.java b/src/main/java/com/gxwebsoft/common/system/param/DictionaryDataParam.java new file mode 100644 index 0000000..f9cbc21 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/DictionaryDataParam.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典数据查询参数 + * + * @author WebSoft + * @since 2021-08-28 22:12:02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "字典数据查询参数") +public class DictionaryDataParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典数据id") + @QueryField(type = QueryType.EQ) + private Integer dictDataId; + + @Schema(description = "字典id") + @QueryField(type = QueryType.EQ) + private Integer dictId; + + @Schema(description = "字典数据标识") + private String dictDataCode; + + @Schema(description = "字典数据名称") + private String dictDataName; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "字典代码") + @TableField(exist = false) + private String dictCode; + + @Schema(description = "字典名称") + @TableField(exist = false) + private String dictName; + + @Schema(description = "字典数据代码或字典数据名称") + @TableField(exist = false) + private String keywords; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/DictionaryParam.java b/src/main/java/com/gxwebsoft/common/system/param/DictionaryParam.java new file mode 100644 index 0000000..0e70378 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/DictionaryParam.java @@ -0,0 +1,38 @@ +package com.gxwebsoft.common.system.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典查询参数 + * + * @author WebSoft + * @since 2021-08-28 22:12:01 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "字典查询参数") +public class DictionaryParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + @Schema(description = "字典id") + private Integer dictId; + + @Schema(description = "字典标识") + private String dictCode; + + @Schema(description = "字典名称") + private String dictName; + + @Schema(description = "备注") + private String comments; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/DomainParam.java b/src/main/java/com/gxwebsoft/common/system/param/DomainParam.java new file mode 100644 index 0000000..c842644 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/DomainParam.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 授权域名查询参数 + * + * @author 科技小王子 + * @since 2024-09-19 23:56:33 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "DomainParam对象", description = "授权域名查询参数") +public class DomainParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "主机记录") + private String hostName; + + @Schema(description = "记录值") + private String hostValue; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "类型 0常规 1后台 2商家端") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/FileRecordParam.java b/src/main/java/com/gxwebsoft/common/system/param/FileRecordParam.java new file mode 100644 index 0000000..bb8d33e --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/FileRecordParam.java @@ -0,0 +1,70 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 文件上传记录查询参数 + * + * @author WebSoft + * @since 2021-08-30 11:29:31 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "文件上传记录查询参数") +public class FileRecordParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + @Schema(description = "主键id") + private Integer id; + + @QueryField(type = QueryType.EQ) + @Schema(description = "分组ID") + private String groupId; + + @Schema(description = "文件名称") + private String name; + + @Schema(description = "文件存储路径") + private String path; + + @QueryField(type = QueryType.EQ) + @Schema(description = "创建人") + private Integer createUserId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "文件类型") + private String contentType; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建人账号") + @TableField(exist = false) + private String createUsername; + + @Schema(description = "创建人名称") + @TableField(exist = false) + private String createNickname; + + @Schema(description = "用户头像") + @TableField(exist = false) + private String avatar; + + @Schema(description = "商户编号") + private String merchantCode; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/LoginParam.java b/src/main/java/com/gxwebsoft/common/system/param/LoginParam.java new file mode 100644 index 0000000..039db8b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/LoginParam.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 登录参数 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "登录参数") +public class LoginParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "账号") + private String username; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "短信验证码") + private String code; + + @Schema(description = "密码") + private String password; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/LoginRecordParam.java b/src/main/java/com/gxwebsoft/common/system/param/LoginRecordParam.java new file mode 100644 index 0000000..833b056 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/LoginRecordParam.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 登录日志查询参数 + * + * @author WebSoft + * @since 2021-08-29 19:09:23 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "登录日志查询参数") +public class LoginRecordParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + @Schema(description = "主键id") + private Integer id; + + @Schema(description = "用户账号") + private String username; + + @Schema(description = "操作系统") + private String os; + + @Schema(description = "设备名") + private String device; + + @Schema(description = "浏览器类型") + private String browser; + + @Schema(description = "ip地址") + private String ip; + + @QueryField(type = QueryType.EQ) + @Schema(description = "操作类型, 0登录成功, 1登录失败, 2退出登录, 3续签token") + private Integer loginType; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "用户id") + @TableField(exist = false) + private Integer userId; + + @Schema(description = "用户昵称") + @TableField(exist = false) + private String nickname; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/MenuParam.java b/src/main/java/com/gxwebsoft/common/system/param/MenuParam.java new file mode 100644 index 0000000..69b70fb --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/MenuParam.java @@ -0,0 +1,68 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 菜单查询参数 + * + * @author WebSoft + * @since 2021-08-29 19:36:10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "菜单查询参数") +public class MenuParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "菜单id") + @QueryField(type = QueryType.EQ) + private Integer menuId; + + @Schema(description = "上级id, 0是顶级") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "菜单名称") + private String title; + + @Schema(description = "菜单路由关键字") + private String path; + + @Schema(description = "菜单组件地址") + private String component; + + @Schema(description = "菜单类型, 0菜单, 1按钮") + @QueryField(type = QueryType.EQ) + private Integer menuType; + + @Schema(description = "权限标识") + private String authority; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "关联应用") + private Integer appId; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示左侧菜单)") + @QueryField(type = QueryType.EQ) + private Integer hide; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/OperationRecordParam.java b/src/main/java/com/gxwebsoft/common/system/param/OperationRecordParam.java new file mode 100644 index 0000000..26b6478 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/OperationRecordParam.java @@ -0,0 +1,67 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 操作日志参数 + * + * @author WebSoft + * @since 2021-08-29 20:35:09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "操作日志参数") +public class OperationRecordParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "操作模块") + private String module; + + @Schema(description = "操作功能") + private String description; + + @Schema(description = "请求地址") + private String url; + + @Schema(description = "请求方式") + private String requestMethod; + + @Schema(description = "调用方法") + private String method; + + @Schema(description = "ip地址") + private String ip; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0成功, 1异常") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户账号") + @TableField(exist = false) + private String username; + + @Schema(description = "用户昵称") + @TableField(exist = false) + private String nickname; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/OrganizationParam.java b/src/main/java/com/gxwebsoft/common/system/param/OrganizationParam.java new file mode 100644 index 0000000..5081089 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/OrganizationParam.java @@ -0,0 +1,81 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 组织机构查询参数 + * + * @author WebSoft + * @since 2021-08-29 20:35:09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "组织机构查询参数") +public class OrganizationParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "机构id") + @QueryField(type = QueryType.EQ) + private Integer organizationId; + + @Schema(description = "上级id, 0是顶级") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "机构名称") + private String organizationName; + + @Schema(description = "机构全称") + private String organizationFullName; + + @Schema(description = "机构代码") + private String organizationCode; + + @Schema(description = "机构类型(字典代码)") + private String organizationType; + + @Schema(description = "所在省份") + @QueryField(type = QueryType.EQ) + private String province; + + @Schema(description = "所在城市") + @QueryField(type = QueryType.EQ) + private String city; + + @Schema(description = "所在辖区") + @QueryField(type = QueryType.EQ) + private String region; + + @Schema(description = "邮政编码") + @QueryField(type = QueryType.EQ) + private String zipCode; + + @Schema(description = "负责人id") + @QueryField(type = QueryType.EQ) + private Integer leaderId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "机构类型名称") + @TableField(exist = false) + private String organizationTypeName; + + @Schema(description = "负责人姓名") + @TableField(exist = false) + private String leaderNickname; + + @Schema(description = "负责人账号") + @TableField(exist = false) + private String leaderUsername; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/PaymentParam.java b/src/main/java/com/gxwebsoft/common/system/param/PaymentParam.java new file mode 100644 index 0000000..c814fcd --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/PaymentParam.java @@ -0,0 +1,81 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 支付方式查询参数 + * + * @author 科技小王子 + * @since 2024-05-11 12:39:11 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "PaymentParam对象", description = "支付方式查询参数") +public class PaymentParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "支付方式") + private String name; + + @Schema(description = "类型") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "标识") + @QueryField(type = QueryType.EQ) + private String code; + + @Schema(description = "微信商户号类型 1普通商户2子商户") + @QueryField(type = QueryType.EQ) + private Integer wechatType; + + @Schema(description = "应用ID") + private String appId; + + @Schema(description = "商户号") + private String mchId; + + @Schema(description = "设置APIv3密钥") + private String apiKey; + + @Schema(description = "证书文件 (CERT)") + private String apiclientCert; + + @Schema(description = "证书文件 (KEY)") + private String apiclientKey; + + @Schema(description = "商户证书序列号") + private String merchantSerialNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "文章排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0启用, 1禁用") + @QueryField(type = QueryType.EQ) + private Boolean status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/PlugParam.java b/src/main/java/com/gxwebsoft/common/system/param/PlugParam.java new file mode 100644 index 0000000..3c32d42 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/PlugParam.java @@ -0,0 +1,95 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 插件扩展查询参数 + * + * @author 科技小王子 + * @since 2023-05-18 11:57:37 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "PlugParam对象", description = "插件扩展查询参数") +public class PlugParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "插件id") + @QueryField(type = QueryType.EQ) + private Integer plugId; + + @Schema(description = "菜单id") + @QueryField(type = QueryType.EQ) + private Integer menuId; + + @Schema(description = "上级id, 0是顶级") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "菜单名称") + private String title; + + @Schema(description = "菜单路由地址") + private String path; + + @Schema(description = "菜单组件地址, 目录可为空") + private String component; + + @Schema(description = "类型, 0菜单, 1按钮") + @QueryField(type = QueryType.EQ) + private Integer menuType; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "权限标识") + private String authority; + + @Schema(description = "打开位置") + private String target; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "图标颜色") + private String color; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") + @QueryField(type = QueryType.EQ) + private Integer hide; + + @Schema(description = "菜单侧栏选中的path") + private String active; + + @Schema(description = "其它路由元信息") + private String meta; + + @Schema(description = "关联应用ID") + @QueryField(type = QueryType.EQ) + private Integer appId; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/RoleParam.java b/src/main/java/com/gxwebsoft/common/system/param/RoleParam.java new file mode 100644 index 0000000..d07e3b5 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/RoleParam.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.common.system.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 角色查询参数 + * + * @author WebSoft + * @since 2021-08-29 20:35:09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "角色查询参数") +public class RoleParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "角色id") + @QueryField(type = QueryType.EQ) + private Integer roleId; + + @Schema(description = "角色标识") + private String roleCode; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "租户ID") + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/SettingParam.java b/src/main/java/com/gxwebsoft/common/system/param/SettingParam.java new file mode 100644 index 0000000..324195b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/SettingParam.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 系统设置查询参数 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "SettingParam对象", description = "系统设置查询参数") +public class SettingParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @QueryField(type = QueryType.EQ) + private Integer settingId; + + @Schema(description = "设置项标示") + @QueryField(type = QueryType.EQ) + private String settingKey; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "同步更新租户名称") + private String tenantName; + + @Schema(description = "租户名称") + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/SmsCaptchaParam.java b/src/main/java/com/gxwebsoft/common/system/param/SmsCaptchaParam.java new file mode 100644 index 0000000..7d1f5b5 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/SmsCaptchaParam.java @@ -0,0 +1,31 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 发送短信验证码参数 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "发送短信验证码参数") +public class SmsCaptchaParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "短信签名") + private String signName; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "短信模板") + private String TemplateParam; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/TenantParam.java b/src/main/java/com/gxwebsoft/common/system/param/TenantParam.java new file mode 100644 index 0000000..03b57c3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/TenantParam.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 租户查询参数 + * + * @author 科技小王子 + * @since 2023-07-17 17:49:53 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "TenantParam对象", description = "租户查询参数") +public class TenantParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "租户名称") + private String tenantName; + + @Schema(description = "租户编号") + private String tenantCode; + + @Schema(description = "logo") + private String logo; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "租户id") + @QueryField(type = QueryType.EQ) + private Integer tenantId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/UpdatePasswordParam.java b/src/main/java/com/gxwebsoft/common/system/param/UpdatePasswordParam.java new file mode 100644 index 0000000..8b67b74 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/UpdatePasswordParam.java @@ -0,0 +1,31 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 修改密码参数 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "修改密码参数") +public class UpdatePasswordParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "原始密码") + private String oldPassword; + + @Schema(description = "新密码") + private String password; + + @Schema(description = "手机号码") + private String phone; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/UserBalanceLogParam.java b/src/main/java/com/gxwebsoft/common/system/param/UserBalanceLogParam.java new file mode 100644 index 0000000..1977e31 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/UserBalanceLogParam.java @@ -0,0 +1,77 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 用户余额变动明细表查询参数 + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserBalanceLogParam对象", description = "用户余额变动明细表查询参数") +public class UserBalanceLogParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer logId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "余额变动场景(10用户充值 20用户消费 30管理员操作 40订单退款)") + @QueryField(type = QueryType.EQ) + private Integer scene; + + @Schema(description = "变动金额") + @QueryField(type = QueryType.EQ) + private BigDecimal money; + + @Schema(description = "变动后余额") + @QueryField(type = QueryType.EQ) + private BigDecimal balance; + + @Schema(description = "描述/说明") + private String describe; + + @Schema(description = "管理员备注") + private String remark; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "余额变动场景筛选") + private String sceneMultiple; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/UserCollectionParam.java b/src/main/java/com/gxwebsoft/common/system/param/UserCollectionParam.java new file mode 100644 index 0000000..85106e3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/UserCollectionParam.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 我的收藏查询参数 + * + * @author 科技小王子 + * @since 2024-04-28 18:08:32 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserCollectionParam对象", description = "我的收藏查询参数") +public class UserCollectionParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tid; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/UserFileParam.java b/src/main/java/com/gxwebsoft/common/system/param/UserFileParam.java new file mode 100644 index 0000000..5404354 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/UserFileParam.java @@ -0,0 +1,40 @@ +package com.gxwebsoft.common.system.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户文件查询参数 + * + * @author WebSoft + * @since 2022-07-21 14:34:40 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserFileParam对象", description = "用户文件查询参数") +public class UserFileParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "文件名称") + private String name; + + @Schema(description = "上级id") + @QueryField(type = QueryType.EQ) + private Integer parentId; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/UserImportParam.java b/src/main/java/com/gxwebsoft/common/system/param/UserImportParam.java new file mode 100644 index 0000000..153a783 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/UserImportParam.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.param; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.io.Serializable; + +/** + * 用户导入参数 + * + * @author WebSoft + * @since 2011-10-15 17:33:34 + */ +@Data +public class UserImportParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Excel(name = "账号") + private String username; + + @Excel(name = "密码") + private String password; + + @Excel(name = "昵称") + private String nickname; + + @Excel(name = "手机号") + private String phone; + + @Excel(name = "邮箱") + private String email; + + @Excel(name = "组织机构") + private String organizationName; + + @Excel(name = "性别") + private String sexName; + + @Excel(name = "角色") + private String roleName; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/UserParam.java b/src/main/java/com/gxwebsoft/common/system/param/UserParam.java new file mode 100644 index 0000000..2ade1fd --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/UserParam.java @@ -0,0 +1,249 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Set; + +/** + * 用户查询参数 + * + * @author WebSoft + * @since 2021-08-29 20:35:09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "用户查询参数") +public class UserParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "用户类型, 0普通用户 10企业用户") + private Integer type; + + @Schema(description = "账号") + private String username; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "用户编码") + private String userCode; + + @Schema(description = "性别(字典)") + @QueryField(type = QueryType.EQ) + private String sex; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "邮箱是否验证, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer emailVerified; + + @Schema(description = "别名") + private String alias; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "身份证号") + private String idCard; + + @Schema(description = "出生日期") + private String birthday; + + @Schema(description = "年龄") + private Integer age; + + @Schema(description = "可用余额") + private BigDecimal balance; + + @Schema(description = "机构id") + @QueryField(type = QueryType.EQ) + private Integer organizationId; + + @Schema(description = "用户分组ID") + @QueryField(type = QueryType.EQ) + private Integer groupId; + + @Schema(description = "注册来源客户端") + @QueryField(type = QueryType.EQ) + private String platform; + + @Schema(description = "是否下线会员") + private Integer offline; + + @Schema(description = "上级机构ID") + @QueryField(type = QueryType.IN) + private Integer parentId; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "角色id") + @TableField(exist = false) + private Integer roleId; + + @Schema(description = "角色标识") + @TableField(exist = false) + private String roleCode; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "关注数") + private Integer followers; + + @Schema(description = "粉丝数") + private Integer fans; + + @Schema(description = "获赞数") + private Integer likes; + + @Schema(description = "评论数") + private Integer commentNumbers; + + @Schema(description = "择偶区域") + @TableField(exist = false) + private String cityMate; + + @Schema(description = "机构名称") + @TableField(exist = false) + private String organizationName; + + @Schema(description = "公司名称") + @TableField(exist = false) + private String companyName; + + @Schema(description = "公司名称") + private String customerName; + + @Schema(description = "性别名称") + @TableField(exist = false) + private String sexName; + + @Schema(description = "推荐状态") + @TableField(exist = false) + private Integer recommend; + + @Schema(description = "搜索关键字") + @TableField(exist = false) + private String keywords; + + @Schema(description = "会员等级") + @TableField(exist = false) + private Integer gradeId; + + @Schema(description = "按角色搜索") + @TableField(exist = false) + private String roleIds; + + @Schema(description = "用户类型 sys系统用户 org机构职员 member商城会员 ") + @TableField(exist = false) + private String userType; + + @Schema(description = "支付宝授权码") + @TableField(exist = false) + private String authCode; + + @Schema(description = "微信凭证code") + @TableField(exist = false) + private String code; + + @Schema(description = "推荐人ID") + @QueryField(type = QueryType.IN) + private Integer refereeId; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "二维码类型") + @TableField(exist = false) + private String codeType; + + @Schema(description = "二维码内容 填网址扫码后可跳转") + @TableField(exist = false) + private String codeContent; + + @Schema(description = "是否内部职员") + @TableField(exist = false) + private Boolean isStaff; + + @Schema(description = "是否管理员") + @TableField(exist = false) + private Boolean isAdmin; + + @Schema(description = "openid") + private String openid; + + @Schema(description = "unionid") + private String unionid; + + @Schema(description = "最后结算时间") + @TableField(exist = false) + private String settlementTime; + + @Schema(description = "报餐时间") + @TableField(exist = false) + private String deliveryTime; + + @Schema(description = "用户ID集合") + @TableField(exist = false) + private Set userIds; + + @Schema(description = "用户手机号码集合") + @TableField(exist = false) + private Set phones; + + @Schema(description = "是否查询用户详细资料表") + @TableField(exist = false) + private Boolean showProfile; + + @Schema(description = "openId") + @TableField(exist = false) + private String openId; + + @Schema(description = "可管理的商户") + @QueryField(type = QueryType.LIKE) + private String merchants; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "关联用户ID") + @TableField(exist = false) + private Integer sysUserId; +} diff --git a/src/main/java/com/gxwebsoft/common/system/param/UserRefereeParam.java b/src/main/java/com/gxwebsoft/common/system/param/UserRefereeParam.java new file mode 100644 index 0000000..3d5389c --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/param/UserRefereeParam.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户推荐关系表查询参数 + * + * @author 科技小王子 + * @since 2023-10-07 22:56:36 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserRefereeParam对象", description = "用户推荐关系表查询参数") +public class UserRefereeParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "推荐人ID") + @QueryField(type = QueryType.EQ) + private Integer dealerId; + + @Schema(description = "用户id(被推荐人)") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "推荐关系层级(1,2,3)") + @QueryField(type = QueryType.EQ) + private Integer level; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/result/CaptchaResult.java b/src/main/java/com/gxwebsoft/common/system/result/CaptchaResult.java new file mode 100644 index 0000000..46bd08f --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/result/CaptchaResult.java @@ -0,0 +1,30 @@ +package com.gxwebsoft.common.system.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 验证码返回结果 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "验证码返回结果") +public class CaptchaResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "图形验证码base64数据") + private String base64; + + @Schema(description = "验证码文本") + private String text; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/result/LoginResult.java b/src/main/java/com/gxwebsoft/common/system/result/LoginResult.java new file mode 100644 index 0000000..940d8e9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/result/LoginResult.java @@ -0,0 +1,31 @@ +package com.gxwebsoft.common.system.result; + +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 登录返回结果 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "登录返回结果") +public class LoginResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "access_token") + private String access_token; + + @Schema(description = "用户信息") + private User user; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/result/RedisResult.java b/src/main/java/com/gxwebsoft/common/system/result/RedisResult.java new file mode 100644 index 0000000..f53282b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/result/RedisResult.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.common.system.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * Redis缓存数据 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "缓存数据返回") +public class RedisResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "key") + private String key; + + @Schema(description = "数据") + private T data; + + @Schema(description = "过期时间") + private LocalDateTime expireTime; + +} diff --git a/src/main/java/com/gxwebsoft/common/system/result/SmsCaptchaResult.java b/src/main/java/com/gxwebsoft/common/system/result/SmsCaptchaResult.java new file mode 100644 index 0000000..8f5bb2a --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/result/SmsCaptchaResult.java @@ -0,0 +1,26 @@ +package com.gxwebsoft.common.system.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 短信验证码返回结果 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "短信验证码返回结果") +public class SmsCaptchaResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "短信验证码") + private String text; +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/CompanyCommentService.java b/src/main/java/com/gxwebsoft/common/system/service/CompanyCommentService.java new file mode 100644 index 0000000..10ca95a --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/CompanyCommentService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyComment; +import com.gxwebsoft.common.system.param.CompanyCommentParam; + +import java.util.List; + +/** + * 应用评论Service + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +public interface CompanyCommentService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CompanyCommentParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CompanyCommentParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return CompanyComment + */ + CompanyComment getByIdRel(Integer id); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/CompanyContentService.java b/src/main/java/com/gxwebsoft/common/system/service/CompanyContentService.java new file mode 100644 index 0000000..e4e1ab4 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/CompanyContentService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyContent; +import com.gxwebsoft.common.system.param.CompanyContentParam; + +import java.util.List; + +/** + * 应用详情Service + * + * @author 科技小王子 + * @since 2024-10-16 13:41:21 + */ +public interface CompanyContentService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CompanyContentParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CompanyContentParam param); + + /** + * 根据id查询 + * + * @param id + * @return CompanyContent + */ + CompanyContent getByIdRel(Integer id); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/CompanyGitService.java b/src/main/java/com/gxwebsoft/common/system/service/CompanyGitService.java new file mode 100644 index 0000000..f3ac263 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/CompanyGitService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyGit; +import com.gxwebsoft.common.system.param.CompanyGitParam; + +import java.util.List; + +/** + * 代码仓库Service + * + * @author 科技小王子 + * @since 2024-10-19 18:08:51 + */ +public interface CompanyGitService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CompanyGitParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CompanyGitParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return CompanyGit + */ + CompanyGit getByIdRel(Integer id); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/CompanyParameterService.java b/src/main/java/com/gxwebsoft/common/system/service/CompanyParameterService.java new file mode 100644 index 0000000..4ffa4c0 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/CompanyParameterService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyParameter; +import com.gxwebsoft.common.system.param.CompanyParameterParam; + +import java.util.List; + +/** + * 应用参数Service + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +public interface CompanyParameterService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CompanyParameterParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CompanyParameterParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return CompanyParameter + */ + CompanyParameter getByIdRel(Integer id); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/CompanyService.java b/src/main/java/com/gxwebsoft/common/system/service/CompanyService.java new file mode 100644 index 0000000..d675f59 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/CompanyService.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Company; +import com.gxwebsoft.common.system.param.CompanyParam; + +import java.util.List; + +/** + * 企业信息Service + * + * @author 科技小王子 + * @since 2023-05-27 14:57:34 + */ +public interface CompanyService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CompanyParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CompanyParam param); + + /** + * 根据id查询 + * + * @param companyId 企业id + * @return Company + */ + Company getByIdRel(Integer companyId); + + Company getByTenantIdRel(Integer tenantId); + + PageResult pageRelAll(CompanyParam param); + + void updateByCompanyId(Company company); + + boolean removeCompanyAll(Integer companyId); + + boolean undeleteAll(Integer companyId); +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/CompanyUrlService.java b/src/main/java/com/gxwebsoft/common/system/service/CompanyUrlService.java new file mode 100644 index 0000000..c2b2479 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/CompanyUrlService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyUrl; +import com.gxwebsoft.common.system.param.CompanyUrlParam; + +import java.util.List; + +/** + * 应用域名Service + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +public interface CompanyUrlService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CompanyUrlParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CompanyUrlParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return CompanyUrl + */ + CompanyUrl getByIdRel(Integer id); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/DictDataService.java b/src/main/java/com/gxwebsoft/common/system/service/DictDataService.java new file mode 100644 index 0000000..86b94bf --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/DictDataService.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.*; +import com.gxwebsoft.common.system.entity.DictData; +import com.gxwebsoft.common.system.param.DictDataParam; + +import java.util.List; + +/** + * 字典数据Service + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface DictDataService extends IService { + + /** + * 关联分页查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(DictDataParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(DictDataParam param); + + /** + * 根据id查询 + * + * @param dictDataId 字典数据id + * @return DictData + */ + DictData getByIdRel(Integer dictDataId); + + /** + * 根据dictCode和dictDataName查询 + * + * @param dictCode 字典标识 + * @param dictDataName 字典项名称 + * @return DictData + */ + DictData getByDictCodeAndName(String dictCode, String dictDataName); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/DictService.java b/src/main/java/com/gxwebsoft/common/system/service/DictService.java new file mode 100644 index 0000000..8aef5ba --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/DictService.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.Dict; + +/** + * 字典Service + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +public interface DictService extends IService { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/DictionaryDataService.java b/src/main/java/com/gxwebsoft/common/system/service/DictionaryDataService.java new file mode 100644 index 0000000..881fd5a --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/DictionaryDataService.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.DictionaryData; +import com.gxwebsoft.common.system.param.DictionaryDataParam; + +import java.util.List; + +/** + * 字典数据Service + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface DictionaryDataService extends IService { + + /** + * 关联分页查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(DictionaryDataParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(DictionaryDataParam param); + + /** + * 根据id查询 + * + * @param dictDataId 字典数据id + * @return DictionaryData + */ + DictionaryData getByIdRel(Integer dictDataId); + + /** + * 根据dictCode和dictDataName查询 + * + * @param dictCode 字典标识 + * @param dictDataName 字典项名称 + * @return DictionaryData + */ + DictionaryData getByDictCodeAndName(String dictCode, String dictDataName); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/DictionaryService.java b/src/main/java/com/gxwebsoft/common/system/service/DictionaryService.java new file mode 100644 index 0000000..4705494 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/DictionaryService.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.Dictionary; + +/** + * 字典Service + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +public interface DictionaryService extends IService { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/DomainService.java b/src/main/java/com/gxwebsoft/common/system/service/DomainService.java new file mode 100644 index 0000000..2996471 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/DomainService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Domain; +import com.gxwebsoft.common.system.param.DomainParam; + +import java.util.List; + +/** + * 授权域名Service + * + * @author 科技小王子 + * @since 2024-09-19 23:56:33 + */ +public interface DomainService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(DomainParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(DomainParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return Domain + */ + Domain getByIdRel(Integer id); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/DomainServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/DomainServiceImpl.java new file mode 100644 index 0000000..9323228 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/DomainServiceImpl.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Domain; +import com.gxwebsoft.common.system.mapper.DomainMapper; +import com.gxwebsoft.common.system.param.DomainParam; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 授权域名Service实现 + * + * @author 科技小王子 + * @since 2024-09-19 23:56:33 + */ +@Service +public class DomainServiceImpl extends ServiceImpl implements DomainService { + + @Override + public PageResult pageRel(DomainParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(DomainParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Domain getByIdRel(Integer id) { + DomainParam param = new DomainParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/EmailRecordService.java b/src/main/java/com/gxwebsoft/common/system/service/EmailRecordService.java new file mode 100644 index 0000000..b99a195 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/EmailRecordService.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.EmailRecord; + +import javax.mail.MessagingException; +import java.io.IOException; +import java.util.Map; + +/** + * 邮件发送记录Service + * + * @author WebSoft + * @since 2019-06-19 04:07:02 + */ +public interface EmailRecordService extends IService { + + /** + * 发送普通邮件 + * + * @param title 标题 + * @param content 内容 + * @param toEmails 收件人 + */ + void sendTextEmail(String title, String content, String[] toEmails); + + /** + * 发送富文本邮件 + * + * @param title 标题 + * @param html 富文本 + * @param toEmails 收件人 + * @throws MessagingException MessagingException + */ + void sendFullTextEmail(String title, String html, String[] toEmails) throws MessagingException; + + /** + * 发送模板邮件 + * + * @param title 标题 + * @param path 模板路径 + * @param map 填充数据 + * @param toEmails 收件人 + * @throws MessagingException MessagingException + * @throws IOException IOException + */ + void sendHtmlEmail(String title, String path, Map map, String[] toEmails) + throws MessagingException, IOException; + + void sendEmail(String title, String content, String receiver); +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/FileRecordService.java b/src/main/java/com/gxwebsoft/common/system/service/FileRecordService.java new file mode 100644 index 0000000..3dd09ac --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/FileRecordService.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.FileRecord; +import com.gxwebsoft.common.system.param.FileRecordParam; + +import java.io.File; +import java.util.List; + +/** + * 文件上传记录Service + * + * @author WebSoft + * @since 2021-08-30 11:20:15 + */ +public interface FileRecordService extends IService { + + /** + * 关联分页查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(FileRecordParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(FileRecordParam param); + + /** + * 根据id查询 + * + * @param id id + * @return FileRecord + */ + FileRecord getByIdRel(Integer id); + + /** + * 根据path查询 + * + * @param path 文件路径 + * @return FileRecord + */ + FileRecord getByIdPath(String path); + + /** + * 异步删除文件 + * + * @param files 文件数组 + */ + void deleteFileAsync(List files); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/LoginRecordService.java b/src/main/java/com/gxwebsoft/common/system/service/LoginRecordService.java new file mode 100644 index 0000000..0c4adbf --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/LoginRecordService.java @@ -0,0 +1,54 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.LoginRecord; +import com.gxwebsoft.common.system.param.LoginRecordParam; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 登录日志Service + * + * @author WebSoft + * @since 2018-12-24 16:10:41 + */ +public interface LoginRecordService extends IService { + + /** + * 关联分页查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(LoginRecordParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(LoginRecordParam param); + + /** + * 根据id查询 + * + * @param id id + * @return LoginRecord + */ + LoginRecord getByIdRel(Integer id); + + /** + * 异步添加 + * + * @param username 用户账号 + * @param type 操作类型 + * @param comments 备注 + * @param tenantId 租户id + * @param request HttpServletRequest + */ + void saveAsync(String username, Integer type, String comments, Integer tenantId, HttpServletRequest request); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/MenuService.java b/src/main/java/com/gxwebsoft/common/system/service/MenuService.java new file mode 100644 index 0000000..db8e967 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/MenuService.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.param.MenuParam; + +/** + * 菜单Service + * + * @author WebSoft + * @since 2018-12-24 16:10:31 + */ +public interface MenuService extends IService { + + Boolean cloneMenu(MenuParam param); + + Boolean install(Integer id); +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/OperationRecordService.java b/src/main/java/com/gxwebsoft/common/system/service/OperationRecordService.java new file mode 100644 index 0000000..227c4e6 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/OperationRecordService.java @@ -0,0 +1,49 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.OperationRecord; +import com.gxwebsoft.common.system.param.OperationRecordParam; + +import java.util.List; + +/** + * 操作日志Service + * + * @author WebSoft + * @since 2018-12-24 16:10:01 + */ +public interface OperationRecordService extends IService { + + /** + * 关联分页查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(OperationRecordParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(OperationRecordParam param); + + /** + * 根据id查询 + * + * @param id id + * @return OperationRecord + */ + OperationRecord getByIdRel(Integer id); + + /** + * 异步添加 + * + * @param operationRecord OperationRecord + */ + void saveAsync(OperationRecord operationRecord); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/OrganizationService.java b/src/main/java/com/gxwebsoft/common/system/service/OrganizationService.java new file mode 100644 index 0000000..94d3407 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/OrganizationService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Organization; +import com.gxwebsoft.common.system.param.OrganizationParam; + +import java.util.List; + +/** + * 组织机构Service + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface OrganizationService extends IService { + + /** + * 关联分页查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(OrganizationParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(OrganizationParam param); + + /** + * 根据id查询 + * + * @param organizationId 机构id + * @return Organization + */ + Organization getByIdRel(Integer organizationId); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/PaymentService.java b/src/main/java/com/gxwebsoft/common/system/service/PaymentService.java new file mode 100644 index 0000000..ae4f571 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/PaymentService.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.param.PaymentParam; + +import java.util.List; + +/** + * 支付方式Service + * + * @author 科技小王子 + * @since 2024-05-11 12:39:11 + */ +public interface PaymentService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(PaymentParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(PaymentParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return Payment + */ + Payment getByIdRel(Integer id); + + Payment getByType(PaymentParam paymentParam); +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/PlugService.java b/src/main/java/com/gxwebsoft/common/system/service/PlugService.java new file mode 100644 index 0000000..18d1194 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/PlugService.java @@ -0,0 +1,44 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Plug; +import com.gxwebsoft.common.system.param.PlugParam; + +import java.util.List; + +/** + * 插件扩展Service + * + * @author 科技小王子 + * @since 2023-05-18 11:57:37 + */ +public interface PlugService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(PlugParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(PlugParam param); + + /** + * 根据id查询 + * + * @param menuId 菜单id + * @return Plug + */ + Plug getByIdRel(Integer menuId); + + Boolean cloneMenu(PlugParam param); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/RoleMenuService.java b/src/main/java/com/gxwebsoft/common/system/service/RoleMenuService.java new file mode 100644 index 0000000..05a3d4f --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/RoleMenuService.java @@ -0,0 +1,35 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.RoleMenu; + +import java.util.List; + +/** + * 角色菜单Service + * + * @author WebSoft + * @since 2018-12-24 16:10:44 + */ +public interface RoleMenuService extends IService { + + /** + * 查询用户对应的菜单 + * + * @param userId 用户id + * @param menuType 菜单类型 + * @return List + */ + List listMenuByUserId(Integer userId, Integer menuType); + + /** + * 查询用户对应的菜单 + * + * @param roleIds 角色id + * @param menuType 菜单类型 + * @return List + */ + List listMenuByRoleIds(List roleIds, Integer menuType); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/RoleService.java b/src/main/java/com/gxwebsoft/common/system/service/RoleService.java new file mode 100644 index 0000000..3e76263 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/RoleService.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.Role; + +/** + * 角色Service + * + * @author WebSoft + * @since 2018-12-24 16:10:32 + */ +public interface RoleService extends IService { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/SettingService.java b/src/main/java/com/gxwebsoft/common/system/service/SettingService.java new file mode 100644 index 0000000..1478c90 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/SettingService.java @@ -0,0 +1,67 @@ +package com.gxwebsoft.common.system.service; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Setting; +import com.gxwebsoft.common.system.param.SettingParam; +import com.wechat.pay.java.core.Config; + +import java.util.List; + +/** + * 系统设置Service + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +public interface SettingService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(SettingParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(SettingParam param); + + /** + * 根据id查询 + * + * @param settingId id + * @return Setting + */ + Setting getByIdRel(Integer settingId); + + /** + * 通过key获取设置内容 + * @param key key + * @return Setting + */ + JSONObject getBySettingKey(String key,Integer tenantId); + + /** + * 跨租户获取设置内容 + * @param key 设置键 + * @param tenantId 租户ID + * @return JSONObject + */ + JSONObject getBySettingKeyIgnoreTenant(String key, Integer tenantId); + + Setting getData(String settingKey); + + JSONObject getCache(String key); + + void initConfig(Setting setting); + + Config getConfig(Integer tenantId); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/TenantService.java b/src/main/java/com/gxwebsoft/common/system/service/TenantService.java new file mode 100644 index 0000000..42614a4 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/TenantService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Tenant; +import com.gxwebsoft.common.system.param.TenantParam; + +import java.util.List; + +/** + * 租户Service + * + * @author 科技小王子 + * @since 2023-07-17 17:49:53 + */ +public interface TenantService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(TenantParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(TenantParam param); + + /** + * 根据id查询 + * + * @param tenantId 租户id + * @return Tenant + */ + Tenant getByIdRel(Integer tenantId); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/UserBalanceLogService.java b/src/main/java/com/gxwebsoft/common/system/service/UserBalanceLogService.java new file mode 100644 index 0000000..eaa4e0d --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/UserBalanceLogService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserBalanceLog; +import com.gxwebsoft.common.system.param.UserBalanceLogParam; + +import java.util.List; + +/** + * 用户余额变动明细表Service + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ +public interface UserBalanceLogService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserBalanceLogParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserBalanceLogParam param); + + /** + * 根据id查询 + * + * @param logId 主键ID + * @return UserBalanceLog + */ + UserBalanceLog getByIdRel(Integer logId); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/UserCollectionService.java b/src/main/java/com/gxwebsoft/common/system/service/UserCollectionService.java new file mode 100644 index 0000000..421c682 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/UserCollectionService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserCollection; +import com.gxwebsoft.common.system.param.UserCollectionParam; + +import java.util.List; + +/** + * 我的收藏Service + * + * @author 科技小王子 + * @since 2024-04-28 18:08:32 + */ +public interface UserCollectionService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserCollectionParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserCollectionParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return UserCollection + */ + UserCollection getByIdRel(Integer id); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/UserCollectionServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/UserCollectionServiceImpl.java new file mode 100644 index 0000000..f5c174f --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/UserCollectionServiceImpl.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserCollection; +import com.gxwebsoft.common.system.mapper.UserCollectionMapper; +import com.gxwebsoft.common.system.param.UserCollectionParam; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 我的收藏Service实现 + * + * @author 科技小王子 + * @since 2024-04-28 18:08:32 + */ +@Service +public class UserCollectionServiceImpl extends ServiceImpl implements UserCollectionService { + + @Override + public PageResult pageRel(UserCollectionParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserCollectionParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public UserCollection getByIdRel(Integer id) { + UserCollectionParam param = new UserCollectionParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/UserFileService.java b/src/main/java/com/gxwebsoft/common/system/service/UserFileService.java new file mode 100644 index 0000000..2c8abe6 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/UserFileService.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.UserFile; + +/** + * 用户文件Service + * + * @author WebSoft + * @since 2022-07-21 14:34:40 + */ +public interface UserFileService extends IService { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/UserRefereeService.java b/src/main/java/com/gxwebsoft/common/system/service/UserRefereeService.java new file mode 100644 index 0000000..e715c4f --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/UserRefereeService.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserReferee; +import com.gxwebsoft.common.system.param.UserRefereeParam; + +import java.util.List; + +/** + * 用户推荐关系表Service + * + * @author 科技小王子 + * @since 2023-10-07 22:56:36 + */ +public interface UserRefereeService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserRefereeParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserRefereeParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return UserReferee + */ + UserReferee getByIdRel(Integer id); + + UserReferee check(Integer dealerId, Integer userId); + + UserReferee getByUserId(Integer userId); +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/UserRoleService.java b/src/main/java/com/gxwebsoft/common/system/service/UserRoleService.java new file mode 100644 index 0000000..c87365b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/UserRoleService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.entity.UserRole; + +import java.util.List; + +/** + * 用户角色Service + * + * @author WebSoft + * @since 2018-12-24 16:10:35 + */ +public interface UserRoleService extends IService { + + /** + * 批量添加用户角色 + * + * @param userId 用户id + * @param roleIds 角色id集合 + * @return int + */ + int saveBatch(Integer userId, List roleIds); + + /** + * 根据用户id查询角色 + * + * @param userId 用户id + * @return List + */ + List listByUserId(Integer userId); + + /** + * 批量根据用户id查询角色 + * + * @param userIds 用户id集合 + * @return List + */ + List listByUserIds(List userIds); + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/UserService.java b/src/main/java/com/gxwebsoft/common/system/service/UserService.java new file mode 100644 index 0000000..4afd0b3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/UserService.java @@ -0,0 +1,122 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.UserParam; +import org.springframework.security.core.userdetails.UserDetailsService; + +import java.util.List; + +/** + * 用户Service + * + * @author WebSoft + * @since 2018-12-24 16:10:52 + */ +public interface UserService extends IService, UserDetailsService { + + /** + * 关联分页查询用户 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserParam param); + + /** + * 关联查询全部用户 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserParam param); + + /** + * 根据id查询用户 + * + * @param userId 用户id + * @return User + */ + User getByIdRel(Integer userId); + + /** + * 根据账号查询用户 + * + * @param username 账号 + * @return User + */ + User getByUsername(String username); + + /** + * 根据账号查询用户 + * + * @param username 账号 + * @param tenantId 租户id + * @return User + */ + User getByUsername(String username, Integer tenantId); + + /** + * 添加用户 + * + * @param user 用户信息 + * @return boolean + */ + boolean saveUser(User user); + + /** + * 修改用户 + * + * @param user 用户信息 + * @return boolean + */ + boolean updateUser(User user); + + /** + * 比较用户密码 + * + * @param dbPassword 数据库存储的密码 + * @param inputPassword 用户输入的密码 + * @return boolean + */ + boolean comparePassword(String dbPassword, String inputPassword); + + /** + * md5加密用户密码 + * + * @param password 密码明文 + * @return 密文 + */ + String encodePassword(String password); + + /** + * 跟进手机号码查询用户 + * @param phone 手机号码 + * @return 用户信息 + */ + User getByPhone(String phone); + + User getByUnionId(UserParam userParam); + + User getByOauthId(UserParam userParam); + + List listStatisticsRel(UserParam param); + + /** + * 更新会员不限租户 + * @param user 用户信息 + */ + void updateByUserId(User user); + + /** + * 根据用户ID查询用户(忽略租户隔离) + * @param userId 用户ID + * @return User + */ + User getByIdIgnoreTenant(Integer userId); + + List pageAdminByPhone(UserParam param); + + List listByAlert(); +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyCommentServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyCommentServiceImpl.java new file mode 100644 index 0000000..e945e66 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyCommentServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyComment; +import com.gxwebsoft.common.system.mapper.CompanyCommentMapper; +import com.gxwebsoft.common.system.param.CompanyCommentParam; +import com.gxwebsoft.common.system.service.CompanyCommentService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 应用评论Service实现 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Service +public class CompanyCommentServiceImpl extends ServiceImpl implements CompanyCommentService { + + @Override + public PageResult pageRel(CompanyCommentParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CompanyCommentParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CompanyComment getByIdRel(Integer id) { + CompanyCommentParam param = new CompanyCommentParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyContentServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyContentServiceImpl.java new file mode 100644 index 0000000..b8604a6 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyContentServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyContent; +import com.gxwebsoft.common.system.mapper.CompanyContentMapper; +import com.gxwebsoft.common.system.param.CompanyContentParam; +import com.gxwebsoft.common.system.service.CompanyContentService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 应用详情Service实现 + * + * @author 科技小王子 + * @since 2024-10-16 13:41:21 + */ +@Service +public class CompanyContentServiceImpl extends ServiceImpl implements CompanyContentService { + + @Override + public PageResult pageRel(CompanyContentParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CompanyContentParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CompanyContent getByIdRel(Integer id) { + CompanyContentParam param = new CompanyContentParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyGitServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyGitServiceImpl.java new file mode 100644 index 0000000..a954d4b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyGitServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyGit; +import com.gxwebsoft.common.system.mapper.CompanyGitMapper; +import com.gxwebsoft.common.system.param.CompanyGitParam; +import com.gxwebsoft.common.system.service.CompanyGitService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 代码仓库Service实现 + * + * @author 科技小王子 + * @since 2024-10-19 18:08:51 + */ +@Service +public class CompanyGitServiceImpl extends ServiceImpl implements CompanyGitService { + + @Override + public PageResult pageRel(CompanyGitParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CompanyGitParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CompanyGit getByIdRel(Integer id) { + CompanyGitParam param = new CompanyGitParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyParameterServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyParameterServiceImpl.java new file mode 100644 index 0000000..4b77612 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyParameterServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyParameter; +import com.gxwebsoft.common.system.mapper.CompanyParameterMapper; +import com.gxwebsoft.common.system.param.CompanyParameterParam; +import com.gxwebsoft.common.system.service.CompanyParameterService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 应用参数Service实现 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Service +public class CompanyParameterServiceImpl extends ServiceImpl implements CompanyParameterService { + + @Override + public PageResult pageRel(CompanyParameterParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CompanyParameterParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CompanyParameter getByIdRel(Integer id) { + CompanyParameterParam param = new CompanyParameterParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyServiceImpl.java new file mode 100644 index 0000000..8bdb503 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyServiceImpl.java @@ -0,0 +1,86 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Company; +import com.gxwebsoft.common.system.mapper.CompanyMapper; +import com.gxwebsoft.common.system.param.CompanyParam; +import com.gxwebsoft.common.system.service.CompanyService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 企业信息Service实现 + * + * @author 科技小王子 + * @since 2023-05-27 14:57:34 + */ +@Service +public class CompanyServiceImpl extends ServiceImpl implements CompanyService { + + @Override + public PageResult pageRel(CompanyParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number desc,create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CompanyParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Company getByIdRel(Integer companyId) { + CompanyParam param = new CompanyParam(); + param.setCompanyId(companyId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public Company getByTenantIdRel(Integer tenantId) { + CompanyParam param = new CompanyParam(); +// final Company one = param.getOne(baseMapper.selectListRel(param)); + param.setAuthoritative(true); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public PageResult pageRelAll(CompanyParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number desc,create_time desc"); + List list = baseMapper.selectPageRelAll(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public void updateByCompanyId(Company company) { + baseMapper.updateByCompanyId(company); + } + + @Override + public boolean removeCompanyAll(Integer companyId){ + if (baseMapper.removeCompanyAll(companyId)) { + return true; + } + return false; + } + + @Override + public boolean undeleteAll(Integer companyId){ + if (baseMapper.undeleteAll(companyId)) { + return true; + } + return false; + } + + + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyUrlServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyUrlServiceImpl.java new file mode 100644 index 0000000..a7922cb --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyUrlServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyUrl; +import com.gxwebsoft.common.system.mapper.CompanyUrlMapper; +import com.gxwebsoft.common.system.param.CompanyUrlParam; +import com.gxwebsoft.common.system.service.CompanyUrlService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 应用域名Service实现 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Service +public class CompanyUrlServiceImpl extends ServiceImpl implements CompanyUrlService { + + @Override + public PageResult pageRel(CompanyUrlParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CompanyUrlParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CompanyUrl getByIdRel(Integer id) { + CompanyUrlParam param = new CompanyUrlParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/DictDataServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/DictDataServiceImpl.java new file mode 100644 index 0000000..e30a0fe --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/DictDataServiceImpl.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.DictData; +import com.gxwebsoft.common.system.mapper.DictDataMapper; +import com.gxwebsoft.common.system.param.DictDataParam; +import com.gxwebsoft.common.system.service.DictDataService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 字典数据Service实现 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Service +public class DictDataServiceImpl extends ServiceImpl + implements DictDataService { + + @Override + public PageResult pageRel(DictDataParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return new PageResult<>(baseMapper.selectPageRel(page, param), page.getTotal()); + } + + @Override + public List listRel(DictDataParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return page.sortRecords(baseMapper.selectListRel(param)); + } + + @Override + public DictData getByIdRel(Integer dictDataId) { + DictDataParam param = new DictDataParam(); + param.setDictDataId(dictDataId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public DictData getByDictCodeAndName(String dictCode, String dictDataName) { + List list = baseMapper.getByDictCodeAndName(dictCode, dictDataName); + return CommonUtil.listGetOne(list); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/DictServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/DictServiceImpl.java new file mode 100644 index 0000000..6b09f90 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/DictServiceImpl.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.Dict; +import com.gxwebsoft.common.system.mapper.DictMapper; +import com.gxwebsoft.common.system.service.DictService; +import org.springframework.stereotype.Service; + +/** + * 字典Service实现 + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +@Service +public class DictServiceImpl extends ServiceImpl implements DictService { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryDataServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryDataServiceImpl.java new file mode 100644 index 0000000..0f26dd2 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryDataServiceImpl.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.DictionaryData; +import com.gxwebsoft.common.system.mapper.DictionaryDataMapper; +import com.gxwebsoft.common.system.param.DictionaryDataParam; +import com.gxwebsoft.common.system.service.DictionaryDataService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 字典数据Service实现 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Service +public class DictionaryDataServiceImpl extends ServiceImpl + implements DictionaryDataService { + + @Override + public PageResult pageRel(DictionaryDataParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return new PageResult<>(baseMapper.selectPageRel(page, param), page.getTotal()); + } + + @Override + public List listRel(DictionaryDataParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return page.sortRecords(baseMapper.selectListRel(param)); + } + + @Override + public DictionaryData getByIdRel(Integer dictDataId) { + DictionaryDataParam param = new DictionaryDataParam(); + param.setDictDataId(dictDataId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public DictionaryData getByDictCodeAndName(String dictCode, String dictDataName) { + List list = baseMapper.getByDictCodeAndName(dictCode, dictDataName); + return CommonUtil.listGetOne(list); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryServiceImpl.java new file mode 100644 index 0000000..74d6fe1 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryServiceImpl.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.Dictionary; +import com.gxwebsoft.common.system.mapper.DictionaryMapper; +import com.gxwebsoft.common.system.service.DictionaryService; +import org.springframework.stereotype.Service; + +/** + * 字典Service实现 + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +@Service +public class DictionaryServiceImpl extends ServiceImpl implements DictionaryService { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/EmailRecordServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/EmailRecordServiceImpl.java new file mode 100644 index 0000000..6cf05fe --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/EmailRecordServiceImpl.java @@ -0,0 +1,99 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.EmailRecord; +import com.gxwebsoft.common.system.mapper.EmailRecordMapper; +import com.gxwebsoft.common.system.service.EmailRecordService; +import org.beetl.core.Configuration; +import org.beetl.core.GroupTemplate; +import org.beetl.core.Template; +import org.beetl.core.resource.ClasspathResourceLoader; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + + +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; +import java.io.IOException; +import java.util.Map; + +/** + * 邮件发送记录Service实现 + * + * @author WebSoft + * @since 2019-06-19 04:07:54 + */ +@Service +public class EmailRecordServiceImpl extends ServiceImpl + implements EmailRecordService { + // 发件邮箱 + @Value("${spring.mail.username:}") + private String formEmail; + @Autowired(required = false) + private JavaMailSender mailSender; + + @Override + public void sendTextEmail(String title, String content, String[] toEmails) { + if (mailSender == null) { + System.out.println("邮件服务未配置,跳过发送邮件: " + title); + return; + } + SimpleMailMessage message = new SimpleMailMessage(); + message.setFrom(formEmail); + message.setTo(toEmails); + message.setSubject(title); + message.setText(content); + mailSender.send(message); + } + + @Override + public void sendFullTextEmail(String title, String html, String[] toEmails) throws MessagingException { + if (mailSender == null) { + System.out.println("邮件服务未配置,跳过发送邮件: " + title); + return; + } + MimeMessage mimeMessage = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); + helper.setFrom(formEmail); + helper.setTo(toEmails); + helper.setSubject(title); + // 发送邮件 + helper.setText(html, true); + mailSender.send(mimeMessage); + } + + @Override + public void sendHtmlEmail(String title, String path, Map map, String[] toEmails) + throws MessagingException, IOException { + ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader("templates/"); + Configuration cfg = Configuration.defaultConfiguration(); + GroupTemplate gt = new GroupTemplate(resourceLoader, cfg); + Template t = gt.getTemplate(path); // 加载html模板 + t.binding(map); // 填充数据 + String html = t.render(); // 获得渲染后的html + sendFullTextEmail(title, html, toEmails); // 发送邮件 + } + + @Async + @Override + public void sendEmail(String title, String content, String receiver) { + // 发送邮件通知 + EmailRecord emailRecord = new EmailRecord(); + emailRecord.setTitle(title); + emailRecord.setContent(content); + emailRecord.setReceiver(receiver); + emailRecord.setCreateUserId(42); + if (mailSender != null) { + sendTextEmail(title,content,receiver.split(",")); + } else { + System.out.println("邮件服务未配置,跳过发送邮件: " + title); + } + save(emailRecord); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/FileRecordServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/FileRecordServiceImpl.java new file mode 100644 index 0000000..72c9c27 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/FileRecordServiceImpl.java @@ -0,0 +1,63 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.FileRecord; +import com.gxwebsoft.common.system.mapper.FileRecordMapper; +import com.gxwebsoft.common.system.param.FileRecordParam; +import com.gxwebsoft.common.system.service.FileRecordService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.util.List; + +/** + * 文件上传记录Service实现 + * + * @author WebSoft + * @since 2021-08-30 11:21:01 + */ +@Service +public class FileRecordServiceImpl extends ServiceImpl implements FileRecordService { + + @Override + public PageResult pageRel(FileRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return new PageResult<>(baseMapper.selectPageRel(page, param), page.getTotal()); + } + + @Override + public List listRel(FileRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(baseMapper.selectListRel(param)); + } + + @Override + public FileRecord getByIdRel(Integer id) { + FileRecordParam param = new FileRecordParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public FileRecord getByIdPath(String path) { + return CommonUtil.listGetOne(baseMapper.getByIdPath(path)); + } + + @Async + @Override + public void deleteFileAsync(List files) { + for (File file : files) { + try { + file.delete(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/LoginRecordServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/LoginRecordServiceImpl.java new file mode 100644 index 0000000..28497e7 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/LoginRecordServiceImpl.java @@ -0,0 +1,78 @@ +package com.gxwebsoft.common.system.service.impl; + +import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.LoginRecord; +import com.gxwebsoft.common.system.mapper.LoginRecordMapper; +import com.gxwebsoft.common.system.param.LoginRecordParam; +import com.gxwebsoft.common.system.service.LoginRecordService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 登录日志Service实现 + * + * @author WebSoft + * @since 2018-12-24 16:10:14 + */ +@Service +public class LoginRecordServiceImpl extends ServiceImpl + implements LoginRecordService { + + @Override + public PageResult pageRel(LoginRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return new PageResult<>(baseMapper.selectPageRel(page, param), page.getTotal()); + } + + @Override + public List listRel(LoginRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(baseMapper.selectListRel(param)); + } + + @Override + public LoginRecord getByIdRel(Integer id) { + LoginRecordParam param = new LoginRecordParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Async + @Override + public void saveAsync(String username, Integer type, String comments, Integer tenantId, + HttpServletRequest request) { + if (username == null) { + return; + } + LoginRecord loginRecord = new LoginRecord(); + loginRecord.setUsername(username); + loginRecord.setLoginType(type); + loginRecord.setComments(comments); + loginRecord.setTenantId(tenantId); + UserAgent ua = UserAgentUtil.parse(ServletUtil.getHeaderIgnoreCase(request, "User-Agent")); + if (ua != null) { + if (ua.getPlatform() != null) { + loginRecord.setOs(ua.getPlatform().toString()); + } + if (ua.getOs() != null) { + loginRecord.setDevice(ua.getOs().toString()); + } + if (ua.getBrowser() != null) { + loginRecord.setBrowser(ua.getBrowser().toString()); + } + } + loginRecord.setIp(ServletUtil.getClientIP(request)); + baseMapper.insert(loginRecord); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/MenuServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/MenuServiceImpl.java new file mode 100644 index 0000000..969aee3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/MenuServiceImpl.java @@ -0,0 +1,139 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.entity.RoleMenu; +import com.gxwebsoft.common.system.mapper.MenuMapper; +import com.gxwebsoft.common.system.param.MenuParam; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.RoleMenuService; +import com.gxwebsoft.common.system.service.RoleService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 菜单Service实现 + * + * @author WebSoft + * @since 2018-12-24 16:10:10 + */ +@Service +public class MenuServiceImpl extends ServiceImpl implements MenuService { + private Integer plugMenuId; + @Resource + private RoleService roleService; + @Resource + private RoleMenuService roleMenuService; + + @Override + @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE) + public Boolean cloneMenu(MenuParam param) { +// System.out.println("准备待克隆的菜单数据 = " + param); + // 删除本项目菜单 + baseMapper.delete(new LambdaQueryWrapper().eq(Menu::getDeleted,0)); + // 顶级栏目 + param.setParentId(0); +// final List list = baseMapper.getMenuByClone(param); +//// final List menuIds = list.stream().map(Menu::getMenuId).collect(Collectors.toList()); + doCloneMenu(baseMapper.getMenuByClone(param)); + return true; + } + + @Override + @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE) + public Boolean install(Integer id) { + // 1.插件绑定的菜单ID + final MenuParam param = new MenuParam(); + param.setMenuId(id); + final List list = baseMapper.getMenuByClone(param); + // TODO 克隆当前插件到顶级菜单 + doCloneMenu(list); + + // 2.查找当前租户的超管权限的roleId + final Role superAdmin = roleService.getOne(new LambdaQueryWrapper().eq(Role::getRoleCode, "superAdmin")); + final Integer roleId = superAdmin.getRoleId(); + final Integer tenantId = superAdmin.getTenantId(); + // 3.勾选菜单根权限 + final RoleMenu roleMenu0 = new RoleMenu(); + roleMenu0.setRoleId(roleId); + roleMenu0.setMenuId(this.plugMenuId); + roleMenuService.save(roleMenu0); + + // 4.勾选根节点下的子菜单权限 + final MenuParam menuParam = new MenuParam(); + menuParam.setParentId(this.plugMenuId); + menuParam.setTenantId(tenantId); + final List menuList = baseMapper.getMenuByClone(menuParam); + menuList.forEach(d->{ + RoleMenu roleMenu = new RoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(d.getMenuId()); + roleMenuService.save(roleMenu); + }); + // 5.调整新插件的排序 + final Menu menu = baseMapper.selectById(this.plugMenuId); + menu.setSortNumber(100); + baseMapper.updateById(menu); + return true; + } + + // 克隆菜单 + private void doCloneMenu(List list) { + final MenuParam param = new MenuParam(); + list.forEach(d -> { + Menu menu = new Menu(); + menu.setParentId(0); + menu.setTitle(d.getTitle()); + menu.setPath(d.getPath()); + menu.setComponent(d.getComponent()); + menu.setMenuType(d.getMenuType()); + menu.setSortNumber(d.getSortNumber()); + menu.setAuthority(d.getAuthority()); + menu.setIcon(d.getIcon()); + menu.setHide(d.getHide()); + menu.setMeta(d.getMeta()); + save(menu); + this.plugMenuId = menu.getMenuId(); + // 二级菜单 + param.setParentId(d.getMenuId()); + final List list1 = baseMapper.getMenuByClone(param); + list1.forEach(d1 -> { + final Menu menu1 = new Menu(); + menu1.setParentId(menu.getMenuId()); + menu1.setTitle(d1.getTitle()); + menu1.setPath(d1.getPath()); + menu1.setComponent(d1.getComponent()); + menu1.setMenuType(d1.getMenuType()); + menu1.setSortNumber(d1.getSortNumber()); + menu1.setAuthority(d1.getAuthority()); + menu1.setIcon(d1.getIcon()); + menu1.setHide(d1.getHide()); + menu1.setMeta(d1.getMeta()); + save(menu1); + // 三级菜单 + param.setParentId(d1.getMenuId()); + final List list2 = baseMapper.getMenuByClone(param); + list2.forEach(d2 -> { + final Menu menu2 = new Menu(); + menu2.setParentId(menu1.getMenuId()); + menu2.setTitle(d2.getTitle()); + menu2.setPath(d2.getPath()); + menu2.setComponent(d2.getComponent()); + menu2.setMenuType(d2.getMenuType()); + menu2.setSortNumber(d2.getSortNumber()); + menu2.setAuthority(d2.getAuthority()); + menu2.setIcon(d2.getIcon()); + menu2.setHide(d2.getHide()); + menu2.setMeta(d2.getMeta()); + save(menu2); + }); + }); + }); + } +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/OperationRecordServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/OperationRecordServiceImpl.java new file mode 100644 index 0000000..8095bf4 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/OperationRecordServiceImpl.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.OperationRecord; +import com.gxwebsoft.common.system.mapper.OperationRecordMapper; +import com.gxwebsoft.common.system.param.OperationRecordParam; +import com.gxwebsoft.common.system.service.OperationRecordService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 操作日志Service实现 + * + * @author WebSoft + * @since 2018-12-24 16:10:02 + */ +@Service +public class OperationRecordServiceImpl extends ServiceImpl + implements OperationRecordService { + + @Override + public PageResult pageRel(OperationRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return new PageResult<>(baseMapper.selectPageRel(page, param), page.getTotal()); + } + + @Override + public List listRel(OperationRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(baseMapper.selectListRel(param)); + } + + @Override + public OperationRecord getByIdRel(Integer id) { + OperationRecordParam param = new OperationRecordParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Async + @Override + public void saveAsync(OperationRecord operationRecord) { + baseMapper.insert(operationRecord); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/OrganizationServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/OrganizationServiceImpl.java new file mode 100644 index 0000000..b2bb53f --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/OrganizationServiceImpl.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Organization; +import com.gxwebsoft.common.system.mapper.OrganizationMapper; +import com.gxwebsoft.common.system.param.OrganizationParam; +import com.gxwebsoft.common.system.service.OrganizationService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 组织机构Service实现 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Service +public class OrganizationServiceImpl extends ServiceImpl + implements OrganizationService { + + @Override + public PageResult pageRel(OrganizationParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return new PageResult<>(baseMapper.selectPageRel(page, param), page.getTotal()); + } + + @Override + public List listRel(OrganizationParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return page.sortRecords(baseMapper.selectListRel(param)); + } + + @Override + public Organization getByIdRel(Integer organizationId) { + OrganizationParam param = new OrganizationParam(); + param.setOrganizationId(organizationId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/PaymentServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/PaymentServiceImpl.java new file mode 100644 index 0000000..9e2d798 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/PaymentServiceImpl.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.mapper.PaymentMapper; +import com.gxwebsoft.common.system.param.PaymentParam; +import com.gxwebsoft.common.system.service.PaymentService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 支付方式Service实现 + * + * @author 科技小王子 + * @since 2024-05-11 12:39:11 + */ +@Service +public class PaymentServiceImpl extends ServiceImpl implements PaymentService { + + @Override + public PageResult pageRel(PaymentParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(PaymentParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Payment getByIdRel(Integer id) { + PaymentParam param = new PaymentParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public Payment getByType(PaymentParam paymentParam) { + return baseMapper.getByType(paymentParam); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/PlugServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/PlugServiceImpl.java new file mode 100644 index 0000000..aee07a6 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/PlugServiceImpl.java @@ -0,0 +1,112 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Plug; +import com.gxwebsoft.common.system.mapper.PlugMapper; +import com.gxwebsoft.common.system.param.PlugParam; +import com.gxwebsoft.common.system.service.PlugService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 插件扩展Service实现 + * + * @author 科技小王子 + * @since 2023-05-18 11:57:37 + */ +@Service +public class PlugServiceImpl extends ServiceImpl implements PlugService { + + @Override + public PageResult pageRel(PlugParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(PlugParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Plug getByIdRel(Integer menuId) { + PlugParam param = new PlugParam(); + param.setMenuId(menuId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE) + public Boolean cloneMenu(PlugParam param) { +// System.out.println("准备待克隆的菜单数据 = " + param); + // 删除本项目菜单 + baseMapper.delete(new LambdaQueryWrapper().eq(Plug::getDeleted,0)); + // 顶级栏目 + param.setParentId(0); + final List list = baseMapper.getMenuByClone(param); +// final List menuIds = list.stream().map(Menu::getMenuId).collect(Collectors.toList()); + + list.forEach(d -> { + Plug plug = new Plug(); + plug.setParentId(0); + plug.setTitle(d.getTitle()); + plug.setPath(d.getPath()); + plug.setComponent(d.getComponent()); + plug.setMenuType(d.getMenuType()); + plug.setSortNumber(d.getSortNumber()); + plug.setAuthority(d.getAuthority()); + plug.setIcon(d.getIcon()); + plug.setHide(d.getHide()); + plug.setMeta(d.getMeta()); + save(plug); + // 二级菜单 + param.setParentId(d.getMenuId()); + final List list1 = baseMapper.getMenuByClone(param); + list1.forEach(d1 -> { + final Plug menu1 = new Plug(); + menu1.setParentId(plug.getMenuId()); + menu1.setTitle(d1.getTitle()); + menu1.setPath(d1.getPath()); + menu1.setComponent(d1.getComponent()); + menu1.setMenuType(d1.getMenuType()); + menu1.setSortNumber(d1.getSortNumber()); + menu1.setAuthority(d1.getAuthority()); + menu1.setIcon(d1.getIcon()); + menu1.setHide(d1.getHide()); + menu1.setMeta(d1.getMeta()); + save(menu1); + // 三级菜单 + param.setParentId(d1.getMenuId()); + final List list2 = baseMapper.getMenuByClone(param); + list2.forEach(d2 -> { + final Plug menu2 = new Plug(); + menu2.setParentId(menu1.getMenuId()); + menu2.setTitle(d2.getTitle()); + menu2.setPath(d2.getPath()); + menu2.setComponent(d2.getComponent()); + menu2.setMenuType(d2.getMenuType()); + menu2.setSortNumber(d2.getSortNumber()); + menu2.setAuthority(d2.getAuthority()); + menu2.setIcon(d2.getIcon()); + menu2.setHide(d2.getHide()); + menu2.setMeta(d2.getMeta()); + save(menu2); + }); + }); + }); + return true; + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/RoleMenuServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/RoleMenuServiceImpl.java new file mode 100644 index 0000000..737c5e3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/RoleMenuServiceImpl.java @@ -0,0 +1,31 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.RoleMenu; +import com.gxwebsoft.common.system.mapper.RoleMenuMapper; +import com.gxwebsoft.common.system.service.RoleMenuService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 角色菜单Service实现 + * + * @author WebSoft + * @since 2018-12-24 16:10:12 + */ +@Service +public class RoleMenuServiceImpl extends ServiceImpl implements RoleMenuService { + + @Override + public List listMenuByUserId(Integer userId, Integer menuType) { + return baseMapper.listMenuByUserId(userId, menuType); + } + + @Override + public List listMenuByRoleIds(List roleIds, Integer menuType) { + return baseMapper.listMenuByRoleIds(roleIds, menuType); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/RoleServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/RoleServiceImpl.java new file mode 100644 index 0000000..f543abd --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/RoleServiceImpl.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.mapper.RoleMapper; +import com.gxwebsoft.common.system.service.RoleService; +import org.springframework.stereotype.Service; + +/** + * 角色服务实现类 + * + * @author WebSoft + * @since 2018-12-24 16:10:11 + */ +@Service +public class RoleServiceImpl extends ServiceImpl implements RoleService { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/SettingServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/SettingServiceImpl.java new file mode 100644 index 0000000..33249de --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/SettingServiceImpl.java @@ -0,0 +1,254 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.annotation.IgnoreTenant; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Setting; +import com.gxwebsoft.common.system.mapper.SettingMapper; +import com.gxwebsoft.common.system.param.SettingParam; +import com.gxwebsoft.common.system.service.SettingService; +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAConfig; +import com.wechat.pay.java.service.payments.jsapi.JsapiService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 系统设置Service实现 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Service +public class SettingServiceImpl extends ServiceImpl implements SettingService { + // 本地缓存 + public static Map configMap = new HashMap<>(); + public static JsapiService service = null; + public static Config config = null; + @Resource + private ConfigProperties pathConfig; + @Resource + private StringRedisTemplate stringRedisTemplate; + + @Value("${spring.profiles.active:prod}") + private String activeProfile; + @Autowired + private SettingService settingService; + + @Override + public PageResult pageRel(SettingParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(SettingParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Setting getByIdRel(Integer settingId) { + SettingParam param = new SettingParam(); + param.setSettingId(settingId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public JSONObject getBySettingKey(String key, Integer tenantId) { + System.out.println("tenantId = " + tenantId); + final JSONObject settingKey = settingService.getBySettingKey("setting_key", tenantId); + System.out.println("settingKey = " + settingKey); + Setting setting = this.getOne(new QueryWrapper().eq("setting_key", key), false); + System.out.println("setting1 = " + setting); + if (setting == null) { + if ("mp-weixin".equals(key)) { + throw new BusinessException("小程序未配置1"); + } + if ("payment".equals(key)) { + throw new BusinessException("支付未配置"); + } + if ("sms".equals(key)) { + throw new BusinessException("短信未配置"); + } + if ("wx-work".equals(key)) { + throw new BusinessException("企业微信未配置"); + } + if ("setting".equals(key)) { + throw new BusinessException("基本信息未配置"); + } + if ("wx-official".equals(key)) { + throw new BusinessException("微信公众号未配置"); + } + if ("printer".equals(key)) { + throw new BusinessException("打印机未配置"); + } + } + return JSON.parseObject(setting.getContent()); + } + + @Override + @IgnoreTenant("跨租户获取指定租户的设置配置") + public JSONObject getBySettingKeyIgnoreTenant(String key, Integer tenantId) { + System.out.println("跨租户查询设置 - key: " + key + ", tenantId: " + tenantId); + final List list = list(new LambdaQueryWrapper().eq(Setting::getTenantId, tenantId)); + System.out.println("list = " + list); + + // 使用跨租户查询,指定租户ID + Setting setting = this.getOne(new QueryWrapper() + .eq("setting_key", key) + .eq("tenant_id", tenantId), false); + + System.out.println("跨租户查询结果: " + setting); + + if (setting == null) { + if ("mp-weixin".equals(key)) { + // 尝试从cms_website_field表中读取微信小程序配置 + JSONObject websiteFieldConfig = getWeixinConfigFromWebsiteField(tenantId); + if (websiteFieldConfig != null) { + System.out.println("从cms_website_field表获取到微信小程序配置: " + websiteFieldConfig); + return websiteFieldConfig; + } + throw new BusinessException("租户 " + tenantId + " 的小程序未配置,请先在系统设置中配置微信小程序信息"); + } + if ("payment".equals(key)) { + throw new BusinessException("租户 " + tenantId + " 的支付未配置"); + } + if ("sms".equals(key)) { + throw new BusinessException("租户 " + tenantId + " 的短信未配置"); + } + if ("wx-work".equals(key)) { + throw new BusinessException("租户 " + tenantId + " 的企业微信未配置"); + } + if ("setting".equals(key)) { + throw new BusinessException("租户 " + tenantId + " 的基本信息未配置"); + } + if ("wx-official".equals(key)) { + throw new BusinessException("租户 " + tenantId + " 的微信公众号未配置"); + } + if ("printer".equals(key)) { + throw new BusinessException("租户 " + tenantId + " 的打印机未配置"); + } + throw new BusinessException("租户 " + tenantId + " 的配置项 " + key + " 未找到"); + } + + return JSON.parseObject(setting.getContent()); + } + + @Override + public Setting getData(String settingKey) { + return query().eq("setting_key", settingKey).one(); + } + + @Override + public JSONObject getCache(String key) { + final String cache = stringRedisTemplate.opsForValue().get(key); + final JSONObject jsonObject = JSONObject.parseObject(cache); + if (jsonObject == null) { + throw new BusinessException("域名未配置"); + } + return jsonObject; + } + + @Override + public void initConfig(Setting data) { + if (data.getSettingKey().equals("payment")) { + final JSONObject jsonObject = JSONObject.parseObject(data.getContent()); + final String mchId = jsonObject.getString("mchId"); + final String apiclientKey = jsonObject.getString("apiclientKey"); + final String privateKey = pathConfig.getUploadPath().concat("file").concat(apiclientKey); + final String apiclientCert = pathConfig.getUploadPath().concat("file").concat(jsonObject.getString("apiclientCert")); + final String merchantSerialNumber = jsonObject.getString("merchantSerialNumber"); + final String apiV3key = jsonObject.getString("wechatApiKey"); + if (config == null) { + // 根据环境选择不同的证书路径配置 + if ("dev".equals(activeProfile)) { + // 开发环境:使用配置文件的upload-path拼接证书路径 - 租户ID 10550 + System.out.println("=== 开发环境:使用配置文件upload-path拼接证书路径 ==="); + String uploadPath = pathConfig.getUploadPath(); // 获取配置的upload-path + String tenantId = "10550"; // 租户ID + String certBasePath = uploadPath + "dev/wechat/" + tenantId + "/"; + String devPrivateKeyPath = certBasePath + "apiclient_key.pem"; + String devCertPath = certBasePath + "apiclient_cert.pem"; + + System.out.println("配置的upload-path: " + uploadPath); + System.out.println("证书基础路径: " + certBasePath); + System.out.println("私钥文件路径: " + devPrivateKeyPath); + System.out.println("证书文件路径: " + devCertPath); + + config = new RSAConfig.Builder() + .merchantId("1246610101") + .privateKeyFromPath(devPrivateKeyPath) + .merchantSerialNumber("2903B872D5CA36E525FAEC37AEDB22E54ECDE7B7") + .wechatPayCertificatesFromPath(devCertPath) + .build(); + System.out.println("开发环境证书路径配置完成"); + } else { + // 生产环境:使用数据库存储的路径 + System.out.println("=== 生产环境:使用数据库存储的证书路径 ==="); + config = new RSAConfig.Builder() + .merchantId(mchId) + .privateKeyFromPath(privateKey) + .merchantSerialNumber(merchantSerialNumber) + .wechatPayCertificatesFromPath(apiclientCert) + .build(); + System.out.println("生产环境证书路径: " + privateKey); + } + configMap.put(data.getTenantId().toString(), config); + System.out.println("当前环境: " + activeProfile); + System.out.println("config = " + config); + } + if (service == null) { + service = new JsapiService.Builder().config(config).build(); + } + } + } + + @Override + public Config getConfig(Integer tenantId) { + if (configMap.get(tenantId.toString()) == null) { + final Setting payment = getOne(new LambdaQueryWrapper().eq(Setting::getSettingKey, "payment")); + this.initConfig(payment); + return configMap.get(tenantId.toString()); + } + return configMap.get(tenantId.toString()); + } + + /** + * 从cms_website_field表中获取微信小程序配置 + * + * @param tenantId 租户ID + * @return 微信小程序配置JSON对象 + */ + private JSONObject getWeixinConfigFromWebsiteField(Integer tenantId) { + try { + System.out.println("尝试从cms_website_field表获取微信小程序配置 - 租户ID: " + tenantId); + return null; + + } catch (Exception e) { + System.err.println("从cms_website_field表获取微信小程序配置异常: " + e.getMessage()); + e.printStackTrace(); + return null; + } + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/TenantServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/TenantServiceImpl.java new file mode 100644 index 0000000..99c423e --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/TenantServiceImpl.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.TenantMapper; +import com.gxwebsoft.common.system.service.TenantService; +import com.gxwebsoft.common.system.entity.Tenant; +import com.gxwebsoft.common.system.param.TenantParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 租户Service实现 + * + * @author 科技小王子 + * @since 2023-07-17 17:49:53 + */ +@Service +public class TenantServiceImpl extends ServiceImpl implements TenantService { + + @Override + public PageResult pageRel(TenantParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(TenantParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Tenant getByIdRel(Integer tenantId) { + TenantParam param = new TenantParam(); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/UserBalanceLogServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/UserBalanceLogServiceImpl.java new file mode 100644 index 0000000..2286471 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/UserBalanceLogServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserBalanceLog; +import com.gxwebsoft.common.system.mapper.UserBalanceLogMapper; +import com.gxwebsoft.common.system.param.UserBalanceLogParam; +import com.gxwebsoft.common.system.service.UserBalanceLogService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 用户余额变动明细表Service实现 + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ +@Service +public class UserBalanceLogServiceImpl extends ServiceImpl implements UserBalanceLogService { + + @Override + public PageResult pageRel(UserBalanceLogParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserBalanceLogParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public UserBalanceLog getByIdRel(Integer logId) { + UserBalanceLogParam param = new UserBalanceLogParam(); + param.setLogId(logId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/UserFileServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/UserFileServiceImpl.java new file mode 100644 index 0000000..b5712c3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/UserFileServiceImpl.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.UserFileMapper; +import com.gxwebsoft.common.system.service.UserFileService; +import com.gxwebsoft.common.system.entity.UserFile; +import org.springframework.stereotype.Service; + +/** + * 用户文件Service实现 + * + * @author WebSoft + * @since 2022-07-21 14:34:40 + */ +@Service +public class UserFileServiceImpl extends ServiceImpl implements UserFileService { + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/UserRefereeServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/UserRefereeServiceImpl.java new file mode 100644 index 0000000..3055b98 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/UserRefereeServiceImpl.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserReferee; +import com.gxwebsoft.common.system.mapper.UserRefereeMapper; +import com.gxwebsoft.common.system.param.UserRefereeParam; +import com.gxwebsoft.common.system.service.UserRefereeService; +import com.gxwebsoft.common.system.service.UserService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用户推荐关系表Service实现 + * + * @author 科技小王子 + * @since 2023-10-07 22:56:36 + */ +@Service +public class UserRefereeServiceImpl extends ServiceImpl implements UserRefereeService { + + @Resource + private UserService userService; + + @Override + public PageResult pageRel(UserRefereeParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + for (UserReferee userReferee : list) { + userReferee.setUser(userService.getById(userReferee.getUserId())); + } + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserRefereeParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public UserReferee getByIdRel(Integer id) { + UserRefereeParam param = new UserRefereeParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public UserReferee check(Integer dealerId, Integer userId) { + return getOne( + new LambdaQueryWrapper() + .eq(UserReferee::getDealerId, dealerId) + .eq(UserReferee::getUserId, userId) + ); + } + + @Override + public UserReferee getByUserId(Integer userId) { + return getOne( + new LambdaQueryWrapper() + .eq(UserReferee::getUserId, userId) + .last("limit 1") + ); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/UserRoleServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/UserRoleServiceImpl.java new file mode 100644 index 0000000..a2a3d11 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/UserRoleServiceImpl.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.entity.UserRole; +import com.gxwebsoft.common.system.mapper.UserRoleMapper; +import com.gxwebsoft.common.system.service.UserRoleService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 用户角色Service实现 + * + * @author WebSoft + * @since 2018-12-24 16:10:36 + */ +@Service +public class UserRoleServiceImpl extends ServiceImpl implements UserRoleService { + + + @Override + public int saveBatch(Integer userId, List roleIds) { + return baseMapper.insertBatch(userId, roleIds); + } + + @Override + public List listByUserId(Integer userId) { + return baseMapper.selectByUserId(userId); + } + + @Override + public List listByUserIds(List userIds) { + return baseMapper.selectByUserIds(userIds); + } + +} diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/UserServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..2d88e9b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/UserServiceImpl.java @@ -0,0 +1,247 @@ +package com.gxwebsoft.common.system.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserRole; +import com.gxwebsoft.common.system.mapper.UserMapper; +import com.gxwebsoft.common.system.param.UserParam; +import com.gxwebsoft.common.system.service.CompanyService; +import com.gxwebsoft.common.system.service.RoleMenuService; +import com.gxwebsoft.common.system.service.UserRoleService; +import com.gxwebsoft.common.system.service.UserService; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 用户Service实现 + * + * @author WebSoft + * @since 2018-12-24 16:10:14 + */ +@Service +public class UserServiceImpl extends ServiceImpl implements UserService { + @Resource + private UserRoleService userRoleService; + @Resource + private RoleMenuService roleMenuService; + @Resource + private BCryptPasswordEncoder bCryptPasswordEncoder; + @Resource + private CompanyService companyService; + @Resource + private RedisUtil redisUtil; + + @Override + public PageResult pageRel(UserParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + // 查询用户的角色 + selectUserRoles(list); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserParam param) { + List list = baseMapper.selectListRel(param); + // 查询用户的角色 + selectUserRoles(list); + // 排序 + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public User getByIdRel(Integer userId) { + UserParam param = new UserParam(); + param.setUserId(userId); + User user = param.getOne(baseMapper.selectListRel(param)); + if (user != null) { + user.setRoles(userRoleService.listByUserId(user.getUserId())); + user.setAuthorities(roleMenuService.listMenuByUserId(user.getUserId(), null)); + // 系统配置信息 +// Map map = new HashMap<>(); + // 1)云存储 +// String key = "setting:upload:" + user.getTenantId(); +// final String upload = redisUtil.get(key); +// if(upload != null){ +// final JSONObject object = JSONObject.parseObject(upload); +// map.put("uploadMethod",object.getString("uploadMethod")); +// map.put("bucketDomain",object.getString("bucketDomain")); +// map.put("fileUrl",object.getString("fileUrl") + "/"); +// user.setSystem(map); +// } + } + return user; + } + + @Override + public User getByUsername(String username) { + return getByUsername(username, null); + } + + @Override + public User getByUsername(String username, Integer tenantId) { + if (StrUtil.isBlank(username)) { + return null; + } + User user = baseMapper.selectByUsername(username, tenantId); + if (user != null) { + user.setRoles(userRoleService.listByUserId(user.getUserId())); + user.setAuthorities(roleMenuService.listMenuByUserId(user.getUserId(), null)); + } + return user; + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + return getByUsername(username); + } + + @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE) + @Override + public boolean saveUser(User user) { + if (StrUtil.isNotEmpty(user.getUsername()) && baseMapper.selectCount(new LambdaQueryWrapper() + .eq(User::getUsername, user.getUsername())) > 0) { + throw new BusinessException("账号已存在"); + } + if (StrUtil.isNotEmpty(user.getPhone()) && baseMapper.selectCount(new LambdaQueryWrapper() + .eq(User::getPhone, user.getPhone())) > 0) { + throw new BusinessException("手机号已存在"); + } + if (StrUtil.isNotEmpty(user.getEmail()) && baseMapper.selectCount(new LambdaQueryWrapper() + .eq(User::getEmail, user.getEmail())) > 0) { + throw new BusinessException("邮箱已存在"); + } + boolean result = baseMapper.insert(user) > 0; + if (result && user.getRoles() != null && user.getRoles().size() > 0) { + List roleIds = user.getRoles().stream().map(Role::getRoleId).collect(Collectors.toList()); + if (userRoleService.saveBatch(user.getUserId(), roleIds) < roleIds.size()) { + throw new BusinessException("用户角色添加失败"); + } + } + return result; + } + + @Transactional(rollbackFor = {Exception.class}) + @Override + public boolean updateUser(User user) { + if (StrUtil.isNotEmpty(user.getUsername()) && baseMapper.selectCount(new LambdaQueryWrapper() + .eq(User::getUsername, user.getUsername()) + .ne(User::getUserId, user.getUserId())) > 0) { + throw new BusinessException("账号已存在"); + } + if (StrUtil.isNotEmpty(user.getPhone()) && baseMapper.selectCount(new LambdaQueryWrapper() + .eq(User::getPhone, user.getPhone()) + .ne(User::getUserId, user.getUserId())) > 0) { + throw new BusinessException("手机号已存在"); + } + if (StrUtil.isNotEmpty(user.getEmail()) && baseMapper.selectCount(new LambdaQueryWrapper() + .eq(User::getEmail, user.getEmail()) + .ne(User::getUserId, user.getUserId())) > 0) { + throw new BusinessException("邮箱已存在"); + } + boolean result = baseMapper.updateById(user) > 0; + if (result && user.getRoles() != null && user.getRoles().size() > 0) { + userRoleService.remove(new LambdaUpdateWrapper().eq(UserRole::getUserId, user.getUserId())); + List roleIds = user.getRoles().stream().map(Role::getRoleId).collect(Collectors.toList()); + if (userRoleService.saveBatch(user.getUserId(), roleIds) < roleIds.size()) { + throw new BusinessException("用户角色添加失败"); + } + } + return result; + } + + @Override + public boolean comparePassword(String dbPassword, String inputPassword) { + return bCryptPasswordEncoder.matches(inputPassword, dbPassword); + } + + @Override + public String encodePassword(String password) { + return password == null ? null : bCryptPasswordEncoder.encode(password); + } + + @Override + public User getByPhone(String phone) { + return query().eq("phone", phone).one(); + } + + @Override + public User getByUnionId(UserParam param) { + return param.getOne(baseMapper.getOne(param)); + } + + @Override + public User getByOauthId(UserParam userParam) { + return userParam.getOne(baseMapper.getOne(userParam)); + } + + @Override + public List listStatisticsRel(UserParam param) { + List list = baseMapper.selectListStatisticsRel(param); + return list; + } + + /** + * 更新用户信息(跨租户) + * + * @param user 用户信息 + */ + @Override + public void updateByUserId(User user) { + baseMapper.updateByUserId(user); + } + + @Override + public List pageAdminByPhone(UserParam param) { + return baseMapper.pageAdminByPhone(param); + } + + @Override + public List listByAlert() { + return baseMapper.listByAlert(); + } + + @Override + public User getByIdIgnoreTenant(Integer userId) { + if (userId == null) { + return null; + } + return baseMapper.selectByIdIgnoreTenant(userId); + } + + /** + * 批量查询用户的角色 + * + * @param users 用户集合 + */ + private void selectUserRoles(List users) { + if (users != null && users.size() > 0) { + List userIds = users.stream().map(User::getUserId).collect(Collectors.toList()); + List userRoles = userRoleService.listByUserIds(userIds); + for (User user : users) { + List roles = userRoles.stream().filter(d -> user.getUserId().equals(d.getUserId())) + .collect(Collectors.toList()); + user.setRoles(roles); + } + } + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..b2b6a2e --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,65 @@ +# 开发环境配置 + +# 服务器配置 +server: + port: 9200 + +# 数据源配置 +spring: + datasource: + url: jdbc:mysql://8.134.169.209:13306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai + username: modules + password: P7KsAyDXG8YdLnkA + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.alibaba.druid.pool.DruidDataSource + + # redis + redis: + database: 0 + host: 8.134.169.209 + port: 16379 + password: redis_WSDb88 + +# 日志配置 +logging: + level: + com.gxwebsoft: DEBUG + com.baomidou.mybatisplus: DEBUG + com.gxwebsoft.shop.mapper: DEBUG + org.apache.ibatis: DEBUG + +socketio: + host: localhost #IP地址 + +# MQTT配置 +mqtt: + enabled: false # 添加开关来禁用MQTT服务 + host: tcp://1.14.159.185:1883 + username: swdev + password: Sw20250523 + client-id-prefix: hjm_car_ + topic: /SW_GPS/# + qos: 2 + connection-timeout: 10 + keep-alive-interval: 20 + auto-reconnect: true + +# 框架配置 +config: + # 开发环境接口 + server-url: https://server.websoft.top/api + upload-path: /Users/gxwebsoft/JAVA/mp-java/src/main/resources # window(D:\Temp) + + # JWT配置 + jwt: + secret: websoft-jwt-secret-key-2025-dev-environment + expire: 86400 # token过期时间(秒) 24小时 + +# 开发环境证书配置 +certificate: + load-mode: CLASSPATH # 开发环境从classpath加载 + wechat-pay: + dev: + private-key-file: "apiclient_key.pem" + apiclient-cert-file: "apiclient_cert.pem" + wechatpay-cert-file: "wechatpay_cert.pem" diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml new file mode 100644 index 0000000..c27504d --- /dev/null +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,84 @@ +# 生产环境配置 + +# 数据源配置 +spring: + datasource: + url: jdbc:mysql://1Panel-mysql-Bqdt:3306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai + username: modules + password: 8YdLnk7KsPAyDXGA + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.alibaba.druid.pool.DruidDataSource + druid: + remove-abandoned: true + + # redis + redis: + database: 0 + host: 1Panel-redis-Q1LE + port: 6379 + password: redis_WSDb88 + +# 日志配置 +logging: + file: + name: websoft-modules.log + level: + root: WARN + com.gxwebsoft: ERROR + com.baomidou.mybatisplus: ERROR + +socketio: + host: 0.0.0.0 #IP地址 + +# MQTT配置 +mqtt: + enabled: false # 添加开关来禁用MQTT服务 + host: tcp://1.14.159.185:1883 + username: swdev + password: Sw20250523 + client-id-prefix: hjm_car_ + topic: /SW_GPS/# + qos: 2 + connection-timeout: 10 + keep-alive-interval: 20 + auto-reconnect: true + +# 框架配置 +config: + # 生产环境接口 + server-url: https://server.websoft.top/api + upload-path: /www/wwwroot/file.ws/ + + # 阿里云OSS云存储 + endpoint: https://oss-cn-shenzhen.aliyuncs.com + accessKeyId: LTAI4GKGZ9Z2Z8JZ77c3GNZP + accessKeySecret: BiDkpS7UXj72HWwDWaFZxiXjNFBNCM + bucketName: oss-gxwebsoft + bucketDomain: https://oss.wsdns.cn + aliyunDomain: https://oss-gxwebsoft.oss-cn-shenzhen.aliyuncs.com + +# 生产环境证书配置 +certificate: + load-mode: VOLUME # 生产环境从Docker挂载卷加载 + cert-root-path: /www/wwwroot/file.ws + +# 支付配置缓存 +payment: + cache: + # 支付配置缓存键前缀,生产环境使用 Payment:1* 格式 + key-prefix: "Payment:1" + # 缓存过期时间(小时) + expire-hours: 24 + +aliyun: + knowledge-base: + access-key-id: LTAI5tD5YRKuxWz6Eg7qrM4P + access-key-secret: bO8TBDXflOwbtSKimPpG8XrJnyzgTk + workspace-id: llm-4pf5auwewoz34zqu + +ai: + template: + # Word 模板路径 + word-template-path: classpath:templates/audit_report_template.docx + # 或者使用绝对路径 + # word-template-path: D:\\公司经济责任审计方案模板.docx \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..751eff3 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,236 @@ +# 端口 +server: + port: 9200 +# 多环境配置 +spring: + profiles: + active: dev + + application: + name: server + + # 允许循环引用(临时解决方案) + main: + allow-circular-references: true + + # 修复 Springfox 与 Spring Boot 2.6+ 兼容性问题 + mvc: + pathmatch: + matching-strategy: ant_path_matcher + + # json时间格式设置 + jackson: + time-zone: GMT+8 + date-format: yyyy-MM-dd HH:mm:ss + serialization: + write-dates-as-timestamps: false + deserialization: + fail-on-unknown-properties: false + # 确保启用Java 8时间支持 + modules: + - com.fasterxml.jackson.datatype.jsr310.JavaTimeModule + + # 连接池配置 + datasource: + druid: + initial-size: 5 + min-idle: 5 + max-active: 20 + max-wait: 30000 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 300000 + test-while-idle: true + test-on-borrow: true + test-on-return: false + remove-abandoned: true + remove-abandoned-timeout: 1800 + #pool-prepared-statements: false + #max-pool-prepared-statement-per-connection-size: 20 + filters: stat, wall + validation-query: SELECT 'x' + aop-patterns: com.gxwebsoft.*.*.service.* + stat-view-servlet: + url-pattern: /druid/* + reset-enable: true + login-username: admin + login-password: admin + + # 设置上传文件大小 + servlet: + multipart: + max-file-size: 100MB + max-request-size: 100MB + + # 邮件服务器配置 + mail: + host: smtp.qq.com + username: 170083662@qq.com + password: mnfokualhfaucaie + default-encoding: UTF-8 + properties: + mail: + smtp: + auth: true + socketFactory: + class: javax.net.ssl.SSLSocketFactory + port: 465 + +# Mybatis-plus配置 +mybatis-plus: + mapper-locations: classpath*:com/gxwebsoft/**/*Mapper.xml + configuration: + map-underscore-to-camel-case: true + cache-enabled: true + global-config: + :banner: false + db-config: + id-type: auto + logic-delete-value: 1 + logic-not-delete-value: 0 + +# 框架配置 +config: + open-office-home: C:/OpenOffice4/ + swagger-base-package: com.gxwebsoft + swagger-title: 网宿软件 API文档 + swagger-description: websoft - 基于java spring、vue3、antd构建的前后端分离快速开发框架 + swagger-version: 2.0 + token-key: WLgNsWJ8rPjRtnjzX/Gx2RGS80Kwnm/ZeLbvIL+NrBs= + # 主服务器 + server-url: https://server.websoft.top/api + # 文件服务器 + file-server: https://file.websoft.top + # 其他 + api-url: https://server.websoft.top/api + upload-path: /Users/gxwebsoft/Documents/uploads + local-upload-path: /Users/gxwebsoft/Documents/uploads + + # 阿里云OSS云存储 + endpoint: https://oss-cn-shenzhen.aliyuncs.com + accessKeyId: LTAI4GKGZ9Z2Z8JZ77c3GNZP + accessKeySecret: BiDkpS7UXj72HWwDWaFZxiXjNFBNCM + bucketName: oss-gxwebsoft + bucketDomain: https://oss.wsdns.cn + aliyunDomain: https://oss-gxwebsoft.oss-cn-shenzhen.aliyuncs.com + +# 商城订单配置 +shop: + order: + # 测试账号配置 + test-account: + enabled: true # 禁用测试账号功能 + phone-numbers: + - "19163679581" # 改为其他测试手机号 + test-pay-amount: 0.01 + + # 租户特殊规则配置 + # tenant-rules: + # - tenant-id: 10324 + # tenant-name: "百色中学" + # min-amount: 10 + # min-amount-message: "捐款金额最低不能少于10元,感谢您的爱心捐赠^_^" + # enabled: true + + # 默认配置 + default-config: + default-title: "订单名称" + default-comments: "暂无" + min-order-amount: 0 + order-timeout-minutes: 30 + + # 订单自动取消配置 + auto-cancel: + # 是否启用自动取消功能 + enabled: true + # 默认超时时间(分钟) + default-timeout-minutes: 30 + # 定时任务检查间隔(分钟) + check-interval-minutes: 1 + # 批量处理大小 + batch-size: 100 + # 定时任务执行时间(cron表达式) + # 生产环境:每5分钟执行一次 + cron: "0 */5 * * * ?" + + # 租户特殊配置 + # tenant-configs: + # - tenant-id: 10324 + # tenant-name: "百色中学" + # timeout-minutes: 120 # 捐款订单给更长的支付时间 + # enabled: true + # 可以添加更多租户配置 + # - tenant-id: 10550 + # tenant-name: "其他租户" + # timeout-minutes: 15 + # enabled: true + +# 证书配置 +certificate: + # 证书加载模式: CLASSPATH, FILESYSTEM, VOLUME + load-mode: CLASSPATH + # Docker挂载卷证书路径 + cert-root-path: /app/certs + # 开发环境证书路径前缀 + dev-cert-path: dev + + # 微信支付证书配置 + wechat-pay: + dev: + api-v3-key: "0kF5OlPr482EZwtn9zGufUcqa7ovgxRL" + private-key-file: "apiclient_key.pem" + apiclient-cert-file: "apiclient_cert.pem" + wechatpay-cert-file: "wechatpay_cert.pem" + prod-base-path: "/file" + cert-dir: "wechat" + + # 支付宝证书配置 + alipay: + cert-dir: "alipay" + app-private-key-file: "app_private_key.pem" + app-cert-public-key-file: "appCertPublicKey.crt" + alipay-cert-public-key-file: "alipayCertPublicKey.crt" + alipay-root-cert-file: "alipayRootCert.crt" + +# 启用 SpringDoc OpenAPI +springdoc: + api-docs: + enabled: true + swagger-ui: + enabled: true + +# 启用 Knife4j +knife4j: + enable: true + +# 优惠券配置 +coupon: + # 过期处理定时任务配置 + expire: + # 定时任务执行时间(cron表达式) + # 生产环境:每天凌晨2点执行 + # 开发环境:每10分钟执行一次 + cron: "0 0 2 * * ?" + # 开发环境可以设置为: "0 */10 * * * ?" + + # 状态管理配置 + status: + # 是否启用自动状态更新 + auto-update: true + # 批量处理大小 + batch-size: 1000 + +# 支付配置 +payment: + # 开发环境配置 + dev: + # 开发环境回调地址(本地调试用) + notify-url: "http://frps-10550.s209.websoft.top/api/shop/shop-order/notify" + # 开发环境是否启用环境感知 + environment-aware: true + + # 生产环境配置 + prod: + # 生产环境回调地址 + notify-url: "https://cms-api.websoft.top/api/shop/shop-order/notify" + # 生产环境是否启用环境感知 + environment-aware: false diff --git a/src/test/java/com/gxwebsoft/TestMain.java b/src/test/java/com/gxwebsoft/TestMain.java new file mode 100644 index 0000000..0cde99b --- /dev/null +++ b/src/test/java/com/gxwebsoft/TestMain.java @@ -0,0 +1,21 @@ +package com.gxwebsoft; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * Created by WebSoft on 2020-03-23 23:37 + */ +@SpringBootTest +public class TestMain { + /** + * 测试 + */ + @Test + public void test() { + + System.out.println("测试"); + + } + +} diff --git a/src/test/java/com/gxwebsoft/generator/ShopGenerator.java b/src/test/java/com/gxwebsoft/generator/ShopGenerator.java new file mode 100644 index 0000000..5a407e4 --- /dev/null +++ b/src/test/java/com/gxwebsoft/generator/ShopGenerator.java @@ -0,0 +1,435 @@ +package com.gxwebsoft.generator; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.core.toolkit.StringPool; +import com.baomidou.mybatisplus.generator.AutoGenerator; +import com.baomidou.mybatisplus.generator.InjectionConfig; +import com.baomidou.mybatisplus.generator.config.*; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; +import com.gxwebsoft.generator.engine.BeetlTemplateEnginePlus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +/** + * CMS模块-代码生成工具 + * + * @author WebSoft + * @since 2021-09-05 00:31:14 + */ +public class ShopGenerator { + // 输出位置 + private static final String OUTPUT_LOCATION = System.getProperty("user.dir"); + //private static final String OUTPUT_LOCATION = "D:/codegen"; // 不想生成到项目中可以写磁盘路径 + // JAVA输出目录 + private static final String OUTPUT_DIR = "/src/main/java"; + // Vue文件输出位置 + private static final String OUTPUT_LOCATION_VUE = "/Users/gxwebsoft/VUE/mp-vue"; + // UniApp文件输出目录 + private static final String OUTPUT_LOCATION_UNIAPP = "/Users/gxwebsoft/VUE/template-10550"; + // Vue文件输出目录 + private static final String OUTPUT_DIR_VUE = "/src"; + // 作者名称 + private static final String AUTHOR = "科技小王子"; + // 是否在xml中添加二级缓存配置 + private static final boolean ENABLE_CACHE = false; + // 数据库连接配置 + private static final String DB_URL = "jdbc:mysql://8.134.169.209:13306/cms_demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8"; + private static final String DB_DRIVER = "com.mysql.cj.jdbc.Driver"; + private static final String DB_USERNAME = "cms_demo"; + private static final String DB_PASSWORD = "EtzJFr4A3c4THZjY"; + // 包名 + private static final String PACKAGE_NAME = "com.gxwebsoft"; + // 模块名 + private static final String MODULE_NAME = "oa"; + // 需要生成的表 + private static final String[] TABLE_NAMES = new String[]{ +// "shop_spec", +// "shop_spec_value", +// "shop_goods", +// "shop_category", +// "shop_goods_spec", +// "shop_goods_sku", +// "shop_goods_category", +// "shop_coupon", +// "shop_goods_description", +// "shop_goods_log", +// "shop_goods_relation", +// "shop_goods_comment", +// "shop_goods_rule", +// "shop_brand", +// "shop_merchant", +// "shop_merchant_type", +// "shop_merchant_apply", +// "shop_merchant_account", +// "shop_chat_message", +// "shop_chat_conversation", +// "shop_user_collection", +// "shop_goods_role_commission" +// "shop_commission_role" +// "shop_order", +// "shop_order_info", +// "shop_order_info_log", +// "shop_order_goods", +// "shop_wechat_deposit", +// "shop_users", +// "shop_user_address", +// "shop_user_balance_log", +// "shop_recharge_order", + // 经销商表 +// "shop_dealer_apply", +// "shop_dealer_capital", +// "shop_dealer_order", +// "shop_dealer_referee", +// "shop_dealer_setting", +// "shop_dealer_user", +// "shop_user_referee", +// "shop_dealer_withdraw", +// "shop_user_coupon", +// "shop_cart", +// "shop_count", +// "shop_order_delivery", +// "shop_order_delivery_goods", +// "shop_order_extract", +// "shop_splash", +// "shop_goods_income_config" +// "shop_express", +// "shop_express_template", +// "shop_express_template_detail", +// "shop_gift" + "shop_article" + }; + // 需要去除的表前缀 + private static final String[] TABLE_PREFIX = new String[]{ + "tb_" + }; + // 不需要作为查询参数的字段 + private static final String[] PARAM_EXCLUDE_FIELDS = new String[]{ + "tenant_id", + "create_time", + "update_time" + }; + // 查询参数使用String的类型 + private static final String[] PARAM_TO_STRING_TYPE = new String[]{ + "Date", + "LocalDate", + "LocalTime", + "LocalDateTime" + }; + // 查询参数使用EQ的类型 + private static final String[] PARAM_EQ_TYPE = new String[]{ + "Integer", + "Boolean", + "BigDecimal" + }; + // 是否添加权限注解 + private static final boolean AUTH_ANNOTATION = true; + // 是否添加日志注解 + private static final boolean LOG_ANNOTATION = true; + // controller的mapping前缀 + private static final String CONTROLLER_MAPPING_PREFIX = "/api"; + // 模板所在位置 + private static final String TEMPLATES_DIR = "/src/test/java/com/gxwebsoft/generator/templates"; + + public static void main(String[] args) { + // 代码生成器 + AutoGenerator mpg = new AutoGenerator(); + + // 全局配置 + GlobalConfig gc = new GlobalConfig(); + gc.setOutputDir(OUTPUT_LOCATION + OUTPUT_DIR); + gc.setAuthor(AUTHOR); + gc.setOpen(false); + gc.setFileOverride(true); + gc.setEnableCache(ENABLE_CACHE); + gc.setSwagger2(true); + gc.setIdType(IdType.AUTO); + gc.setServiceName("%sService"); + mpg.setGlobalConfig(gc); + + // 数据源配置 + DataSourceConfig dsc = new DataSourceConfig(); + dsc.setUrl(DB_URL); + // dsc.setSchemaName("public"); + dsc.setDriverName(DB_DRIVER); + dsc.setUsername(DB_USERNAME); + dsc.setPassword(DB_PASSWORD); + mpg.setDataSource(dsc); + + // 包配置 + PackageConfig pc = new PackageConfig(); + pc.setModuleName(MODULE_NAME); + pc.setParent(PACKAGE_NAME); + mpg.setPackageInfo(pc); + + // 策略配置 + StrategyConfig strategy = new StrategyConfig(); + strategy.setNaming(NamingStrategy.underline_to_camel); + strategy.setColumnNaming(NamingStrategy.underline_to_camel); + strategy.setInclude(TABLE_NAMES); + strategy.setTablePrefix(TABLE_PREFIX); + strategy.setSuperControllerClass(PACKAGE_NAME + ".common.core.web.BaseController"); + strategy.setEntityLombokModel(true); + strategy.setRestControllerStyle(true); + strategy.setControllerMappingHyphenStyle(true); + strategy.setLogicDeleteFieldName("deleted"); + mpg.setStrategy(strategy); + + // 模板配置 + TemplateConfig templateConfig = new TemplateConfig(); + templateConfig.setController(TEMPLATES_DIR + "/controller.java"); + templateConfig.setEntity(TEMPLATES_DIR + "/entity.java"); + templateConfig.setMapper(TEMPLATES_DIR + "/mapper.java"); + templateConfig.setXml(TEMPLATES_DIR + "/mapper.xml"); + templateConfig.setService(TEMPLATES_DIR + "/service.java"); + templateConfig.setServiceImpl(TEMPLATES_DIR + "/serviceImpl.java"); + mpg.setTemplate(templateConfig); + mpg.setTemplateEngine(new BeetlTemplateEnginePlus()); + + // 自定义模板配置 + InjectionConfig cfg = new InjectionConfig() { + @Override + public void initMap() { + Map map = new HashMap<>(); + map.put("packageName", PACKAGE_NAME); + map.put("paramExcludeFields", PARAM_EXCLUDE_FIELDS); + map.put("paramToStringType", PARAM_TO_STRING_TYPE); + map.put("paramEqType", PARAM_EQ_TYPE); + map.put("authAnnotation", AUTH_ANNOTATION); + map.put("logAnnotation", LOG_ANNOTATION); + map.put("controllerMappingPrefix", CONTROLLER_MAPPING_PREFIX); + // 添加项目类型标识,用于模板中的条件判断 + map.put("isUniApp", false); // Vue 项目 + map.put("isVueAdmin", true); // 后台管理项目 + this.setMap(map); + } + }; + String templatePath = TEMPLATES_DIR + "/param.java.btl"; + List focList = new ArrayList<>(); + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION + OUTPUT_DIR + "/" + + PACKAGE_NAME.replace(".", "/") + + "/" + pc.getModuleName() + "/param/" + + tableInfo.getEntityName() + "Param" + StringPool.DOT_JAVA; + } + }); + /** + * 以下是生成VUE项目代码 + * 生成文件的路径 /api/shop/goods/index.ts + */ + templatePath = TEMPLATES_DIR + "/index.ts.btl"; + + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE + + "/api/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "index.ts"; + } + }); + // UniApp 使用专门的模板 + String uniappTemplatePath = TEMPLATES_DIR + "/index.ts.uniapp.btl"; + focList.add(new FileOutConfig(uniappTemplatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + + "/api/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "index.ts"; + } + }); + // 生成TS文件 (/api/shop/goods/model/index.ts) + templatePath = TEMPLATES_DIR + "/model.ts.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE + + "/api/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/model/" + "index.ts"; + } + }); + // UniApp 使用专门的 model 模板 + String uniappModelTemplatePath = TEMPLATES_DIR + "/model.ts.uniapp.btl"; + focList.add(new FileOutConfig(uniappModelTemplatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + + "/api/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/model/" + "index.ts"; + } + }); + // 生成Vue文件(/views/shop/goods/index.vue) + templatePath = TEMPLATES_DIR + "/index.vue.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE + + "/views/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "index.vue"; + } + }); + + // 生成components文件(/views/shop/goods/components/edit.vue) + templatePath = TEMPLATES_DIR + "/components.edit.vue.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE + + "/views/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/components/" + tableInfo.getEntityPath() + "Edit.vue"; + } + }); + + // 生成components文件(/views/shop/goods/components/search.vue) + templatePath = TEMPLATES_DIR + "/components.search.vue.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE + + "/views/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/components/" + "search.vue"; + } + }); + + // ========== 移动端页面文件生成 ========== + // 生成移动端列表页面配置文件 (/src/shop/goods/index.config.ts) + templatePath = TEMPLATES_DIR + "/index.config.ts.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + + "/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "index.config.ts"; + } + }); + + // 生成移动端列表页面组件文件 (/src/shop/goods/index.tsx) + templatePath = TEMPLATES_DIR + "/index.tsx.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + + "/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "index.tsx"; + } + }); + + // 生成移动端新增/编辑页面配置文件 (/src/shop/goods/add.config.ts) + templatePath = TEMPLATES_DIR + "/add.config.ts.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + + "/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "add.config.ts"; + } + }); + + // 生成移动端新增/编辑页面组件文件 (/src/shop/goods/add.tsx) + templatePath = TEMPLATES_DIR + "/add.tsx.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + + "/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "add.tsx"; + } + }); + + cfg.setFileOutConfigList(focList); + mpg.setCfg(cfg); + + mpg.execute(); + + // 自动更新 app.config.ts + updateAppConfig(TABLE_NAMES, MODULE_NAME); + } + + /** + * 自动更新 app.config.ts 文件,添加新生成的页面路径 + */ + private static void updateAppConfig(String[] tableNames, String moduleName) { + String appConfigPath = OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + "/app.config.ts"; + + try { + // 读取原文件内容 + String content = new String(Files.readAllBytes(Paths.get(appConfigPath))); + + // 为每个表生成页面路径 + StringBuilder newPages = new StringBuilder(); + for (String tableName : tableNames) { + String entityPath = tableName.replaceAll("_", ""); + // 转换为驼峰命名 + String[] parts = tableName.split("_"); + StringBuilder camelCase = new StringBuilder(parts[0]); + for (int i = 1; i < parts.length; i++) { + camelCase.append(parts[i].substring(0, 1).toUpperCase()).append(parts[i].substring(1)); + } + entityPath = camelCase.toString(); + + newPages.append(" '").append(entityPath).append("/index',\n"); + newPages.append(" '").append(entityPath).append("/add',\n"); + } + + // 查找对应模块的子包配置 + String modulePattern = "\"root\":\\s*\"" + moduleName + "\",\\s*\"pages\":\\s*\\[([^\\]]*)]"; + Pattern pattern = Pattern.compile(modulePattern, Pattern.DOTALL); + Matcher matcher = pattern.matcher(content); + + if (matcher.find()) { + String existingPages = matcher.group(1); + + // 检查页面是否已存在,避免重复添加 + boolean needUpdate = false; + String[] newPageArray = newPages.toString().split("\n"); + for (String newPage : newPageArray) { + if (!newPage.trim().isEmpty() && !existingPages.contains(newPage.trim().replace(" ", "").replace(",", ""))) { + needUpdate = true; + break; + } + } + + if (needUpdate) { + // 备份原文件 + String backupPath = appConfigPath + ".backup." + System.currentTimeMillis(); + Files.copy(Paths.get(appConfigPath), Paths.get(backupPath)); + System.out.println("已备份原文件到: " + backupPath); + + // 在现有页面列表末尾添加新页面 + String updatedPages = existingPages.trim(); + if (!updatedPages.endsWith(",")) { + updatedPages += ","; + } + updatedPages += "\n" + newPages.toString().trim(); + + // 替换内容 + String updatedContent = content.replace(matcher.group(1), updatedPages); + + // 写入更新后的内容 + Files.write(Paths.get(appConfigPath), updatedContent.getBytes()); + + System.out.println("✅ 已自动更新 app.config.ts,添加了以下页面路径:"); + System.out.println(newPages.toString()); + } else { + System.out.println("ℹ️ app.config.ts 中已包含所有页面路径,无需更新"); + } + } else { + System.out.println("⚠️ 未找到 " + moduleName + " 模块的子包配置,请手动添加页面路径"); + } + + } catch (Exception e) { + System.err.println("❌ 更新 app.config.ts 失败: " + e.getMessage()); + e.printStackTrace(); + } + } + +} diff --git a/src/test/java/com/gxwebsoft/generator/engine/BeetlTemplateEnginePlus.java b/src/test/java/com/gxwebsoft/generator/engine/BeetlTemplateEnginePlus.java new file mode 100644 index 0000000..1a73826 --- /dev/null +++ b/src/test/java/com/gxwebsoft/generator/engine/BeetlTemplateEnginePlus.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.generator.engine; + +import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder; +import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine; +import org.beetl.core.Configuration; +import org.beetl.core.GroupTemplate; +import org.beetl.core.Template; +import org.beetl.core.resource.FileResourceLoader; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Map; + +/** + * Beetl模板引擎实现文件输出 + * + * @author WebSoft + * @since 2021-09-05 00:30:28 + */ +public class BeetlTemplateEnginePlus extends AbstractTemplateEngine { + private GroupTemplate groupTemplate; + + @Override + public AbstractTemplateEngine init(ConfigBuilder configBuilder) { + super.init(configBuilder); + try { + Configuration cfg = Configuration.defaultConfiguration(); + groupTemplate = new GroupTemplate(new FileResourceLoader(), cfg); + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + return this; + } + + @Override + public void writer(Map objectMap, String templatePath, String outputFile) throws Exception { + Template template = groupTemplate.getTemplate(templatePath); + try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) { + template.binding(objectMap); + template.renderTo(fileOutputStream); + } + logger.debug("模板:" + templatePath + "; 文件:" + outputFile); + } + + @Override + public String templateFilePath(String filePath) { + return filePath + ".btl"; + } + +} diff --git a/src/test/java/com/gxwebsoft/generator/templates/add.config.ts.btl b/src/test/java/com/gxwebsoft/generator/templates/add.config.ts.btl new file mode 100644 index 0000000..a93cafd --- /dev/null +++ b/src/test/java/com/gxwebsoft/generator/templates/add.config.ts.btl @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationBarTitleText: '新增${table.comment!'数据'}', + navigationBarTextStyle: 'black' +}) diff --git a/src/test/java/com/gxwebsoft/generator/templates/add.tsx.btl b/src/test/java/com/gxwebsoft/generator/templates/add.tsx.btl new file mode 100644 index 0000000..73055da --- /dev/null +++ b/src/test/java/com/gxwebsoft/generator/templates/add.tsx.btl @@ -0,0 +1,115 @@ +import {useEffect, useState, useRef} from "react"; +import {useRouter} from '@tarojs/taro' +import {Button, Loading, CellGroup, Input, TextArea, Form} from '@nutui/nutui-react-taro' +import Taro from '@tarojs/taro' +import {View} from '@tarojs/components' +import {${entity}} from "@/api/${package.ModuleName}/${table.entityPath}/model"; +import {get${entity}, list${entity}, update${entity}, add${entity}} from "@/api/${package.ModuleName}/${table.entityPath}"; + +const Add${entity} = () => { + const {params} = useRouter(); + const [loading, setLoading] = useState(true) + const [FormData, setFormData] = useState<${entity}>({}) + const formRef = useRef(null) + + const reload = async () => { + if (params.id) { + const data = await get${entity}(Number(params.id)) + setFormData(data) + } else { + setFormData({}) + } + } + + // 提交表单 + const submitSucceed = async (values: any) => { + try { + if (params.id) { + // 编辑模式 + await update${entity}({ + ...values, + id: Number(params.id) + }) + } else { + // 新增模式 + await add${entity}(values) + } + + Taro.showToast({ + title: `操作成功`, + icon: 'success' + }) + + setTimeout(() => { + return Taro.navigateBack() + }, 1000) + } catch (error) { + Taro.showToast({ + title: `操作失败`, + icon: 'error' + }); + } + } + + const submitFailed = (error: any) => { + console.log(error, 'err...') + } + + useEffect(() => { + reload().then(() => { + setLoading(false) + }) + }, []); + + if (loading) { + return 加载中 + } + + return ( + <> +
submitSucceed(values)} + onFinishFailed={(errors) => submitFailed(errors)} + footer={ +
+ +
+ } + > + +<% for(field in table.fields){ %> +<% if(field.propertyName != 'id' && field.propertyName != 'createTime' && field.propertyName != 'updateTime'){ %> + +<% if(field.propertyType == 'String' && field.comment?? && (field.comment?contains('描述') || field.comment?contains('备注') || field.comment?contains('内容'))){ %> +