From b686ecac5fc9679338d6462ce0891d9a4f511d9e Mon Sep 17 00:00:00 2001 From: wangmingwei Date: Tue, 21 Apr 2026 17:41:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 35 + README | 0 README.md | 129 + pom.xml | 194 ++ yunzhupaas-boot-common/pom.xml | 56 + .../yunzhupaas-common-ai/pom.xml | 25 + .../config/AiAutoConfiguration.java | 203 ++ .../com/yunzhupaas/config/AiProperties.java | 134 + .../com/yunzhupaas/constants/AiConstants.java | 58 + .../com/yunzhupaas/service/OpenAiService.java | 42 + .../impl/DefaultOpenAiServiceImpl.java | 101 + .../impl/DisabledOpenAiServiceImpl.java | 41 + .../java/com/yunzhupaas/util/AiLimitUtil.java | 51 + .../yunzhupaas-common-auth/pom.xml | 71 + .../com/yunzhupaas/config/AsyncConfig.java | 149 + .../config/AuthAutoConfigration.java | 45 + .../config/YunzhupaasOauthConfig.java | 63 + .../config/YunzhupaasTokenConfig.java | 101 + .../com/yunzhupaas/consts/AuthConsts.java | 81 + .../com/yunzhupaas/consts/DeviceType.java | 41 + .../yunzhupaas/consts/LoginTicketStatus.java | 47 + .../consts/ScanCodeTicketStatus.java | 30 + .../granter/AbstractTokenGranter.java | 292 ++ .../com/yunzhupaas/granter/TokenGranter.java | 25 + .../granter/TokenGranterBuilder.java | 82 + .../granter/UserDetailsServiceBuilder.java | 39 + .../yunzhupaas/model/LoginTicketModel.java | 38 + .../model/ScanCodeLoginConfigModel.java | 26 + .../com/yunzhupaas/service/LoginService.java | 62 + .../yunzhupaas/service/UserDetailService.java | 20 + .../com/yunzhupaas/util/TenantProvider.java | 122 + .../java/com/yunzhupaas/util/TicketUtil.java | 69 + .../com/yunzhupaas/util/UserProvider.java | 546 ++++ .../yunzhupaas-common-office-v3/pom.xml | 23 + .../easypoi/util/PoiValidationUtil.java | 70 + .../yunzhupaas-common-connector/pom.xml | 16 + .../connector/HttpRequestUserInfoService.java | 25 + .../permission/connector/UserInfoService.java | 44 + .../yunzhupaas-common-core/pom.xml | 315 +++ .../com/yunzhupaas/annotation/EncryptApi.java | 28 + .../com/yunzhupaas/annotation/HandleLog.java | 33 + .../annotation/OrganizeAdminIsTrator.java | 19 + .../annotation/OrganizePermission.java | 18 + .../annotation/PositionPermission.java | 18 + .../yunzhupaas/annotation/RolePermission.java | 19 + .../yunzhupaas/annotation/SaCheckSame.java | 24 + .../yunzhupaas/annotation/UserPermission.java | 18 + .../annotation/YunzhupaasField.java | 117 + .../com/yunzhupaas/base/ActionResult.java | 114 + .../com/yunzhupaas/base/ActionResultCode.java | 69 + .../base/DataInterfacePageListVO.java | 19 + .../com/yunzhupaas/base/DataSourceInfo.java | 43 + .../java/com/yunzhupaas/base/LogSortEnum.java | 86 + .../yunzhupaas/base/MyBatisPrimaryBase.java | 90 + .../main/java/com/yunzhupaas/base/Page.java | 16 + .../java/com/yunzhupaas/base/PageModel.java | 59 + .../java/com/yunzhupaas/base/Pagination.java | 34 + .../com/yunzhupaas/base/PaginationTime.java | 18 + .../java/com/yunzhupaas/base/SmsModel.java | 30 + .../java/com/yunzhupaas/base/UserInfo.java | 215 ++ .../base/entity/SuperBaseEntity.java | 133 + .../yunzhupaas/base/entity/SuperEntity.java | 12 + .../base/entity/SuperExtendEntity.java | 67 + .../yunzhupaas/base/user/UserTenantModel.java | 29 + .../com/yunzhupaas/base/vo/DownloadVO.java | 27 + .../java/com/yunzhupaas/base/vo/ListVO.java | 25 + .../com/yunzhupaas/base/vo/PageListVO.java | 20 + .../com/yunzhupaas/base/vo/PaginationVO.java | 19 + .../config/ApplicationStartErrorCheck.java | 63 + .../config/Conf2SystemConfiguration.java | 53 + .../yunzhupaas/config/ConfigValueUtil.java | 379 +++ .../config/CoreAutoConfiguration.java | 75 + .../com/yunzhupaas/constant/ConfigConst.java | 87 + .../constant/DataInterfaceVarConst.java | 88 + .../constant/DbSensitiveConstant.java | 33 + .../com/yunzhupaas/constant/DsKeyConst.java | 36 + .../com/yunzhupaas/constant/EventConst.java | 11 + .../yunzhupaas/constant/FileTypeConstant.java | 96 + .../yunzhupaas/constant/GenerateConstant.java | 380 +++ .../com/yunzhupaas/constant/GlobalConst.java | 33 + .../com/yunzhupaas/constant/ModuleName.java | 32 + .../java/com/yunzhupaas/constant/MsgCode.java | 740 +++++ .../yunzhupaas/constant/PermissionConst.java | 62 + .../constant/TableFieldsNameConst.java | 23 + .../yunzhupaas/constant/YunzhupaasConst.java | 99 + .../com/yunzhupaas/constant/model/MCode.java | 48 + .../com/yunzhupaas/emnus/DataFieldType.java | 39 + .../com/yunzhupaas/emnus/DataSetTypeEnum.java | 33 + .../com/yunzhupaas/emnus/DbDriverEnum.java | 39 + .../com/yunzhupaas/emnus/DsJoinTypeEnum.java | 64 + .../yunzhupaas/emnus/ExportModelTypeEnum.java | 43 + .../yunzhupaas/emnus/FilePreviewTypeEnum.java | 25 + .../com/yunzhupaas/emnus/ModuleTypeEnum.java | 104 + .../yunzhupaas/emnus/SearchMethodEnum.java | 109 + .../com/yunzhupaas/emnus/TemplateEnum.java | 76 + .../com/yunzhupaas/emnus/TimetaskTypes.java | 54 + .../exception/ConnectDatabaseException.java | 9 + .../yunzhupaas/exception/DataException.java | 45 + .../exception/DataTypeException.java | 10 + .../exception/EncryptFailException.java | 16 + .../yunzhupaas/exception/ImportException.java | 8 + .../yunzhupaas/exception/LoginException.java | 28 + .../exception/TenantDatabaseException.java | 23 + .../exception/TenantInvalidException.java | 32 + .../exception/WorkFlowException.java | 32 + .../com/yunzhupaas/exception/WxError.java | 96 + .../exception/WxErrorException.java | 31 + .../i18n/config/I18nProperties.java | 28 + .../i18n/constant/I18nApiConst.java | 16 + .../yunzhupaas/i18n/constant/I18nConst.java | 12 + .../i18n/core/DynamicMessageSource.java | 31 + ...ReloadableResourceBundleMessageSource.java | 97 + .../i18n/provider/DynamicMessageProvider.java | 44 + .../i18n/provider/I18nMessageProvider.java | 14 + .../i18n/provider/MessageSourceProvider.java | 22 + .../com/yunzhupaas/i18n/util/I18nUtil.java | 68 + .../com/yunzhupaas/model/BaseSystemInfo.java | 253 ++ .../com/yunzhupaas/model/DbTableConModel.java | 52 + .../java/com/yunzhupaas/model/FileListVO.java | 22 + .../java/com/yunzhupaas/model/FileModel.java | 22 + .../com/yunzhupaas/model/FlowWorkListVO.java | 25 + .../com/yunzhupaas/model/FlowWorkModel.java | 22 + .../yunzhupaas/model/MultiTenantType1.java | 44 + .../com/yunzhupaas/model/OnlineDevData.java | 66 + .../com/yunzhupaas/model/TransferModel.java | 19 + .../com/yunzhupaas/model/UserMenuModel.java | 42 + .../yunzhupaas/model/ai/AiFormFieldModel.java | 47 + .../model/ai/AiFormFieldOptionModel.java | 30 + .../com/yunzhupaas/model/ai/AiFormModel.java | 43 + .../model/login/AllMenuSelectVO.java | 37 + .../model/login/AllUserMenuModel.java | 27 + .../com/yunzhupaas/model/login/MeInfoVO.java | 20 + .../yunzhupaas/model/login/MenuTreeVO.java | 37 + .../com/yunzhupaas/model/login/PcUserVO.java | 41 + .../model/login/PermissionModel.java | 16 + .../yunzhupaas/model/login/PermissionVO.java | 11 + .../yunzhupaas/model/login/SystemInfo.java | 102 + .../model/login/UserCommonInfoVO.java | 104 + .../model/login/UserPositionVO.java | 14 + .../yunzhupaas/model/login/UserSystemVO.java | 29 + .../model/logout/LogoutResultModel.java | 19 + .../yunzhupaas/model/tenant/AdminInfoVO.java | 27 + .../model/tenant/TenantAuthorizeModel.java | 26 + .../model/tenant/TenantLinkModel.java | 167 ++ .../model/tenant/TenantMenuModel.java | 18 + .../model/tenant/TenantMenuTreeModel.java | 27 + .../tenant/TenantMenuTreeReturnModel.java | 28 + .../yunzhupaas/model/tenant/TenantMenuVO.java | 26 + .../model/tenant/TenantReSetPasswordForm.java | 30 + .../com/yunzhupaas/model/tenant/TenantVO.java | 92 + .../yunzhupaas/model/visualJson/AbleUtil.java | 96 + .../model/visualJson/FieLdsModel.java | 432 +++ .../model/visualJson/FooterBtnsModel.java | 17 + .../model/visualJson/FormCloumnUtil.java | 488 ++++ .../model/visualJson/FormDataModel.java | 94 + .../model/visualJson/OnlineCusCheckModel.java | 44 + .../model/visualJson/TableFields.java | 21 + .../model/visualJson/TableModel.java | 56 + .../model/visualJson/TemplateJsonModel.java | 26 + .../visualJson/UploaderTemplateModel.java | 20 + .../visualJson/analysis/FormAllModel.java | 30 + .../visualJson/analysis/FormColumnModel.java | 23 + .../analysis/FormColumnTableModel.java | 110 + .../model/visualJson/analysis/FormEnum.java | 99 + .../analysis/FormMastTableModel.java | 22 + .../model/visualJson/analysis/FormModel.java | 58 + .../visualJson/analysis/RecursionForm.java | 22 + .../visualJson/analysis/TableCreModel.java | 24 + .../visualJson/analysis/TableCreModels.java | 18 + .../visualJson/analysis/TableModels.java | 16 + .../model/visualJson/config/ConfigModel.java | 186 ++ .../model/visualJson/config/HeaderModel.java | 18 + .../visualJson/config/PrefixSuffixModel.java | 25 + .../model/visualJson/config/RegListModel.java | 11 + .../model/visualJson/config/RuleConfig.java | 46 + .../visualJson/config/TabConfigModel.java | 30 + .../visualJson/options/ColumnOptionModel.java | 17 + .../visualJson/options/OptionsModel.java | 14 + .../model/visualJson/props/PropsModel.java | 12 + .../yunzhupaas/properties/GatewayWhite.java | 195 ++ .../properties/MvcSecurityProperties.java | 199 ++ .../properties/SecurityProperties.java | 67 + .../support/MyStandardMultipartFile.java | 82 + .../com/yunzhupaas/util/CacheKeyUtil.java | 247 ++ .../java/com/yunzhupaas/util/ClassUtil.java | 95 + .../java/com/yunzhupaas/util/CodeUtil.java | 139 + .../java/com/yunzhupaas/util/Constants.java | 89 + .../java/com/yunzhupaas/util/DataClob.java | 58 + .../java/com/yunzhupaas/util/DateUtil.java | 1817 ++++++++++++ .../java/com/yunzhupaas/util/DesUtil.java | 295 ++ .../java/com/yunzhupaas/util/DownUtil.java | 318 +++ .../com/yunzhupaas/util/FileDownloadUtil.java | 102 + .../java/com/yunzhupaas/util/FileUtil.java | 893 ++++++ .../com/yunzhupaas/util/FlowFormConstant.java | 17 + .../main/java/com/yunzhupaas/util/IpUtil.java | 216 ++ .../java/com/yunzhupaas/util/JScriptUtil.java | 100 + .../java/com/yunzhupaas/util/JsonUtil.java | 201 ++ .../java/com/yunzhupaas/util/JsonUtilEx.java | 79 + .../com/yunzhupaas/util/LockObjectUtil.java | 27 + .../java/com/yunzhupaas/util/Md5Util.java | 115 + .../com/yunzhupaas/util/NoDataSourceBind.java | 21 + .../com/yunzhupaas/util/OptimizeUtil.java | 54 + .../java/com/yunzhupaas/util/PadUtil.java | 52 + .../java/com/yunzhupaas/util/PageUtil.java | 37 + .../com/yunzhupaas/util/ParameterUtil.java | 134 + .../java/com/yunzhupaas/util/PathUtil.java | 26 + .../java/com/yunzhupaas/util/PinYinUtil.java | 114 + .../java/com/yunzhupaas/util/RandomUtil.java | 81 + .../com/yunzhupaas/util/ReflectionUtil.java | 255 ++ .../java/com/yunzhupaas/util/RegexUtils.java | 219 ++ .../java/com/yunzhupaas/util/ServletUtil.java | 251 ++ .../java/com/yunzhupaas/util/StringUtil.java | 500 ++++ .../com/yunzhupaas/util/TableFeildsEnum.java | 122 + .../com/yunzhupaas/util/TenantHolder.java | 54 + .../util/ThreadPoolExecutorUtil.java | 19 + .../main/java/com/yunzhupaas/util/UpUtil.java | 88 + .../com/yunzhupaas/util/VisusalImgUrl.java | 17 + .../java/com/yunzhupaas/util/XSSEscape.java | 143 + .../java/com/yunzhupaas/util/ZipUtil.java | 53 + .../com/yunzhupaas/util/ZxingCodeUtil.java | 218 ++ .../util/context/RequestContext.java | 26 + .../util/context/SpringContext.java | 50 + .../util/data/DataSourceContextHolder.java | 58 + .../yunzhupaas/util/dbcolum/ColumnType.java | 38 + .../util/enums/DictionaryDataEnum.java | 138 + .../util/generater/DataSwapUtil.java | 70 + .../java/com/yunzhupaas/util/jwt/JwtUtil.java | 75 + .../yunzhupaas/util/minio/StorageType.java | 41 + .../com/yunzhupaas/util/text/CharsetKit.java | 82 + .../com/yunzhupaas/util/text/Convert.java | 862 ++++++ .../yunzhupaas/util/text/StrFormatter.java | 100 + .../util/treeutil/ListToTreeUtil.java | 220 ++ .../com/yunzhupaas/util/treeutil/SumTree.java | 25 + .../yunzhupaas/util/treeutil/SumTree2.java | 25 + .../util/treeutil/TreeDotUtils.java | 147 + .../util/treeutil/TreeListModel.java | 49 + .../yunzhupaas/util/treeutil/TreeModel.java | 24 + .../util/treeutil/TreeViewModel.java | 33 + .../treeutil/newtreeutil/TreeDotUtils.java | 183 ++ .../treeutil/newtreeutil/TreeDotUtils2.java | 144 + .../yunzhupaas/util/type/AuthorizeType.java | 48 + .../com/yunzhupaas/util/type/CompareType.java | 14 + .../yunzhupaas/util/type/IntegerNumber.java | 24 + .../com/yunzhupaas/util/type/MethodType.java | 38 + .../com/yunzhupaas/util/type/RequestType.java | 16 + .../com/yunzhupaas/util/type/SortType.java | 24 + .../yunzhupaas/util/type/StringNumber.java | 25 + .../util/visiual/DataTypeConst.java | 50 + .../util/visiual/YunzhupaasKeyConsts.java | 409 +++ .../com/yunzhupaas/util/wxutil/HttpUtil.java | 705 +++++ .../yunzhupaas/util/wxutil/MediaFileType.java | 50 + .../yunzhupaas/util/wxutil/SendPostUtil.java | 116 + .../main/resources/AntiSamy_zh_CN.properties | 34 + .../main/resources/META-INF/spring.factories | 1 + .../resources/antisamy-ebay-imgonlybase64.xml | 2453 ++++++++++++++++ .../src/main/resources/antisamy-ebay.xml | 2455 +++++++++++++++++ .../src/main/resources/antisamy-empty.xml | 73 + .../yunzhupaas-common-database/pom.xml | 157 ++ .../base/controller/SuperController.java | 27 + .../yunzhupaas/base/mapper/SuperMapper.java | 203 ++ .../yunzhupaas/base/service/SuperService.java | 28 + .../base/service/SuperServiceImpl.java | 83 + .../database/config/DruidConfig.java | 81 + .../database/config/IdGeneratorConfig.java | 90 + .../database/config/MybatisPlusConfig.java | 423 +++ .../config/MybatisPlusMetaObjectHandler.java | 67 + .../database/constant/DbAliasConst.java | 91 + .../yunzhupaas/database/constant/DbConst.java | 79 + .../database/constant/DbFieldConst.java | 35 + .../database/constant/RsColumnKeyConst.java | 104 + .../database/constant/RsTableKeyConst.java | 15 + .../database/datatype/db/DtDMEnum.java | 94 + .../database/datatype/db/DtDorisEnum.java | 95 + .../datatype/db/DtKingbaseESEnum.java | 86 + .../database/datatype/db/DtMySQLEnum.java | 119 + .../database/datatype/db/DtOracleEnum.java | 80 + .../datatype/db/DtPostgreSQLEnum.java | 75 + .../database/datatype/db/DtSQLServerEnum.java | 99 + .../datatype/db/interfaces/DtInterface.java | 192 ++ .../datatype/db/interfaces/DtLimitBase.java | 154 ++ .../datatype/limit/DateTimeLimit.java | 41 + .../database/datatype/limit/DecimalLimit.java | 41 + .../database/datatype/limit/FloatLimit.java | 42 + .../database/datatype/limit/IntegerLimit.java | 73 + .../database/datatype/limit/NumberLimit.java | 57 + .../database/datatype/limit/StringLimit.java | 91 + .../datatype/limit/base/DtLimitModel.java | 58 + .../datatype/limit/base/DtModelBase.java | 45 + .../datatype/limit/util/DtLimitUtil.java | 152 + .../database/datatype/model/DtModel.java | 61 + .../database/datatype/model/DtModelDTO.java | 125 + .../datatype/sync/enums/DtConvertEnum.java | 771 ++++++ .../sync/enums/DtConvertMultiEnum.java | 112 + .../datatype/sync/model/DtConvertModel.java | 53 + .../datatype/sync/util/DtSyncTest.java | 160 ++ .../datatype/sync/util/DtSyncUtil.java | 75 + .../database/datatype/utils/DataTypeUtil.java | 28 + .../datatype/viewshow/DtViewEnum.java | 63 + .../datatype/viewshow/ViewDataTypeEnum.java | 118 + .../viewshow/constant/DtViewConst.java | 54 + .../database/enums/DbAliasEnum.java | 149 + .../yunzhupaas/database/enums/ParamEnum.java | 75 + .../database/mapper/JdbcMapper.java | 19 + .../database/model/dbfield/DbFieldModel.java | 117 + .../model/dbfield/JdbcColumnModel.java | 243 ++ .../model/dbfield/base/DbFieldModelBase.java | 59 + .../model/dbtable/DbTableFieldModel.java | 153 + .../model/dbtable/JdbcTableModel.java | 256 ++ .../model/dbtable/base/DbTableModelBase.java | 42 + .../database/model/dto/DataSourceDTO.java | 35 + .../database/model/dto/DbConnDTO.java | 50 + .../database/model/dto/JdbcResult.java | 54 + .../database/model/dto/ModelDTO.java | 40 + .../database/model/dto/PrepSqlDTO.java | 222 ++ .../database/model/entity/DbLinkEntity.java | 54 + .../model/interfaces/DbSourceOrDbLink.java | 24 + .../model/interfaces/JdbcCreUpDel.java | 47 + .../database/model/interfaces/JdbcGetMod.java | 25 + .../database/model/page/DbTableDataForm.java | 19 + .../database/model/page/JdbcPageMod.java | 39 + .../model/superQuery/ConditionJsonModel.java | 27 + .../model/superQuery/SuperJsonModel.java | 15 + .../superQuery/SuperQueryConditionModel.java | 26 + .../model/superQuery/SuperQueryJsonModel.java | 23 + .../plugins/DynamicGeneratorInterceptor.java | 76 + .../DynamicSourceGeneratorInterface.java | 29 + .../database/plugins/ITenantPlugin.java | 40 + .../database/plugins/LogicDeleteHandler.java | 76 + ...MyDefaultMasterSlaveAutoRoutingPlugin.java | 69 + .../plugins/MyDefaultSqlInjector.java | 163 ++ ...amicDataSourceAutoRollbackInterceptor.java | 75 + .../plugins/MyDynamicRoutingDataSource.java | 88 + .../MyLogicDeleteInnerInterceptor.java | 340 +++ .../MyLogicServiceBeanPostProcessor.java | 92 + .../plugins/MySchemaInnerInterceptor.java | 161 ++ .../plugins/MyTenantLineInnerInterceptor.java | 159 ++ .../MyTenantMasterSlaveAutoRoutingPlugin.java | 76 + .../plugins/ResultSetInterceptor.java | 56 + .../yunzhupaas/database/source/DbBase.java | 210 ++ .../yunzhupaas/database/source/DbModel.java | 65 + .../yunzhupaas/database/source/impl/DbDM.java | 60 + .../database/source/impl/DbDoris.java | 54 + .../database/source/impl/DbKingbase.java | 57 + .../database/source/impl/DbMySQL.java | 40 + .../database/source/impl/DbOracle.java | 156 ++ .../database/source/impl/DbPostgre.java | 82 + .../database/source/impl/DbSQLServer.java | 50 + .../com/yunzhupaas/database/sql/SqlBase.java | 61 + .../database/sql/enums/SqlDMEnum.java | 257 ++ .../database/sql/enums/SqlKingbaseESEnum.java | 182 ++ .../database/sql/enums/SqlMySQLEnum.java | 171 ++ .../database/sql/enums/SqlOracleEnum.java | 304 ++ .../database/sql/enums/SqlPostgreSQLEnum.java | 219 ++ .../database/sql/enums/SqlSQLServerEnum.java | 233 ++ .../database/sql/enums/base/SqlComEnum.java | 302 ++ .../database/sql/enums/base/SqlFrameBase.java | 146 + .../database/sql/model/DbStruct.java | 92 + .../database/sql/model/SqlPrintHandler.java | 228 ++ .../database/sql/param/FormatSqlDM.java | 29 + .../database/sql/param/FormatSqlDoris.java | 63 + .../sql/param/FormatSqlKingbaseES.java | 33 + .../database/sql/param/FormatSqlMySQL.java | 56 + .../database/sql/param/FormatSqlOracle.java | 186 ++ .../sql/param/FormatSqlPostgreSQL.java | 13 + .../sql/param/FormatSqlSQLServer.java | 13 + .../database/sql/param/base/FormatSql.java | 125 + .../database/sql/util/SqlFastUtil.java | 365 +++ .../database/sql/util/SqlFrameFastUtil.java | 28 + .../database/sql/util/SqlFrameUtil.java | 102 + .../yunzhupaas/database/util/ConnUtil.java | 303 ++ .../database/util/DataSourceUtil.java | 176 ++ .../yunzhupaas/database/util/DbTypeUtil.java | 246 ++ .../database/util/DynamicDataSourceUtil.java | 271 ++ .../util/IgnoreLogicDeleteHolder.java | 29 + .../database/util/JdbcOriginUtil.java | 69 + .../yunzhupaas/database/util/JdbcUtil.java | 314 +++ .../database/util/NotTenantPluginHolder.java | 51 + .../database/util/ResetSetHolder.java | 34 + .../yunzhupaas/database/util/TableUtil.java | 61 + .../database/util/TenantDataSourceUtil.java | 653 +++++ .../src/main/resources/mapper/JdbcMapper.xml | 25 + .../yunzhupaas-common-event/pom.xml | 22 + .../config/ProjectEventAutoConfiguration.java | 63 + .../yunzhupaas/consts/ProjectEventConst.java | 56 + .../yunzhupaas/event/ProjectEventHolder.java | 58 + .../event/ProjectEventKeyMatcher.java | 94 + .../event/ProjectEventListener.java | 36 + ...ntListenerAnnotationBeanPostProcessor.java | 110 + .../event/ProjectEventProccess.java | 110 + .../yunzhupaas/event/ProjectEventSender.java | 12 + .../ProjectEventRedisMessageHandler.java | 86 + .../handler/ProjectEventRedisSender.java | 46 + .../com/yunzhupaas/module/ProjectEvent.java | 84 + .../module/ProjectEventBuilder.java | 46 + .../module/ProjectEventInstance.java | 28 + .../module/ProjectEventPublish.java | 21 + .../ProjectEventPublishTransaction.java | 21 + .../yunzhupaas/properties/EventProperty.java | 24 + .../com/yunzhupaas/util/PublishEventUtil.java | 100 + .../yunzhupaas-common-file/pom.xml | 131 + .../aspect/LogFileStorageAspect.java | 74 + .../yunzhupaas/config/LocalPathConfig.java | 126 + .../com/yunzhupaas/entity/FileDetail.java | 162 ++ .../yunzhupaas/mapper/FileDetailMapper.java | 10 + .../yunzhupaas/service/FileDetailService.java | 69 + .../com/yunzhupaas/util/DataFileExport.java | 60 + .../java/com/yunzhupaas/util/FileExport.java | 26 + .../com/yunzhupaas/util/FilePathUtil.java | 108 + .../com/yunzhupaas/util/FileUploadUtils.java | 324 +++ .../com/yunzhupaas/util/UploaderUtil.java | 71 + .../src/main/resources/FileDetailMapper.xml | 32 + .../yunzhupaas-common-i18n/pom.xml | 22 + .../i18n/config/I18nAutoConfiguration.java | 75 + .../config/I18nRefreshListenerConfig.java | 31 + .../provider/MyDynamicMessageProvider.java | 63 + .../i18n/provider/MyI18nMessageProvider.java | 108 + .../yunzhupaas-common-office/pom.xml | 41 + .../yunzhupaas/excel/ExcelExportStyler.java | 118 + .../com/yunzhupaas/excel/ExcelFunction.java | 10 + .../com/yunzhupaas/excel/ExcelHelper.java | 158 ++ .../com/yunzhupaas/excel/ExcelPostHandle.java | 8 + .../com/yunzhupaas/excel/ExcelPreHandle.java | 8 + .../excel/handle/ExcelCommentHandle.java | 86 + .../excel/handle/ExcelDataValidation.java | 122 + .../excel/handle/ExcelRequireRedColor.java | 61 + .../com/yunzhupaas/model/ExcelColumnAttr.java | 34 + .../com/yunzhupaas/model/ExcelImportForm.java | 37 + .../com/yunzhupaas/model/ExcelImportVO.java | 41 + .../java/com/yunzhupaas/model/ExcelModel.java | 54 + .../yunzhupaas/model/ExcelViewFieldModel.java | 45 + .../java/com/yunzhupaas/util/ExcelUtil.java | 308 +++ .../java/com/yunzhupaas/util/PdfUtil.java | 52 + .../java/com/yunzhupaas/util/WordUtil.java | 161 ++ .../yunzhupaas-common-redis/pom.xml | 36 + .../com/yunzhupaas/config/FastJsonRedis.java | 50 + .../config/Lock4jAutoConfiguration.java | 51 + .../com/yunzhupaas/config/RedisConfig.java | 101 + .../config/RedisListenerConfig.java | 31 + .../com/yunzhupaas/consts/RedisConst.java | 18 + .../java/com/yunzhupaas/util/RedisUtil.java | 396 +++ .../yunzhupaas-common-scheduletask/pom.xml | 35 + .../rest/RestScheduleTaskUtil.java | 182 ++ .../yunzhupaas-common-security/pom.xml | 27 + .../config/SecurityConfiguration.java | 150 + .../EmptyEncryptRestRequestHandler.java | 27 + .../encrypt/EncryptResponseAdvice.java | 43 + .../encrypt/EncryptRestInterceptor.java | 154 ++ .../filter/ClearThreadContextFilter.java | 41 + .../filter/RequestWrapperFilter.java | 48 + .../com/yunzhupaas/filter/SecurityFilter.java | 83 + .../com/yunzhupaas/handler/IRestHandler.java | 59 + .../permissions/PermissionInterfaceImpl.java | 131 + .../yunzhupaas/wrapper/MyRequestWrapper.java | 240 ++ .../yunzhupaas/wrapper/MyResponseWrapper.java | 159 ++ .../yunzhupaas-common-selenium/pom.xml | 35 + .../yunzhupaas/selenium/SeleniumHelper.java | 34 + .../SeleniumAutoConfiguration.java | 35 + .../selenium/consts/SeleniumConsts.java | 19 + .../selenium/driver/AbstractBrowser.java | 100 + .../selenium/driver/ChromeBrowser.java | 62 + .../selenium/driver/SeleniumBrowser.java | 149 + .../properties/SeleniumProperties.java | 44 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../yunzhupaas-common-shardingsphere/pom.xml | 33 + .../config/ShardingSphereAutoConfig.java | 46 + .../yunzhupaas-common-sms/pom.xml | 53 + .../util/message/SmsAliYunUtil.java | 143 + .../util/message/SmsTenCentCloudUtil.java | 168 ++ .../com/yunzhupaas/util/message/SmsUtil.java | 68 + .../yunzhupaas/util/third/DingTalkUtil.java | 141 + .../yunzhupaas/util/third/QyWebChatUtil.java | 92 + .../yunzhupaas-common-swagger/pom.xml | 64 + .../yunzhupaas/MySpringWebMvcProvider.java | 33 + .../java/com/yunzhupaas/SwaggerConfig.java | 109 + yunzhupaas-cloud-common/pom.xml | 34 + .../pom.xml | 28 + .../config/CloudShardingSphereAutoConfig.java | 51 + .../yunzhupaas-common-dubbo/pom.xml | 39 + .../filter/MyDubboRequestFilter.java | 41 + .../yunzhupaas/filter/MyDubboTokenFilter.java | 67 + .../dubbo/org.apache.dubbo.rpc.Filter | 2 + .../resources/security/serialize.allowlist | 2 + .../yunzhupaas-common-feign/pom.xml | 26 + .../main/java/com/yunzhupaas/FeignConfig.java | 85 + .../com/yunzhupaas/utils/FeignHolder.java | 68 + .../java/com/yunzhupaas/utils/FeignName.java | 38 + .../yunzhupaas-common-mq/pom.xml | 40 + .../config/MqAutoConfiguration.java | 33 + .../handler/ProjectEventMQMessageHandler.java | 57 + .../handler/ProjectEventMQSender.java | 37 + .../yunzhupaas-common-seata/pom.xml | 35 + .../seata/rm/datasource/SqlGenerateUtils.java | 159 ++ yunzhupaas-dependencies/pom.xml | 1029 +++++++ 493 files changed, 52349 insertions(+) create mode 100644 .gitignore delete mode 100644 README create mode 100644 README.md create mode 100644 pom.xml create mode 100644 yunzhupaas-boot-common/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-ai/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/config/AiAutoConfiguration.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/config/AiProperties.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/constants/AiConstants.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/service/OpenAiService.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/service/impl/DefaultOpenAiServiceImpl.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/service/impl/DisabledOpenAiServiceImpl.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/util/AiLimitUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/AsyncConfig.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/AuthAutoConfigration.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/YunzhupaasOauthConfig.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/YunzhupaasTokenConfig.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/AuthConsts.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/DeviceType.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/LoginTicketStatus.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/ScanCodeTicketStatus.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/AbstractTokenGranter.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/TokenGranter.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/TokenGranterBuilder.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/UserDetailsServiceBuilder.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/model/LoginTicketModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/model/ScanCodeLoginConfigModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/service/LoginService.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/service/UserDetailService.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/util/TenantProvider.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/util/TicketUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/util/UserProvider.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-compatible/yunzhupaas-common-office-v3/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-compatible/yunzhupaas-common-office-v3/src/main/java/cn/afterturn/easypoi/util/PoiValidationUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-connector/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-connector/src/main/java/com/yunzhupaas/permission/connector/HttpRequestUserInfoService.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-connector/src/main/java/com/yunzhupaas/permission/connector/UserInfoService.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/EncryptApi.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/HandleLog.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/OrganizeAdminIsTrator.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/OrganizePermission.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/PositionPermission.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/RolePermission.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/SaCheckSame.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/UserPermission.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/YunzhupaasField.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/ActionResult.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/ActionResultCode.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/DataInterfacePageListVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/DataSourceInfo.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/LogSortEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/MyBatisPrimaryBase.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/Page.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/PageModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/Pagination.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/PaginationTime.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/SmsModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/UserInfo.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/entity/SuperBaseEntity.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/entity/SuperEntity.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/entity/SuperExtendEntity.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/user/UserTenantModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/DownloadVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/ListVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/PageListVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/PaginationVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/ApplicationStartErrorCheck.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/Conf2SystemConfiguration.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/ConfigValueUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/CoreAutoConfiguration.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/ConfigConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/DataInterfaceVarConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/DbSensitiveConstant.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/DsKeyConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/EventConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/FileTypeConstant.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/GenerateConstant.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/GlobalConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/ModuleName.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/MsgCode.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/PermissionConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/TableFieldsNameConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/YunzhupaasConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/model/MCode.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DataFieldType.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DataSetTypeEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DbDriverEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DsJoinTypeEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/ExportModelTypeEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/FilePreviewTypeEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/ModuleTypeEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/SearchMethodEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/TemplateEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/TimetaskTypes.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/ConnectDatabaseException.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/DataException.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/DataTypeException.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/EncryptFailException.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/ImportException.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/LoginException.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/TenantDatabaseException.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/TenantInvalidException.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/WorkFlowException.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/WxError.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/WxErrorException.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/config/I18nProperties.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/constant/I18nApiConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/constant/I18nConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/core/DynamicMessageSource.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/core/MyReloadableResourceBundleMessageSource.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/provider/DynamicMessageProvider.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/provider/I18nMessageProvider.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/provider/MessageSourceProvider.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/util/I18nUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/BaseSystemInfo.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/DbTableConModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FileListVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FileModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FlowWorkListVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FlowWorkModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/MultiTenantType1.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/OnlineDevData.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/TransferModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/UserMenuModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/ai/AiFormFieldModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/ai/AiFormFieldOptionModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/ai/AiFormModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/AllMenuSelectVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/AllUserMenuModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/MeInfoVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/MenuTreeVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/PcUserVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/PermissionModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/PermissionVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/SystemInfo.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/UserCommonInfoVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/UserPositionVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/UserSystemVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/logout/LogoutResultModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/AdminInfoVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantAuthorizeModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantLinkModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuTreeModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuTreeReturnModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantReSetPasswordForm.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/AbleUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FieLdsModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FooterBtnsModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FormCloumnUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FormDataModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/OnlineCusCheckModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/TableFields.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/TableModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/TemplateJsonModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/UploaderTemplateModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormAllModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormColumnModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormColumnTableModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormMastTableModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/RecursionForm.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/TableCreModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/TableCreModels.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/TableModels.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/ConfigModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/HeaderModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/PrefixSuffixModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/RegListModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/RuleConfig.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/TabConfigModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/options/ColumnOptionModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/options/OptionsModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/props/PropsModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/properties/GatewayWhite.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/properties/MvcSecurityProperties.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/properties/SecurityProperties.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/support/MyStandardMultipartFile.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/CacheKeyUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ClassUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/CodeUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/Constants.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DataClob.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DateUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DesUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DownUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/FileDownloadUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/FileUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/FlowFormConstant.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/IpUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/JScriptUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/JsonUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/JsonUtilEx.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/LockObjectUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/Md5Util.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/NoDataSourceBind.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/OptimizeUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PadUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PageUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ParameterUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PathUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PinYinUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/RandomUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ReflectionUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/RegexUtils.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ServletUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/StringUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/TableFeildsEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/TenantHolder.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ThreadPoolExecutorUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/UpUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/VisusalImgUrl.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/XSSEscape.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ZipUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ZxingCodeUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/context/RequestContext.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/context/SpringContext.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/data/DataSourceContextHolder.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/dbcolum/ColumnType.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/enums/DictionaryDataEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/generater/DataSwapUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/jwt/JwtUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/minio/StorageType.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/text/CharsetKit.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/text/Convert.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/text/StrFormatter.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/ListToTreeUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/SumTree.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/SumTree2.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeDotUtils.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeListModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeViewModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/newtreeutil/TreeDotUtils.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/newtreeutil/TreeDotUtils2.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/AuthorizeType.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/CompareType.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/IntegerNumber.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/MethodType.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/RequestType.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/SortType.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/StringNumber.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/visiual/DataTypeConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/visiual/YunzhupaasKeyConsts.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/wxutil/HttpUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/wxutil/MediaFileType.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/wxutil/SendPostUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/AntiSamy_zh_CN.properties create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/META-INF/spring.factories create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/antisamy-ebay-imgonlybase64.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/antisamy-ebay.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/antisamy-empty.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/controller/SuperController.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/mapper/SuperMapper.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/service/SuperService.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/service/SuperServiceImpl.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/DruidConfig.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/IdGeneratorConfig.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/MybatisPlusConfig.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/MybatisPlusMetaObjectHandler.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/DbAliasConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/DbConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/DbFieldConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/RsColumnKeyConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/RsTableKeyConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtDMEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtDorisEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtKingbaseESEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtMySQLEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtOracleEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtPostgreSQLEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtSQLServerEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/interfaces/DtInterface.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/interfaces/DtLimitBase.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/DateTimeLimit.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/DecimalLimit.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/FloatLimit.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/IntegerLimit.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/NumberLimit.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/StringLimit.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/base/DtLimitModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/base/DtModelBase.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/util/DtLimitUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/model/DtModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/model/DtModelDTO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/enums/DtConvertEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/enums/DtConvertMultiEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/model/DtConvertModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/util/DtSyncTest.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/util/DtSyncUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/utils/DataTypeUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/viewshow/DtViewEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/viewshow/ViewDataTypeEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/viewshow/constant/DtViewConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/enums/DbAliasEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/enums/ParamEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/mapper/JdbcMapper.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbfield/DbFieldModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbfield/JdbcColumnModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbfield/base/DbFieldModelBase.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbtable/DbTableFieldModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbtable/JdbcTableModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbtable/base/DbTableModelBase.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/DataSourceDTO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/DbConnDTO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/JdbcResult.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/ModelDTO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/PrepSqlDTO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/entity/DbLinkEntity.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/interfaces/DbSourceOrDbLink.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/interfaces/JdbcCreUpDel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/interfaces/JdbcGetMod.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/page/DbTableDataForm.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/page/JdbcPageMod.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/ConditionJsonModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/SuperJsonModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/SuperQueryConditionModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/SuperQueryJsonModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/DynamicGeneratorInterceptor.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/DynamicSourceGeneratorInterface.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/ITenantPlugin.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/LogicDeleteHandler.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDefaultMasterSlaveAutoRoutingPlugin.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDefaultSqlInjector.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDynamicDataSourceAutoRollbackInterceptor.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDynamicRoutingDataSource.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyLogicDeleteInnerInterceptor.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyLogicServiceBeanPostProcessor.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MySchemaInnerInterceptor.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyTenantLineInnerInterceptor.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyTenantMasterSlaveAutoRoutingPlugin.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/ResultSetInterceptor.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/DbBase.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/DbModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbDM.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbDoris.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbKingbase.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbMySQL.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbOracle.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbPostgre.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbSQLServer.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/SqlBase.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlDMEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlKingbaseESEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlMySQLEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlOracleEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlPostgreSQLEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlSQLServerEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/base/SqlComEnum.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/base/SqlFrameBase.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/model/DbStruct.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/model/SqlPrintHandler.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlDM.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlDoris.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlKingbaseES.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlMySQL.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlOracle.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlPostgreSQL.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlSQLServer.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/base/FormatSql.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/util/SqlFastUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/util/SqlFrameFastUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/util/SqlFrameUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/ConnUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/DataSourceUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/DbTypeUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/DynamicDataSourceUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/IgnoreLogicDeleteHolder.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/JdbcOriginUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/JdbcUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/NotTenantPluginHolder.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/ResetSetHolder.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/TableUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/TenantDataSourceUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-database/src/main/resources/mapper/JdbcMapper.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/config/ProjectEventAutoConfiguration.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/consts/ProjectEventConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventHolder.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventKeyMatcher.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventListener.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventListenerAnnotationBeanPostProcessor.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventProccess.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventSender.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/handler/ProjectEventRedisMessageHandler.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/handler/ProjectEventRedisSender.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEvent.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventBuilder.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventInstance.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventPublish.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventPublishTransaction.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/properties/EventProperty.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/util/PublishEventUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-file/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/aspect/LogFileStorageAspect.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/config/LocalPathConfig.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/entity/FileDetail.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/mapper/FileDetailMapper.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/service/FileDetailService.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/DataFileExport.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/FileExport.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/FilePathUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/FileUploadUtils.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/UploaderUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-file/src/main/resources/FileDetailMapper.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-i18n/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/config/I18nAutoConfiguration.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/config/I18nRefreshListenerConfig.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/provider/MyDynamicMessageProvider.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/provider/MyI18nMessageProvider.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelExportStyler.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelFunction.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelHelper.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelPostHandle.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelPreHandle.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/handle/ExcelCommentHandle.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/handle/ExcelDataValidation.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/handle/ExcelRequireRedColor.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelColumnAttr.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelImportForm.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelImportVO.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelViewFieldModel.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/util/ExcelUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/util/PdfUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/util/WordUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-redis/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/FastJsonRedis.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/Lock4jAutoConfiguration.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/RedisConfig.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/RedisListenerConfig.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/consts/RedisConst.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/util/RedisUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-scheduletask/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-scheduletask/src/main/java/com/yunzhupaas/scheduletask/rest/RestScheduleTaskUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-security/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/config/SecurityConfiguration.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/encrypt/EmptyEncryptRestRequestHandler.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/encrypt/EncryptResponseAdvice.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/encrypt/EncryptRestInterceptor.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/filter/ClearThreadContextFilter.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/filter/RequestWrapperFilter.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/filter/SecurityFilter.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/handler/IRestHandler.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/permissions/PermissionInterfaceImpl.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/wrapper/MyRequestWrapper.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/wrapper/MyResponseWrapper.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-selenium/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/SeleniumHelper.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/autoconfiguration/SeleniumAutoConfiguration.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/consts/SeleniumConsts.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/driver/AbstractBrowser.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/driver/ChromeBrowser.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/driver/SeleniumBrowser.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/properties/SeleniumProperties.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-shardingsphere/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-shardingsphere/src/main/java/com/yunzhupaas/config/ShardingSphereAutoConfig.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-sms/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/message/SmsAliYunUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/message/SmsTenCentCloudUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/message/SmsUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/third/DingTalkUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/third/QyWebChatUtil.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-swagger/pom.xml create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-swagger/src/main/java/com/yunzhupaas/MySpringWebMvcProvider.java create mode 100644 yunzhupaas-boot-common/yunzhupaas-common-swagger/src/main/java/com/yunzhupaas/SwaggerConfig.java create mode 100644 yunzhupaas-cloud-common/pom.xml create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-cloudshardingsphere/pom.xml create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-cloudshardingsphere/src/main/java/com/yunzhupaas/config/CloudShardingSphereAutoConfig.java create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-dubbo/pom.xml create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/java/com/yunzhupaas/filter/MyDubboRequestFilter.java create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/java/com/yunzhupaas/filter/MyDubboTokenFilter.java create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/resources/security/serialize.allowlist create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-feign/pom.xml create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-feign/src/main/java/com/yunzhupaas/FeignConfig.java create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-feign/src/main/java/com/yunzhupaas/utils/FeignHolder.java create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-feign/src/main/java/com/yunzhupaas/utils/FeignName.java create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-mq/pom.xml create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-mq/src/main/java/com/yunzhupaas/config/MqAutoConfiguration.java create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-mq/src/main/java/com/yunzhupaas/handler/ProjectEventMQMessageHandler.java create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-mq/src/main/java/com/yunzhupaas/handler/ProjectEventMQSender.java create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-seata/pom.xml create mode 100644 yunzhupaas-cloud-common/yunzhupaas-common-seata/src/main/java/io/seata/rm/datasource/SqlGenerateUtils.java create mode 100644 yunzhupaas-dependencies/pom.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c0c8926 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# IDEA artifacts and output dirs +*.iml +*.ipr +*.iws +.idea +out +test-output +atlassian-ide-plugin.xml +.gradletasknamecache +classes/ +target/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* diff --git a/README b/README deleted file mode 100644 index e69de29..0000000 diff --git a/README.md b/README.md new file mode 100644 index 0000000..90fd476 --- /dev/null +++ b/README.md @@ -0,0 +1,129 @@ +> 特别说明:源码、JDK、数据库、Redis等安装或存放路径禁止包含中文、空格、特殊字符等 + +## 一 项目结构 + +```text +├── yunzhupaas-boot-common - 单体版本涉及依赖 +│ ├── yunzhupaas-common-auth - 认证模块 +│ ├── yunzhupaas-common-compatible - 兼容模块文件夹 +│ ├── yunzhupaas-common-office-v3- Boot3 Office +│ ├── yunzhupaas-common-connector - 单点数据推送模块 +│ ├── yunzhupaas-common-core - 基础类及常用工具 +│ ├── yunzhupaas-common-database - 数据库配置及多数据库兼容 +│ ├── yunzhupaas-common-event - 事件发布 +│ ├── yunzhupaas-common-file - 文件工具类模块 +│ ├── yunzhupaas-common-i18n - 文件工具类模块 +│ ├── yunzhupaas-common-office - office操作模块 +│ ├── yunzhupaas-common-redis - 缓存工具Redis组件配置 +│ ├── yunzhupaas-common-scheduletask - 调度工具 +│ ├── yunzhupaas-common-security - 接口鉴权配置 +│ ├── yunzhupaas-common-selenium - 浏览器模拟 +│ ├── yunzhupaas-common-shardingsphere - shardingsphere配置 +│ ├── yunzhupaas-common-sms - 短信模块 +│ ├── yunzhupaas-common-swagger - API组件Swagger配置 +│ └── pom.xml +├── yunzhupaas-cloud-common - 微服务版本涉及依赖 +│ ├── yunzhupaas-common-cloudshardingsphere - 微服务shardingsphere配置 +│ ├── yunzhupaas-common-dubbo - Dubbo拦截器, 自动封装认证信息 +│ ├── yunzhupaas-common-mq - 消息队列 +│ ├── yunzhupaas-common-feign - 远程调用Feign组件配置 +│ ├── yunzhupaas-common-seata - seata依赖 +│ └── pom.xml +├── yunzhupaas-dependencies - 所有依赖版本 +│ └── pom.xml +├── pom.xml +└── README.md - 项目说明文档 +``` + +## 二 环境要求 + +| 类目 | 版本或建议 | +|-------|---------| +| 硬件 | 开发电脑建议使用I3及以上CPU,16G及以上内存 | +| 操作系统 | Windows 10/11,MacOS | +| JDK | 默认使用JDK 21,兼容JDK 8/11、JDK17(需调整部分代码),推荐使用 `OpenJDK`,如 `Liberica JDK`、`Eclipse Temurin`、`Alibaba Dragonwell`、`BiSheng`等发行版; | +| Maven | 依赖管理工具,推荐使用 `3.6.3` 及以上版本 | +| IDE | 代码集成开发环境,推荐使用 `IDEA2024` 及以上版本,兼容 `Eclipse`、 `Spring Tool Suite` 等IDE工具 | + +## 三 关联项目 + +> 为以下项目提供基础依赖 + +| 项目 | 分支 | 说明 | +| --- |---------------| --- | +| yunzhupaas-file-core-starter | v5.2.x-stable | 文件基础依赖项目源码 | +| yunzhupaas-java-datareport-univer | v5.2.x-stable | Univer报表源码 | +| yunzhupaas-java-datareport-univer-core | v5.2.x-stable | Univer报表核心依赖源码 | +| yunzhupaas-scheduletask | v5.2.x-stable | 任务调度客户端依赖及服务端项目源码 | +| yunzhupaas-java-boot | v5.2.x-stable | Java单体后端项目源码 | +| yunzhupaas-java-cloud | v5.2.x-stable | Java微服务后端项目源码 | + +## 四 使用方式 + +### 4.1 前置条件 + +#### 4.1.1 本地安装yunzhupaas-common-core + +在IDEA中,双击右侧 `Maven` 中 `yunzhupaas-common` > `yunzhupaas-boot-common` > `yunzhupaas-common-core` > `Lifecycle` > `install`,将 `yunzhupaas-common-core` 包安装至本地 + +#### 4.1.2 本地安装yunzhupaas-dependencies + +在IDEA中,双击右侧 `Maven` 中 `yunzhupaas-common` > `yunzhupaas-dependencies` > `Lifecycle` > `install`,将 `yunzhupaas-dependencies` 包安装至本地 + +#### 4.1.3 本地安装file-core-starter + +IDEA打开 `yunzhupaas-file-core-starter` 项目, 双击右侧 `Maven`中 `yunzhupaas-file-core-starter` > `Lifecycle` > `install`,将 `yunzhupaas-file-core-starter` 包安装至本地 + +#### 4.1.4 本地安装scheduletask + +IDEA打开 `yunzhupaas-scheduletask` 项目, 双击右侧 `Maven`中`yunzhupaas-scheduletask` > `Lifecycle` > `install`,将 `yunzhupaas-scheduletask` 包安装至本地 + +### 4.2 本地安装 + +在IDEA中,双击右侧 `Maven` 中 `yunzhupaas-common` > `Lifecycle` > `install`,将 `yunzhupaas-common` 包安装至本地 + +### 4.3 私服发布 +> 若无Maven私服,忽略本节内容 + +#### 4.3.1 配置Maven + +打开Maven安装目录中的 `conf/setttings.xml`, + +在 `` 节点增加 `` ,如下所示: + +```xml + + + maven-releases + admin(账号,结合私服配置设置) + 123456(密码,结合私服配置设置) + +``` + +#### 4.3.2 配置项目 +> 注意:pom.xml里 `` 和 setting.xml 配置里 `` 对应。 + +修改 `yunzhupaas-common/yunzhupaas-dependencies/pom.xml` 文件 + +```xml + + + maven-releases + maven-releases + http://nexus.yunzhupaas.com/repository/maven-releases/ + + +``` + +#### 4.3.3 发布到私服 + +在IDEA中,双击右侧 `Maven` 中 `yunzhupaas-common` > `Lifecycle` > `deploy` 发布至私服。 + +## 五 更新版本号 + +打开 `yunzhupaas-common/yunzhupaas-dependencies/` 目录,执行如下命令 + +``` +# mvn versions:set -DnewVersion=5.2.0-RELEASE +mvn versions:set -DnewVersion=版本号 +``` diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..bdc7e5a --- /dev/null +++ b/pom.xml @@ -0,0 +1,194 @@ + + + 4.0.0 + + + com.yunzhupaas + yunzhupaas-dependencies + 5.2.0-RELEASE + yunzhupaas-dependencies/pom.xml + + + yunzhupaas-common + pom + + yunzhupaas-dependencies + yunzhupaas-boot-common + yunzhupaas-cloud-common + + + + + + + + + org.projectlombok + lombok + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + + + com.yunzhupaas + yunzhupaas-dependencies + ${project.version} + + + com.yunzhupaas + yunzhupaas-boot-common + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-auth + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-connector + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-core + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-database + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-file + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-office + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-redis + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-scheduletask + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-security + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-shardingsphere + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-sms + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-swagger + ${project.version} + + + com.yunzhupaas + yunzhupaas-cloud-common + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-dubbo + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-feign + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-seata + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-selenium + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-i18n + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-event + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-mq + ${project.version} + + + com.yunzhupaas + yunzhupaas-common-ai + ${project.version} + + + + com.yunzhupaas + yunzhupaas-scheduletask-client + ${project.version} + + + com.yunzhupaas + yunzhupaas-scheduletask-model + ${project.version} + + + com.yunzhupaas + xxl-job-core + ${project.version} + + + + + + + + boot3 + + [17,) + + + + + com.yunzhupaas + yunzhupaas-common-office-v3 + ${project.version} + + + + + + + diff --git a/yunzhupaas-boot-common/pom.xml b/yunzhupaas-boot-common/pom.xml new file mode 100644 index 0000000..6b71c8c --- /dev/null +++ b/yunzhupaas-boot-common/pom.xml @@ -0,0 +1,56 @@ + + + + yunzhupaas-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-boot-common + pom + + yunzhupaas-common-core + yunzhupaas-common-database + yunzhupaas-common-redis + yunzhupaas-common-auth + yunzhupaas-common-security + yunzhupaas-common-swagger + yunzhupaas-common-connector + yunzhupaas-common-file + yunzhupaas-common-office + yunzhupaas-common-scheduletask + yunzhupaas-common-sms + yunzhupaas-common-shardingsphere + yunzhupaas-common-selenium + yunzhupaas-common-i18n + yunzhupaas-common-event + yunzhupaas-common-ai + + + + + + + + getui-nexus + http://mvn.gt.igexin.com/nexus/content/repositories/releases/ + + + + + + boot3 + + [17,) + + + yunzhupaas-common-compatible/yunzhupaas-common-office-v3 + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-ai/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-ai/pom.xml new file mode 100644 index 0000000..d339ebb --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-ai/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + + com.yunzhupaas + yunzhupaas-boot-common + 5.2.0-RELEASE + + + yunzhupaas-common-ai + + + + com.yunzhupaas + yunzhupaas-common-core + + + com.unfbx + chatgpt-java + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/config/AiAutoConfiguration.java b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/config/AiAutoConfiguration.java new file mode 100644 index 0000000..8a1b3f0 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/config/AiAutoConfiguration.java @@ -0,0 +1,203 @@ +package com.yunzhupaas.config; + +import com.unfbx.chatgpt.OpenAiClient; +import com.unfbx.chatgpt.function.KeyRandomStrategy; +import com.unfbx.chatgpt.function.KeyStrategyFunction; +import com.unfbx.chatgpt.interceptor.DefaultOpenAiAuthInterceptor; +import com.unfbx.chatgpt.interceptor.OpenAiAuthInterceptor; +import com.yunzhupaas.constants.AiConstants; +import com.yunzhupaas.service.OpenAiService; +import com.yunzhupaas.service.impl.DefaultOpenAiServiceImpl; +import com.yunzhupaas.service.impl.DisabledOpenAiServiceImpl; +import com.yunzhupaas.util.StringUtil; +import okhttp3.Authenticator; +import okhttp3.OkHttpClient; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.Proxy; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * AI客户端 自动配置 + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/9 14:03 + */ +@Configuration(proxyBeanMethods = false) +public class AiAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(prefix = AiConstants.CONFIGURATION_PREFIX, name = "enabled", havingValue = "false", matchIfMissing = true) + public OpenAiService getDisabledOpenAiService() { + return new DisabledOpenAiServiceImpl(); + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnProperty(prefix = AiConstants.CONFIGURATION_PREFIX, name = "enabled", havingValue = "true") + public static class AiEnabledConfiguration { + + @Bean + @ConfigurationProperties(prefix = AiConstants.CONFIGURATION_PREFIX) + public AiProperties getAiProperties() { + return new AiProperties(); + } + + @Bean + public OpenAiService getDefaultOpenAiService(OpenAiClient openAiClient, AiProperties aiProperties) { + return new DefaultOpenAiServiceImpl(openAiClient, aiProperties); + } + + @Bean + @ConditionalOnMissingBean + public OpenAiClient getOpenAiClient( + @Qualifier(AiConstants.DEFAULT_HTTP_CLIENT_BEAN_NAME) OkHttpClient okHttpClient, + KeyStrategyFunction, String> keyStrategyFunction, OpenAiAuthInterceptor authInterceptor, + AiProperties aiProperties) { + String apiHost = aiProperties.getApiHost(); + // 需要以 / 结尾 + if (!apiHost.isEmpty() && !apiHost.endsWith("/")) { + apiHost += "/"; + } + // 构造openAiClient + return OpenAiClient.builder() + .apiHost(apiHost) + .apiKey(aiProperties.getApiKey()) + .keyStrategy(keyStrategyFunction) + .authInterceptor(authInterceptor) + .okHttpClient(okHttpClient) + .build(); + } + + /* + * @Bean + * + * @ConditionalOnMissingBean + * public OpenAiStreamClient + * getOpenAiStreamClient(@Qualifier(AiConstants.DEFAULT_HTTP_CLIENT_BEAN_NAME) + * OkHttpClient okHttpClient + * , KeyStrategyFunction, String> keyStrategyFunction, + * OpenAiAuthInterceptor authInterceptor, AiProperties aiProperties) { + * String apiHost = aiProperties.getApiHost(); + * // 需要以 / 结尾 + * if(!apiHost.isEmpty() && !apiHost.endsWith("/")){ + * apiHost +="/"; + * } + * // 构造openAiClient + * return OpenAiStreamClient.builder() + * .apiHost(apiHost) + * .apiKey(aiProperties.getApiKey()) + * .keyStrategy(keyStrategyFunction) + * .authInterceptor(authInterceptor) + * .okHttpClient(okHttpClient) + * .build(); + * } + */ + + /** + * 多 Key 选择策略 + */ + @Bean + @ConditionalOnMissingBean + public KeyStrategyFunction, String> getDefaultOpenAiKeyStrategyFunction() { + return new KeyRandomStrategy(); + } + + /** + * 认证拦截器 + * + * @see com.unfbx.chatgpt.interceptor.DynamicKeyOpenAiAuthInterceptor 动态移除无效Key + */ + @Bean + @ConditionalOnMissingBean + public OpenAiAuthInterceptor getDefaultOpenAiAuthInterceptor() { + return new DefaultOpenAiAuthInterceptor(); + } + + /** + * 默认okhttpclient + */ + @Bean(name = AiConstants.DEFAULT_HTTP_CLIENT_BEAN_NAME) + @ConditionalOnMissingBean(name = AiConstants.DEFAULT_HTTP_CLIENT_BEAN_NAME) + public OkHttpClient getDefaultOpenAiOkHttpClient(AiProperties aiProperties) { + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + + if (aiProperties.getProxy() != null + && StringUtil.isNotEmpty(aiProperties.getProxy().getHost()) + && aiProperties.getProxy().getPort() != null) { + // 设置代理 + builder.proxy(new Proxy(aiProperties.getProxy().getType(), + new InetSocketAddress(aiProperties.getProxy().getHost(), aiProperties.getProxy().getPort()))); + // 设置代理认证 + if (StringUtil.isNotEmpty(aiProperties.getProxy().getUsername()) + && StringUtil.isNotEmpty(aiProperties.getProxy().getPassword())) { + builder.proxyAuthenticator(Authenticator.JAVA_NET_AUTHENTICATOR); + java.net.Authenticator.setDefault(new java.net.Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + // 返回代理的用户名和密码 + return new PasswordAuthentication(aiProperties.getProxy().getUsername(), + aiProperties.getProxy().getPassword().toCharArray()); + } + }); + } + } + /* + * try { + * // 创建一个信任所有证书的 TrustManager + * final TrustManager[] trustAllCerts = new TrustManager[]{ + * new X509TrustManager() { + * + * @Override + * public void checkClientTrusted(X509Certificate[] chain, String authType) + * throws CertificateException { + * } + * + * @Override + * public void checkServerTrusted(X509Certificate[] chain, String authType) + * throws CertificateException { + * } + * + * @Override + * public X509Certificate[] getAcceptedIssuers() { + * return new X509Certificate[]{}; + * } + * } + * }; + * + * // 安装所有信任管理器 + * final SSLContext sslContext = SSLContext.getInstance("SSL"); + * sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); + * + * // 创建 OkHttpClient 并配置 SSL socket factory 和 hostname verifier + * final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + * + * // 信任所有证书 + * builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) + * trustAllCerts[0]); + * builder.hostnameVerifier((hostname, session) -> true); + * } catch (Exception e) { + * throw new RuntimeException(e); + * } + */ + + return builder + .callTimeout(aiProperties.getTimeout(), TimeUnit.SECONDS) + .connectTimeout(aiProperties.getTimeout(), TimeUnit.SECONDS) + .writeTimeout(aiProperties.getTimeout(), TimeUnit.SECONDS) + .readTimeout(aiProperties.getTimeout(), TimeUnit.SECONDS) + .build(); + } + + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/config/AiProperties.java b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/config/AiProperties.java new file mode 100644 index 0000000..83436e5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/config/AiProperties.java @@ -0,0 +1,134 @@ +package com.yunzhupaas.config; + +import com.yunzhupaas.constants.AiConstants; +import lombok.Data; + +import java.time.Duration; +import java.util.List; + +/** + * AI 配置 + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/9 14:03 + */ +@Data +public class AiProperties { + + /** + * 是否启用 + */ + private boolean enabled; + + /** + * openai服务器 + */ + private String apiHost = AiConstants.OPENAI_HOST; + + /** + * openai key + */ + private List apiKey; + + /** + * 超时时间 + */ + private Long timeout = 30L; + + /** + * 每个用户限制时间内的请求次数 + */ + private Integer userLimitCount = 1; + + /** + * 每个用户限制时间频率 + */ + private Duration userLimitTime = Duration.ofSeconds(3); + + /** + * 全部请求限制时间内的请求次数 + */ + private Integer totalLimitCount = 500; + + /** + * 全部请求限制时间频率 + */ + private Duration totalLimitTime = Duration.ofMinutes(1L); + + /** + * 代理配置 + */ + private Proxy proxy = new Proxy(); + + /** + * 对话配置 + */ + private ChatOption chat = new ChatOption(); + + + + + @Data + public class ChatOption{ + + /** + * @see AiConstants.Model + */ + private String mode = AiConstants.Model.QWEN_25_3; + + /** + * 设置seed参数会使文本生成过程更具有确定性,通常用于使模型每次运行的结果一致。 + * 在每次模型调用时传入相同的seed值(由您指定),并保持其他参数不变,模型将很可能返回相同的结果。 + */ + private Integer seed = 1234; + + /** + * 允许模型生成的最大Token数。 + */ + private Integer maxTokens = 1500; + + /** + * 核采样的概率阈值,用于控制模型生成文本的多样性。 + * top_p越高,生成的文本更多样。反之,生成的文本更确定。 + * 由于temperature与top_p均可以控制生成文本的多样性,因此建议您只设置其中一个值。 + */ + private Double topP = 0.8; + + /** + * 采样温度,用于控制模型生成文本的多样性。 + * temperature越高,生成的文本更多样,反之,生成的文本更确定。 + * 由于temperature与top_p均可以控制生成文本的多样性,因此建议您只设置其中一个值。 + */ + private Double temperature = 0.85; + + private boolean enableSearch = true; + + } + + + @Data + public class Proxy{ + /** + * HTTP, SOCKS + */ + private java.net.Proxy.Type type = java.net.Proxy.Type.HTTP; + /** + * 代理域名 + */ + private String host; + /** + * 代理端口 + */ + private Integer port; + /** + * 代理用户名 + */ + private String username; + /** + * 代理密码 + */ + private String password; + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/constants/AiConstants.java b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/constants/AiConstants.java new file mode 100644 index 0000000..195c182 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/constants/AiConstants.java @@ -0,0 +1,58 @@ +package com.yunzhupaas.constants; + +/** + * AI 常量 + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/9 14:05 + */ +public class AiConstants { + + public static final String OPENAI_HOST = "https://dashscope.aliyuncs.com/compatible-mode/"; + + public static final String CONFIGURATION_PREFIX = "spring.cloud.ai.openai"; + + public static final String DEFAULT_HTTP_CLIENT_BEAN_NAME = "defaultOpenAiHttpClient"; + + public static final String GEN_MODEL_COMPNENT = "- input - textarea - inputNumber - switch - radio - checkbox - select - datePicker - timePicker - uploadFile - uploadImg - colorPicker - rate - slider - editor - depSelect - posSelect - userSelect - roleSelect - areaSelect - signature - sign - location"; + + public static final String GEN_MODEL_QUETION = "根据当前业务需求,设计相应的表单结构。请仅返回JSON数据,不包含其他任何形式的内容。预期结果是一个JSON数组,因涉及不同表单需求,故可能包含多个表单对象。请确保命名规避数据库与编程保留字。\n" + + + "所需表单应充分利用以下组件列表进行设计: " + GEN_MODEL_COMPNENT + "。\n" + + "参考给定的JSON格式,属性包含:中文名(tableTitle)、英文名(tableName)、字段列表(fields);字段列表是一个json数组,包含字段英文名(fieldName)、字段中文名(fieldTitle)等;" + + + "创建表单结构,示例如下: [ { \"tableTitle\": \"商城订单\", \"tableName\": \"online_order_form\", \"fields\": [ {\"fieldTitle\": \"订单编号\", \"fieldName\": \"order_id\", \"fieldDbType\": \"varchar\", \"fieldComponent\": \"input\"}, {\"fieldTitle\": \"订单状态\", \"fieldName\": \"order_status\", \"fieldDbType\": \"int\", \"fieldComponent\": \"radio\", \"fieldOptions\":[{\"id\":\"1\", \"fullName\":\"未付款\"},{\"id\":\"2\", \"fullName\":\"已付款\"}]}] }, { \"tableTitle\": \"订单商品明细\", \"tableName\": \"order_item_details\", \"fields\": [ {\"fieldTitle\": \"订单ID(外键)\", \"fieldName\": \"order_id_fk\", \"fieldDbType\": \"varchar\", \"fieldComponent\": \"input\"}, {\"fieldTitle\": \"商品名称\", \"fieldName\": \"product_name\", \"fieldDbType\": \"varchar\", \"fieldComponent\": \"input\"}, {\"fieldTitle\": \"商品数量\", \"fieldName\": \"quantity\", \"fieldDbType\": \"int\", \"fieldComponent\": \"inputNumber\"}] } ]\n" + + + "请依据实际业务逻辑,合理选择组件与字段类型,确保设计的表单既能满足数据收集需求,又便于用户操作。"; + + public static final String CHAT_PRE_QUETION = "深圳市乐程软件有限公司下的低代码产品YUNZHUPAAS介绍"; + + /** + * 模型名称 + * + * @see com.unfbx.chatgpt.entity.chat.ChatCompletion.Model + * 阿里官方稳定模型列表 + */ + public static class Model { + + /** + * 通义千问系列效果最好的模型,适合复杂、多步骤的任务。 + */ + public static final String QWEN_MAX = "qwen-max"; + /** + * 通义千问系列速度最快、成本很低的模型,适合简单任务。 + */ + public static final String QWEN_TURBO = "qwen-turbo"; + /** + * 通义千问开源版, 可部署参数最高的版本, 云版本收费 + */ + public static final String QWEN_25_72 = "qwen2.5-72b-instruct"; + /** + * 通义千问开源版, 官方提供接口免费版本, 云版本限时免费 + */ + public static final String QWEN_25_3 = "qwen2.5-3b-instruct"; + + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/service/OpenAiService.java b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/service/OpenAiService.java new file mode 100644 index 0000000..fbe0c5b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/service/OpenAiService.java @@ -0,0 +1,42 @@ +package com.yunzhupaas.service; + +import com.unfbx.chatgpt.entity.chat.Message; +import com.yunzhupaas.model.ai.AiFormModel; + +import java.util.List; + + +/** + * AI服务工具 + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/9 14:38 + */ +public interface OpenAiService { + + /** + * 简单对话 + * @param prompt + */ + String completion(String prompt); + + /** + * 连续对话 + * @param messages 历史对话内容 + */ + String completion(Message... messages); + + /** + * 生成表单 + * @param businessName 业务名称 + * @return + */ + String generatorModelStr(String businessName); + + /** + * 生成表单 + * @param prompt + * @return + */ + List generatorModelVO(String prompt); +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/service/impl/DefaultOpenAiServiceImpl.java b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/service/impl/DefaultOpenAiServiceImpl.java new file mode 100644 index 0000000..64b3df0 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/service/impl/DefaultOpenAiServiceImpl.java @@ -0,0 +1,101 @@ +package com.yunzhupaas.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.unfbx.chatgpt.OpenAiClient; +import com.unfbx.chatgpt.entity.chat.ChatCompletion; +import com.unfbx.chatgpt.entity.chat.ChatCompletionResponse; +import com.unfbx.chatgpt.entity.chat.Message; +import com.yunzhupaas.config.AiProperties; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.constants.AiConstants; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.model.ai.AiFormModel; +import com.yunzhupaas.service.OpenAiService; +import com.yunzhupaas.util.StringUtil; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * OpenAi 实现类 + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/9 14:39 + */ +@Slf4j +@AllArgsConstructor +public class DefaultOpenAiServiceImpl implements OpenAiService { + + private OpenAiClient openAiClient; + private AiProperties aiProperties; + + @Override + public String completion(String prompt) { + Message sendMessage = Message.builder().role(Message.Role.USER).content(prompt).build(); + ChatCompletion chatCompletion; + if (StringUtil.isNotEmpty(prompt) && prompt.toLowerCase().contains("com.yunzhupaas")) { + Message sysMessage = Message.builder().role(Message.Role.SYSTEM).content(AiConstants.CHAT_PRE_QUETION).build(); + chatCompletion = getDefaultChatComletion(sysMessage, sendMessage); + } else { + chatCompletion = getDefaultChatComletion(sendMessage); + } + ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion); + return chatCompletionResponse.getChoices().stream().map(chatChoice -> chatChoice.getMessage().getContent()).collect(Collectors.joining()); + } + + @Override + public String generatorModelStr(String businessName) { + Message sysMessage = Message.builder().role(Message.Role.SYSTEM).content(AiConstants.GEN_MODEL_QUETION).build(); + String userTemplate = "当前业务需求是:"; + Message sendMessage = Message.builder().role(Message.Role.USER).content(userTemplate + businessName).build(); + + ChatCompletion chatCompletion = getDefaultChatComletion(sysMessage, sendMessage); + ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion); + return chatCompletionResponse.getChoices().stream().map(chatChoice -> chatChoice.getMessage().getContent()).collect(Collectors.joining()); + } + + @Override + public List generatorModelVO(String prompt) { + String result = ""; + List aiFormModels; + try { + result = generatorModelStr(prompt); + int startIndex = result.indexOf("["); + int endIndex = result.lastIndexOf("]"); + if (startIndex != -1 && endIndex != -1 && startIndex < endIndex) { + result = result.substring(startIndex, endIndex + 1).trim(); + } + aiFormModels = JSON.parseObject(result, new TypeReference>() { + }); + } catch (Exception e) { + log.error("AI表单生成转换失败: {}, {}", result, e.getMessage()); + throw new DataException(MsgCode.SYS181.get()); + } + return aiFormModels; + } + + @Override + public String completion(Message... messages) { + ChatCompletion chatCompletion = getDefaultChatComletion(messages); + ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion); + return chatCompletionResponse.getChoices().stream().map(chatChoice -> chatChoice.getMessage().getContent()).collect(Collectors.joining()); + } + + private ChatCompletion getDefaultChatComletion(Message... messages) { + AiProperties.ChatOption chatOption = aiProperties.getChat(); + return ChatCompletion.builder() + .model(chatOption.getMode()) + .temperature(chatOption.getTemperature()) + .topP(chatOption.getTopP()) + .seed(chatOption.getSeed()) + .maxTokens(chatOption.getMaxTokens()) + .messages(Arrays.asList(messages)).build(); + } + + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/service/impl/DisabledOpenAiServiceImpl.java b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/service/impl/DisabledOpenAiServiceImpl.java new file mode 100644 index 0000000..0969fb2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/service/impl/DisabledOpenAiServiceImpl.java @@ -0,0 +1,41 @@ +package com.yunzhupaas.service.impl; + +import com.unfbx.chatgpt.entity.chat.Message; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.model.ai.AiFormModel; +import com.yunzhupaas.service.OpenAiService; + +import java.util.List; + +/** + * 未启用是空实现 + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/15 17:00 + */ +public class DisabledOpenAiServiceImpl implements OpenAiService { + @Override + public String completion(String prompt) { + return throwError(); + } + + @Override + public String completion(Message... messages) { + return throwError(); + } + + @Override + public String generatorModelStr(String businessName) { + return throwError(); + } + + @Override + public List generatorModelVO(String prompt) { + return throwError(); + } + + public T throwError(){ + throw new DataException(MsgCode.SYS180.get()); + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/util/AiLimitUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/util/AiLimitUtil.java new file mode 100644 index 0000000..47d0b74 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-ai/src/main/java/com/yunzhupaas/util/AiLimitUtil.java @@ -0,0 +1,51 @@ +package com.yunzhupaas.util; + +import cn.hutool.cache.CacheUtil; +import cn.hutool.cache.impl.TimedCache; +import com.yunzhupaas.config.AiProperties; + +import java.util.concurrent.atomic.AtomicInteger; + + +/** + * AI接口限流 + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + * @date 2025/3/7 10:00 + */ +public class AiLimitUtil { + + private static AiProperties aiProperties; + + private static TimedCache limit = null; + + private static final String TOTAL_KEY = "ai_limit_total"; + + public AiLimitUtil(AiProperties aiProperties) { + AiLimitUtil.aiProperties = aiProperties; + if (limit == null) { + limit = CacheUtil.newTimedCache(aiProperties.getUserLimitTime().toMillis()); + // 一分钟清理一次无用数据 + limit.schedulePrune(1000L * 60); + } + } + + /** + * 是否可以请求 + * @param userId + * @return + */ + public static boolean tryAcquire(String userId) { + if (StringUtil.isNotEmpty(userId)) { + // 按用户限制 + AtomicInteger userCount = limit.get(userId, false, AtomicInteger::new); + if (userCount.incrementAndGet() > aiProperties.getUserLimitCount()) { + return false; + } + } + // 所有请求限制 + AtomicInteger totalCount = limit.get(TOTAL_KEY, false, aiProperties.getTotalLimitTime().toMillis(), AtomicInteger::new); + return totalCount.incrementAndGet() <= aiProperties.getTotalLimitCount(); + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-auth/pom.xml new file mode 100644 index 0000000..ec82a19 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/pom.xml @@ -0,0 +1,71 @@ + + + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-auth + + + + com.yunzhupaas + yunzhupaas-common-redis + + + + cn.dev33 + sa-token-jwt + + + cn.hutool + hutool-jwt + + + + + cn.dev33 + sa-token-redis-jackson + + + + + + + + boot3 + + [17,) + + + + cn.dev33 + sa-token-spring-boot3-starter + + + + + boot2 + + (,17) + + + + cn.dev33 + sa-token-spring-boot-starter + + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/AsyncConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/AsyncConfig.java new file mode 100644 index 0000000..ef28516 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/AsyncConfig.java @@ -0,0 +1,149 @@ +package com.yunzhupaas.config; + +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.model.tenant.TenantVO; +import com.yunzhupaas.util.TenantHolder; +import com.yunzhupaas.util.UserProvider; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 提供一个全局的Spring线程池对象 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-12-10 + */ +@Slf4j +@Configuration +@EnableAsync(proxyTargetClass = true) +@AllArgsConstructor +public class AsyncConfig implements AsyncConfigurer { + + +// private final Map asyncTaskCount = new HashMap<>(); + + + + @Primary + @Bean("threadPoolTaskExecutor") + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + // 设置线程池核心容量 + executor.setCorePoolSize(10); + // 设置线程池最大容量 + executor.setMaxPoolSize(50); + // 设置任务队列长度 + executor.setQueueCapacity(2000); + // 设置线程超时时间 + executor.setKeepAliveSeconds(30); + // 设置线程名称前缀 + executor.setThreadNamePrefix("sysTaskExecutor"); + // 设置任务丢弃后的处理策略 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.setTaskDecorator( r ->{ + //实现线程上下文穿透, 异步线程内无法获取之前的Request,租户信息等, 如有新的上下文对象在此处添加 + //此方法在请求结束后在无法获取request, 下方完整异步Servlet请求 +// RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); + TenantVO tenantVO = TenantHolder.getLocalTenantCache(); + UserInfo userInfo = UserProvider.getUser(); + return () -> { + try { +// if(attributes!= null) { +// RequestContextHolder.setRequestAttributes(attributes); +// } + if(tenantVO != null){ + TenantHolder.setLocalTenantCache(tenantVO); + } + UserProvider.setLocalLoginUser(userInfo); + r.run(); + } finally { + UserProvider.clearLocalUser(); + RequestContextHolder.resetRequestAttributes(); + TenantHolder.clearLocalTenantCache(); + } + }; + }); + + /* + //Tomcat异步Servlet只能增加吞吐量, 不能减少响应时间 + executor.setTaskDecorator( r ->{ + //实现线程上下文穿透, 异步线程内无法获取之前的Request,租户信息等, 如有新的上下文对象在此处添加 + RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); + String dataSourceId = DataSourceContextHolder.getDatasourceId(); + String dataSourceName = DataSourceContextHolder.getDatasourceName(); + final AsyncContext asyncContext = (AsyncContext) Optional.ofNullable(null).orElseGet(()->{ + if(attributes!= null) { + HttpServletRequest request = ((ServletRequestAttributes) attributes).getRequest(); + HttpServletResponse response = ((ServletRequestAttributes) attributes).getResponse(); + synchronized (AsyncConfig.class) { + //开启多个异步 + AsyncContext tmpAsyncContext = request.isAsyncStarted() ? request.getAsyncContext() : request.startAsync(request, response); + asyncTaskCount.put(tmpAsyncContext, asyncTaskCount.getOrDefault(tmpAsyncContext, 0) +1); + return tmpAsyncContext; + } + } + return null; + }); + return () -> { + if (asyncContext != null) { + asyncContext.start(() -> { + if (dataSourceId != null || dataSourceName != null) { + DataSourceContextHolder.setDatasource(dataSourceId, dataSourceName); + } + RequestContextHolder.setRequestAttributes(attributes); + try { + r.run(); + }finally{ + synchronized (AsyncConfig.class){ + //多个异步 最后一个执行关闭 + int count = asyncTaskCount.get(asyncContext)-1; + if(count > 0){ + asyncTaskCount.put(asyncContext, count); + }else{ + asyncTaskCount.remove(asyncContext); + asyncContext.complete(); + } + } + RequestContextHolder.resetRequestAttributes(); + DataSourceContextHolder.clearDatasourceType(); + } + }); + } else { + if (dataSourceId != null || dataSourceName != null) { + DataSourceContextHolder.setDatasource(dataSourceId, dataSourceName); + } + try { + r.run(); + }finally{ + DataSourceContextHolder.clearDatasourceType(); + } + } + }; + }); + */ + return executor; + } + + + @Bean("defaultExecutor") + public ThreadPoolTaskExecutor getAsyncExecutorDef(@Qualifier("threadPoolTaskExecutor") Executor executor) { + return (ThreadPoolTaskExecutor) executor; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/AuthAutoConfigration.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/AuthAutoConfigration.java new file mode 100644 index 0000000..4c95b3b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/AuthAutoConfigration.java @@ -0,0 +1,45 @@ +package com.yunzhupaas.config; + +import cn.dev33.satoken.config.SaTokenConfig; +import cn.dev33.satoken.jwt.StpLogicJwtForSimple; +import cn.dev33.satoken.stp.StpLogic; +import com.yunzhupaas.consts.AuthConsts; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +/** + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +@Configuration +public class AuthAutoConfigration { + + @Primary + @Bean + @ConfigurationProperties(prefix = "oauth.login") + public SaTokenConfig getYunzhupaasTokenConfig() { + return new YunzhupaasTokenConfig(); + } + + @Bean + @ConditionalOnMissingBean + @ConfigurationProperties(prefix = YunzhupaasOauthConfig.PREFIX) + public YunzhupaasOauthConfig getYunzhupaasOauthConfig() { + return new YunzhupaasOauthConfig(); + } + + @Primary + @Bean(AuthConsts.ACCOUNT_LOGIC_BEAN_DEFAULT) + public StpLogic getYunzhupaasTokenJwtLogic() { + return new StpLogicJwtForSimple(AuthConsts.ACCOUNT_TYPE_DEFAULT); + } + + @Bean(AuthConsts.ACCOUNT_LOGIC_BEAN_TENANT) + public StpLogic getYunzhupaasTenantTokenJwtLogic() { + return new StpLogicJwtForSimple(AuthConsts.ACCOUNT_TYPE_TENANT); + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/YunzhupaasOauthConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/YunzhupaasOauthConfig.java new file mode 100644 index 0000000..2d92959 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/YunzhupaasOauthConfig.java @@ -0,0 +1,63 @@ +package com.yunzhupaas.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; + +/** + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +@Data +public class YunzhupaasOauthConfig { + + public static final String PREFIX = "oauth"; + + /** + * 服务器域名 + * + * @see ConfigValueUtil#getApiDomain() + */ + @Deprecated + @Value("${config.ApiDomain:}") + private String yunzhupaasDomain; + + /** + * 开启单点登录, 需额外代码支持 + */ + private Boolean ssoEnabled = false; + + /** + * 后端登录完整路径路径 + */ + private String loginPath; + + /** + * 默认发起的登录协议 + */ + private String defaultSSO = "cas"; + + /** + * 轮询Ticket有效期, 秒 + */ + private long ticketTimeout = 60; + + /** + * pc端服务器域名 + * + * @see ConfigValueUtil#getFrontDomain() + */ + @Deprecated + @Value("${config.FrontDomain:}") + private String yunzhupaasFrontDomain; + + /** + * app端服务器域名 + * + * @see ConfigValueUtil#getAppDomain() + */ + @Deprecated + @Value("${config.AppDomain:}") + private String yunzhupaasAppDomain; + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/YunzhupaasTokenConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/YunzhupaasTokenConfig.java new file mode 100644 index 0000000..f155200 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/config/YunzhupaasTokenConfig.java @@ -0,0 +1,101 @@ +package com.yunzhupaas.config; + +import cn.dev33.satoken.config.SaTokenConfig; +import com.yunzhupaas.consts.AuthConsts; +import com.yunzhupaas.model.BaseSystemInfo; +import com.yunzhupaas.util.Constants; +import com.yunzhupaas.util.TenantProvider; + +import java.util.Optional; + +/** + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +public class YunzhupaasTokenConfig extends SaTokenConfig { + + @Override + public long getTimeout() { + BaseSystemInfo baseSystemInfo = getSycConfig(); + if (baseSystemInfo == null) { + return super.getTimeout(); + } else { + return Long.parseLong(getSycConfig().getTokenTimeout()) * 60L; + } + } + + @Override + public Boolean getIsConcurrent() { + BaseSystemInfo baseSystemInfo = getSycConfig(); + if (baseSystemInfo == null) { + return super.getIsConcurrent(); + } else { + return Optional.ofNullable(getSycConfig().getSingleLogin()).orElse(1) == 2; + } + } + + @Override + public String getJwtSecretKey() { + String secrekey = super.getJwtSecretKey(); + if (secrekey == null) { + return AuthConsts.JWT_SECRET; + } + return secrekey; + } + + @Override + public String getCurrDomain() { + return super.getCurrDomain(); + } + + @Override + public String getTokenPrefix() { + return AuthConsts.TOKEN_PREFIX; + } + + @Override + public Boolean getTokenSessionCheckLogin() { + return false; + } + + @Override + public Boolean getIsPrint() { + return false; + } + + @Override + public Boolean getIsShare() { + return false; + } + + @Override + public String getTokenName() { + return Constants.AUTHORIZATION; + } + + @Override + public Boolean getIsReadCookie() { + return false; + } + + @Override + public Boolean getIsReadBody() { + return false; + } + + @Override + public Boolean getIsReadHeader() { + return true; + } + + @Override + public int getMaxLoginCount() { + return -1; + } + + private BaseSystemInfo getSycConfig() { + return TenantProvider.getBaseSystemInfo(); + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/AuthConsts.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/AuthConsts.java new file mode 100644 index 0000000..0426d91 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/AuthConsts.java @@ -0,0 +1,81 @@ +package com.yunzhupaas.consts; + +import cn.dev33.satoken.same.SaSameUtil; +import com.yunzhupaas.service.UserDetailService; + +/** + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +public class AuthConsts { + + public static final String DEF_TENANT_ID = ""; + public static final String DEF_TENANT_DB = ""; + + public static final String ACCOUNT_TYPE_DEFAULT = "login"; + public static final String ACCOUNT_TYPE_TENANT = "tenant"; + public static final String ACCOUNT_LOGIC_BEAN_DEFAULT = "defaultStpLogic"; + public static final String ACCOUNT_LOGIC_BEAN_TENANT = "tenantStpLogic"; + + public static final String PAR_GRANT_TYPE = "grant_type"; + + public static final String SYSTEM_INFO = "system_info"; + + /** + * 跨服务调用验证KEY + */ + public static final String INNER_TOKEN_KEY = SaSameUtil.SAME_TOKEN; + + /** + * 网关调用验证KEY + */ + public static final String INNER_GATEWAY_TOKEN_KEY = INNER_TOKEN_KEY + "_GATEWAY"; + + public static final String TENANT_SESSION = "tenant:"; + + public static final String TOKEN_PREFIX = "bearer"; + public static final String TOKEN_PREFIX_SP = TOKEN_PREFIX + " "; + + public static final String PARAMS_YUNZHUPAAS_TICKET = "yunzhupaas_ticket"; + public static final String PARAMS_SSO_LOGOUT_TICKET = "ticket"; + + public static final Integer REDIRECT_PAGETYPE_LOGIN = 1; + public static final Integer REDIRECT_PAGETYPE_LOGOUT = 2; + + public static final Integer TMP_TOKEN_UNLOGIN = -1; + public static final Integer TMP_TOKEN_ERRLOGIN = -2; + + public static final String ONLINE_TICKET_KEY = "online_ticket:"; + public static final String ONLINE_TICKET_TOKEN = "online_token"; + + public static final String JWT_SECRET = "WviMjFNC72VKwGqm5LPoheQo5XN9iN4d"; + + /** + * clientId + */ + public static final String Client_Id = "Client_Id"; + + /** + * 用户信息获取方式 account + */ + public static final String USERDETAIL_ACCOUNT = UserDetailService.USER_DETAIL_PREFIX + "UserAccount"; + /** + * 用户信息获取方式 user_id + */ + public static final String USERDETAIL_USER_ID = UserDetailService.USER_DETAIL_PREFIX + "UserId"; + + /** + * 认证方式 常规账号密码 + */ + public static final String GRANT_TYPE_PASSWORD = "password"; + /** + * 认证方式 单点 CAS + */ + public static final String GRANT_TYPE_CAS = "cas"; + /** + * 认证方式 单点 OAUTH + */ + public static final String GRANT_TYPE_OAUTH = "auth2"; + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/DeviceType.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/DeviceType.java new file mode 100644 index 0000000..6bd90d5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/DeviceType.java @@ -0,0 +1,41 @@ +package com.yunzhupaas.consts; + +import lombok.AllArgsConstructor; +import lombok.Getter; + + +/** + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +@Getter +@AllArgsConstructor +public enum DeviceType { + + /** + * pc端 + */ + PC("PC"), + + /** + * app端 手机都归为移动 自行扩展 + */ + APP("APP"), + + /** + * 程序运行中使用的无限制临时用户 + */ + TEMPUSER("TEMPUSER"), + + + /** + * 程序运行中使用的限制临时用户, 不可访问主系统, CurrentUser接口报错 + */ + TEMPUSERLIMITED("TEMPUSERLIMITED"); + + + private final String device; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/LoginTicketStatus.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/LoginTicketStatus.java new file mode 100644 index 0000000..1b9fcc1 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/LoginTicketStatus.java @@ -0,0 +1,47 @@ +package com.yunzhupaas.consts; + +import lombok.AllArgsConstructor; +import lombok.Getter; + + +/** + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +@Getter +@AllArgsConstructor +public enum LoginTicketStatus { + + /** + * 登录成功 + */ + Success(1), + /** + * 未登录 + */ + UnLogin(2), + /** + * 登录失败 + */ + ErrLogin(3), + /** + * 未绑定 + */ + UnBind(4), + /** + * 失效 + */ + Invalid(5), + /** + * 多租户 + */ + Multitenancy(6), + /** + * 第三方账号未绑定账号,请绑定后重试 + */ + UnBindMes(7),; + + private int status; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/ScanCodeTicketStatus.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/ScanCodeTicketStatus.java new file mode 100644 index 0000000..8155e7f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/consts/ScanCodeTicketStatus.java @@ -0,0 +1,30 @@ +package com.yunzhupaas.consts; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum ScanCodeTicketStatus { + + /** + * 已失效 + */ + Invalid(-1), + /** + * 未扫码 + */ + UnScanCode(0), + /** + * 已扫码 + */ + ScanCode(1), + /** + * 登录成功 + */ + Success(2); + + + private int status; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/AbstractTokenGranter.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/AbstractTokenGranter.java new file mode 100644 index 0000000..86bcb11 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/AbstractTokenGranter.java @@ -0,0 +1,292 @@ +package com.yunzhupaas.granter; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import com.yunzhupaas.base.ActionResult; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.config.ConfigValueUtil; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.consts.AuthConsts; +import com.yunzhupaas.consts.DeviceType; +import com.yunzhupaas.consts.LoginTicketStatus; +import com.yunzhupaas.exception.LoginException; +import com.yunzhupaas.exception.TenantDatabaseException; +import com.yunzhupaas.model.BaseSystemInfo; +import com.yunzhupaas.model.LoginTicketModel; +import com.yunzhupaas.model.logout.LogoutResultModel; +import com.yunzhupaas.model.tenant.TenantVO; +import com.yunzhupaas.service.LoginService; +import com.yunzhupaas.util.RedisUtil; +import com.yunzhupaas.util.TenantProvider; +import com.yunzhupaas.util.TicketUtil; +import com.yunzhupaas.util.UserProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.Ordered; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; + +import java.util.HashMap; +import java.util.Map; + +import static com.yunzhupaas.consts.AuthConsts.DEF_TENANT_DB; +import static com.yunzhupaas.consts.AuthConsts.DEF_TENANT_ID; + +/** + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +public abstract class AbstractTokenGranter implements TokenGranter, Ordered { + + @Autowired(required = false) + protected LoginService loginService; + @Autowired + protected UserProvider userProvider; + @Autowired + protected ConfigValueUtil configValueUtil; + @Autowired + protected RedisUtil redisUtil; + + protected static PathMatcher pathMatcher = new AntPathMatcher(); + + private String authenticationUrl; + + public AbstractTokenGranter(String authenticationUrl) { + this.authenticationUrl = authenticationUrl; + } + + /** + * 最终登录用户 + * + * @param userInfo 包含账户名, 登录方式 + * @return + */ + protected String loginAccount(UserInfo userInfo, BaseSystemInfo baseSystemInfo) throws LoginException { + try { + // 获取用户实现类接口名称 + userInfo.setUserDetailKey(getUserDetailKey()); + // 获取登录信息 + userInfo = getUserInfo(userInfo, baseSystemInfo); + // 预登陆 + preLogin(userInfo, baseSystemInfo); + // 登录 + login(userInfo, baseSystemInfo); + } catch (Exception e) { + try { + loginFailure(userInfo, baseSystemInfo, e); + } catch (Exception e1) { + throw e1; + } + throw e; + } + loginSuccess(userInfo, baseSystemInfo); + // 返回token信息 + return userInfo.getToken(); + } + + /** + * 切换多租户 + * + * @param userInfo + * @return userAccount, tenantId, tenandDb + * @throws LoginException + */ + protected UserInfo switchTenant(UserInfo userInfo) throws LoginException { + if (configValueUtil.isMultiTenancy()) { + userInfo = loginService.getTenantAccount(userInfo); + return userInfo; + + } + userInfo.setTenantId(DEF_TENANT_ID); + userInfo.setTenantDbConnectionString(DEF_TENANT_DB); + userInfo.setTenantDbType(TenantVO.NONE); + return userInfo; + } + + /** + * 获取系统配置 + * + * @param userInfo + * @return + */ + protected BaseSystemInfo getSysconfig(UserInfo userInfo) throws LoginException { + BaseSystemInfo baseSystemInfo = loginService.getBaseSystemConfig(userInfo.getTenantId()); + if (baseSystemInfo != null && baseSystemInfo.getSingleLogin() != null) { + TenantProvider.setBaseSystemInfo(baseSystemInfo); + } else { + throw new TenantDatabaseException().setLogMsg(MsgCode.LOG110.get()); + } + return baseSystemInfo; + } + + /** + * 获取登录设备 + * + * @return + */ + protected DeviceType getDeviceType() { + return UserProvider.getDeviceForAgent(); + } + + /** + * 生成登录用户信息 + * + * @param userInfo + * @return + */ + protected UserInfo getUserInfo(UserInfo userInfo, BaseSystemInfo sysConfigInfo) throws LoginException { + userInfo.setGrantType(getGrantType()); + userInfo = loginService.userInfo(userInfo, sysConfigInfo); + return userInfo; + } + + /** + * 登录前执行 + * + * @param userInfo + * @param baseSystemInfo + */ + protected void preLogin(UserInfo userInfo, BaseSystemInfo baseSystemInfo) throws LoginException { + + } + + /** + * 登录操作 + * + * @param userInfo + * @param baseSystemInfo + */ + protected void login(UserInfo userInfo, BaseSystemInfo baseSystemInfo) throws LoginException { + UserProvider.login(userInfo, getLoginModel(userInfo, baseSystemInfo)); + } + + /** + * 登录成功触发 + * + * @param userInfo + * @param baseSystemInfo + */ + protected void loginSuccess(UserInfo userInfo, BaseSystemInfo baseSystemInfo) { + + } + + /** + * 登录失败触发 + * + * @param baseSystemInfo + */ + protected void loginFailure(UserInfo userInfo, BaseSystemInfo baseSystemInfo, Exception e) { + + } + + protected abstract String getUserDetailKey(); + + protected String createToken(UserInfo userInfo, BaseSystemInfo baseSystemInfo) { + // 登录 + UserProvider.login(userInfo, getLoginModel(userInfo, baseSystemInfo)); + return StpUtil.getTokenValueNotCut(); + } + + /** + * 更新轮询结果为成功 + */ + protected void updateTicketSuccess(UserInfo userInfo) { + String ticket = getYunzhupaasTicket(); + if (!ticket.isEmpty()) { + LoginTicketModel loginTicketModel = new LoginTicketModel() + .setStatus(LoginTicketStatus.Success.getStatus()) + .setValue(StpUtil.getTokenValueNotCut()) + .setTheme(userInfo.getTheme()); + TicketUtil.updateTicket(ticket, loginTicketModel, null); + } + } + + /** + * 更新轮询结果为失败 + */ + protected void updateTicketError(String msg) { + String ticket = getYunzhupaasTicket(); + if (!ticket.isEmpty()) { + LoginTicketModel loginTicketModel = new LoginTicketModel() + .setStatus(LoginTicketStatus.ErrLogin.getStatus()) + .setValue(msg); + TicketUtil.updateTicket(ticket, loginTicketModel, null); + } + } + + /** + * 获取轮询ticket + * + * @return + */ + protected String getYunzhupaasTicket() { + return SaHolder.getRequest().getParam(AuthConsts.PARAMS_YUNZHUPAAS_TICKET, ""); + } + + protected boolean isValidYunzhupaasTicket() { + String yunzhupaasTicket = getYunzhupaasTicket(); + if (!yunzhupaasTicket.isEmpty()) { + LoginTicketModel loginTicketModel = TicketUtil.parseTicket(yunzhupaasTicket); + if (loginTicketModel == null) { + return false; + } + } + return true; + } + + /** + * 获取登录参数 + * + * @param userInfo + * @param baseSystemInfo + * @return + */ + protected SaLoginModel getLoginModel(UserInfo userInfo, BaseSystemInfo baseSystemInfo) { + SaLoginModel loginModel = new SaLoginModel(); + loginModel.setTimeout(userInfo.getTokenTimeout() * 60L); + loginModel.setExtraData(getTokenExtraData(userInfo, baseSystemInfo)); + if (userInfo.getLoginDevice() == null) { + loginModel.setDevice(getDeviceType().getDevice()); + userInfo.setLoginDevice(loginModel.device); + } else { + loginModel.setDevice(userInfo.getLoginDevice()); + } + return loginModel; + } + + /** + * 获取额外的JWT内容 + * + * @param userInfo + * @param baseSystemInfo + * @return + */ + protected Map getTokenExtraData(UserInfo userInfo, BaseSystemInfo baseSystemInfo) { + Map tokenInfo = new HashMap<>(); + // tokenInfo.put("token", StpUtil.getTokenValue()); + tokenInfo.put("singleLogin", baseSystemInfo == null ? null : baseSystemInfo.getSingleLogin()); + tokenInfo.put("user_name", userInfo.getUserAccount()); + tokenInfo.put("user_id", userInfo.getUserId()); + tokenInfo.put("exp", userInfo.getOverdueTime().getTime()); + tokenInfo.put("token", userInfo.getId()); + return tokenInfo; + } + + @Override + public ActionResult logout() { + UserProvider.logout(); + return ActionResult.success(); + } + + protected abstract String getGrantType(); + + @Override + public boolean requiresAuthentication() { + String path = SaHolder.getRequest().getRequestPath(); + if (path != null && path.startsWith("/api/oauth")) { + path = path.replace("/api/oauth", ""); + } + return pathMatcher.match(authenticationUrl, path); + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/TokenGranter.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/TokenGranter.java new file mode 100644 index 0000000..6e3e5d4 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/TokenGranter.java @@ -0,0 +1,25 @@ +package com.yunzhupaas.granter; + +import com.yunzhupaas.base.ActionResult; +import com.yunzhupaas.exception.LoginException; +import com.yunzhupaas.model.logout.LogoutResultModel; + +import java.util.Map; + + +/** + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +public interface TokenGranter { + + ActionResult granter(Map loginParameters) throws LoginException; + + + ActionResult logout(); + + boolean requiresAuthentication(); + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/TokenGranterBuilder.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/TokenGranterBuilder.java new file mode 100644 index 0000000..0d8c48c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/TokenGranterBuilder.java @@ -0,0 +1,82 @@ +package com.yunzhupaas.granter; + +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.config.YunzhupaasOauthConfig; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.consts.AuthConsts; +import com.yunzhupaas.exception.LoginException; +import com.yunzhupaas.util.UserProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +@Component +public class TokenGranterBuilder { + + @Autowired + private UserProvider userProvider; + @Autowired + private YunzhupaasOauthConfig oauthConfig; + + private final Map granterPool = new ConcurrentHashMap<>(); + + public TokenGranterBuilder(Map granterPool) { + granterPool.forEach(this.granterPool::put); + } + + /** + * 获取TokenGranter + * + * @param grantType 授权类型 + * @return ITokenGranter + */ + public TokenGranter getGranter(String grantType) throws LoginException { + TokenGranter tokenGranter = null; + if (!oauthConfig.getSsoEnabled()) { + tokenGranter = granterPool.get(grantType); + } + if (tokenGranter == null) { + // URL匹配 + for (TokenGranter value : granterPool.values()) { + if (value.requiresAuthentication()) { + tokenGranter = value; + break; + } + } + } + if (tokenGranter == null) { + if (oauthConfig.getSsoEnabled()) { + throw new LoginException(MsgCode.LOG111.get()); + } else { + throw new LoginException(MsgCode.LOG112.get()); + } + } + return tokenGranter; + } + + /** + * 获取当前登录用户的TokenGranter + * + * @return + * @throws LoginException + */ + public TokenGranter getGranterByLogin(String grandType) { + if (grandType == null || grandType.isEmpty()) { + UserInfo userInfo = userProvider.get(); + if (userInfo.getGrantType() != null) { + grandType = userInfo.getGrantType(); + } else { + grandType = AuthConsts.GRANT_TYPE_PASSWORD; + } + } + return granterPool.get(grandType); + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/UserDetailsServiceBuilder.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/UserDetailsServiceBuilder.java new file mode 100644 index 0000000..72814fb --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/granter/UserDetailsServiceBuilder.java @@ -0,0 +1,39 @@ +package com.yunzhupaas.granter; + +import com.yunzhupaas.consts.AuthConsts; +import com.yunzhupaas.service.UserDetailService; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +@Component +public class UserDetailsServiceBuilder { + + + private final Map userDetailServices = new ConcurrentHashMap<>(); + + public UserDetailsServiceBuilder(Map userDetailServices) { + userDetailServices.forEach(this.userDetailServices::put); + } + + + /** + * 根据类型获取合适的UserDetailService + * @param detailType + * @return + */ + public UserDetailService getUserDetailService(String detailType){ + if(detailType == null){ + detailType = AuthConsts.USERDETAIL_ACCOUNT; + } + return userDetailServices.get(detailType); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/model/LoginTicketModel.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/model/LoginTicketModel.java new file mode 100644 index 0000000..3d84c74 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/model/LoginTicketModel.java @@ -0,0 +1,38 @@ +package com.yunzhupaas.model; + +import com.yunzhupaas.consts.LoginTicketStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NonNull; +import lombok.experimental.Accessors; + +/** + * 轮询登录模型 + */ +@Data +@Accessors(chain = true) +public class LoginTicketModel { + + /** + * 状态 + * @see LoginTicketStatus + */ + @NonNull + private int status = LoginTicketStatus.UnLogin.getStatus(); + + /** + * 额外的值, 登录Token、第三方登录的ID + */ + private String value; + + /** + * 前端主题 + */ + private String theme; + /** + * 票据有效期, 时间戳 + */ + private Long ticketTimeout; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/model/ScanCodeLoginConfigModel.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/model/ScanCodeLoginConfigModel.java new file mode 100644 index 0000000..079f0d4 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/model/ScanCodeLoginConfigModel.java @@ -0,0 +1,26 @@ +package com.yunzhupaas.model; + +import com.yunzhupaas.consts.ScanCodeTicketStatus; +import lombok.Data; +import lombok.NonNull; + +@Data +public class ScanCodeLoginConfigModel { + + /** + * 状态 + * @see ScanCodeTicketStatus + */ + @NonNull + private int status = ScanCodeTicketStatus.UnScanCode.getStatus(); + + /** + * 额外的值, 登录Token、第三方登录的ID + */ + private String value; + /** + * 票据有效期, 时间戳 + */ + private Long ticketTimeout; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/service/LoginService.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/service/LoginService.java new file mode 100644 index 0000000..5dd4afc --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/service/LoginService.java @@ -0,0 +1,62 @@ +package com.yunzhupaas.service; + +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.exception.LoginException; +import com.yunzhupaas.model.BaseSystemInfo; +import com.yunzhupaas.model.login.PcUserVO; + +/** + * 登陆业务层 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-23 + */ +public interface LoginService { + + /** + * 租戶登录验证 + * + * @param userInfo + * @return userAccount, tenantId, tenandDb + * @throws LoginException + */ + UserInfo getTenantAccount(UserInfo userInfo) throws LoginException; + + /** + * 生成用户登录信息 + * @param userInfo 账户信息 + * @param sysConfigInfo 系统配置 + * @return + * @throws LoginException + */ + UserInfo userInfo(UserInfo userInfo, BaseSystemInfo sysConfigInfo) throws LoginException; + + /** + * 获取用户登陆信息 + * + * @return + */ + PcUserVO getCurrentUser(String type, String systemCode); + + /** + * 修改密码信息发送 + * + * @return + */ + void updatePasswordMessage(); + + /** + * + * @param tenantId + * @param tenantDb + * @param isAssignDataSource 是否租户指定数据源 + * @return + */ + BaseSystemInfo getBaseSystemConfig(String tenantId); + + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/service/UserDetailService.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/service/UserDetailService.java new file mode 100644 index 0000000..bd05239 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/service/UserDetailService.java @@ -0,0 +1,20 @@ +package com.yunzhupaas.service; + +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.exception.LoginException; +import org.springframework.core.Ordered; + +public interface UserDetailService extends Ordered { + + static final String USER_DETAIL_PREFIX = "USERDETAIL_"; + + /** + * 获取用户信息 + * @param userInfo + * @return UserEntity + * @param + */ + T loadUserEntity(UserInfo userInfo) throws LoginException; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/util/TenantProvider.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/util/TenantProvider.java new file mode 100644 index 0000000..d01b861 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/util/TenantProvider.java @@ -0,0 +1,122 @@ +package com.yunzhupaas.util; + +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.session.SaSessionCustomUtil; +import com.yunzhupaas.model.BaseSystemInfo; +import lombok.extern.slf4j.Slf4j; + +import static com.yunzhupaas.consts.AuthConsts.DEF_TENANT_ID; +import static com.yunzhupaas.consts.AuthConsts.TENANT_SESSION; + + +/** + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +@Slf4j +public class TenantProvider { + + + private static final long tenantTimeout = 60 * 60 * 24 * 30L; + + /** + * 获取租户Redis存储对象 + * + * @param tenantId + * @return + */ + public static SaSession getTenantSession(String tenantId) { + if (tenantId == null) { +// tenantId = TenantHolder.getDatasourceId(); +// if (tenantId == null) { + tenantId = DEF_TENANT_ID; +// } + } + SaSession saSession = SaSessionCustomUtil.getSessionById(TENANT_SESSION + tenantId); + if (saSession != null && !saSession.get("init", false)) { + saSession.set("init", true); + saSession.updateTimeout(tenantTimeout); + } + return saSession; + } + + /** + * 存入租户缓存空间 + * + * @param tenantId + * @param key + * @param value + */ + public static void putTenantCache(String tenantId, String key, Object value) { + SaSession saSession = getTenantSession(tenantId); + if (saSession != null) { + saSession.set(key, value).updateTimeout(tenantTimeout); + } + } + + /** + * 获取租户缓存数据 + * + * @param tenantId + * @param key + * @param + * @return + */ + public static T getTenantCache(String tenantId, String key) { + SaSession saSession = getTenantSession(tenantId); + if (saSession != null) { + return (T) saSession.get(key); + } + return null; + } + + /** + * 删除租户缓存数据 + * + * @param tenantId + * @param key + */ + public static void delTenantCache(String tenantId, String key) { + SaSession saSession = getTenantSession(tenantId); + if (saSession != null) { + saSession.delete(key); + } + } + + public static void renewTimeout(String tenantId, long timeout) { + if (tenantId == null) { + tenantId = DEF_TENANT_ID; + } + SaSession saSession = getTenantSession(tenantId); + if (saSession != null) { + saSession.updateTimeout(timeout); + } + } + + + private static ThreadLocal systemInfoThreadLocal = new ThreadLocal<>(); + + /** + * 获取系统设置信息 + * + * @return + */ + public static BaseSystemInfo getBaseSystemInfo() { + BaseSystemInfo systemInfo = systemInfoThreadLocal.get(); + return systemInfo; + } + + + public static void setBaseSystemInfo(BaseSystemInfo baseSystemInfo) { + systemInfoThreadLocal.set(baseSystemInfo); + } + + + public static void clearBaseSystemIfo() { + systemInfoThreadLocal.remove(); + } + + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/util/TicketUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/util/TicketUtil.java new file mode 100644 index 0000000..46a778d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/util/TicketUtil.java @@ -0,0 +1,69 @@ +package com.yunzhupaas.util; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.temp.SaTempUtil; +import cn.dev33.satoken.util.SaTokenConsts; +import org.springframework.stereotype.Component; + + +/** + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +@Component +public class TicketUtil { + + + /** + * 创建临时TOKEN + * @param value 值 + * @param timeout 有效时间, 秒 + * @return + */ + public static String createTicket(Object value, long timeout){ + return SaTempUtil.createToken(value, timeout); + } + + /** + * 获取临时TOKEN内的数据 + * @see #createTicket(Object, long) + * @param ticket 票据 + * @return + * @param + */ + public static T parseTicket(String ticket){ + return (T) SaTempUtil.parseToken(ticket); + } + + /** + * 移除临时Token + * @param ticket + */ + public static void deleteTicket(String ticket){ + SaTempUtil.deleteToken(ticket); + } + + /** + * 更新Ticket内的内容 + * @see #createTicket(Object, long) + * @param ticket 票据 + * @param value 新值 + * @param timeout 超时时间, 秒, 可空为不更新 + */ + public static void updateTicket(String ticket, Object value, Long timeout){ + Object obj = parseTicket(ticket); + if(obj == null) return; + String key = getTicketKey(ticket); + if(timeout != null){ + SaManager.getSaTokenDao().setObject(key, value, timeout); + }else{ + SaManager.getSaTokenDao().updateObject(key, value); + } + } + + private static String getTicketKey(String ticket){ + return SaManager.getSaTemp().splicingKeyTempToken(SaTokenConsts.DEFAULT_TEMP_TOKEN_SERVICE, ticket); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/util/UserProvider.java b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/util/UserProvider.java new file mode 100644 index 0000000..7bf1cc5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-auth/src/main/java/com/yunzhupaas/util/UserProvider.java @@ -0,0 +1,546 @@ +package com.yunzhupaas.util; + +import cn.dev33.satoken.same.SaSameUtil; +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.session.TokenSign; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.text.StrPool; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.consts.DeviceType; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.util.List; +import java.util.stream.Collectors; + +import static com.yunzhupaas.consts.AuthConsts.TOKEN_PREFIX_SP; + + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:57 + */ +@Slf4j +@Component +public class UserProvider { + + private static RedisUtil redisUtil; + private static CacheKeyUtil cacheKeyUtil; + + public static final String USER_INFO_KEY = "userInfo"; + + private static final ThreadLocal USER_CACHE = new ThreadLocal<>(); + + public UserProvider(RedisUtil redisUtil, CacheKeyUtil cacheKeyUtil) { + UserProvider.redisUtil = redisUtil; + UserProvider.cacheKeyUtil = cacheKeyUtil; + } + + + + // =================== 登录相关操作 =================== + + /** + * 登录系统 适用于Request环境 + * + * @param userInfo 登录用户信息 + */ + public static void login(UserInfo userInfo) { + setLocalLoginUser(userInfo); + StpUtil.login(splicingLoginId(userInfo.getUserId())); + userInfo.setToken(StpUtil.getTokenValueNotCut()); + setLoginUser(userInfo); + } + + /** + * 登录系统 适用于Request环境 + * + * @param userInfo 用户信息 + * @param loginModel 登录参数 + */ + public static void login(UserInfo userInfo, SaLoginModel loginModel) { + setLocalLoginUser(userInfo); + StpUtil.login(splicingLoginId(userInfo.getUserId()), loginModel); + userInfo.setToken(StpUtil.getTokenValueNotCut()); + setLoginUser(userInfo); + } + + /** + * 适用于非Request环境 + * @param userInfo + * @param loginModel + */ + public static void loginNoRequest(UserInfo userInfo, SaLoginModel loginModel) { + setLocalLoginUser(userInfo); + String token = StpUtil.createLoginSession(splicingLoginId(userInfo.getUserId()), loginModel); + userInfo.setToken(TOKEN_PREFIX_SP + token); + setLoginUser(userInfo); + } + + + // =================== 登录用户ID相关操作 =================== + + /** + * 获取指定TOKEN用户ID + * + * @param token + * @return + */ + public static String getLoginUserId(String token) { + String loginId = (String) StpUtil.getLoginIdByToken(token); + return parseLoginId(loginId); + } + + /** + * 获取当前用户ID, 包含临时切换用户ID + * + * @return + */ + public static String getLoginUserId() { + String loginId = getUser().getUserId(); + return parseLoginId(loginId); + } + + + + // =================== 用户ID拼接相关操作 =================== + + + /** + * 拼接租户下的用户ID + * + * @param userId + * @return + */ + public static String splicingLoginId(String userId) { + return splicingLoginId(userId, null); + } + + /** + * 拼接租户下的用户ID + * @param userId + * @param tenantId + * @return + */ + private static String splicingLoginId(String userId, String tenantId) { + if(StringUtil.isEmpty(tenantId)){ + tenantId = TenantHolder.getDatasourceId(); + } + if (!StringUtil.isEmpty(tenantId)) { + return tenantId + StrPool.COLON + userId; + } + return userId; + } + + /** + * 解析租户下的登录ID + * @param loginId + * @return + */ + private static String parseLoginId(String loginId) { + if (loginId != null && loginId.contains(StrPool.COLON)) { + loginId = loginId.substring(loginId.indexOf(StrPool.COLON) + 1); + } + return loginId; + } + + /** + * Token是否有效 + * + * @param token + * @return + */ + public static Boolean isValidToken(String token) { + UserInfo userInfo = getUser(token); + return userInfo.getUserId() != null; + } + + + // =================== UserInfo缓存相关操作 =================== + + + /** + * 设置Redis用户数据 + */ + public static void setLoginUser(UserInfo userInfo) { + StpUtil.getTokenSessionByToken(cutToken(userInfo.getToken())).set(USER_INFO_KEY, userInfo); + } + + /** + * 设置本地用户数据 + */ + public static void setLocalLoginUser(UserInfo userInfo) { + USER_CACHE.set(userInfo); + } + + /** + * 获取本地用户数据 + */ + public static UserInfo getLocalLoginUser() { + return USER_CACHE.get(); + } + + /** + * 清空本地用户数据 + */ + public static void clearLocalUser() { + USER_CACHE.remove(); + } + + + + + /** + * 获取用户缓存 + * 保留旧方法 + * + * @param token + * @return + */ + public UserInfo get(String token) { + return UserProvider.getUser(token); + } + + /** + * 获取用户缓存 + * + * @return + */ + public UserInfo get() { + return UserProvider.getUser(); + } + + + /** + * 根据用户ID, 租户ID获取随机获取一个UserInfo + * @param userId + * @param tenantId + * @return + */ + public static UserInfo getUser(String userId, String tenantId){ + return getUser(userId, tenantId, null, null); + } + + /** + * 根据用户ID, 租户ID, 设备类型获取随机获取一个UserInfo + * @param userId + * @param tenantId + * @param includeDevice 指定的设备类型中查找 + * @param excludeDevice 排除指定设备类型 + * @return + */ + public static UserInfo getUser(String userId, String tenantId, List includeDevice, List excludeDevice){ + SaSession session = StpUtil.getSessionByLoginId(splicingLoginId(userId, tenantId), false); + if (session != null) { + List tokenSignList = session.tokenSignListCopy(); + if (!tokenSignList.isEmpty()) { + tokenSignList = tokenSignList.stream().filter(tokenSign -> { + if(!ObjectUtils.isEmpty(excludeDevice)){ + if(excludeDevice.contains(tokenSign.getDevice())){ + return false; + } + } + if(!ObjectUtils.isEmpty(includeDevice)){ + if(!includeDevice.contains(tokenSign.getDevice())){ + return false; + } + } + return true; + }).collect(Collectors.toList()); + if(!tokenSignList.isEmpty()){ + return getUser(tokenSignList.get(0).getValue()); + } + } + } + return new UserInfo(); + } + + /** + * 获取用户缓存 + * + * @param token + * @return + */ + public static UserInfo getUser(String token) { + UserInfo userInfo = null; + String tokens = null; + if (token != null) { + tokens = cutToken(token); + } else { + try { + //处理非Web环境报错 + tokens = StpUtil.getTokenValue(); + } catch (Exception e) { + } + } + if (tokens != null) { + if (StpUtil.getLoginIdByToken(tokens) != null) { + userInfo = (UserInfo) StpUtil.getTokenSessionByToken(tokens).get(USER_INFO_KEY); + } + } + if (userInfo == null) { + userInfo = new UserInfo(); + } + return userInfo; + } + + /** + * 获取用户缓存 + * + * @return + */ + public static UserInfo getUser() { +// if(StpUtil.getTokenValue() == null){ +// return new UserInfo(); +// } + UserInfo userInfo = USER_CACHE.get(); + if (userInfo != null) { + return userInfo; + } + userInfo = UserProvider.getUser(null); + if (userInfo.getUserId() != null) { + USER_CACHE.set(userInfo); + } + return userInfo; + } + + // =================== Token相关操作 =================== + + /** + * 去除Token前缀 + * + * @param token + * @return + */ + public static String cutToken(String token) { + if (token != null && token.startsWith(TOKEN_PREFIX_SP)) { + token = token.substring(TOKEN_PREFIX_SP.length()); + } + return token; + } + + /** + * 获取token + */ + public static String getToken() { + String toke = getAuthorize(); + return toke; + } + + + /** + * 获取Authorize + */ + public static String getAuthorize() { + String authorize = ServletUtil.getHeader(Constants.AUTHORIZATION); + return authorize; + } + + + /** + * TOKEN续期 + */ + public static void renewTimeout() { + if (StpUtil.getTokenValue() != null) { + UserInfo userInfo = UserProvider.getUser(); + if(userInfo.getUserId() == null || userInfo.getTokenTimeout() == null) { + //避免请求过网关之后TOKEN失效(携带TOKEN调用登录接口之后账号被顶替) + return; + } + StpUtil.renewTimeout(userInfo.getTokenTimeout() * 60L); + SaSession saSession = StpUtil.getSessionByLoginId(splicingLoginId(userInfo.getUserId()), false); + if (saSession != null) { + saSession.updateTimeout(userInfo.getTokenTimeout() * 60L); + } + } + } + + /** + * 获取所有Token记录 + * 包含无效状态的用户、临时用户 + * + * @return + */ + public static List getLoginUserListToken() { + return StpUtil.searchTokenValue("", -1, -1, true).stream().map(token -> token.replace(StpUtil.stpLogic.splicingKeyTokenValue(""), "")).collect(Collectors.toList()); + } + + + // =================== 临时Token相关操作 =================== + + + /** + * 获取内部服务传递验证TOKEN + * + * @return + */ + public static String getInnerAuthToken() { + return SaSameUtil.getToken(); + } + + /** + * 验证内部传递Token是否有效 抛出异常 + * @param token + */ + public static void checkInnerToken(String token){ + SaSameUtil.checkToken(token); + } + + /** + * 验证内部传递Token是否有效 + * @param token + */ + public static boolean isValidInnerToken(String token){ + return SaSameUtil.isValid(token); + } + + + // =================== 退出相关操作 =================== + + + /** + * 根据用户ID踢出全部用户 + * @param userId + */ + public static void kickoutByUserId(String userId, String tenantId) { + StpUtil.kickout(splicingLoginId(userId, tenantId)); + } + + /** + * 根据Token踢出指定会话 + * @param tokens + */ + public static void kickoutByToken(String... tokens) { + for (String token : tokens) { + StpUtil.kickoutByTokenValue(token); + } + } + + /** + * 退出当前Token, 不清除用户其他系统缓存 + */ + public static void logout() { + StpUtil.logout(); + + } + + /** + * 退出指定Token, 不清除用户其他系统缓存 + * + * @param token + */ + public static void logoutByToken(String token) { + if (token == null) { + logout(); + } else { + StpUtil.logoutByTokenValue(cutToken(token)); + } + } + + /** + * 退出指定设备类型的用户的全部登录信息, 不清除用户其他系统缓存 + * + * @param userId + * @param deviceType + */ + public static void logoutByUserId(String userId, DeviceType deviceType) { + StpUtil.logout(splicingLoginId(userId), deviceType.getDevice()); + } + + /** + * 退出指定用户的全部登录信息, 清除相关缓存 + * + * @param userId + */ + public static void logoutByUserId(String userId) { + StpUtil.logout(splicingLoginId(userId)); + removeOtherCache(userId); + + } + + // =================== 用户权限 =================== + + /** + * 获取当前用户拥有的权限列表(菜单编码列表、功能ID列表) + * @return + */ + public static List getPermissionList(){ + return StpUtil.getPermissionList(); + } + + /** + * 获取当前用户拥有的角色列表 + * @return + */ + public static List getRoleList(){ + return StpUtil.getRoleList(); + } + + + + + + // =================== 其他缓存相关操作 =================== + + /** + * 移除 + */ + public static void removeOtherCache(String userId) { + redisUtil.remove(cacheKeyUtil.getUserAuthorize() + userId); + redisUtil.remove(cacheKeyUtil.getSystemInfo()); + } + + /** + * 是否在线 + */ + public boolean isOnLine(String userId) { + return StpUtil.getTokenValueByLoginId(splicingLoginId(userId), getDeviceForAgent().getDevice()) != null; + } + + + /** + * 是否登陆 + */ + public static boolean isLogined() { + return StpUtil.isLogin(); + } + + /** + * 指定Token是否有效 + * @param token + * @return + */ + public static boolean isValid(String token) { + return StpUtil.getLoginIdByToken(token) != null; + } + + + public static DeviceType getDeviceForAgent() { + if (ServletUtil.getIsMobileDevice()) { + return DeviceType.APP; + } else { + return DeviceType.PC; + } + } + + /** + * 判断用户是否是临时用户 + * @param userInfo + * @return + */ + public static boolean isTempUser(UserInfo userInfo){ + if(userInfo == null){ + userInfo = getUser(); + } + return DeviceType.TEMPUSER.getDevice().equals(userInfo.getLoginDevice()) + || DeviceType.TEMPUSERLIMITED.getDevice().equals(userInfo.getLoginDevice()); + } + + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-compatible/yunzhupaas-common-office-v3/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-compatible/yunzhupaas-common-office-v3/pom.xml new file mode 100644 index 0000000..cf18efb --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-compatible/yunzhupaas-common-office-v3/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../../pom.xml + + + yunzhupaas-common-office-v3 + + + + + com.yunzhupaas + yunzhupaas-common-office + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-compatible/yunzhupaas-common-office-v3/src/main/java/cn/afterturn/easypoi/util/PoiValidationUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-compatible/yunzhupaas-common-office-v3/src/main/java/cn/afterturn/easypoi/util/PoiValidationUtil.java new file mode 100644 index 0000000..d17ad93 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-compatible/yunzhupaas-common-office-v3/src/main/java/cn/afterturn/easypoi/util/PoiValidationUtil.java @@ -0,0 +1,70 @@ +package cn.afterturn.easypoi.util; + +import cn.afterturn.easypoi.excel.annotation.Excel; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; + +/** + * 导入可选校验 ImportParams.needVerify + * HIBERNATE 校验工具类 + * + * @author JueYue + * 2015年11月11日 下午10:04:07 + */ +public class PoiValidationUtil { + + private final static Validator VALIDATOR; + + static { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + VALIDATOR = factory.getValidator(); + } + + public static String validation(Object obj, Class[] verfiyGroup) { + Set> set = null; + if (verfiyGroup != null) { + set = VALIDATOR.validate(obj, verfiyGroup); + } else { + set = VALIDATOR.validate(obj); + } + if (set != null && set.size() > 0) { + return getValidateErrMsg(set); + } + return null; + } + + private static String getValidateErrMsg(Set> set) { + StringBuilder builder = new StringBuilder(); + for (ConstraintViolation constraintViolation : set) { + Class cls = constraintViolation.getRootBean().getClass(); + String fieldName = constraintViolation.getPropertyPath().toString(); + List fields = new ArrayList<>(Arrays.asList(cls.getDeclaredFields())); + Class superClass = cls.getSuperclass(); + if (superClass != null) { + fields.addAll(Arrays.asList(superClass.getDeclaredFields())); + } + String name = null; + for (Field field : fields) { + if (field.getName().equals(fieldName) && field.isAnnotationPresent(Excel.class)) { + name = field.getAnnotation(Excel.class).name(); + break; + } + } + if (name == null) { + name = fieldName; + } + builder.append(name).append(constraintViolation.getMessage()).append(","); + } + return builder.substring(0, builder.length() - 1); + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-connector/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-connector/pom.xml new file mode 100644 index 0000000..c714c42 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-connector/pom.xml @@ -0,0 +1,16 @@ + + + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-connector + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-connector/src/main/java/com/yunzhupaas/permission/connector/HttpRequestUserInfoService.java b/yunzhupaas-boot-common/yunzhupaas-common-connector/src/main/java/com/yunzhupaas/permission/connector/HttpRequestUserInfoService.java new file mode 100644 index 0000000..c7fcb59 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-connector/src/main/java/com/yunzhupaas/permission/connector/HttpRequestUserInfoService.java @@ -0,0 +1,25 @@ +package com.yunzhupaas.permission.connector; + +import java.util.Map; + +/** + * 用户推送 + * + * @author :云筑产品开发平台组 + * @version: V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date :2022/8/3 13:50 + */ +public interface HttpRequestUserInfoService { + + /** + * 同步数据到本地数据库 + * + * @param userEntity + * @param method + * @param tenantId + */ + void syncUserInfo(Map userEntity, String method, String tenantId); + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-connector/src/main/java/com/yunzhupaas/permission/connector/UserInfoService.java b/yunzhupaas-boot-common/yunzhupaas-common-connector/src/main/java/com/yunzhupaas/permission/connector/UserInfoService.java new file mode 100644 index 0000000..cdcbc2c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-connector/src/main/java/com/yunzhupaas/permission/connector/UserInfoService.java @@ -0,0 +1,44 @@ +package com.yunzhupaas.permission.connector; + +import java.util.Map; + +/** + * 拉取用户 + * + * @author :云筑产品开发平台组 + * @version: V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date :2022/7/28 14:27 + */ +public interface UserInfoService { + + /** + * 添加 + * + * @param map + */ + Boolean create(Map map); + + /** + * 修改 + * + * @param map + */ + Boolean update(Map map); + + /** + * 删除 + * + * @param map + */ + Boolean delete(Map map); + + /** + * 获取信息 + * + * @param id + */ + Map getInfo(String id); + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-core/pom.xml new file mode 100644 index 0000000..8be986c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/pom.xml @@ -0,0 +1,315 @@ + + + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-core + + + + + org.projectlombok + lombok + provided + + + cn.afterturn + easypoi-annotation + + + com.baomidou + mybatis-plus-annotation + + + + + com.nimbusds + nimbus-jose-jwt + + + + + com.alibaba + fastjson + + + + + org.apache.commons + commons-lang3 + + + + + + + + org.quartz-scheduler + quartz + + + HikariCP-java7 + com.zaxxer + + + + + + + com.google.zxing + core + + + + + com.belerweb + pinyin4j + + + + + + + + org.apache.commons + commons-pool2 + + + + org.apache.httpcomponents + httpmime + + + + + + org.hibernate.validator + hibernate-validator + + + + + org.springframework.boot + spring-boot-starter-web + + + + + + commons-io + commons-io + + + + org.owasp.antisamy + antisamy + + + commons-io + commons-io + + + + + + org.apache.commons + commons-text + + + + + org.apache.commons + commons-collections4 + + + com.google.guava + guava + + + + cn.hutool + hutool-all + + + + net.lingala.zip4j + zip4j + + + com.github.yitter + yitter-idgenerator + + + org.apache.poi + poi + + + com.baomidou + mybatis-plus-core + ${mybatis-plus.vesion} + + + + org.springframework.boot + spring-boot-properties-migrator + runtime + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + net.logstash.logback + logstash-logback-encoder + + + jackson-databind + com.fasterxml.jackson.core + + + + + + org.apache.skywalking + apm-toolkit-logback-1.x + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + boot3 + + [17,) + + + + + jakarta.servlet + jakarta.servlet-api + + + io.swagger.core.v3 + swagger-annotations-jakarta + + + io.swagger.core.v3 + swagger-models-jakarta + + + jakarta.annotation + jakarta.annotation-api + + + jakarta.validation + jakarta.validation-api + + + org.openjdk.nashorn + nashorn-core + + + + + boot2 + + (,17) + + + + + javax.servlet + javax.servlet-api + + + + jakarta.servlet + jakarta.servlet-api + + + io.swagger.core.v3 + swagger-annotations + + + io.swagger.core.v3 + swagger-models + + + javax.annotation + javax.annotation-api + + + + jakarta.validation + jakarta.validation-api + + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/EncryptApi.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/EncryptApi.java new file mode 100644 index 0000000..4f7b5e1 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/EncryptApi.java @@ -0,0 +1,28 @@ +package com.yunzhupaas.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 接口传输加密 + * 加密请求和返回结果: @EncryptApi + * 只加密请求: @EncryptApi(encryptRequest = false) + * 只加密返回结果: @EncryptApi(encryptResponse = false) + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD,ElementType.PARAMETER}) +public @interface EncryptApi { + + /** + * 加密请求内容 + */ + boolean encryptRequest() default true; + + /** + * 加密返回结果 + */ + boolean encryptResponse() default true; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/HandleLog.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/HandleLog.java new file mode 100644 index 0000000..914c1d3 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/HandleLog.java @@ -0,0 +1,33 @@ +package com.yunzhupaas.annotation; + +import java.lang.annotation.*; + +/** + * 请求日志注解 + * + * @author :云筑产品开发平台组 + * @version: V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date :2022/3/15 11:19 + */ +@Documented +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface HandleLog { + + /** + * 操作模块 + * + * @return + */ + String moduleName() default ""; + + /** + * 操作方式 + * + * @return + */ + String requestMethod() default ""; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/OrganizeAdminIsTrator.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/OrganizeAdminIsTrator.java new file mode 100644 index 0000000..d95a9e8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/OrganizeAdminIsTrator.java @@ -0,0 +1,19 @@ +package com.yunzhupaas.annotation; + + +import java.lang.annotation.*; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:53 + */ +@Documented +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface OrganizeAdminIsTrator { + String value() default ""; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/OrganizePermission.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/OrganizePermission.java new file mode 100644 index 0000000..154f640 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/OrganizePermission.java @@ -0,0 +1,18 @@ +package com.yunzhupaas.annotation; + +import java.lang.annotation.*; + +/** + * 组织权限验证 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-10-30 + */ +@Documented +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface OrganizePermission { +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/PositionPermission.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/PositionPermission.java new file mode 100644 index 0000000..f7a1394 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/PositionPermission.java @@ -0,0 +1,18 @@ +package com.yunzhupaas.annotation; + +import java.lang.annotation.*; + +/** + * 组织权限验证 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-10-30 + */ +@Documented +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface PositionPermission { +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/RolePermission.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/RolePermission.java new file mode 100644 index 0000000..123c55a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/RolePermission.java @@ -0,0 +1,19 @@ +package com.yunzhupaas.annotation; + +import java.lang.annotation.*; + +/** + * 角色权限验证 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-10-30 + */ +@Documented +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RolePermission { + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/SaCheckSame.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/SaCheckSame.java new file mode 100644 index 0000000..6f4ad43 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/SaCheckSame.java @@ -0,0 +1,24 @@ +package com.yunzhupaas.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 内部请求校验:校验是否来自内部请求 + * + *

可标注在方法、类上(效果等同于标注在此类的所有方法上) + * + * @author 云筑产品开发平台组 + * @version V5.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-12-31 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE }) +public @interface SaCheckSame { + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/UserPermission.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/UserPermission.java new file mode 100644 index 0000000..46a9fb4 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/UserPermission.java @@ -0,0 +1,18 @@ +package com.yunzhupaas.annotation; + +import java.lang.annotation.*; + +/** + * 组织权限验证 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-10-30 + */ +@Documented +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface UserPermission { +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/YunzhupaasField.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/YunzhupaasField.java new file mode 100644 index 0000000..66c5eb2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/annotation/YunzhupaasField.java @@ -0,0 +1,117 @@ +package com.yunzhupaas.annotation; + +import java.lang.annotation.*; + +/** + * 控件属性 + * + * @author 云筑产品开发平台组 + * @version V3.4.3 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2022/9/19 + */ +@Documented +@Target({ ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface YunzhupaasField { + + String vModel() default ""; + + String label() default ""; + + /** + * 是否多选 + */ + boolean multiple() default false; + + String yunzhupaasKey() default ""; + + /** + * 显示层级 + */ + String showLevel() default ""; + + /** + * 省市区显示层级 + */ + String level() default "0"; + + /** + * 单据规则 + */ + String rule() default ""; + + String activeTxt() default "开"; + + String inactiveTxt() default "关"; + + int min() default -1; + + int max() default -1; + + /** + * + * 是否唯一 + */ + boolean unique() default false; + + boolean isUpdate() default false; + + /** + * 单行输入正则 + */ + String regex() default ""; + + /** + * 表名 + */ + String relationTable() default ""; + + String tableName() default ""; + + /** + * 时间 + */ + String format() default ""; + + /** + * 数据接口 + */ + String dataType() default ""; + + String dataLabel() default "fullName"; + + String dataValue() default "id"; + + String dataChildren() default "children"; + + String propsUrl() default ""; + + String dictionaryType() default ""; + + String options() default ""; + + String ableDepIds() default "[]"; + + String ablePosIds() default "[]"; + + String ableUserIds() default "[]"; + + String ableRoleIds() default "[]"; + + String ableGroupIds() default "[]"; + + String ableIds() default "[]"; + + String selectType() default ""; + + /** + * 开始时间 + */ + String startTime() default ""; + + /** + * 结束时间 + */ + String endTime() default ""; +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/ActionResult.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/ActionResult.java new file mode 100644 index 0000000..a4166e7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/ActionResult.java @@ -0,0 +1,114 @@ +package com.yunzhupaas.base; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import com.yunzhupaas.base.vo.PageListVO; +import com.yunzhupaas.base.vo.PaginationVO; +import com.yunzhupaas.constant.MsgCode; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:45 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ActionResult { + + @Schema(description = "状态码") + private Integer code; + + @Schema(description = "返回信息") + private String msg; + + @Schema(description = "返回数据") + private T data; + + /* ============== success ============ */ + + public static ActionResult success() { + ActionResult jsonData = new ActionResult<>(); + jsonData.setCode(200); + jsonData.setMsg(MsgCode.SU000.get()); + return jsonData; + } + + public static ActionResult success(String msg) { + ActionResult jsonData = new ActionResult<>(); + jsonData.setCode(200); + jsonData.setMsg(msg); + return jsonData; + } + + public static ActionResult success(T object) { + ActionResult jsonData = new ActionResult<>(); + jsonData.setData(object); + jsonData.setCode(200); + jsonData.setMsg(MsgCode.SU000.get()); + return jsonData; + } + + public static ActionResult success(String msg, T object) { + ActionResult jsonData = new ActionResult<>(); + jsonData.setData(object); + jsonData.setCode(200); + jsonData.setMsg(msg); + return jsonData; + } + + /* ============== fail ============ */ + + public static ActionResult fail(Integer code, String message) { + ActionResult jsonData = new ActionResult<>(); + jsonData.setCode(code); + jsonData.setMsg(message); + return jsonData; + } + + public static ActionResult fail(String msg, String data) { + ActionResult jsonData = new ActionResult<>(); + jsonData.setMsg(msg); + jsonData.setData(data); + return jsonData; + } + + public static ActionResult fail(String msg) { + ActionResult jsonData = new ActionResult<>(); + jsonData.setMsg(msg); + jsonData.setCode(400); + return jsonData; + } + + /* ============== page ============ */ + + public static ActionResult> page(List list, PaginationVO pagination) { + ActionResult> jsonData = new ActionResult<>(); + PageListVO vo = new PageListVO<>(); + vo.setList(list); + vo.setPagination(pagination); + jsonData.setData(vo); + jsonData.setCode(200); + jsonData.setMsg(MsgCode.SU000.get()); + return jsonData; + } + + public static ActionResult> page(List list, PaginationVO pagination, String dataProcessing) { + ActionResult> jsonData = new ActionResult<>(); + DataInterfacePageListVO vo = new DataInterfacePageListVO<>(); + vo.setList(list); + vo.setPagination(pagination); + vo.setDataProcessing(dataProcessing); + jsonData.setCode(200); + jsonData.setData(vo); + jsonData.setMsg(MsgCode.SU000.get()); + return jsonData; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/ActionResultCode.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/ActionResultCode.java new file mode 100644 index 0000000..9926fd5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/ActionResultCode.java @@ -0,0 +1,69 @@ +package com.yunzhupaas.base; + +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.constant.model.MCode; + +/** + * 错误提示枚举类 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-09-26 上午9:18 + */ +public enum ActionResultCode { + + /** + * 成功 + */ + Success(200, MsgCode.GT101), + /** + * 失败 + */ + Fail(400, MsgCode.GT102), + /** + * 验证错误 + */ + ValidateError(401, MsgCode.GT103), + /** + * 异常 + */ + Exception(500, MsgCode.GT104), + /** + * 登录过期提示 + */ + SessionOverdue(600, MsgCode.GT105), + /** + * 踢出提示 + */ + SessionOffLine(601, MsgCode.GT106), + /** + * token失效 + */ + SessionError(602, MsgCode.GT107); + + private int code; + private MCode message; + + ActionResultCode(int code, MCode message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message.get(); + } + + public void setMessage(MCode message) { + this.message = message; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/DataInterfacePageListVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/DataInterfacePageListVO.java new file mode 100644 index 0000000..e0227e5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/DataInterfacePageListVO.java @@ -0,0 +1,19 @@ +package com.yunzhupaas.base; + +import com.yunzhupaas.base.vo.PageListVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 数据接口弹窗选择 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-12-31 + */ +@Data +public class DataInterfacePageListVO extends PageListVO { + private String dataProcessing; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/DataSourceInfo.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/DataSourceInfo.java new file mode 100644 index 0000000..835fcef --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/DataSourceInfo.java @@ -0,0 +1,43 @@ +package com.yunzhupaas.base; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-04-07 + */ +public class DataSourceInfo { + public static final String mysqlUrl="jdbc:mysql://{host}:{port}/{dbName}?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&serverTimezone=UTC"; + + public static final String mysqlDriver="com.mysql.cj.jdbc.Driver"; + + + + public static final String oracleUrl="jdbc:oracle:thin:@{host}:{port}:{dbName}"; + + public static final String oracleDriver="oracle.jdbc.OracleDriver"; + + + + public static final String sqlserverUrl="jdbc:sqlserver://{host}:{port};Databasename={dbName}"; + + public static final String sqlserverDriver="com.microsoft.sqlserver.jdbc.SQLServerDriver"; + + public static final String dmUrl="jdbc:dm://{host}:{port}/{dbName}?yunzhupaasDateTimeBehavior=convertToNull&useUnicode" + + "=true&characterEncoding=utf-8"; + + + public static final String dmDriver="dm.jdbc.driver.DmDriver"; + + + public static final String kingBaseUrl = "jdbc:kingbase8://{host}:{port}/{dbName}"; + + public static final String kingBaseDriver = "com.kingbase8.Driver"; + + + public static final String postgreUrl = "jdbc:postgresql://{host}:{port}/{dbName}" ; + + public static final String postgreDriver = "org.postgresql.Driver"; +} + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/LogSortEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/LogSortEnum.java new file mode 100644 index 0000000..b67927f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/LogSortEnum.java @@ -0,0 +1,86 @@ +package com.yunzhupaas.base; + +/** + * 日志分类 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-09-26 上午9:18 + */ +public enum LogSortEnum { + + /** + * 登录 + */ + Login(1, "登录"), + /** + * 访问 + */ + Visit(2, "访问"), + /** + * 操作 + */ + Operate(3, "操作"), + /** + * 异常 + */ + Exception(4, "异常"), + /** + * 请求 + */ + Request(5, "请求"); + + private int code; + private String message; + + LogSortEnum(int code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + /** + * 根据状态code获取枚举名称 + * + * @return + */ + public static String getMessageByCode(Integer code) { + for (LogSortEnum status : LogSortEnum.values()) { + if (status.getCode().equals(code)) { + return status.message; + } + } + return null; + } + + /** + * 根据状态code获取枚举值 + * + * @return + */ + public static LogSortEnum getByCode(Integer code) { + for (LogSortEnum status : LogSortEnum.values()) { + if (status.getCode().equals(code)) { + return status; + } + } + return null; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/MyBatisPrimaryBase.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/MyBatisPrimaryBase.java new file mode 100644 index 0000000..144191e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/MyBatisPrimaryBase.java @@ -0,0 +1,90 @@ +package com.yunzhupaas.base; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.v3.oas.annotations.media.Schema; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.exception.DataException; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +/** + * 联合主键 + * + * 门户管理单条数据,可以由平台、门户ID、系统ID 三种数据定位 + * 它们组合成门户管理的联合主键,此类将其看成一个主键来配合QueryWrapper使用 + * + * @author 云筑产品开发平台组 + * @version v3.4.8 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2023-04-20 + */ +public abstract class MyBatisPrimaryBase { + + { + ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass(); + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + Class clz = (Class)actualTypeArguments[0]; + try { + entity = clz.getDeclaredConstructor().newInstance(); + } catch (Exception ignore) {} + } + + @Schema(description = "查询器") + protected QueryWrapper queryWrapper = new QueryWrapper<>(); + + private T entity; + + @Schema(description = "获取处理后的查询器") + public QueryWrapper getQuery(){ + try{ + for (Field field : this.getClass().getDeclaredFields()) { + try{ + TableField annotation = entity.getClass().getDeclaredField(field.getName()).getAnnotation(TableField.class); + String columnName; + if(annotation != null) { + columnName = annotation.value(); + }else if(field.getName().equalsIgnoreCase("id")) { + columnName = "F_Id"; + }else if(field.getName().equalsIgnoreCase("creatorId")){ + columnName = "F_Creator_Id"; + }else { + columnName = field.getName(); + } + field.setAccessible(true); + Object value = field.get(this); + if(value != null) queryWrapper.eq(columnName, value); + }catch (Exception ignore){} + } + }catch (Exception ignore){} + return queryWrapper; + } + + @Schema(description = "获取实例") + public T getEntity() throws Exception { + checkEntity(); + for (Field field : this.getClass().getDeclaredFields()) { + for (Field entityField : entity.getClass().getDeclaredFields()) { + if(entityField.getName().equals(field.getName())){ + entityField.setAccessible(true); + field.setAccessible(true); + entityField.set(entity, field.get(this)); + } + } + } + return entity; + } + + private void checkEntity() throws Exception{ + for (Field field : this.getClass().getFields()) { + Object o = field.get(this); + if(o == null){ + throw new DataException(MsgCode.DB011.get(field.getName())); + } + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/Page.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/Page.java new file mode 100644 index 0000000..6f45dd7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/Page.java @@ -0,0 +1,16 @@ +package com.yunzhupaas.base; + +import lombok.Data; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Data +public class Page { + private String keyword=""; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/PageModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/PageModel.java new file mode 100644 index 0000000..3926a25 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/PageModel.java @@ -0,0 +1,59 @@ +package com.yunzhupaas.base; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Data +public class PageModel { + /** + * 每页行数 + */ + private int rows; + /** + * 当前页 + */ + private int page; + /** + * 总页数 + */ + private long total; + /** + * 总记录数 + */ + private long records; + /** + * 排序列 + */ + private String sidx; + /** + * 排序类型 + */ + private String sord; + /** + * 查询条件 + */ + private String queryJson; + /** + * 查询关键字 + */ + private String keyword; + + public List setData(List data, long records) { + this.records = records; + if(this.records>0){ + this.total = this.records % this.rows == 0 ? this.records / this.rows : this.records/this.rows+1; + }else { + this.total = 0; + } + return data; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/Pagination.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/Pagination.java new file mode 100644 index 0000000..4b1327f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/Pagination.java @@ -0,0 +1,34 @@ +package com.yunzhupaas.base; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Data +public class Pagination extends Page{ + private long pageSize=20; + private String sort="DESC"; + private String sidx=""; + private long currentPage=1; + + @JsonIgnore + private long total; + @JsonIgnore + private long records; + + public List setData(List data, long records) { + this.total = records; + return data; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/PaginationTime.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/PaginationTime.java new file mode 100644 index 0000000..30fc130 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/PaginationTime.java @@ -0,0 +1,18 @@ +package com.yunzhupaas.base; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Data +public class PaginationTime extends Pagination { + private Long startTime; + private Long endTime; +// private String type; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/SmsModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/SmsModel.java new file mode 100644 index 0000000..16cd1ac --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/SmsModel.java @@ -0,0 +1,30 @@ +package com.yunzhupaas.base; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 发送短信配置模型 + * + * @版本: V3.1.0 + * @版权: 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @作者: 云筑产品开发平台组 + * @日期: 2021/4/20 14:22 + */ +@Data +public class SmsModel { + /** + * 阿里 + */ + private String aliAccessKey; + private String aliSecret; + + /** + * 腾讯 + */ + private String tencentSecretId; + private String tencentSecretKey; + private String tencentAppId; + private String tencentAppKey; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/UserInfo.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/UserInfo.java new file mode 100644 index 0000000..70b6ef8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/UserInfo.java @@ -0,0 +1,215 @@ +package com.yunzhupaas.base; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 登录者信息 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-09-26 上午9:18 + */ +@Data +public class UserInfo implements Serializable { + + /** + * 唯一Id + */ + private String id; + /** + * 用户主键 + */ + private String userId; + /** + * 用户账户 + */ + private String userAccount; + /** + * 用户姓名 + */ + private String userName; + /** + * 用户头像 + */ + private String userIcon; + /** + * 用户性别 + */ + private String userGender; + /** + * 主题 + */ + private String theme; + /** + * 机构主键 + */ + private String organizeId; + /** + * 机构主键 + */ + private String departmentId; + /** + * 我的主管 + */ + private String managerId; + /** + * 下属机构 + */ + private String[] subOrganizeIds; + /** + * 我的下属 + */ + private List subordinateIds; + /** + * 岗位主键 + */ + private String[] positionIds; + /** + * 角色主键 + */ + private List roleIds; + /** + * 登录时间 + */ + private String loginTime; + /** + * 登录IP地址 + */ + private String loginIpAddress; + /** + * 登录IP地址所在城市 + */ + private String loginIpAddressName; + /** + * 登录MAC地址 + */ + private String macAddress; + /** + * 登录平台设备(UA) + */ + private String loginPlatForm; + /** + * 登录平台名称 + */ + private String loginDevice; + /** + * 上次登录时间 + */ + private Date prevLoginTime; + /** + * 上次登录IP地址 + */ + private String prevLoginIpAddress; + /** + * 上次登录IP地址所在城市 + */ + private String prevLoginIpAddressName; + /** + * 是否超级管理员 + */ + private Boolean isAdministrator = true; + /** + * 过期时间 + */ + private Date overdueTime; + /** + * 系统配置超时时间 + */ + private Integer tokenTimeout; + /** + * 租户编码 + */ + private String tenantId; + public String getTenantId() { + return tenantId = tenantId == null ? "" : tenantId; + } + /** + * 租户数据库连接串(注意:主要解决多租户系统用的。每个租户连接数据库都是唯一的) + */ + /** + * 目前就支持一个数据库。如果业务需要多个数据库,手动去添加 ConnectionString1、ConnectionString2 等等 + */ + @Deprecated + private String tenantDbConnectionString; + /** + * 租户数据源类型 + * @see com.yunzhupaas.model.tenant.TenantVO + */ + private int tenantDbType; + + private String portalId; + + /** + * 系统id + */ + private String systemId; + + /** + * 系统id + */ + private List systemIds; + + /** + * APP系统id + */ + private String appSystemId; + /** + * 登录类型 + */ + private String grantType; + /** + * 单点登录用户票据, 用于单点注销 + */ + private String onlineTicket; + /** + * Token + */ + private String token; + /** + * 用户信息实现接口 + */ + private String userDetailKey; + + private List groupIds; + + private List groupNames; + /** + * 浏览器 + */ + private String browser; + /** + * 所属组织 + */ + private String organize; + + /** + * 独立URL Code + */ + private String systemCode; + + /** + * 手机号 + */ + private String mobilePhone; + + /** + * 邮箱 + */ + private String email; + + /** + * 启用状态 + */ + private Integer enabledMark; + + /** + * 创建时间 + */ + private Date createTime; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/entity/SuperBaseEntity.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/entity/SuperBaseEntity.java new file mode 100644 index 0000000..d4a9f0b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/entity/SuperBaseEntity.java @@ -0,0 +1,133 @@ +package com.yunzhupaas.base.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import io.swagger.v3.oas.annotations.media.Schema; +import com.yunzhupaas.constant.TableFieldsNameConst; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.util.Date; + +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = false) +public abstract class SuperBaseEntity implements Serializable { + + @Data + @ToString(callSuper = true) + @EqualsAndHashCode(callSuper = false) + public static abstract class SuperIBaseEntity extends SuperBaseEntity { + + /** + * 主键 + */ + @TableId(TableFieldsNameConst.F_ID) + public T id; + + } + + @Data + @ToString(callSuper = true) + @EqualsAndHashCode(callSuper = false) + public static abstract class SuperTBaseEntity extends SuperIBaseEntity { + + /** + * 租户id + */ + @TableField(value = TableFieldsNameConst.F_TENANT_ID, fill = FieldFill.INSERT_UPDATE) + private String tenantId; + + } + + @Data + @ToString(callSuper = true) + @EqualsAndHashCode(callSuper = false) + public static abstract class SuperCBaseEntity extends SuperTBaseEntity { + + /** + * 创建时间 + */ + @TableField(value = TableFieldsNameConst.F_CREATOR_TIME, fill = FieldFill.INSERT) + private Date creatorTime; + + /** + * 创建用户 + */ + @TableField(value = TableFieldsNameConst.F_CREATOR_USER_ID, fill = FieldFill.INSERT) + private String creatorUserId; + + } + + @Data + @ToString(callSuper = true) + @EqualsAndHashCode(callSuper = false) + public static abstract class SuperCUBaseEntity extends SuperCBaseEntity { + + /** + * 修改时间 + */ + @TableField(value = TableFieldsNameConst.F_LAST_MODIFY_TIME, fill = FieldFill.UPDATE) + private Date lastModifyTime; + + /** + * 修改用户 + */ + @TableField(value = TableFieldsNameConst.F_LAST_MODIFY_USER_ID, fill = FieldFill.UPDATE) + private String lastModifyUserId; + + } + + @Data + @ToString(callSuper = true) + @EqualsAndHashCode(callSuper = false) + public static abstract class SuperCUDBaseEntity extends SuperCUBaseEntity { + + /** + * 删除标志 + */ + @TableField(value = TableFieldsNameConst.F_DELETE_MARK, updateStrategy = FieldStrategy.IGNORED) + private Integer deleteMark; + + /** + * 删除时间 + */ + @TableField(value = TableFieldsNameConst.F_DELETE_TIME, fill = FieldFill.UPDATE) + private Date deleteTime; + + /** + * 删除用户 + */ + @TableField(value = TableFieldsNameConst.F_DELETE_USER_ID, fill = FieldFill.UPDATE) + private String deleteUserId; + } + + @Data + @ToString(callSuper = true) + @EqualsAndHashCode(callSuper = false) + public static abstract class SuperCDBaseEntity extends SuperCBaseEntity { + + /** + * 删除标志 + */ + @TableField(value = TableFieldsNameConst.F_DELETE_MARK, updateStrategy = FieldStrategy.IGNORED) + private Integer deleteMark; + + /** + * 删除时间 + */ + @TableField(value = TableFieldsNameConst.F_DELETE_TIME, fill = FieldFill.UPDATE) + private Date deleteTime; + + /** + * 删除用户 + */ + @TableField(value = TableFieldsNameConst.F_DELETE_USER_ID, fill = FieldFill.UPDATE) + private String deleteUserId; + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/entity/SuperEntity.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/entity/SuperEntity.java new file mode 100644 index 0000000..ec14bdc --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/entity/SuperEntity.java @@ -0,0 +1,12 @@ +package com.yunzhupaas.base.entity; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public abstract class SuperEntity extends SuperBaseEntity.SuperCUDBaseEntity { + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/entity/SuperExtendEntity.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/entity/SuperExtendEntity.java new file mode 100644 index 0000000..f4ebcb5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/entity/SuperExtendEntity.java @@ -0,0 +1,67 @@ +package com.yunzhupaas.base.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.yunzhupaas.constant.TableFieldsNameConst; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public abstract class SuperExtendEntity extends SuperEntity { + + /** + * 排序码 + */ + @TableField(TableFieldsNameConst.F_SORT_CODE) + private Long sortCode; + + @Data + @ToString(callSuper = true) + @EqualsAndHashCode(callSuper = true) + public static abstract class SuperExtendDescriptionEntity extends SuperExtendEntity { + + /** + * 描述 + */ + @TableField(TableFieldsNameConst.F_DESCRIPTION) + private String description; + + } + + @Data + @ToString(callSuper = true) + @EqualsAndHashCode(callSuper = true) + public static abstract class SuperExtendEnabledEntity extends SuperExtendEntity { + + /** + * 有效标志 (0-默认,禁用,1-启用) + */ + @TableField(value = TableFieldsNameConst.F_ENABLED_MARK, fill = FieldFill.INSERT) + private Integer enabledMark; + + } + + @Data + @ToString(callSuper = true) + @EqualsAndHashCode(callSuper = true) + public static abstract class SuperExtendDEEntity extends SuperExtendEntity { + + /** + * 描述 + */ + @TableField(TableFieldsNameConst.F_DESCRIPTION) + private String description; + + /** + * 有效标志 (0-默认,禁用,1-启用) + */ + @TableField(value = TableFieldsNameConst.F_ENABLED_MARK, fill = FieldFill.INSERT) + private Integer enabledMark; + + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/user/UserTenantModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/user/UserTenantModel.java new file mode 100644 index 0000000..b341cb8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/user/UserTenantModel.java @@ -0,0 +1,29 @@ +package com.yunzhupaas.base.user; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 用户租户信息 + * + * @author :云筑产品开发平台组 + * @version: V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date :2022/5/10 16:13 + */ +@Data +public class UserTenantModel implements Serializable { + /** + * 租户手机号 + */ + private String tenantId; + + public UserTenantModel() { + } + + public UserTenantModel(String tenantId) { + this.tenantId = tenantId; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/DownloadVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/DownloadVO.java new file mode 100644 index 0000000..3442353 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/DownloadVO.java @@ -0,0 +1,27 @@ +package com.yunzhupaas.base.vo; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DownloadVO { + @Schema(description = "名称") + private String name; + @Schema(description = "请求接口") + private String url; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/ListVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/ListVO.java new file mode 100644 index 0000000..4f6ba23 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/ListVO.java @@ -0,0 +1,25 @@ +package com.yunzhupaas.base.vo; + +import lombok.AllArgsConstructor; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ListVO { + + private List list; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/PageListVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/PageListVO.java new file mode 100644 index 0000000..19f766d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/PageListVO.java @@ -0,0 +1,20 @@ +package com.yunzhupaas.base.vo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Data +public class PageListVO { + private List list; + PaginationVO pagination; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/PaginationVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/PaginationVO.java new file mode 100644 index 0000000..1b1dc36 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/base/vo/PaginationVO.java @@ -0,0 +1,19 @@ +package com.yunzhupaas.base.vo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 需要分页的模型 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-15 09:50 + */ +@Data +public class PaginationVO { + private Long currentPage; + private Long pageSize; + private Integer total; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/ApplicationStartErrorCheck.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/ApplicationStartErrorCheck.java new file mode 100644 index 0000000..53b2812 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/ApplicationStartErrorCheck.java @@ -0,0 +1,63 @@ +package com.yunzhupaas.config; + +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.SmartInitializingSingleton; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * 程序启动线程初始化类 + */ +@Slf4j +public class ApplicationStartErrorCheck implements SmartInitializingSingleton { + + private static boolean startError = false; + + @Getter + private static final ThreadPoolExecutor applicationInitThreadPool = new ThreadPoolExecutor(10, Integer.MAX_VALUE, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue()); + + public static void setStartError() { + ApplicationStartErrorCheck.startError = true; + } + + @SneakyThrows + @Override + public void afterSingletonsInstantiated() { + long count = 0; + long sleep = 100L; + //最多等待程序启动5分钟 + long maxCount = 5 * 60000 / sleep; + boolean isComplete = true; + // 等待异步初始化全部完成 + while(!applicationInitThreadPool.getQueue().isEmpty() || applicationInitThreadPool.getActiveCount() > 0){ + if(log.isDebugEnabled()) { + log.error("等待初始化线程全部结束"); + } + Thread.sleep(sleep); + if(++count > maxCount){ + isComplete = false; + break; + } + } + if(!isComplete){ + log.error("容器初始化时间过长 请检查是否存在问题"); + System.exit(0); + } + if(startError){ + log.error("Bean初始化发生错误, 请检查启动日志"); + System.exit(0); + } +// System.out.println("延迟五秒"); +// Thread.sleep(5000L); + if(log.isDebugEnabled()) { + log.debug("容器初始化结束"); + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/Conf2SystemConfiguration.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/Conf2SystemConfiguration.java new file mode 100644 index 0000000..7c397b8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/Conf2SystemConfiguration.java @@ -0,0 +1,53 @@ +package com.yunzhupaas.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.PropertySource; + +/** + * 将Spring中的配置设置到系统属性中 + * conf2system: + * csp.sentinel.log.dir: log/${spring.application.name}/sentinel + * rocketmq.log.level: "OFF" + * demo.enabled: false + * + * @author 云筑产品开发平台组 + * @version V5.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-12-17 + */ +@Slf4j +public class Conf2SystemConfiguration implements ApplicationContextInitializer, Ordered { + + private static final String PREFIX = "conf2system."; + + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + ConfigurableEnvironment environment = applicationContext.getEnvironment(); + for (PropertySource source : applicationContext.getEnvironment().getPropertySources()) { + if(source instanceof EnumerablePropertySource){ + for (String propertyName : ((EnumerablePropertySource) source).getPropertyNames()) { + if(propertyName.startsWith(PREFIX)){ + Object value = environment.getProperty(propertyName); + if(value != null){ + System.setProperty(propertyName.substring(PREFIX.length()), String.valueOf(value)); + if(log.isDebugEnabled()){ + log.debug("Setting system property [{}] to [{}]", propertyName.substring(PREFIX.length()), value); + } + } + } + } + } + } + } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE+1000; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/ConfigValueUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/ConfigValueUtil.java new file mode 100644 index 0000000..b96b1bc --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/ConfigValueUtil.java @@ -0,0 +1,379 @@ +package com.yunzhupaas.config; + +import cn.hutool.core.net.url.UrlBuilder; +import com.yunzhupaas.constant.ConfigConst; +import com.yunzhupaas.constant.TableFieldsNameConst; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.XSSEscape; +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:47 + */ +@Data +public class ConfigValueUtil { + + public static final String PREFIX = "config"; + + @Value("spring.application.name:YUNZHUPAAS") + private String applicationName; + + // /** + // * 环境路径 + // */ + // @Value("${config.Path:}") + // private String path; + /** + * 数据库备份文件路径 + */ + private String dataBackupFilePath; + /** + * 临时文件存储路径 + */ + private String temporaryFilePath; + /** + * 系统文件存储路径 + */ + private String systemFilePath; + /** + * 文件模板存储路径 + */ + private String templateFilePath; + /** + * 代码模板存储路径 + */ + private String templateCodePath; + /** + * vue3代码模板存储路径 + */ + private String templateCodePathVue3; + /** + * 邮件文件存储路径 + */ + private String emailFilePath; + /** + * 大屏图片存储目录 + */ + private String biVisualPath; + /** + * 文档管理存储路径 + */ + private String documentFilePath; + /** + * 文件在线预览存储pdf + */ + private String documentPreviewPath; + /** + * 用户头像存储路径 + */ + private String userAvatarFilePath; + /** + * IM聊天图片+语音存储路径 + */ + private String imContentFilePath; + /** + * 允许上传文件类型 + */ + private String allowUploadFileType; + /** + * 允许图片类型 + */ + private String allowUploadImageType; + + /** + * 允许预览类型 + */ + private String allowPreviewFileType; + + /** + * 预览方式 + */ + private String previewType; + + /** + * 预览方式 + */ + private String kkFileUrl; + + /** + * 多语言json路径 + */ + private String baseLanguagePath; + + /** + * 前端文件目录 + */ + private String serviceDirectoryPath = ConfigConst.CODE_TEMP_FOLDER; + /** + * 代码生成器命名空间 + */ + private String codeAreasName; + + /** + * 前端附件文件目录 + */ + private String webAnnexFilePath; + + /** + * ApacheShardingSphere 配置开关 + */ + private boolean shardingSphereEnabled; + + /** + * 软件的错误报告 + */ + private String errorReport; + /** + * 软件的错误报告发给谁 + */ + private String errorReportTo; + /** + * 系统日志启用:true、false + */ + private String recordLog; + /** + * 多租户启用:true、false + */ + private boolean multiTenancy; + /** + * 多租户接口 + */ + private String multiTenancyUrl; + /** + * 多租户字段 + */ + private String multiTenantColumn = TableFieldsNameConst.F_TENANT_ID; + /** + * 字段多租户忽略表 + */ + private List multiTenantIgnoreTable = initMultiTenantIgnoreTable(); + /** + * 多租户登录短信验证接口 + */ + private String multiTenancyOfficialLoginCodeUrl = null; + /** + * 多租户重置密码短信验证接口 + */ + private String multiTenancyOfficialResetCodeUrl = null; + /** + * 开启逻辑删除功能 + */ + private boolean enableLogicDelete = false; + /** + * 扫码登录过期时间 + */ + private Long codeCertificateTimeout = 180L; + /** + * 逻辑删除字段 + */ + private String logicDeleteColumn = TableFieldsNameConst.F_DELETE_MARK; + /** + * 版本 + */ + private String softVersion; + /** + * 推送是否启动:false、true + */ + private String igexinEnabled; + /** + * APPID + */ + private String igexinAppid; + /** + * APPKEY + */ + private String igexinAppkey; + /** + * MASTERSECRET + */ + private String igexinMastersecret; + + private String appUpdateContent; + private String appVersion; + + /** + * pc端服务器域名 + */ + private String frontDomain; + + /** + * app端服务器域名 + */ + private String appDomain; + + /** + * 服务器域名 + */ + private String apiDomain; + + /** + * 工作流域名 + */ + private String flowDomain; + + /** + * 检查PDF文件安全 + */ + private boolean checkFilePdf; + + /** + * -------------跨域配置----------- + */ + // @Value("${config.Origins}") + // private String origins; + // @Value("${config.Methods}") + // private String methods; + + /** + * -------------是否开启测试环境,admin账户可以无限登陆,并且无法修改密码----------- + */ + private String testVersion; + + /** + * -------------uniPush在线----------- + */ + private String appPushUrl; + + public String getMultiTenancyOfficialLoginCodeUrl() { + if (multiTenancyOfficialLoginCodeUrl == null) { + if (StringUtil.isNotEmpty(multiTenancyUrl)) { + UrlBuilder urlBuilder1 = UrlBuilder.of(multiTenancyUrl); + multiTenancyOfficialLoginCodeUrl = String.format("%s://%s:%s/api/Saas/Tenant/LoginSmsCodeCheck/", + urlBuilder1.getSchemeWithDefault(), urlBuilder1.getHost(), urlBuilder1.getPortWithDefault()); + } else { + multiTenancyOfficialLoginCodeUrl = ""; + } + } + return multiTenancyOfficialLoginCodeUrl; + } + + public String getMultiTenancyOfficialResetCodeUrl() { + if (multiTenancyOfficialResetCodeUrl == null) { + if (StringUtil.isNotEmpty(multiTenancyUrl)) { + UrlBuilder urlBuilder1 = UrlBuilder.of(multiTenancyUrl); + multiTenancyOfficialResetCodeUrl = String.format( + "%s://%s:%s/api/Saas/Tenant/ResetPasswordSmsCodeCheck/", urlBuilder1.getSchemeWithDefault(), + urlBuilder1.getHost(), urlBuilder1.getPortWithDefault()); + } else { + multiTenancyOfficialResetCodeUrl = ""; + } + } + return multiTenancyOfficialResetCodeUrl; + } + + public String getServiceDirectoryPath() { + String folder = StringUtil.isNotEmpty(serviceDirectoryPath) ? serviceDirectoryPath + : ConfigConst.CODE_TEMP_FOLDER; + return getXssPath(folder + "/"); + } + + public String getDataBackupFilePath() { + String folder = StringUtil.isNotEmpty(dataBackupFilePath) ? dataBackupFilePath : ConfigConst.DATA_BACKUP_FOLDER; + return getXssPath(folder + "/"); + } + + public String getTemporaryFilePath() { + String folder = StringUtil.isNotEmpty(temporaryFilePath) ? temporaryFilePath : ConfigConst.TEMPORARY_FOLDER; + return getXssPath(folder + "/"); + } + + public String getSystemFilePath() { + String folder = StringUtil.isNotEmpty(systemFilePath) ? systemFilePath : ConfigConst.SYSTEM_FOLDER; + return getXssPath(folder + "/"); + } + + public String getTemplateFilePath() { + String folder = StringUtil.isNotEmpty(templateFilePath) ? templateFilePath : ConfigConst.TEMPLATE_FOLDER; + return getXssPath(folder + "/"); + } + + public String getTemplateCodePath() { + String folder = StringUtil.isNotEmpty(templateCodePath) ? templateCodePath : ConfigConst.TEMPLATE_CODE_FOLDER; + return getXssPath(folder + "/"); + } + + public String getTemplateCodePathVue3() { + String folder = StringUtil.isNotEmpty(templateCodePathVue3) ? templateCodePathVue3 + : ConfigConst.TEMPLATEVUE3_CODE_FOLDER; + return getXssPath(folder + "/"); + } + + public String getEmailFilePath() { + String folder = StringUtil.isNotEmpty(emailFilePath) ? emailFilePath : ConfigConst.EMAIL_FOLDER; + return getXssPath(folder + "/"); + } + + public String getDocumentPreviewPath() { + String folder = StringUtil.isNotEmpty(documentPreviewPath) ? documentPreviewPath + : ConfigConst.DOCUMENT_PREVIEW_FOLDER; + return getXssPath(folder + "/"); + } + + public String getUserAvatarFilePath() { + String folder = StringUtil.isNotEmpty(userAvatarFilePath) ? userAvatarFilePath : ConfigConst.USER_AVATAR_FOLDER; + return getXssPath(folder + "/"); + } + + public String getImContentFilePath() { + String folder = StringUtil.isNotEmpty(imContentFilePath) ? imContentFilePath : ConfigConst.IM_CONTENT_FOLDER; + return getXssPath(folder + "/"); + } + + public String getDocumentFilePath() { + String folder = StringUtil.isNotEmpty(documentFilePath) ? documentFilePath : ConfigConst.DOCUMENT_FOLDER; + return getXssPath(folder + "/"); + } + + public String getWebAnnexFilePath() { + String folder = StringUtil.isNotEmpty(webAnnexFilePath) ? webAnnexFilePath : ConfigConst.WEB_ANNEX_FOLDER; + return getXssPath(folder + "/"); + } + + public String getBiVisualPath() { + String folder = StringUtil.isNotEmpty(biVisualPath) ? biVisualPath : ConfigConst.BI_VISUAL_FOLDER; + return getXssPath(folder + "/"); + } + + public String getBaseLanguagePath() { + String folder = StringUtil.isNotEmpty(baseLanguagePath) ? baseLanguagePath : ConfigConst.BASE_LANGUAGE; + return getXssPath(folder + "/"); + } + + private String getXssPath(String path) { + String xssPath = XSSEscape.escapePath(path); + return xssPath; + } + + public void setMultiTenantIgnoreTable(List multiTenantIgnoreTable) { + initMultiTenantIgnoreTable(); + this.multiTenantIgnoreTable.addAll(multiTenantIgnoreTable); + // 全部转小写, 对比时也转小写 + this.multiTenantIgnoreTable = this.multiTenantIgnoreTable.stream().map(String::toLowerCase) + .collect(Collectors.toList()); + } + + public List getMultiTenantIgnoreTable() { + return new ArrayList<>(this.multiTenantIgnoreTable); + } + + private List initMultiTenantIgnoreTable() { + List multiTenantIgnoreTable = this.multiTenantIgnoreTable; + if (multiTenantIgnoreTable == null) { + multiTenantIgnoreTable = new ArrayList<>(); + } else { + multiTenantIgnoreTable.clear(); + } + multiTenantIgnoreTable.add("dual"); + return multiTenantIgnoreTable; + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/CoreAutoConfiguration.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/CoreAutoConfiguration.java new file mode 100644 index 0000000..642f48c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/config/CoreAutoConfiguration.java @@ -0,0 +1,75 @@ +package com.yunzhupaas.config; + +import cn.hutool.http.useragent.*; +import com.yunzhupaas.i18n.config.I18nProperties; +import com.yunzhupaas.properties.GatewayWhite; +import com.yunzhupaas.properties.MvcSecurityProperties; +import com.yunzhupaas.properties.SecurityProperties; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +@Configuration(proxyBeanMethods = false) +public class CoreAutoConfiguration implements InitializingBean { + + + @Bean + @ConditionalOnMissingBean + @ConfigurationProperties(prefix = GatewayWhite.PREFIX) + public GatewayWhite getGateWhite(){ + return new GatewayWhite(); + } + + @Bean + @ConditionalOnMissingBean + @ConfigurationProperties(prefix = SecurityProperties.PREFIX) + public SecurityProperties getSecurityProperties(){ + return new SecurityProperties(); + } + + @Bean + @ConditionalOnMissingBean + @ConfigurationProperties(prefix = ConfigValueUtil.PREFIX) + public ConfigValueUtil getConfigValueUtil(){ + return new ConfigValueUtil(); + } + + @Bean + @Primary + @ConfigurationProperties(prefix = "spring.messages") + public I18nProperties getI18nProperties(){ + return new I18nProperties(); + } + + @Bean + @ConditionalOnMissingBean + @ConfigurationProperties(prefix = MvcSecurityProperties.PREFIX) + public MvcSecurityProperties getCorsProperties(){ + return new MvcSecurityProperties(); + } + + @Bean + public ApplicationStartErrorCheck getApplicationStartupErrorCheck(){ + return new ApplicationStartErrorCheck(); + } + + @Override + public void afterPropertiesSet() { + // UserAgent + initUserAgent(); + } + + private void initUserAgent(){ + // Harmony 鸿蒙OS + OS.addCustomOs("OpenHarmony", "OpenHarmony", "OpenHarmony\\s+(\\d+([._]\\d+)*)"); + // 鸿蒙OS移动端 + Platform platform = new Platform("OpenHarmony", "Phone;\\s*OpenHarmony\\s*"); + Platform.mobilePlatforms.add(platform); + Platform.platforms.add(platform); + Browser.browers.add(0, new Browser("OpenHarmony", "Phone;\\s*OpenHarmony.*ArkWeb", "ArkWeb\\/([\\d\\w\\.\\-]+)")); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/ConfigConst.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/ConfigConst.java new file mode 100644 index 0000000..fcaf9bb --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/ConfigConst.java @@ -0,0 +1,87 @@ +package com.yunzhupaas.constant; + +/** + * 配置静态参数 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/12/15 + */ +public class ConfigConst { + + /** + * 前端附件文件夹 + */ + public final static String WEB_ANNEX_FOLDER = "WebAnnexFile"; + + /** + * 临时文件夹 + */ + public final static String TEMPORARY_FOLDER = "TemporaryFile"; + + /** + * 系统文件夹 + */ + public final static String SYSTEM_FOLDER = "SystemFile"; + + /** + * 文件模板文件夹 + */ + public final static String TEMPLATE_FOLDER = "TemplateFile"; + + /** + * 邮件文件夹 + */ + public final static String EMAIL_FOLDER = "EmailFile"; + + /** + * 文档管理文件夹 + */ + public final static String DOCUMENT_FOLDER = "DocumentFile"; + + /** + * 文档预览文件夹 + */ + public final static String DOCUMENT_PREVIEW_FOLDER = "DocumentPreview"; + + /** + * 用户头像文件夹 + */ + public final static String USER_AVATAR_FOLDER = "UserAvatar"; + + /** + * IM聊天图片+语音存储文件夹 + */ + public final static String IM_CONTENT_FOLDER = "IMContentFile"; + + /** + * 代码模板文件夹 + */ + public final static String TEMPLATE_CODE_FOLDER = "TemplateCode"; + /** + * vue3代码模板文件夹 + */ + public final static String TEMPLATEVUE3_CODE_FOLDER = "TemplateCodeVue3"; + + /** + * 大屏图片文件夹 + */ + public final static String BI_VISUAL_FOLDER = "BiVisualPath"; + + /** + * 数据库备份文件夹 + */ + public final static String DATA_BACKUP_FOLDER = "DataBackupFile"; + + /** + * 前端模板文件夹 + */ + public final static String CODE_TEMP_FOLDER = "CodeTemp"; + + /** + * 多语言文件夹 + */ + public final static String BASE_LANGUAGE = "Language"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/DataInterfaceVarConst.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/DataInterfaceVarConst.java new file mode 100644 index 0000000..082717c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/DataInterfaceVarConst.java @@ -0,0 +1,88 @@ +package com.yunzhupaas.constant; + +/** + * 接口数据配置系统变量 + * + * @author 云筑产品开发平台组 + * @version V3.4.2 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024/6、29 + */ +public class DataInterfaceVarConst { + + /** + * 当前用户 + */ + public static final String USER = "@userId"; + /** + * 当前用户及下属 + */ + public static final String USERANDSUB = "@userAndSubordinates"; + /** + * 当前组织 + */ + public static final String ORG = "@organizeId"; + /** + * 当前组织及子组织 + */ + public static final String ORGANDSUB = "@organizationAndSuborganization"; + /** + * 当前分管组织 + */ + public static final String CHARORG = "@branchManageOrganize"; + + /** + * 页行数 + */ + public static final String PAGESIZE = "@pageSize"; + /** + * 关键字 + */ + public static final String KEYWORD = "@keyword"; + /** + * 当前页 + */ + public static final String CURRENTPAGE = "@currentPage"; + /** + * 条数 + */ + public static final String OFFSETSIZE = "@offsetSize"; + /** + * 当前分管组织及子组织 + */ + public static final String SHOWKEY = "@showKey"; + /** + * 当前分管组织及子组织 + */ + public static final String SHOWVALUE = "@showValue"; + /** + * 生成雪花id + */ + public static final String ID = "@snowFlakeID"; + /** + * 每次生成新的雪花id + */ + public static final String ID_LOT = "@lotSnowID"; + /** + * 表单id + */ + public static final String FORM_ID = "@formId"; + /** + * 当前岗位 + */ + public static final String POSITIONID = "@positionId"; + /** + * 当前部门 + */ + public static final String DEPID = "@depId"; + + /** + * 当前部门及下级部门 + */ + public static final String DEPANDSUBORDINATES = "@depAndSubordinates"; + /** + * 当前时间 + */ + public static final String CURRENTTIME = "@currentTime"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/DbSensitiveConstant.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/DbSensitiveConstant.java new file mode 100644 index 0000000..0924938 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/DbSensitiveConstant.java @@ -0,0 +1,33 @@ +package com.yunzhupaas.constant; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 数据库敏感词 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-01-12 + */ +@Data +public class DbSensitiveConstant { + + /** + * 数据库敏感词 + * INSERT,DELETE,UPDATE 不为敏感字 + */ + public static final String SENSITIVE = "CREATE,UNIQUE,CHECK,DEFAULT,DROP,INDEX,ALTER,TABLE,VIEW"; + + /** + * 数据库敏感词 + * INSERT,DELETE,UPDATE 不为敏感字 + */ + public static final String PRINT_SENSITIVE = SENSITIVE + ",INSERT,DELETE,UPDATE"; + + /** + * 文件路径敏感词 + */ + public static final String FILE_SENSITIVE = "<,>,/,\\\\,:,|"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/DsKeyConst.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/DsKeyConst.java new file mode 100644 index 0000000..57db4f0 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/DsKeyConst.java @@ -0,0 +1,36 @@ +package com.yunzhupaas.constant; + +import java.util.ArrayList; +import java.util.List; + +/** + * 数据集参数类型常量 + * + * @author 云筑产品开发平台组 + * @version v5.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/9/13 16:15:14 + */ +public class DsKeyConst { + public static final String TEXT = "text"; + public static final String DOUBLE = "double"; + public static final String BIGINT = "bigint"; + public static final String DATE = "date"; + public static final String TIME = "time"; + + public static final List DateSelect = new ArrayList() { + { + add(DATE); + add(TIME); + } + }; + + public static final List BetweenSelect = new ArrayList() { + { + add(DATE); + add(TIME); + add(BIGINT); + add(DOUBLE); + } + }; +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/EventConst.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/EventConst.java new file mode 100644 index 0000000..fa4accf --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/EventConst.java @@ -0,0 +1,11 @@ +package com.yunzhupaas.constant; + +/** + * 事件常量 + */ +public class EventConst { + + public static final String EVENT_USER_LOGIN = "user_login"; + public static final String EVENT_INIT_LOGIN_PERMISSION = "init_login_permission"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/FileTypeConstant.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/FileTypeConstant.java new file mode 100644 index 0000000..6f2c7f6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/FileTypeConstant.java @@ -0,0 +1,96 @@ +package com.yunzhupaas.constant; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +public class FileTypeConstant { + /** + * 用户头像存储路径 + */ + public static final String USERAVATAR = "useravatar"; + /** + * 邮件文件存储路径 + */ + public static final String MAIL = "mail"; + /** + * IM聊天图片+语音存储路径 + */ + public static final String IM = "im"; + /** + *临时文件存储路径 + */ + public static final String WORKFLOW="workflow"; + /** + *前端附件文件目录 + */ + public static final String ANNEX="annex"; + public static final String ANNEXPIC="annexpic"; + /** + *数据库备份文件路径 + */ + public static final String DATABACKUP="dataBackup"; + /** + *文档管理存储路径 + */ + public static final String DOCUMENT="document"; + /** + *临时文件存储路径 + */ + public static final String TEMPORARY="temporary"; + /** + *允许上传文件类型 + */ + public static final String ALLOWUPLOADFILETYPE="allowuploadfiletype"; + /** + *文件在线预览存储pdf + */ + public static final String DOCUMENTPREVIEWPATH="preview"; + /** + *文件模板存储路径 + */ + public static final String TEMPLATEFILE="templatefile"; + /** + *前端文件目录 + */ + public static final String SERVICEDIRECTORY="servicedirectory"; + /** + *后端文件目录 + */ + public static final String WEBDIRECTORY="webdirectory"; + /** + * 代码生成器生成位置 + */ + public static final String CODETEMP = "codetemp"; + /** + * 导出 + */ + public static final String EXPORT = "export"; + /** + * 文件预览 + */ + public static final String DOCUMENTPREVIEW = "documentpreview"; + /** + * 大屏路径 + */ + public static final String BIVISUALPATH = "bivisualpath"; + + /** + * 初始化模板 + */ + public static final String TEMPLATECODEPATH = "templatecodepath"; + + /** + * 报表路径 + */ + public static final String REPORTPATH = "reportfile"; + + /** + * 文件zip打包下载临时文件路径 + */ + public static final String FILEZIPDOWNTEMPPATH = "filezipdownloadtemppath"; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/GenerateConstant.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/GenerateConstant.java new file mode 100644 index 0000000..5bbd277 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/GenerateConstant.java @@ -0,0 +1,380 @@ +package com.yunzhupaas.constant; + +import com.yunzhupaas.util.StringUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author 云筑产品开发平台组 + * @version V3.5.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024/5/31 + */ +public class GenerateConstant { + + /** + * 作者 + */ + public static final String AUTHOR = "云筑产品开发平台组"; + + /** + * 版本 + */ + public static final String VERSION = "V5.2.0"; + + /** + * 版权 + */ + public static final String COPYRIGHT = "深圳市乐程软件有限公司(http://www.szlecheng.cn)"; + + /** + * 描述 + */ + public static final String DESCRIPTION = ""; + + /** + * 文件本地服务器标识 + */ + public static final String LOCAL = "local"; + /** + * 系统配置信息key + */ + public static final String SYSCONFIG = "SysConfig"; + // 文件名前缀 + /** + * 实体后缀 + */ + public static final String ENTITY = "Entity"; + + /** + * Mapper XML后缀 + */ + public static final String MAPPER_XML = "Mapper"; + + /** + * Mapper后缀 + */ + public static final String MAPPER = "Mapper"; + + /** + * Service后缀 + */ + public static final String SERVICE = "Service"; + + /** + * SERVICEIMPL后缀 + */ + public static final String SERVICEIMPL = "ServiceImpl"; + + /** + * controller后缀 + */ + public static final String CONTROLLER = "Controller"; + + /** + * 包名 + */ + public static final String PACKAGE_NAME = "com.yunzhupaas"; + + /** + * 系统关键字 + */ + public static final List SYS_KEYWORD = Arrays.asList("tenantid", "id", "foreignid", "flowid", "flowtaskid", + "deleteuserid", "deletetime", "deletemark", + "version", "tenant_id", "foreign_id", "flow_id", "flow_task_id", "delete_user_id", "delete_time", + "delete_mark", "f_tenant_id", "f_id", "f_foreign_id", + "f_flow_id", "f_flow_task_id", "f_delete_user_id", "f_delete_time", "f_delete_mark", "f_version"); + /** + * JAVA关键字 + */ + public static final List JAVA_KEYWORD = Arrays.asList("abstract", "boolean", "break", "byte", "catch", + "char", "class", "continue", "default", "do", "double", + "else", "extends", "final", "finally", "float", "for", "if", "implements", "import", "instanceof", "int", + "interface", "long", "native", "new", "null", + "package", "private", "protected", "public", "short", "static", "super", "switch", "synchronized", "this", + "throw", "throws", "transient", "try", "void", + "volatile", "while"); + /** + * 数据库关键字 + */ + public static final List SQL_KEYWORD = Arrays.asList("abort", "abs", "absent", "absolute", "abstract", + "access", "accessed", "accessible", "according", "account", "across", "action", "activate", "ada", "add", + "admin", "administer", "administrator", "advanced", "advise", "advisor", "after", "against", "aggregate", + "algorithm", "alias", "all", "all_rows", "allocate", "allow", "allow_datetime", "allow_ip", "also", "alter", + "always", "analyse", "analyze", "ancillary", "and", "and_equal", "antijoin", "any", "append", "apply", + "apr", "archive", "archivedir", "archivelog", "archivestyle", "are", "array", "array_agg", + "array_max_cardinality", "arraylen", "as", "asc", "ascii", "asensitive", "asin", "assertion", "assign", + "assignment", "associate", "asymmetric", "asynchronous", "at", "atach", "atan", "atomic", "attach", + "attribute", "attributes", "audit", "aug", "authenticated", "authentication", "authid", "authorization", + "auto", "auto_increment", "autoallocate", "autoextend", "autoextend_size", "automatic", + "autonomous_transaction", "availability", "avg", "avg_row_length", "backed", "backup", "backupdir", + "backupinfo", "backupset", "backward", "badfile", "bakfile", "base", "base64", "batch", "become", "before", + "begin", "begin_frame", "begin_partition", "behalf", "bernoulli", "between", "bfile", "bigdatediff", + "bigfile", "bigint", "binary", "binary_double", "binary_double_infinity", "binary_double_nan", + "binary_float", "binary_float_infinity", "binary_float_nan", "binding", "binlog", "bit", "bit_length", + "bitmap", "bits", "bitvar", "blob", "block", "block_range", "blocked", "blocks", "blocksize", "body", "bom", + "bool", "boolean", "both", "bound", "branch", "breadth", "break", "broadcast", "browse", "bstring", "btree", + "buffer", "buffer_cache", "buffer_pool", "build", "bulk", "by", "byday", "byhour", "byminute", "bymonth", + "bymonthday", "bypass_recursive_check", "bypass_ujvc", "bysecond", "byte", "byweekno", "byyearday", "cache", + "cache_cb", "cache_instances", "cache_temp_table", "calculate", "call", "called", "cancel", "cardinality", + "cascade", "cascaded", "case", "cast", "catalog", "catalog_name", "catch", "category", "ceil", "ceiling", + "certificate", "cfile", "chain", "chained", "chaining", "change", "changed", "channel", "char", "char_cs", + "char_length", "character", "character_length", "character_set_catalog", "character_set_name", + "character_set_schema", "characteristics", "characters", "charset", "check", "checked", "checkpoint", + "checksum", "child", "choose", "chunk", "cipher", "civ_gb", "class", "class_origin", "classifies", "clear", + "client", "clob", "clone", "close", "close_cached_open_cursors", "cluster", "clusterbtr", "clustered", + "clustering_factor", "coalesce", "coarse", "cobol", "code", "collate", "collation", "collation_catalog", + "collation_name", "collation_schema", "collect", "collections_get_refs", "column", "column_format", + "column_name", "column_stats", "column_value", "columns", "command_function", "command_function_code", + "comment", "comments", "commit", "committed", "commitwork", "compact", "compatibility", "compile", + "complete", "completion", "composite_limit", "compress", "compressed", "compression", "compute", "concat", + "concurrent", "concurrently", "condition", "condition_number", "conditional", "configuration", "conflict", + "conforming", "connect", "connect_by_iscycle", "connect_by_isleaf", "connect_by_root", "connect_idle_time", + "connect_time", "connection", "connection_name", "consider", "consistent", "const", "constant", + "constraint", "constraint_catalog", "constraint_name", "constraint_schema", "constraints", "constructor", + "container", "contains", "containstable", "content", "contents", "context", "continue", "control", + "controlfile", "conversion", "convert", "copy", "corr", "corresponding", "corrupt", "corruption", "cos", + "cosh", "cost", "count", "counter", "covar_pop", "covar_samp", "cpu", "cpu_costing", "cpu_per_call", + "cpu_per_session", "create", "create_stored_outlines", "createdb", "createuser", "cross", "crypto", "csv", + "ctlfile", "cube", "cube_gb", "cume_dist", "cumulative", "current", "current_catalog", "current_date", + "current_default_transform_group", "current_path", "current_role", "current_row", "current_schema", + "current_time", "current_timestamp", "current_transform_group_for_type", "current_user", "cursor", + "cursor_name", "cursor_sharing_exact", "cursor_specific_segment", "cycle", "daily", "dangling", "data", + "database", "databases", "datafile", "datafiles", "datalink", "dataobjno", "date", "date_mode", "dateadd", + "datediff", "datepart", "datetime", "datetime_interval_code", "datetime_interval_precision", "day", + "day_hour", "day_microsecond", "day_minute", "day_second", "db", "dba", "dba_recyclebin", "dbcc", "dbfile", + "dbtimezone", "ddl", "ddl_clone", "deallocate", "debug", "dec", "decfloat", "decimal", "declare", "decode", + "decrement", "default", "default_auth", "defaults", "deferrable", "deferred", "define", "defined", + "definer", "degree", "delay", "delay_key_write", "delayed", "delete", "deleting", "delimited", "delimiter", + "delimiters", "delta", "demand", "dense_rank", "deny", "depends", "depth", "deref", "deref_no_rewrite", + "derived", "des_key_file", "desc", "describe", "descriptor", "destroy", "destructor", "detach", "detached", + "determines", "deterministic", "device", "diagnostics", "dictionary", "dimension", "directory", "disable", + "disassociate", "discard", "disconnect", "disk", "diskgroup", "disks", "diskspace", "dismount", "dispatch", + "distinct", "distinctrow", "distinguished", "distributed", "div", "dlnewcopy", "dlpreviouscopy", + "dlurlcomplete", "dlurlcompleteonly", "dlurlcompletewrite", "dlurlpath", "dlurlpathonly", "dlurlpathwrite", + "dlurlscheme", "dlurlserver", "dlvalue", "dml", "dml_update", "do", "document", "domain", + "domain_index_no_sort", "domain_index_sort", "double", "down", "downgrade", "driving_site", "drop", "dual", + "dump", "dumpfile", "duplicate", "dynamic", "dynamic_function", "dynamic_function_code", "dynamic_sampling", + "dynamic_sampling_est_cdn", "each", "editionable", "element", "else", "elseif", "elsif", "empty", "enable", + "enclosed", "encoding", "encrypt", "encrypted", "encryption", "end", "end_frame", "end_partition", + "end-exec", "ends", "enforce", "enforced", "engine", "engines", "entry", "enum", "equ", "equals", "errlvl", + "error", "error_on_overlap_time", "errors", "escape", "escaped", "estimate", "event", "eventinfo", "events", + "every", "except", "exception", "exception_init", "exceptions", "exchange", "exclude", "excluding", + "exclusive", "exec", "execute", "exempt", "existing", "exists", "exit", "exp", "expand_gset_to_union", + "expansion", "expire", "explain", "explosion", "export", "expr_corr_check", "expression", "extend", + "extended", "extends", "extension", "extent", "extent_size", "extents", "extern", "external", "externally", + "extract", "fact", "failed", "failed_login_attemps", "failed_login_attempts", "failgroup", "family", "fast", + "faults", "fbtscan", "feb", "fetch", "fic_civ", "fic_piv", "fields", "file", "file_block_size", "filegroup", + "filesize", "fillfactor", "filter", "final", "finally", "fine", "finish", "first", "first_rows", + "first_value", "fixed", "flag", "flagger", "flashback", "float", "float4", "float8", "flob", "floor", + "flush", "following", "follows", "for", "forall", "force", "force_xml_query_rewrite", "foreign", + "foreign key", "format", "fortran", "forward", "found", "frame_row", "free", "freelist", "freelists", + "freepools", "freetext", "freetexttable", "freeze", "freq", "frequence", "fresh", "fri", "from", "fs", + "fulfill", "full", "full join", "fulltext", "fulltexttable", "fully", "function", "functions", "fusion", + "gather_plan_statistics", "gby_conc_rollup", "general", "generated", "geometry", "geometrycollection", + "get", "get_format", "gight", "global", "global_name", "global_topic_enabled", "globally", "go", "goto", + "grant", "granted", "grants", "great", "greatest", "group", "group by", "group_by", "group_replication", + "grouping", "groups", "guarantee", "guaranteed", "guard", "handler", "hash", "hash_aj", "hash_sj", + "hashkeys", "hashpartmap", "having", "header", "heap", "help", "hex", "hextoraw", "hierarchy", "high", + "high_priority", "hintset_begin", "hintset_end", "hold", "holdlock", "host", "hosts", "hour", + "hour_microsecond", "hour_minute", "hour_second", "hourly", "huge", "hwm_brokered", "id", "identified", + "identifier", "identity", "identity_insert", "identitycol", "idgenerators", "idle_time", "if", "ifnull", + "ignore", "ignore_on_clause", "ignore_optim_embedded_hints", "ignore_row_on_dupkey_index", + "ignore_server_ids", "ignore_where_clause", "ilike", "image", "immediate", "immediately", "immutable", + "implementation", "implicit", "import", "in", "in_memory_metadata", "include", "include_version", + "including", "increase", "increment", "incremental", "indent", "index", "index_asc", "index_combine", + "index_desc", "index_ffs", "index_filter", "index_join", "index_rows", "index_rrs", "index_scan", + "index_skip_scan", "index_ss", "index_ss_asc", "index_ss_desc", "index_stats", "indexed", "indexes", + "indextype", "indextypes", "indicator", "indices", "infile", "infinite", "informational", "inherit", + "inherits", "initial", "initial_size", "initialize", "initialized", "initially", "initrans", "inline", + "inner", "inner join", "innerid", "inout", "input", "insensitive", "insert", "insert_method", "inserting", + "install", "instance", "instances", "instantiable", "instantly", "instead", "int", "int1", "int2", "int3", + "int4", "int8", "integer", "integrity", "intent", "intermediate", "internal_convert", "internal_use", + "interpreted", "intersect", "intersection", "interval", "into", "invalidate", "invisible", "invoker", "io", + "io_after_gtids", "io_before_gtids", "io_thread", "ipc", "is", "isnull", "isolation", "isolation_level", + "issuer", "iterate", "iteration_number", "jan", "java", "job", "join", "json", "json_array", + "json_arrayagg", "json_exists", "json_object", "json_objectagg", "json_query", "json_table", + "json_table_primitive", "json_value", "jul", "jun", "keep", "kerberos", "key", "key_block_size", + "key_length", "key_member", "key_type", "keyfile", "keys", "keysize", "kill", "label", "lag", "language", + "large", "last", "last_value", "lateral", "lax", "layer", "ldap_reg_sync_interval", "ldap_registration", + "ldap_registration_enabled", "lead", "leading", "leakproof", "least", "leave", "leaves", "left", + "left join", "length", "less", "level", "levels", "lexer", "library", "like", "like_expand", "like_regex", + "like2", "like4", "likec", "limit", "linear", "lineno", "lines", "linestring", "link", "list", "listagg", + "listen", "ln", "lnnvl", "load", "lob", "local", "local_indexes", "local_object", "locally", "localtime", + "localtimestamp", "location", "locator", "lock", "locked", "locks", "log", "log10", "logfile", "logged", + "logging", "logical", "logical_reads_per_call", "logical_reads_per_session", "login", "logoff", "logon", + "logout", "logs", "long", "longblob", "longtext", "longvarbinary", "longvarchar", "loop", "low_priority", + "lower", "lsn", "main", "manage", "managed", "management", "manual", "map", "mapped", "mapping", "mar", + "master", "master_auto_position", "master_bind", "master_connect_retry", "master_delay", + "master_heartbeat_period", "master_host", "master_log_file", "master_log_pos", "master_password", + "master_port", "master_retry_count", "master_server_id", "master_ssl", "master_ssl_ca", "master_ssl_capath", + "master_ssl_cert", "master_ssl_cipher", "master_ssl_crl", "master_ssl_crlpath", "master_ssl_key", + "master_ssl_verify_server_cert", "master_tls_version", "master_user", "match", "match_number", + "match_recognize", "matched", "matches", "materialize", "materialized", "max", "max_connections_per_hour", + "max_queries_per_hour", "max_rows", "max_run_duration", "max_size", "max_statement_time", + "max_updates_per_hour", "max_user_connections", "maxarchlogs", "maxdatafiles", "maxextents", "maximize", + "maxinstances", "maxlogfiles", "maxloghistory", "maxlogmembers", "maxpiecesize", "maxsize", "maxtrans", + "maxvalue", "may", "measures", "medium", "mediumblob", "mediumint", "mediumtext", "mem_space", "member", + "memory", "merge", "merge_aj", "merge_const_on", "merge_sj", "message_length", "message_octet_length", + "message_text", "method", "micro", "microsecond", "middleint", "migrate", "min", "min_rows", "minextents", + "minimize", "minimum", "minus", "minute", "minute_microsecond", "minute_second", "minutely", "minvalue", + "mirror", "mlslabel", "mod", "mode", "model", "model_dontverify_uniqueness", "model_min_analysis", + "model_no_analysis", "model_pby", "model_push_ref", "modifies", "modify", "module", "mon", "money", + "monitoring", "month", "monthly", "more", "mount", "move", "movement", "multilinestring", "multipoint", + "multipolygon", "multiset", "mumps", "mutex", "mv_merge", "mysql_errno", "name", "named", "names", + "namespace", "nan", "national", "native", "natural", "nav", "nchar", "nchar_cs", "ncharacter", "nclob", + "ndb", "ndbcluster", "needed", "nested", "nested_table_fast_insert", "nested_table_get_refs", + "nested_table_id", "nested_table_set_refs", "nested_table_set_setid", "nesting", "network", "never", "new", + "next", "nfc", "nfd", "nfkc", "nfkd", "nil", "nl_aj", "nl_sj", "nls_calendar", "nls_characterset", + "nls_comp", "nls_currency", "nls_date_format", "nls_date_language", "nls_iso_currency", "nls_lang", + "nls_language", "nls_length_semantics", "nls_nchar_conv_excp", "nls_numeric_characters", "nls_sort", + "nls_special_chars", "nls_territory", "no", "no_access", "no_basetable_multimv_rewrite", "no_buffer", + "no_cpu_costing", "no_expand", "no_expand_gset_to_union", "no_fact", "no_filtering", "no_index", + "no_index_ffs", "no_index_ss", "no_merge", "no_model_push_ref", "no_monitoring", "no_multimv_rewrite", + "no_order_rollups", "no_parallel", "no_parallel_index", "no_partial_commit", "no_prune_gsets", + "no_push_pred", "no_push_subq", "no_qkn_buff", "no_query_transformation", "no_ref_cascade", "no_rewrite", + "no_semijoin", "no_set_to_join", "no_star_transformation", "no_stats_gsets", "no_swap_join_inputs", + "no_trigger", "no_unnest", "no_use_hash", "no_use_merge", "no_use_nl", "no_wait", "no_write_to_binlog", + "no_xml_query_rewrite", "noappend", "noarchivelog", "noaudit", "nobranch", "nocache", "nocheck", + "nocompress", "nocopy", "nocpu_costing", "nocycle", "node", "nodegroup", "nodelay", "noforce", + "noguarantee", "nologging", "nomapping", "nomaxvalue", "nominimize", "nominvalue", "nomonitoring", + "nonblocking", "nonclustered", "none", "noneditionable", "noorder", "nooverride", "noparallel", + "noparallel_index", "norely", "norepair", "noresetlogs", "noreverse", "norewrite", "normal", "normalize", + "normalized", "norowdependencies", "nosegment", "nosort", "nostrict", "noswitch", "not", + "not_allow_datetime", "not_allow_ip", "nothing", "notify", "notnull", "nov", "novalidate", "nowait", + "nth_value", "ntile", "null", "nullable", "nullif", "nulls", "number", "numeric", "nvarchar", "nvarchar2", + "object", "objno", "objno_reuse", "occurrences_regex", "oct", "octet_length", "octets", "of", "off", + "offline", "offset", "offsets", "oid", "oidindex", "oids", "old", "old_password", "omit", "on", "once", + "one", "online", "only", "opaque", "opaque_transform", "opaque_xcanonical", "opcode", "open", + "opendatasource", "openquery", "openrowset", "openxml", "operation", "operator", "opt_estimate", "optimal", + "optimize", "optimizer_costs", "optimizer_features_enable", "optimizer_goal", "option", "optionally", + "options", "or", "or_expand", "ora_rowscn", "order", "order by", "ordered", "ordered_predicates", + "ordering", "ordinality", "organization", "others", "out", "out_of_line", "outer", "outfile", "outline", + "output", "over", "overflow", "overflow_nomove", "overlaps", "overlay", "override", "overriding", "own", + "owned", "owner", "pack_keys", "package", "packages", "pad", "page", "parallel", "parallel_enable", + "parallel_index", "parameter", "parameter_mode", "parameter_name", "parameter_ordinal_position", + "parameter_specific_catalog", "parameter_specific_name", "parameter_specific_schema", "parameters", + "parent", "parity", "parms", "parse_gcol_expr", "parser", "partial", "partially", "partition", + "partition_hash", "partition_list", "partition_range", "partitioning", "partitions", "pascal", "pass", + "passing", "passthrough", "password", "password_grace_time", "password_life_time", "password_lock_time", + "password_policy", "password_reuse_max", "password_reuse_time", "password_verify_function", "past", "path", + "pattern", "pctfree", "pctincrease", "pctthreshold", "pctused", "pctversion", "pendant", "per", "percent", + "percent_rank", "percentile_cont", "percentile_disc", "performance", "period", "permanent", "permission", + "permute", "pfile", "phase", "physical", "pipe", "pipelined", "piv_gb", "piv_ssf", "pivot", "placing", + "plan", "plans", "pli", "pls_integer", "plsql_code_type", "plsql_debug", "plsql_optimize_level", + "plsql_warnings", "plugin", "plugin_dir", "plugins", "point", "policy", "polygon", "port", "portion", + "position", "position_regex", "post_transaction", "postfix", "power", "pq_distribute", "pq_map", "pq_nomap", + "pragma", "prebuilt", "precedes", "preceding", "precision", "prefix", "preorder", "prepare", "prepared", + "present", "preserve", "pretty", "primary", "primary key", "print", "prior", "private", "private_sga", + "privilege", "privileges", "proc", "procedural", "procedure", "procedures", "processlist", "profile", + "profiles", "program", "project", "protected", "protection", "proxy", "prune", "ptf", "public", + "publication", "purge", "push_pred", "push_subq", "px_granule", "qb_name", "quarter", "query", + "query_block", "query_rewrite_integrity", "queue", "queue_curr", "queue_rowp", "quick", "quiesce", "quota", + "quote", "quotes", "raid0", "raise", "raiserror", "random", "randomly", "range", "rank", "rapidly", "raw", + "rawtohex", "rba", "read", "read_only", "read_per_call", "read_per_session", "read_write", "readonly", + "reads", "readtext", "real", "reassign", "rebalance", "rebuild", "recheck", "reconfigure", "record", + "records", "records_per_block", "recover", "recoverable", "recovery", "recursive", "recycle", "recyclebin", + "redo_buffer_size", "redofile", "reduced", "redundancy", "redundant", "ref", "ref_cascade_cursor", + "reference", "referenced", "references", "referencing", "refresh", "regexp", "regexp_like", "register", + "regr_avgx", "regr_avgy", "regr_count", "regr_intercept", "regr_r2", "regr_slope", "regr_sxx", "regr_sxy", + "regr_syy", "reindex", "reject", "rekey", "related", "relational", "relative", "relay", "relay_log_file", + "relay_log_pos", "relay_thread", "relaylog", "release", "reload", "rely", "remote_mapped", "remove", + "rename", "reorganize", "repair", "repeat", "repeatable", "replace", "replay", "replica", "replicate", + "replicate_do_db", "replicate_do_table", "replicate_ignore_db", "replicate_ignore_table", + "replicate_rewrite_db", "replicate_wild_do_table", "replicate_wild_ignore_table", "replication", "require", + "required", "requiring", "reset", "resetlogs", "resignal", "resize", "resolve", "resolver", "resource", + "respect", "restart", "restore", "restore_as_intervals", "restrict", "restrict_all_ref_cons", + "restrict_references", "restricted", "result", "result_cache", "resumable", "resume", "retention", "return", + "returned_cardinality", "returned_length", "returned_octet_length", "returned_sqlstate", "returning", + "returns", "reuse", "reverse", "revert", "revoke", "rewrite", "rewrite_or_error", "right", "right join", + "rlike", "role", "roles", "rollback", "rollfile", "rollup", "root", "rotate", "round", "routine", + "routine_catalog", "routine_name", "routine_schema", "routines", "row", "row_count", "row_format", + "row_length", "row_number", "rowcount", "rowdependencies", "rowguidcol", "rowid", "rownum", "rows", "rtree", + "rule", "rules", "running", "salt", "sample", "sat", "save", "save_as_intervals", "savepoint", "sb4", + "sbyte", "scalar", "scale", "scale_rows", "scan", "scan_instances", "schedule", "scheduler", "schema", + "schema_name", "schemas", "scn", "scn_ascending", "scope", "scope_catalog", "scope_name", "scope_schema", + "scroll", "sd_all", "sd_inhibit", "sd_show", "sealed", "search", "second", "second_microsecond", "secondly", + "section", "security", "securityaudit", "seed", "seg_block", "seg_file", "segment", "select", "selective", + "selectivity", "self", "semijoin", "semijoin_driver", "sensitive", "sep", "separator", "sequence", + "sequenced", "sequences", "sequential", "sererr", "serial", "serializable", "server", "server_name", + "servererror", "session", "session_cached_cursors", "session_per_user", "session_user", "sessions_per_user", + "sessiontimezone", "sessiontzname", "set", "set_to_join", "setof", "sets", "settings", "setuser", "severe", + "share", "shared", "shared_pool", "short", "show", "shrink", "shutdown", "siblings", "sid", "signal", + "signed", "similar", "simple", "sin", "since", "single", "singletask", "sinh", "size", "sizeof", "skip", + "skip_ext_optimizer", "skip_unq_unusable_idx", "skip_unusable_indexes", "slave", "slow", "smallfile", + "smallint", "snapshot", "socket", "some", "soname", "sort", "sound", "sounds", "source", "space", "span", + "spatial", "specific", "specific_name", "specification", "specifictype", "speed", "spfile", "split", + "spreadsheet", "sql", "sql_after_gtids", "sql_after_mts_gaps", "sql_before_gtids", "sql_big_result", + "sql_buffer_result", "sql_cache", "sql_calc_found_rows", "sql_no_cache", "sql_small_result", "sql_thread", + "sql_trace", "sql_tsi_day", "sql_tsi_hour", "sql_tsi_minute", "sql_tsi_month", "sql_tsi_quarter", + "sql_tsi_second", "sql_tsi_week", "sql_tsi_year", "sqlca", "sqlcode", "sqlerror", "sqlexception", "sqlldr", + "sqlstate", "sqlwarning", "sqrt", "ssl", "stable", "stacked", "standalone", "standby", "star", + "star_transformation", "start", "starting", "starts", "startup", "stat", "state", "statement", + "statement_id", "static", "statistics", "stats_auto_recalc", "stats_persistent", "stats_sample_pages", + "status", "stddev", "stddev_pop", "stddev_samp", "stdin", "stdout", "stop", "storage", "store", "stored", + "straight_join", "streams", "strict", "string", "strip", "struct", "structure", "style", "subclass_origin", + "subject", "submultiset", "subpartition", "subpartition_rel", "subpartitions", "subscription", "subset", + "substitutable", "substring", "substring_regex", "subtype", "succeeds", "successful", "sum", "summary", + "sun", "super", "supplemental", "support", "suspend", "swap_join_inputs", "swaps", "switch", "switches", + "switchover", "symmetric", "sync", "synchronous", "synonym", "sys_connect_by_path", "sys_dl_cursor", + "sys_fbt_insdel", "sys_op_bitvec", "sys_op_cast", "sys_op_col_present", "sys_op_enforce_not_null$", + "sys_op_mine_value", "sys_op_noexpand", "sys_op_ntcimg$", "sys_parallel_txn", "sys_rid_order", "sysaux", + "sysdate", "sysdba", "sysid", "sysoper", "system", "system_time", "system_user", "systimestamp", "table", + "table_checksum", "table_name", "table_stats", "tables", "tablesample", "tablespace", "tablespace_no", + "tabno", "tan", "tanh", "task", "temp", "tempfile", "template", "temporary", "temptable", "terminate", + "terminated", "test", "text", "textsize", "than", "the", "then", "thread", "through", "throw", "thu", + "ties", "time", "time_zone", "timeout", "timer", "times", "timestamp", "timestampadd", "timestampdiff", + "timezone_abbr", "timezone_hour", "timezone_minute", "timezone_region", "tinyblob", "tinyint", "tinytext", + "tiv_gb", "tiv_ssf", "to", "token", "top", "top_level_count", "toplevel", "trace", "tracing", "tracking", + "trailing", "tran", "transaction", "transaction_active", "transactional", "transactions_committed", + "transactions_rolled_back", "transform", "transforms", "transitional", "translate", "translate_regex", + "translation", "treat", "trigger", "trigger_catalog", "trigger_name", "trigger_schema", "triggers", "trim", + "trim_array", "truncate", "truncsize", "trusted", "trxid", "try", "tsequal", "tue", "tuning", "tx", "type", + "typedef", "typeof", "types", "tz_offset", "ub2", "uba", "uescape", "uid", "uint", "ulong", "unarchived", + "unbound", "unbounded", "uncommitted", "unconditional", "undefined", "under", "undo", "undo_buffer_size", + "undofile", "undrop", "unencrypted", "unicode", "uniform", "uninstall", "union", "unique", "unknown", + "unlimited", "unlink", "unlisten", "unlock", "unlogged", "unmatched", "unnamed", "unnest", "unpacked", + "unpivot", "unprotected", "unquiesce", "unrecoverable", "unsigned", "until", "untyped", "unusable", + "unused", "up", "upd_indexes", "upd_joinindex", "updatable", "update", "updated", "updatetext", "updating", + "upgrade", "upper", "upsert", "uri", "urowid", "usage", "use", "use_anti", "use_concat", "use_frm", + "use_hash", "use_merge", "use_nl", "use_nl_with_index", "use_private_outlines", "use_semi", + "use_stored_outlines", "use_ttt_for_gsets", "use_weak_name_resl", "user", "user_defined", + "user_defined_type_catalog", "user_defined_type_code", "user_defined_type_name", "user_defined_type_schema", + "user_recyclebin", "user_resources", "ushort", "using", "utc_date", "utc_time", "utc_timestamp", "utf16", + "utf32", "utf8", "vacuum", "valid", "validate", "validation", "validator", "value", "value_of", "values", + "var_pop", "var_samp", "varbinary", "varchar", "varchar2", "varcharacter", "variable", "variables", + "variadic", "variance", "varray", "varying", "vector_read", "vector_read_trace", "verbose", "verify", + "version", "versioning", "versions", "versions_endtime", "versions_endtrxid", "versions_operation", + "versions_starttime", "versions_starttrxid", "vertical", "view", "views", "virtual", "visible", "void", + "volatile", "vsize", "wait", "waitfor", "warnings", "wed", "week", "weekly", "weight_string", "wellformed", + "when", "whenever", "where", "while", "whitespace", "width_bucket", "window", "with", "within", "without", + "work", "wrapped", "wrapper", "write", "writetext", "x_dyn_prune", "x509", "xa", "xid", "xml", "xmlagg", + "xmlattributes", "xmlbinary", "xmlcast", "xmlcolattval", "xmlcomment", "xmlconcat", "xmldeclaration", + "xmldocument", "xmlelement", "xmlexists", "xmlforest", "xmliterate", "xmlnamespaces", "xmlparse", "xmlpi", + "xmlquery", "xmlroot", "xmlschema", "xmlserialize", "xmltable", "xmltext", "xmltype", "xmlvalidate", "xor", + "year", "year_month", "yearly", "yes", "yunzhupaasfill", "zone", "false", "true"); + + /** + * 系统,语言,数据关键字 + */ + public static final List getAllKeyWord() { + List allKeyWord = new ArrayList<>(); + allKeyWord.addAll(SYS_KEYWORD); + allKeyWord.addAll(JAVA_KEYWORD); + allKeyWord.addAll(SQL_KEYWORD); + return allKeyWord; + } + + /** + * 系统,语言,数据关键字是否包含 + */ + public static final boolean containKeyword(String keyword) { + if (StringUtil.isEmpty(keyword)) { + return false; + } + List allKeyWord = getAllKeyWord(); + return allKeyWord.contains(keyword.toLowerCase()); + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/GlobalConst.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/GlobalConst.java new file mode 100644 index 0000000..dbbd848 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/GlobalConst.java @@ -0,0 +1,33 @@ +package com.yunzhupaas.constant; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +public class GlobalConst { + + /** + * 网关、Feign转发后携带原有HOST(网关或者FEIGN转发后HOST不准确) + */ + public static final String HEADER_HOST = "MY_HOST"; + + + /** + * 默认租户字段值 + */ + public static final String DEFAULT_TENANT_VALUE = "0"; + + public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + public static final String DEFAULT_CHARSET_STR = DEFAULT_CHARSET.name(); + + /** + * 默认语种 + */ + public static final String DEFAULT_LANGUAGE = "zh-CN"; + + /** + * 扫包路径 多个使用封号分割 + */ + public static final String PROJECT_SCAN_PACKAGES = "com.yunzhupaas"; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/ModuleName.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/ModuleName.java new file mode 100644 index 0000000..1a1f2d2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/ModuleName.java @@ -0,0 +1,32 @@ +package com.yunzhupaas.constant; + +/** + * 项目模块应用名称 + */ +public class ModuleName { + + public static final String SYSTEM_SERVER_NAME = "yunzhupaas-system" ; + + public static final String MESSAGE_SERVER_NAME = "yunzhupaas-message" ; + + public static final String VUSUALDEV_SERVER_NAME = "yunzhupaas-visualdev" ; + + public static final String EXAMPLE_SERVER_NAME = "yunzhupaas-example" ; + + public static final String EXTEND_SERVER_NAME = "yunzhupaas-extend" ; + + public static final String APP_SERVER_NAME = "yunzhupaas-app" ; + + public static final String WORKFLOW_SERVER_NAME = "yunzhupaas-workflow" ; + + public static final String FILE_SERVER_NAME = "yunzhupaas-file"; + + public static final String PERMISSION_SERVER_NAME = "yunzhupaas-permission"; + + public static final String FORM_SERVER_NAME = "yunzhupaas-flowForm"; + + public static final String OAUTH_SERVER_NAME = "yunzhupaas-oauth"; + + public static final String SCHEDULE_SERVER_NAME = "yunzhupaas-scheduletask" ; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/MsgCode.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/MsgCode.java new file mode 100644 index 0000000..90af152 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/MsgCode.java @@ -0,0 +1,740 @@ +package com.yunzhupaas.constant; + +import com.yunzhupaas.constant.model.MCode; + +/** + * 常用提示信息 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/12/20 + */ +public interface MsgCode { + /** + * 编码和提示语正则提取 MCode\s+[\w\d]+\s+=\s+[\w\d]+[(]"([\w\d]+)"\s*,\s*"(.+)"[)]; + */ + + /** + * 执行成功:SU(success) + */ + MCode SU000 = MSG("SU000", "Success"); + MCode SU001 = MSG("SU001", "新建成功"); + MCode SU002 = MSG("SU002", "保存成功"); + MCode SU003 = MSG("SU003", "删除成功"); + MCode SU004 = MSG("SU004", "更新成功"); + MCode SU005 = MSG("SU005", "操作成功"); + MCode SU006 = MSG("SU006", "提交成功,请耐心等待"); + MCode SU007 = MSG("SU007", "复制成功"); + MCode SU008 = MSG("SU008", "停止成功"); + MCode SU009 = MSG("SU009", "终止成功"); + MCode SU010 = MSG("SU010", "还原成功"); + MCode SU011 = MSG("SU011", "发布成功"); + MCode SU012 = MSG("SU012", "发送成功"); + MCode SU013 = MSG("SU013", "接口修改成功"); + MCode SU014 = MSG("SU014", "更新接口状态成功"); + MCode SU015 = MSG("SU015", "上传成功"); + MCode SU016 = MSG("SU016", "设置成功"); + MCode SU017 = MSG("SU017", "验证成功"); + MCode SU018 = MSG("SU018", "添加成功"); + MCode SU019 = MSG("SU019", "获取成功"); + MCode SU020 = MSG("SU020", "回滚成功"); + MCode SU021 = MSG("SU021", "移除成功"); + MCode SU022 = MSG("SU022", "查询成功"); + + /** + * 执行失败:FA(fail) + */ + MCode FA001 = MSG("FA001", "数据不存在"); + MCode FA002 = MSG("FA002", "更新失败,数据不存在"); + MCode FA003 = MSG("FA003", "删除失败,数据不存在"); + MCode FA004 = MSG("FA004", "复制失败,数据不存在"); + MCode FA005 = MSG("FA005", "发送失败,数据不存在"); + MCode FA006 = MSG("FA006", "下载失败,数据不存在"); + MCode FA007 = MSG("FA007", "操作失败,数据不存在"); + MCode FA008 = MSG("FA008", "停止失败,数据不存在"); + MCode FA009 = MSG("FA009", "终止失败,数据不存在"); + MCode FA010 = MSG("FA010", "还原失败,数据不存在"); + MCode FA011 = MSG("FA011", "发布失败,数据不存在"); + MCode FA012 = MSG("FA012", "获取失败,数据不存在"); + MCode FA013 = MSG("FA013", "接口修改失败,数据不存在"); + MCode FA014 = MSG("FA014", "更新接口状态失败,数据不存在"); + MCode FA015 = MSG("FA015", "预览失败,数据不存在"); + MCode FA016 = MSG("FA016", "删除失败,该文件夹存在数据"); + MCode FA017 = MSG("FA017", "文件格式不正确"); + MCode FA018 = MSG("FA018", "文件不存在"); + MCode FA019 = MSG("FA019", "已失效"); + MCode FA020 = MSG("FA020", "未查到信息"); + MCode FA021 = MSG("FA021", "操作失败!您没有权限操作"); + MCode FA022 = MSG("FA022", "更新失败!您没有权限操作 (角色只有超级管理员才能够操作)"); + MCode FA023 = MSG("FA023", "更新失败!已绑定用户,无法切换组织"); + MCode FA024 = MSG("FA024", "删除失败!已绑定用户"); + MCode FA025 = MSG("FA025", "该组织内权限为空,组织切换失败!"); + MCode FA031 = MSG("FA031", "该组织无本应用权限,切换失败"); + MCode FA026 = MSG("FA026", "更新失败,关联组织不存在,请重新登录,或者刷新页面"); + MCode FA027 = MSG("FA027", "该系统下菜单为空,系统切换失败"); + MCode FA028 = MSG("FA028", "新增数据失败"); + MCode FA029 = MSG("FA029", "修改数据失败"); + MCode FA030 = MSG("FA030", "更新失败!已绑定用户,无法修改状态"); + MCode FA032 = MSG("FA032", "上传文件不能为空"); + MCode FA033 = MSG("FA033", "文件上传失败!"); + MCode FA034 = MSG("FA034", "非法请求, 缺少认证信息"); + MCode FA035 = MSG("FA035", "未获取到租户指定数据源信息"); + MCode FA036 = MSG("FA036", "常用数据已存在"); + MCode FA037 = MSG("FA037", "接口请求失败"); + MCode FA038 = MSG("FA038", "文件存储路径错误"); + MCode FA039 = MSG("FA039", "链接已失效"); + MCode FA040 = MSG("FA040", "预览失败,请检查文件类型是否规范"); + MCode FA041 = MSG("FA041", "预览失败,请重新上传文件"); + MCode FA042 = MSG("FA042", "请输入正确的文件格式"); + MCode FA043 = MSG("FA043", "存在同名文件!"); + MCode FA044 = MSG("FA044", "不存在该文件"); + MCode FA045 = MSG("FA045", "删除文件:{0}失败"); + MCode FA046 = MSG("FA046", "文件读取失败"); + MCode FA047 = MSG("FA047", "未发现文件"); + MCode FA048 = MSG("FA048", "微信公众号原始id不能重复"); + MCode FA049 = MSG("FA049", "此记录与“消息发送配置”关联引用,不允许被禁用"); + MCode FA050 = MSG("FA050", "此记录与“消息发送配置”关联引用,不允许被删除"); + MCode FA051 = MSG("FA051", "接口已配置加密, 数据解密失败."); + MCode FA052 = MSG("FA052", "该身份未分配权限"); + MCode FA053 = MSG("FA053", "上传失败, 文件中包含不安全内容"); + + + /*======1 短语======*/ + MCode FA101 = MSG("FA101", "保存失败"); + MCode FA102 = MSG("FA102", "更新失败"); + MCode FA103 = MSG("FA103", "删除失败"); + MCode FA104 = MSG("FA104", "获取失败"); + MCode FA105 = MSG("FA105", "预览失败,请先保存在预览数据"); + MCode FA106 = MSG("FA106", "预览失败,单元格配置出现死循环"); + MCode FA107 = MSG("FA107", "报表导出报错"); + + + + /** + * 重名判断 + */ + MCode EXIST001 = MSG("EXIST001", "名称不能重复"); + MCode EXIST002 = MSG("EXIST002", "编码不能重复"); + MCode EXIST003 = MSG("EXIST003", "模板名已存在"); + MCode EXIST004 = MSG("EXIST004", "文件夹名称不能重复"); + MCode EXIST005 = MSG("EXIST005", "模板名称超过了限制长度"); + MCode EXIST101 = MSG("EXIST101", "名称重复,请重新输入"); + MCode EXIST102 = MSG("EXIST102", "编码重复,请重新输入"); + MCode EXIST103 = MSG("EXIST103", "不能重复"); + + + /** + * 导入导出:IMP(import/export) + */ + MCode IMP001 = MSG("IMP001", "导入成功"); + MCode IMP002 = MSG("IMP002", "导入失败,文件格式错误"); + MCode IMP003 = MSG("IMP003", "导入失败,数据已存在"); + MCode IMP004 = MSG("IMP004", "导入失败,数据有误"); + MCode IMP005 = MSG("IMP005", "导出失败"); + MCode IMP006 = MSG("IMP006", "导入数据格式不正确"); + MCode IMP007 = MSG("IMP007", "重复"); + MCode IMP008 = MSG("IMP008", "名称"); + MCode IMP009 = MSG("IMP009", "编码"); + MCode IMP010 = MSG("IMP010", "导入失败,查询不到上级分类"); + MCode IMP011 = MSG("IMP011", "请选择导出字段"); + + /** + * 其他 + */ + // 打印模板 (print) + MCode PRI001 = MSG("PRI001", "打印模板不存在"); + MCode PRI002 = MSG("PRI002", "数字字典不存在printDev的字典分类"); + MCode PRI003 = MSG("PRI003", "第1条SQL语句:查询出多条表头信息"); + MCode PRI004 = MSG("PRI004", "第1条SQL语句:未查出表头信息"); + MCode PRI005 = MSG("PRI005", "第{index}条SQL语句:"); + MCode PRI006 = MSG("PRI006", "已到达该模板复制上限,请复制源模板"); + MCode COD001 = MSG("COD001", "集合条件过滤获得目标为空"); + MCode PRI007 = MSG("PRI007", "Sql语法错误"); + MCode PRI008 = MSG("PRI008", "该报表已删除"); + + /** + * 复制 + */ + MCode COPY001 = MSG("COPY001", "复制名称长度超过了限制长度"); + + + /** + * 登录相关 + */ + /*=====0-账号相关====*/ + MCode LOG001 = MSG("LOG001", "账户异常"); + MCode LOG002 = MSG("LOG002", "注销成功"); + MCode LOG004 = MSG("LOG004", "账号异常,请联系管理员修改所属组织信息"); + MCode LOG005 = MSG("LOG005", "账号未被激活"); + MCode LOG006 = MSG("LOG006", "账号已被禁用"); + MCode LOG007 = MSG("LOG007", "账号已被删除"); + MCode LOG010 = MSG("LOG010", "此IP未在白名单中"); + MCode LOG011 = MSG("LOG011", "登录失败,用户暂未绑定角色"); + MCode LOG012 = MSG("LOG012", "账号已被锁定,请联系管理员解除锁定"); + + /*======1-登录相关======*/ + MCode LOG101 = LOG("LOG101", "账号或密码错误"); + MCode LOG102 = LOG("LOG102", "账号有误,请重新输入"); + MCode LOG103 = LOG("LOG103", "请输入验证码"); + MCode LOG104 = LOG("LOG104", "验证码错误"); + MCode LOG107 = LOG("LOG107", "验证码已失效"); + MCode LOG105 = LOG("LOG105", "连接租户服务失败,请稍后再试"); + MCode LOG106 = LOG("LOG106", "短信验证码错误"); + MCode LOG108 = MSG("LOG108", "请等待{0}分钟后再进行登录,或联系管理员解除锁定"); + MCode LOG109 = LOG("LOG109", "租户登录失败,请用手机验证码登录"); + MCode LOG110 = LOG("LOG110", "数据库异常,请联系管理员处理"); + MCode LOG111 = LOG("LOG111", "已开启单点登录, 不支持此登录方式"); + MCode LOG112 = LOG("LOG112", "不支持此登录方式"); + MCode LOG113 = LOG("LOG113", "未设置租户信息"); + MCode LOG114 = LOG("LOG114", "租户编码不允许为空"); + MCode LOG115 = LOG("LOG115", "租户信息获取失败"); + MCode LOG116 = LOG("LOG116", "不支持此验证"); + MCode LOG117 = LOG("LOG117", "短信验证码验证失败:{0}"); + MCode LOG118 = LOG("LOG118", "租户库名为空"); + + /*======2-密码修改========*/ + MCode LOG201 = LOG("LOG201", "旧密码错误"); + MCode LOG202 = LOG("LOG202", "修改成功,请牢记新密码"); + MCode LOG203 = LOG("LOG203", "修改失败,账号不存在"); + MCode LOG204 = LOG("LOG204", "修改失败,新建密码不能与旧密码一样"); + MCode LOG205 = LOG("LOG205", "重置密码成功"); + MCode LOG206 = LOG("LOG206", "重置密码失败"); + + + //oauth + MCode OA001 = OA("OA001", "用户登录"); + MCode OA002 = OA("OA002", "设备"); + MCode OA003 = OA("OA003", "TOKEN"); + MCode OA004 = OA("OA004", "用户退出"); + MCode OA005 = OA("OA005", "用户踢出"); + MCode OA006 = OA("OA006", "用户顶替"); + MCode OA007 = OA("OA007", "登录异常"); + MCode OA008 = OA("OA008", "登录获取系统配置失败"); + MCode OA009 = OA("OA009", "该用户未分配权限"); + MCode OA010 = OA("OA010", "仅支持pc端访问,APP端不支持"); + MCode OA011 = OA("OA011", "应用不存在"); + MCode OA012 = OA("OA012", "当前应用已被禁用"); + MCode OA013 = OA("OA013", "登录密码解密失败"); + MCode OA014 = OA("OA014", "注销成功"); + MCode OA015 = OA("OA015", "登录成功"); + MCode OA016 = OA("OA016", "登录票据已失效"); + MCode OA017 = OA("OA017", "第三方未绑定账号"); + MCode OA018 = OA("OA018", "不允许访问此登录接口"); + MCode OA019 = OA("OA019", "账号不存在"); + MCode OA020 = OA("OA020", "账户或密码错误,请重新输入"); + MCode OA021 = OA("OA021", "验证成功"); + MCode OA022 = OA("OA022", "限制会话, 不允许访问系统"); + MCode OA023 = OA("OA023", "管理员不能注销"); + MCode OA024 = OA("OA024", "登录失败"); + MCode OA025 = OA("OA025", "超级管理员"); + MCode OA026 = OA("OA026", "普通管理员"); + MCode OA027 = OA("OA027", "普通用户"); + MCode OA028 = OA("OA028", "未知来源"); + + //oauth + MCode PS001 = PS("PS001", "此记录与\"{0}\"关联引用,不允许被删除"); + MCode PS003 = PS("PS003", "组织"); + MCode PS004 = PS("PS004", "岗位"); + MCode PS005 = PS("PS005", "用户"); + MCode PS006 = PS("PS006", "角色"); + MCode PS007 = PS("PS007", "账号不能为空"); + MCode PS008 = PS("PS008", "姓名不能为空"); + MCode PS009 = PS("PS009", "用户额度已达到上限"); + MCode PS010 = PS("PS010", "权限已变更,请重新登录"); + MCode PS011 = PS("PS011", "密码已变更,请重新登录"); + MCode PS012 = PS("PS012", "类型不能为空"); + MCode PS013 = PS("PS013", "当前机构Id不能与父机构Id相同"); + MCode PS014 = PS("PS014", "该应用已禁用"); + MCode PS015 = PS("PS015", "无法设置当前用户为分级管理员"); + MCode PS016 = PS("PS016", "无法设置超管为分级管理员"); + MCode PS017 = PS("PS017", "无法设置当前用户操作权限"); + MCode PS018 = PS("PS018", "解绑失败"); + MCode PS019 = PS("PS019", "第三方登录未配置"); + MCode PS020 = PS("PS020", "性别不能为空"); + MCode PS021 = PS("PS021", "无法禁用管理员用户"); + MCode PS022 = PS("PS022", "管理员只能修改自己,不能修改其他管理员"); + MCode PS023 = PS("PS023", "无法修改管理员账户"); + MCode PS024 = PS("PS024", "直属主管不能是自己"); + MCode PS025 = PS("PS025", "直属主管不能是我的下属用户"); + MCode PS026 = PS("PS026", "无法删除管理员账户"); + MCode PS027 = PS("PS027", "此用户为某部门主管,无法删除"); + MCode PS028 = PS("PS028", "此用户有下属,无法删除"); + MCode PS029 = PS("PS029", "无法修改管理员账户状态"); + MCode PS030 = PS("PS030", "用户信息已变更,请重新登录"); + MCode PS031 = PS("PS031", "该应用已删除"); + MCode PS032 = PS("PS032", "该组织无本应用权限,切换失败"); + MCode PS033 = PS("PS033", "工作交接成功!"); + MCode PS034 = PS("PS034", "工作交接无法转移给管理员"); + MCode PS035 = PS("PS035", "工作交接无法转移给本人"); + + /** + * 数据库 + */ + MCode DB001 = DB("DB001", "数据类型编码不符合标准(请注意大小写)。MySQL , SQLServer , Oracle , DM , KingbaseES , PostgreSQL"); + MCode DB002 = DB("DB002", "请检查 1、连接信息 2、网络通信 3、数据库服务启动状态。 详情:{0}"); + MCode DB003 = DB("DB003", "通过url找不到对应数据库"); + MCode DB004 = DB("DB004", "查询结果集为空。"); + MCode DB005 = DB("DB005", "未找到对应数据库类型:{0}({1})"); + MCode DB006 = DB("DB006", "未找到对应数据类型转换"); + MCode DB007 = DB("DB007", "导入表名存在重复"); + MCode DB008 = DB("DB008", "建表数据与当前操作数据库不匹配: {0} -> {1}"); + MCode DB009 = DB("DB009", "未找到表信息: {0}"); + MCode DB010 = DB("DB010", "数据库{0},未找到此表:{1}"); + MCode DB011 = DB("DB011", "联合主键类缺少“{0}”字段值"); + MCode DB012 = DB("DB012", "表示对应获取数值失败"); + MCode DB013 = DB("DB013", "目前还未支持{0}数据类型:{1}"); + MCode DB014 = DB("DB014", "表 \"{0}\"中字段 \"{1}\" 为主键,不允许数据类型 \"{2}\" "); + MCode DB015 = DB("DB015", "未找到字段SQL语句"); + MCode DB016 = DB("DB016", "没有初始字段"); + MCode DB017 = DB("DB017", "sql异常:{0}"); + MCode DB018 = DB("DB018", "请在数据库中添加对应的数据表"); + MCode DB019 = DB("DB019", "添加失败"); + /*== 系统自带表 DB1 ==*/ + MCode DB101 = DB("DB101", "系统自带表,不允许被删除"); + MCode DB102 = DB("DB102", "系统自带表,不允许被编辑"); + /*== 表已经被使用 DB2 ==*/ + MCode DB201 = DB("DB201", "表已经被使用,不允许被删除"); + MCode DB202 = DB("DB202", "表已经被使用,不允许被编辑"); + /*== 数据库连接问题 ==*/ + MCode DB301 = DB("DB301", "数据库连接成功"); + MCode DB302 = DB("DB302", "数据库连接失败"); + + + + /** + * 工作流相关错误码 + */ + MCode WF001 = WF("WF001","审核成功"); + MCode WF002 = WF("WF002","退回成功"); + MCode WF003 = WF("WF003","转办成功"); + MCode WF004 = WF("WF004","加签成功"); + MCode WF005 = WF("WF005","当前流程被退回,无法撤回流程"); + MCode WF006 = WF("WF006","流程已撤回,不能重复操作"); + MCode WF007 = WF("WF007","撤回失败,转向数据无法撤回"); + MCode WF008 = WF("WF008","撤回成功"); + MCode WF009 = WF("WF009","功能流程不能终止"); + MCode WF010 = WF("WF010","指派成功"); + MCode WF011 = WF("WF011","批量操作完成"); + MCode WF012 = WF("WF012","该流程不能操作"); + MCode WF013 = WF("WF013","复活成功"); + MCode WF014 = WF("WF014","变更成功"); + MCode WF015 = WF("WF015","挂起成功"); + MCode WF016 = WF("WF016","恢复成功"); + MCode WF017 = WF("WF017","委托人和被委托人相同,委托失败"); + MCode WF018 = WF("WF018","操作失败,同一时间内有相同流程的委托"); + MCode WF019 = WF("WF019","操作失败,同一时间内有相同流程,不能相互委托"); + MCode WF020 = WF("WF020","功能流程不能删除"); + MCode WF021 = WF("WF021","不能删除"); + MCode WF022 = WF("WF022","催办成功"); + MCode WF023 = WF("WF023","未找到催办人"); + MCode WF024 = WF("WF024", "该功能已被流程引用,请重新选择关联功能"); + MCode WF025 = WF("WF025","启用失败,流程未设计"); + MCode WF026 = WF("WF026","启用成功"); + MCode WF027 = WF("WF027","禁用成功"); + MCode WF028 = WF("WF028","该版本内有工单任务流转,无法删除"); + MCode WF029 = WF("WF029","您没有发起该流程的权限"); + MCode WF030 = WF("WF030","表单未找到"); + MCode WF031 = WF("WF031","已审核完成"); + MCode WF032 = WF("WF032","冻结不能操作"); + MCode WF033 = WF("WF033","转向节点不存在或配置错误"); + MCode WF034 = WF("WF034","转向失败,转向节点未审批"); + MCode WF035 = WF("WF035","退回至您的审批,不能再发起退回"); + MCode WF036 = WF("WF036","流程已处理,无法撤回"); + MCode WF037 = WF("WF037","当前流程包含子流程,无法撤回"); + MCode WF038 = WF("WF038","子流程无法撤回"); + MCode WF039 = WF("WF039","下一节点为选择分支无法批量审批"); + MCode WF040 = WF("WF040","条件流程包含候选人无法批量通过"); + MCode WF041 = WF("WF041","该流程工单已终止"); + MCode WF042 = WF("WF042","该流程工单已撤回"); + MCode WF043 = WF("WF043","该节点没有数据,无法复活"); + MCode WF044 = WF("WF044","此流程不支持变更"); + MCode WF045 = WF("WF045","当前节点有子流程无法变更"); + MCode WF046 = WF("WF046","退回节点包含子流程,退回失败"); + MCode WF047 = WF("WF047","当前节点未审批,不能退回"); + MCode WF048 = WF("WF048","流程处于挂起状态,不可操作"); + MCode WF049 = WF("WF049","当前流程正在运行不能删除"); + MCode WF050 = WF("WF050","已被挂起不能删除"); + MCode WF051 = WF("WF051","没有删除权限"); + MCode WF052 = WF("WF052","主版本没有内容"); + MCode WF053 = WF("WF053","流程没有启用"); + MCode WF054 = WF("WF054","流程编码不能重复"); + MCode WF055 = WF("WF055","流程表单不一致,请重新选择"); + MCode WF056 = WF("WF056","该流程由在线开发生成的,无法直接删除,请在功能设计中删除相关功能"); + MCode WF057 = WF("WF057","该流程内工单任务流转未结束,无法删除"); + MCode WF058 = WF("WF058","当前流程正在运行不能重复提交"); + MCode WF059 = WF("WF059","流程自动发起审批失败"); + MCode WF060 = WF("WF060","驳回节点不能是子流程"); + MCode WF061 = WF("WF061", "下一节点无审批人员请联系管理员"); + MCode WF062 = WF("WF062", "表单已被引用,请重新选择"); + MCode WF063 = WF("WF063", "流程已发起,无法删除"); + MCode WF064 = WF("WF064", "任务不存在,或者已处理"); + MCode WF065 = WF("WF065", "拒绝成功"); + MCode WF066 = WF("WF066", "同意成功"); + MCode WF067 = WF("WF067", "协办成功"); + MCode WF068 = WF("WF068", "协办保存成功"); + MCode WF069 = WF("WF069", "减签成功"); + MCode WF070 = WF("WF070", "撤销成功"); + MCode WF071 = WF("WF071", "最后一条数据不能删除"); + MCode WF072 = WF("WF072", "启用版本不能删除"); + MCode WF073 = WF("WF073", "归档版本不能删除"); + MCode WF074 = WF("WF074", "暂停成功"); + MCode WF075 = WF("WF075", "条件不满足无法流转"); + MCode WF076 = WF("WF076", "节点不存在"); + MCode WF077 = WF("WF077", "流程无法撤回"); + MCode WF078 = WF("WF078", "流程未同意,无法撤销"); + MCode WF079 = WF("WF079", "归档异常"); + MCode WF080 = WF("WF080", "选择的数据不能退签"); + MCode WF081 = WF("WF081", "无法加签"); + MCode WF082 = WF("WF082", "无法减签"); + MCode WF083 = WF("WF083", "无法退回"); + MCode WF084 = WF("WF084", "无法转审"); + MCode WF085 = WF("WF085", "无法协办"); + MCode WF086 = WF("WF086", "无法批量审批"); + MCode WF087 = WF("WF087", "经办未签收"); + MCode WF088 = WF("WF088", "经办未开始办理"); + MCode WF089 = WF("WF089", "流程发布失败"); + MCode WF090 = WF("WF090", "流程发布失败"); + MCode WF091 = WF("WF091", "流程提交失败"); + MCode WF092 = WF("WF092", "获取引擎当前任务失败"); + MCode WF093 = WF("WF093", "流程删除失败"); + MCode WF094 = WF("WF094", "获取出线集合失败"); + MCode WF095 = WF("WF095", "获取线之后的任务节点失败"); + MCode WF096 = WF("WF096", "获取下一级任务节点集合失败"); + MCode WF097 = WF("WF097", "获取上一级任务节点集合失败"); + MCode WF098 = WF("WF098", "任务完成失败"); + MCode WF099 = WF("WF099", "获取流程实例失败"); + MCode WF100 = WF("WF100", "获取未经过的节点失败"); + MCode WF101 = WF("WF101", "获取节点的后续节点失败"); + MCode WF102 = WF("WF102", "获取可回退的节点失败"); + MCode WF103 = WF("WF103", "退回失败"); + MCode WF104 = WF("WF104", "节点跳转失败"); + MCode WF105 = WF("WF105", "补偿失败"); + MCode WF106 = WF("WF106", "不能加签给自己"); + MCode WF107 = WF("WF107", "不能转审给自己"); + MCode WF108 = WF("WF108", "不能协办给自己"); + MCode WF109 = WF("WF109", "必须保留一名加签人员"); + MCode WF110 = WF("WF110", "审批异常无法撤销"); + MCode WF111 = WF("WF111", "所选流程包含条件候选人"); + MCode WF112 = WF("WF112", "选择的数据对应流程已暂停"); + MCode WF113 = WF("WF113", "已被暂停不能删除"); + MCode WF114 = WF("WF114","流程处于暂停状态,不可操作"); + MCode WF115 = WF("WF115", "流程已受理,无法删除"); + MCode WF116 = WF("WF116", "不能加签给委托人"); + MCode WF117 = WF("WF117", "不能转审给委托人"); + MCode WF118 = WF("WF118", "不能协办给委托人"); + MCode WF119 = WF("WF119", "设置了流转条件,无法批量审批"); + MCode WF120 = WF("WF120", "下一节点审批异常,无法批量审批"); + MCode WF121 = WF("WF121", "子流程自动发起审批失败"); + MCode WF122 = WF("WF122", "流程不存在"); + MCode WF123 = WF("WF123", "流程处于终止状态,不可操作"); + MCode WF124 = WF("WF124", "该流程已发起数据,无法删除!"); + MCode WF125 = WF("WF125", "您没有发起委托流程"); + MCode WF126 = WF("WF126", "撤销流程不能转审"); + MCode WF127 = WF("WF127", "撤销流程不能退回"); + MCode WF128 = WF("WF128", "该用户已审批,请重新打开界面"); + MCode WF129 = WF("WF129", "委托人已无该流程权限"); + MCode WF130 = WF("WF130", "管理员不能新建委托/代理"); + MCode WF131 = WF("WF131", "不能选择admin"); + MCode WF132 = WF("WF132", "已有人接受,不可编辑"); + MCode WF133 = WF("WF133", "流转条件不满足,无法发起审批"); + MCode WF134 = WF("WF134", "第一个审批节点设置候选人,无法发起审批"); + MCode WF135 = WF("WF135", "第一个审批节点异常,无法发起审批"); + MCode WF136 = WF("WF136", "找不到发起人,发起失败"); + MCode WF137 = WF("WF137","代理人和被代理人相同,代理失败"); + MCode WF138 = WF("WF138","存在未签收的数据,无法关闭"); + MCode WF139 = WF("WF139","该流程已触发了任务,无法删除"); + MCode WF140 = WF("WF140","该流程已下架"); + MCode WF141 = WF("WF141","存在待办理的数据,无法关闭"); + MCode WF142 = WF("WF142","流程引擎异常"); + MCode WF143 = WF("WF143","已到达加签限制层级,无法再加签"); + MCode WF144 = WF("WF144","操作失败,同一时间内有相同流程的代理"); + MCode WF145 = WF("WF145","操作失败,同一时间内有相同流程,不能相互代理"); + MCode WF146 = WF("WF146","该任务流程已下架"); + MCode WF147 = WF("WF147","发起节点设置了选择分支,无法发起审批"); + MCode WF148 = WF("WF148","办理成功"); + MCode WF149 = WF("WF149", "不能转办给自己"); + MCode WF150 = WF("WF150", "不能转办给委托人"); + MCode WF151 = WF("WF151", "无法转办"); + MCode WF152 = WF("WF152", "转审成功"); + /** + * 在线开发相关错误码 + */ + /*=========1-错误提示=========*/ + MCode VS401 = VS("VS401", "该模板内表单内容为空,无法"); + MCode VS402 = VS("VS402", "该模板内列表内容为空,无法"); + MCode VS403 = VS("VS403", "该功能未配置流程不可用"); + MCode VS404 = VS("VS404", "单行输入不能重复"); + MCode VS405 = VS("VS405", "当前表单原数据已被调整,请重新进入该页面编辑并提交数据"); + MCode VS406 = VS("VS406", "该功能配置的流程处于停用"); + MCode VS407 = VS("VS407", "表头名称不可更改,表头行不能删除"); + MCode VS408 = VS("VS408", "请至少选择一个数据表"); + MCode VS409 = VS("VS409", "未找到主表信息"); + MCode VS410 = VS("VS410", "请导入对应功能的json文件"); + MCode VS411 = VS("VS411", "已存在相同功能"); + MCode VS412 = VS("VS412", "该表单已删除"); + MCode VS413 = VS("VS413", "应用不能为空"); + MCode VS414 = VS("VS414", "门户数据信息存在重复"); + MCode VS415 = VS("VS415", "该门户已删除"); + //base + MCode VS001 = VS("VS001", "同步到流程时,{0}"); + MCode VS002 = VS("VS002", "发布失败,流程未设计!"); + MCode VS003 = VS("VS003", "无表生成有表失败"); + MCode VS004 = VS("VS004", "发布"); + MCode VS005 = VS("VS005", "预览"); + MCode VS006 = VS("VS006", "下载"); + MCode VS007 = VS("VS007", "同步成功"); + MCode VS008 = VS("VS008", "回滚失败,暂无线上版本"); + MCode VS009 = VS("VS009", "参数解析错误!"); + MCode VS010 = VS("VS010", "无效链接"); + MCode VS011 = VS("VS011", "密码错误"); + MCode VS012 = VS("VS012", "未找到该功能表单"); + MCode VS013 = VS("VS013", "未开启表单外链!"); + MCode VS014 = VS("VS014", "下载链接已失效"); + MCode VS015 = VS("VS015", "字段不能为空"); + MCode VS016 = VS("VS016", "路径错误"); + MCode VS017 = VS("VS017", "集成助手被禁用"); + MCode VS018 = VS("VS018", "表规范名称不能重复"); + MCode VS019 = VS("VS019", "规范名称不能使用系统关键字或JAVA关键字"); + MCode VS020 = VS("VS020", "字段规范名称不能重复"); + MCode VS021 = VS("VS021", "“{0}”命名不符合规范"); + MCode VS022 = VS("VS022", "主键策略:[雪花ID],表[ {0} ]主键设置不支持!"); + MCode VS023 = VS("VS023", "主键策略:[自增ID],表[ {0} ]主键设置不支持!"); + MCode VS024 = VS("VS024", "表单不存在或者未发布!"); + MCode VS025 = VS("VS025", "未获取到流程发起人"); + MCode VS026 = VS("VS026", "规范名称前两字母必须小写"); + MCode VS027 = VS("VS027", "自动生成的【{0}】超出长度,提交失败!"); + MCode VS028 = VS("VS028", "视图最多新建5个"); + MCode VS029 = VS("VS029", "设置视图主键后才能正常使用"); + + + + /** + * 网关 + */ + MCode GT101 = GT("GT101", "成功"); + MCode GT102 = GT("GT102", "失败"); + MCode GT103 = GT("GT103", "验证错误"); + MCode GT104 = GT("GT104", "异常"); + MCode GT105 = GT("GT105", "登录过期,请重新登录"); + MCode GT106 = GT("GT106", "您的帐号在其他地方已登录,被强制踢出"); + MCode GT107 = GT("GT107", "Token验证失败"); + MCode GT108 = GT("GT108", "请求超过最大数"); + + /** + * 调度 + */ + MCode SC001 = SCHEDULE("SC001", "操作失败,任务不存在"); + + /** + * admin exception + */ + MCode AD101 = MSG("AD101", "接口无法访问"); + MCode AD102 = MSG("AD102", "系统异常"); + MCode AD103 = MSG("AD103", "操作过于频繁"); + MCode AD104 = MSG("AD104", "没有访问权限,请联系管理员授权"); + MCode AD105 = MSG("AD105", "认证失败,无法访问系统资源"); + MCode AD106 = MSG("AD106", "无效内部认证,无法访问系统资源"); + + /** + * extend + */ + MCode ETD101 = MSG("ETD101", "操作失败,原文件不存在"); + MCode ETD102 = MSG("ETD102", "找不到父级"); + MCode ETD103 = MSG("ETD103", "不能移动到自己的文件夹"); + MCode ETD104 = MSG("ETD104", "未能找到此订单"); + MCode ETD105 = MSG("ETD105", "新建成功10000条数据"); + MCode ETD106 = MSG("ETD106", "获取失败"); + MCode ETD107 = MSG("ETD107", "账户认证错误"); + MCode ETD108 = MSG("ETD108", "你还没有设置邮件的帐户"); + MCode ETD109 = MSG("ETD109", "文件导出失败"); + MCode ETD110 = MSG("ETD110", "文件格式不正确"); + MCode ETD111 = MSG("ETD111", "文件找不到"); + MCode ETD112 = MSG("ETD112", "此记录被关联引用,不允许被删除"); + MCode ETD113 = MSG("ETD113", "防止恶意创建过多数据"); + MCode ETD114 = MSG("ETD114", "保存失败,请重新登陆"); + MCode ETD115 = MSG("ETD115", "请输入预览的url"); + MCode ETD116 = MSG("ETD116", "请选择正确的预览方式"); + MCode ETD117 = MSG("ETD117", "数据超过1000条"); + /** + * form + */ + MCode FM001 = MSG("FM001", "未找到接口"); + MCode FM002 = MSG("FM002", "表单信息不存在"); + MCode FM003 = MSG("FM003", "子表重复"); + MCode FM004 = MSG("FM004", "已到达该模板复制上限,请复制源模板!"); + MCode FM005 = MSG("FM005", "该表单已被流程引用,无法删除!"); + MCode FM006 = MSG("FM006", "该表单未发布,无法回滚表单内容"); + MCode FM007 = MSG("FM007", "该模板内表单内容为空,无法发布"); + MCode FM008 = MSG("FM008", "该功能未导入流程表单"); + MCode FM009 = MSG("FM009", "流程未设计,请先设计流程!"); + MCode FM010 = MSG("FM010", "该功能流程处于停用状态!"); + MCode FM011 = MSG("FM011", "表[{0}]无主键!"); + MCode FM012 = MSG("FM012", "主键策略:{0},与表[{1}]主键策略不一致!"); + MCode FM013 = MSG("FM013", "表新增错误:{0}"); + + /** + * message的消息提示 + */ + MCode MSERR101 = MSG("MSERR101", "发送失败,失败原因:SMTP服务为空"); + MCode MSERR102 = MSG("MSERR102", "发送失败,失败原因:发件人邮箱为空"); + MCode MSERR103 = MSG("MSERR103", "发送失败,失败原因:发件人密码为空"); + MCode MSERR104 = MSG("MSERR104", "发送失败,失败原因:接收人为空"); + MCode MSERR105 = MSG("MSERR105", "发送失败。失败原因:{0}的邮箱账号格式有误!"); + MCode MSERR106 = MSG("MSERR106", "发送失败。失败原因:{0}的邮箱账号为空!"); + MCode MSERR107 = MSG("MSERR107", "发送失败。失败原因:接收人对应的邮箱全部为空"); + MCode MSERR108 = MSG("MSERR108", "发送失败。失败原因:{0}"); + MCode MSERR109 = MSG("MSERR109", "连接成功"); + MCode MSERR110 = MSG("MSERR110", "连接失败。失败原因:{0}"); + MCode MSERR111 = MSG("MSERR111", "已发送"); + MCode MSERR112 = MSG("MSERR112", "内容不能包含<符号"); + MCode MSERR113 = MSG("MSERR113", "暂无未读消息"); + MCode MSERR114 = MSG("MSERR114", "自定义模板编码不能使用系统模板编码规则"); + MCode MSERR115 = MSG("MSERR115", "创建失败,存在多个标题参数"); + MCode MSERR116 = MSG("MSERR116", "创建失败,不存在标题参数"); + MCode MSERR117 = MSG("MSERR117", "更新失败,存在多个标题参数"); + MCode MSERR118 = MSG("MSERR118", "更新失败,不存在标题参数"); + MCode MSERR119 = MSG("MSERR119", "请先前往系统同步设置,配置钉钉账号"); + MCode MSERR120 = MSG("MSERR120", "请先前往系统同步设置,配置企业微信账号"); + MCode MSERR121 = MSG("MSERR121", "配置模板无数据,无法测试"); + + /******************** + * system + ********************/ + MCode SYS001 = SYS("SYS001", "区域编码不能重复"); + MCode SYS002 = SYS("SYS002", "删除失败,当前有子节点数据"); + MCode SYS003 = SYS("SYS003", "单据已经被使用,不允许被删除"); + MCode SYS004 = SYS("SYS004", "清理成功"); + MCode SYS005 = SYS("SYS005", "接口创建成功"); + MCode SYS006 = SYS("SYS006", "当前SQL含有敏感字:{0}"); + MCode SYS007 = SYS("SYS007", "接口请求成功"); + MCode SYS008 = SYS("SYS008", "接口不符合规范"); + MCode SYS009 = SYS("SYS009", "变量名不能包含敏感字符"); + MCode SYS010 = SYS("SYS010", "变量名已存在"); + MCode SYS011 = SYS("SYS011", "数据库连接不能相同"); + MCode SYS012 = SYS("SYS012", "请检查,同一数据库下无法同步数据"); + MCode SYS013 = SYS("SYS013", "同步失败:{0}"); + MCode SYS014 = SYS("SYS014", "字典类型下面有字典值禁止删除"); + MCode SYS015 = SYS("SYS015", "模板不存在"); + MCode SYS016 = SYS("SYS016", "当前目录存在数据,不能修改类型"); + MCode SYS017 = SYS("SYS017", "删除失败,请先删除子菜单"); + MCode SYS018 = SYS("SYS018", "当前导入菜单为{0}端菜单,请在对应模块下导入!"); + MCode SYS019 = SYS("SYS019", "请在顶级节点下创建目录后再进行菜单导入"); + MCode SYS020 = SYS("SYS020", "该字段在方案{0}中已被使用"); + MCode SYS021 = SYS("SYS021", "修改失败,该方案不允许编辑"); + MCode SYS022 = SYS("SYS022", "编码错误"); + MCode SYS023 = SYS("SYS023", "请求发生错误!"); + MCode SYS024 = SYS("SYS024", "获取不到数据!"); + MCode SYS025 = SYS("SYS025", "获取企业微信access_token失败"); + MCode SYS026 = SYS("SYS026", "正在进行同步,请稍后再试"); + MCode SYS027 = SYS("SYS027", "请先从企业微信同步部门到本地"); + MCode SYS028 = SYS("SYS028", "请先从钉钉同步部门到本地"); + + MCode SYS029 = SYS("SYS029", "验证码位数不能大于6"); + MCode SYS030 = SYS("SYS030", "验证码位数不能小于3"); + MCode SYS031 = SYS("SYS031", "测试发送消息的连接失败:{0}"); + MCode SYS032 = SYS("SYS032", "测试发送消息连接成功"); + MCode SYS033 = SYS("SYS033", "测试组织同步的连接失败:{0}"); + MCode SYS034 = SYS("SYS034", "测试组织同步连接成功"); + MCode SYS035 = SYS("SYS035", "测试连接类型错误"); + MCode SYS036 = SYS("SYS036", "测试钉钉连接失败:"); + MCode SYS037 = SYS("SYS037", "测试连接成功"); + MCode SYS038 = SYS("SYS038", "表信息抽取异常"); + MCode SYS039 = MSG("SYS039", "删除失败,请先删除该应用下的菜单和门户"); + MCode SYS040 = MSG("SYS040", "删除失败,请先删除该应用下的菜单"); + MCode SYS041 = MSG("SYS041", "删除失败,请先删除该应用下的门户"); + MCode SYS042 = MSG("SYS042", "该日程已被删除"); + MCode SYS043 = MSG("SYS043", "最后一条数据不能删除"); + MCode SYS044 = MSG("SYS044", "启用版本不能删除"); + MCode SYS045 = MSG("SYS045", "归档版本不能删除"); + MCode SYS046 = MSG("SYS046", "数据集不能重名"); + MCode SYS047 = MSG("SYS047", "SQL语句仅支持查询语句"); + MCode SYS048 = MSG("SYS048", "SQL语句需带上@formId条件"); + MCode SYS049 = MSG("SYS049", "正在进行同步,请稍等"); + MCode SYS050 = MSG("SYS050", "只能输入字母、数字、点、横线和下划线,且以字母开头"); + MCode SYS051 = MSG("SYS051", "翻译标记不能重复"); + MCode SYS052 = MSG("SYS052", "翻译语言至少填写一项"); + MCode SYS053 = SYS("SYS053", "获取钉钉access_token失败"); + + /** + * 应用 + */ + MCode SYS101 = SYS("SYS101", "更新失败,主系统不允许禁用"); + MCode SYS102 = SYS("SYS102", "主系统不允许删除"); + MCode SYS103 = SYS("SYS103", "系统在审批常用语中被使用,不允许删除"); + MCode SYS104 = SYS("SYS104", "更新失败,主系统不允许修改编码"); + MCode SYS105 = SYS("SYS105", "常用语已存在"); + + /** + * 数据接口 + */ + MCode SYS121 = SYS("SYS121", "接口暂只支持HTTP和HTTPS方式"); + MCode SYS122 = SYS("SYS122", "接口请求失败"); + MCode SYS123 = SYS("SYS123", "接口请求失败, JS调用失败,错误:{0}"); + MCode SYS124 = SYS("SYS124", "验证请求超时"); + MCode SYS125 = SYS("SYS125", "appSecret错误"); + MCode SYS126 = SYS("SYS126", "appId使用期限已到期"); + MCode SYS127 = SYS("SYS127", "appId参数错误"); + + MCode SYS128 = SYS("SYS128", "{0}不能使用系统、开发语言及数据库关键字命名"); + MCode SYS129 = SYS("SYS129", "当前数据源不支持全连接"); + + MCode SYS130 = SYS("SYS130", "标题不能为空"); + MCode SYS131 = SYS("SYS131", "结束时间必须晚于开始时间"); + MCode SYS132 = SYS("SYS132", "结束重复必须晚于开始时间"); + + MCode SYS133 = SYS("SYS133", "请先设置数据接口的字段列表!"); + + /** + * AI + */ + MCode SYS180 = SYS("SYS180", "AI功能未配置启用"); + MCode SYS181 = SYS("SYS181", "AI结果获取失败, 请稍后再尝试"); + MCode SYS182 = SYS("SYS182", "AI请求频率达到限制, 请稍后再尝试"); + + /******************** + * system + ********************/ + + + static MCode MSG(String code, String desc){ + return new MCode("message", code, desc); + } + + static MCode LOG(String code, String desc){ + return new MCode("login", code, desc); + } + + static MCode DB(String code, String desc){ + return new MCode("database", code, desc); + } + + static MCode WF(String code, String desc){ + return new MCode("workflow", code, desc); + } + + static MCode VS(String code, String desc){ + return new MCode("visual", code, desc); + } + + static MCode GT(String code, String desc){ + return new MCode("gateway", code, desc); + } + + static MCode OA(String code, String desc){ + return new MCode("oauth", code, desc); + } + + static MCode PS(String code, String desc){ + return new MCode("permission", code, desc); + } + + static MCode SCHEDULE(String code, String desc){ + return new MCode("schedule", code, desc); + } + + static MCode SYS(String code, String desc){ + return new MCode("system", code, desc); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/PermissionConst.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/PermissionConst.java new file mode 100644 index 0000000..8cb3825 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/PermissionConst.java @@ -0,0 +1,62 @@ +package com.yunzhupaas.constant; + +public class PermissionConst { + + /** + * 组织标识 + */ + public static final String ORGANIZE = "Organize"; + /** + * 岗位标识 + */ + public static final String POSITION = "Position"; + /** + * 角色标识 + */ + public static final String ROLE = "Role"; + + + public static final String COMPANY = "company"; + + + public static final String DEPARTMENT = "department"; + + /** + * 分组 + */ + public static final String GROUP = "Group"; + + /** + * 应用 + */ + public static final String SYSTEM = "System"; + + /** + * 身份 + */ + public static final String STAND = "Standing"; + + /** + * 菜单 + */ + public static final String MODULE = "Module"; + + /** + * 用户 + */ + public static final String USER = "user"; + + + /** + * 在线开发常用按钮权限 + */ + public static final String BTN_ADD = "btn_add"; + public static final String BTN_EDIT = "btn_edit"; + public static final String BTN_REMOVE = "btn_remove"; + public static final String BTN_DETAIL = "btn_detail"; + public static final String BTN_UPLOAD = "btn_upload"; + public static final String BTN_DOWNLOAD = "btn_download"; + public static final String BTN_BATCHREMOVE = "btn_batchRemove"; + public static final String BTN_BATCHPRINT = "btn_batchPrint"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/TableFieldsNameConst.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/TableFieldsNameConst.java new file mode 100644 index 0000000..949355f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/TableFieldsNameConst.java @@ -0,0 +1,23 @@ +package com.yunzhupaas.constant; + +public class TableFieldsNameConst { + + public static final String ID = "id"; + public static final String F_ID = "f_id"; + public static final String F_TENANT_ID = "f_tenant_id"; + public static final String F_VERSION = "f_version"; + public static final String F_FLOW_TASK_ID = "f_flow_task_id"; + public static final String F_FLOW_ID = "f_flow_id"; + public static final String F_DELETE_MARK = "f_delete_mark"; + public static final String F_DELETE_TIME = "f_delete_time"; + public static final String F_DELETE_USER_ID = "f_delete_user_id"; + public static final String F_FOREIGN_ID = "f_foreign_id"; + public static final String F_CREATOR_TIME = "f_creator_time"; + public static final String F_CREATOR_USER_ID = "f_creator_user_id"; + public static final String F_LAST_MODIFY_TIME = "f_last_modify_time"; + public static final String F_LAST_MODIFY_USER_ID = "f_last_modify_user_id"; + public static final String F_SORT_CODE = "f_sort_code"; + public static final String F_DESCRIPTION = "f_description"; + public static final String F_ENABLED_MARK = "f_enabled_mark"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/YunzhupaasConst.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/YunzhupaasConst.java new file mode 100644 index 0000000..1dc6c14 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/YunzhupaasConst.java @@ -0,0 +1,99 @@ +package com.yunzhupaas.constant; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 功能中所用常量 + * + * @author 云筑产品开发平台组 + * @version V3.5.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2023/6/6 15:08:10 + */ +@Data +public class YunzhupaasConst { + + /** + * 被过滤的系统菜单常量 + */ + public static final String MAIN_SYSTEM_CODE = "mainSystem"; + + /** + * 业务平台编码 + */ + public static final String WORK_SYSTEM_CODE = "workSystem"; + + /** + * 被过滤的系统菜单常量 + */ + public static final List MODULE_CODE = new ArrayList() { + { + add("workFlow.addFlow"); + add("workFlow.flowLaunch"); + add("workFlow.entrust"); + add("workFlow"); + add("workFlow.flowTodo"); + add("workFlow.flowDone"); + add("workFlow.flowCirculate"); + add("workFlow.document"); + add("workFlow.schedule"); + add("workFlow.flowToSign"); + add("workFlow.flowDoing"); + add("workFlow.printTemplate"); + } + }; + + /** + * 当前组织 + */ + public static final String CURRENT_ORG = "@currentOrg"; + public static final String CURRENT_ORG_TYPE = "@currentOrg--system"; + + /** + * 当前组织及子组织 + */ + public static final String CURRENT_ORG_SUB = "@currentOrgAndSubOrg"; + public static final String CURRENT_ORG_SUB_TYPE = "@currentOrgAndSubOrg--system"; + + /** + * 当前分管组织 + */ + public static final String CURRENT_GRADE = "@currentGradeOrg"; + public static final String CURRENT_GRADE_TYPE = "@currentGradeOrg--system"; + + /** + * 高级控件系统参数 + */ + public static final Map SYSTEM_PARAM = new HashMap() { + { + put(CURRENT_ORG, "当前组织"); + put(CURRENT_ORG_SUB, "当前组织及子组织"); + put(CURRENT_GRADE, "当前分管组织"); + put(CURRENT_ORG_TYPE, "当前组织"); + put(CURRENT_ORG_SUB_TYPE, "当前组织及子组织"); + put(CURRENT_GRADE_TYPE, "当前分管组织"); + } + }; + + /** + * 在线开发数据日志事件key + */ + public static final String VSLOG_EVENT_KEY = "vslogEventKey"; + + /** + * 流程签收菜单 + */ + public static final String WORK_FLOWSIGN = "workFlow.flowToSign"; + + /** + * 流程办理菜单 + */ + public static final String WORK_FLOWTODO = "workFlow.flowTodo"; + + public static String FIELD_SUFFIX_YUNZHUPAASID = "_yunzhupaasId"; +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/model/MCode.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/model/MCode.java new file mode 100644 index 0000000..37c66c1 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/constant/model/MCode.java @@ -0,0 +1,48 @@ +package com.yunzhupaas.constant.model; + +import com.yunzhupaas.i18n.util.I18nUtil; +import lombok.Data; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/12/20 + */ +@Data +public class MCode { + + /** + * 提示信息类型 + */ + private final String type; + + /** + * 错误编码 + */ + private final String code; + + /** + * description 描述 + */ + private final String desc; + + + public MCode(String type, String code, String desc){ + this.type = type; + this.code = code; + this.desc = desc; + } + + public String get(Object... args){ + return I18nUtil.getMessageStr(this, args); + } + + public String getMsg(){ + return type + ":" + code + " " + desc; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DataFieldType.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DataFieldType.java new file mode 100644 index 0000000..8d577b5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DataFieldType.java @@ -0,0 +1,39 @@ +package com.yunzhupaas.emnus; +/** + * 数据权限字段类型 + * + * @author 云筑产品开发平台组 + * @version V3.2 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2021/10/8 + */ +public enum DataFieldType { + /** + * 浮点型 + */ + Double("Double"), + /** + * 字符型 + */ + Varchar("String"), + + /** + * 数值型 + */ + Number("Int32"); + + private String message; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + DataFieldType(String message) { + this.message = message; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DataSetTypeEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DataSetTypeEnum.java new file mode 100644 index 0000000..cf3c648 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DataSetTypeEnum.java @@ -0,0 +1,33 @@ +package com.yunzhupaas.emnus; + +/** + * 数据及关联数据类型枚举 + * + * @author 云筑产品开发平台组 + * @version v5.0.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/5/7 10:56:58 + */ +public enum DataSetTypeEnum { + + PRINT_VER("printVersion", "打印版本"), + REPORT_VER("reportVersion", "报表版本"); + + private final String code; + + private final String msg; + + public String getCode() { + return code; + } + + public String getMsg() { + return msg; + } + + DataSetTypeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DbDriverEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DbDriverEnum.java new file mode 100644 index 0000000..2cd8253 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DbDriverEnum.java @@ -0,0 +1,39 @@ +package com.yunzhupaas.emnus; + +/** + * 数据库驱动枚举类 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-23 + */ +public enum DbDriverEnum { + /** + * mysql + */ + MYSQL("com.mysql.cj.jdbc.Driver"), + /** + * oracle + */ + ORACLE("oracle.jdbc.OracleDriver"), + /** + * sqlserver + */ + SQLSERVER("com.microsoft.sqlserver.jdbc.SQLServerDriver"); + + private String dbDriver; + + DbDriverEnum(String dbDriver) { + this.dbDriver = dbDriver; + } + + public String getDbDriver() { + return dbDriver; + } + + public void setDbDriver(String dbDriver) { + this.dbDriver = dbDriver; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DsJoinTypeEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DsJoinTypeEnum.java new file mode 100644 index 0000000..a8541e6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/DsJoinTypeEnum.java @@ -0,0 +1,64 @@ +package com.yunzhupaas.emnus; + +/** + * 连接关系枚举 + * + * @author 云筑产品开发平台组 + * @version v5.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/9/12 9:36:05 + */ +public enum DsJoinTypeEnum { + LEFT_JOIN(1, "LEFT JOIN", "左连接"), + + RIGHT_JOIN(2, "LEFT JOIN", "右连接"), + + INNER_JOIN(3, "INNER JOIN", "内连接"), + + FULL_JOIN(4, "FULL JOIN", "全连接"); + + private Integer type; + private String code; + private String fullName; + + DsJoinTypeEnum(Integer type, String code, String fullName) { + this.type = type; + this.code = code; + this.fullName = fullName; + } + + public Integer getType() { + return type; + } + + public String getCode() { + return code; + } + + public String getFullName() { + return fullName; + } + + public static String getCodeByType(Integer type) { + String code = null; + switch (type) { + case 1: + code = LEFT_JOIN.getCode(); + break; + case 2: + code = RIGHT_JOIN.getCode(); + break; + case 3: + code = INNER_JOIN.getCode(); + break; + case 4: + code = FULL_JOIN.getCode(); + break; + default: + code = LEFT_JOIN.getCode(); + break; + } + return code; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/ExportModelTypeEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/ExportModelTypeEnum.java new file mode 100644 index 0000000..7e5ca64 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/ExportModelTypeEnum.java @@ -0,0 +1,43 @@ +package com.yunzhupaas.emnus; + +/** + * 导入导出模板类型 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2021/7/15 + */ + +public enum ExportModelTypeEnum { + /** + * 功能设计 + */ + Design(1,"design"), + + /** + * APP + */ + App(2,"app"), + + /** + *门户 + */ + Portal(5,"portal"); + private final int code; + private final String message; + + public int getCode() { + return code; + } + + public String getMessage() { + return message; + } + + ExportModelTypeEnum(int code, String message) { + this.code = code; + this.message = message; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/FilePreviewTypeEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/FilePreviewTypeEnum.java new file mode 100644 index 0000000..4a6698f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/FilePreviewTypeEnum.java @@ -0,0 +1,25 @@ +package com.yunzhupaas.emnus; +/** + * 文件预览方式 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2021/5/6 + */ +public enum FilePreviewTypeEnum { + /** + * yozo:永中预览; doc:kk文档预览; + */ + YOZO_ONLINE_PREVIEW("yozoOnlinePreview"), + LOCAL_PREVIEW("localPreview"); + FilePreviewTypeEnum(String type) { + this.type = type; + } + private String type; + + public String getType() { + return type; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/ModuleTypeEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/ModuleTypeEnum.java new file mode 100644 index 0000000..9d1c561 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/ModuleTypeEnum.java @@ -0,0 +1,104 @@ +package com.yunzhupaas.emnus; + +/** + * 功能分类枚举 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-10-27 + */ +public enum ModuleTypeEnum { + /** + * 数据接口类型 + */ + SYSTEM_DATAINTEFASE("bd"), + /** + * 数据接口类型 + */ + SYSTEM_DATAINTEFASE_VARIATE("ffa"), + /** + * 单据规则 + */ + SYSTEM_BILLRULE("bb"), + /** + * 菜单 + */ + SYSTEM_MODULE("bm"), + /** + * 数据建模 + */ + SYSTEM_DBTABLE("bdb"), + /** + * 数据字典 + */ + SYSTEM_DICTIONARYDATA("bdd"), + /** + * 打印模板 + */ + SYSTEM_PRINT("bp"), + /** + * 表单套件 + */ + SYSTEM_KIT("bvk"), + /** + * 大屏导出 + */ + VISUAL_DATA("vd"), + /** + * 在线开发 + */ + VISUAL_DEV("vdd"), + /** + * APP导出 + */ + VISUAL_APP("va"), + /** + * 门户导出 + */ + VISUAL_PORTAL("vp"), + /** + * 流程设计 + */ + FLOW_FLOWENGINE("ffe"), + /** + * 账号配置 + */ + ACCOUNT_CONFIG("mac"), + /** + * 消息模板 + */ + MESSAGE_TEMPLATE("mes"), + /** + * 消息模板 + */ + MESSAGE_SEND_CONFIG("msc"), + /** + * 流程表单 + */ + FLOW_FLOWDFORM("fff"), + /** + * 流程表单 + */ + BASE_INTEGRATE("bi"), + /** + * 报表 + */ + REPORT_TEMPLATE("rp"), + ; + + ModuleTypeEnum(String moduleName) { + this.tableName = moduleName; + } + + private String tableName; + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/SearchMethodEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/SearchMethodEnum.java new file mode 100644 index 0000000..7f4e64c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/SearchMethodEnum.java @@ -0,0 +1,109 @@ +package com.yunzhupaas.emnus; + + +/** + * 查询功能 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-09-26 上午9:18 + */ +public enum SearchMethodEnum { + /** + * 等于 + */ + Equal("==", "等于"), + /** + * 介于 + */ + Between("between", "介于"), + /** + * 不等于 + */ + NotEqual("<>", "不等于"), + /** + * 大于 + */ + GreaterThan(">", "大于"), + /** + * 大于等于 + */ + GreaterThanOrEqual(">=", "大于等于"), + /** + * 小于 + */ + LessThan("<", "小于"), + /** + * 小于等于 + */ + LessThanOrEqual("<=", "小于等于"), + /** + * 包含任意一个 + */ + Included("in", "包含任意一个"), + /** + * 不包含任意一个 + */ + NotIncluded("notIn", "不包含任意一个"), + /** + * 为空 + */ + IsNull("null", "为空"), + /** + * 不为空 + */ + IsNotNull("notNull", "不为空"), + /** + * 包含 + */ + Like("like", "包含"), + /** + * 不包含 + */ + NotLike("notLike", "不包含"), + /** + * 并且 + */ + And("and", "并且"), + /** + * 或者 + */ + Or("or", "或者"); + + + SearchMethodEnum(String symbol, String message) { + this.symbol = symbol; + this.message = message; + } + + private String symbol; + private String message; + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public static SearchMethodEnum getSearchMethod(String symbol) { + for (SearchMethodEnum status : SearchMethodEnum.values()) { + if (status.getSymbol().equals(symbol)) { + return status; + } + } + return Equal; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/TemplateEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/TemplateEnum.java new file mode 100644 index 0000000..0c60cc2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/TemplateEnum.java @@ -0,0 +1,76 @@ +package com.yunzhupaas.emnus; + + +import cn.hutool.core.util.ObjectUtil; + +/** + * 接口类型 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-09-26 上午9:18 + */ +public enum TemplateEnum { + //字段 + Field(1, "字段"), + //自定义 + Custom(2, "自定义"), + //为空 + Empty(3, "为空"), + //系统 + System(4, "系统"); + + private Integer code; + private String message; + + TemplateEnum(Integer code, String message) { + this.code = code; + this.message = message; + } + + /** + * 根据状态code获取枚举名称 + * + * @return + */ + public static String getMessageByCode(Integer code) { + for (TemplateEnum status : TemplateEnum.values()) { + if (ObjectUtil.equal(status.getCode(), code)) { + return status.message; + } + } + return null; + } + + /** + * 根据状态code获取枚举值 + * + * @return + */ + public static TemplateEnum getByCode(Integer code) { + for (TemplateEnum status : TemplateEnum.values()) { + if (ObjectUtil.equal(status.getCode(), code)) { + return status; + } + } + return null; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/TimetaskTypes.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/TimetaskTypes.java new file mode 100644 index 0000000..059dc05 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/emnus/TimetaskTypes.java @@ -0,0 +1,54 @@ +package com.yunzhupaas.emnus; + + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:56 + */ +public enum TimetaskTypes { + + /** + * 执行一次 + */ + One(1, "执行一次"), + /** + * 重复执行 + */ + Two(2, "重复执行"), + /** + * 调度明细 + */ + Three(3, "调度明细"), + /** + * 调度任务 + */ + Four(4, "调度任务"); + + private int code; + private String message; + + TimetaskTypes(int code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/ConnectDatabaseException.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/ConnectDatabaseException.java new file mode 100644 index 0000000..33da390 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/ConnectDatabaseException.java @@ -0,0 +1,9 @@ +package com.yunzhupaas.exception; + +public class ConnectDatabaseException extends RuntimeException { + + public ConnectDatabaseException(String reason, Throwable cause) { + super(reason, cause); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/DataException.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/DataException.java new file mode 100644 index 0000000..8e59372 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/DataException.java @@ -0,0 +1,45 @@ +package com.yunzhupaas.exception; + +import com.yunzhupaas.constant.MsgCode; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * 数据库异常类 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:10 + */ +public class DataException extends RuntimeException { + + public DataException(){ + super(); + } + + public DataException(String message) { + super(message); + } + + public static DataException errorLink(String warning) { + return new DataException(MsgCode.DB002.get(warning)); + } + + + public static SQLException rollbackDataException(SQLException e, Connection rollbackConn) { + executeRollback(rollbackConn); + return e; + } + + private static void executeRollback(Connection conn){ + try { + conn.rollback(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/DataTypeException.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/DataTypeException.java new file mode 100644 index 0000000..4e9ba61 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/DataTypeException.java @@ -0,0 +1,10 @@ +package com.yunzhupaas.exception; + +public class DataTypeException extends Exception { + + public DataTypeException(String message) { + super(message); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/EncryptFailException.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/EncryptFailException.java new file mode 100644 index 0000000..23b67cd --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/EncryptFailException.java @@ -0,0 +1,16 @@ +package com.yunzhupaas.exception; + +/** + * 数据加密异常 + */ +public class EncryptFailException extends RuntimeException{ + + public EncryptFailException(String message) { + super(message); + } + + public EncryptFailException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/ImportException.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/ImportException.java new file mode 100644 index 0000000..d44dbd6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/ImportException.java @@ -0,0 +1,8 @@ +package com.yunzhupaas.exception; + +public class ImportException extends Exception { + public ImportException(String message) { + super(message); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/LoginException.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/LoginException.java new file mode 100644 index 0000000..3e8ed99 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/LoginException.java @@ -0,0 +1,28 @@ +package com.yunzhupaas.exception; + +import lombok.Getter; +import lombok.Setter; + +/** + * 登录异常 + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:53 + */ +public class LoginException extends RuntimeException { + + @Getter + @Setter + private Object data; + public LoginException(String message) { + super(message); + } + + public LoginException(String message, Object data) { + super(message); + this.data = data; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/TenantDatabaseException.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/TenantDatabaseException.java new file mode 100644 index 0000000..67214b2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/TenantDatabaseException.java @@ -0,0 +1,23 @@ +package com.yunzhupaas.exception; + +import lombok.experimental.Accessors; + +/** + * 租户数据库相关异常 + */ +@Accessors(chain = true) +public class TenantDatabaseException extends TenantInvalidException { + + public TenantDatabaseException() { + super(); + } + + public TenantDatabaseException(String message) { + super(message); + } + + public TenantDatabaseException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/TenantInvalidException.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/TenantInvalidException.java new file mode 100644 index 0000000..a9ab995 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/TenantInvalidException.java @@ -0,0 +1,32 @@ +package com.yunzhupaas.exception; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +/** + * 租户无效异常 + */ +@Accessors(chain = true) +public class TenantInvalidException extends RuntimeException{ + + @Getter + @Setter + private String logMsg; + @Getter + @Setter + private Object data; + + public TenantInvalidException() { + super(); + } + + public TenantInvalidException(String message) { + super(message); + } + + public TenantInvalidException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/WorkFlowException.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/WorkFlowException.java new file mode 100644 index 0000000..fbef472 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/WorkFlowException.java @@ -0,0 +1,32 @@ +package com.yunzhupaas.exception; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:57 + */ +public class WorkFlowException extends Exception { + + private Integer code = 400; + + public WorkFlowException(Integer code,String message) { + super(message); + this.code = code; + } + + public WorkFlowException(String message,Throwable e) { + super(message,e); + this.code = code; + } + + public WorkFlowException(String message) { + super(message); + } + + public Integer getCode() { + return code; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/WxError.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/WxError.java new file mode 100644 index 0000000..26d8c22 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/WxError.java @@ -0,0 +1,96 @@ +package com.yunzhupaas.exception; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; + +import java.io.Serializable; + +/** + * 微信错误码说明,请阅读: 全局返回码说明 + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:57 + */ +public class WxError implements Serializable { + + private static final long serialVersionUID = 7869786563361406291L; + + @JSONField(name = "errcode") + private int errorCode; + + @JSONField(name = "errmsg") + private String errorMsg; + + private String json; + + public static WxError fromJson(String json) { + WxError error = JSONObject.parseObject(json, WxError.class); + error.setJson(json); + return error; + } + + public static WxError fromJson(JSONObject jsonObject) { + WxError error = WxError.newBuilder().setErrorCode(jsonObject.getInteger("errcode")).setErrorMsg(jsonObject.getString("errmsg")).build(); + + return error; + } + public static Builder newBuilder() { + return new Builder(); + } + + public int getErrorCode() { + return this.errorCode; + } + + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMsg() { + return this.errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } + + public String getJson() { + return this.json; + } + + public void setJson(String json) { + this.json = json; + } + + @Override + public String toString() { + if (this.json != null) { + return this.json; + } + return "错误: Code=" + this.errorCode + ", Msg=" + this.errorMsg; + } + + public static class Builder { + private int errorCode; + private String errorMsg; + + public Builder setErrorCode(int errorCode) { + this.errorCode = errorCode; + return this; + } + + public Builder setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + return this; + } + + public WxError build() { + WxError wxError = new WxError(); + wxError.setErrorCode(this.errorCode); + wxError.setErrorMsg(this.errorMsg); + return wxError; + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/WxErrorException.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/WxErrorException.java new file mode 100644 index 0000000..f344949 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/exception/WxErrorException.java @@ -0,0 +1,31 @@ +package com.yunzhupaas.exception; + +/** + * 微信异常封装 + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:57 + */ +public class WxErrorException extends Exception { + + private static final long serialVersionUID = -6357149550353160810L; + + private WxError error; + + public WxErrorException(WxError error) { + super(error.toString()); + this.error = error; + } + + public WxErrorException(WxError error, Throwable cause) { + super(error.toString(), cause); + this.error = error; + } + + public WxError getError() { + return this.error; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/config/I18nProperties.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/config/I18nProperties.java new file mode 100644 index 0000000..dc213d9 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/config/I18nProperties.java @@ -0,0 +1,28 @@ +package com.yunzhupaas.i18n.config; + +import com.yunzhupaas.constant.GlobalConst; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.boot.autoconfigure.context.MessageSourceProperties; + +/** + * 国际化配置类 + * + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/21 14:00 + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class I18nProperties extends MessageSourceProperties { + + /** + * 未获取到语言设置时默认语言 + */ + private String defaultLanguage = GlobalConst.DEFAULT_LANGUAGE; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/constant/I18nApiConst.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/constant/I18nApiConst.java new file mode 100644 index 0000000..1230363 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/constant/I18nApiConst.java @@ -0,0 +1,16 @@ +package com.yunzhupaas.i18n.constant; + + +/** + * 国际接口 + */ +public class I18nApiConst { + + public I18nApiConst(String baseUrl) { + I18nApiConst.i18nListUrl = baseUrl + "/api/system/BaseLang/ServerLang"; + } + + public static String i18nListUrl; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/constant/I18nConst.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/constant/I18nConst.java new file mode 100644 index 0000000..c02d555 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/constant/I18nConst.java @@ -0,0 +1,12 @@ +package com.yunzhupaas.i18n.constant; + +/** + * 国际化常量 + */ +public class I18nConst { + + public static final String CACHE_KEY_SERVER = "i18n:server:"; + public static final String CACHE_KEY_FRONT = "i18n:front:"; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/core/DynamicMessageSource.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/core/DynamicMessageSource.java new file mode 100644 index 0000000..84658f8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/core/DynamicMessageSource.java @@ -0,0 +1,31 @@ +package com.yunzhupaas.i18n.core; + +import com.yunzhupaas.constant.model.MCode; +import com.yunzhupaas.i18n.provider.I18nMessageProvider; +import org.springframework.context.support.AbstractMessageSource; + +import java.text.MessageFormat; +import java.util.Locale; + +/** + * 自定义消息来源 + */ +public class DynamicMessageSource extends AbstractMessageSource { + + + private I18nMessageProvider i18nMessageProvider; + + public DynamicMessageSource(I18nMessageProvider i18nMessageProvider) { + this.i18nMessageProvider = i18nMessageProvider; + } + + @Override + protected MessageFormat resolveCode(String code, Locale locale) { + MCode i18nMessage = i18nMessageProvider.getI18nMessage(code, locale); + if(i18nMessage != null){ + return createMessageFormat(i18nMessage.getDesc(), locale); + } + return null; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/core/MyReloadableResourceBundleMessageSource.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/core/MyReloadableResourceBundleMessageSource.java new file mode 100644 index 0000000..f78040c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/core/MyReloadableResourceBundleMessageSource.java @@ -0,0 +1,97 @@ +package com.yunzhupaas.i18n.core; + +import cn.hutool.core.util.ReflectUtil; +import com.yunzhupaas.i18n.provider.MessageSourceProvider; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.support.ReloadableResourceBundleMessageSource; + +import java.io.IOException; +import java.io.StringReader; +import java.util.List; +import java.util.Locale; +import java.util.Properties; +import java.util.concurrent.ConcurrentMap; + +/** + * 本地动态消息来源 + * + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/21 14:00 + */ +@Slf4j +public class MyReloadableResourceBundleMessageSource extends ReloadableResourceBundleMessageSource { + + + + @Getter + private final ConcurrentMap cachedPropertiesCopy; + + @Getter + private final ConcurrentMap cachedMergedPropertiesCopy; + + private List messageSourceProviders; + + public MyReloadableResourceBundleMessageSource(List messageSourceProviders) { + this.messageSourceProviders = messageSourceProviders; + cachedPropertiesCopy = (ConcurrentMap) ReflectUtil.getFieldValue(this, "cachedProperties"); + cachedMergedPropertiesCopy = (ConcurrentMap) ReflectUtil.getFieldValue(this, "cachedMergedProperties"); + } + + + @Override + protected PropertiesHolder refreshProperties(String filename, PropertiesHolder propHolder) { + propHolder = super.refreshProperties(filename, propHolder); + // 本地未获取到语言翻译文件, 从自定义来源获取 + if (propHolder.getProperties() == null && messageSourceProviders != null) { + for (MessageSourceProvider messageSourceProvider : messageSourceProviders) { + try { + String config = messageSourceProvider.loadMessageResource(filename, this); + if (config != null) { + propHolder = refreshConfig(filename, config); + break; + } + } catch (Exception e) { + log.error("加载语言配置失败:{}, {}", filename, e.getMessage(), e); + } + } + } + return propHolder; + } + + /** + * 刷新语言配置文件 + * @param filename 语言文件 + * @param config properties内容 + * @throws IOException + */ + public PropertiesHolder refreshConfig(String filename, String config) throws IOException { + long refreshTimestamp = (getCacheMillis() < 0 ? -1 : System.currentTimeMillis()); + Properties properties = new Properties(); + properties.load(new StringReader(config)); + PropertiesHolder propertiesHolder = new PropertiesHolder(properties, refreshTimestamp); + propertiesHolder.setRefreshTimestamp(refreshTimestamp); + this.cachedPropertiesCopy.put(filename, propertiesHolder); + this.cachedMergedPropertiesCopy.clear(); + return propertiesHolder; + } + + /** + * 更新某个语言中的配置 + * + * @param filename 语言文件 + * @param property 语言标识符 + * @param value 语言内容 + */ + public void refreshConfig(String filename, String property, String value) { + PropertiesHolder propertiesHolder = cachedPropertiesCopy.get(filename); + Properties properties = propertiesHolder.getProperties(); + if (properties != null) { + properties.setProperty(property, value); + this.cachedMergedPropertiesCopy.clear(); + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/provider/DynamicMessageProvider.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/provider/DynamicMessageProvider.java new file mode 100644 index 0000000..29865fa --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/provider/DynamicMessageProvider.java @@ -0,0 +1,44 @@ +package com.yunzhupaas.i18n.provider; + +import com.yunzhupaas.util.StringUtil; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Locale; +import java.util.Properties; + +/** + * 动态翻译文件获取 + */ +public interface DynamicMessageProvider { + + + /** + * 返回语言配置Properties文件字符串 + * @param locale + * @return + */ + String getI18nList(Locale locale); + + /** + * 返回语言配置Properties + * @param locale + * @return + */ + default Properties getI18nListProperties(Locale locale){ + String i18nList = getI18nList(locale); + if(i18nList != null){ + Properties properties = new Properties(); + try { + properties.load(new StringReader(i18nList)); + return properties; + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/provider/I18nMessageProvider.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/provider/I18nMessageProvider.java new file mode 100644 index 0000000..39d171d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/provider/I18nMessageProvider.java @@ -0,0 +1,14 @@ +package com.yunzhupaas.i18n.provider; + +import com.yunzhupaas.constant.model.MCode; + +import java.util.Locale; + +/** + * 动态翻译内容获取 + */ +public interface I18nMessageProvider { + + MCode getI18nMessage(String code, Locale locale); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/provider/MessageSourceProvider.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/provider/MessageSourceProvider.java new file mode 100644 index 0000000..9b694a2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/provider/MessageSourceProvider.java @@ -0,0 +1,22 @@ +package com.yunzhupaas.i18n.provider; + + +import com.yunzhupaas.i18n.core.MyReloadableResourceBundleMessageSource; + +import java.io.IOException; + +/** + * 自定义消息来源提供者 + * + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/21 14:00 + */ +public interface MessageSourceProvider { + + String PROPERTIES_SUFFIX = ".properties"; + + String loadMessageResource(String filename, MyReloadableResourceBundleMessageSource messageSource) throws IOException; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/util/I18nUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/util/I18nUtil.java new file mode 100644 index 0000000..4138fd1 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/i18n/util/I18nUtil.java @@ -0,0 +1,68 @@ +package com.yunzhupaas.i18n.util; + +import com.yunzhupaas.constant.model.MCode; +import com.yunzhupaas.i18n.config.I18nProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Component; + +import java.util.Locale; + +/** + * 国际化工具类 + * + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/21 14:00 + */ +@Component +public class I18nUtil { + + private static MessageSource messageSource; + + private static I18nProperties i18nProperties; + + @Autowired(required = false) + public void setMessageSource(MessageSource messageSource) { + I18nUtil.messageSource = messageSource; + } + + @Autowired(required = false) + public void setI18nProperties(I18nProperties i18nProperties) { + I18nUtil.i18nProperties = i18nProperties; + } + + public static String getMessageStr(String code, String message, Locale locale, Object... args) { + if (messageSource == null) { + return message == null ? code : message; + } + if (message != null) { + return messageSource.getMessage(code, args, message, locale); + } + return messageSource.getMessage(code, args, locale); + } + + public static String getMessageStr(String code, String message, Object... args) { + Locale locale; + try { + locale = LocaleContextHolder.getLocale(); + } catch (Exception e) { + locale = Locale.forLanguageTag(i18nProperties.getDefaultLanguage()); + } + return getMessageStr(code, message, locale, args); + } + + + public static String getMessageStr(MCode mCode, Locale locale, Object... args) { + return getMessageStr(mCode.getCode(), mCode.getDesc(), locale, args); + } + + public static String getMessageStr(MCode mCode, Object... args) { + return getMessageStr(mCode.getCode(), mCode.getDesc(), args); + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/BaseSystemInfo.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/BaseSystemInfo.java new file mode 100644 index 0000000..985ea63 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/BaseSystemInfo.java @@ -0,0 +1,253 @@ +package com.yunzhupaas.model; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 系统的核心基础信息 + * + * @author 云筑产品开发平台组 + * @version v5.2.7 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-09-26 上午9:18 + */ +@Data +public class BaseSystemInfo implements Serializable { + /** + * 单一登录:1-后登录踢出先登录、2-同时登陆 + */ + private Integer singleLogin; + /** + * 密码错误次数 + */ + private Integer passwordErrorsNumber; + /** + * 错误策略 1--账号锁定 2--延时登录 + */ + private Integer lockType; + /** + * 延时登录时间 + */ + private Integer lockTime; + /** + * 是否开启验证码 + */ + private Integer enableVerificationCode; + /** + * 验证码位数 + */ + private Integer verificationCodeNumber; + + + + /** + * 超时登出时间小时 + */ + private String tokenTimeout; + /** + * 上次登录时间提示开关 + */ + private Integer lastLoginTimeSwitch=0; + /** + * 公司电话 + */ + private String companyTelePhone; + /** + * appid + */ + private String wxGzhAppId; + /** + * 公司地址 + */ + private String companyAddress; + + private String wxGzhAppSecret; + + private String qyhCorpSecret; + + private String isLog; + + private String emailSmtpPort; + + private String emailPop3Host; + + private String emailSenderName; + /** + * 公司邮箱 + */ + private String companyEmail; + + private String sysName; + /** + * 版权信息 + */ + private String copyright; + + private String qyhAgentId; + + private String lastLoginTime; + + private String emailAccount; + + private String qyhJoinUrl; + + private String whitelistSwitch; + + private String pageSize; + /** + * 系统描述 + */ + private String sysDescription; + + private String emailPassword; + /** + * 公司法人 + */ + private String companyContacts; + /** + * 系统主题 + */ + private String sysTheme; + + private String qyhAgentSecret; + + private String whitelistIp; + /** + * 公司简称 + */ + private String companyCode; + + private String emailSsl; + + private String emailSmtpHost; + + private String registerKey; + + private String wxGzhToken; + + private String qyhJoinTitle; + + private String qyhCorpId; + /** + * 系统版本 + */ + private String sysVersion; + + private String emailPop3Port; + /** + * 公司名称 + */ + private String companyName; + + private String wxGzhUrl; + + /** + * 企业微信-是否同步组织(包含:公司、部门) + */ + private Integer qyhIsSynOrg; + + /** + * 企业微信-是否同步用户 + */ + private Integer qyhIsSynUser; + + + /** + * 钉钉同步公司-部门-用户的应用AppKey + */ + private String dingSynAppKey; + + /** + * 钉钉同步公司-部门-用户的应用AppSecret + */ + private String dingSynAppSecret; + + /** + * 钉钉-是否同步组织(包含:公司、部门) + */ + private Integer dingSynIsSynOrg; + + /** + * 钉钉-是否同步用户 + */ + private Integer dingSynIsSynUser; + + // 图标---- + private String loginIcon; + + private String logoIcon; + + private String appIcon; + + private String navigationIcon; + + private String dingDepartment; + + /** + * 审批链接时效性 + */ + private String linkTime; + + /** + * 链接点击次数 + */ + private Integer isClick; + + /** + * 链接失效次数 + */ + private Integer unClickNum; + + /** 密码策略 */ + /** + * 密码定期更新开关 + */ + private Integer passwordIsUpdatedRegularly; + + /** + * 更新周期 + */ + private Integer updateCycle; + + /** + * 提前N天提醒更新 + */ + private Integer updateInAdvance; + + @Schema(description = "窗口标题") + private String title; + + @Schema(description = "用户密码") + private String newUserDefaultPassword; + + /*以下日程相关属性添加*/ + @Schema(description = "默认视图") + private String defaultView; + @Schema(description = "显示农历") + private Boolean showLunarCalendar; + @Schema(description = "周第一天") + private Integer firstDay; + @Schema(description = "默认时长") + private Integer duration; + @Schema(description = "流程签收") + private Integer flowSign = 0; + @Schema(description = "流程办理") + private Integer flowTodo = 0; + /** + * 1:无范围限制 2:同一部门 3:同一岗位 6:同一公司 + */ + @Schema(description = "委托范围") + private Integer delegateScope = 1; + @Schema(description = "委托确认") + private Integer delegateAck = 0; + @Schema(description = "代理范围") + private Integer proxyScope = 1; + @Schema(description = "代理确认") + private Integer proxyAck = 0; + @Schema(description = "加签层级") + private Integer addSignLevel = 1; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/DbTableConModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/DbTableConModel.java new file mode 100644 index 0000000..052c8af --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/DbTableConModel.java @@ -0,0 +1,52 @@ +package com.yunzhupaas.model; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 数据建模DTO + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-09-26 上午9:18 + */ +@Data +public class DbTableConModel { + /** + * 标识 + */ + private String id; + /** + * 表名 + */ + private String table; + /** + * 新表名 + */ + private String newTable; + /** + * 表说明 + */ + private String tableName; + /** + * 大小 + */ + private String size; + /** + * 总数 + */ + private Integer sum; + /** + * 说明 + */ + private String description; + /** + * 主键 + */ + private String primaryKey; + /** + * 数据源主键 + */ + private String dataSourceId; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FileListVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FileListVO.java new file mode 100644 index 0000000..0ea734b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FileListVO.java @@ -0,0 +1,22 @@ +package com.yunzhupaas.model; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +@Data +public class FileListVO implements Serializable { + @Schema(description = "主键id") + private String fileId; + @Schema(description = "文件名称") + private String fileName; + @Schema(description = "文件大小") + private String fileSize; + @Schema(description = "修改时间") + private String fileTime; + @Schema(description = "文件类型") + private String fileType; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FileModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FileModel.java new file mode 100644 index 0000000..b9dbfeb --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FileModel.java @@ -0,0 +1,22 @@ +package com.yunzhupaas.model; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 附件模型 + * + * @author 云筑产品开发平台组 + * @version v5.2.7 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-09-26 上午9:18 + */ +@Data +public class FileModel { + private String fileId; + private String fileName; + private String fileSize; + private String fileTime; + private String fileState; + private String fileType; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FlowWorkListVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FlowWorkListVO.java new file mode 100644 index 0000000..97f90a6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FlowWorkListVO.java @@ -0,0 +1,25 @@ +package com.yunzhupaas.model; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/15 9:18 + */ +@Data +public class FlowWorkListVO { + private List wait = new ArrayList<>(); + private List flowTask = new ArrayList<>(); + private List flow = new ArrayList<>(); + private List charge = new ArrayList<>(); + private List circulate = new ArrayList<>(); + private List permission = new ArrayList<>(); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FlowWorkModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FlowWorkModel.java new file mode 100644 index 0000000..561f644 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/FlowWorkModel.java @@ -0,0 +1,22 @@ +package com.yunzhupaas.model; + +import lombok.Data; + +import java.util.List; + +/** + * + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + */ +@Data +public class FlowWorkModel { + private String id; + private String fullName; + private String icon; + private String enCode; + private List children; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/MultiTenantType1.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/MultiTenantType1.java new file mode 100644 index 0000000..c3e3c8b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/MultiTenantType1.java @@ -0,0 +1,44 @@ +package com.yunzhupaas.model; + +import lombok.Getter; + +/** + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/9/26 20:32 + */ +@Getter +public enum MultiTenantType1 { + + /** + * 表中字段过滤租户数据 + */ + COLUMN("字段模式"), + + /** + * 动态替换SQL + * {租户ID}.表名 + */ + SCHEMA("SCHEMA模式"); + + + private String directions; + + MultiTenantType1(String directions) { + this.directions = directions; + } + + + public boolean eq(String val) { + return this.name().equalsIgnoreCase(val); + } + + public boolean eq(MultiTenantType1 val) { + if (val == null) { + return false; + } + return eq(val.name()); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/OnlineDevData.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/OnlineDevData.java new file mode 100644 index 0000000..5a17aec --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/OnlineDevData.java @@ -0,0 +1,66 @@ +package com.yunzhupaas.model; + +import lombok.Data; + +/** + * 在线开发常用常量 + */ +@Data +public class OnlineDevData { + /** + * 用于判断是否是有表数据 + */ + public static final String TABLE_CONST = "[]"; + + /** + * 详情id副本 + */ + public static final String INFO_ID = "_id"; + //以下列表类型 + /** + * 列表类型:1-普通列表 + */ + public static final Integer COLUMNTYPE_ONE = 1; + /** + * 列表类型:2-左侧树 + */ + public static final Integer COLUMNTYPE_TOW = 2; + /** + * 列表类型:3-分组 + */ + public static final Integer COLUMNTYPE_THREE = 3; + /** + * 列表类型:4-行内编辑 + */ + public static final Integer COLUMNTYPE_FOUR = 4; + /** + * 列表类型:5-树形列表 + */ + public static final Integer COLUMNTYPE_FIVE = 5; + //状态启用禁用 + /** + * 禁用 + */ + public static final Integer STATE_DISABLE = 0; + /** + * 启用 + */ + public static final Integer STATE_ENABLE = 1; + //表单类型 + /** + * 自定义表单 + */ + public static final Integer FORM_TYPE_DEV = 1; + /** + * 系统表单 + */ + public static final Integer FORM_TYPE_SYS = 2; + + /** + * 默认分类编码encode + */ + public static final String DEFAULT_CATEGATY_ENCODE = "default"; + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/TransferModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/TransferModel.java new file mode 100644 index 0000000..27ea2a8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/TransferModel.java @@ -0,0 +1,19 @@ +package com.yunzhupaas.model; + +import lombok.Data; + +/** + * 版本: V3.0.0 + * 版权: 深圳市乐程软件有限公司 + * 作者: 管理员/admin + * 日期: 2020-10-21 14:23:30 + */ +@Data +public class TransferModel { + private String targetField; + private String targetFieldLabel; + private Integer sourceType; + private String sourceValue; + private Boolean required = false; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/UserMenuModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/UserMenuModel.java new file mode 100644 index 0000000..621e65f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/UserMenuModel.java @@ -0,0 +1,42 @@ +package com.yunzhupaas.model; + +import com.yunzhupaas.util.treeutil.SumTree; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 用户DTO + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-09-26 上午9:18 + */ +@Data +public class UserMenuModel extends SumTree { + private String id; + private String fullName; + private Integer isButtonAuthorize; + private Integer isColumnAuthorize; + private Integer isDataAuthorize; + private Integer isFormAuthorize; + private String enCode; + private String parentId; + private String icon; + private String urlAddress; + private String linkTarget; + private Integer type; + private Boolean isData; + private Integer enabledMark; + private Long sortCode; + private String category; + private String description; + private String propertyJson; + + private String systemId; + private Boolean hasModule; + private Long creatorTime; + + private Boolean disabled =false; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/ai/AiFormFieldModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/ai/AiFormFieldModel.java new file mode 100644 index 0000000..4950ca0 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/ai/AiFormFieldModel.java @@ -0,0 +1,47 @@ +package com.yunzhupaas.model.ai; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * AI生成表单字段模型 + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/17 15:08 + */ +@Data +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class AiFormFieldModel { + + /** + * 字段注释 + */ + private String fieldTitle; + + /** + * 字段名 + */ + private String fieldName; + + /** + * 数据库类型 + */ + private String fieldDbType; + + /** + * 前端组件 + */ + private String fieldComponent; + + /** + * 字典选项 + */ + private List fieldOptions; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/ai/AiFormFieldOptionModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/ai/AiFormFieldOptionModel.java new file mode 100644 index 0000000..66acd70 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/ai/AiFormFieldOptionModel.java @@ -0,0 +1,30 @@ +package com.yunzhupaas.model.ai; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * AI生成表单字段可选字典模型 + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/17 15:08 + */ +@Data +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class AiFormFieldOptionModel { + + /** + * 字典注释 + */ + private String fullName; + + /** + * 字典值 + */ + private String id; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/ai/AiFormModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/ai/AiFormModel.java new file mode 100644 index 0000000..f461d8f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/ai/AiFormModel.java @@ -0,0 +1,43 @@ +package com.yunzhupaas.model.ai; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * AI生成表单模型 + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/17 15:07 + */ +@Data +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class AiFormModel { + + /** + * 表注释 + */ + private String tableTitle; + + /** + * 表名 + */ + private String tableName; + + /** + * 是否主表 + */ + private Boolean isMain; + + /** + * 表字段 + */ + private List fields; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/AllMenuSelectVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/AllMenuSelectVO.java new file mode 100644 index 0000000..8baeecc --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/AllMenuSelectVO.java @@ -0,0 +1,37 @@ +package com.yunzhupaas.model.login; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Data +public class AllMenuSelectVO { + @Schema(description = "主键") + private String id; + @Schema(description = "名称") + private String fullName; + @Schema(description = "菜单编码") + private String enCode; + @Schema(description = "父主键") + private String parentId; + @Schema(description = "图标") + private String icon; + @Schema(description = "是否有下级菜单") + private Boolean hasChildren; + @Schema(description = "菜单地址") + private String urlAddress; + @Schema(description = "链接目标") + private String linkTarget; + @Schema(description = "下级菜单列表") + private List children; + @Schema(description = "菜单分类【1-类别、2-页面】") + private Integer type; + private String propertyJson; + private Long sortCode; + + private String systemId; + private Boolean isData; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/AllUserMenuModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/AllUserMenuModel.java new file mode 100644 index 0000000..0ea757e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/AllUserMenuModel.java @@ -0,0 +1,27 @@ +package com.yunzhupaas.model.login; + + +import com.yunzhupaas.util.treeutil.SumTree; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class AllUserMenuModel extends SumTree { + @Schema(description = "名称") + private String fullName; + @Schema(description = "菜单编码") + private String enCode; + @Schema(description = "图标") + private String icon; + @Schema(description = "菜单地址") + private String urlAddress; + @Schema(description = "链接目标") + private String linkTarget; + @Schema(description = "菜单分类【1-类别、2-页面】") + private Integer type; + private String propertyJson; + private Long sortCode; + + private String systemId; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/MeInfoVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/MeInfoVO.java new file mode 100644 index 0000000..f7ff4eb --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/MeInfoVO.java @@ -0,0 +1,20 @@ +package com.yunzhupaas.model.login; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +@Data +@Accessors(chain = true) +public class MeInfoVO { + + @Schema(description = "用户id") + private String userId; + @Schema(description = "用户账号") + private String userAccount; + @Schema(description = "用户姓名") + private String userName; + @Schema(description = "租户编码") + private String tenantId; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/MenuTreeVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/MenuTreeVO.java new file mode 100644 index 0000000..7c1dbdd --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/MenuTreeVO.java @@ -0,0 +1,37 @@ +package com.yunzhupaas.model.login; + + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +@Data +public class MenuTreeVO implements Serializable { + @Schema(description = "主键") + private String id; + @Schema(description = "名称") + private String fullName; + @Schema(description = "菜单编码") + private String enCode; + @Schema(description = "父主键") + private String parentId; + @Schema(description = "图标") + private String icon; + @Schema(description = "是否有下级菜单") + private Boolean hasChildren = true; + @Schema(description = "菜单地址") + private String urlAddress; + @Schema(description = "链接目标") + private String linkTarget; + @Schema(description = "下级菜单列表") + private List children = new ArrayList<>(); + @Schema(description = "菜单分类【1-类别、2-页面】") + private Integer type; + private String propertyJson; + private Long sortCode; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/PcUserVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/PcUserVO.java new file mode 100644 index 0000000..12978db --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/PcUserVO.java @@ -0,0 +1,41 @@ +package com.yunzhupaas.model.login; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:54 + */ +@Data +public class PcUserVO { + @Schema(description = "菜单集合") + private List menuList; + @Schema(description = "权限集合") + private List permissionList; + @Schema(description = "用户信息") + private UserCommonInfoVO userInfo; + + /** + * 系统配置 + */ + @Schema(description = "系统配置") + private SystemInfo sysConfigInfo; + + public PcUserVO() { + } + + public PcUserVO(List menuList, List permissionList, UserCommonInfoVO userInfo, SystemInfo sysConfigInfo) { + this.menuList = menuList; + this.permissionList = permissionList; + this.userInfo = userInfo; + this.sysConfigInfo = sysConfigInfo; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/PermissionModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/PermissionModel.java new file mode 100644 index 0000000..b3b58d4 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/PermissionModel.java @@ -0,0 +1,16 @@ +package com.yunzhupaas.model.login; +import java.io.Serializable; +import java.util.List; + +import lombok.Data; + +@Data +public class PermissionModel implements Serializable { + private String modelId; + private String moduleName; + private List button; + private List column; + private List resource; + private List form; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/PermissionVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/PermissionVO.java new file mode 100644 index 0000000..bd5f431 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/PermissionVO.java @@ -0,0 +1,11 @@ +package com.yunzhupaas.model.login; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class PermissionVO { + private String id; + private String fullName; + private String enCode; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/SystemInfo.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/SystemInfo.java new file mode 100644 index 0000000..0d9eb4c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/SystemInfo.java @@ -0,0 +1,102 @@ +package com.yunzhupaas.model.login; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 登陆时返回系统配置信息 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024年3月7日08:58:52 + */ +@Data +public class SystemInfo { + /** + * 系统名称 + */ + public String sysName; + + /** + * 系统版本 + */ + public String sysVersion; + + /** + * 登录图标 + */ + public String loginIcon; + + /** + * 版权信息 + */ + public String copyright; + + /** + * 公司名称 + */ + public String companyName; + + /** + * 导航图标 + */ + public String navigationIcon; + + /** + * Logo图片 + */ + public String workLogoIcon; + + /** + * logo图标 + */ + public String logoIcon; + + /** + * App图标 + */ + public String appIcon; + + @Schema(description = "窗口标题") + private String title; + + /** + * 后端服务器域名 + */ + private String yunzhupaasDomain; + + @Schema(description = "用户密码") + private String newUserDefaultPassword; + + /*以下日程相关属性添加*/ + @Schema(description = "默认视图") + private String defaultView; + @Schema(description = "显示农历") + private Boolean showLunarCalendar; + @Schema(description = "周第一天") + private Integer firstDay; + @Schema(description = "默认时长") + private Integer duration; + + @Schema(description = "流程签收") + private Integer flowSign = 0; + @Schema(description = "流程待办") + private Integer flowTodo = 0; + /** + * 1:无范围限制 2:同一部门 3:同一岗位 6:同一公司 + */ + @Schema(description = "委托范围") + private Integer delegateScope = 1; + @Schema(description = "委托确认") + private Integer delegateAck = 0; + @Schema(description = "代理范围") + private Integer proxyScope = 1; + @Schema(description = "代理确认") + private Integer proxyAck = 0; + @Schema(description = "加签层级") + private Integer addSignLevel = 1; +} + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/UserCommonInfoVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/UserCommonInfoVO.java new file mode 100644 index 0000000..0f93dd6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/UserCommonInfoVO.java @@ -0,0 +1,104 @@ +package com.yunzhupaas.model.login; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +@Data +public class UserCommonInfoVO implements Serializable { + @Schema(description = "用户id") + private String userId; + @Schema(description = "用户账号") + private String userAccount; + @Schema(description = "用户姓名") + private String userName; + @Schema(description = "用户头像") + private String headIcon; + @Schema(description = "组织主键") + private String organizeId; + @Schema(description = "组织主键集合") + private List organizeIdList; + @Schema(description = "组织名称") + private String organizeName; + @Schema(description = "岗位") + private List positionIds; + @Schema(description = "系统集合") + private List systemIds; + + private String positionId; + + private String positionName; + + @Schema(description = "上次登录") + private Integer prevLogin; + @Schema(description = "上次登录时间", example = "1") + private Long prevLoginTime; + @Schema(description = "上次登录IP") + private String prevLoginIPAddress; + @Schema(description = "上次登录地址") + private String prevLoginIPAddressName; + @Schema(description = "门户id") + private String portalId; + @Schema(description = "app门户id") + private String appPortalId; + + /** + * 当前组织角色+全局角色 Id数组 + */ + private List roleIds; + + /** + * 当前组织角色+全局角色 名称集合用 , 号隔开 + */ + private String roleName; + + /** + * 直属主管 (u.RealName + "/" + u.Account) + */ + private String manager; + /** + * 手机 + */ + private String mobilePhone; + + /** + * 邮箱 + */ + private String email; + + /** + * 生日 + */ + private Long birthday; + + /** + * 部门id + */ + private String departmentId; + + /** + * 部门名称 结构树 + */ + private String departmentName; + + private Boolean isAdministrator; + private String signImg; + private String signId; + + private Date changePasswordDate; + + private String systemId; + + private String appSystemId; + + private List groupIds; + + private List groupNames; + private int workflowEnabled; + private List standingList; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/UserPositionVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/UserPositionVO.java new file mode 100644 index 0000000..90a8202 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/UserPositionVO.java @@ -0,0 +1,14 @@ +package com.yunzhupaas.model.login; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class UserPositionVO { + @Schema(description = "岗位id") + private String id; + @Schema(description = "岗位名称") + private String name; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/UserSystemVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/UserSystemVO.java new file mode 100644 index 0000000..f05cebb --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/login/UserSystemVO.java @@ -0,0 +1,29 @@ +package com.yunzhupaas.model.login; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:59 + */ +@Data +public class UserSystemVO { + @Schema(description = "系统id") + private String id; + @Schema(description = "系统名称") + private String name; + @Schema(description = "系统图标") + private String icon; + @Schema(description = "系统编码") + private String enCode; + @Schema(description = "是否当前系统") + private boolean currentSystem; + @Schema(description = "是否当前身份") + private boolean currentStanding; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/logout/LogoutResultModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/logout/LogoutResultModel.java new file mode 100644 index 0000000..73101a3 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/logout/LogoutResultModel.java @@ -0,0 +1,19 @@ +package com.yunzhupaas.model.logout; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 退出接口返回结果 + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/11/11 14:19 + */ +@Data +@Accessors(chain = true) +public class LogoutResultModel { + + //单点注销后端接口地址 + private String ssoLogoutApiUrl; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/AdminInfoVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/AdminInfoVO.java new file mode 100644 index 0000000..86a966e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/AdminInfoVO.java @@ -0,0 +1,27 @@ +package com.yunzhupaas.model.tenant; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; +import java.io.Serializable; + +@Data +public class AdminInfoVO implements Serializable { + @Schema(description ="主键") + private String id; + @Schema(description ="账号") + private String account; + @NotNull(message = "姓名不能为空") + @Schema(description ="姓名") + private String realName; + @NotNull(message = "手机号码不能为空") + @Schema(description ="手机号码") + private String mobilePhone; + @NotNull(message = "电子邮箱不能为空") + @Schema(description ="电子邮箱") + private String email; + @Schema(description ="租户id") + private String tenantId; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantAuthorizeModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantAuthorizeModel.java new file mode 100644 index 0000000..cbcc6ed --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantAuthorizeModel.java @@ -0,0 +1,26 @@ +package com.yunzhupaas.model.tenant; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class TenantAuthorizeModel implements Serializable { + /** + * 菜单id + */ + private List moduleIdList = new ArrayList<>(); + + /** + * 菜单地址 + */ + private List urlAddressList = new ArrayList<>(); + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantLinkModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantLinkModel.java new file mode 100644 index 0000000..0e8c4e6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantLinkModel.java @@ -0,0 +1,167 @@ +package com.yunzhupaas.model.tenant; + + +import cn.hutool.core.annotation.Alias; +import cn.hutool.core.bean.BeanUtil; + +import java.io.Serializable; + +/** + * @author :云筑产品开发平台组 + * @version: V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date :2022/3/31 17:41 + */ +public class TenantLinkModel implements Serializable { + /** + * id + */ + public String id; + + /** + * 数据库名 + */ + @Alias("dbName") + public String serviceName; + + /** + * 用户名 + */ + public String userName; + + /** + * 端口 + */ + public String port; + + /** + * 连接名称 + */ + public String fullName; + + /** + * 主机地址 + */ + public String host; + + /** + * 密码 + */ + public String password; + + /** + * 模式 + */ + public String dbSchema; + + /** + * 连接配置(0:主,1:从) + */ + public Integer configType; + + /** + * 数据库类型 + */ + public String dbType; + + /** + * 自定义连接语句 + */ + @Alias("prepareUrl") + public String connectionStr; + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getDbSchema() { + return dbSchema; + } + + public void setDbSchema(String dbSchema) { + this.dbSchema = dbSchema; + } + + public Integer getConfigType() { + return configType; + } + + public void setConfigType(Integer configType) { + this.configType = configType; + } + + public String getDbType() { + return dbType; + } + + public void setDbType(String dbType) { + this.dbType = dbType; + } + + public String getConnectionStr() { + return connectionStr; + } + + public void setConnectionStr(String connectionStr) { + this.connectionStr = connectionStr; + } + + public T toDbLink(T obj){ + BeanUtil.copyProperties(this, obj); + return obj; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuModel.java new file mode 100644 index 0000000..d1fa3b8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuModel.java @@ -0,0 +1,18 @@ +package com.yunzhupaas.model.tenant; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class TenantMenuModel implements Serializable { + private String tenantId; + private List ids; + private List urlAddressList; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuTreeModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuTreeModel.java new file mode 100644 index 0000000..25c9409 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuTreeModel.java @@ -0,0 +1,27 @@ +package com.yunzhupaas.model.tenant; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.yunzhupaas.util.treeutil.SumTree; +import lombok.Data; + +import java.util.List; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/12 15:26 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class TenantMenuTreeModel extends SumTree { + private String fullName; + private String icon; + private Integer type; + private Long sortCode; + private String category; + private boolean disabled; + private String urlAddress; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuTreeReturnModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuTreeReturnModel.java new file mode 100644 index 0000000..16e1fe8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuTreeReturnModel.java @@ -0,0 +1,28 @@ +package com.yunzhupaas.model.tenant; + +import lombok.Data; + +import java.util.List; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/12 15:26 + */ +@Data +public class TenantMenuTreeReturnModel { + private String fullName; + private String icon; + private Integer type; + private Long sortCode; + private String category; + private boolean disabled; + private String id; + private String parentId; + private Boolean hasChildren; + private String urlAddress; + private List children; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuVO.java new file mode 100644 index 0000000..fa02f75 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantMenuVO.java @@ -0,0 +1,26 @@ +package com.yunzhupaas.model.tenant; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/12 15:27 + */ +@Data +public class TenantMenuVO { + @Schema(description = "权限模型集合") + List list = new ArrayList<>(); + @Schema(description = "id集合") + List ids = new ArrayList<>(); + //all字段里面不包括菜单id + @Schema(description = "所有的id") + List all = new ArrayList<>(); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantReSetPasswordForm.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantReSetPasswordForm.java new file mode 100644 index 0000000..9c99bd6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantReSetPasswordForm.java @@ -0,0 +1,30 @@ +package com.yunzhupaas.model.tenant; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; + + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/12 15:31 + */ +@Data +public class TenantReSetPasswordForm { + @NotNull(message = "主键不能为空") + @Schema(description ="主键") + private String id; + @NotNull(message = "新密码不能为空") + @Schema(description ="新密码") + private String userPassword; + @NotNull(message = "确认新密码不能为空") + @Schema(description ="确认新密码") + private String validatePassword; + @Schema(description ="tenantId") + private String tenantId; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantVO.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantVO.java new file mode 100644 index 0000000..3d5244e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/tenant/TenantVO.java @@ -0,0 +1,92 @@ +package com.yunzhupaas.model.tenant; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +/** + * + * BaseTenant模型 + * @版本: V3.1.0 + * @版权: 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @作者: 云筑产品开发平台组 + * @日期: 2020-12-17 16:09:07 + */ +@Data +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class TenantVO implements Serializable { + + + /** + * 无多租户 + */ + public static final int NONE = -1; + /** + * 库隔离 + */ + public static final int SCHEMA = 0; + /** + * 字段隔离 + */ + public static final int COLUMN = 1; + /** + * 指定数据源 + */ + public static final int REMOTE = 2; + + + /** + * 数据库名称 + */ + private String dbName; + + /** + * 租户编码 + */ + private String enCode; + + /** + * 账号限额 + */ + private long accountNum; + + /** + * 数据源模式 + */ + private int type; + + /** + * 配置连接 + */ + private List linkList; + + /** + * 卫翎信息 官网专用 + */ + private Map wl_qrcode; + + @JsonIgnore + public boolean isSchema(){ + return type == SCHEMA; + } + + @JsonIgnore + public boolean isColumn(){ + return type == COLUMN; + } + + @JsonIgnore + public boolean isRemote(){ + return type == REMOTE; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/AbleUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/AbleUtil.java new file mode 100644 index 0000000..589c315 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/AbleUtil.java @@ -0,0 +1,96 @@ +package com.yunzhupaas.model.visualJson; + +import com.yunzhupaas.constant.YunzhupaasConst; +import com.yunzhupaas.constant.PermissionConst; +import com.yunzhupaas.model.visualJson.OnlineCusCheckModel; +import com.yunzhupaas.util.JsonUtil; +import com.yunzhupaas.util.visiual.YunzhupaasKeyConsts; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class AbleUtil { + + public static OnlineCusCheckModel ableModel(String ableIdsAll, String yunzhupaasKey) { + List ableIdList = new ArrayList<>(); + List ableComIds = new ArrayList<>(); + List ableComIdsStr = new ArrayList<>(); + List ableDepIds = new ArrayList<>(); + List ableGroupIds = new ArrayList<>(); + List ableRoleIds = new ArrayList<>(); + List ablePosIds = new ArrayList<>(); + List ableUserIds = new ArrayList<>(); + List ableSystemIds = new ArrayList<>(); + List ableIds = new ArrayList<>(); + + try { + List> list = JsonUtil.getJsonToBean(ableIdsAll, List.class); + for (List ableId : list) { + ableIdList.addAll(ableId); + ableComIdsStr.add(JsonUtil.getListToJsonArray(ableId).toJSONString()); + } + } catch (Exception e) { + List list = JsonUtil.getJsonToBean(ableIdsAll, List.class); + for (String ableId : list) { + ableIdList.add(ableId); + } + } + for (String id : ableIdList) { + String[] split = id.split("--"); + if (split.length > 1) { + if (PermissionConst.COMPANY.equalsIgnoreCase(split[1])) { + ableComIds.add(split[0]); + } + if (PermissionConst.DEPARTMENT.equalsIgnoreCase(split[1])) { + ableDepIds.add(split[0]); + } + if (PermissionConst.USER.equalsIgnoreCase(split[1])) { + ableUserIds.add(split[0]); + } + if (PermissionConst.ROLE.equalsIgnoreCase(split[1])) { + ableRoleIds.add(split[0]); + } + if (PermissionConst.GROUP.equalsIgnoreCase(split[1])) { + ableGroupIds.add(split[0]); + } + if (PermissionConst.POSITION.equalsIgnoreCase(split[1])) { + ablePosIds.add(split[0]); + } + if (PermissionConst.SYSTEM.equalsIgnoreCase(split[1])) { + ableSystemIds.add(split[0]); + } + ableIds.add(id); + } else { + Map param = YunzhupaasConst.SYSTEM_PARAM; + if (param.get(id) != null) { + ableSystemIds.add(id); + } else { + if (YunzhupaasKeyConsts.COMSELECT.equalsIgnoreCase(yunzhupaasKey)) { + ableComIds.add(id); + } + if (YunzhupaasKeyConsts.DEPSELECT.equalsIgnoreCase(yunzhupaasKey)) { + ableDepIds.add(id); + } + if (YunzhupaasKeyConsts.ROLESELECT.equalsIgnoreCase(yunzhupaasKey)) { + ableRoleIds.add(id); + } + if (YunzhupaasKeyConsts.GROUPSELECT.equalsIgnoreCase(yunzhupaasKey)) { + ableGroupIds.add(id); + } + if (YunzhupaasKeyConsts.USERSELECT.equalsIgnoreCase(yunzhupaasKey) + || YunzhupaasKeyConsts.CUSTOMUSERSELECT.equalsIgnoreCase(yunzhupaasKey)) { + ableUserIds.add(id); + } + + } + } + } + OnlineCusCheckModel ableModel = OnlineCusCheckModel.builder().ableComIdsStr(ableComIdsStr) + .ableComIds(ableComIds).ableDepIds(ableDepIds) + .ableGroupIds(ableGroupIds).ablePosIds(ablePosIds).ableRoleIds(ableRoleIds) + .ableSystemIds(ableSystemIds).ableUserIds(ableUserIds).ableIds(ableIds).build(); + return ableModel; + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FieLdsModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FieLdsModel.java new file mode 100644 index 0000000..52483c7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FieLdsModel.java @@ -0,0 +1,432 @@ +package com.yunzhupaas.model.visualJson; + +import com.yunzhupaas.model.visualJson.config.ConfigModel; +import com.yunzhupaas.model.visualJson.options.ColumnOptionModel; +import com.yunzhupaas.model.visualJson.props.PropsModel; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:49 + */ +@Data +public class FieLdsModel { + private ConfigModel config; + private String placeholder; + private Object style; + private Boolean clearable; + private String prefixIcon; + private Integer precision; + private String suffixIcon; + private String maxlength; + private Boolean showWordLimit; + private Boolean readonly; + private Boolean disabled; + /** + * 设置默认值为空字符串 + */ + private String vModel = ""; + private String label; + /** + * 列表拼接字段接收 + */ + private String id = ""; + private String field; + /** + * 是否启用调用签名 + */ + private Boolean isInvoke; + /** + * 关联表单id + */ + private String modelId = ""; + + /** + * 子表表单 + */ + private List footerBtnsList = new ArrayList<>(); + private List columnBtnsList = new ArrayList<>(); + + /** + * 关联表单 二维码 条形码 字段 + */ + private String relationField; + private String relationFieldSource; + private Boolean relationChild = false; + private String relationModel; + private Boolean hasPage; + private String pageSize; + private String type; + private Object autoSize; + private Integer step; + private Boolean stepstrictly; + private Object textStyle; + private Integer lineHeight; + private Integer fontSize; + private Boolean showChinese; + private Boolean showPassword; + private String tipLabel; + + /** + * 链接 + */ + private String target; + private String href; + + /** + * 大小 + */ + private String size; + private Boolean filterable; + /** + * 关联表单属性 + */ + private String showField; + /** + * 多选 + */ + private Boolean multiple = false; + + private Boolean searchMultiple = false; + private Object value; + + /** + * 待定 + */ + private PropsModel props; + /** + * 待定 + */ + private Boolean showAllLevels; + private String separator; + private Boolean isrange; + private String rangeseparator; + private String startplaceholder; + private String endplaceholder; + private String format; + private String valueformat; + private Object pickeroptions; + /** v2评分-最大值*/ + private Integer max; + /** 评分-允许半选*/ + private Boolean allowhalf; + /** v3评分-最大值*/ + private Integer count; + private Boolean showText; + private Boolean showScore; + private Boolean showAlpha; + private String colorformat; + private String activecolor; + private String inactivecolor; + private String activeValue; + private String inactiveValue; + private Integer min; + private Boolean showStops; + private Boolean range; + private String content; + private String header; + private Boolean accordion; + private String tabPosition; + /** + * 未找到 + */ + private String accept; + private Boolean showTip; + private Integer fileSize; + private String sizeUnit; + private Integer limit; + private String contentPosition; + /** + * 标题提示 + */ + private String helpMessage; + private String buttonText; + private Integer level; + private String options; + private String shadow; + private String name; + private String title; + + /** + * 文件路径类型 默认路径:defaultPath 自定义路径:selfPath + */ + private String pathType; + /** + * 时间格式 + */ + private String timeFormat; + /** + * 路径生成规则 + */ + private List sortRule; + /** + * 文件夹名,子级文件用“/”隔开,如:文件1/文件1-1 + */ + private String folder; + + /** + * 查询方式 1.eq 2.like 3.between + */ + private Integer searchType; + private String interfaceId; + private List columnOptions; + private List extraOptions; + /** + * 存储字段(弹窗和关联表单) + */ + private String propsValue; + + /** + * 开关 值 + */ + private String activeTxt; + private String inactiveTxt; + + /** + * 条形码 条码颜色 + */ + private String lineColor; + /** + * 条形码 背景色 + */ + private String background; + /** + * 条形码 宽高 + */ + private Integer width; + private Integer height; + /** + * 条形码 二维码 固定值 + */ + private String staticText; + + private String templateJson = "[]"; + + /** + * 条形码 二维码 类型 (静态,或者组件,当前表单路径) static relation form + */ + private String dataType = ""; + + /** + * 二维码 条码颜色 + */ + private String colorDark; + + /** + * 二维码 背景色 + */ + private String colorLight; + + /** + * 按钮(居中,右,左) + */ + private String align; + + /** + * 子表是否合计 + */ + private Boolean showSummary; + + /** + * 子表合计字段 + */ + private String summaryField; + + /** + * 所属部门展示内容 + */ + private String showLevel; + + /** + * 弹窗 样式属性 + */ + private String popupType; + private String popupTitle; + private String popupWidth; + + + private boolean closable; + + private boolean showIcon; + + private String selectType; + + //自定义 + private String ableDepIds; + private String ableOrgIds; + private String ablePosIds; + private String ableUserIds; + private String ableRoleIds; + private String ableGroupIds; + private String ableIds; + /** + * 导入子表字段数量 + */ + private Integer childrenSize; + /** + * 是否是需要导入的字段 + */ + private boolean needImport; + + private String relationTableForeign; + private String mainTableId; + private String childMainKey; + /** + * 0主表 1 副表 2子表 + */ + private Integer tableType; + private String beforeVmodel; + + private String description; + private String closeText; + + private String tipText; + private String direction; + private String addonAfter; + private String addonBefore; + private Boolean isAmountChinese; + /** + * 数字输入-是否有加减按键 + */ + private String controls; + private String startTime; + private String endTime; + + private String optionType; + /** + * 下拉补全展示条数 + */ + private Integer total; + + /** + * 单选框按键风格 + */ + private String buttonStyle; + + /** + * 千分位开关 + */ + private boolean thousands = false; + + /** + * 千分位字段列表 + */ + private List thousandsField = new ArrayList<>(); + + /** + * 展示 存储数据 0-不存储,1-存储 + */ + private Integer isStorage; + + //高级搜索 + private String fieldValue; + private Object fieldValueOne; + private Object fieldValueTwo; + private List dataList = new ArrayList<>(); + private String fieldValueType; + private String symbol; + + /** + * 地图属性 + */ + private boolean autoLocation = false; + private boolean enableLocationScope = false; + private int adjustmentScope; + private boolean enableDesktopLocation = false; + private List locationScope; + + /** + * 列表字段是否关键词 + */ + private Boolean isKeyword = false; + private Boolean sortable = false; + + /** + * 是否选中数据及子信息(只针对视图) + */ + private Boolean isIncludeSubordinate = false; + + private Boolean useScan = false; + private Boolean useMask = false; + private Object maskConfig; + + /** + * iframe属性 + * borderType 边框 ,borderColor 边框颜色 , borderWidth边框宽度 + */ + private String borderType; + private String borderColor; + private Integer borderWidth; + + /** + * 单行输入控件和多行输入控件,总字数 + */ + private Boolean showCount; + + //针对命名规范添加的字段 + /** + * 表别名 + */ + private String tableAlias; + /** + * 字段别名 + */ + private String fieldAlias; + /** + * 计算公式表达式 + */ + private String expression; + + + private String layoutType; + + private Boolean defaultExpandAll; + + /** + * 步骤条:风格 + */ + private Boolean simple; + /** + * 步骤条:当前状态 + */ + private String processStatus; + /** + * 步骤条:图标 + */ + private String icon; + + /** + * 多语言字段 + */ + private String placeholderI18nCode; + private String contentI18nCode; + private String helpMessageI18nCode; + private String buttonTextI18nCode; + private String titleI18nCode; + private String descriptionI18nCode; + private String closeTextI18nCode; + private String labelI18nCode; + private String tipLabelI18nCode; + private String headerI18nCode; + + /** + * 关联表单:0-简易查询,1-全部查询 + */ + private Integer queryType; + /** + * 列表查询:true-隐藏,false-显示 + */ + private Boolean noShow=false; + /** + * 列表查询:1-四舍五入,2-截断舍入,3-向上取整,4-向下取整 + */ + private Integer roundType; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FooterBtnsModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FooterBtnsModel.java new file mode 100644 index 0000000..c520a7e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FooterBtnsModel.java @@ -0,0 +1,17 @@ +package com.yunzhupaas.model.visualJson; + +import lombok.Data; + +@Data +public class FooterBtnsModel { + private String value; + private String label; + private String labelI18nCode; + private Boolean show = true; + private String btnType; + private String btnIcon; + private String actionConfig; + private String showConfirm; + private Integer actionType; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FormCloumnUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FormCloumnUtil.java new file mode 100644 index 0000000..f79e069 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FormCloumnUtil.java @@ -0,0 +1,488 @@ +package com.yunzhupaas.model.visualJson; + +import cn.hutool.core.bean.BeanUtil; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.model.visualJson.analysis.*; +import com.yunzhupaas.model.visualJson.config.ConfigModel; +import com.yunzhupaas.model.visualJson.config.HeaderModel; +import com.yunzhupaas.util.JsonUtil; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.visiual.YunzhupaasKeyConsts; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 在线工作流开发 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2023/09/27 + */ +public class FormCloumnUtil { + + /** + * 引擎递归 + **/ + public static void recursionFormGen(RecursionForm recursionForm, List formAllModel) { + List tableModelList = recursionForm.getTableModelList(); + List list = recursionForm.getList(); + for (FieLdsModel item : list) { + FieLdsModel fieLdsModel = BeanUtil.copyProperties(item, FieLdsModel.class); + FormAllModel start = new FormAllModel(); + FormAllModel end = new FormAllModel(); + ConfigModel config = fieLdsModel.getConfig(); + String tipLable = StringUtil.isNotEmpty(config.getTipLabel()) + ? config.getTipLabel().trim().replaceAll("\r", "").replaceAll("\n", " ") + : config.getTipLabel(); + config.setTipLabel(tipLable); + String visibility = config.getVisibility(); + multipleChoices(config); + String yunzhupaaskey = config.getYunzhupaasKey(); + List childrenList = config.getChildren(); + List keyList = Arrays.asList( + FormEnum.row.getMessage(), + FormEnum.card.getMessage(), + FormEnum.tab.getMessage(), + FormEnum.tabItem.getMessage(), + FormEnum.collapse.getMessage(), + FormEnum.collapseItem.getMessage(), + FormEnum.tableGrid.getMessage(), + FormEnum.tableGridTr.getMessage(), + FormEnum.tableGridTd.getMessage(), + FormEnum.STEPS.getMessage(), + FormEnum.STEP_ITEM.getMessage()); + boolean isEndYunzhupaasKey = FormEnum.collapseItem.getMessage().equals(yunzhupaaskey) + || FormEnum.tabItem.getMessage().equals(yunzhupaaskey) + || FormEnum.STEP_ITEM.getMessage().equals(yunzhupaaskey); + if (keyList.contains(yunzhupaaskey) || isEndYunzhupaasKey) { + String key = yunzhupaaskey; + if (FormEnum.collapseItem.getMessage().equals(yunzhupaaskey)) { + key = FormEnum.collapse.getMessage(); + } + if (FormEnum.tabItem.getMessage().equals(yunzhupaaskey)) { + key = FormEnum.tab.getMessage(); + } + if (FormEnum.STEP_ITEM.getMessage().equals(yunzhupaaskey)) { + key = FormEnum.STEPS.getMessage(); + } + // 布局属性 + FormModel formModel = JsonUtil.getJsonToBean(fieLdsModel, FormModel.class); + formModel.setSpan(config.getSpan()); + int activeId = 0; + if (StringUtil.isNotEmpty(config.getActive())) { + List children = config.getChildren(); + for (int i = 0; i < children.size(); i++) { + String name = children.get(i).getName(); + if (config.getActive().equals(name)) { + activeId = i; + } + } + } + formModel.setActiveIndex(activeId + ""); + formModel.setActive(config.getActive()); + formModel.setChildNum(config.getChildNum()); + formModel.setModel(config.getModel()); + formModel.setVisibility(config.getVisibility()); + formModel.setMerged(config.getMerged()); + formModel.setColspan(config.getColspan()); + formModel.setRowspan(config.getRowspan()); + formModel.setRowType(config.getRowType()); + formModel.setBorderType(config.getBorderType()); + formModel.setBorderWidth(config.getBorderWidth()); + formModel.setBorderColor(config.getBorderColor()); + String outermost = !isEndYunzhupaasKey ? "0" : "1"; + if (FormEnum.tab.getMessage().equals(key) || FormEnum.collapse.getMessage().equals(key) + || FormEnum.STEPS.getMessage().equals(key)) { + if (!isEndYunzhupaasKey) { + String chidModel = "active" + key + formModel.getConfig().getFormId(); + formModel.setModel(chidModel); + for (int i = 0; i < childrenList.size(); i++) { + FieLdsModel childModel = childrenList.get(i); + ConfigModel childConfig = childModel.getConfig(); + childConfig.setVisibility(visibility); + childConfig.setModel(chidModel); + childConfig.setChildNum(i); + multipleChoices(childConfig); + childModel.setConfig(childConfig); + } + formModel.setChildren(childrenList); + } + formModel.setOutermost(outermost); + } + start.setYunzhupaasKey(key); + start.setFormModel(formModel); + formAllModel.add(start); + RecursionForm recursion = new RecursionForm(childrenList, tableModelList); + recursionFormGen(recursion, formAllModel); + end.setIsEnd("1"); + end.setYunzhupaasKey(key); + // 折叠、标签的判断里层还是外层 + FormModel endFormModel = new FormModel(); + endFormModel.setOutermost(outermost); + endFormModel.setConfig(config); + end.setFormModel(endFormModel); + formAllModel.add(end); + } else if (FormEnum.table.getMessage().equals(yunzhupaaskey)) { + tableModel(fieLdsModel, formAllModel); + } else if (FormEnum.isModel(yunzhupaaskey)) { + FormModel formModel = JsonUtil.getJsonToBean(fieLdsModel, FormModel.class); + formModel.setVisibility(fieLdsModel.getConfig().getVisibility()); + start.setYunzhupaasKey(yunzhupaaskey); + start.setFormModel(formModel); + formAllModel.add(start); + } else { + model(fieLdsModel, formAllModel, tableModelList); + } + } + for (FormAllModel formModel : formAllModel) { + if (FormEnum.mast.getMessage().equals(formModel.getYunzhupaasKey())) { + setRelationFieldAttr(formAllModel, formModel.getFormColumnModel().getFieLdsModel()); + } else if (FormEnum.mastTable.getMessage().equals(formModel.getYunzhupaasKey())) { + setRelationFieldAttr(formAllModel, formModel.getFormMastTableModel().getMastTable().getFieLdsModel()); + } + } + } + + /** + * 多端选择 + * + * @param configModel + * @return + */ + private static ConfigModel multipleChoices(ConfigModel configModel) { + String visibility = configModel.getVisibility(); + if (Objects.nonNull(visibility)) { + configModel.setApp(visibility.contains("app")); + configModel.setPc(visibility.contains("pc")); + } + return configModel; + } + + /** + * 主表属性添加 + **/ + private static void model(FieLdsModel fieLdsModel, List formAllModel, + List tableModelList) { + FormColumnModel mastModel = formModel(fieLdsModel); + FormAllModel formModel = new FormAllModel(); + formModel.setYunzhupaasKey(FormEnum.mast.getMessage()); + formModel.setFormColumnModel(mastModel); + if (tableModelList.size() > 0) { + TableModel tableModel = tableModelList.stream() + .filter(t -> t.getTable().equals(fieLdsModel.getConfig().getTableName())).findFirst().orElse(null); + if (tableModel == null) { + Optional first = tableModelList.stream().filter(t -> "1".equals(t.getTypeId())).findFirst(); + if (first.isPresent()) { + tableModel = first.get(); + } else { + throw new RuntimeException(MsgCode.VS409.get()); + } + } + String type = tableModel.getTypeId(); + if ("1".equals(type)) { + mastModel.getFieLdsModel().getConfig().setTableName(tableModel.getTable()); + formModel.setFormColumnModel(mastModel); + formAllModel.add(formModel); + } else { + mastTable(tableModel, fieLdsModel, formAllModel); + } + } else { + formAllModel.add(formModel); + } + } + + /** + * 主表的属性是子表字段 + */ + private static void mastTable(TableModel tableModel, FieLdsModel fieLdsModel, List formAllModel) { + FormMastTableModel childModel = new FormMastTableModel(); + String vModel = fieLdsModel.getVModel(); + List tableFieldsList = tableModel.getFields(); + String mastKey = "yunzhupaas_" + tableModel.getTable() + "_yunzhupaas_"; + TableFields tableFields = tableFieldsList.stream() + .filter(t -> StringUtil.isNotEmpty(vModel) && vModel.equals(mastKey + t.getField())).findFirst() + .orElse(null); + FormAllModel formModel = new FormAllModel(); + formModel.setYunzhupaasKey(FormEnum.mastTable.getMessage()); + if (tableFields != null) { + childModel.setTable(tableModel.getTable()); + formModel.setFormMastTableModel(childModel); + childModel.setField(tableFields.getField()); + childModel.setVModel(vModel); + } + FormColumnModel mastTable = formModel(fieLdsModel); + childModel.setMastTable(mastTable); + formAllModel.add(formModel); + } + + /** + * 子表表属性添加 + **/ + private static void tableModel(FieLdsModel model, List formAllModel) { + List childList = new ArrayList<>(); + ConfigModel config = model.getConfig(); + List childModelList = config.getChildren(); + List childFieldList = new ArrayList<>(); + List complexHeaderList = config.getComplexHeaderList(); + String table = model.getVModel(); + List summaryField = StringUtil.isNotEmpty(model.getSummaryField()) + ? JsonUtil.getJsonToList(model.getSummaryField(), String.class) + : new ArrayList<>(); + Map summaryName = new HashMap<>(); + for (int i = 0; i < childModelList.size(); i++) { + FieLdsModel childmodel = childModelList.get(i); + String vModel = childmodel.getVModel(); + FormColumnModel childModel = formModel(childmodel); + boolean isSummary = summaryField.contains(vModel); + if (isSummary) { + summaryName.put(vModel, childmodel.getConfig().getLabel()); + } + relationModel(childModelList, childmodel); + String tableFixed = childModel.getFieLdsModel().getConfig().getTableFixed(); + // 子表复杂表头不能包含冻结字段 + if (tableFixed == null || "none".equals(tableFixed)) { + for (HeaderModel headerModelList : complexHeaderList) { + List headerFieldList = headerModelList.getChildList(); + if (headerModelList.getChildColumns().contains(vModel)) { + headerFieldList.add(childModel); + } + if (headerFieldList.size() > 0) { + headerModelList.setChildList(headerFieldList); + } + } + } + childList.add(childModel); + } + + // 复杂表头抽取排序 + List headerList = new ArrayList<>(); + Map firstField = new HashMap<>(); + List complexAllKey = new ArrayList<>(); + for (HeaderModel headerModel : complexHeaderList) { + List headerChildListAll = headerModel.getChildList(); + List headerChildList = new ArrayList<>(); + for (String item : headerModel.getChildColumns()) { + FormColumnModel columnModel = headerChildListAll.stream() + .filter(t -> item.equals(t.getFieLdsModel().getVModel())).findFirst().orElse(null); + if (columnModel != null) { + ConfigModel headerConfig = columnModel.getFieLdsModel().getConfig(); + Boolean noShow = headerConfig.getNoShow(); + if (!noShow) { + complexAllKey.add(columnModel.getFieLdsModel().getVModel()); + headerChildList.add(columnModel); + } + } + } + headerModel.setChildList(headerChildList); + if (headerChildList.size() > 0) { + firstField.put(headerChildList.get(0).getFieLdsModel().getVModel(), headerModel); + headerList.add(headerModel); + } + } + // 重整子表列表(复杂表头和列表同列) + for (FormColumnModel item : childList) { + if (complexAllKey.contains(item.getFieLdsModel().getVModel())) { + if (firstField.get(item.getFieLdsModel().getVModel()) != null) { + FormColumnModel itemnew = new FormColumnModel(); + itemnew.setHeaderModel(firstField.get(item.getFieLdsModel().getVModel())); + childFieldList.add(itemnew); + } + } else { + childFieldList.add(item); + } + } + + multipleChoices(config); + FormColumnTableModel tableModel = JsonUtil.getJsonToBean(config, FormColumnTableModel.class); + String tipLable = StringUtil.isNotEmpty(tableModel.getTipLabel()) + ? tableModel.getTipLabel().trim().replaceAll("\r", "").replaceAll("\n", " ") + : tableModel.getTipLabel(); + tableModel.setTipLabel(tipLable); + tableModel.setTableModel(table); + tableModel.setChildList(childList); + tableModel.setComplexHeaderList(headerList); + tableModel.setChildFieldList(childFieldList); + tableModel.setShowSummary(model.getShowSummary()); + tableModel.setSummaryField(JsonUtil.getObjectToString(summaryField)); + tableModel.setSummaryFieldName(JsonUtil.getObjectToString(summaryName)); + tableModel.setThousands(model.isThousands()); + tableModel.setVisibility(config.getVisibility()); + tableModel.setColumnBtnsList(model.getColumnBtnsList()); + tableModel.setFooterBtnsList(model.getFooterBtnsList()); + tableModel.setLayoutType(model.getLayoutType()); + tableModel.setDefaultExpandAll(model.getDefaultExpandAll()); + FormAllModel formModel = new FormAllModel(); + formModel.setYunzhupaasKey(FormEnum.table.getMessage()); + formModel.setChildList(tableModel); + formAllModel.add(formModel); + } + + private static void relationModel(List childModelList, FieLdsModel childmodel) { + ConfigModel config = childmodel.getConfig(); + String yunzhupaaskey = config.getYunzhupaasKey(); + String startRelationField = config.getStartRelationField(); + String endRelationField = config.getEndRelationField(); + String childRelationField = childmodel.getRelationField(); + if (FormEnum.relationFormAttr.getMessage().equals(yunzhupaaskey) + || FormEnum.popupAttr.getMessage().equals(yunzhupaaskey)) { + String relationField = childmodel.getRelationField().split("_yunzhupaasTable_")[0]; + FieLdsModel child = childModelList.stream().filter(t -> relationField.equals(t.getVModel())).findFirst() + .orElse(null); + if (child != null) { + childmodel.setInterfaceId(child.getInterfaceId()); + childmodel.setModelId(child.getModelId()); + childmodel.setPropsValue(child.getPropsValue()); + if (StringUtil.isEmpty(childmodel.getRelationFieldSource())) { + childmodel.setRelationFieldSource(childmodel.getRelationField()); + } + if (Objects.equals(0, childmodel.getIsStorage())) { + childmodel.getConfig().setNoShow(child.getConfig().getNoShow()); + } + childmodel.setRelationField(relationField); + } + } + if (YunzhupaasKeyConsts.USERSELECT.equals(yunzhupaaskey) && StringUtil.isNotEmpty(childRelationField)) { + String[] relationField = childRelationField.split("-"); + if (relationField.length > 1) { + childmodel.setRelationField(relationField[1]); + } + childmodel.setRelationChild(relationField.length > 1); + } + if (YunzhupaasKeyConsts.DATE.equals(yunzhupaaskey) || YunzhupaasKeyConsts.TIME.equals(yunzhupaaskey)) { + if (StringUtil.isNotEmpty(startRelationField)) { + String[] relationField = startRelationField.split("-"); + if (relationField.length > 1) { + childmodel.getConfig().setStartRelationField(relationField[1]); + } + childmodel.getConfig().setStartChild(relationField.length > 1); + } + if (StringUtil.isNotEmpty(endRelationField)) { + String[] relationField = endRelationField.split("-"); + if (relationField.length > 1) { + childmodel.getConfig().setEndRelationField(relationField[1]); + } + childmodel.getConfig().setEndRChild(relationField.length > 1); + } + } + } + + /** + * 属性赋值 + **/ + private static FormColumnModel formModel(FieLdsModel model) { + ConfigModel configModel = model.getConfig(); + multipleChoices(configModel); + if (configModel.getDefaultValue() instanceof String) { + configModel.setValueType("String"); + } + if (configModel.getDefaultValue() == null) { + configModel.setValueType("undefined"); + } + FormColumnModel formColumnModel = new FormColumnModel(); + formColumnModel.setFieLdsModel(model); + return formColumnModel; + } + + /** + * 判断重复子表 + * + * @return + */ + public static boolean repetition(RecursionForm recursionForm, List formAllModel) { + boolean flag = false; + List tableModelList = recursionForm.getTableModelList(); + recursionForm(recursionForm, formAllModel); + if (tableModelList.size() > 0) { + List tables = formAllModel.stream() + .filter(t -> FormEnum.table.getMessage().equals(t.getYunzhupaasKey())).collect(Collectors.toList()); + List mastTable = formAllModel.stream() + .filter(t -> FormEnum.mastTable.getMessage().equals(t.getYunzhupaasKey())) + .collect(Collectors.toList()); + List tableList = tables.stream().map(t -> t.getChildList().getTableName()) + .collect(Collectors.toList()); + List mastTableList = mastTable.stream().map(t -> t.getFormMastTableModel().getTable()) + .collect(Collectors.toList()); + flag = tableList.stream().filter(item -> mastTableList.contains(item)).count() > 0; + } + return flag; + } + + /** + * 获取关联表单字段信息 + * + * @param + * @return + * @copyright 深圳市乐程软件有限公司 + * @date 2023/3/29 + */ + private static void setRelationFieldAttr(List formAllModel, FieLdsModel formModel) { + String yunzhupaaskey = formModel.getConfig().getYunzhupaasKey(); + if (FormEnum.relationFormAttr.getMessage().equals(yunzhupaaskey) + || FormEnum.popupAttr.getMessage().equals(yunzhupaaskey)) { + List fieLdsModelList = new ArrayList<>(); + fieLdsModelList.addAll(formAllModel.stream().filter(t -> t.getFormColumnModel() != null) + .map(t -> t.getFormColumnModel().getFieLdsModel()).collect(Collectors.toList())); + fieLdsModelList.addAll(formAllModel.stream().filter(t -> t.getFormMastTableModel() != null) + .map(t -> t.getFormMastTableModel().getMastTable().getFieLdsModel()).collect(Collectors.toList())); + relationModel(fieLdsModelList, formModel); + } + } + + /** + * 在线开发表单解析。(不包含布局控件) + * + * @param recursionForm + * @param formAllModel + */ + public static void recursionForm(RecursionForm recursionForm, List formAllModel) { + recursionFormOnline(recursionForm, formAllModel, true); + } + + public static void recursionFormOnline(RecursionForm recursionForm, List formAllModel, boolean flag) { + List tableModelList = recursionForm.getTableModelList(); + List list = recursionForm.getList(); + for (FieLdsModel item : list) { + FieLdsModel fieLdsModel = BeanUtil.copyProperties(item, FieLdsModel.class); + ConfigModel config = fieLdsModel.getConfig(); + String yunzhupaaskey = config.getYunzhupaasKey(); + List childrenList = config.getChildren(); + List keyList = Arrays.asList( + FormEnum.row.getMessage(), + FormEnum.card.getMessage(), + FormEnum.tab.getMessage(), + FormEnum.tabItem.getMessage(), + FormEnum.collapse.getMessage(), + FormEnum.collapseItem.getMessage(), + FormEnum.tableGrid.getMessage(), + FormEnum.tableGridTr.getMessage(), + FormEnum.tableGridTd.getMessage(), + FormEnum.STEPS.getMessage(), + FormEnum.STEP_ITEM.getMessage()); + boolean isEndYunzhupaasKey = FormEnum.collapseItem.getMessage().equals(yunzhupaaskey) + || FormEnum.tabItem.getMessage().equals(yunzhupaaskey) + || FormEnum.STEP_ITEM.getMessage().equals(yunzhupaaskey); + if (keyList.contains(yunzhupaaskey) || isEndYunzhupaasKey) { + RecursionForm recursion = new RecursionForm(childrenList, tableModelList); + recursionFormOnline(recursion, formAllModel, false); + } else if (FormEnum.table.getMessage().equals(yunzhupaaskey)) { + tableModel(fieLdsModel, formAllModel); + } else if (FormEnum.isModel(yunzhupaaskey)) { + continue; + } else { + model(fieLdsModel, formAllModel, tableModelList); + } + } + if (flag) { + for (FormAllModel formModel : formAllModel) { + if (FormEnum.mast.getMessage().equals(formModel.getYunzhupaasKey())) { + setRelationFieldAttr(formAllModel, formModel.getFormColumnModel().getFieLdsModel()); + } else if (FormEnum.mastTable.getMessage().equals(formModel.getYunzhupaasKey())) { + setRelationFieldAttr(formAllModel, + formModel.getFormMastTableModel().getMastTable().getFieLdsModel()); + } + } + } + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FormDataModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FormDataModel.java new file mode 100644 index 0000000..9f52b88 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/FormDataModel.java @@ -0,0 +1,94 @@ +package com.yunzhupaas.model.visualJson; + +import lombok.Data; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:49 + */ +@Data +public class FormDataModel { + /** + * 模块 + */ + private String areasName; + /** + * 功能名称 + */ + private String className; + /** + * 后端目录 + */ + private String serviceDirectory; + /** + * 所属模块 + */ + private String module; + /** + * 子表名称集合 + */ + private String subClassName; + + + private String formRef; + private String formModel; + private String size; + private String labelPosition; + private Integer labelWidth; + private String formRules; + private String drawerWidth; + private Integer gutter; + private Boolean disabled; + private String span; + private Boolean formBtns; + private Integer idGlobal; + private String fields; + private String popupType; + private String fullScreenWidth; + private String formStyle; + private String generalWidth; + private Boolean hasCancelBtn; + private String cancelButtonText; + private String cancelButtonTextI18nCode; + private Boolean hasConfirmBtn; + private String confirmButtonText; + private String confirmButtonTextI18nCode; + private Boolean hasPrintBtn; + private String printButtonText; + private String printButtonTextI18nCode; + private Boolean hasConfirmAndAddBtn; + private String confirmAndAddText; + private String labelSuffix; + + private String[] printId; + + private FieLdsModel children; + + //主键策略 默认 雪花 + private Integer primaryKeyPolicy = 1; + //并发锁 + private Boolean concurrencyLock = false; + // 过滤规则 + private String ruleList; + // 过滤规则app + private String ruleListApp; + //逻辑删除 + private Boolean logicalDelete = false; + //数据日志 + private boolean dataLog; + //业务主键属性 + private boolean useBusinessKey; + private String[] businessKeyList; + private String businessKeyTip; + + public void setPrimaryKeyPolicy(Integer primaryKeyPolicy) { + if (primaryKeyPolicy == null) { + this.primaryKeyPolicy = 1; + } else { + this.primaryKeyPolicy = primaryKeyPolicy; + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/OnlineCusCheckModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/OnlineCusCheckModel.java new file mode 100644 index 0000000..d288953 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/OnlineCusCheckModel.java @@ -0,0 +1,44 @@ +package com.yunzhupaas.model.visualJson; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OnlineCusCheckModel { + @Builder.Default + private List ableDepIds = new ArrayList<>(); + @Builder.Default + private List ableComIds = new ArrayList<>(); + @Builder.Default + private List ableComIdsStr = new ArrayList<>(); + @Builder.Default + private List ableGroupIds = new ArrayList<>(); + @Builder.Default + private List ablePosIds = new ArrayList<>(); + @Builder.Default + private List ableRoleIds = new ArrayList<>(); + @Builder.Default + private List ableUserIds = new ArrayList<>(); + @Builder.Default + private List ableSystemIds = new ArrayList<>(); + @Builder.Default + private List ableIds = new ArrayList<>(); + + /** + * 数据 + */ + @Builder.Default + private List dataList = new ArrayList<>(); + /** + * 控件类型 + */ + private String controlType; +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/TableFields.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/TableFields.java new file mode 100644 index 0000000..cc29330 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/TableFields.java @@ -0,0 +1,21 @@ +package com.yunzhupaas.model.visualJson; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TableFields { + private String field; + private String aliasName; + private String fieldName; + private String dataType; + private Integer primaryKey; + + public TableFields(String field, String fieldName) { + this.field = field; + this.fieldName = fieldName; + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/TableModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/TableModel.java new file mode 100644 index 0000000..0897068 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/TableModel.java @@ -0,0 +1,56 @@ +package com.yunzhupaas.model.visualJson; + +import lombok.Data; + +import java.util.List; + +@Data +public class TableModel { + + /** + * 类型:1-主表、0-子表 + */ + private String typeId; + /** + * 表名 + */ + private String table; + /** + * 说明 + */ + private String comment; + /** + * 说明 + */ + private String tableName; + /** + * 主键 + */ + private String tableKey; + /** + * 外键字段 + */ + private String tableField; + /** + * 关联主表 + */ + private String relationTable; + /** + * 关联主键 + */ + private String relationField; + + private List fields; + + private String initName; + + /** + * 是否子表, sub:子表 sub-yunzhupaas:副表 main:主表 + */ + private String tableTag; + + /** + * 别名 + */ + private String aliasName; +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/TemplateJsonModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/TemplateJsonModel.java new file mode 100644 index 0000000..6b4f08d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/TemplateJsonModel.java @@ -0,0 +1,26 @@ +package com.yunzhupaas.model.visualJson; + +import com.yunzhupaas.emnus.TemplateEnum; +import lombok.Data; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:56 + */ +@Data +public class TemplateJsonModel { + private String fieldName; + private String field; + private String defaultValue; + private String yunzhupaasKey; + private String dataType; + private String id; + private String required; + private Boolean isSubTable = false; + private String relationField; + private String msgTemplateId; + private Integer sourceType = TemplateEnum.Field.getCode(); +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/UploaderTemplateModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/UploaderTemplateModel.java new file mode 100644 index 0000000..b4159e6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/UploaderTemplateModel.java @@ -0,0 +1,20 @@ +package com.yunzhupaas.model.visualJson; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:58 + */ +@Data +public class UploaderTemplateModel { + private String dataType; + private List selectKey = new ArrayList<>(); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormAllModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormAllModel.java new file mode 100644 index 0000000..4c84761 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormAllModel.java @@ -0,0 +1,30 @@ +package com.yunzhupaas.model.visualJson.analysis; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 解析引擎 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/15 9:19 + */ +@Data +public class FormAllModel { + /** + * 所有模板的标签 row(栅格)、card(卡片)、table(子表)、mast(主表)、mastTable(主表)、groupTitle(分组标题) + **/ + private String yunzhupaasKey; + /** 是否是结束标签 0.不是 1.是 **/ + private String isEnd = "0"; + /** 主表数据 **/ + private FormColumnModel formColumnModel; + /** 子表的数据 **/ + private FormColumnTableModel childList; + /** 栅格和卡片等数据 **/ + private FormModel formModel; + /** 主表中有子表数据 **/ + private FormMastTableModel formMastTableModel; +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormColumnModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormColumnModel.java new file mode 100644 index 0000000..2cbaf29 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormColumnModel.java @@ -0,0 +1,23 @@ +package com.yunzhupaas.model.visualJson.analysis; + +import com.yunzhupaas.model.visualJson.FieLdsModel; +import io.swagger.v3.oas.annotations.media.Schema; +import com.yunzhupaas.model.visualJson.config.HeaderModel; +import lombok.Data; + +/** + * 解析引擎 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/15 9:19 + */ +@Data +public class FormColumnModel { + + private FieLdsModel fieLdsModel; + + private HeaderModel headerModel; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormColumnTableModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormColumnTableModel.java new file mode 100644 index 0000000..a5b3cd2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormColumnTableModel.java @@ -0,0 +1,110 @@ +package com.yunzhupaas.model.visualJson.analysis; +import com.yunzhupaas.model.visualJson.FooterBtnsModel; +import com.yunzhupaas.model.visualJson.config.HeaderModel; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * 解析引擎 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/15 9:19 + */ +@Data +public class FormColumnTableModel { + + /**json原始名称**/ + private String tableModel; + /**表名称**/ + private String tableName; + /**标题**/ + private String label; + private String tipLabel; + /**宽度**/ + private Integer span; + /**是否显示标题**/ + private boolean showTitle; + /**按钮名称**/ + private String actionText; + /**子表的属性**/ + private List childList; + private List complexHeaderList; + private List childFieldList; + /**app子表属性**/ + private String fieLdsModel; + + /** + * 子表是否合计 + */ + private Boolean showSummary; + + /** + * 子表合计字段 + */ + private String summaryField; + + /** + * app子表合计名称 + */ + private String summaryFieldName; + + /** + * 代码生成器多端显示 + */ + private boolean app = true; + private boolean pc = true; + + private String visibility; + private boolean required = false; + /** + * 别名 + */ + private String aliasClassName; + /** + * 别名首字母小写 + */ + private String aliasLowName; + + /** + * 别名首字母大写 + */ + private String aliasUpName; + /** + * 千分位开关 + */ + private boolean thousands=false; + /** + * 千分位字段列表 + */ + private List thousandsField=new ArrayList<>(); + + /** + * 设计子表底部按钮 + */ + private List footerBtnsList = new ArrayList<>(); + + /** + * 设计子表顶部按钮 + */ + private List columnBtnsList = new ArrayList<>(); + + private String layoutType; + + private Boolean defaultExpandAll; + + /** + * 多语言字段 + */ + private String labelI18nCode; + private String tipLabelI18nCode; + + /** + * 子表仅展示 + */ + private Boolean disabled; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormEnum.java new file mode 100644 index 0000000..b611c92 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormEnum.java @@ -0,0 +1,99 @@ +package com.yunzhupaas.model.visualJson.analysis; + +import java.util.ArrayList; +import java.util.List; + +/** + * 引擎模板 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-09-29 上午9:18 + */ +public enum FormEnum { + + // 子表 + table("table"), + // 主表 + mast("mast"), + // 表单子表 + mastTable("mastTable"), + + // 栅格 + row("row"), + // 折叠 + collapse("collapse"), + collapseItem("collapseItem"), + // 标签 + tab("tab"), + tabItem("tabItem"), + // 表格 + tableGrid("tableGrid"), + // 表格 + tableGridTr("tableGridTr"), + // 表格 + tableGridTd("tableGridTd"), + // 卡片 + card("card"), + + // 分组标题 + groupTitle("groupTitle"), + // 分割线 + divider("divider"), + // 文本 + YUNZHUPAASText("text"), + // 按钮 + button("button"), + // 关联表单属性 + relationFormAttr("relationFormAttr"), + // 关联表单属性 + popupAttr("popupAttr"), + // 条形码 + BARCODE("barcode"), + // 连接 + link("link"), + // 提示语 + alert("alert"), + // 二维码 + QR_CODE("qrcode"), + + STEPS("steps"), + + STEP_ITEM("stepItem"); + + private String message; + + FormEnum(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + // 无用的对象 + private static List isNodeList = new ArrayList() { + { + add(FormEnum.groupTitle.getMessage()); + add(FormEnum.divider.getMessage()); + add(FormEnum.YUNZHUPAASText.getMessage()); + add(FormEnum.button.getMessage()); + // add(FormEnum.relationFormAttr.getMessage()); + add(FormEnum.BARCODE.getMessage()); + add(FormEnum.QR_CODE.getMessage()); + add(FormEnum.alert.getMessage()); + add(FormEnum.link.getMessage()); + } + }; + + public static boolean isModel(String value) { + boolean isData = isNodeList.contains(value); + return isData; + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormMastTableModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormMastTableModel.java new file mode 100644 index 0000000..8cd10d7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormMastTableModel.java @@ -0,0 +1,22 @@ +package com.yunzhupaas.model.visualJson.analysis; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class FormMastTableModel { + /** + * 表名 + */ + private String table; + /** + * 字段 + */ + private String field; + /** + * 原始字段 + */ + private String vModel; + + private FormColumnModel mastTable; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormModel.java new file mode 100644 index 0000000..cde8a4b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/FormModel.java @@ -0,0 +1,58 @@ +package com.yunzhupaas.model.visualJson.analysis; + +import com.yunzhupaas.model.visualJson.FieLdsModel; +import lombok.Data; + +import java.util.List; + +/** + * 解析引擎 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/15 9:19 + */ +@Data +public class FormModel extends FieLdsModel { + + + /** + * 栅格 + */ + private Integer span; + + /** + * 标签页 + */ + private String model; + + /** + * 折叠、标签公用 + */ + private String active; + private String activeIndex; + + /**判断折叠、标签是否最外层 0.不是 1.是**/ + private String outermost; + + /** + * 折叠、标签公用的子节点 + */ + private List children; + + + /** + * app代码生成器 + */ + private int childNum; + + private String visibility; + + private boolean merged; + private String colspan; + private String rowspan; + private String rowType; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/RecursionForm.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/RecursionForm.java new file mode 100644 index 0000000..756c6b6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/RecursionForm.java @@ -0,0 +1,22 @@ +package com.yunzhupaas.model.visualJson.analysis; + +import com.yunzhupaas.model.visualJson.FieLdsModel; +import com.yunzhupaas.model.visualJson.TableModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RecursionForm { + private List list; + private List tableModelList; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/TableCreModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/TableCreModel.java new file mode 100644 index 0000000..206806c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/TableCreModel.java @@ -0,0 +1,24 @@ +package com.yunzhupaas.model.visualJson.analysis; + +import com.alibaba.fastjson.JSONArray; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 无表生成有表模型 + * + * @author 云筑产品开发平台组 + * @version V3.4 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2022/5/10 + */ +@Data +public class TableCreModel { + private JSONArray jsonArray; + private List formAllModel; + private String table; + private String linkId; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/TableCreModels.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/TableCreModels.java new file mode 100644 index 0000000..3e4abdc --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/TableCreModels.java @@ -0,0 +1,18 @@ +package com.yunzhupaas.model.visualJson.analysis; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class TableCreModels { + private List> jsonArray; + private List formAllModel; + private String table; + private String linkId; + private String fullName; + private Boolean concurrency = false; + private Integer primaryKey = 1; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/TableModels.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/TableModels.java new file mode 100644 index 0000000..a5d6855 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/analysis/TableModels.java @@ -0,0 +1,16 @@ +package com.yunzhupaas.model.visualJson.analysis; + +import com.yunzhupaas.model.visualJson.TableModel; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Data +public class TableModels { + private List table = new ArrayList<>(); + private List> jsonArray = new ArrayList<>(); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/ConfigModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/ConfigModel.java new file mode 100644 index 0000000..2248ec3 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/ConfigModel.java @@ -0,0 +1,186 @@ +package com.yunzhupaas.model.visualJson.config; + +import com.yunzhupaas.model.visualJson.FieLdsModel; +import com.yunzhupaas.model.visualJson.TemplateJsonModel; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class ConfigModel { + private String label; + private String labelWidth; + private Boolean showLabel; + private Boolean changeTag; + private Boolean border; + private String tag; + private String tagIcon; + //是否必填 + private boolean required = false; + //是否唯一 + private Boolean unique = false; + private String layout; + private String dataType; + private Integer span = 24; + private String yunzhupaasKey; + private String dictionaryType; + private String formId; + private String relationTable; + private Long renderKey; + private Integer columnWidth; + private List regList; + private String reg; + private Object defaultValue; + private Boolean defaultCurrent; + + private String active; + + /** + * 提示语 + */ + private String title; + private String type; + private Boolean showIcon; + private Boolean closable; + /** + * app静态数据 + */ + private String options; + /** + * 判断defaultValue类型 + */ + private String valueType; + private String propsUrl; + private String optionType; + /** + * 子表添加字段 + */ + private Boolean showTitle; + private String tableName; + private String aliasClassName; + private List children; + private List complexHeaderList = new ArrayList<>(); + + /** + * 多端显示 + */ + private String visibility="[\"app\",\"pc\"]" ; + + + private List templateJson = new ArrayList(); + + /** + * 单据规则使用 + */ + private String rule; + + /** + * 验证规则触发方式 + */ + private String trigger="blur"; + /** + * 隐藏 + */ + private Boolean noShow=false; + /** + * app代码生成器 + */ + private int childNum; + private String model; + + /** + * 代码生成器多端显示 + */ + private boolean app = true; + private boolean pc = true; + + /** + * 高级查询 + */ + private String parentVModel; + + private Boolean merged=false; + private String colspan; + private String rowspan; + private String rowType; + + private String tipLabel = ""; + private String startRelationField; + private String endRelationField; + private Boolean startChild = false; + private Boolean endRChild = false ; + + /** + * 开始时间开关 + */ + private Boolean startTimeRule = false; + /** + * 开始时间类型:1-特定时间,2-表单字段,3-填写当前时间,4-当前时间前,5-当前时间后 + */ + private String startTimeType; + /** + * 开始时间单位:1-年,2-月,3-日/1-时,2-分,3-秒 + */ + private String startTimeTarget; + /** + * 开始时间值 + */ + private String startTimeValue; + private Boolean endTimeRule = false; + private String endTimeType; + private String endTimeTarget; + private String endTimeValue; + /** + * 取表格td配置中的backgroundColor + */ + private String backgroundColor; + + /** + * table属性 + * borderType 边框 ,borderColor 边框颜色 , borderWidth边框宽度 + */ + private String borderType; + private String borderColor; + private Integer borderWidth; + + /** + * 是否参数(视图) + */ + private Boolean isFromParam = false; + /** + * 对齐方式 + */ + private String tableAlign; + /** + * 冻结方式 + */ + private String tableFixed; + + /** + * 多语言字段 + */ + private String labelI18nCode; + private String tipLabelI18nCode; + + /** + * 是否缓存: + * “单选框组”、“多选框组”、“下拉选择”、“级联选择”、“下拉树形”、“下拉表格”、“弹窗选择” + */ + private Boolean useCache = false; + + /** + * 单据规则类型:1-单据模板2-单据规则 + */ + private Integer ruleType; + /** + * 单据规则配置 + */ + private RuleConfig ruleConfig; + + private String propsValue; + private String format; +} + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/HeaderModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/HeaderModel.java new file mode 100644 index 0000000..3bcff3e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/HeaderModel.java @@ -0,0 +1,18 @@ +package com.yunzhupaas.model.visualJson.config; + +import com.yunzhupaas.model.visualJson.analysis.FormColumnModel; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class HeaderModel { + private List childList = new ArrayList<>(); + private List childColumns = new ArrayList<>(); + private String fullName; + private String fullNameI18nCode; + private String id; + private String align; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/PrefixSuffixModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/PrefixSuffixModel.java new file mode 100644 index 0000000..ea2f136 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/PrefixSuffixModel.java @@ -0,0 +1,25 @@ +package com.yunzhupaas.model.visualJson.config; + +import lombok.Data; + +/** + * 前后缀对象属性 + * + * @author 云筑产品开发平台组 + * @version v5.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/9/3 14:47:39 + */ +@Data +public class PrefixSuffixModel { + /** + * 前后缀类型:2-自定义,1-表单字段 + */ + private Integer sourceType; + + /** + * sourceType1-表单字段vmodel,sourceType2-值 + */ + private String relationField; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/RegListModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/RegListModel.java new file mode 100644 index 0000000..0917ff7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/RegListModel.java @@ -0,0 +1,11 @@ +package com.yunzhupaas.model.visualJson.config; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class RegListModel { + private String pattern; + private String message; + private String messageI18nCode; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/RuleConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/RuleConfig.java new file mode 100644 index 0000000..f427d73 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/RuleConfig.java @@ -0,0 +1,46 @@ +package com.yunzhupaas.model.visualJson.config; + +import lombok.Data; + +import java.util.List; + +@Data +public class RuleConfig { + /** + * 前缀 + */ + private List prefixList; + + /** + * 方式类型:1-时间,2-随机,3-UUID + */ + private Integer type; + + /** + * 日期格式 + */ + private String dateFormat; + /** + * 流水位数 + */ + private Integer digit; + /** + * 流水起始 + */ + private String startNumber; + + /** + * 随机数位数 + */ + private Integer randomDigit; + /** + * 随机数类型 + */ + private Integer randomType; + + /** + * 后缀 + */ + private List suffixList; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/TabConfigModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/TabConfigModel.java new file mode 100644 index 0000000..dabe3e4 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/config/TabConfigModel.java @@ -0,0 +1,30 @@ +package com.yunzhupaas.model.visualJson.config; + +import com.yunzhupaas.model.visualJson.FieLdsModel; +import lombok.Data; + +@Data +public class TabConfigModel { + /** + * 是否开启标签面板 + */ + private boolean on; + /** + * 标签面板关联字段 + */ + private String relationField; + /** + * 是否有:全部标签 + */ + private boolean hasAllTab; + /** + * 标签面板关联字段-属性 + */ + private FieLdsModel fieldsModel; + + /** + * 标签面板是否生成代码 + */ + private boolean createTab; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/options/ColumnOptionModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/options/ColumnOptionModel.java new file mode 100644 index 0000000..9f1e00d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/options/ColumnOptionModel.java @@ -0,0 +1,17 @@ +package com.yunzhupaas.model.visualJson.options; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2021/6/29 + */ +@Data +public class ColumnOptionModel { + private String value; + private String label; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/options/OptionsModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/options/OptionsModel.java new file mode 100644 index 0000000..8e18c13 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/options/OptionsModel.java @@ -0,0 +1,14 @@ +package com.yunzhupaas.model.visualJson.options; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Data +public class OptionsModel { + private Integer id; + private Integer value; + private String label; + private List children; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/props/PropsModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/props/PropsModel.java new file mode 100644 index 0000000..f0f86cb --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/model/visualJson/props/PropsModel.java @@ -0,0 +1,12 @@ +package com.yunzhupaas.model.visualJson.props; + +import lombok.Data; + +@Data +public class PropsModel { + private boolean multiple; + private String label; + private String value; + private String children=""; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/properties/GatewayWhite.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/properties/GatewayWhite.java new file mode 100644 index 0000000..7622036 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/properties/GatewayWhite.java @@ -0,0 +1,195 @@ +package com.yunzhupaas.properties; + + +import java.util.ArrayList; +import java.util.List; + +/** + * 放行的url + * 由下方的URL列表加上配置里的URL组合 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-24 + */ +public class GatewayWhite { + + public static final String PREFIX = "gateway"; + + + /** + * 放行不记录 + */ + public List excludeUrl = new ArrayList<>(); + + /** + * 不验证Token, 记录访问 + */ + public List whiteUrl = new ArrayList<>(); + + /** + * 禁止访问 + */ + public List blockUrl = new ArrayList<>(); + + /** + * 禁止访问地址的白名单IP + * startsWith匹配, 访问IP.startsWith(whiteIP) + */ + public List whiteIp = new ArrayList<>(); + + public GatewayWhite(){ + interceptPath(); + whitePath(); + excludePath(); + whiteIp(); + } + + + public List getWhiteUrl() { + return new ArrayList<>(whiteUrl); + } + + public List getBlockUrl() { + return new ArrayList<>(blockUrl); + } + + public List getExcludeUrl() { + return new ArrayList<>(excludeUrl); + } + + public List getWhiteIp() { + return new ArrayList<>(whiteIp); + } + + public void setWhiteUrl(List whiteUrl) { + whitePath(); + this.whiteUrl.addAll(whiteUrl); + } + + public void setBlockUrl(List blockUrl) { + interceptPath(); + this.blockUrl.addAll(blockUrl); + } + + public void setExcludeUrl(List excludeUrl) { + excludePath(); + this.excludeUrl.addAll(excludeUrl); + } + + public void setWhiteIp(List whiteIp) { + whiteIp(); + this.whiteIp.addAll(whiteIp); + } + + protected void interceptPath() { + blockUrl.clear(); + blockUrl.add("/actuator/**"); + blockUrl.add("/api/*/actuator/**"); + blockUrl.add("/doc.html"); + blockUrl.add("/swagger-resources/**"); + blockUrl.add("/swagger-ui/**"); + blockUrl.add("/api/*/v?/api-docs/**"); + blockUrl.add("/v?/api-docs/**"); + } + + protected void whitePath() { + whiteUrl.clear(); + //oauth + whiteUrl.add("/api/oauth/Login/**"); + whiteUrl.add("/api/oauth/Logout/**"); + whiteUrl.add("/api/oauth/resetOfficialPassword/**"); + whiteUrl.add("/api/oauth/codeCertificate"); + whiteUrl.add("/api/oauth/codeCertificateStatus/*"); + // APP + whiteUrl.add("/api/app/Version"); + + //websocket + whiteUrl.add("/api/message/websocket/*"); + //大屏图片 + whiteUrl.add("/api/file/VisusalImg/**"); + whiteUrl.add("/api/blade-visual/map/data"); + whiteUrl.add("/api/blade-visual/category/list"); + whiteUrl.add("/api/blade-visual/visual/put-file/**"); + //数据地图 + whiteUrl.add("/api/system/DataMap/**"); + //代码下载接口 + whiteUrl.add("/api/visualdev/Generater/DownloadVisCode"); + //多租户 + whiteUrl.add("/api/tenant/DbName/**"); + whiteUrl.add("/api/tenant/login"); + whiteUrl.add("/api/tenant/logout"); + //报表导出 + whiteUrl.add("/api/Report/data/Download"); + //extend KK + whiteUrl.add("/api/extend/DocumentPreview/**"); + //file模块不拦截 + //文件下载接口 + whiteUrl.add("/api/file/filedownload/**"); + whiteUrl.add("/api/file/VisusalImg/**"); + whiteUrl.add("/api/file/AppStartInfo/*"); + whiteUrl.add("/api/file/IMVoice/*"); + whiteUrl.add("/api/file/{type}/{fileName}"); + whiteUrl.add("/api/file/IMImage/*"); + whiteUrl.add("/api/file/Image/**"); + whiteUrl.add("/api/file/DownloadModel"); + whiteUrl.add("/api/file/Download/**"); + whiteUrl.add("/api/file/ImageCode/**"); + + whiteUrl.add("/api/system/DictionaryData/*/Data/Selector"); + whiteUrl.add("/api/datareport/pdf/show"); + whiteUrl.add("/api/datareport/preview/loadPagePaper"); + whiteUrl.add("/api/datareport/pdf"); + whiteUrl.add("/api/datareport/word"); + whiteUrl.add("/api/datareport/excel/**"); + whiteUrl.add("/api/datareport/Data/*/Actions/Export"); + //报表模板导入 + whiteUrl.add("/api/datareport/import"); + whiteUrl.add("/api/system/DataInterface/*/Actions/Response"); + whiteUrl.add("/api/system/DataInterface/Actions/GetAuth"); + //swagger3 + whiteUrl.add("/doc.html"); + whiteUrl.add("/webjars/**"); + whiteUrl.add("/api/*/v?/api-docs/**"); + whiteUrl.add("/v?/api-docs/**"); + whiteUrl.add("/swagger-ui/**"); + whiteUrl.add("/swagger-resources/**"); + + whiteUrl.add("/csrf"); + whiteUrl.add("/api/oauth/ImageCode/**"); + whiteUrl.add("/api/oauth/getConfig/*"); + whiteUrl.add("/api/oauth/getLoginConfig"); + whiteUrl.add("/api/oauth/getTicketStatus/*"); + whiteUrl.add("/api/oauth/getTicket"); + //扫描登录放行调用接口 + whiteUrl.add("/api/oauth/setCodeCertificateStatus/{ticket}/{status}"); + + whiteUrl.add("/api/message/ShortLink/**"); + whiteUrl.add("/api/message/WechatOpen/token/**"); + + //在线表单外链触发接口 + whiteUrl.add("/api/visualdev/ShortLink/**"); + + //webhook两个接口 + whiteUrl.add("/api/visualdev/Hooks/*"); + whiteUrl.add("/api/visualdev/Hooks/*/params/*"); + whiteUrl.add("/api/workflow/Hooks/*"); + whiteUrl.add("/api/workflow/Hooks/*/params/*"); + + whiteUrl.add("/api/system/Location/*"); + } + + protected void excludePath(){ + excludeUrl.clear(); + excludeUrl.add("/favicon.ico"); + excludeUrl.add("/api/message/websocket/*"); + } + + protected void whiteIp(){ + whiteIp.clear(); + whiteIp.add("127.0.0.1"); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/properties/MvcSecurityProperties.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/properties/MvcSecurityProperties.java new file mode 100644 index 0000000..335e3f8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/properties/MvcSecurityProperties.java @@ -0,0 +1,199 @@ +package com.yunzhupaas.properties; + + + +import lombok.Data; + +import java.util.Collections; +import java.util.List; + +/** + * mvc配置 + * @author 云筑产品开发平台组 + * @version V5.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2025/1/16 8:47 + */ +@Data +public class MvcSecurityProperties { + + public static final String PREFIX = "spring.mvc"; + + public static final String HEADER_XFRAME_OPTIONS = "X-Frame-Options"; + public static final String HEADER_XSS_PROTECTION = "X-XSS-Protection"; + public static final String HEADER_Content_Type_Options = "X-Content-Type-Options"; + + /** + * 默认配置 Content-Security-Policy + * 只允许请求同源、内联、动态脚本 + * 参考文章 + */ + private static final String DEFAULT_CONTENT_SECURITY_POLICY = "default-src 'self' 'unsafe-eval' 'unsafe-inline';font-src 'self' data: blob; img-src 'self' data: blob:;frame-ancestors 'self';script-src 'self' 'unsafe-eval' 'unsafe-inline' https://cdn.staticfile.org;"; + + + /** + * 跨域相关配置 + * 默认允许全部域名跨域 + */ + private Cors cors = new Cors(); + + /** + * 头部相关配置 + */ + private Headers headers = new Headers(); + + /** + * CSRF防御, 验证放空不验证, 填写允许的域名 + */ + private List csrfOrigins = Collections.emptyList();; + + /** + * CSRF防御, 放空不验证, 填写允许的域名正则 + */ + private List csrfOriginsPatterns = Collections.emptyList();; + + + @Data + public static class Headers{ + + /** + * 返回的Web服务器名称 + */ + private String serverName; + + /** + * XSS保护 + * 0 :禁用; 1 :启用; 1;mode=block :启用, 如果检测到攻击停止渲染 + */ + private XXssProtectionMode xXssProtection = XXssProtectionMode.ENABLED_MODE_BLOCK; + + /** + * 是否允许在Iframe中被加载 + * deny :不允许; sameorign :允许相同的域名; allow-from-uri 域名:允许指定来源 + */ + private XFrameOptionsMode xFrameOptions = XFrameOptionsMode.SAMEORIGIN; + + /** + * MIME嗅探 + * nosniff + */ + private XContentTypeOptions xContentTypeOptions = XContentTypeOptions.DISABLED; + } + + @Data + public static class Cors{ + + + private static final String ALL = "*"; + private static final String ALL_PATTERNS = "**"; + private static final Long MAX_AGE = 18000L; + + /** + * 允许跨域的域名 + */ + private List allowedOrigins = Collections.emptyList(); + /** + * 允许跨域的域名正则匹配 + */ + private List allowedOriginPatterns = Collections.singletonList(ALL_PATTERNS); + /** + * 允许跨域的请求方法 + */ + private List allowedMethods = Collections.singletonList(ALL); + /** + * 允许跨域的头部信息 + */ + private List allowedHeaders = Collections.singletonList(ALL); + /** + * 预检请求的有效期, 单位为秒 + */ + private long optionsMaxAge = MAX_AGE; + + } + + + + public enum XContentTypeOptions { + + /** + * 不处理 + */ + DISABLED("disabled"), + + /** + * 不允许浏览器嗅探资源类型 + */ + NOSNIFF("nosniff"); + + private final String mode; + + XContentTypeOptions(String mode) { + this.mode = mode; + } + + public String getMode() { + return this.mode; + } + + } + + public enum XFrameOptionsMode { + + /** + * 不处理 + */ + DISABLED("disabled"), + + /** + * 不允许在iframe中被加载 + */ + DENY("deny"), + + /** + * 允许在相同的域名的iframe中被加载 + */ + SAMEORIGIN("sameorigin"); + + private final String mode; + + XFrameOptionsMode(String mode) { + this.mode = mode; + } + + public String getMode() { + return this.mode; + } + + } + + + public enum XXssProtectionMode { + + /** + * 禁用; ; + */ + DISABLED("0"), + + /** + * 启用 + */ + ENABLED("1"), + + /** + * 启用, 如果检测到攻击停止渲染 + */ + ENABLED_MODE_BLOCK("1; mode=block"); + + private final String mode; + + XXssProtectionMode(String mode) { + this.mode = mode; + } + + public String getMode() { + return this.mode; + } + + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/properties/SecurityProperties.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/properties/SecurityProperties.java new file mode 100644 index 0000000..5d61c00 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/properties/SecurityProperties.java @@ -0,0 +1,67 @@ +package com.yunzhupaas.properties; + +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class SecurityProperties { + + public static final String PREFIX = "security"; + + + @Getter + private static SecurityProperties instance; + + public SecurityProperties() { + initIgnoreXssUrl(); + SecurityProperties.instance = this; + } + + /** + * AES, DES 公钥 + * 长度 16/24/32 + * @return + */ + private String securityKey = "EY8WePvjM5GGwQzn"; + + /** + * 开启数据传输加密 + */ + private boolean enableRestEncrypt; + + /** + * 是否开启接口鉴权 + */ + private boolean enablePreAuth; + + /** + * 是否验证请求是否来自内部 + */ + private boolean enableInnerAuth; + + /** + * 忽略XSS过滤路径 + */ + public List ignoreXssUrl = new ArrayList<>(); + + + public List getIgnoreXssUrl() { + return new ArrayList<>(ignoreXssUrl); + } + + public void setIgnoreXssUrl(List ignoreXssUrl) { + initIgnoreXssUrl(); + this.ignoreXssUrl.addAll(ignoreXssUrl); + } + + private void initIgnoreXssUrl(){ + ignoreXssUrl.clear(); + //添加默认URL + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/support/MyStandardMultipartFile.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/support/MyStandardMultipartFile.java new file mode 100644 index 0000000..b8af974 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/support/MyStandardMultipartFile.java @@ -0,0 +1,82 @@ +package com.yunzhupaas.support; + +import lombok.Getter; +import org.apache.catalina.core.ApplicationPart; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.nio.file.Files; +import java.nio.file.Path; + +public class MyStandardMultipartFile implements MultipartFile, Serializable { + + @Getter + private final ApplicationPart part; + + private final String filename; + + public MyStandardMultipartFile(ApplicationPart part, String filename) { + this.part = part; + this.filename = filename; + } + + @Override + public String getName() { + return this.part.getName(); + } + + @Override + public String getOriginalFilename() { + return this.filename; + } + + @Override + public String getContentType() { + return this.part.getContentType(); + } + + @Override + public boolean isEmpty() { + return (this.part.getSize() == 0); + } + + @Override + public long getSize() { + return this.part.getSize(); + } + + @Override + public byte[] getBytes() throws IOException { + return FileCopyUtils.copyToByteArray(this.part.getInputStream()); + } + + @Override + public InputStream getInputStream() throws IOException { + return this.part.getInputStream(); + } + + @Override + public void transferTo(File dest) throws IOException, IllegalStateException { + this.part.write(dest.getPath()); + if (dest.isAbsolute() && !dest.exists()) { + // Servlet Part.write is not guaranteed to support absolute file paths: + // may translate the given path to a relative location within a temp dir + // (e.g. on Jetty whereas Tomcat and Undertow detect absolute paths). + // At least we offloaded the file from memory storage; it'll get deleted + // from the temp dir eventually in any case. And for our user's purposes, + // we can manually copy it to the requested location as a fallback. + FileCopyUtils.copy(this.part.getInputStream(), Files.newOutputStream(dest.toPath())); + } + } + + @Override + public void transferTo(Path dest) throws IOException, IllegalStateException { + FileCopyUtils.copy(this.part.getInputStream(), Files.newOutputStream(dest)); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/CacheKeyUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/CacheKeyUtil.java new file mode 100644 index 0000000..8cde92e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/CacheKeyUtil.java @@ -0,0 +1,247 @@ +package com.yunzhupaas.util; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:45 + */ +@Slf4j +@Component +public class CacheKeyUtil { + + /** + *系统配置 + */ + public static String SYSTEMINFO = "systeminfo"; + /** + *系统配置 + */ + public static String WECHATCONFIG = "wechatconfig"; + /** + *验证码 + */ + public static String VALIDCODE = "validcode_"; + /** + *短信验证码 + */ + public static String SMSVALIDCODE = "sms_validcode_"; + /** + *登陆token + */ + public static String LOGINTOKEN = "login_token_"; + /** + *登陆在线用户 + */ + public static String LOGINONLINE = "login_online_"; + /** + *登陆在线用户 - 移动APP + */ + public static String MOBILELOGINONLINE = "login_online_mobile_"; + /** + *移动设备列表 + */ + public static String MOBILEDEVICELIST = "mobiledevicelist"; + /** + *用户权限 + */ + public static String USERAUTHORIZE="authorize_"; + /** + *公司选择 + */ + public static String COMPANYSELECT="companyselect"; + /** + *组织选择 + */ + public static String ORGANIZELIST="organizeList"; + /** + *字典数据 + */ + public static String DICTIONARY="dictionary_"; + /** + *远端数据 + */ + public static String DYNAMIC="dynamic_"; + /** + *岗位列表 + */ + public static String POSITIONLIST="positionlist_"; + /** + *所有用户 + */ + public static String ALLUSER="alluser"; + /** + *可视化数据包 + */ + public static String VISIUALDATA ="visiualdata_"; + /** + * ID生成器 + */ + public static String IDGENERATOR ="idgenerator_"; + /** + * 组织信息集合 + */ + public static final String ORGANIZEINFOLIST ="organizeinfolist_"; + + /** + * 系统控件缓存key + */ + public static final String SYS_ORG_Tree = "_organizeTree";//组织多级 + public static final String SYS_DEP = "_department";//部门单个id + public static final String SYS_POS = "_position"; + public static final String SYS_USER = "_user"; + public static final String SYS_ROLE = "_role"; + public static final String SYS_GROUP = "_group"; + + + /** + * Lock4J锁记录 + */ + public static final String LOCK = "lock:"; + + public String getOrganizeInfoList() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+ORGANIZEINFOLIST; + } + return ORGANIZEINFOLIST; + } + + public String getVisiualData() { + String tenantId= TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+ VISIUALDATA; + } + return VISIUALDATA; + } + + public String getCompanySelect() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+COMPANYSELECT; + } + return COMPANYSELECT; + } + + public String getOrganizeList() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+ORGANIZELIST; + } + return ORGANIZELIST; + } + + public String getDictionary() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+DICTIONARY; + } + return DICTIONARY; + } + + public String getDynamic() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+DYNAMIC; + } + return DYNAMIC; + } + + public String getPositionList() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+POSITIONLIST; + } + return POSITIONLIST; + } + + public String getAllUser() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+ALLUSER; + } + return ALLUSER; + } + + public String getSystemInfo() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+SYSTEMINFO; + } + return SYSTEMINFO; + } + + public String getWechatConfig() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+WECHATCONFIG; + } + return WECHATCONFIG; + } + + + + public String getValidCode() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+VALIDCODE; + } + return VALIDCODE; + } + + public String getSmsValidCode() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+SMSVALIDCODE; + } + return SMSVALIDCODE; + } + + public String getLoginToken(String tenantId) { + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+LOGINTOKEN; + } + return LOGINTOKEN; + } + + public String getLoginOnline() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+LOGINONLINE; + } + return LOGINONLINE; + } + + public String getMobileLoginOnline() { + String tenantId= TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+MOBILELOGINONLINE; + } + return MOBILELOGINONLINE; + } + + public String getMobileDeviceList() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+MOBILEDEVICELIST; + } + return MOBILEDEVICELIST; + } + + /** + * 用户权限集合 + */ + public String getUserAuthorize() { + String tenantId=TenantHolder.getDatasourceId(); + if(!StringUtil.isEmpty(tenantId)){ + return tenantId+USERAUTHORIZE; + } + return USERAUTHORIZE; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ClassUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ClassUtil.java new file mode 100644 index 0000000..8f2a923 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ClassUtil.java @@ -0,0 +1,95 @@ +package com.yunzhupaas.util; + + +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.stereotype.Component; +import org.springframework.util.ClassUtils; + +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.function.Predicate; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/12 15:31 + */ +@Component +public class ClassUtil { + + private static Environment environment; + private static ResourcePatternResolver resourcePatternResolver; + private static MetadataReaderFactory metadataReaderFactory; + + @Autowired(required = false) + public void setEnvironment(Environment environment) { + ClassUtil.environment = environment; + } + + @Autowired(required = false) + public void setMetadataReaderFactory(MetadataReaderFactory metadataReaderFactory) { + ClassUtil.metadataReaderFactory = metadataReaderFactory; + } + + @Autowired(required = false) + public void setResourcePatternResolver(ResourcePatternResolver resourcePatternResolver) { + ClassUtil.resourcePatternResolver = resourcePatternResolver; + } + private static Environment getEnvironment() { + if (environment == null) { + environment = new StandardEnvironment(); + } + return environment; + } + + protected static String resolveBasePackage(String basePackage) { + return ClassUtils.convertClassNameToResourcePath(getEnvironment().resolveRequiredPlaceholders(basePackage)); + } + + private static ResourcePatternResolver getResourcePatternResolver() { + if (resourcePatternResolver == null) { + resourcePatternResolver = new PathMatchingResourcePatternResolver(); + } + return resourcePatternResolver; + } + private static MetadataReaderFactory getMetadataReaderFactory() { + if (metadataReaderFactory == null) { + metadataReaderFactory = new CachingMetadataReaderFactory(); + } + return metadataReaderFactory; + } + public static Set> scanCandidateComponents(String basePackage, Predicate predicate) { + Set> classes = new LinkedHashSet<>(); + try { + String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + + resolveBasePackage(basePackage) + '/' + "**/*.class"; + Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); + for (Resource resource : resources) { + MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); + Class cls = environment.getClass().getClassLoader().loadClass(metadataReader.getClassMetadata().getClassName()); + if(predicate.test(cls)){ + classes.add(cls); + } + } + } + catch (IOException ex) { + throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + return classes; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/CodeUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/CodeUtil.java new file mode 100644 index 0000000..6ccf3df --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/CodeUtil.java @@ -0,0 +1,139 @@ +package com.yunzhupaas.util; + +import lombok.Cleanup; + +import javax.imageio.ImageIO; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.Objects; +import java.util.Random; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:45 + */ +public class CodeUtil { + /** + *放到session中的key + */ + public static final String RANDOMCODEKEY = "RANDOMCODEKEY"; + private Random random = new Random(); + /** + *随机产生的字符串 + */ + private String randString = "abcdefghjklmnopqrstuvwxyz23456789ABCDEFGHJKLMNPQRSTUVWXYZ"; + /** + *图片宽 + */ + private int width = 120; + /** + *图片高 + */ + private int height = 40; + /** + *干扰线数量 + */ + private int lineSize = 10; + /** + *随机产生字符数量 + */ + private int stringNum = 4; + + /** + * 获得字体 + */ + private Font getFont(){ + return new Font("Fixedsys", Font.CENTER_BASELINE,18); + } + + /** + * 获得颜色 + */ + private Color getRandColor(int fc, int bc){ + if(fc > 255) { + fc = 255; + } + if(bc > 255) { + bc = 255; + } + int r = fc + random.nextInt(bc-fc-16); + int g = fc + random.nextInt(bc-fc-14); + int b = fc + random.nextInt(bc-fc-18); + return new Color(r,g,b); + } + + /** + * 生成随机图片 + */ + public void getRandcode(HttpServletResponse response, Integer stringLength) { + try { + HttpSession session = ServletUtil.getSession(); + //BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类 + BufferedImage image = new BufferedImage(width,height, BufferedImage.TYPE_INT_BGR); + //产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作 + Graphics g = image.getGraphics(); + g.fillRect(0, 0, width, height); + g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE,20)); + g.setColor(getRandColor(110, 133)); + //绘制干扰线 + for(int i=0;i<=lineSize;i++){ + drowLine(g); + } + //绘制随机字符 + String randomString = ""; + if (Objects.nonNull(stringLength)) { + stringNum = stringLength; + } + for(int i = 1; i <= stringNum; i++){ + randomString=drowString(g,randomString,i); + } + session.removeAttribute(RANDOMCODEKEY); + session.setAttribute(RANDOMCODEKEY, randomString); + System.out.println("后台代码"+randomString); + g.dispose(); + @Cleanup ServletOutputStream outputStream = response.getOutputStream(); + //将内存中的图片通过流动形式输出到客户端 + ImageIO.write(image, "JPEG", outputStream); + }catch (Exception e){ + e.getStackTrace(); + } + } + + /** + * 绘制字符串 + */ + private String drowString(Graphics g, String randomString, int i){ + g.setFont(getFont()); + g.setColor(new Color(random.nextInt(101),random.nextInt(111),random.nextInt(121))); + String rand = String.valueOf(getRandomString(random.nextInt(randString.length()))); + randomString +=rand; + g.translate(random.nextInt(3), random.nextInt(3)); + g.drawString(rand, 15*i, 22); + return randomString; + } + + /** + * 绘制干扰线 + */ + private void drowLine(Graphics g){ + int x = random.nextInt(width); + int y = random.nextInt(height); + int xl = random.nextInt(13); + int yl = random.nextInt(15); + g.drawLine(x, y, x+xl, y+yl); + } + + /** + * 获取随机的字符 + */ + public String getRandomString(int num){ + return String.valueOf(randString.charAt(num)); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/Constants.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/Constants.java new file mode 100644 index 0000000..bf86eb4 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/Constants.java @@ -0,0 +1,89 @@ +package com.yunzhupaas.util; + +/** + * 通用常量信息 + * + * @author yunzhupaas + */ +public class Constants { + + /** + * token + */ + public static final String AUTHORIZATION = "Authorization"; + + /** + * UTF-8 字符集 + */ + public static final String UTF8 = "UTF-8"; + + /** + * GBK 字符集 + */ + public static final String GBK = "GBK"; + + /** + * http请求 + */ + public static final String HTTP = "http://"; + + /** + * https请求 + */ + public static final String HTTPS = "https://"; + + /** + * 成功标记 + */ + public static final Integer SUCCESS = 200; + + /** + * 失败标记 + */ + public static final Integer FAIL = 500; + + /** + * 登录成功 + */ + public static final String LOGIN_SUCCESS = "Success"; + + /** + * 注销 + */ + public static final String LOGOUT = "Logout"; + + /** + * 注册 + */ + public static final String REGISTER = "Register"; + + /** + * 验证码 redis key + */ + public static final String CAPTCHA_CODE_KEY = "captcha_codes:"; + + /** + * 验证码有效期(分钟) + */ + public static final long CAPTCHA_EXPIRATION = 2; + + /** + * 令牌有效期(分钟) + */ + public final static long TOKEN_EXPIRE = 720; + + /** + * swagger版本号 + */ + public final static String SWAGGER_VERSION = "3.4.8"; + + /** + * swagger版本号 + */ + public final static String USER_AGENT = "User-Agent"; + + /** + * 管理员账号 + */ + public static final String ADMIN_KEY = "admin"; +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DataClob.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DataClob.java new file mode 100644 index 0000000..deb2587 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DataClob.java @@ -0,0 +1,58 @@ +package com.yunzhupaas.util; + +import lombok.extern.slf4j.Slf4j; + +import java.sql.Clob; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 在线详情编辑工具类 + * + * @author 云筑产品开发平台组 + * @version V3.2 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024/10/27 + */ +@Slf4j +public class DataClob { + + public static List> swapClob(List> list) { + if (list == null || list.isEmpty()) { + return list; + } + List> result = new ArrayList<>(); + for (int i = 0; i < list.size(); i++) { + Map map = list.get(i); + for (String key : map.keySet()) { + swapClob(map, key); + } + result.add(map); + } + return result; + } + + public static void swapClob(Map map, String key) { + if (map != null && map.get(key) != null && map.get(key) instanceof Clob) { + Clob clob = (Clob) map.get(key); + StringBuilder sb = new StringBuilder(); + // 获取CLOB字段的内容长度 + int length = 0; + // 以流的形式读取CLOB字段的内容 + try (java.io.Reader reader = clob.getCharacterStream()) { + length = (int) clob.length(); + char[] buffer = new char[length]; + int bytesRead; + // 逐个字符读取并添加到字符串构建器中 + while ((bytesRead = reader.read(buffer)) != -1) { + sb.append(buffer, 0, bytesRead); + } + } catch (Exception e) { + e.printStackTrace(); + } + map.put(key, sb.toString()); + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DateUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DateUtil.java new file mode 100644 index 0000000..7cb3b97 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DateUtil.java @@ -0,0 +1,1817 @@ +package com.yunzhupaas.util; + +import cn.hutool.core.date.DateTime; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONArray; +import com.yunzhupaas.exception.DataException; +import org.quartz.CronExpression; +import org.quartz.TriggerUtils; +import org.quartz.impl.triggers.CronTriggerImpl; + +import java.sql.Timestamp; +import java.text.ParseException; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.util.*; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:47 + */ +public class DateUtil { + // ============================借助Calendar类获取今天、昨天、本周、上周、本年及特定时间的开始时间和结束时间(返回类型为date类型)======================== + + /** + * 获取当天开始时间 + * + * @return + */ + public static Date getDayBegin() { + Calendar cal = Calendar.getInstance(); + // 0点 + cal.set(Calendar.HOUR_OF_DAY, 0); + // 0分 + cal.set(Calendar.MINUTE, 0); + // 0秒 + cal.set(Calendar.SECOND, 0); + // 0毫秒 + cal.set(Calendar.MILLISECOND, 0); + return cal.getTime(); + } + + /** + * 获取当前时间 + */ + public static String getNow() { + LocalDateTime ldt1 = LocalDateTime.now(); + DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + String temp = dtf1.format(ldt1); + return temp; + } + + /** + * 获取当前时间 + */ + public static String getNow(String zone) { + LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of(zone)); + DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + String temp = dtf1.format(ldt1); + return temp; + } + + /** + * 获取当前时间 + */ + public static String getmmNow() { + LocalDateTime ldt1 = LocalDateTime.now(); + DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + String temp = dtf1.format(ldt1); + return temp; + } + + /** + * 获取当前时间字符串 + * yyyyMMddHHmmss + */ + public static String nowDateTime() { + LocalDateTime ldt1 = LocalDateTime.now(); + DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); + String temp = dtf1.format(ldt1); + return temp; + } + + /** + * 获取当前时间 + */ + public static Date getNowDate() { + Date date = new Date(); + return date; + } + + /** + * 获取当天结束时间 + * + * @return + */ + public static Date getDayEnd() { + Calendar cal = Calendar.getInstance(); + // 23点 + cal.set(Calendar.HOUR_OF_DAY, 23); + // 59分 + cal.set(Calendar.MINUTE, 59); + // 59秒 + cal.set(Calendar.SECOND, 59); + return cal.getTime(); + } + + /** + * 获取昨天开始时间 + * + * @return + */ + public static Date getBeginDayOfYesterday() { + Calendar cal = Calendar.getInstance(); + // 当天开始时间 + cal.setTime(getDayBegin()); + // 当天月份天数减1 + cal.add(Calendar.DAY_OF_MONTH, -1); + return cal.getTime(); + } + + /** + * 获取昨天结束时间 + * + * @return + */ + public static Date getEndDayOfYesterday() { + Calendar cal = Calendar.getInstance(); + // 当天结束时间 + cal.setTime(getDayEnd()); + // 当天月份天数减1 + cal.add(Calendar.DAY_OF_MONTH, -1); + return cal.getTime(); + } + + /** + * 获取明天开始时间 + * + * @return + */ + public static Date getBeginDayOfTomorrow() { + Calendar cal = Calendar.getInstance(); + // 当天开始时间 + cal.setTime(getDayBegin()); + // 当天月份天数加1 + cal.add(Calendar.DAY_OF_MONTH, 1); + return cal.getTime(); + } + + /** + * 获取明天结束时间 + * + * @return + */ + public static Date getEndDayOfTomorrow() { + Calendar cal = Calendar.getInstance(); + // 当天结束时间 + cal.setTime(getDayEnd()); + // 当天月份天数加1 + cal.add(Calendar.DAY_OF_MONTH, 1); + return cal.getTime(); + } + + /** + * 获取某个日期的开始时间 + * + * @param d + * @return + */ + public static Timestamp getDayStartTime(Date d) { + Calendar calendar = Calendar.getInstance(); + if (null != d) { + calendar.setTime(d); + } + calendar.set(calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0); + calendar.set(Calendar.MILLISECOND, 0); + return new Timestamp(calendar.getTimeInMillis()); + } + + /** + * 获取某个日期的结束时间 + * + * @param d + * @return + */ + public static Timestamp getDayEndTime(Date d) { + Calendar calendar = Calendar.getInstance(); + if (null != d) { + calendar.setTime(d); + } + calendar.set(calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59); + calendar.set(Calendar.MILLISECOND, 999); + return new Timestamp(calendar.getTimeInMillis()); + } + + /** + * 获取本周的开始时间 + * + * @return + */ + public static Date getBeginDayOfWeek() { + Date date = new Date(); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); + if (dayOfWeek == 1) { + dayOfWeek += 7; + } + cal.add(Calendar.DATE, 2 - dayOfWeek); + return getDayStartTime(cal.getTime()); + } + + /** + * 获取本周的结束时间 + * + * @return + */ + public static Date getEndDayOfWeek() { + Calendar cal = Calendar.getInstance(); + cal.setTime(getBeginDayOfWeek()); + cal.add(Calendar.DAY_OF_WEEK, 6); + Date weekEndSta = cal.getTime(); + return getDayEndTime(weekEndSta); + } + + /** + * 获取上周开始时间 + */ + @SuppressWarnings("unused") + public static Date getBeginDayOfLastWeek() { + Date date = new Date(); + if (date == null) { + return null; + } + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int dayofweek = cal.get(Calendar.DAY_OF_WEEK); + if (dayofweek == 1) { + dayofweek += 7; + } + cal.add(Calendar.DATE, 2 - dayofweek - 7); + return getDayStartTime(cal.getTime()); + } + + /** + * 获取上周的结束时间 + * + * @return + */ + public static Date getEndDayOfLastWeek() { + Calendar cal = Calendar.getInstance(); + cal.setTime(getBeginDayOfLastWeek()); + cal.add(Calendar.DAY_OF_WEEK, 6); + Date weekEndSta = cal.getTime(); + return getDayEndTime(weekEndSta); + } + + /** + * 获取今年是哪一年 + * + * @return + */ + public static Integer getNowYear() { + Date date = new Date(); + GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance(); + gc.setTime(date); + return Integer.valueOf(gc.get(1)); + } + + /** + * 获取本月是哪一月 + * + * @return + */ + public static int getNowMonth() { + Date date = new Date(); + GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance(); + gc.setTime(date); + return gc.get(2) + 1; + } + + /** + * 获取本月的开始时间 + * + * @return + */ + public static Date getBeginDayOfMonth() { + Calendar calendar = Calendar.getInstance(); + calendar.set(getNowYear(), getNowMonth() - 1, 1); + return getDayStartTime(calendar.getTime()); + } + + /** + * 获取本月的结束时间 + * + * @return + */ + public static Date getEndDayOfMonth() { + Calendar calendar = Calendar.getInstance(); + calendar.set(getNowYear(), getNowMonth() - 1, 1); + int day = calendar.getActualMaximum(5); + calendar.set(getNowYear(), getNowMonth() - 1, day); + return getDayEndTime(calendar.getTime()); + } + + /** + * 获取上月的开始时间 + * + * @return + */ + public static Date getBeginDayOfLastMonth() { + Calendar calendar = Calendar.getInstance(); + calendar.set(getNowYear(), getNowMonth() - 2, 1); + return getDayStartTime(calendar.getTime()); + } + + /** + * 获取上月的结束时间 + * + * @return + */ + public static Date getEndDayOfLastMonth() { + Calendar calendar = Calendar.getInstance(); + calendar.set(getNowYear(), getNowMonth() - 2, 1); + int day = calendar.getActualMaximum(5); + calendar.set(getNowYear(), getNowMonth() - 2, day); + return getDayEndTime(calendar.getTime()); + } + + /** + * 获取本年的开始时间 + * + * @return + */ + public static Date getBeginDayOfYear() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, getNowYear()); + cal.set(Calendar.MONTH, Calendar.JANUARY); + cal.set(Calendar.DATE, 1); + return getDayStartTime(cal.getTime()); + } + + /** + * 获取本年的结束时间 + * + * @return + */ + public static Date getEndDayOfYear() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, getNowYear()); + cal.set(Calendar.MONTH, Calendar.DECEMBER); + cal.set(Calendar.DATE, 31); + return getDayEndTime(cal.getTime()); + } + + /** + * 两个日期相减得到的天数 + * + * @param beginDate + * @param endDate + * @return + */ + public static int getDiffDays(Date beginDate, Date endDate) { + if (beginDate == null || endDate == null) { + throw new IllegalArgumentException("getDiffDays param is null!"); + } + long diff = (endDate.getTime() - beginDate.getTime()) / (1000 * 60 * 60 * 24); + int days = (int) diff; + return days; + } + + /** + * 两个日期相减得到的毫秒数 + * + * @param beginDate + * @param endDate + * @return + */ + public static long dateDiff(Date beginDate, Date endDate) { + long date1ms = beginDate.getTime(); + long date2ms = endDate.getTime(); + return date2ms - date1ms; + } + + /** + * 获取两个日期中的最大日起 + * + * @param beginDate + * @param endDate + * @return + */ + public static Date max(Date beginDate, Date endDate) { + if (beginDate == null) { + return endDate; + } + if (endDate == null) { + return beginDate; + } + // beginDate日期大于endDate + if (beginDate.after(endDate)) { + return beginDate; + } + return endDate; + } + + /** + * 获取两个日期中的最小日期 + * + * @param beginDate + * @param endDate + * @return + */ + public static Date min(Date beginDate, Date endDate) { + if (beginDate == null) { + return endDate; + } + if (endDate == null) { + return beginDate; + } + if (beginDate.after(endDate)) { + return endDate; + } + return beginDate; + } + + /** + * 获取某月该季度的第一个月 + * + * @param date + * @return + */ + public static Date getFirstSeasonDate(Date date) { + final int[] season = { 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4 }; + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int sean = season[cal.get(Calendar.MONTH)]; + cal.set(Calendar.MONTH, sean * 3 - 3); + return cal.getTime(); + } + + /** + * 返回某个日期下几天的日期 + * + * @param date + * @param i + * @return + */ + public static Date getNextDay(Date date, int i) { + Calendar cal = new GregorianCalendar(); + cal.setTime(date); + cal.set(Calendar.DATE, cal.get(Calendar.DATE) + i); + return cal.getTime(); + } + + /** + * 返回某个日期前几天的日期 + * + * @param date + * @param i + * @return + */ + public static Date getFrontDay(Date date, int i) { + Calendar cal = new GregorianCalendar(); + cal.setTime(date); + cal.set(Calendar.DATE, cal.get(Calendar.DATE) - i); + return cal.getTime(); + } + + /** + * 获取某年某月按天切片日期集合(某个月间隔多少天的日期集合) + * + * @param beginYear + * @param beginMonth + * @param k + * @return + */ + public static List getTimeList(int beginYear, int beginMonth, int k) { + List list = new ArrayList<>(); + Calendar begincal = new GregorianCalendar(beginYear, beginMonth, 1); + int max = begincal.getActualMaximum(Calendar.DATE); + for (int i = 1; i < max; i = i + k) { + list.add(begincal.getTime()); + begincal.add(Calendar.DATE, k); + } + begincal = new GregorianCalendar(beginYear, beginMonth, max); + list.add(begincal.getTime()); + return list; + } + + /** + * 获取某年某月到某年某月按天的切片日期集合(间隔天数的集合) + * + * @param beginYear + * @param beginMonth + * @param endYear + * @param endMonth + * @param k + * @return + */ + public static List> getTimeList(int beginYear, int beginMonth, int endYear, int endMonth, int k) { + List> list = new ArrayList<>(); + if (beginYear == endYear) { + for (int j = beginMonth; j <= endMonth; j++) { + list.add(getTimeList(beginYear, j, k)); + } + } else { + { + for (int j = beginMonth; j < 12; j++) { + list.add(getTimeList(beginYear, j, k)); + } + for (int i = beginYear + 1; i < endYear; i++) { + for (int j = 0; j < 12; j++) { + list.add(getTimeList(i, j, k)); + } + } + for (int j = 0; j <= endMonth; j++) { + list.add(getTimeList(endYear, j, k)); + } + } + } + return list; + } + + /** + * 判断当前时间是否在[startTime, endTime]区间,注意时间格式要一致 + * + * @param nowTime 当前时间 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return + */ + public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) { + if (nowTime.getTime() == startTime.getTime() + || nowTime.getTime() == endTime.getTime()) { + return true; + } + Calendar date = Calendar.getInstance(); + date.setTime(nowTime); + Calendar begin = Calendar.getInstance(); + begin.setTime(startTime); + Calendar end = Calendar.getInstance(); + end.setTime(endTime); + + if (date.after(begin) && date.before(end)) { + return true; + } else { + return false; + } + } + + // =================================时间格式转换========================== + + /** + * date类型进行格式化输出 + * + * @param pattern + * @return + */ + public static String dateNow(String pattern) { + Date date = new Date(); + if (pattern == null && "".equals(pattern)) { + return null; + } + SimpleDateFormat formatter = new SimpleDateFormat(pattern); + String dateString = formatter.format(date); + return dateString; + } + + /** + * date类型进行格式化输出 + * + * @param date + * @param pattern + * @return + */ + public static String dateToString(Date date, String pattern) { + if (StringUtil.isEmpty(pattern) && date == null) { + return null; + } + SimpleDateFormat formatter = new SimpleDateFormat(pattern); + String dateString = formatter.format(date); + return dateString; + } + + /** + * date类型进行格式化输出(返回类型:String) + * + * @param date + * @return + */ + public static String dateFormat(Date date) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String dateString = formatter.format(date); + return dateString; + } + + /** + * date类型进行格式化输出(返回类型:String) + * + * @param date + * @return + */ + public static String daFormat(Date date) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + String dateString = formatter.format(date); + return dateString; + } + + /** + * date类型进行格式化输出(返回类型:String) + * + * @param date + * @return + */ + public static String dateFormatByPattern(Date date, String pattern) { + SimpleDateFormat formatter = new SimpleDateFormat(pattern); + String dateString = formatter.format(date); + return dateString; + } + + /** + * 时间戳类型进行格式化输出(返回类型:String) + * + * @param date + * @return + */ + public static String daFormat(Long date) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + Date time = new Date(date); + String dateString = formatter.format(time); + return dateString; + } + + /** + * 时间戳类型进行格式化输出yyyy-MM-dd(返回类型:String) + * + * @param date + * @return + */ + public static String daFormatYmd(Long date) { + DateTimeFormatter ftf = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String dateString = ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(date), ZoneId.of("+8"))); + return dateString; + } + + /** + * 时间戳类型进行格式化输出(返回类型:String) + * + * @param date + * @return + */ + public static String daFormatHHMMSSAddEight(Long date) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date time = dateAddHours(new Date(date), 8); + String dateString = formatter.format(time); + return dateString; + } + + /** + * 时间戳类型进行格式化输出(返回类型:String) + * + * @param date + * @return + */ + public static String daFormatHHMMSS(Long date) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date time = new Date(date); + String dateString = formatter.format(time); + return dateString; + } + + /** + * 将"2015-08-31 21:08:06"型字符串转化为Date + * + * @param str + * @return + * @throws ParseException + */ + public static Date stringToDate(String str) { + Date date = null; + if (StringUtil.isEmpty(str)) { + return date; + } + try { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + date = formatter.parse(str); + } catch (ParseException e) { + System.out.println(e.getMessage()); + return date; + } + return date; + } + + /** + * 将"2015-08-31"型字符串转化为Date + * + * @param str + * @return + * @throws ParseException + */ + public static Date stringToDates(String str) { + Date date = null; + try { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + date = formatter.parse(str); + } catch (ParseException e) { + return date; + } + return date; + } + + /** + * 将CST时间类型字符串进行格式化输出 + * + * @param str + * @return + * @throws ParseException + */ + public static String cstFormat(String str) { + try { + SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US); + Date date = formatter.parse(str); + return dateFormat(date); + } catch (Exception e) { + return ""; + } + } + + /** + * 将long类型转化为Date + * + * @param str + * @return + * @throws ParseException + */ + public static Date longToDate(long str) throws ParseException { + return new Date(str * 1000); + } + + // ====================================其他常见日期操作方法====================== + + /** + * 判断当前日期是否在[startDate, endDate]区间 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return + * @author jqlin + */ + public static boolean isEffectiveDate(Date startDate, Date endDate) { + if (startDate == null || endDate == null) { + return false; + } + long currentTime = System.currentTimeMillis(); + if (currentTime >= startDate.getTime() + && currentTime <= endDate.getTime()) { + return true; + } + return false; + } + + /** + * 得到二个日期间的间隔天数 + * + * @param secondString:后一个日期 + * @param firstString:前一个日期 + * @return + */ + public static String getTwoDay(String secondString, String firstString) { + SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd"); + long day = 0; + try { + Date secondTime = myFormatter.parse(secondString); + Date firstTime = myFormatter.parse(firstString); + day = (secondTime.getTime() - firstTime.getTime()) / (24 * 60 * 60 * 1000); + } catch (Exception e) { + return ""; + } + return day + ""; + } + + /** + * 时间前推或后推分钟,其中JJ表示分钟. + * + * @param stringTime:时间 + * @param minute:分钟(有正负之分) + * @return + */ + public static String getPreTime(String stringTime, String minute) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String mydate1 = ""; + try { + Date date1 = format.parse(stringTime); + long time = (date1.getTime() / 1000) + Integer.parseInt(minute) * 60; + date1.setTime(time * 1000); + mydate1 = format.format(date1); + } catch (Exception e) { + return ""; + } + return mydate1; + } + + /** + * 时间转成成秒 + */ + public static long getTime(Date data) { + if (data != null) { + return (data.getTime() / 1000); + } + return 0; + } + + /** + * 将短时间格式字符串转换为时间 yyyy-MM-dd + * + * @param strDate + * @return + */ + public static Date strToDate(String strDate) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + ParsePosition pos = new ParsePosition(0); + Date strtodate = formatter.parse(strDate, pos); + return strtodate; + } + + /** + * 得到一个时间延后或前移几天的时间 + * + * @param nowdate:时间 + * @param delay:前移或后延的天数 + * @return + */ + public static String getNextDay(String nowdate, String delay) { + try { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + String mdate = ""; + Date d = strToDate(nowdate); + long myTime = (d.getTime() / 1000) + Integer.parseInt(delay) * 24 * 60 * 60; + d.setTime(myTime * 1000); + mdate = format.format(d); + return mdate; + } catch (Exception e) { + return ""; + } + } + + /** + * 判断是否闰年 + * + * @param ddate + * @return + */ + public static boolean isLeapYear(String ddate) { + /** + * 详细设计: 1.被400整除是闰年,否则: 2.不能被4整除则不是闰年 3.能被4整除同时不能被100整除则是闰年 + * 3.能被4整除同时能被100整除则不是闰年 + */ + Date d = strToDate(ddate); + GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance(); + gc.setTime(d); + int year = gc.get(Calendar.YEAR); + if ((year % 400) == 0) { + return true; + } else if ((year % 4) == 0) { + if ((year % 100) == 0) { + return false; + } else { + return true; + } + } else { + return false; + } + } + + /** + * 返回美国时间格式 + * + * @param str + * @return + */ + public static String geteDate(String str) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + ParsePosition pos = new ParsePosition(0); + Date strtodate = formatter.parse(str, pos); + String j = strtodate.toString(); + String[] k = j.split(" "); + return k[2] + k[1].toUpperCase() + k[5].substring(2, 4); + } + + /** + * 判断二个时间是否在同一个周 + * + * @param date1 + * @param date2 + * @return + */ + public static boolean isSameWeekDates(Date date1, Date date2) { + Calendar cal1 = Calendar.getInstance(); + Calendar cal2 = Calendar.getInstance(); + cal1.setTime(date1); + cal2.setTime(date2); + int subYear = cal1.get(Calendar.YEAR) - cal2.get(Calendar.YEAR); + if (0 == subYear) { + if (cal1.get(Calendar.WEEK_OF_YEAR) == cal2.get(Calendar.WEEK_OF_YEAR)) { + return true; + } + } else if (1 == subYear && 11 == cal2.get(Calendar.MONTH)) { + // 如果12月的最后一周横跨来年第一周的话则最后一周即算做来年的第一周 + if (cal1.get(Calendar.WEEK_OF_YEAR) == cal2.get(Calendar.WEEK_OF_YEAR)) { + return true; + } + } else if (-1 == subYear && 11 == cal1.get(Calendar.MONTH)) { + if (cal1.get(Calendar.WEEK_OF_YEAR) == cal2.get(Calendar.WEEK_OF_YEAR)) { + return true; + } + } + return false; + } + + /** + * 产生周序列,即得到当前时间所在的年度是第几周 + * + * @return + */ + public static String getSeqWeek() { + Calendar c = Calendar.getInstance(Locale.CHINA); + String week = Integer.toString(c.get(Calendar.WEEK_OF_YEAR)); + if (week.length() == 1) { + week = "0" + week; + } + String year = Integer.toString(c.get(Calendar.YEAR)); + return year + "年第" + week + "周"; + } + + /** + * 获得一个日期所在的周的星期几的日期,如要找出2002年2月3日所在周的星期一是几号 + * + * @param sdate:日期 + * @param num:星期几(星期天是一周的第一天) + * @return + */ + public static String getWeek(String sdate, String num) { + // 再转换为时间 + Date dd = strToDate(sdate); + Calendar c = Calendar.getInstance(); + c.setTime(dd); + if ("1".equals(num)) { + // 返回星期一所在的日期 + c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); + } else if ("2".equals(num)) { + // 返回星期二所在的日期 + c.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY); + } else if ("3".equals(num)) { + // 返回星期三所在的日期 + c.set(Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY); + } else if ("4".equals(num)) { + // 返回星期四所在的日期 + c.set(Calendar.DAY_OF_WEEK, Calendar.THURSDAY); + } else if ("5".equals(num)) { + // 返回星期五所在的日期 + c.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY); + } else if ("6".equals(num)) { + // 返回星期六所在的日期 + c.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY); + } else if ("0".equals(num)) { + // 返回星期日所在的日期 + c.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); + } + return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime()); + } + + /** + * 根据一个日期,返回是星期几的字符串 + * + * @param sdate + * @return + */ + public static String getWeek(String sdate) { + // 再转换为时间 + Date date = strToDate(sdate); + Calendar c = Calendar.getInstance(); + c.setTime(date); + return new SimpleDateFormat("EEEE").format(c.getTime()); + } + + /** + * 根据一个日期,返回是星期几的字符串 + * + * @param sdate + * @return + */ + public static String getWeekStr(String sdate) { + String str = ""; + str = getWeek(sdate); + if ("1".equals(str)) { + str = "星期日"; + } else if ("2".equals(str)) { + str = "星期一"; + } else if ("3".equals(str)) { + str = "星期二"; + } else if ("4".equals(str)) { + str = "星期三"; + } else if ("5".equals(str)) { + str = "星期四"; + } else if ("6".equals(str)) { + str = "星期五"; + } else if ("7".equals(str)) { + str = "星期六"; + } + return str; + } + + /** + * 根据一个日期,返回是星期几的字符串 + * + * @param date + * @return + */ + public static String getWeekStr(Date date) { + Calendar c = Calendar.getInstance(); + c.setTime(date); + String str = c.get(Calendar.DAY_OF_WEEK) + ""; + if ("1".equals(str)) { + str = "SUN"; + } else if ("2".equals(str)) { + str = "MON"; + } else if ("3".equals(str)) { + str = "TUE"; + } else if ("4".equals(str)) { + str = "WED"; + } else if ("5".equals(str)) { + str = "THU"; + } else if ("6".equals(str)) { + str = "FRI"; + } else if ("7".equals(str)) { + str = "SAT"; + } + return str; + } + + /** + * 两个时间之间的天数 + * + * @param date1 + * @param date2 + * @return + */ + public static long getDays(String date1, String date2) { + if (date1 == null || "".equals(date1)) { + return 0; + } + if (date2 == null || "".equals(date2)) { + return 0; + } + // 转换为标准时间 + SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd"); + Date date = null; + Date mydate = null; + try { + date = myFormatter.parse(date1); + mydate = myFormatter.parse(date2); + } catch (Exception e) { + throw new RuntimeException(e); + } + long day = (date.getTime() - mydate.getTime()) / (24 * 60 * 60 * 1000); + return day; + } + + /** + * 形成如下的日历 , 根据传入的一个时间返回一个结构 星期日 星期一 星期二 星期三 星期四 星期五 星期六 下面是当月的各个时间 + * 此函数返回该日历第一行星期日所在的日期 + * + * @param sdate + * @return + */ + public static String getNowMonth(String sdate) { + // 取该时间所在月的一号 + sdate = sdate.substring(0, 8) + "01"; + // 得到这个月的1号是星期几 + Date date = strToDate(sdate); + Calendar c = Calendar.getInstance(); + c.setTime(date); + int u = c.get(Calendar.DAY_OF_WEEK); + String newday = getNextDay(sdate, (1 - u) + ""); + return newday; + } + + /** + * 根据用户传入的时间表示格式,返回当前时间的格式 如果是yyyyMMdd,注意字母y不能大写 + * + * @param sformat + * @return + */ + public static String getUserDate(String sformat) { + Date currentTime = new Date(); + SimpleDateFormat formatter = new SimpleDateFormat(sformat); + String dateString = formatter.format(currentTime); + return dateString; + } + + /** + * 根据用户传入的时间表示格式,返回当前时间的格式 如果是yyyyMMdd,注意字母y不能大写 + * + * @param sformat + * @return + */ + public static String getDateString(Date date, String sformat) { + Date currentTime = null; + if (date == null) { + currentTime = new Date(); + } else { + currentTime = date; + } + SimpleDateFormat formatter = new SimpleDateFormat(sformat); + String dateString = formatter.format(currentTime); + return dateString; + } + + /** + * 返回一个i位数的随机数 + * + * @param i + * @return + */ + public static String getRandom(int i) { + Random jjj = new Random(); + if (i == 0) { + return ""; + } + String jj = ""; + for (int k = 0; k < i; k++) { + jj = jj + jjj.nextInt(9); + } + return jj; + } + + // ====================================日期格式转换====================== + + /** + * Date转换为LocalDateTime + * + * @param date + */ + public static LocalDateTime dateToLocalDateTime(Date date) { + if (date != null) { + // An instantaneous point on the time-line.(时间线上的一个瞬时点。) + Instant instant = date.toInstant(); + // A time-zone ID, such ZxingCodeUtil {@code Europe/Paris}.(时区) + ZoneId zoneId = ZoneId.systemDefault(); + LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime(); + return localDateTime; + } + return null; + } + + /** + * LocalDateTime转换为Date + * + * @param localDateTime + */ + public static Date localDateTimeToDate(LocalDateTime localDateTime) { + if (localDateTime != null) { + ZoneId zoneId = ZoneId.systemDefault(); + // Combines this date-time with a time-zone to create a ZonedDateTime. + ZonedDateTime zdt = localDateTime.atZone(zoneId); + Date date = Date.from(zdt.toInstant()); + return date; + } + return null; + } + + // ====================================当前时间加减====================== + + /** + * 时间加减小时 + * + * @param startDate 要处理的时间,Null则为当前时间 + * @param hours 加减的小时 + * @return Date + */ + public static Date dateAddHours(Date startDate, int hours) { + if (startDate == null) { + startDate = new Date(); + } + Calendar c = Calendar.getInstance(); + c.setTime(startDate); + c.set(Calendar.HOUR, c.get(Calendar.HOUR) + hours); + return c.getTime(); + } + + /** + * 时间加减分钟 + * + * @param startDate 要处理的时间,Null则为当前时间 + * @param minutes 加减的分钟 + * @return Date + */ + public static Date dateAddMinutes(Date startDate, int minutes) { + if (startDate == null) { + startDate = new Date(); + } + Calendar c = Calendar.getInstance(); + c.setTime(startDate); + c.set(Calendar.MINUTE, c.get(Calendar.MINUTE) + minutes); + return c.getTime(); + } + + /** + * 时间加减秒数 + * + * @param startDate 要处理的时间,Null则为当前时间 + * @param seconds 加减的秒数 + * @return Date + */ + public static Date dateAddSeconds(Date startDate, int seconds) { + if (startDate == null) { + startDate = new Date(); + } + Calendar c = Calendar.getInstance(); + c.setTime(startDate); + c.set(Calendar.SECOND, c.get(Calendar.SECOND) + seconds); + return c.getTime(); + } + + /** + * 时间加减年数 + * + * @param startDate 要处理的时间,Null则为当前时间 + * @param years 加减的年数 + * @return Date + */ + public static Date dateAddYears(Date startDate, int years) { + if (startDate == null) { + startDate = new Date(); + } + Calendar c = Calendar.getInstance(); + c.setTime(startDate); + c.set(Calendar.YEAR, c.get(Calendar.YEAR) + years); + return c.getTime(); + } + + /** + * 时间加减月数 + * + * @param startDate 要处理的时间,Null则为当前时间 + * @param months 加减的月数 + * @return Date + */ + public static Date dateAddMonths(Date startDate, int months) { + if (startDate == null) { + startDate = new Date(); + } + Calendar c = Calendar.getInstance(); + c.setTime(startDate); + c.set(Calendar.MONTH, c.get(Calendar.MONTH) + months); + return c.getTime(); + } + + /** + * 时间加减天数 + * + * @param startDate 要处理的时间,Null则为当前时间 + * @param days 加减的天数 + * @return Date + */ + public static Date dateAddDays(Date startDate, int days) { + if (startDate == null) { + startDate = new Date(); + } + Calendar c = Calendar.getInstance(); + c.setTime(startDate); + c.set(Calendar.DATE, c.get(Calendar.DATE) + days); + return c.getTime(); + } + + /** + * 时间加减小时 + * + * @param localDateTime 要处理的时间,Null则为当前时间 + * @param hours 加减的小时 + * @return Date + */ + public static LocalDateTime localDateAddHours(LocalDateTime localDateTime, int hours) { + if (localDateTime == null) { + localDateTime = LocalDateTime.now(); + } + return localDateTime.plusHours(hours); + } + + /** + * 时间加减分钟 + * + * @param localDateTime 要处理的时间,Null则为当前时间 + * @param minutes 加减的分钟 + * @return Date + */ + public static LocalDateTime localDateAddMinutes(LocalDateTime localDateTime, int minutes) { + if (localDateTime == null) { + localDateTime = LocalDateTime.now(); + } + return localDateTime.plusMinutes(minutes); + } + + /** + * 时间加减秒数 + * + * @param localDateTime 要处理的时间,Null则为当前时间 + * @param seconds 加减的秒数 + * @return Date + */ + public static LocalDateTime localDateAddSeconds(LocalDateTime localDateTime, int seconds) { + if (localDateTime == null) { + localDateTime = LocalDateTime.now(); + } + return localDateTime.plusSeconds(seconds); + } + + /** + * 时间加减年数 + * + * @param localDateTime 要处理的时间,Null则为当前时间 + * @param years 加减的年数 + * @return Date + */ + public static LocalDateTime localDateAddYears(LocalDateTime localDateTime, int years) { + if (localDateTime == null) { + localDateTime = LocalDateTime.now(); + } + return localDateTime.plusYears(years); + } + + /** + * 时间加减月数 + * + * @param localDateTime 要处理的时间,Null则为当前时间 + * @param months 加减的月数 + * @return Date + */ + public static LocalDateTime localDateMonths(LocalDateTime localDateTime, int months) { + if (localDateTime == null) { + localDateTime = LocalDateTime.now(); + } + return localDateTime.plusMonths(months); + } + + /** + * 时间加减天数 + * + * @param localDateTime 要处理的时间,Null则为当前时间 + * @param days 加减的天数 + * @return Date + */ + public static LocalDateTime localDateAddDays(LocalDateTime localDateTime, int days) { + if (localDateTime == null) { + localDateTime = LocalDateTime.now(); + } + return localDateTime.plusDays(days); + } + + // ====================================时间比较====================== + + /** + * 时间比较(如果myDate>compareDate返回1,<返回-1,相等返回0) + * + * @param myDate 时间 + * @param compareDate 要比较的时间 + * @return int + */ + public static int dateCompare(Date myDate, Date compareDate) { + Calendar myCal = Calendar.getInstance(); + Calendar compareCal = Calendar.getInstance(); + myCal.setTime(myDate); + compareCal.setTime(compareDate); + return myCal.compareTo(compareCal); + } + + /** + * 获取两个时间中最小的一个时间 + * + * @param date + * @param compareDate + * @return Date + */ + public static Date dateMin(Date date, Date compareDate) { + if (date == null) { + return compareDate; + } + if (compareDate == null) { + return date; + } + if (1 == dateCompare(date, compareDate)) { + return compareDate; + } else if (-1 == dateCompare(date, compareDate)) { + return date; + } + return date; + } + + /** + * 获取两个时间中最大的一个时间 + * + * @param date + * @param compareDate + * @return Date + */ + public static Date dateMax(Date date, Date compareDate) { + if (date == null) { + return compareDate; + } + if (compareDate == null) { + return date; + } + if (1 == dateCompare(date, compareDate)) { + return date; + } else if (-1 == dateCompare(date, compareDate)) { + return compareDate; + } + return date; + } + + /** + * 获取时间当年某个月的最后一天 + * + * @param startDate + * @param month 月份 + * @return int 天数 + */ + public static int getLastDayOfMonth(Date startDate, int month) { + if (startDate == null) { + startDate = new Date(); + } + Calendar c = Calendar.getInstance(); + c.setTime(startDate); + c.set(c.get(Calendar.YEAR), month, 1); + c.add(Calendar.DATE, -1); + int day = c.get(Calendar.DAY_OF_MONTH); + return day; + } + + /** + * 获取固定日期范围内的所有日期,以数组形式返回 + */ + public static List getAllDays(Date startTime, Date endTime) { + List listDay = new ArrayList<>(); + Date dtDay = new Date(); + for (dtDay = startTime; dtDay.compareTo(endTime) <= 0; dtDay = DateUtil.dateAddDays(dtDay, 1)) { + listDay.add(dtDay); + } + return listDay; + } + + // ====================================通过cron转换成时间====================== + + /** + * 获取最近几次的运行时间 + * + * @param cron 表达式 + * @param numTimes 次数 + * @return + */ + public static List getRecentExecTime(String cron, int numTimes) { + List list = new ArrayList<>(); + try { + CronTriggerImpl cronTriggerImpl = new CronTriggerImpl(); + cronTriggerImpl.setCronExpression(cron); + // 这个是重点,一行代码搞定 + List dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, numTimes); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + for (Date date : dates) { + list.add(dateFormat.format(date)); + } + } catch (ParseException e) { + e.getMessage(); + } + return list; + } + + /** + * 获取从某个时间段下一次执行的运行时间 + * + * @param cron 表达式 + * @param dates 日期 + * @return + */ + public static String getNextCron(String cron, Date dates) { + String crons = null; + if (dates == null) { + dates = new Date(); + } + if (StringUtil.isEmpty(cron)) { + return crons; + } + CronExpression cronExpression = null; + try { + cronExpression = new CronExpression(cron); + } catch (ParseException e) { + System.out.println(e.getMessage()); + return crons; + } + Date date = cronExpression.getNextValidTimeAfter(dates); + if (date != null) { + crons = dateFormat(date); + } + return crons; + } + + /** + * 获取从某个时间段下一次执行的运行时间 + * + * @param cron 表达式 + * @param dates 日期 + * @return + */ + public static Date getNextCronDate(String cron, Date dates) { + Date crons = new Date(); + if (dates == null) { + dates = new Date(); + } + if (StringUtil.isEmpty(cron)) { + return crons; + } + CronExpression cronExpression = null; + try { + cronExpression = new CronExpression(cron); + } catch (ParseException e) { + System.out.println(e.getMessage()); + return crons; + } + Date date = cronExpression.getNextValidTimeAfter(dates); + return date; + } + + public static void getNextDate(int num, String repetition, Date dates, Date repeatTime, List dataList) { + if (dates == null) { + dates = new Date(); + } + if (repeatTime == null) { + repeatTime = new Date(); + } + int result = 0; + List repetitionList = new ArrayList() { + { + add("2"); + add("3"); + add("4"); + add("5"); + } + }; + if (ObjectUtil.isNotEmpty(repetition) && repetitionList.contains(repetition)) { + switch (repetition) { + case "2": + DateTime day = cn.hutool.core.date.DateUtil.offsetDay(dates, num); + if (day.getTime() <= repeatTime.getTime()) { + dataList.add(day); + num++; + result++; + } + break; + case "3": + DateTime week = cn.hutool.core.date.DateUtil.offsetDay(dates, num * 7); + if (week.getTime() <= repeatTime.getTime()) { + dataList.add(week); + num++; + result++; + } + break; + case "4": + DateTime month = cn.hutool.core.date.DateUtil.offsetMonth(dates, num); + if (month.getTime() <= repeatTime.getTime()) { + dataList.add(month); + num++; + result++; + } + break; + case "5": + DateTime year = cn.hutool.core.date.DateUtil.offsetMonth(dates, num * 12); + if (year.getTime() <= repeatTime.getTime()) { + dataList.add(year); + num++; + result++; + } + break; + default: + break; + + } + if (result > 0) { + getNextDate(num, repetition, dates, repeatTime, dataList); + } + } else { + dataList.add(dates); + } + } + + public static void getNextDate(Date dates, String repetition, Date repeatTime, List dataList) { + if (dates == null) { + dates = new Date(); + } + if (repeatTime == null) { + repeatTime = new Date(); + } + List repetitionList = new ArrayList() { + { + add("2"); + add("3"); + add("4"); + add("5"); + } + }; + if (repeatTime.getTime() >= dates.getTime() && ObjectUtil.isNotEmpty(repetition) + && repetitionList.contains(repetition)) { + dataList.add(dates); + Date date = dates; + switch (repetition) { + case "2": + date = cn.hutool.core.date.DateUtil.offsetDay(dates, 1); + break; + case "3": + date = cn.hutool.core.date.DateUtil.offsetDay(dates, 7); + break; + case "4": + date = cn.hutool.core.date.DateUtil.offsetMonth(dates, 1); + break; + case "5": + date = cn.hutool.core.date.DateUtil.offsetMonth(dates, 12); + break; + default: + break; + } + getNextDate(date, repetition, repeatTime, dataList); + } else if (!repetitionList.contains(repetition)) { + dataList.add(dates); + } + } + + /** + * 时间转成cron + * + * @return + */ + public static String getDateToCron(Date date) { + String cron = null; + String dateFormat = "ss mm HH dd MM ?"; + if (date == null) { + cron = dateNow(dateFormat); + } else { + cron = dateToString(date, dateFormat); + } + return cron; + } + + public static boolean timeCalendar(Date nowTime, Date dayTimeStart, Date dayTimeEnd) { + // 设置当前时间 + Calendar date = Calendar.getInstance(); + date.setTime(nowTime); + // 设置开始时间 + Calendar timeStart = Calendar.getInstance(); + timeStart.setTime(dayTimeStart); + // 设置结束时间 + Calendar timeEnd = Calendar.getInstance(); + timeEnd.setTime(dayTimeEnd); + if (date.equals(timeStart) || date.equals(timeEnd)) { + return true; + } + if ((date.after(timeStart) && date.before(timeEnd))) { + return true; + } else { + return false; + } + } + + public static boolean isValidDate(String str) { + boolean convertSuccess = true; + // 指定日期格式为四位年/两位月份/两位日期,注意yyyy/MM/dd区分大小写; + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + if (str.length() == 10) { + format = new SimpleDateFormat("yyyy-MM-dd"); + } + try { + // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期,比如2007/02/29会被接受,并转换成2007/03/01 + format.setLenient(false); + format.parse(str); + } catch (ParseException e) { + convertSuccess = false; + } + return convertSuccess; + } + + public static boolean isOverlap(Date leftStartDate, Date leftEndDate, Date rightStartDate, Date rightEndDate) { + + return ((leftStartDate.getTime() >= rightStartDate.getTime()) + && leftStartDate.getTime() < rightEndDate.getTime()) + || + ((leftStartDate.getTime() > rightStartDate.getTime()) + && leftStartDate.getTime() <= rightEndDate.getTime()) + || + ((rightStartDate.getTime() >= leftStartDate.getTime()) + && rightStartDate.getTime() < leftEndDate.getTime()) + || + ((rightStartDate.getTime() > leftStartDate.getTime()) + && rightStartDate.getTime() <= leftEndDate.getTime()); + + } + + /** + * 时间范围添加连接符 + * + * @param jsonArray + * @param type + * @param format + * @return + */ + public static JSONArray addCon(JSONArray jsonArray, String type, String format) { + + if ("timeRange".equals(type)) { + String value1 = jsonArray.get(0).toString(); + String value2 = jsonArray.get(1).toString(); + jsonArray.clear(); + jsonArray.add(value1 + "至"); + jsonArray.add(value2); + } + if ("dateRange".equals(type)) { + DateTimeFormatter ftfDateRange = DateTimeFormatter.ofPattern(format); + long date1 = Long.parseLong(String.valueOf(jsonArray.get(0))); + long date2 = Long.parseLong(String.valueOf(jsonArray.get(1))); + String value1 = ftfDateRange + .format(LocalDateTime.ofInstant(Instant.ofEpochMilli(date1), ZoneId.systemDefault())); + String value2 = ftfDateRange + .format(LocalDateTime.ofInstant(Instant.ofEpochMilli(date2), ZoneId.systemDefault())); + jsonArray.clear(); + jsonArray.add(value1 + "至"); + jsonArray.add(value2); + } + return jsonArray; + } + + /** + * 获取时间戳 + */ + public static Long getMillis2() { + return Instant.now().toEpochMilli(); + } + + /** + * LocalDateTime转时间戳 + */ + public static Long localDateTime2Millis(LocalDateTime localDateTime) { + return localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli(); + } + + /** + * LocalDate转时间戳 + */ + public static Long localDate2Millis(LocalDate localDate) { + return LocalDateTime.of(localDate, LocalTime.MIN).toInstant(ZoneOffset.ofHours(8)).toEpochMilli(); + } + + /** + * Clock转时间戳 + */ + public static Long clock2Millis(Clock clock) { + return clock.millis(); + } + + /** + * ZoneDateTIme转时间戳(这个不常用吧~) + */ + public static Long zoneDateTime2Millis(ZonedDateTime zonedDateTime) { + return zonedDateTime.toLocalDateTime().toInstant(ZoneOffset.ofHours(8)).toEpochMilli(); + } + + /** + * String转时间戳(JDK8) + */ + public static Long string2MillisWithJdk8(String dateStr, String formatStr) { + return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(formatStr)).toInstant(ZoneOffset.ofHours(8)) + .toEpochMilli(); + } + + /** + * ZonedDateTime转String + * + * @param zonedDateTime + * @return + */ + public static String getZonedDateTimeToString(ZonedDateTime zonedDateTime) { + ZonedDateTime zoneDateTime1 = zonedDateTime.plusHours(11); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + return zoneDateTime1.format(formatter); + } + + /** + * 根据格式判断时间值是否正确 + * + * @param dataStr + * @param format + * @return + */ + public static Date checkDate(String dataStr, String format) { + try { + if (format.length() != dataStr.length()) + throw new DataException(); + SimpleDateFormat formatter = new SimpleDateFormat(format); + formatter.setLenient(false); + return formatter.parse(dataStr); + } catch (Exception e) { + return null; + } + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DesUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DesUtil.java new file mode 100644 index 0000000..26575f6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DesUtil.java @@ -0,0 +1,295 @@ +package com.yunzhupaas.util; + + + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.HexUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.SymmetricAlgorithm; +import cn.hutool.crypto.symmetric.SymmetricCrypto; +import com.yunzhupaas.constant.GlobalConst; +import com.yunzhupaas.properties.SecurityProperties; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.SecureRandom; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +public class DesUtil { + private static final String MD5 = "MD5"; + private static final String SHA1 = "SHA1"; + private static final String HMAC_MD_5 = "HmacMD5"; + private static final String HMAC_SHA_1 = "HmacSHA1"; + private static final String DES = "DES"; + private static final String AES = "AES"; + + /**编码格式;默认使用uft-8*/ + private static String charset = "utf-8"; + /**DES*/ + private static int keysizeDES = 0; + /**AES*/ + private static int keysizeAES = 128; + + + /** + * 使用MessageDigest进行单向加密(无密码) + * @param res 被加密的文本 + * @param algorithm 加密算法名称 + * @return + */ + private static String messageDigest(String res,String algorithm){ + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + byte[] resBytes = charset==null?res.getBytes():res.getBytes(charset); + return base64(md.digest(resBytes)); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 使用KeyGenerator进行单向/双向加密(可设密码) + * @param res 被加密的原文 + * @param algorithm 加密使用的算法名称 + * @param key 加密使用的秘钥 + * @return + */ + private static String keyGeneratorMac(String res,String algorithm,String key){ + try { + SecretKey sk = null; + if (key==null) { + KeyGenerator kg = KeyGenerator.getInstance(algorithm); + sk = kg.generateKey(); + }else { + byte[] keyBytes = charset==null?key.getBytes():key.getBytes(charset); + sk = new SecretKeySpec(keyBytes, algorithm); + } + Mac mac = Mac.getInstance(algorithm); + mac.init(sk); + byte[] result = mac.doFinal(res.getBytes()); + return base64(result); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 使用KeyGenerator双向加密,DES/AES,注意这里转化为字符串的时候是将2进制转为16进制格式的字符串,不是直接转,因为会出错 + * @param res 加密的原文 + * @param algorithm 加密使用的算法名称 + * @param key 加密的秘钥 + * @param keysize + * @param isEncode + * @return + */ + private static String keyGeneratorEs(String res, String algorithm, String key, int keysize, boolean isEncode){ + try { + SecretKeySpec sks = null; + KeyGenerator kg = KeyGenerator.getInstance(algorithm); + if (key==null) { + kg.init(keysize); + }else { + SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); + random.setSeed(key.getBytes()); + if (keysize == 0) { + kg.init(random); + } else { + kg.init(keysize, random); + } + } + SecretKey sk = kg.generateKey(); + sks = new SecretKeySpec(sk.getEncoded(), algorithm); + Cipher cipher = Cipher.getInstance(algorithm); + if (isEncode) { + cipher.init(Cipher.ENCRYPT_MODE, sks); + byte[] resBytes = charset==null?res.getBytes():res.getBytes(charset); + return parseByte2HexStr(cipher.doFinal(resBytes)); + }else { + cipher.init(Cipher.DECRYPT_MODE, sks); + return new String(cipher.doFinal(parseHexStr2Byte(res))); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private static String base64(byte[] res){ + return Base64.encode(res); + } + + /**将二进制转换成16进制 */ + public static String parseByte2HexStr(byte[] buf) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < buf.length; i++) { + String hex = Integer.toHexString(buf[i] & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + sb.append(hex.toUpperCase()); + } + return sb.toString(); + } + /**将16进制转换为二进制*/ + public static byte[] parseHexStr2Byte(String hexStr) { + if (hexStr.length() < 1) { + return null; + } + byte[] result = new byte[hexStr.length()/2]; + for (int i = 0;i< hexStr.length()/2; i++) { + int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); + int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); + result[i] = (byte) (high * 16 + low); + } + return result; + } + + /** + * md5加密算法进行加密(不可逆) + * @param res 需要加密的原文 + * @return + */ + public static String md5(String res) { + return messageDigest(res, MD5); + } + + /** + * md5加密算法进行加密(不可逆) + * @param res 需要加密的原文 + * @param key 秘钥 + * @return + */ + public static String md5(String res, String key) { + return keyGeneratorMac(res, HMAC_MD_5, key); + } + + /** + * 使用SHA1加密算法进行加密(不可逆) + * @param res 需要加密的原文 + * @return + */ + public static String sha1(String res) { + return messageDigest(res, SHA1); + } + + /** + * 使用SHA1加密算法进行加密(不可逆) + * @param res 需要加密的原文 + * @param key 秘钥 + * @return + */ + public static String sha1(String res, String key) { + return keyGeneratorMac(res, HMAC_SHA_1, key); + } + + /** + * 使用DES加密算法进行加密(可逆) + * @param res 需要加密的原文 + * @return + */ + public static String desEncode(String res) { + return keyGeneratorEs(res, DES, SecurityProperties.getInstance().getSecurityKey(), keysizeDES, true); + } + + /** + * 对使用DES加密算法的密文进行解密(可逆) + * @param res 需要解密的密文 + * @return + */ + public static String desDecode(String res) { + return keyGeneratorEs(res, DES, SecurityProperties.getInstance().getSecurityKey(), keysizeDES, false); + } + + /** + * 使用AES加密算法经行加密(可逆) + * @param res 需要加密的密文 + * @return + */ + public static String aesEncode(String res) { + return keyGeneratorEs(res, AES, SecurityProperties.getInstance().getSecurityKey(), keysizeAES, true); + } + + /** + * 对使用AES加密算法的密文进行解密 + * @param res 需要解密的密文 + * @return + */ + public static String aesDecode(String res) { + return keyGeneratorEs(res, AES, SecurityProperties.getInstance().getSecurityKey(), keysizeAES, false); + } + + /** + * 使用Base64进行加密 + * @param res 密文 + * @return + */ + public static String base64Encode(String res) { + return Base64.encode(res.getBytes()); + } + + + /** + * 使用Base64进行解密 + * @param res + * @return + */ + public static String base64Decode(String res) { + return new String(Base64.decode(res)); + } + + + /** + * aes des 加密解密 + * 加密 输出hexstr + * 解密 输入hexstr + * @param res + * @return + */ + public static String aesOrDecode(String res,boolean isEncode,boolean isAes){ + byte[] bytes; + if(isEncode){ + bytes = StrUtil.bytes(res, GlobalConst.DEFAULT_CHARSET); + }else{ + bytes = HexUtil.decodeHex(res); + } + bytes = aesOrDecode(bytes, isEncode, isAes, SecurityProperties.getInstance().getSecurityKey()); + if(isEncode){ + return HexUtil.encodeHexStr(bytes); + }else{ + return StrUtil.str(bytes, GlobalConst.DEFAULT_CHARSET); + } + } + + /** + * aes des 加密解密 + * @param res + * @return + */ + public static byte[] aesOrDecode(byte[] res, boolean isEncode, boolean isAes, String key){ + //KEY 16/24/32, + SymmetricAlgorithm symmetricAlgorithm = isAes ? SymmetricAlgorithm.AES : SymmetricAlgorithm.DES; + byte[] keyBytes = SecureUtil.generateKey(symmetricAlgorithm.getValue(), key.getBytes(GlobalConst.DEFAULT_CHARSET)).getEncoded(); + SymmetricCrypto symmetricCrypto = new SymmetricCrypto(symmetricAlgorithm, keyBytes); + if(isEncode){ + return symmetricCrypto.encrypt(res); + }else{ + return symmetricCrypto.decrypt(res); + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DownUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DownUtil.java new file mode 100644 index 0000000..e517bcd --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/DownUtil.java @@ -0,0 +1,318 @@ +package com.yunzhupaas.util; + +import com.yunzhupaas.constant.MsgCode; +import lombok.Cleanup; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Workbook; + +import javax.imageio.ImageIO; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Slf4j +public class DownUtil { + + /** + * 下载excel + * + * @param fileName excel名称 + * @param workbook + */ + public static void dowloadExcel(Workbook workbook, String fileName) { + try { + HttpServletResponse response = ServletUtil.getResponse(); + response.setCharacterEncoding(Constants.UTF8); + response.setHeader("content-Type", "application/vnd.ms-excel"); + response.setHeader("Content-Disposition", + "attachment;filename=" + URLEncoder.encode(fileName, Constants.UTF8)); + @Cleanup + ServletOutputStream outputStream = response.getOutputStream(); + workbook.write(outputStream); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 下载文件 + * + * @param file 文件 + * @param fileName 订单信息.pdf + */ + public static void dowloadFile(File file, String fileName) { + HttpServletResponse response = ServletUtil.getResponse(); + HttpServletRequest request = ServletUtil.getRequest(); + try { + @Cleanup + InputStream is = new FileInputStream(file); + @Cleanup + BufferedInputStream bis = new BufferedInputStream(is); + response.setCharacterEncoding("UTF-8"); + response.setContentType("application/x-download"); + // 编码的文件名字,关于中文乱码的改造 + String codeFileName = ""; + String agent = request.getHeader("USER-AGENT").toLowerCase(); + if (-1 != agent.indexOf("msie") || -1 != agent.indexOf("trident")) { + // IE + codeFileName = URLEncoder.encode(fileName, "UTF-8"); + } else if (-1 != agent.indexOf("mozilla")) { + // 火狐,谷歌 + codeFileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1"); + } else { + codeFileName = URLEncoder.encode(fileName, "UTF-8"); + } + response.setHeader("Content-Disposition", "attachment;filename=\"" + codeFileName + "\""); + @Cleanup + OutputStream os = response.getOutputStream(); + int i; + byte[] buff = new byte[1024 * 8]; + while ((i = bis.read(buff)) != -1) { + os.write(buff, 0, i); + } + os.flush(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 下载文件 + * + * @param paths 路径 + * @param fileName 订单信息.pdf + */ + public static void dowloadFile(String paths, String fileName) { + HttpServletResponse response = ServletUtil.getResponse(); + HttpServletRequest request = ServletUtil.getRequest(); + try { + @Cleanup + InputStream is = new FileInputStream(new File(XSSEscape.escapePath(paths))); + @Cleanup + BufferedInputStream bis = new BufferedInputStream(is); + response.setCharacterEncoding("UTF-8"); + response.setContentType("text/plain"); + if (fileName.endsWith(".pdf")) { + response.setContentType("application/pdf"); + } + if (fileName.contains(".svg")) { + response.setContentType("image/svg+xml"); + } + // 编码的文件名字,关于中文乱码的改造 + String codeFileName = ""; + String agent = request.getHeader("USER-AGENT").toLowerCase(); + if (-1 != agent.indexOf("msie") || -1 != agent.indexOf("trident")) { + // IE + codeFileName = URLEncoder.encode(fileName, "UTF-8"); + } else if (-1 != agent.indexOf("mozilla")) { + // 火狐,谷歌 + codeFileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1"); + } else { + codeFileName = URLEncoder.encode(fileName, "UTF-8"); + } + response.setHeader("Content-Disposition", + "attachment;filename=" + new String(codeFileName.getBytes(), "utf-8")); + @Cleanup + OutputStream os = response.getOutputStream(); + int i; + byte[] buff = new byte[1024 * 8]; + while ((i = bis.read(buff)) != -1) { + os.write(buff, 0, i); + } + os.flush(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 显示验证码 + */ + public static void downCode(Integer stringLength) { + HttpServletResponse response = DownUtil.getResponse(); + CodeUtil codeUtil = new CodeUtil(); + codeUtil.getRandcode(response, stringLength); + } + + /** + * 流返回界面 + */ + public static void write(BufferedImage image) { + try { + HttpServletResponse response = DownUtil.getResponse(); + // 将内存中的图片通过流动形式输出到客户端 + ImageIO.write(image, "PNG", response.getOutputStream()); + } catch (Exception e) { + e.getMessage(); + } + } + + /** + * 设置img的response + */ + public static HttpServletResponse getResponse() { + HttpServletResponse response = ServletUtil.getResponse(); + response.setCharacterEncoding("UTF-8"); + // 设置相应类型,告诉浏览器输出的内容为图片 + response.setContentType("image/jpeg"); + // 设置响应头信息,告诉浏览器不要缓存此内容 + response.setHeader("Pragma", "No-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.setDateHeader("Expire", 0); + return response; + } + + /** + * 显示预览的 pdf + */ + public static void dowloadFile(File file) { + try { + // 读取指定路径下面的文件 + @Cleanup + InputStream in = new FileInputStream(file); + @Cleanup + OutputStream outputStream = new BufferedOutputStream(ServletUtil.getResponse().getOutputStream()); + ServletUtil.getResponse().setContentType("application/pdf;charset=utf-8"); + // 编码的文件名字,关于中文乱码的改造 + String codeFileName = ""; + String agent = ServletUtil.getRequest().getHeader("USER-AGENT").toLowerCase(); + if (-1 != agent.indexOf("msie") || -1 != agent.indexOf("trident")) { + // IE + codeFileName = URLEncoder.encode(file.getName(), "UTF-8"); + } else if (-1 != agent.indexOf("mozilla")) { + // 火狐,谷歌 + codeFileName = new String(file.getName().getBytes("UTF-8"), StandardCharsets.ISO_8859_1); + } else { + codeFileName = URLEncoder.encode(file.getName(), "UTF-8"); + } + ServletUtil.getResponse().setHeader("Content-Disposition", "filename=" + codeFileName); + // 创建存放文件内容的数组 + byte[] buff = new byte[1024]; + // 所读取的内容使用 n 来接收 + int n; + // 当没有读取完时,继续读取,循环 + while ((n = in.read(buff)) != -1) { + // 将字节数组的数据全部写入到输出流中 + outputStream.write(buff, 0, n); + } + // 强制将缓存区的数据进行输出 + outputStream.flush(); + } catch (Exception e) { + e.getMessage(); + } + } + + /** + * 显示文件 + */ + public static void dowloadFile(String file) { + try { + HttpServletResponse response = ServletUtil.getResponse(); + @Cleanup + ServletOutputStream outputStream1 = response.getOutputStream(); + @Cleanup + InputStream in = new FileInputStream(file); + @Cleanup + OutputStream outputStream = new BufferedOutputStream(outputStream1); + // 创建存放文件内容的数组 + byte[] buff = new byte[1024]; + // 所读取的内容使用 n 来接收 + int n; + // 当没有读取完时,继续读取,循环 + while ((n = in.read(buff)) != -1) { + // 将字节数组的数据全部写入到输出流中 + outputStream.write(buff, 0, n); + } + // 强制将缓存区的数据进行输出 + outputStream.flush(); + } catch (Exception e) { + e.getMessage(); + } + } + + /** + * 下载 svg + * + * @param file + */ + public static void dowloadSvgFile(File file) { + try { + // 读取指定路径下面的文件 + @Cleanup + InputStream in = new FileInputStream(file); + @Cleanup + OutputStream outputStream = new BufferedOutputStream(ServletUtil.getResponse().getOutputStream()); + ServletUtil.getResponse().setContentType("image/svg+xml;charset=utf-8"); + // 编码的文件名字,关于中文乱码的改造 + String codeFileName = ""; + String agent = ServletUtil.getRequest().getHeader("USER-AGENT").toLowerCase(); + if (-1 != agent.indexOf("msie") || -1 != agent.indexOf("trident")) { + // IE + codeFileName = URLEncoder.encode(file.getName(), "UTF-8"); + } else if (-1 != agent.indexOf("mozilla")) { + // 火狐,谷歌 + codeFileName = new String(file.getName().getBytes("UTF-8"), "iso-8859-1"); + } else { + codeFileName = URLEncoder.encode(file.getName(), "UTF-8"); + } + ServletUtil.getResponse().setHeader("Content-Disposition", "filename=" + codeFileName); + // 创建存放文件内容的数组 + byte[] buff = new byte[1024]; + // 所读取的内容使用 n 来接收 + int n; + // 当没有读取完时,继续读取,循环 + while ((n = in.read(buff)) != -1) { + // 将字节数组的数据全部写入到输出流中 + outputStream.write(buff, 0, n); + } + // 强制将缓存区的数据进行输出 + outputStream.flush(); + } catch (Exception e) { + e.getMessage(); + } + } + + /** + * 下载文件 + * + * @param str + * @param fileName + */ + public static Boolean downloadFile(String str, String fileName) { + HttpServletResponse response = ServletUtil.getResponse(); + OutputStream os = null; + try { + response.reset(); + response.setContentType("application/octet-stream; charset=utf-8"); + response.setHeader("Content-Disposition", + "attachment; filename=" + new String(fileName.getBytes(), "ISO8859-1")); + byte[] bytes = str.getBytes("utf-8"); + os = response.getOutputStream(); + // 将字节流传入到响应流里,响应到浏览器 + os.write(bytes); + os.close(); + return true; + } catch (Exception ex) { + log.error("导出失败:", ex); + throw new RuntimeException(MsgCode.IMP005.get()); + } finally { + try { + if (null != os) { + os.close(); + } + } catch (IOException ioEx) { + log.error("导出失败:", ioEx); + } + } + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/FileDownloadUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/FileDownloadUtil.java new file mode 100644 index 0000000..213b8c2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/FileDownloadUtil.java @@ -0,0 +1,102 @@ +package com.yunzhupaas.util; + +import cn.hutool.core.net.URLEncodeUtil; +import com.yunzhupaas.constant.GlobalConst; +import lombok.Cleanup; +import org.springframework.http.MediaType; +import org.springframework.http.MediaTypeFactory; + +import jakarta.servlet.http.HttpServletResponse; +import java.io.*; + +public class FileDownloadUtil { + + /** + * 下载文件 + * + * @param bytes + * @param fileName 订单信息.pdf + */ + public static void downloadFile(byte[] bytes, String fileName, String downName) { + if (StringUtil.isNotEmpty(downName)) { + fileName = downName; + } + HttpServletResponse response = ServletUtil.getResponse(); + // HttpServletRequest request = ServletUtil.getRequest(); + try { + @Cleanup + InputStream is = new ByteArrayInputStream(bytes); + @Cleanup + BufferedInputStream bis = new BufferedInputStream(is); + response.setCharacterEncoding("UTF-8"); + response.setContentType("text/plain"); + if (fileName.endsWith(".pdf")) { + response.setContentType("application/pdf"); + } + if (fileName.contains(".svg")) { + response.setContentType("image/svg+xml"); + } + // 编码的文件名字,关于中文乱码的改造 + String codeFileName = fileName; + // String agent = request.getHeader("USER-AGENT").toLowerCase(); + // if (-1 != agent.indexOf("mozilla")) { + // //火狐,谷歌 + //// codeFileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1"); + // } + response.setHeader("Content-Disposition", + "attachment;filename=" + URLEncodeUtil.encode(codeFileName, GlobalConst.DEFAULT_CHARSET)); + @Cleanup + OutputStream os = response.getOutputStream(); + int i; + byte[] buff = new byte[1024 * 8]; + while ((i = bis.read(buff)) != -1) { + os.write(buff, 0, i); + } + os.flush(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 显示文件 + */ + public static void flushImage(byte[] bytes) { + flushImage(bytes, null); + } + + /** + * 显示文件 + */ + public static void flushImage(byte[] bytes, String fileName) { + try { + // 设置文件类型 + if (fileName != null && MediaTypeFactory.getMediaType(fileName).isPresent()) { + ServletUtil.getResponse() + .setContentType(MediaTypeFactory.getMediaType(fileName).orElse(MediaType.ALL).toString()); + } + // 设置文件大小 + ServletUtil.getResponse().setContentLength(bytes.length); + + // 读取指定路径下面的文件 + @Cleanup + InputStream in = new ByteArrayInputStream(bytes); + @Cleanup + OutputStream outputStream = new BufferedOutputStream(ServletUtil.getResponse().getOutputStream()); + // 创建存放文件内容的数组 + byte[] buff = new byte[1024]; + // 所读取的内容使用 n 来接收 + int n; + // 当没有读取完时,继续读取,循环 + while ((n = in.read(buff)) != -1) { + // 将字节数组的数据全部写入到输出流中 + outputStream.write(buff, 0, n); + } + // 强制将缓存区的数据进行输出 + outputStream.flush(); + } catch (Exception e) { + e.getMessage(); + } + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/FileUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/FileUtil.java new file mode 100644 index 0000000..68e4d0f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/FileUtil.java @@ -0,0 +1,893 @@ +package com.yunzhupaas.util; + +import com.yunzhupaas.constant.GlobalConst; +import com.yunzhupaas.support.MyStandardMultipartFile; +import lombok.Cleanup; +import lombok.extern.slf4j.Slf4j; +import org.apache.catalina.core.ApplicationPart; +import org.apache.tomcat.util.http.fileupload.FileItem; +import org.apache.tomcat.util.http.fileupload.FileItemFactory; +import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Slf4j +public class FileUtil { + + /** + * 判断文件夹是否存在 + * + * @param filePath 文件地址 + * @return + */ + public static boolean fileIsExists(String filePath) { + File f = new File(XSSEscape.escapePath(filePath)); + if (!f.exists()) { + return false; + } + return true; + } + + /** + * 判断文件是否存在 + * + * @param filePath + * @return + */ + public static boolean fileIsFile(String filePath) { + File f = new File(XSSEscape.escapePath(filePath)); + if (!f.isFile()) { + return false; + } + return true; + } + + /** + * 删除tmp文件 + * + * @param multipartFile + * @return + */ + public static boolean deleteTmp(MultipartFile multipartFile) { + try { + ((MyStandardMultipartFile) multipartFile).getPart().delete(); + return true; + } catch (Exception e) { + log.error("删除tmp文件失败,错误:" + e.getMessage()); + return false; + } + } + + /** + * 创建文件 + * + * @param filePath 文件地址 + * @param fileName 文件名 + * @return + */ + public static boolean createFile(String filePath, String fileName) { + String strFilePath = XSSEscape.escapePath(filePath + fileName);; + File file = new File(XSSEscape.escapePath(filePath)); + if (!file.exists()) { + /** 注意这里是 mkdirs()方法 可以创建多个文件夹 */ + file.mkdirs(); + } + File subfile = new File(XSSEscape.escapePath(strFilePath)); + if (!subfile.exists()) { + try { + boolean b = subfile.createNewFile(); + return b; + } catch (IOException e) { + e.printStackTrace(); + } + } else { + return true; + } + return false; + } + + /** + * 创建文件夹 + * + * @param filePath 文件夹地址 + * @return + */ + public static void createDirs(String filePath) { + File file = new File(XSSEscape.escapePath(filePath)); + if (!file.exists()) { + /** 注意这里是 mkdirs()方法 可以创建多个文件夹 */ + file.mkdirs(); + } + } + + /** + * 遍历文件夹下当前文件 + * + * @param file 地址 + */ + public static List getFile(File file) { + List list = new ArrayList<>(); + File[] fileArray = file.listFiles(); + if (fileArray == null) { + return list; + } else { + for (File f : fileArray) { + if (f.isFile()) { + list.add(0, f); + } + } + } + return list; + } + + /** + * 遍历文件夹下所有文件 + * + * @param file 地址 + */ + public static List getFile(File file, List list) { + File[] fileArray = file.listFiles(); + if (fileArray == null) { + return list; + } else { + for (File f : fileArray) { + if (f.isFile()) { + list.add(0, f); + } else { + getFile(f, list); + } + } + } + return list; + } + + /** + * 删除文件或文件夹以及子文件夹和子文件等 【注意】请谨慎调用该方法,避免删除重要文件 + * + * @param file + */ + public static void deleteFileAll(File file) { + if (file.exists()) { + if (file.isFile()) { + // 文件 + log.info(file.getAbsolutePath() + " 删除中..."); + file.delete(); + log.info("删除成功!"); + return; + } else { + // 文件夹 + File[] files = file.listFiles(); + for (int i = 0; i < files.length; i++) { + deleteFileAll(files[i]); + } + file.delete(); + } + } else { + log.info(file.getAbsolutePath() + " 文件不存在!"); + } + } + + /** + * 删除单个文件 + * + * @param filePath 文件路径 + */ + public static void deleteFile(String filePath) { + File file = new File(XSSEscape.escapePath(filePath)); + if (file.exists() && file.isFile()) { + file.delete(); + } + } + + /** + * 删除空文件夹、空的子文件夹 + * + * @param file + * @author cielo + */ + public static void deleteEmptyDirectory(File file) { + if (file != null && file.exists() && file.isDirectory()) { + File[] files = file.listFiles(); + if (files != null && files.length > 0) { + for (int i = 0; i < files.length; i++) { + deleteEmptyDirectory(files[i]); + } + // 子文件夹里的删除完后,重新获取。判断空的子文件删除后,该文件夹是否为空 + files = file.listFiles(); + } + if (files == null || files.length == 0) { + String absolutePath = file.getAbsolutePath(); + file.delete(); + log.info("删除空文件夹!路径:" + absolutePath); + } + } + } + + /** + * 打开目录 + * + * @param path + */ + public static void open(String path) { + // 打开输出目录 + try { + String osName = System.getProperty("os.name"); + if (osName != null) { + if (osName.contains("Mac")) { + Runtime.getRuntime().exec("open " + path); + } else if (osName.contains("Windows")) { + Runtime.getRuntime().exec("cmd /c start " + path); + } else { + log.debug("文件输出目录:" + path); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 向文件中添加内容 + * + * @param strcontent 内容 + * @param filePath 地址 + * @param fileName 文件名 + */ + public static void writeToFile(String strcontent, String filePath, String fileName) { + //生成文件夹之后,再生成文件,不然会出错 + String strFilePath = filePath + fileName; + // 每次写入时,都换行写 + File subfile = new File(strFilePath); + try { + /** 构造函数 第二个是读写方式 */ + @Cleanup RandomAccessFile raf = new RandomAccessFile(subfile, "rw"); + /** 将记录指针移动到该文件的最后 */ + raf.seek(subfile.length()); + /** 向文件末尾追加内容 */ + raf.write(strcontent.getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 向文件中添加内容 + * + * @param is 内容 + * @param filePath 地址 + * @param fileName 文件名 + */ + public static void writeToFile(InputStream is, String filePath, String fileName) { + //生成文件夹之后,再生成文件,不然会出错 + String strFilePath = filePath; + // 每次写入时,都换行写 + File subfile = new File(XSSEscape.escapePath(strFilePath)); + try { + @Cleanup FileOutputStream downloadFile = new FileOutputStream(subfile); + int index; + byte[] bytes = new byte[1024]; + while ((index = is.read(bytes)) != -1) { + downloadFile.write(bytes, 0, index); + downloadFile.flush(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 修改文件内容(覆盖或者添加) + * + * @param path 文件地址 + * @param content 覆盖内容 + * @param append 指定了写入的方式,是覆盖写还是追加写(true=追加)(false=覆盖) + */ + public static void modifyFile(String path, String content, boolean append) { + try { + @Cleanup FileWriter fileWriter = new FileWriter(path, append); + @Cleanup BufferedWriter writer = new BufferedWriter(fileWriter); + writer.append(content); + writer.flush(); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 读取文件内容 + * + * @param filePath 地址 + * @param filename 名称 + * @return 返回内容 + */ + public static String getString(String filePath, String filename) { + try { + @Cleanup FileInputStream inputStream = null; + inputStream = new FileInputStream(new File(XSSEscape.escapePath(filePath + filename))); + @Cleanup InputStreamReader inputStreamReader = null; + inputStreamReader = new InputStreamReader(inputStream, Constants.UTF8); + @Cleanup BufferedReader reader = new BufferedReader(inputStreamReader); + StringBuffer sb = new StringBuffer(""); + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + sb.append("\n"); + } + return sb.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + /** + * 重命名文件 + * + * @param oldPath 原来的文件地址 + * @param newPath 新的文件地址 + */ + public static void renameFile(String oldPath, String newPath) { + File oleFile = new File(XSSEscape.escapePath(oldPath)); + File newFile = new File(XSSEscape.escapePath(newPath)); + //执行重命名 + oleFile.renameTo(newFile); + } + + /** + * 复制文件 + * + * @param fromFile 要复制的文件目录 + * @param toFile 要粘贴的文件目录 + * @return 是否复制成功 + */ + public static boolean copy(String fromFile, String toFile) { + //要复制的文件目录 + File[] currentFiles; + File root = new File(XSSEscape.escapePath(fromFile)); + //如同判断SD卡是否存在或者文件是否存在 + //如果不存在则 return出去 + if (!root.exists()) { + return false; + } + //如果存在则获取当前目录下的全部文件 填充数组 + currentFiles = root.listFiles(); + //目标目录 + File targetDir = new File(XSSEscape.escapePath(toFile)); + //创建目录 + if (!targetDir.exists()) { + targetDir.mkdirs(); + } + //遍历要复制该目录下的全部文件 + for (int i = 0; i < currentFiles.length; i++) { + if (currentFiles[i].isDirectory()) { + //如果当前项为子目录 进行递归 + copy(currentFiles[i].getPath() + "/", toFile + currentFiles[i].getName() + "/"); + } else { + //如果当前项为文件则进行文件拷贝 + copyFile(currentFiles[i].getPath(), toFile + currentFiles[i].getName()); + } + } + return true; + } + + /** + * 文件拷贝 + * 要复制的目录下的所有非子目录(文件夹)文件拷贝 + * + * @param fromFile + * @param toFile + * @return + */ + public static boolean copyFile(String fromFile, String toFile) { + try { + @Cleanup InputStream fosfrom = new FileInputStream(XSSEscape.escapePath(fromFile)); + @Cleanup OutputStream fosto = new FileOutputStream(XSSEscape.escapePath(toFile)); + byte[] bt = new byte[1024]; + int c; + while ((c = fosfrom.read(bt)) > 0) { + fosto.write(bt, 0, c); + } + return true; + } catch (Exception ex) { + return false; + } + } + + /** + * 文件拷贝 + * + * @param fromFile + * @param toFile + * @param fileName + * @return + */ + public static boolean copyFile(String fromFile, String toFile, String fileName) { + try { + //目标目录 + File targetDir = new File(XSSEscape.escapePath(toFile)); + //创建目录 + if (!targetDir.exists()) { + targetDir.mkdirs(); + } + @Cleanup InputStream fosfrom = new FileInputStream(fromFile); + @Cleanup OutputStream fosto = new FileOutputStream(toFile + fileName); + byte[] bt = new byte[1024]; + int c; + while ((c = fosfrom.read(bt)) > 0) { + fosto.write(bt, 0, c); + } + return true; + } catch (Exception ex) { + return false; + } + } + + /** + * 获取文件输入流 + */ + public static InputStream readFileToInputStream(String path) { + InputStream inputStream = null; + try { + File file = new File(XSSEscape.escapePath(path)); + inputStream = new FileInputStream(file); + } catch (IOException e) { + e.getMessage(); + } + return inputStream; + } + + /** + * 保存文件 + * + * @param inputStream + * @param path + * @param fileName + */ + public static void write(InputStream inputStream, String path, String fileName) { + OutputStream os = null; + long dateStr = System.currentTimeMillis(); + try { + // 1K的数据缓冲 + byte[] bs = new byte[1024]; + // 读取到的数据长度 + int len; + // 输出的文件流保存到本地文件 + File tempFile = new File(XSSEscape.escapePath(path)); + if (!tempFile.exists()) { + tempFile.mkdirs(); + } + String newFileName = tempFile.getPath() + File.separator + fileName; + log.info("保存文件:" + newFileName); + os = new FileOutputStream(XSSEscape.escapePath(newFileName)); + // 开始读取 + while ((len = inputStream.read(bs)) != -1) { + os.write(bs, 0, len); + } + } catch (IOException e) { + log.error("生成excel失败"); + } catch (Exception e) { + log.error("生成excel失败"); + } finally { + // 完毕,关闭所有链接 + try { + if (os != null) { + os.close(); + } + inputStream.close(); + } catch (IOException e) { + log.error("关闭链接失败" + e.getMessage()); + } + } + } + + /** + * 写入文件 + * + * @param inputStream + * @param path + * @param fileName + */ + public static void writeFile(InputStream inputStream, String path, String fileName) { + OutputStream os = null; + try { + // 1K的数据缓冲 + byte[] bs = new byte[1024]; + // 读取到的数据长度 + int len; + // 输出的文件流保存到本地文件 + File tempFile = new File(XSSEscape.escapePath(path)); + if (!tempFile.exists()) { + tempFile.mkdirs(); + } + String newFileName = tempFile.getPath() + File.separator + fileName; + log.info("保存文件:" + newFileName); + os = new FileOutputStream(XSSEscape.escapePath(newFileName)); + // 开始读取 + while ((len = inputStream.read(bs)) != -1) { + os.write(bs, 0, len); + } + } catch (IOException e) { + log.error("生成excel失败"); + } catch (Exception e) { + log.error("生成excel失败"); + } finally { + // 完毕,关闭所有链接 + try { + if (os != null) { + os.close(); + } + inputStream.close(); + } catch (IOException e) { + log.error("关闭链接失败" + e.getMessage()); + } + } + } + + /** + * 上传文件 + * + * @param file 文件 + * @param filePath 保存路径 + * @param fileName 保存名称 + */ + public static void upFile(MultipartFile file, String filePath, String fileName) { + try { + // 输出的文件流保存到本地文件 + File tempFile = new File(XSSEscape.escapePath(filePath)); + if (!tempFile.exists()) { + tempFile.mkdirs(); + } + File f = new File(filePath, fileName); + //将上传的文件存储到指定位置 + file.transferTo(f); + } catch (Exception e) { + log.error(e.getMessage()); + } + } + + /** + * 读取文件修改时间 + */ + public static String getCreateTime(String filePath) { + DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + File file = new File(XSSEscape.escapePath(filePath)); + // 毫秒数 + long modifiedTime = file.lastModified(); + // 通过毫秒数构造日期 即可将毫秒数转换为日期 + Date date = new Date(modifiedTime); + String dateString = format.format(date); + return dateString; + } + + /** + * 获取文件类型 + */ + public static String getFileType(File file) { + if (file.isFile()) { + String fileName = file.getName(); + String fileTyle = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()); + return fileTyle; + } + return null; + } + + /** + * 获取文件类型 + */ + public static String getFileType(String fileName) { + int lastIndexOf = fileName.lastIndexOf(".") + 1; + //获取文件的后缀名 jpg + String suffix = fileName.substring(lastIndexOf); + return suffix; + } + + /** + * 获取文件大小 + * + * @param data + * @return + */ + public static String getSize(String data) { + String size = ""; + if (data != null && !StringUtil.isEmpty(data)) { + long fileS = Long.parseLong(data); + DecimalFormat df = new DecimalFormat("#.00"); + if (fileS < 1024) { + size = df.format((double) fileS) + "BT"; + } else if (fileS < 1048576) { + size = df.format((double) fileS / 1024) + "KB"; + } else if (fileS < 1073741824) { + size = df.format((double) fileS / 1048576) + "MB"; + } else { + size = df.format((double) fileS / 1073741824) + "GB"; + } + } else { + size = "0BT"; + } + return size; + } + + private static final int BUFFER_SIZE = 2 * 1024; + + /** + * 压缩文件夹 + * + * @param srcDir 压缩文件夹路径 + * @param outDir 压缩文件路径 + * @param keepDirStructure 是否保留原来的目录结构, + * true:保留目录结构; + * false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败) + * @throws RuntimeException 压缩失败会抛出运行时异常 + */ + public static void toZip(String outDir, boolean keepDirStructure, String... srcDir) { + try { + @Cleanup OutputStream out = new FileOutputStream(new File(XSSEscape.escapePath(outDir))); + @Cleanup ZipOutputStream zos = null; + try { + zos = new ZipOutputStream(out); + List sourceFileList = new ArrayList(); + for (String dir : srcDir) { + File sourceFile = new File(XSSEscape.escapePath(dir)); + sourceFileList.add(sourceFile); + } + compress(sourceFileList, zos, keepDirStructure); + } catch (Exception e) { + throw new RuntimeException("zip error from ZipUtils", e); + } + } catch (Exception e) { + log.error("压缩失败:{}", e.getMessage()); + } + } + + /** + * 递归压缩方法 + * + * @param sourceFile 源文件 + * @param zos zip输出流 + * @param name 压缩后的名称 + * @param keepDirStructure 是否保留原来的目录结构, + * true:保留目录结构; + * false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败) + * @throws Exception + */ + private static void compress(File sourceFile, ZipOutputStream zos, String name, boolean keepDirStructure) throws Exception { + byte[] buf = new byte[BUFFER_SIZE]; + if (sourceFile.isFile()) { + zos.putNextEntry(new ZipEntry(name)); + int len; + @Cleanup FileInputStream in = new FileInputStream(sourceFile); + while ((len = in.read(buf)) != -1) { + zos.write(buf, 0, len); + } + zos.closeEntry(); + in.close(); + } else { + File[] listFiles = sourceFile.listFiles(); + if (listFiles == null || listFiles.length == 0) { + if (keepDirStructure) { + zos.putNextEntry(new ZipEntry(name + "/")); + zos.closeEntry(); + } + } else { + for (File file : listFiles) { + if (keepDirStructure) { + compress(file, zos, name + "/" + file.getName(), + keepDirStructure); + } else { + compress(file, zos, file.getName(), keepDirStructure); + } + } + } + } + } + + private static void compress(List sourceFileList, ZipOutputStream zos, boolean keepDirStructure) throws Exception { + byte[] buf = new byte[BUFFER_SIZE]; + for (File sourceFile : sourceFileList) { + String name = sourceFile.getName(); + if (sourceFile.isFile()) { + zos.putNextEntry(new ZipEntry(name)); + int len; + @Cleanup FileInputStream in = new FileInputStream(sourceFile); + while ((len = in.read(buf)) != -1) { + zos.write(buf, 0, len); + } + zos.closeEntry(); + in.close(); + } else { + File[] listFiles = sourceFile.listFiles(); + if (listFiles == null || listFiles.length == 0) { + if (keepDirStructure) { + zos.putNextEntry(new ZipEntry(name + "/")); + zos.closeEntry(); + } + } else { + for (File file : listFiles) { + if (keepDirStructure) { + compress(file, zos, name + "/" + file.getName(), + keepDirStructure); + } else { + compress(file, zos, file.getName(), + keepDirStructure); + } + + } + } + } + } + } + + //=================================判断文件后缀========================== + + /** + * 允许文件类型 + * + * @param fileType 文件所有类型 + * @param fileExtension 当前文件类型 + * @return + */ + public static boolean fileType(String fileType, String fileExtension) { + String[] allowExtension = fileType.split(","); + return Arrays.asList(allowExtension).contains(fileExtension.toLowerCase()); + } + + /** + * 允许图片类型 + * + * @param imageType 图片所有类型 + * @param fileExtension 当前图片类型 + * @return + */ + public static boolean imageType(String imageType, String fileExtension) { + String[] allowExtension = imageType.split(","); + return Arrays.asList(allowExtension).contains(fileExtension.toLowerCase()); + } + + /** + * 允许上传大小 + * + * @param fileSize 文件大小 + * @param maxSize 最大的文件 + * @return + */ + public static boolean fileSize(Long fileSize, int maxSize) { + if (fileSize > maxSize) { + return true; + } + return false; + } + + /** + * 导入生成临时文件后,获取文件内容 + * + * @param multipartFile 文件 + * @param filePath 路径 + * @return + */ + public static String getFileContent(MultipartFile multipartFile, String filePath) { + //文件名 + String fileName = multipartFile.getName(); + //上传到项目文件路径中 + FileUtil.upFile(multipartFile, filePath, fileName); + //读取文件文件内容 + String fileContent = FileUtil.getString(filePath, fileName); + return fileContent; + } + + /** + * 导入生成临时文件后,获取文件内容 + * + * @param multipartFile 文件 + * @return + */ + public static String getFileContent(MultipartFile multipartFile) { + StringBuffer content = new StringBuffer(); + try { + @Cleanup InputStream is = multipartFile.getInputStream(); + @Cleanup InputStreamReader isReader = new InputStreamReader(is, GlobalConst.DEFAULT_CHARSET); + @Cleanup BufferedReader br = new BufferedReader(isReader); + //循环逐行读取 + while (br.ready()) { + content.append(br.readLine()); + } + } catch (IOException e) { + log.error(e.getMessage()); + } + return content.toString(); + } + + + /** + * 判断是否为json格式且不为空 + * @param multipartFile + * @param type 类型 + * @return + */ + public static boolean existsSuffix(MultipartFile multipartFile, String type) { + if (!multipartFile.getOriginalFilename().endsWith("." + type) || multipartFile.getSize()<1){ + return true; + } + return false; + } + + /** + * File转MultipartFile + * + * @param file + * @return + */ + public static MultipartFile createFileItem(File file) { + FileItemFactory factory = new DiskFileItemFactory(16, null); + FileItem item = factory.createItem("textField", "text/plain", true, file.getName()); + int bytesRead = 0; + byte[] buffer = new byte[8192]; + try { + @Cleanup FileInputStream fis = new FileInputStream(file); + OutputStream os = item.getOutputStream(); + while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) { + os.write(buffer, 0, bytesRead); + } + os.close(); + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + MultipartFile multipartFile = new MyStandardMultipartFile(new ApplicationPart(item, null), file.getName()); + return multipartFile; + } + + /** + * MultipartFile 转 File + * + * @param file + * @throws Exception + */ + public static File multipartFileToFile(MultipartFile file) { + File toFile = null; + if (file.getSize() > 0) { + InputStream ins = null; + try { + ins = file.getInputStream(); + toFile = new File(file.getOriginalFilename()); + //获取流文件 + try { + @Cleanup OutputStream os = new FileOutputStream(toFile); + int bytesRead = 0; + byte[] buffer = new byte[8192]; + while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) { + os.write(buffer, 0, bytesRead); + } + os.close(); + ins.close(); + } catch (Exception e) { + e.printStackTrace(); + } + ins.close(); + } catch (Exception e) { + log.error(e.getMessage()); + } + } + return toFile; + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/FlowFormConstant.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/FlowFormConstant.java new file mode 100644 index 0000000..c05ce3b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/FlowFormConstant.java @@ -0,0 +1,17 @@ +package com.yunzhupaas.util; + +/** + * 流程设计 + * + * @author 云筑产品开发平台组 + * @version V3.4.2 + * @copyright 深圳市乐程软件有限公司 + * @date 2023/1/30 10:37:12 + */ +public class FlowFormConstant { + public static final String FLOWID = "flowId"; + public static final String FLOW_STATE = "flowState"; + public static final String FLOWTASKID = "flowTaskId"; + public static final String ID = "id"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/IpUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/IpUtil.java new file mode 100644 index 0000000..59a39ba --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/IpUtil.java @@ -0,0 +1,216 @@ +package com.yunzhupaas.util; + +import com.alibaba.fastjson.JSONObject; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Slf4j +public class IpUtil { + + /** + * 检测ip信息的网站 + */ + private final static String IP_URL = "https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query={ip}&resource_id=6006"; + /** + * IP的正则 + */ + private static Pattern pattern = Pattern + .compile("(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\." + + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\." + + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\." + + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})"); + + /** + * 内网IP + * + * @return + */ + private static List ipFilterRegexList = new ArrayList<>(); + static { + Set ipFilter = new HashSet(); + ipFilter.add("^10\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[0-9])" + + "\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[0-9])" + "\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[0-9])$"); + // B类地址范围: 172.16.0.0---172.31.255.255 + ipFilter.add("^172\\.(1[6789]|2[0-9]|3[01])\\" + ".(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[0-9])\\" + + ".(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[0-9])$"); + // C类地址范围: 192.168.0.0---192.168.255.255 + ipFilter.add("^192\\.168\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[0-9])\\" + + ".(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[0-9])$"); + ipFilter.add("127.0.0.1"); + ipFilter.add("0.0.0.0"); + ipFilter.add("localhost"); + for (String tmp : ipFilter) { + ipFilterRegexList.add(Pattern.compile(tmp)); + } + } + + public static String getIpAddr() { + HttpServletRequest request = ServletUtil.getRequest(); + if(request == null){ + //任务调度调用数据接口, 无法获取IP + return "127.0.0.1"; + } + String xIp = request.getHeader("X-Real-IP"); + String xFor = request.getHeader("X-Forwarded-For"); + if (StringUtil.isNotEmpty(xFor) && !"unKnown".equalsIgnoreCase(xFor)) { + int index = xFor.indexOf(","); + if (index != -1) { + return xFor.substring(0, index); + } else { + return xFor; + } + } + xFor = xIp; + if (StringUtil.isNotEmpty(xFor) && !"unKnown".equalsIgnoreCase(xFor)) { + return xFor; + } + if (StringUtil.isBlank(xFor) || "unknown".equalsIgnoreCase(xFor)) { + xFor = request.getHeader("Proxy-Client-IP"); + } + if (StringUtil.isBlank(xFor) || "unknown".equalsIgnoreCase(xFor)) { + xFor = request.getHeader("WL-Proxy-Client-IP"); + } + if (StringUtil.isBlank(xFor) || "unknown".equalsIgnoreCase(xFor)) { + xFor = request.getHeader("HTTP_CLIENT_IP"); + } + if (StringUtil.isBlank(xFor) || "unknown".equalsIgnoreCase(xFor)) { + xFor = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (StringUtil.isBlank(xFor) || "unknown".equalsIgnoreCase(xFor)) { + xFor = request.getRemoteAddr(); + } + String ip = "0:0:0:0:0:0:0:1".equals(xFor) ? "127.0.0.1" : xFor; + return ip; + } + + /** + * 检查IP是否合法 + * + * @param ip + * @return + */ + public static boolean isValid(String ip) { + Matcher m = pattern.matcher(ip); + return m.matches(); + } + + /** + * 获取ip信息 + */ + private static JSONObject getIpInfo(String ip) { + JSONObject data = null; + if (!ipIsInner(ip)) { + long begin = System.currentTimeMillis(); + try { + String ipUrl = IP_URL.replace("{ip}", ip); + URL url = new URL(ipUrl); + HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection(); + httpUrlConnection.setRequestMethod("GET"); + httpUrlConnection.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); + httpUrlConnection.setDoInput(true); + httpUrlConnection.setDoOutput(true); + httpUrlConnection.setReadTimeout(5000); + InputStream inputStream = httpUrlConnection.getInputStream(); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int len = 0; + while (true) { + len = inputStream.read(b); + if (len == -1) { + break; + } + byteArrayOutputStream.write(b, 0, len); + } + long end = System.currentTimeMillis() - begin; + byte[] lens = byteArrayOutputStream.toByteArray(); + String result = new String(lens, "GBK"); + data = JSONObject.parseObject(result); + if (null == data) { + return data; + } + data = JSONObject.parseObject(data.getJSONArray("data").get(0).toString()); + } catch (Exception e) { + log.error("ip信息获取失败,请检查ip接口工具IPUtil。"); + } + } + + return data; + } + + /** + * 获取ip所在的城市和宽带属于哪一家 + */ + public static String getIpCity(String ip) { + String ipInfo = null; + if (ip != null) { + JSONObject[] data = {null}; + Callable task = new Callable() { + @Override + public JSONObject call() throws Exception { + data[0] = getIpInfo(ip); + return data[0]; + } + }; + Future future = ThreadPoolExecutorUtil.getExecutor().submit(task); + try { + //设置超时时间 + future.get(5, TimeUnit.SECONDS); + } catch (TimeoutException e) { + log.error("ip信息获取超时"); + } catch (Exception e) { + log.error("ip信息获取错误:" + e.getMessage()); + } + if (null == data[0]) { + if ("127.0.0.1".equals(ip) || "localhost".equals(ip)) { + ipInfo = "本地连接"; + }else { + ipInfo = "本地局域网"; + } + return ipInfo; + } + ipInfo = data[0].getString("location"); + return ipInfo; + } + return ipInfo; + } + + /** + * 判断IP是否内网IP + * @Title: ipIsInner + * @param ip + * @return: boolean + */ + public static boolean ipIsInner(String ip) { + boolean isInnerIp = false; + for (Pattern tmp : ipFilterRegexList) { + Matcher matcher = tmp.matcher(ip); + if (matcher.find()) { + isInnerIp = true; + break; + } + } + return isInnerIp; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/JScriptUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/JScriptUtil.java new file mode 100644 index 0000000..ca4f3e8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/JScriptUtil.java @@ -0,0 +1,100 @@ +package com.yunzhupaas.util; + +import com.yunzhupaas.util.JsonUtil; +import com.yunzhupaas.util.StringUtil; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import java.util.List; +import java.util.Map; + +/** + * Java执行js代码工具类 + * + * @author :云筑产品开发平台组 + * @version: V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date :2022/5/28 9:44 + */ +public class JScriptUtil { + + /** + * 数据接口通用定义函数 + */ + public static final String JSCONTENT = "var method = function(data) {" + + "${jsContent}" + + "};" + + "var result = method(${data});" + + "if(typeof(result)=='object'){JSON.stringify(result);}else{result;};;"; + + /** + * 调用js代码 + * @param script 脚本内容 + * @return 如果JS内返回的是对象 返回内容为ScriptObjectMirror + * @throws ScriptException + */ + public static Object callJs(String script) throws ScriptException { + ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); + ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("js"); + return scriptEngine.eval(script); + } + + + /** + * 调用js代码, 处理JSON数据 返回JSON数据 + * + * @param dataProcessing 数据处理函数 + * @param data JSON对象/数组 + * @return JSON对象/数组 + */ + public static Object callJs(String dataProcessing, Object data) throws ScriptException { + String jsContent = getJsContent(dataProcessing); + if (StringUtil.isEmpty(dataProcessing)) { + return data; + } + String replace = JSCONTENT.replace("${jsContent}", jsContent); + replace = replace.replace("${data}", JsonUtil.getObjectToString(data)); + Object result = null; + try { + result = callJs(replace); + } catch (Exception e) { + throw e; + } + try { + List> jsonToListMap = JsonUtil.getJsonToListMap(result.toString()); + return jsonToListMap; + } catch (Exception e) { + try { + Map map = JsonUtil.stringToMap(result.toString()); + return map; + } catch (Exception ee) { + return result; + } + } + } + + /** + * 返回js内容 + * + * @param dataProcessing + * @return + */ + public static String getJsContent(String dataProcessing) { + if (StringUtil.isNotEmpty(dataProcessing) && dataProcessing.length() > 0) { + // 获取位置 + int indexOf = dataProcessing.indexOf("{"); + if (indexOf > -1) { + dataProcessing = dataProcessing.substring(indexOf + 1); + } + int lastIndexOf = dataProcessing.lastIndexOf("}"); + if (lastIndexOf > -1) { + dataProcessing = dataProcessing.substring(0, lastIndexOf); + } + return dataProcessing; + } + return ""; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/JsonUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/JsonUtil.java new file mode 100644 index 0000000..f5aef75 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/JsonUtil.java @@ -0,0 +1,201 @@ +package com.yunzhupaas.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.exception.DataException; + +import java.util.List; +import java.util.Map; + +/** + * JSON转换工具类 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-09-26 上午9:18 + */ +public class JsonUtil { + + /** + * list 转成 JSONField + * + * @param lists + * @return + */ + public static List listToJsonField(List lists) { + // 空的也显示 + String jsonStr = JSONArray.toJSONString(lists, SerializerFeature.WriteMapNullValue); + // 空的不显示 + List list = JSONArray.parseObject(jsonStr, List.class); + return list; + } + + /** + * 对象转成Map + * + * @param object + * @return + */ + public static Map entityToMap(Object object) { + String jsonStr = JSONObject.toJSONString(object); + Map map = JSONObject.parseObject(jsonStr, new TypeReference>() { + }); + return map; + } + + public static Map entityToMaps(Object object) { + String jsonStr = JSONObject.toJSONString(object); + Map map = JSONObject.parseObject(jsonStr, new TypeReference>() { + }); + return map; + } + + /** + * String转成Map + * + * @param object + * @return + */ + public static Map stringToMap(String object) { + Map map = JSONObject.parseObject(object, new TypeReference>() { + }); + return map; + } + + /** + * 功能描述:把JSON数据转换成指定的java对象 + * + * @param jsonData JSON数据 + * @param clazz 指定的java对象 + * @return 指定的java对象 + */ + public static T getJsonToBean(String jsonData, Class clazz) { + return JSON.parseObject(jsonData, clazz); + } + + /** + * 功能描述:把JSON数据转换成JSONArray数据 + * + * @param json + * @return + */ + public static JSONArray getJsonToJsonArray(String json) { + return JSONArray.parseArray(json); + } + + /** + * 功能描述:把List数据转换成JSONArray数据 + * + * @param list + * @param + * @return + */ + public static JSONArray getListToJsonArray(List list) { + return JSONArray.parseArray(JsonUtil.getObjectToString(list)); + } + + /** + * 功能描述:把java对象转换成JSON数据 + * + * @param object java对象 + * @return JSON数据 + */ + public static String getObjectToString(Object object) { + return JSON.toJSONString(object, SerializerFeature.WriteMapNullValue); + } + + /** + * 功能描述:把java对象转换成JSON数据 + * + * @param object java对象 + * @return JSON数据 + */ + public static String getObjectToStringAsDate(Object object) { + return JSON.toJSONStringWithDateFormat(object, "yyy-MM-dd HH:mm:ss"); + } + + /** + * 功能描述:把java对象转换成JSON数据,时间格式化 + * + * @param object java对象 + * @return JSON数据 + */ + public static String getObjectToStringDateFormat(Object object, String dateFormat) { + return JSON.toJSONStringWithDateFormat(object, dateFormat, SerializerFeature.WriteMapNullValue); + } + + /** + * 功能描述:把JSON数据转换成指定的java对象 + * + * @param dto dto对象 + * @param clazz 指定的java对象 + * @return 指定的java对象 + */ + public static T getJsonToBeanEx(Object dto, Class clazz) throws DataException { + if (dto == null) { + throw new DataException(MsgCode.FA001.get()); + } + return JSON.parseObject(getObjectToString(dto), clazz); + } + + /** + * 功能描述:把JSON数据转换成指定的java对象列表 + * + * @param jsonData JSON数据 + * @param clazz 指定的java对象 + * @return List + */ + public static List getJsonToList(String jsonData, Class clazz) { + return JSON.parseArray(jsonData, clazz); + } + + /** + * 功能描述:把JSON数据转换成较为复杂的List> + * + * @param jsonData JSON数据 + * @return List> + */ + public static List> getJsonToListMap(String jsonData) { + return JSON.parseObject(jsonData, new TypeReference>>() { + }); + } + + /** + * 功能描述:把JSONArray数据转换成较为复杂的List> + * + * @param jsonArray JSONArray数据 + * @return List> + */ + public static List> getJsonToList(JSONArray jsonArray) { + return JSON.parseObject(JSON.toJSONString(jsonArray), new TypeReference>>() { + }); + } + + /** + * 功能描述:把JSON数据转换成指定的java对象 + * + * @param dto dto对象 + * @param clazz 指定的java对象 + * @return 指定的java对象 + */ + public static T getJsonToBean(Object dto, Class clazz) { + return JSON.parseObject(getObjectToString(dto), clazz); + } + + /** + * 功能描述:把JSON数据转换成指定的java对象列表 + * + * @param dto dto对象 + * @param clazz 指定的java对象 + * @return List + */ + public static List getJsonToList(Object dto, Class clazz) { + return JSON.parseArray(getObjectToString(dto), clazz); + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/JsonUtilEx.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/JsonUtilEx.java new file mode 100644 index 0000000..6b1f388 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/JsonUtilEx.java @@ -0,0 +1,79 @@ +package com.yunzhupaas.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.exception.DataException; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +public class JsonUtilEx { + + + /** + * 功能描述:把java对象转换成JSON数据,时间格式化 + * @param object java对象 + * @return JSON数据 + */ + public static String getObjectToStringDateFormat(Object object,String dateFormat) { + return JSON.toJSONStringWithDateFormat(object, dateFormat,SerializerFeature.WriteMapNullValue); + } + +// /** +// * 功能描述:把JSON数据转换成指定的java对象列表 +// * @param jsonData JSON数据 +// * @param clazz 指定的java对象 +// * @return List +// */ +// public static List getJsonToListStringDateFormat(String jsonData, Class clazz,String dateFormat) { +// JSONArray jsonArray=JSONUtil.getJsonToJsonArray(jsonData); +// JSONArray newJsonArray=JSONUtil.getJsonToJsonArray(jsonData); +// for (int i = 0; i < jsonArray.size(); i++) { +// JSONObject jsonObject = jsonArray.getJSONObject(i); +// newJsonArray.add(JSON.toJSONStringWithDateFormat(jsonObject, dateFormat,SerializerFeature.WriteMapNullValue)); +// } +// jsonData=JSONUtil.getObjectToString(newJsonArray); +// return JSON.parseArray(jsonData, clazz); +// } +// +// public static void main(String[] args) { +// Date date=new Date(); +// String obk="[" + +// "{\"date\":\""+date+"\"},{\"date\":\"1603165505\"}" + +// "]"; +// List list1= getJsonToList(obk,String.class); +// List list11= getJsonToListStringDateFormat(obk,String.class,"yyyy-MM-dd"); +// System.out.println("aaa"); +// } + + + /** + * 功能描述:把java对象转换成JSON数据 + * @param object java对象 + * @return JSON数据 + */ + public static String getObjectToString(Object object) { + return JSON.toJSONString(object, SerializerFeature.WriteMapNullValue); + } + + /** + * 功能描述:把JSON数据转换成指定的java对象 + * @param dto dto对象 + * @param clazz 指定的java对象 + * @return 指定的java对象 + */ + public static T getJsonToBeanEx(Object dto, Class clazz) throws DataException { + if(dto==null){ + throw new DataException(MsgCode.FA001.get()); + } + return JSON.parseObject(getObjectToString(dto), clazz); + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/LockObjectUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/LockObjectUtil.java new file mode 100644 index 0000000..598152a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/LockObjectUtil.java @@ -0,0 +1,27 @@ +package com.yunzhupaas.util; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/11/30 21:17 + */ +public class LockObjectUtil { + + private static Map lockMap = new HashMap<>(); + + public static synchronized Object addLockKey(Object key){ + Object val = lockMap.get(key); + if(val == null){ + lockMap.put(key, key); + val = key; + } + return val; + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/Md5Util.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/Md5Util.java new file mode 100644 index 0000000..8d93167 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/Md5Util.java @@ -0,0 +1,115 @@ +package com.yunzhupaas.util; + +import lombok.Cleanup; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +public class Md5Util { + /** + * 默认的密码字符串组合,用来将字节转换成 16 进制表示的字符,Apache校验下载的文件的正确性用的就是默认的这个组合 + */ + protected static char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e','f' }; + protected static MessageDigest messagedigest = null; + static { + try { + messagedigest = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } + + /** + * 获取文件MD5值 + * @param file + * @return + * @throws IOException + */ + public static String getFileMd5String(File file) throws IOException { + @Cleanup InputStream fis = new FileInputStream(file); + byte[] buffer = new byte[1024]; + int numRead = 0; + while ((numRead = fis.read(buffer)) > 0) { + messagedigest.update(buffer, 0, numRead); + } + fis.close(); + return bufferToHex(messagedigest.digest()); + } + + /** + * 密码字符串MD5加密 32位小写 + * @param str + * @return + */ + public static String getStringMd5(String str) { + //MessageDigest是线程不安全的,新建实例保证不出错 + MessageDigest messagedigest; + try { + messagedigest = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + if (StringUtil.isEmpty(str)) { + return ""; + } + byte[] buffer = str.getBytes(); + messagedigest.update(buffer); + return bufferToHex(messagedigest.digest()); + } + + public static String bufferToHex(byte[] bytes) { + return bufferToHex(bytes, 0, bytes.length); + } + + private static String bufferToHex(byte[] bytes, int m, int n) { + StringBuffer stringbuffer = new StringBuffer(2 * n); + int k = m + n; + for (int l = m; l < k; l++) { + appendHexPair(bytes[l], stringbuffer); + } + return stringbuffer.toString(); + } + + private static void appendHexPair(byte bt, StringBuffer stringbuffer) { + char c0 = hexDigits[(bt & 0xf0) >> 4]; + char c1 = hexDigits[bt & 0xf]; + stringbuffer.append(c0); + stringbuffer.append(c1); + } + + private static final String toHex(byte[] hash) { + if (hash == null) { + return null; + } + StringBuffer buf = new StringBuffer(hash.length * 2); + int i; + + for (i = 0; i < hash.length; i++) { + if ((hash[i] & 0xff) < 0x10) { + buf.append("0"); + } + buf.append(Long.toString(hash[i] & 0xff, 16)); + } + return buf.toString(); + } + + public static String hash(String s) { + try { + return new String(toHex(getStringMd5(s).getBytes(Constants.UTF8)).getBytes(Constants.UTF8), Constants.UTF8); + } catch (Exception e) { + return s; + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/NoDataSourceBind.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/NoDataSourceBind.java new file mode 100644 index 0000000..d799f40 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/NoDataSourceBind.java @@ -0,0 +1,21 @@ +package com.yunzhupaas.util; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Target({ElementType.TYPE,ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface NoDataSourceBind { + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/OptimizeUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/OptimizeUtil.java new file mode 100644 index 0000000..586d935 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/OptimizeUtil.java @@ -0,0 +1,54 @@ +package com.yunzhupaas.util; + + +import java.util.Arrays; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +public class OptimizeUtil { + + /** + * 允许文件类型 + * + * @param fileType 文件所有类型 + * @param fileExtension 当前文件类型 + * @return + */ + public static boolean fileType(String fileType, String fileExtension) { + String[] allowExtension = fileType.split(","); + return Arrays.asList(allowExtension).contains(fileExtension.toLowerCase()); + } + + /** + * 允许图片类型 + * + * @param imageType 图片所有类型 + * @param fileExtension 当前图片类型 + * @return + */ + public static boolean imageType(String imageType, String fileExtension) { + String[] allowExtension = imageType.split(","); + return Arrays.asList(allowExtension).contains(fileExtension.toLowerCase()); + } + + /** + * 允许上传大小 + * + * @param fileSize 文件大小 + * @param maxSize 最大的文件 + * @return + */ + public static boolean fileSize(Long fileSize, int maxSize) { + if (fileSize > maxSize) { + return true; + } + return false; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PadUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PadUtil.java new file mode 100644 index 0000000..f7ba32a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PadUtil.java @@ -0,0 +1,52 @@ +package com.yunzhupaas.util; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +public class PadUtil { + + /** + * String左对齐 + * @param src + * @param len + * @param ch + * @return + */ + public static String padLeft(String src, int len, char ch) { + int diff = len - src.length(); + if (diff <= 0) { + return src; + } + char[] charr = new char[len]; + System.arraycopy(src.toCharArray(), 0, charr, 0, src.length()); + for (int i = src.length(); i < len; i++) { + charr[i] = ch; + } + return new String(charr); + } + + /** + * String右对齐 + * @param src + * @param len + * @param ch + * @return + */ + public static String padRight(String src, int len, char ch) { + int diff = len - src.length(); + if (diff <= 0) { + return src; + } + char[] charr = new char[len]; + System.arraycopy(src.toCharArray(), 0, charr, diff, src.length()); + for (int i = 0; i < diff; i++) { + charr[i] = ch; + } + return new String(charr); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PageUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PageUtil.java new file mode 100644 index 0000000..b2d097c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PageUtil.java @@ -0,0 +1,37 @@ +package com.yunzhupaas.util; + +import java.util.List; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +public class PageUtil { + /** + * 自定义分页 + * @param page + * @param pageSize + * @param list + * @return + */ + public static List getListPage(int page, int pageSize, List list) { + if (list == null || list.size() == 0) { + return list; + } + int totalCount = list.size(); + page = page - 1; + int fromIndex = page * pageSize; + if (fromIndex >= totalCount) { + return list; + } + int toIndex = ((page + 1) * pageSize); + if (toIndex > totalCount) { + toIndex = totalCount; + } + return list.subList(fromIndex, toIndex); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ParameterUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ParameterUtil.java new file mode 100644 index 0000000..fc9899e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ParameterUtil.java @@ -0,0 +1,134 @@ +package com.yunzhupaas.util; + +import com.yunzhupaas.constant.DbSensitiveConstant; + +import java.util.List; + +/** + * 短信参数解析 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-12-10 + */ +public class ParameterUtil { + + /** + * 获取参数 + * + * @param text 需要解析的文本 + * @param list 存放参数的集合 + * @return + */ + public static String parse(String openToken, String closeToken, String text, List list) { + if (text == null || text.isEmpty()) { + return ""; + } + // search open token + int start = text.indexOf(openToken); + if (start == -1) { + return text; + } + char[] src = text.toCharArray(); + int offset = 0; + final StringBuilder builder = new StringBuilder(); + StringBuilder expression = null; + while (start > -1) { + if (start > 0 && src[start - 1] == '\\') { + // this open token is escaped. remove the backslash and continue. + builder.append(src, offset, start - offset - 1).append(openToken); + offset = start + openToken.length(); + } else { + // found open token. let's search close token. + if (expression == null) { + expression = new StringBuilder(); + } else { + expression.setLength(0); + } + builder.append(src, offset, start - offset); + offset = start + openToken.length(); + int end = text.indexOf(closeToken, offset); + while (end > -1) { + if (end > offset && src[end - 1] == '\\') { + // this close token is escaped. remove the backslash and continue. + expression.append(src, offset, end - offset - 1).append(closeToken); + offset = end + closeToken.length(); + end = text.indexOf(closeToken, offset); + } else { + expression.append(src, offset, end - offset); + break; + } + } + // 塞到list中 + list.add(expression.toString()); + if (end == -1) { + // close token was not found. + builder.append(src, start, src.length - start); + offset = src.length; + } else { + offset = end + closeToken.length(); + } + } + start = text.indexOf(openToken, offset); + } + if (offset < src.length) { + builder.append(src, offset, src.length - offset); + } + return builder.toString(); + } + + /** + * 判断数据库类型 + * + * @param driverName 驱动名称 + * @return + */ + public static String getDbType(String driverName) { + if (StringUtil.isNotEmpty(driverName)) { + // 不是使用自定义URL + String dbType = ""; + if (driverName.contains("mysql")) { + dbType = "MySQL"; + } else if (driverName.contains("sqlserver")) { + dbType = "SQLServer"; + } else if (driverName.contains("oracle")) { + dbType = "Oracle"; + } else if (driverName.contains("dm")) { + dbType = "DM"; + } else if (driverName.contains("kingbase8")) { + dbType = "KingbaseES"; + } else if (driverName.contains("postgresql")) { + dbType = "PostgreSQL"; + } + return dbType; + } + return null; + } + + /** + * 检查是否含有关键字 + * + * @param sql + * @param sensitive + * @return + */ + public static String checkContainsSensitive(String sql, String sensitive) { + if (StringUtil.isNotEmpty(sql)) { + String[] split = sensitive.split(","); + for (String str : split) { + str = str.trim(); + String[] matchStr = new String[]{str + " ", str.trim() + "-"}; + for (String s : matchStr) { + boolean contains = sql.toUpperCase().contains(s); + if (contains) { + return str.trim(); + } + } + } + } + return ""; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PathUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PathUtil.java new file mode 100644 index 0000000..429c3d9 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PathUtil.java @@ -0,0 +1,26 @@ +package com.yunzhupaas.util; + +import org.springframework.util.AntPathMatcher; +import org.springframework.util.ObjectUtils; + +import java.util.List; + +/** + * URL匹配工具 + */ +public class PathUtil { + + private static AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher(); + + public static boolean isIgnorePath(String url, List ignoreUrls){ + if(ObjectUtils.isEmpty(url)){ + return true; + } + if(ObjectUtils.isEmpty(ignoreUrls)){ + return false; + } + return ignoreUrls.stream().anyMatch(u -> url.startsWith(u) || ANT_PATH_MATCHER.match(u, url)); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PinYinUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PinYinUtil.java new file mode 100644 index 0000000..628e4e2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/PinYinUtil.java @@ -0,0 +1,114 @@ +package com.yunzhupaas.util; + +import net.sourceforge.pinyin4j.PinyinHelper; +import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; +import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; +import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; +import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; +import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +public class PinYinUtil { + /** + * 将字符串中的中文转化为拼音,其他字符不变 + * + * @param inputString + * @return + */ + public static String getPingYin(String inputString) { + HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); + format.setCaseType(HanyuPinyinCaseType.LOWERCASE); + format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); + format.setVCharType(HanyuPinyinVCharType.WITH_V); + char[] input = inputString.trim().toCharArray(); + String output = ""; + try { + for (int i = 0; i < input.length; i++) { + if (Character.toString(input[i]).matches("[\\u4E00-\\u9FA5]+")) { + String[] temp = PinyinHelper.toHanyuPinyinStringArray(input[i], format); + output += temp[0]; + } else { + output += Character.toString(input[i]); + } + } + } catch (BadHanyuPinyinOutputFormatCombination e) { + e.printStackTrace(); + } + return output; + } + + /** + * 获取汉字串拼音首字母,英文字符不变 + * + * @param chinese + * 汉字串 + * @return 汉语拼音首字母 + */ + public static String getFirstSpell(String chinese) { + StringBuffer pybf = new StringBuffer(); + if(chinese==null){ + return null; + } + char[] arr = chinese.toCharArray(); + HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat(); + defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); + defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); + for (int i = 0; i < arr.length; i++) { + if (arr[i] > 128) { + try { + String[] temp = PinyinHelper.toHanyuPinyinStringArray(arr[i], defaultFormat); + if (temp != null) { + if (temp[0].length() > 0) { + pybf.append(temp[0].charAt(0)); + } else { + return null; + } + } + } catch (BadHanyuPinyinOutputFormatCombination e) { + e.printStackTrace(); + } + } else { + pybf.append(arr[i]); + } + } + return pybf.toString().replaceAll("\\W", "").trim(); + } + + /** + * 获取汉字串拼音,英文字符不变 + * + * @param chinese 汉字串 + * @return 汉语拼音 + */ + public static String getFullSpell(String chinese) { + StringBuffer pybf = new StringBuffer(); + char[] arr = chinese.toCharArray(); + HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat(); + defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); + defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); + for (int i = 0; i < arr.length; i++) { + if (arr[i] > 128) { + try { + String[] ca = PinyinHelper.toHanyuPinyinStringArray(arr[i], defaultFormat); + String temp = ca==null ? "" : ca[0]; + if(temp!=null){ + pybf.append(temp); + } + } catch (BadHanyuPinyinOutputFormatCombination e) { + e.printStackTrace(); + } + } else { + pybf.append(arr[i]); + } + } + return pybf.toString(); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/RandomUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/RandomUtil.java new file mode 100644 index 0000000..edff164 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/RandomUtil.java @@ -0,0 +1,81 @@ +package com.yunzhupaas.util; + +import com.github.yitter.contract.IdGeneratorOptions; +import com.github.yitter.idgen.YitIdHelper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Random; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:54 + */ +@Slf4j +@Component +public class RandomUtil { + + static { + IdGeneratorOptions options = new IdGeneratorOptions((short) 1); +// options.WorkerIdBitLength = 8; +// options.SeqBitLength = 4; + YitIdHelper.setIdGenerator(options); + } + + public static void main(String[] args) { + System.out.println(uuId()); + } + + /** + * 生成主键id + * + * @return + */ + public static String uuId() { + long newId = YitIdHelper.nextId(); + return newId + ""; + } + + /** + * 生成6位数随机英文 + * + * @return + */ + public static String enUuId() { + String str = ""; + for (int i = 0; i < 6; i++) { + //你想生bai成几个字符的,du就把3改成zhi几,dao如果改成1,那就生成一个1653随机字母. + str = str + (char) (Math.random() * 26 + 'a'); + } + return str; + } + + /** + * 生成排序编码 + * + * @return + */ + public static Long parses() { + Long time = 0L; + return time; + } + + /** + * 生成短信验证码 + * + * @return + */ + public static String getRandomCode() { + String code = ""; + Random rand = new Random(); + for (int i = 0; i < 6; i++) { + int ran = rand.nextInt(10); + code = code + ran; + } + return code; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ReflectionUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ReflectionUtil.java new file mode 100644 index 0000000..9e912ad --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ReflectionUtil.java @@ -0,0 +1,255 @@ +package com.yunzhupaas.util; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.Assert; + +import java.lang.reflect.*; + +/** + * 反射工具类 + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:56 + */ +@Slf4j +public class ReflectionUtil { + + /** 是否Debug模式 */ + private static boolean isDebug = false; + + /** + * 调用Getter方法. + */ + public static Object invokeGetterMethod(Object obj, String propertyName) { + String getterMethodName = "get" + StringUtil.capitalize(propertyName); + return invokeMethod(obj, getterMethodName, new Class[] {}, new Object[] {}); + } + + /** + * 调用Setter方法.使用value的Class来查找Setter方法. + */ + public static void invokeSetterMethod(Object obj, String propertyName, Object value) { + invokeSetterMethod(obj, propertyName, value, null); + } + + /** + * 调用Setter方法. + * + * @param propertyType 用于查找Setter方法,为空时使用value的Class替代. + */ + public static void invokeSetterMethod(Object obj, String propertyName, Object value, Class propertyType) { + Class type = propertyType != null ? propertyType : value.getClass(); + String setterMethodName = "set" + StringUtil.capitalize(propertyName); + invokeMethod(obj, setterMethodName, new Class[] { type }, new Object[] { value }); + } + + /** + * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数. + */ + public static Object getFieldValue(final Object obj, final String fieldName) { + Field field = getAccessibleField(obj, fieldName); + if (field == null) { + throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]"); + } + Object result = null; + try { + result = field.get(obj); + } catch (IllegalAccessException e) { + log.error("不可能抛出的异常{}", e); + } + return result; + } + + /** + * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. + */ + public static void setFieldValue(final Object obj, final String fieldName, final Object value) { + Field field = getAccessibleField(obj, fieldName); + if (field == null) { + throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]"); + } + try { + field.set(obj, value); + } catch (IllegalAccessException e) { + log.error("不可能抛出的异常:{}", e); + } + } + + /** + * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. + * + * 如向上转型到Object仍无法找到, 返回null. + */ + public static Field getAccessibleField(final Object obj, final String fieldName) { + Assert.notNull(obj, "object不能为空"); + Assert.hasText(fieldName, "fieldName"); + for (Class superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) { + try { + Field field = superClass.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException e) {// NOSONAR + // Field不在当前类定义,继续向上转型 + } + } + return null; + } + + /** + * 直接调用对象方法, 无视private/protected修饰符. 用于一次性调用的情况. + */ + public static Object invokeMethod(final Object obj, final String methodName, final Class[] parameterTypes, final Object[] args) { + Method method = getAccessibleMethod(obj, methodName, parameterTypes); + if (method == null) { + throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); + } + try { + return method.invoke(obj, args); + } catch (Exception e) { + throw convertReflectionExceptionToUnchecked(e); + } + } + + + + /** + * 系统调度使用!!! + * 直接调用对象方法, 无视private/protected修饰符. 用于一次性调用的情况. + */ + public static Boolean invokeMethodByTask(final Object obj, final String methodName, final Class[] parameterTypes, final Object[] args) { + Method method = getAccessibleMethod(obj, methodName, parameterTypes); + if (method == null) { + return false; + } + try { + method.invoke(obj, args); + return true; + } catch (Exception e) { + throw convertReflectionExceptionToUnchecked(e); + } + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. 如向上转型到Object仍无法找到, 返回null. + * + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + */ + public static Method getAccessibleMethod(final Object obj, final String methodName, final Class... parameterTypes) { + Assert.notNull(obj, "object不能为空"); + for (Class superClass = obj.getClass(); superClass != Object.class; superClass = superClass + .getSuperclass()) { + try { + Method method = superClass.getDeclaredMethod(methodName, parameterTypes); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) {// NOSONAR + // Method不在当前类定义,继续向上转型 + } + } + return null; + } + + /** + * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. 如无法找到, 返回Object.class. eg. public UserDao extends HibernateDao + * + * @param clazz + * The class to introspect + * @return the first generic declaration, or Object.class if cannot be determined + */ + @SuppressWarnings("unchecked") + public static Class getSuperClassGenricType(final Class clazz) { + return (Class) getSuperClassGenricType(clazz, 0); + } + + /** + * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. 如无法找到, 返回Object.class. + * + * 如public UserDao extends HibernateDao + * + * @param clazz + * clazz The class to introspect + * @param index + * the Index of the generic ddeclaration,start from 0. + * @return the index generic declaration, or Object.class if cannot be determined + */ + public static Class getSuperClassGenricType(final Class clazz, final int index) { + Type genType = clazz.getGenericSuperclass(); + if (!(genType instanceof ParameterizedType)) { + log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType"); + return Object.class; + } + Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); + if (index >= params.length || index < 0) { + log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + + params.length); + return Object.class; + } + if (!(params[index] instanceof Class)) { + log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); + return Object.class; + } + return (Class) params[index]; + } + + /** + * 将反射时的checked exception转换为unchecked exceptions. + */ + public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) { + if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException + || e instanceof NoSuchMethodException) { + return new IllegalArgumentException("Reflection com.yunzhupaas.exception.", e); + } else if (e instanceof InvocationTargetException) { + return new RuntimeException("Reflection com.yunzhupaas.exception.", ((InvocationTargetException) e).getTargetException()); + } else if (e instanceof RuntimeException) { + return (RuntimeException) e; + } + return new RuntimeException("Unexpected Checked com.yunzhupaas.exception.", e); + } + + /** + * 调用传入对象的toString方法或反射返回对象成员变量值字符串。 + * + * @param obj + * 传入对象 + * @return + * @author Lin Chenglin 2013-4-9 + */ + public static String toString(final Object obj) { + if (obj == null) { + return null; + } + if (obj.getClass() == Object.class || obj.getClass().isPrimitive()) { + return obj.toString(); + } + try { + Method method = obj.getClass().getDeclaredMethod("toString", new Class[] {}); + if (isDebug) { + log.debug("传入的对象实现了自己的toString方法,直接调用!"); + } + return (String) method.invoke(obj, new Object[] {}); + } catch (NoSuchMethodException e) { + if (isDebug) { + log.debug("传入的对象没有实现自己的toString方法,反射获取!"); + } + StringBuffer buf = new StringBuffer(obj.getClass().getName()); + buf.append(" ["); + // 获取所有成员变量 + Field[] fileds = obj.getClass().getDeclaredFields(); + int size = fileds.length; + for (int i = 0; i < size; i++) { + Field field = fileds[i]; + Object value = ReflectionUtil.getFieldValue(obj, field.getName()); + buf.append(field.getName() + "=" + ReflectionUtil.toString(value)); + if (i != size - 1) { + buf.append(", "); + } + } + buf.append("]"); + return buf.toString(); + } catch (Exception e) { + throw convertReflectionExceptionToUnchecked(e); + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/RegexUtils.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/RegexUtils.java new file mode 100644 index 0000000..22bfda9 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/RegexUtils.java @@ -0,0 +1,219 @@ +package com.yunzhupaas.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:55 + */ +public class RegexUtils { + /** + * 验证Email + * @param email email地址,格式:zhangsan@zuidaima.com,zhangsan@xxx.com.cn,xxx代表邮件服务商 + * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkEmail(String email) { + String regex = "\\w+@\\w+\\.[a-z]+(\\.[a-z]+)?"; + return Pattern.matches(regex, email); + } + + /** + * 验证身份证号码 + * @param idCard 居民身份证号码15位或18位,最后一位可能是数字或字母 + * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkIdCard(String idCard) { + String regex = "[1-9]\\d{13,16}[a-zA-Z0-9]{1}"; + return Pattern.matches(regex,idCard); + } + + /** + * 验证手机号码(支持国际格式,+86135xxxx...(中国内地),+00852137xxxx...(中国香港)) + * @param mobile 移动、联通、电信运营商的号码段 + *

移动的号段:134(0-8)、135、136、137、138、139、147(预计用于TD上网卡) + *、150、151、152、157(TD专用)、158、159、187(未启用)、188(TD专用)

+ *

联通的号段:130、131、132、155、156(世界风专用)、185(未启用)、186(3g)

+ *

电信的号段:133、153、180(未启用)、189

+ * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkMobile(String mobile) { + String regex = "(\\+\\d+)?1[345789]\\d{9}$"; + return Pattern.matches(regex,mobile); + } + + /** + * 验证固定电话号码 + * @param phone 电话号码,格式:国家(地区)电话代码 + 区号(城市代码) + 电话号码,如:+8602085588447 + *

国家(地区) 代码 :标识电话号码的国家(地区)的标准国家(地区)代码。它包含从 0 到 9 的一位或多位数字, + * 数字之后是空格分隔的国家(地区)代码。

+ *

区号(城市代码):这可能包含一个或多个从 0 到 9 的数字,地区或城市代码放在圆括号—— + * 对不使用地区或城市代码的国家(地区),则省略该组件。

+ *

电话号码:这包含从 0 到 9 的一个或多个数字

+ * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkPhone(String phone) { + String regex = "(\\+\\d+)?(\\d{3,4}\\-?)?\\d{7,8}$"; + return Pattern.matches(regex, phone); + } + + /** + * 验证整数(正整数和负整数) + * @param digit 一位或多位0-9之间的整数 + * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkDigit(String digit) { + String regex = "\\-?[1-9]\\d+"; + return Pattern.matches(regex,digit); + } + + /** + * 验证整数和浮点数(正负整数和正负浮点数) + * @param decimals 一位或多位0-9之间的浮点数,如:1.23,233.30 + * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkDecimals(String decimals) { + String regex = "\\-?[1-9]\\d+(\\.\\d+)?"; + return Pattern.matches(regex,decimals); + } + + /** + * 验证空白字符 + * @param blankSpace 空白字符,包括:空格、\t、\n、\r、\f、\x0B + * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkBlankSpace(String blankSpace) { + String regex = "\\s+"; + return Pattern.matches(regex,blankSpace); + } + + /** + * 验证中文 + * @param chinese 中文字符 + * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkChinese(String chinese) { + String regex = "^[\u4E00-\u9FA5]+$"; + return Pattern.matches(regex,chinese); + } + + /** + * 验证日期(年月日) + * @param birthday 日期,格式:1992-09-03,或1992.09.03 + * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkBirthday(String birthday) { + String regex = "[1-9]{4}([-./])\\d{1,2}\\1\\d{1,2}"; + return Pattern.matches(regex,birthday); + } + + /** + * 验证URL地址 + * @param url 格式:http://blog.csdn.net:80/xyang81/article/details/7705960? 或 http://www.csdn.net:80 + * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkUrl(String url) { + String regex = "(https?://(w{3}\\.)?)?\\w+\\.\\w+(\\.[a-zA-Z]+)*(:\\d{1,5})?(/\\w*)*(\\??(.+=.*)?(&.+=.*)?)?"; + return Pattern.matches(regex, url); + } + + /** + *
+     * 获取网址 URL 的一级域
+     * 
+ * + * @param url + * @return + */ + public static String getDomain(String url) { + String regex = "(?<=http://|\\.)[^.]*?\\.(com|cn|net|org|biz|info|cc|tv)"; + Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); +// 获取完整的域名 + Matcher matcher = p.matcher(url); + matcher.find(); + return matcher.group(); + } + /** + * 匹配中国邮政编码 + * @param postcode 邮政编码 + * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkPostcode(String postcode) { + String regex = "[1-9]\\d{5}"; + return Pattern.matches(regex, postcode); + } + + /** + * 匹配IP地址(简单匹配,格式,如:192.168.1.1,127.0.0.1,没有匹配IP段的大小) + * @param ipAddress IPv4标准地址 + * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkIpAddress(String ipAddress) { + String regex = "[1-9](\\d{1,2})?\\.(0|([1-9](\\d{1,2})?))\\.(0|([1-9](\\d{1,2})?))\\.(0|([1-9](\\d{1,2})?))"; + return Pattern.matches(regex, ipAddress); + } + + /** + * 验证整数和浮点数(正整数和正两位小数) + * @param decimals 整数或多位0-9之间的浮点数,如:1.23,233.30 + * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkDecimals2(String decimals) { + String regex = "^(([1-9]{1}\\d*)|([0]{1}))(\\.(\\d){0,2})?$"; + return Pattern.matches(regex,decimals); + } + + /** + * 验证是否为正整数 + * @param digit 一位或多位0-9之间的整数 + * @return 验证成功返回true,验证失败返回false + */ + public static boolean checkDigit2(String digit) { + String regex = "[1-9]\\d*"; + return Pattern.matches(regex,digit); + } + + /** + * 验证请假时间为0.5的倍数 + * @param leave + * @return + */ + public static boolean checkLeave(String leave){ + String regex = "^[1-9]\\d*\\.[5]$|0\\.[5]$||\\d\\.0|^[1-9]\\d*$"; + return Pattern.matches(regex,leave); + } + + /** + * 编码正则 + * 只能输入英文、数字和小数点且小数点不能放在首尾 + * @return + */ + public static boolean checkEnCode(String enCode){ + String regex = "[a-zA-Z0-9][a-zA-Z0-9.]*[a-zA-Z0-9]"; + return Pattern.matches(regex,enCode); + } + + /** + * 编码正则(翻译标记用) + * 只能输入字母、数字、点、横线和下划线,且以字母开头 + * @return + */ + public static boolean checkEnCode2(String enCode){ + String regex = "^[a-zA-Z][a-zA-Z0-9._-]*$"; + return Pattern.matches(regex,enCode); + } + + /** + * 名称和编码等使用 + * xxx不能含有特殊符号 + * @return + */ + public static boolean checkSpecoalSymbols(String enCode){ + String regex = "^([\u4e00-\u9fa5]|[a-zA-Z0-9])+$"; + return Pattern.matches(regex,enCode); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ServletUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ServletUtil.java new file mode 100644 index 0000000..8083ac5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ServletUtil.java @@ -0,0 +1,251 @@ +package com.yunzhupaas.util; + +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import com.yunzhupaas.constant.GlobalConst; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import java.io.IOException; +import java.util.Collections; +import java.util.Enumeration; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 客户端工具类 + * + * @author yunzhupaas + */ +public class ServletUtil { + + + private static AntPathMatcher matcher = new AntPathMatcher(); + + /** + * 获取request + */ + public static HttpServletRequest getRequest() { + try { + return getRequestAttributes().getRequest(); + } catch (Exception e) { + return null; + } + } + + public static String getHeader(String name) { + if (getRequest() != null) { + return getRequest().getHeader(name); + } + return null; + } + + + /** + * 判断是否是手机端登陆 + */ + public static boolean getIsMobileDevice() { + return isMobileDevice(ServletUtil.getUserAgent()); + } + + /** + * 判断是否是手机端登陆 + */ + public static boolean getIsMobileDevice(String userAgent) { + return isMobileDevice(userAgent); + } + + + /** + * 获取User-Agent + */ + public static String getUserAgent() { + return ServletUtil.getHeader("User-Agent"); + } + + /** + * 判断是否是移动设备 + * + * @param requestHeader + * @return + */ + public static boolean isMobileDevice(String requestHeader) { + UserAgent userAgent = UserAgentUtil.parse(requestHeader); + if (userAgent == null) { + return false; + } + return userAgent.isMobile(); + } + + /** + * 获取ServletPath + */ + public static String getServletPath() { + return ServletUtil.getRequest().getServletPath(); + } + + /** + * 获取response + */ + public static HttpServletResponse getResponse() { + try { + return getRequestAttributes().getResponse(); + } catch (Exception e) { + return null; + } + } + + /** + * 获取session + */ + public static HttpSession getSession() { + return getRequest().getSession(); + } + + public static ServletRequestAttributes getRequestAttributes() { + try { + RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); + return (ServletRequestAttributes) attributes; + } catch (Exception e) { + return null; + } + } + + public static Map getHeaders(HttpServletRequest request) { + Map map = new LinkedHashMap<>(); + Enumeration enumeration = request.getHeaderNames(); + if (enumeration != null) { + while (enumeration.hasMoreElements()) { + String key = enumeration.nextElement(); + String value = request.getHeader(key); + map.put(key, value); + } + } + return map; + } + + public static Map getParams(HttpServletRequest request) { + Map parameters = new LinkedHashMap<>(); + Enumeration parameterNames = request.getParameterNames(); + if (parameterNames != null) { + while (parameterNames.hasMoreElements()) { + String key = parameterNames.nextElement(); + if (key == null) { + continue; + } + parameters.put(key,request.getParameter(key)); + } + } + return parameters; + } + + /** + * 将字符串渲染到客户端 + * + * @param response 渲染对象 + * @param string 待渲染的字符串 + * @return null + */ + public static String renderString(HttpServletResponse response, String string) { + try { + response.setStatus(200); + response.setContentType("application/json"); + response.setCharacterEncoding("utf-8"); + response.getWriter().print(string); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 是否是Ajax异步请求 + * + * @param request + */ + public static boolean isAjaxRequest(HttpServletRequest request) { + String accept = request.getHeader("accept"); + if (accept != null && accept.indexOf("application/json") != -1) { + return true; + } + + String xRequestedWith = request.getHeader("X-Requested-With"); + if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) { + return true; + } + + String uri = request.getRequestURI(); + if (StringUtil.inStringIgnoreCase(uri, ".json", ".xml")) { + return true; + } + + String ajax = request.getParameter("__ajax"); + if (StringUtil.inStringIgnoreCase(ajax, "json", "xml")) { + return true; + } + return false; + } + + /** + * 获取URL中的path变量 + * + * @param pattern + * @param path + * @return + */ + public static Map getPathVariables(String pattern, String path) { + Map vars = null; + try { + if (!StringUtil.isEmpty(path)) { + vars = matcher.extractUriTemplateVariables(pattern, path); + } + } catch (Exception e) { + } + if (vars == null) { + vars = Collections.EMPTY_MAP; + } + return vars; + } + + + /** + * 获取当前访问地址中的path变量 + * + * @param pattern + * @return + */ + public static Map getPathVariables(String pattern) { + return getPathVariables(pattern, getServletPath()); + } + + public static String getRequestHost() { + HttpServletRequest request = getRequest(); + if (request != null) { + String host = request.getHeader(GlobalConst.HEADER_HOST); + if (StringUtil.isEmpty(host)) { + host = request.getHeader("X-Forwarded-Host"); + if (StringUtil.isNotEmpty(host)) { + int index = host.lastIndexOf(","); + if (index != -1) { + return host.substring(index); + } else { + return host; + } + } else { + host = request.getHeader("Host"); + } + } + if (StringUtil.isNotEmpty(host)) { + return host; + } + } + return StringUtil.EMPTY; + } +} + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/StringUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/StringUtil.java new file mode 100644 index 0000000..6903a45 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/StringUtil.java @@ -0,0 +1,500 @@ +package com.yunzhupaas.util; + +import com.yunzhupaas.util.text.StrFormatter; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static java.util.stream.Collectors.toList; + +/** + * 字符串工具类 + * + * @author yunzhupaas + */ +public class StringUtil extends org.apache.commons.lang3.StringUtils { + /** 空字符串 */ + public static final String NULLSTR = ""; + + /** 下划线 */ + public static final char SEPARATOR = '_'; + + /** 星号 */ + public static final String START = "*"; + + /** + * 获取参数不为空值 + * + * @param value defaultValue 要判断的value + * @return value 返回值 + */ + public static T nvl(T value, T defaultValue) { + return value != null ? value : defaultValue; + } + + /** + * * 判断一个Collection是否为空, 包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Collection coll) { + return isNull(coll) || coll.isEmpty(); + } + + /** + * * 判断一个Collection是否非空,包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Collection coll) { + return !isEmpty(coll); + } + + /** + * * 判断一个对象数组是否为空 + * + * @param objects 要判断的对象数组 + ** @return true:为空 false:非空 + */ + public static boolean isEmpty(Object[] objects) { + return isNull(objects) || (objects.length == 0); + } + + /** + * * 判断一个对象数组是否非空 + * + * @param objects 要判断的对象数组 + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Object[] objects) { + return !isEmpty(objects); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Map map) { + return isNull(map) || map.isEmpty(); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Map map) { + return !isEmpty(map); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) { + return isNull(str) || NULLSTR.equals(str.trim()); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + /** + * * 判断一个对象是否为空 + * + * @param object Object + * @return true:为空 false:非空 + */ + public static boolean isNull(Object object) { + return object == null; + } + + /** + * * 判断一个对象是否非空 + * + * @param object Object + * @return true:非空 false:空 + */ + public static boolean isNotNull(Object object) { + return !isNull(object); + } + + /** + * * 判断一个对象是否是数组类型(Java基本型别的数组) + * + * @param object 对象 + * @return true:是数组 false:不是数组 + */ + public static boolean isArray(Object object) { + return isNotNull(object) && object.getClass().isArray(); + } + + /** + * 去空格 + */ + public static String trim(String str) { + return (str == null ? "" : str.trim()); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) { + if (str == null) { + return NULLSTR; + } + + if (start < 0) { + start = str.length() + start; + } + + if (start < 0) { + start = 0; + } + if (start > str.length()) { + return NULLSTR; + } + + return str.substring(start); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) { + if (str == null) { + return NULLSTR; + } + + if (end < 0) { + end = str.length() + end; + } + if (start < 0) { + start = str.length() + start; + } + + if (end > str.length()) { + end = str.length(); + } + + if (start > end) { + return NULLSTR; + } + + if (start < 0) { + start = 0; + } + if (end < 0) { + end = 0; + } + + return str.substring(start, end); + } + + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param template 文本模板,被替换的部分用 {} 表示 + * @param params 参数值 + * @return 格式化后的文本 + */ + public static String format(String template, Object... params) { + if (isEmpty(params) || isEmpty(template)) { + return template; + } + return StrFormatter.format(template, params); + } + + /** + * 下划线转驼峰命名 + */ + public static String toUnderScoreCase(String str) { + if (str == null) { + return null; + } + StringBuilder sb = new StringBuilder(); + // 前置字符是否大写 + boolean preCharIsUpperCase = true; + // 当前字符是否大写 + boolean curreCharIsUpperCase = true; + // 下一字符是否大写 + boolean nexteCharIsUpperCase = true; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (i > 0) { + preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); + } else { + preCharIsUpperCase = false; + } + + curreCharIsUpperCase = Character.isUpperCase(c); + + if (i < (str.length() - 1)) { + nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); + } + + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) { + sb.append(SEPARATOR); + } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) { + sb.append(SEPARATOR); + } + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) { + if (str != null && strs != null) { + for (String s : strs) { + if (str.equalsIgnoreCase(trim(s))) { + return true; + } + } + } + return false; + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 + * 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) { + StringBuilder result = new StringBuilder(); + // 快速检查 + if (name == null || name.isEmpty()) { + // 没必要转换 + return ""; + } else if (!name.contains("_")) { + // 不含下划线,仅将首字母大写 + return name.substring(0, 1).toUpperCase() + name.substring(1); + } + // 用下划线将原始字符串分割 + String[] camels = name.split("_"); + for (String camel : camels) { + // 跳过原始字符串中开头、结尾的下换线或双重下划线 + if (camel.isEmpty()) { + continue; + } + // 首字母大写 + result.append(camel.substring(0, 1).toUpperCase()); + result.append(camel.substring(1).toLowerCase()); + } + return result.toString(); + } + + /** + * 驼峰式命名法 例如:user_name->userName + */ + public static String toCamelCase(String s) { + if (s == null) { + return null; + } + s = s.toLowerCase(); + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + if (c == SEPARATOR) { + upperCase = true; + } else if (upperCase) { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } else { + sb.append(c); + } + } + return sb.toString(); + } + + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) { + if (isEmpty(str) || isEmpty(strs)) { + return false; + } + for (String testStr : strs) { + if (matches(str, testStr)) { + return true; + } + } + return false; + } + + /** + * 查找指定字符串是否匹配指定字符串数组中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, String... strs) { + if (isEmpty(str) || isEmpty(strs)) { + return false; + } + for (String testStr : strs) { + if (matches(str, testStr)) { + return true; + } + } + return false; + } + + /** + * 查找指定字符串是否匹配 + * + * @param str 指定字符串 + * @param pattern 需要检查的字符串 + * @return 是否匹配 + */ + public static boolean matches(String str, String pattern) { + if (isEmpty(pattern) || isEmpty(str)) { + return false; + } + + // 替换空格 + pattern = pattern.replaceAll("\\s*", ""); + // pattern截取开始位置 + int beginOffset = 0; + // 前星号的偏移位置 + int formerStarOffset = -1; + // 后星号的偏移位置 + int latterStarOffset = -1; + + String remainingUrl = str; + String prefixPattern = ""; + String suffixPattern = ""; + + boolean result = false; + do { + formerStarOffset = indexOf(pattern, START, beginOffset); + prefixPattern = substring(pattern, beginOffset, + formerStarOffset > -1 ? formerStarOffset : pattern.length()); + + // 匹配前缀Pattern + result = remainingUrl.contains(prefixPattern); + // 已经没有星号,直接返回 + if (formerStarOffset == -1) { + return result; + } + + // 匹配失败,直接返回 + if (!result) { + return false; + } + + if (!isEmpty(prefixPattern)) { + remainingUrl = substringAfter(str, prefixPattern); + } + + // 匹配后缀Pattern + latterStarOffset = indexOf(pattern, START, formerStarOffset + 1); + suffixPattern = substring(pattern, formerStarOffset + 1, + latterStarOffset > -1 ? latterStarOffset : pattern.length()); + + result = remainingUrl.contains(suffixPattern); + // 匹配失败,直接返回 + if (!result) { + return false; + } + + if (!isEmpty(suffixPattern)) { + remainingUrl = substringAfter(str, suffixPattern); + } + + // 移动指针 + beginOffset = latterStarOffset + 1; + + } while (!isEmpty(suffixPattern) && !isEmpty(remainingUrl)); + + return true; + } + + @SuppressWarnings("unchecked") + public static T cast(Object obj) { + return (T) obj; + } + + /** + * 取交集,分别删除交集,将剩余的值添加进新的list + * + * @param list1 + * @param list2 + * @return + */ + public static List removeRepeatFactor(List list1, List list2) { + List intersection = list1.stream().filter(item -> list2.contains(item)).collect(toList()); + List listAllDistinct = new ArrayList<>(); + list1.removeAll(intersection); + list2.removeAll(intersection); + listAllDistinct.addAll(list1); + listAllDistinct.addAll(list2); + return listAllDistinct; + } + + /** + * 相邻的多个指定字符串替换成单个字符串 + * + * @param value + * @param str + * @return + */ + public static String replaceMoreStrToOneStr(String value, String str) { + if (isEmpty(value) || isEmpty(str)) { + return value; + } + String twoStr = str + str; + if (value.indexOf(twoStr) >= 0) { + value = value.replaceAll(twoStr, str); + return replaceMoreStrToOneStr(value, str); + } + return value; + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/TableFeildsEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/TableFeildsEnum.java new file mode 100644 index 0000000..59fd20f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/TableFeildsEnum.java @@ -0,0 +1,122 @@ +package com.yunzhupaas.util; + +import com.yunzhupaas.constant.TableFieldsNameConst; + +/** + * 流程设计 + * + * @author 云筑产品开发平台组 + * @version V3.4.2 + * @copyright 深圳市乐程软件有限公司 + * @date 2023/1/13 15:50:25 + */ +public enum TableFeildsEnum { + FID(TableFieldsNameConst.F_ID , "主键", "50","varchar" ,true,"NOT NULL",false), + TENANTID(TableFieldsNameConst.F_TENANT_ID , "租户id", "50","varchar" ,true,"NOT NULL",false), + VERSION(TableFieldsNameConst.F_VERSION , "乐观锁", "20","int" ,false,"NULL",false), + FLOWTASKID(TableFieldsNameConst.F_FLOW_TASK_ID , "流程任务主键", "50","varchar" ,false,"NULL",false), + FLOWID(TableFieldsNameConst.F_FLOW_ID , "流程id", "50","varchar" ,false,"NULL",false), + DELETEMARK(TableFieldsNameConst.F_DELETE_MARK , "删除标志", "20","int" ,false,"NULL",false), + DELETETIME(TableFieldsNameConst.F_DELETE_TIME , "删除时间", "0","datetime" ,false,"NULL",false), + DELETEUSERID(TableFieldsNameConst.F_DELETE_USER_ID , "删除用户", "50","varchar" ,false,"NULL",false), + FOREIGN(TableFieldsNameConst.F_FOREIGN_ID , "外键", "50","varchar" ,false,"NULL",false); + + + /** + * 字段名 + */ + protected String field; + /** + * 注释 + */ + protected String comment; + /** + * 数据长度 (n,m) 或 (n) + */ + protected String length; + /** + * 数据类型 + */ + protected String dataType; + /** + * 是否主键 + */ + protected Boolean isPrimaryKey; + /** + * 是否非空 + * (允空非空及0与1较容易混淆,故使用标识传作参数) + */ + protected String nullSign; + /** + * 是否自增 + */ + protected Boolean isAutoIncrement; + + TableFeildsEnum(String field, String comment, String length, String dataType, Boolean isPrimaryKey, String nullSign, Boolean isAutoIncrement) { + this.field = field; + this.comment = comment; + this.length = length; + this.dataType = dataType; + this.isPrimaryKey = isPrimaryKey; + this.nullSign = nullSign; + this.isAutoIncrement = isAutoIncrement; + + } + + public String getLength() { + return length; + } + + public void setLength(String length) { + this.length = length; + } + + public String getDataType() { + return dataType; + } + + public void setDataType(String dataType) { + this.dataType = dataType; + } + + public String getField() { + return field; + } + + public void setField(String field) { + this.field = field; + } + + public Boolean getPrimaryKey() { + return isPrimaryKey; + } + + public void setPrimaryKey(Boolean primaryKey) { + isPrimaryKey = primaryKey; + } + + public String getNullSign() { + return nullSign; + } + + public void setNullSign(String nullSign) { + this.nullSign = nullSign; + } + + public Boolean getAutoIncrement() { + return isAutoIncrement; + } + + public void setAutoIncrement(Boolean autoIncrement) { + isAutoIncrement = autoIncrement; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/TenantHolder.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/TenantHolder.java new file mode 100644 index 0000000..470e816 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/TenantHolder.java @@ -0,0 +1,54 @@ +package com.yunzhupaas.util; + +import com.yunzhupaas.model.tenant.TenantVO; +/** + * 租户线程缓存工具类 + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2023/12/01 16:16 + */ +public class TenantHolder { + + private TenantHolder() { + } + + private static final ThreadLocal TENANT_CACHE = new ThreadLocal<>(); + + public static void setLocalTenantCache(TenantVO tenantInfo){ + TENANT_CACHE.set(tenantInfo); + } + + public static TenantVO getLocalTenantCache(){ + return TENANT_CACHE.get(); + } + + public static void clearLocalTenantCache(){ + TENANT_CACHE.remove(); + } + + public static String getDatasourceId() { + return getLocalTenantCache() == null ? null: getLocalTenantCache().getEnCode(); + } + /** + * 取得当前数据源名称 + */ + public static String getDatasourceName() { + return getLocalTenantCache() == null ? null: getLocalTenantCache().getDbName(); + } + + public static boolean isSchema(){ + return getLocalTenantCache() != null && getLocalTenantCache().isSchema(); + } + + public static boolean isColumn(){ + return getLocalTenantCache() != null && getLocalTenantCache().isColumn(); + } + + public static boolean isRemote(){ + return getLocalTenantCache() != null && getLocalTenantCache().isRemote(); + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ThreadPoolExecutorUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ThreadPoolExecutorUtil.java new file mode 100644 index 0000000..dbfaa7e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ThreadPoolExecutorUtil.java @@ -0,0 +1,19 @@ +package com.yunzhupaas.util; + +import lombok.Getter; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Component; + + +@Component +public class ThreadPoolExecutorUtil { + + @Getter + private static ThreadPoolTaskExecutor executor; + + public ThreadPoolExecutorUtil(ThreadPoolTaskExecutor executor) { + ThreadPoolExecutorUtil.executor = executor; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/UpUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/UpUtil.java new file mode 100644 index 0000000..73fe208 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/UpUtil.java @@ -0,0 +1,88 @@ +package com.yunzhupaas.util; + +import com.yunzhupaas.constant.MsgCode; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.multipart.MultipartResolver; +import org.springframework.web.multipart.support.StandardServletMultipartResolver; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:57 + */ +public class UpUtil { + + /** + * 获取上传文件 + */ + public static List getFileAll(){ + MultipartResolver resolver = new StandardServletMultipartResolver(); + MultipartHttpServletRequest mRequest = resolver.resolveMultipart(ServletUtil.getRequest()); + Map fileMap = mRequest.getFileMap(); + List list = new ArrayList<>(); + for(Map.Entry map : fileMap.entrySet()){ + list.add(map.getValue()); + } + return list; + } + + /** + * 获取文件大小 + */ + public static long getFileSize(MultipartFile multipartFile){ + return multipartFile.getSize(); + } + + /** + * 获取文件类型 + */ + public static String getFileType(MultipartFile multipartFile){ + if (multipartFile.getContentType()!=null) { + String[] split = multipartFile.getOriginalFilename().split("\\."); + if (split.length>1) { + return split[split.length-1]; + } + } + return ""; + } + + /** + * 上传文件 + */ + public static String upLoad(MultipartFile file) { + if (file.isEmpty()) { + throw new RuntimeException(MsgCode.FA032.get()); + } + String fileName = file.getOriginalFilename(); + Date date=new Date(); + SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd"); + String time = formatter.format(date); + String uuidFileName = time+"_"+ RandomUtil.uuId()+"@"+fileName; + File dest = new File(XSSEscape.escapePath(uuidFileName)); + if(!dest.getParentFile().exists()){ + dest.getParentFile().mkdir(); + } + try { + file.transferTo(dest); + return uuidFileName; + } catch (IllegalStateException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/VisusalImgUrl.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/VisusalImgUrl.java new file mode 100644 index 0000000..235ef75 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/VisusalImgUrl.java @@ -0,0 +1,17 @@ +package com.yunzhupaas.util; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * Minio + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-06-15 + */ +@Data +public class VisusalImgUrl { + public static String url = "/api/file/VisusalImg/"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/XSSEscape.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/XSSEscape.java new file mode 100644 index 0000000..dc95633 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/XSSEscape.java @@ -0,0 +1,143 @@ +package com.yunzhupaas.util; + +import lombok.extern.slf4j.Slf4j; +import org.owasp.validator.html.AntiSamy; +import org.owasp.validator.html.CleanResults; +import org.owasp.validator.html.Policy; +import org.springframework.util.ObjectUtils; + +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 防止XSS注入 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-12-07 + */ +@Slf4j +public class XSSEscape { + + + /** + * 非法路径符号 + */ + private static final Pattern PATH_PATTERN = Pattern.compile("\\.\\.|~[/\\\\]|[<]|>|\"|[*]|[|]|[?]", Pattern.CASE_INSENSITIVE); + + private static InputStream inputStream; + private static Policy policy; + private static Policy emptyPolicy; + private static Policy imgOnlyBase64Policy; + + static{ + try{ + inputStream = XSSEscape.class.getClassLoader().getResourceAsStream("antisamy-ebay.xml"); + policy = Policy.getInstance(inputStream); + inputStream.close(); + inputStream = XSSEscape.class.getClassLoader().getResourceAsStream("antisamy-ebay-imgonlybase64.xml" ); + imgOnlyBase64Policy = Policy.getInstance(inputStream); + inputStream.close(); + inputStream = XSSEscape.class.getClassLoader().getResourceAsStream("antisamy-empty.xml"); + emptyPolicy = Policy.getInstance(inputStream); + inputStream.close(); + }catch (Exception e){ + e.printStackTrace(); + } + } + + /** + * 跨站式脚本攻击字符串过滤 + * @param character 需要转义的字符串 + */ + public static String escape(String character) { + try { + AntiSamy antiSamy = new AntiSamy(); + String str = character.replaceAll(""", "\""); + str = str.replaceAll("&", "&"); + str = str.replaceAll("<", "<"); + str = str.replaceAll(">", ">"); + str = str.replaceAll(" ", " "); + CleanResults scan = antiSamy.scan(str, policy); + str = scan.getCleanHTML(); + return str; + } catch (Exception e) { + log.error("转换错误:" + e.getMessage()); + } + return null; + } + + + /** + * 跨站式脚本攻击字符串过滤(图片标签只允许base64格式) + * @param character 需要转义的字符串 + */ + public static String escapeImgOnlyBase64(String character) { + try { + AntiSamy antiSamy = new AntiSamy(); + String str = character.replaceAll(""", "\""); + str = str.replaceAll("&", "&"); + str = str.replaceAll("<", "<"); + str = str.replaceAll(">", ">"); + str = str.replaceAll(" ", " "); + CleanResults scan = antiSamy.scan(str, imgOnlyBase64Policy); + str = scan.getCleanHTML(); + return str; + } catch (Exception e) { + log.error("转换错误:" + e.getMessage()); + } + return null; + } + + + /** + * 此方法伪过滤 + * @param character 需要转义的字符串 + */ + public static T escapeObj(T character) { + try { + if(ObjectUtils.isEmpty(character)){ + return character; + } + String str = escapeEmpty(character.toString()); + if(ObjectUtils.isEmpty(str.trim())){ + return character; + } + return (T) JsonUtil.getJsonToBean(JsonUtil.getObjectToString(str), character.getClass()); + } catch (Exception e) { + } + return character; + } + + /** + * 此方法伪过滤 + * @param character 需要转义的字符串 + */ + public static String escapeEmpty(String character) { + try { + AntiSamy antiSamy = new AntiSamy(); + CleanResults scan = antiSamy.scan(character, emptyPolicy); + return scan.getCleanHTML(); + } catch (Exception e) { + } + return character; + } + + /** + * 过滤非法路径 + * @param path + * @return + */ + public static String escapePath(String path){ + Matcher matcher; + while((matcher = PATH_PATTERN.matcher(path)).find()){ + path = matcher.replaceAll(""); + } + return escapeEmpty(path); + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ZipUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ZipUtil.java new file mode 100644 index 0000000..53b36ba --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ZipUtil.java @@ -0,0 +1,53 @@ +package com.yunzhupaas.util; + +import net.lingala.zip4j.ZipFile; +import net.lingala.zip4j.exception.ZipException; +import net.lingala.zip4j.model.ZipParameters; +import net.lingala.zip4j.model.enums.CompressionLevel; +import net.lingala.zip4j.model.enums.CompressionMethod; + +import java.io.File; +import java.io.InputStream; + +public class ZipUtil { + + /** + * 压缩文件 + * @param zipFilePath zip文件 + * @param filePath 文件路径 + * @param newFileName 在zip中的文件名称 + * @throws ZipException + */ + public static void fileAddToZip(String zipFilePath, String filePath, String newFileName) throws Exception { + ZipFile zipFile = new ZipFile(new File(zipFilePath)); + ZipParameters zipParameters = new ZipParameters(); + zipParameters.setCompressionMethod(CompressionMethod.DEFLATE); //设置压缩方法 + zipParameters.setCompressionLevel(CompressionLevel.NORMAL); ////设置压缩级别 + zipParameters.setFileNameInZip(newFileName); + zipFile.addFile(filePath, zipParameters); + } + + /** + * 压缩文件 + * @param zipFilePath zip文件 + * @param inputStream 文件输入流 + * @param newFileName 在zip中的文件名称 + * @throws ZipException + */ + public static void fileAddToZip(String zipFilePath, InputStream inputStream, String newFileName) throws Exception { + ZipFile zipFile = new ZipFile(new File(zipFilePath)); + ZipParameters zipParameters = new ZipParameters(); + zipParameters.setCompressionMethod(CompressionMethod.DEFLATE); //设置压缩方法 + zipParameters.setCompressionLevel(CompressionLevel.NORMAL); ////设置压缩级别 + zipParameters.setFileNameInZip(newFileName); + zipFile.addStream(inputStream, zipParameters); + } + + + public static void main(String[] args) throws Exception { + fileAddToZip("D:/xx/xpx.zip", "D:/xx/运行.txt", "运行2222.txt"); + System.out.println("生成成功"); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ZxingCodeUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ZxingCodeUtil.java new file mode 100644 index 0000000..446ad20 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/ZxingCodeUtil.java @@ -0,0 +1,218 @@ +package com.yunzhupaas.util; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:58 + */ +public class ZxingCodeUtil { + + //-----------------------------------条形码----------------------------------- + /** + * 条形码的颜色 + */ + private static final int BLACK = 0xff000000; + /** + * 背景色 + */ + private static final int WHITE = 0xFFFFFFFF; + + /** + * 生成一维码(128) + * + * @param message 内容 + * @param width 宽度 + * @param height 高度 + * @return + */ + public static BufferedImage getBarcode(String message, int width, int height) { + try { + Hashtable hints = new Hashtable(); + hints.put(EncodeHintType.CHARACTER_SET, "code"); + BitMatrix bitMatrix = new MultiFormatWriter().encode(message,BarcodeFormat.CODE_128, width, height, hints); + return toBufferedImage(bitMatrix); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 转换成图片 + * + * @param matrix + * @return + */ + private static BufferedImage toBufferedImage(BitMatrix matrix) { + int width = matrix.getWidth(); + int height = matrix.getHeight(); + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE); + } + } + return image; + } + + //--------------------------二维码----------------------------------- + /** + * 二维码颜色 + */ + private static final int QRCOLOR = 0xFF000000; + /** + * 背景色 + */ + private static final int BGCOLOR = 0xFFFFFFFF; + + /** + * 生成普通的二维码 + * @param message 二维码内容 + * @param width 宽度 + * @param height 高度 + * @return + */ + public static BufferedImage createCode(String message, int width, int height) { + MultiFormatWriter multiFormatWriter = null; + BitMatrix bm = null; + BufferedImage image = null; + Map hints = getDecodeHintType(); + try { + multiFormatWriter = new MultiFormatWriter(); + // 参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数 + bm = multiFormatWriter.encode(message, BarcodeFormat.QR_CODE, width, height, hints); + int w = bm.getWidth(); + int h = bm.getHeight(); + image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + // 开始利用二维码数据创建Bitmap图片,分别设为黑(0xFFFFFFFF)白(0xFF000000)两色 + for (int x = 0; x < w; x++) { + for (int y = 0; y < h; y++) { + image.setRGB(x, y, bm.get(x, y) ? QRCOLOR : BGCOLOR); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return image; + } + + /** + * 生成带logo的二维码 + * @param message 二维码内容 + * @param logoPath log路径 + * @param width 宽度 + * @param height 高度 + * @return + */ + public static BufferedImage createCodeWithLogo(String message, String logoPath, int width, int height) { + BufferedImage bim = createCode(message,width,height); + try { + // 读取二维码图片,并构建绘图对象 + BufferedImage image = bim; + Graphics2D g = image.createGraphics(); + // 读取Logo图片 + BufferedImage logo = ImageIO.read(new File(XSSEscape.escapePath(logoPath))); + //设置logo的大小,这里设置为二维码图片的20%,过大会盖掉二维码 + int widthLogo = logo.getWidth(null) > image.getWidth() * 3 / 10 ? (image.getWidth() * 3 / 10) : logo.getWidth(null), + heightLogo = logo.getHeight(null) > image.getHeight() * 3 / 10 ? (image.getHeight() * 3 / 10) : logo.getWidth(null); + // logo放在中心 + int x = (image.getWidth() - widthLogo) / 2; + int y = (image.getHeight() - heightLogo) / 2; + //开始绘制图片 + g.drawImage(logo, x, y, widthLogo, heightLogo, null); + g.dispose(); + logo.flush(); + image.flush(); + return image; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 生成带logo和文字的二维码 + * @param message 二维码内容 + * @param logoPath log路径 + * @param text 文字 + * @param width 宽度 + * @param height 高度 + * @return + */ + public static BufferedImage createCodeWithLogoAndText(String message, String logoPath, String text, int width, int height) { + BufferedImage image = createCodeWithLogo(message, logoPath,width,height); + try { + if (text != null && !"".equals(text)) { + //新的图片,把带logo的二维码下面加上文字 + BufferedImage outImage = new BufferedImage(400, 445, BufferedImage.TYPE_4BYTE_ABGR); + Graphics2D outg = outImage.createGraphics(); + //画二维码到新的面板 + outg.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null); + //画文字到新的面板 + outg.setColor(Color.BLACK); + //字体、字型、字号 + outg.setFont(new Font("宋体", Font.BOLD, 30)); + int strWidth = outg.getFontMetrics().stringWidth(text); + if (strWidth > 399) { + String productName1 = text.substring(0, text.length() / 2); + String productName2 = text.substring(text.length() / 2, text.length()); + int strWidth1 = outg.getFontMetrics().stringWidth(productName1); + int strWidth2 = outg.getFontMetrics().stringWidth(productName2); + outg.drawString(productName1, 200 - strWidth1 / 2, image.getHeight() + (outImage.getHeight() - image.getHeight()) / 2 + 12); + BufferedImage outImage2 = new BufferedImage(400, 485, BufferedImage.TYPE_4BYTE_ABGR); + Graphics2D outg2 = outImage2.createGraphics(); + outg2.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null); + outg2.setColor(Color.BLACK); + //字体、字型、字号 + outg2.setFont(new Font("宋体", Font.BOLD, 30)); + outg2.drawString(productName2, 200 - strWidth2 / 2, outImage.getHeight() + (outImage2.getHeight() - outImage.getHeight()) / 2 + 5); + outg2.dispose(); + outImage2.flush(); + outImage = outImage2; + } else { + //画文字 + outg.drawString(text, 200 - strWidth / 2, image.getHeight() + (outImage.getHeight() - image.getHeight()) / 2 + 12); + } + outg.dispose(); + outImage.flush(); + image = outImage; + image.flush(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return image; + } + + /** + * 设置二维码的格式参数 + * @return + */ + private static Map getDecodeHintType() { + Map hints = new HashMap(16); + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); + hints.put(EncodeHintType.CHARACTER_SET, Constants.UTF8); + hints.put(EncodeHintType.MARGIN, 0); + hints.put(EncodeHintType.MAX_SIZE, 350); + hints.put(EncodeHintType.MIN_SIZE, 100); + return hints; + } +} + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/context/RequestContext.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/context/RequestContext.java new file mode 100644 index 0000000..654907a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/context/RequestContext.java @@ -0,0 +1,26 @@ +package com.yunzhupaas.util.context; + +import com.yunzhupaas.util.ServletUtil; +import java.util.Objects; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.5.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2023/9/11 00:00 + */ +public class RequestContext { + + public static boolean isVue3(){ + //2, 3 + return Objects.equals(ServletUtil.getHeader("vue-version"), "3"); + } + + public static boolean isOrignPc(){ + //pc, app + return !Objects.equals(ServletUtil.getHeader("yunzhupaas-origin"), "app"); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/context/SpringContext.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/context/SpringContext.java new file mode 100644 index 0000000..8a7f3c5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/context/SpringContext.java @@ -0,0 +1,50 @@ +package com.yunzhupaas.util.context; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Component +public class SpringContext implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + SpringContext.applicationContext = applicationContext; + } + + public static ApplicationContext getApplicationContext() { + assertApplicationContext(); + return applicationContext; + } + + public static T getBean(String beanName) { + assertApplicationContext(); + try { + return (T) applicationContext.getBean(beanName); + } catch (Exception e) { + return null; + } + } + + public static T getBean(Class beanName) { + assertApplicationContext(); + return (T) applicationContext.getBean(beanName); + } + + private static void assertApplicationContext() { + if (SpringContext.applicationContext == null) { + throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!"); + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/data/DataSourceContextHolder.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/data/DataSourceContextHolder.java new file mode 100644 index 0000000..985f33a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/data/DataSourceContextHolder.java @@ -0,0 +1,58 @@ +package com.yunzhupaas.util.data; + +/** + * 数据库上下文切换 + * + * @see com.yunzhupaas.util.TenantHolder + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:49 + */ +@Deprecated +public class DataSourceContextHolder { + + private static final ThreadLocal CONTEXT_DB_NAME_HOLDER = new ThreadLocal<>(); + + private static final ThreadLocal CONTEXT_DB_ID_HOLDER = new ThreadLocal<>(); + + private static final ThreadLocal CONTEXT_ASSIGN_HOLDER = new ThreadLocal<>(); + + /** + * 设置当前数据库 + */ + public static void setDatasource(String dbId,String dbName, boolean assign) { + CONTEXT_DB_NAME_HOLDER.set(dbName); + CONTEXT_DB_ID_HOLDER.set(dbId); + CONTEXT_ASSIGN_HOLDER.set(assign); + } + + /** + * 取得当前数据源Id + */ + public static String getDatasourceId() { + String str = CONTEXT_DB_ID_HOLDER.get(); + return str; + } + /** + * 取得当前数据源名称 + */ + public static String getDatasourceName() { + String str = CONTEXT_DB_NAME_HOLDER.get(); + return str; + } + + public static Boolean isAssignDataSource(){ + return Boolean.TRUE.equals(CONTEXT_ASSIGN_HOLDER.get()); + } + + /** + * 清除上下文数据 + */ + public static void clearDatasourceType() { + CONTEXT_DB_NAME_HOLDER.remove(); + CONTEXT_DB_ID_HOLDER.remove(); + CONTEXT_ASSIGN_HOLDER.remove(); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/dbcolum/ColumnType.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/dbcolum/ColumnType.java new file mode 100644 index 0000000..bd759d1 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/dbcolum/ColumnType.java @@ -0,0 +1,38 @@ +package com.yunzhupaas.util.dbcolum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 常用字段常量类 + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-15 09:00 + */ +@Data +public class ColumnType { + + /** + *MySQL字段常量 + */ + public static final String MYSQL_VARCHAR = "varchar"; + + public static final String MYSQL_DATETIME = "datetime"; + + public static final String MYSQL_DECIMAL = "decimal"; + + public static final String MYSQL_TEXT = "text"; + + /** + *Oracle字段常量 + */ + public static final String ORACLE_NVARCHAR = "NVARCHAR2"; + + public static final String ORACLE_DATE = "DATE"; + + public static final String ORACLE_DECIMAL = "DECIMAL"; + + public static final String ORACLE_CLOB = "CLOB"; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/enums/DictionaryDataEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/enums/DictionaryDataEnum.java new file mode 100644 index 0000000..a8bee64 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/enums/DictionaryDataEnum.java @@ -0,0 +1,138 @@ +package com.yunzhupaas.util.enums; + +/** + * 数据字典分类id + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-10-20 + */ +public enum DictionaryDataEnum { + /** + * 功能设计 + */ + VISUALDEV(1, "businessType"), + /** + * 移动设计 + */ + VISUALDEV_APP(2, "businessType"), + /** + * 流程表单 + */ + VISUALDEV_GENERATER_FLOWWORK(3, "businessType"), + /** + * 功能表单 + */ + VISUALDEV_GENERATER(4, "businessType"), + /** + * 移动表单 + */ + VISUALDEV_GENERATER_APP(5, "businessType"), + /** + * 门户设计 + */ + VISUALDEV_PORTAL(6, "businessType"), + /** + * 数据连接 + */ + SYSTEM_DBLINK(7, "dbType"), + /** + * 打印模板 + */ + SYSTEM_PRINTDEV(8, "businessType"), + /** + * 数据接口 + */ + SYSTEM_DATAINTERFACE(12, "DataInterfaceType"), + /** + * 角色类型 + */ + PERMISSION_ROLE(9, "RoleType"), + /** + * 分组id + */ + PERMISSION_GROUP(12, "groupType"), + /** + * 报表设计 + */ + VISUALDEV_REPORT(10, "businessType"), + /** + * 流程设计 + */ + FLOWWOEK_ENGINE(11, "businessType"), + /** + * 企业性质 + */ + ENTERPRISE_NATURE(13, "EnterpriseNature"), + /** + * 行业类别 + */ + INDUSTRY_TYPE(14, "IndustryType"), + /** + * 性别 + */ + SEX_TYPE(15, "sex"), + /** + * 职级 + */ + RANK(16, "Rank"), + /** + * 民族 + */ + NATION(17, "Nation"), + /** + * 证件类型 + */ + CERTIFICATE_TYPE(18, "certificateType"), + /** + * 文化程度 + */ + EDUCATION(19, "Education"), + + /** + * 岗位分类 + */ + POSITION_TYPE(20, "PositionType"); + + private Integer type; + private String dictionaryTypeId; + + DictionaryDataEnum(Integer type, String dictionaryTypeId) { + this.type = type; + this.dictionaryTypeId = dictionaryTypeId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getDictionaryTypeId() { + return dictionaryTypeId; + } + + public void setDictionaryTypeId(String dictionaryTypeId) { + this.dictionaryTypeId = dictionaryTypeId; + } + + /** + * 获取通过type获取数据字典分类id + * + * @param type 类型 + * @return + */ + public static String getTypeId(Integer type) { + for (DictionaryDataEnum value : DictionaryDataEnum.values()) { + if (type.equals(value.getType())) { + return value.getDictionaryTypeId(); + } + } + return ""; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/generater/DataSwapUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/generater/DataSwapUtil.java new file mode 100644 index 0000000..cf7d61d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/generater/DataSwapUtil.java @@ -0,0 +1,70 @@ +package com.yunzhupaas.util.generater; + +import com.alibaba.fastjson.JSONArray; +import com.yunzhupaas.util.StringUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * 在线开发,代码生成通用方法 + * + * @author 云筑产品开发平台组 + * @version V3.4.2 + * @copyright 深圳市乐程软件有限公司 + * @date 2023/3/6 16:40:09 + */ +public class DataSwapUtil { + /** + * json(string)对象转list + * @param obj 对象 + * @return + * @copyright 深圳市乐程软件有限公司 + * @date 2023/3/6 + */ + public static List convertToList(Object obj) { + if (obj instanceof List) { + List arrayList = (List) obj; + return arrayList; + } else { + List arrayList = new ArrayList(); + arrayList.add(obj); + return arrayList; + } + } + /** + * json(list)对象转string + * @param mult 多选 + * @param isOrg 是否组织选择(组织选择存在‘[[’) + * @return + * @copyright 深圳市乐程软件有限公司 + * @date 2023/3/6 + */ + public static String convertValueToString(String obj, boolean mult, boolean isOrg) { + if (StringUtil.isNotEmpty(obj)) { + String prefix = "["; + if(isOrg){ + prefix = "[["; + } + if (mult) { + if (!obj.startsWith(prefix)) { + JSONArray arr = new JSONArray(); + if(isOrg){ + //组织多选为二维数组 + arr.add(JSONArray.parse(obj)); + }else { + arr.add(obj); + } + return arr.toJSONString(); + } + } else { + if (obj.startsWith(prefix)) { + JSONArray objects = JSONArray.parseArray(obj); + return objects.size() > 0 ? objects.get(0).toString() : ""; + } + } + } + return obj; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/jwt/JwtUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/jwt/JwtUtil.java new file mode 100644 index 0000000..78cdb3a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/jwt/JwtUtil.java @@ -0,0 +1,75 @@ +package com.yunzhupaas.util.jwt; + +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; + +import java.util.Date; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +public class JwtUtil { + + /** + * 获取jwt中的携带的Redis的token + * @param token + * @return + */ + public static String getRealToken(String token) { + String realToken; + try { + SignedJWT sjwt = SignedJWT.parse(token.split(" ")[1]); + JWTClaimsSet claims = sjwt.getJWTClaimsSet(); + realToken = String.valueOf(claims.getClaim("token")); + return realToken; + } catch (Exception e) { + return realToken = null; + } + } + + /** + * 获取jwt中的携带的Redis的token + * @param token + * @return + */ + public static Integer getSingleLogin(String token) { + int singleLogin; + try { + SignedJWT sjwt = SignedJWT.parse(token.split(" ")[1]); + JWTClaimsSet claims = sjwt.getJWTClaimsSet(); + singleLogin = Integer.parseInt(String.valueOf(claims.getClaim("singleLogin"))); + return singleLogin; + } catch (Exception e) { + return singleLogin = 1; + } + } + + /** + * 获取jwt中的过期时间 + * @param token + * @return + */ + public static Date getExp(String token){ + Date date; + try { + SignedJWT sjwt = SignedJWT.parse(token.split(" ")[1]); + JWTClaimsSet claims = sjwt.getJWTClaimsSet(); + date = (Date)claims.getClaim("exp"); + return date; + } catch (Exception e) { + return date = null; + } + } + + public static void main(String[] args) { + String test = getRealToken("Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiIxNDEwMDEiLCJzY29wZSI6WyJhbGwiXSwiZXhwIjoxNjA5MDA5NDQxLCJhdXRob3JpdGllcyI6WyJhYSJdLCJqdGkiOiIxYWNkYTI4MS0yYTUxLTRmZGYtYmRlYy03OWFkNmI5NzZmODEiLCJjbGllbnRfaWQiOiJhZG1pbiIsInRva2VuIjoibG9naW5fdG9rZW5fMDNhNDEyNTgwOGU5NGVhYjhlY2I3MzM4OTQ2ZjJhMzgifQ.b1LJ5dWQeI0it7JPP0vAm56Ns-2l-zpi768Z2KhdAODLWyfO640jIz02dNixfnw0_2hgBwqj9Y-1NIMVEZmRPMoRhIOwh6qw4p8b05k8Y3M2KXhdYaQTaw9ZkpR-TFRuVf8_v2bUaUjmnulXRffV3iVAYmcZcXHBrv0938_oJJEIKHmjtlbbOCaKIf6IEPCwmFci8gLCnld6FnVIytg9rMD85AsagwLHs_dNaNavEg3-s5Fi9jov7L2_h940aHPvtwBiCNpPkFIA-hmYb7-ChETmx8yFN3TnJbNX4-wpQ_dJlaNnHTtbt8ztNr-ugXbKGqfkZzWPxn-anqeSjyBUAA"); + System.out.println(test); + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/minio/StorageType.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/minio/StorageType.java new file mode 100644 index 0000000..c470153 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/minio/StorageType.java @@ -0,0 +1,41 @@ +package com.yunzhupaas.util.minio; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 文件储存类型常量类 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-04-06 + */ +@Data +public class StorageType { + /** + * 本地存储 + */ + public static final String STORAGE = "local"; + + /** + * Minio存储 + */ + public static final String MINIO = "minio"; + + /** + * AliOSS存储 + */ + public static final String ALI_OSS = "aliyun-oss"; + + /** + * 七牛云 + */ + public static final String QINIU = "qiniu-kodo"; + + /** + * 腾讯云 + */ + public static final String TENCENT = "tencent-cos"; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/text/CharsetKit.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/text/CharsetKit.java new file mode 100644 index 0000000..2e71ddc --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/text/CharsetKit.java @@ -0,0 +1,82 @@ +package com.yunzhupaas.util.text; + +import com.yunzhupaas.util.StringUtil; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * 字符集工具类 + * + * @author yunzhupaas + */ +public class CharsetKit { + /** ISO-8859-1 */ + public static final String ISO_8859_1 = "ISO-8859-1"; + /** UTF-8 */ + public static final String UTF_8 = "UTF-8"; + /** GBK */ + public static final String GBK = "GBK"; + + /** ISO-8859-1 */ + public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1); + /** UTF-8 */ + public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8); + /** GBK */ + public static final Charset CHARSET_GBK = Charset.forName(GBK); + + /** + * 转换为Charset对象 + * + * @param charset 字符集,为空则返回默认字符集 + * @return Charset + */ + public static Charset charset(String charset) { + return StringUtil.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * @return 转换后的字符集 + */ + public static String convert(String source, String srcCharset, String destCharset) { + return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset)); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * @return 转换后的字符集 + */ + public static String convert(String source, Charset srcCharset, Charset destCharset) { + if (null == srcCharset) { + srcCharset = StandardCharsets.ISO_8859_1; + } + + if (null == destCharset) { + destCharset = StandardCharsets.UTF_8; + } + + if (StringUtil.isEmpty(source) || srcCharset.equals(destCharset)) { + return source; + } + return new String(source.getBytes(srcCharset), destCharset); + } + + /** + * @return 系统字符集编码 + */ + public static String systemCharset() { + return Charset.defaultCharset().name(); + } + +} + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/text/Convert.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/text/Convert.java new file mode 100644 index 0000000..7a5286d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/text/Convert.java @@ -0,0 +1,862 @@ +package com.yunzhupaas.util.text; + +import com.yunzhupaas.util.StringUtil; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.text.NumberFormat; +import java.util.Set; + +/** + * 类型转换器 + * + * @author yunzhupaas + */ +public class Convert { + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static String toStr(Object value, String defaultValue) { + if (null == value) { + return defaultValue; + } + if (value instanceof String) { + return (String) value; + } + return value.toString(); + } + + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static String toStr(Object value) { + return toStr(value, null); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Character toChar(Object value, Character defaultValue) { + if (null == value) { + return defaultValue; + } + if (value instanceof Character) { + return (Character) value; + } + + final String valueStr = toStr(value, null); + return StringUtil.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Character toChar(Object value) { + return toChar(value, null); + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Byte toByte(Object value, Byte defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Byte) { + return (Byte) value; + } + if (value instanceof Number) { + return ((Number) value).byteValue(); + } + final String valueStr = toStr(value, null); + if (StringUtil.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Byte.parseByte(valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Byte toByte(Object value) { + return toByte(value, null); + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Short toShort(Object value, Short defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Short) { + return (Short) value; + } + if (value instanceof Number) { + return ((Number) value).shortValue(); + } + final String valueStr = toStr(value, null); + if (StringUtil.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Short.parseShort(valueStr.trim()); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Short toShort(Object value) { + return toShort(value, null); + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Number toNumber(Object value, Number defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Number) { + return (Number) value; + } + final String valueStr = toStr(value, null); + if (StringUtil.isEmpty(valueStr)) { + return defaultValue; + } + try { + return NumberFormat.getInstance().parse(valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Number toNumber(Object value) { + return toNumber(value, null); + } + + /** + * 转换为int
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Integer toInt(Object value, Integer defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Integer) { + return (Integer) value; + } + if (value instanceof Number) { + return ((Number) value).intValue(); + } + final String valueStr = toStr(value, null); + if (StringUtil.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Integer.parseInt(valueStr.trim()); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为int
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Integer toInt(Object value) { + return toInt(value, null); + } + + /** + * 转换为Integer数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String str) { + return toIntArray(",", str); + } + + /** + * 转换为Long数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String str) { + return toLongArray(",", str); + } + + /** + * 转换为Integer数组
+ * + * @param split 分隔符 + * @param split 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String split, String str) { + if (StringUtil.isEmpty(str)) { + return new Integer[] {}; + } + String[] arr = str.split(split); + final Integer[] ints = new Integer[arr.length]; + for (int i = 0; i < arr.length; i++) { + final Integer v = toInt(arr[i], 0); + ints[i] = v; + } + return ints; + } + + /** + * 转换为Long数组
+ * + * @param split 分隔符 + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String split, String str) { + if (StringUtil.isEmpty(str)) { + return new Long[] {}; + } + String[] arr = str.split(split); + final Long[] longs = new Long[arr.length]; + for (int i = 0; i < arr.length; i++) { + final Long v = toLong(arr[i], null); + longs[i] = v; + } + return longs; + } + + /** + * 转换为String数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String str) { + return toStrArray(",", str); + } + + /** + * 转换为String数组
+ * + * @param split 分隔符 + * @param split 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String split, String str) { + return str.split(split); + } + + /** + * 转换为long
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Long toLong(Object value, Long defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Long) { + return (Long) value; + } + if (value instanceof Number) { + return ((Number) value).longValue(); + } + final String valueStr = toStr(value, null); + if (StringUtil.isEmpty(valueStr)) { + return defaultValue; + } + try { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).longValue(); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为long
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Long toLong(Object value) { + return toLong(value, null); + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Double toDouble(Object value, Double defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Double) { + return (Double) value; + } + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + final String valueStr = toStr(value, null); + if (StringUtil.isEmpty(valueStr)) { + return defaultValue; + } + try { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).doubleValue(); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Double toDouble(Object value) { + return toDouble(value, null); + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Float toFloat(Object value, Float defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Float) { + return (Float) value; + } + if (value instanceof Number) { + return ((Number) value).floatValue(); + } + final String valueStr = toStr(value, null); + if (StringUtil.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Float.parseFloat(valueStr.trim()); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Float toFloat(Object value) { + return toFloat(value, null); + } + + /** + * 转换为boolean
+ * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Boolean toBool(Object value, Boolean defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Boolean) { + return (Boolean) value; + } + String valueStr = toStr(value, null); + if (StringUtil.isEmpty(valueStr)) { + return defaultValue; + } + valueStr = valueStr.trim().toLowerCase(); + switch (valueStr) { + case "true": + return true; + case "false": + return false; + case "yes": + return true; + case "ok": + return true; + case "no": + return false; + case "1": + return true; + case "0": + return false; + default: + return defaultValue; + } + } + + /** + * 转换为boolean
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Boolean toBool(Object value) { + return toBool(value, null); + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * + * @param clazz Enum的Class + * @param value 值 + * @param defaultValue 默认值 + * @return Enum + */ + public static > E toEnum(Class clazz, Object value, E defaultValue) { + if (value == null) { + return defaultValue; + } + if (clazz.isAssignableFrom(value.getClass())) { + @SuppressWarnings("unchecked") + E myE = (E) value; + return myE; + } + final String valueStr = toStr(value, null); + if (StringUtil.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Enum.valueOf(clazz, valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * + * @param clazz Enum的Class + * @param value 值 + * @return Enum + */ + public static > E toEnum(Class clazz, Object value) { + return toEnum(clazz, value, null); + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value, BigInteger defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof BigInteger) { + return (BigInteger) value; + } + if (value instanceof Long) { + return BigInteger.valueOf((Long) value); + } + final String valueStr = toStr(value, null); + if (StringUtil.isEmpty(valueStr)) { + return defaultValue; + } + try { + return new BigInteger(valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value) { + return toBigInteger(value, null); + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof BigDecimal) { + return (BigDecimal) value; + } + if (value instanceof Long) { + return new BigDecimal((Long) value); + } + if (value instanceof Double) { + return new BigDecimal((Double) value); + } + if (value instanceof Integer) { + return new BigDecimal((Integer) value); + } + final String valueStr = toStr(value, null); + if (StringUtil.isEmpty(valueStr)) { + return defaultValue; + } + try { + return new BigDecimal(valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value) { + return toBigDecimal(value, null); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @return 字符串 + */ + public static String utf8Str(Object obj) { + return str(obj, CharsetKit.CHARSET_UTF_8); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charsetName 字符集 + * @return 字符串 + */ + public static String str(Object obj, String charsetName) { + return str(obj, Charset.forName(charsetName)); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(Object obj, Charset charset) { + if (null == obj) { + return null; + } + + if (obj instanceof String) { + return (String) obj; + } else if (obj instanceof byte[] || obj instanceof Byte[]) { + return str((Byte[]) obj, charset); + } else if (obj instanceof ByteBuffer) { + return str((ByteBuffer) obj, charset); + } + return obj.toString(); + } + + /** + * 将byte数组转为字符串 + * + * @param bytes byte数组 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(byte[] bytes, String charset) { + return str(bytes, StringUtil.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset)); + } + + /** + * 解码字节码 + * + * @param data 字符串 + * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 + * @return 解码后的字符串 + */ + public static String str(byte[] data, Charset charset) { + if (data == null) { + return null; + } + + if (null == charset) { + return new String(data); + } + return new String(data, charset); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, String charset) { + if (data == null) { + return null; + } + + return str(data, Charset.forName(charset)); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, Charset charset) { + if (null == charset) { + charset = Charset.defaultCharset(); + } + return charset.decode(data).toString(); + } + + // ----------------------------------------------------------------------- + // 全角半角转换 + /** + * 半角转全角 + * + * @param input String. + * @return 全角字符串. + */ + public static String toSbc(String input) { + return toSbc(input, null); + } + + /** + * 半角转全角 + * + * @param input String + * @param notConvertSet 不替换的字符集合 + * @return 全角字符串. + */ + public static String toSbc(String input, Set notConvertSet) { + char[] c = input.toCharArray(); + for (int i = 0; i < c.length; i++) { + if (null != notConvertSet && notConvertSet.contains(c[i])) { + // 跳过不替换的字符 + continue; + } + + if (c[i] == ' ') { + c[i] = '\u3000'; + } else if (c[i] < '\177') { + c[i] = (char) (c[i] + 65248); + + } + } + return new String(c); + } + + /** + * 全角转半角 + * + * @param input String. + * @return 半角字符串 + */ + public static String toDbc(String input) { + return toDbc(input, null); + } + + /** + * 替换全角为半角 + * + * @param text 文本 + * @param notConvertSet 不替换的字符集合 + * @return 替换后的字符 + */ + public static String toDbc(String text, Set notConvertSet) { + char[] c = text.toCharArray(); + for (int i = 0; i < c.length; i++) { + if (null != notConvertSet && notConvertSet.contains(c[i])) { + // 跳过不替换的字符 + continue; + } + + if (c[i] == '\u3000') { + c[i] = ' '; + } else if (c[i] > '\uFF00' && c[i] < '\uFF5F') { + c[i] = (char) (c[i] - 65248); + } + } + String returnString = new String(c); + + return returnString; + } + + /** + * 数字金额大写转换 先写个完整的然后将如零拾替换成零 + * + * @param n 数字 + * @return 中文大写数字 + */ + public static String digitUppercase(double n) + { + String[] fraction = { "角", "分" }; + String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }; + String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } }; + + String head = n < 0 ? "负" : ""; + n = Math.abs(n); + + String s = ""; + for (int i = 0; i < fraction.length; i++) + { + s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", ""); + } + if (s.length() < 1) + { + s = "整"; + } + int integerPart = (int) Math.floor(n); + + for (int i = 0; i < unit[0].length && integerPart > 0; i++) + { + String p = ""; + for (int j = 0; j < unit[1].length && n > 0; j++) + { + p = digit[integerPart % 10] + unit[1][j] + p; + integerPart = integerPart / 10; + } + s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s; + } + return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整"); + } + +} + + + + + // + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/text/StrFormatter.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/text/StrFormatter.java new file mode 100644 index 0000000..72395d1 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/text/StrFormatter.java @@ -0,0 +1,100 @@ +package com.yunzhupaas.util.text; + +import com.yunzhupaas.util.StringUtil; + +/** + * 字符串格式化 + * + * @author yunzhupaas + */ +public class StrFormatter +{ + public static final String EMPTY_JSON = "{}"; + public static final char C_BACKSLASH = '\\'; + public static final char C_DELIM_START = '{'; + public static final char C_DELIM_END = '}'; + + /** + * 格式化字符串
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param strPattern 字符串模板 + * @param argArray 参数列表 + * @return 结果 + */ + public static String format(final String strPattern, final Object... argArray) + { + if (StringUtil.isEmpty(strPattern) || StringUtil.isEmpty(argArray)) + { + return strPattern; + } + final int strPatternLength = strPattern.length(); + + // 初始化定义好的长度以获得更好的性能 + StringBuilder sbuf = new StringBuilder(strPatternLength + 50); + + int handledPosition = 0; + int delimIndex;// 占位符所在位置 + for (int argIndex = 0; argIndex < argArray.length; argIndex++) + { + delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition); + if (delimIndex == -1) + { + if (handledPosition == 0) + { + return strPattern; + } + else + { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果 + sbuf.append(strPattern, handledPosition, strPatternLength); + return sbuf.toString(); + } + } + else + { + if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) + { + if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) + { + // 转义符之前还有一个转义符,占位符依旧有效 + sbuf.append(strPattern, handledPosition, delimIndex - 1); + sbuf.append(Convert.utf8Str(argArray[argIndex])); + handledPosition = delimIndex + 2; + } + else + { + // 占位符被转义 + argIndex--; + sbuf.append(strPattern, handledPosition, delimIndex - 1); + sbuf.append(C_DELIM_START); + handledPosition = delimIndex + 1; + } + } + else + { + // 正常占位符 + sbuf.append(strPattern, handledPosition, delimIndex); + sbuf.append(Convert.utf8Str(argArray[argIndex])); + handledPosition = delimIndex + 2; + } + } + } + // 加入最后一个占位符后所有的字符 + sbuf.append(strPattern, handledPosition, strPattern.length()); + + return sbuf.toString(); + } +} + + + + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/ListToTreeUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/ListToTreeUtil.java new file mode 100644 index 0000000..698a5a0 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/ListToTreeUtil.java @@ -0,0 +1,220 @@ +package com.yunzhupaas.util.treeutil; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:49 + */ +public class ListToTreeUtil { + + /** + * 转换TreeView + * + * @param data + * @return + */ + public static List toTreeView(List data) { + List treeList = getChildNodeList(data, "0"); + return treeList; + } + + /** + * 递归 + * + * @param data + * @param parentId + */ + private static List getChildNodeList(List data, String parentId) { + List treeList = new ArrayList<>(); + List childNodeList = data.stream().filter(t -> String.valueOf(t.getParentId()).equals(parentId)).collect(Collectors.toList()); + for (TreeViewModel entity : childNodeList) { + TreeViewModel model = new TreeViewModel(); + model.setId(entity.getId()); + model.setText(entity.getText()); + model.setParentId(entity.getParentId()); + model.setIsexpand(entity.getIsexpand()); + model.setComplete(entity.getComplete()); + model.setHasChildren(entity.getHasChildren() == null ? data.stream().filter(t -> String.valueOf(t.getParentId()).equals(String.valueOf(entity.getId()))).count() == 0 ? false : true : false); + if (entity.getShowcheck()) { + model.setCheckstate(entity.getCheckstate()); + model.setShowcheck(true); + } + if (entity.getImg() != null) { + model.setImg(entity.getImg()); + } + if (entity.getCssClass() != null) { + model.setCssClass(entity.getCssClass()); + } + if (entity.getClick() != null) { + model.setClick(entity.getClick()); + } + if (entity.getCode() != null) { + model.setCode(entity.getCode()); + } + if (entity.getTitle() != null) { + model.setTitle(entity.getTitle()); + } + if (entity.getHt() != null) { + model.setHt(entity.getHt()); + } + model.setChildNodes(getChildNodeList(data, entity.getId())); + treeList.add(model); + } + return treeList; + } + + /** + * 递归查询父节点 + * + * @param data 条件的的数据 + * @param dataAll 所有的数据 + * @param id id + * @param parentId parentId + * @param + * @return + */ + public static JSONArray treeWhere(List data, List dataAll, String id, String parentId) { + JSONArray resultData = new JSONArray(); + if (data.size() == dataAll.size()) { + resultData.addAll(data); + return resultData; + } + List dataListAll = new ArrayList<>(); + CollectionUtils.addAll(dataListAll,dataAll); + dataListAll.removeAll(data); + for (int i = 0; i < data.size(); i++) { + T entity = data.get(i); + JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(entity)); + String firstParentId = json.getString(parentId); + if (resultData.stream().filter(t -> t.equals(json)).count() == 0) { + resultData.add(entity); + } + if (!"-1".equals(firstParentId)) { + ParentData(dataListAll, json, resultData, id, parentId); + } + } + return resultData; + } + + /** + * 递归查询父节点 + * + * @param data 条件的的数据 + * @param dataAll 所有的数据 + * @param + * @return + */ + public static JSONArray treeWhere(List data, List dataAll) { + String id = "id"; + String parentId = "parentId"; + return treeWhere(data, dataAll, id, parentId); + } + + /** + * 递归查询父节点 + * + * @param dataAll 所有数据 + * @param json 当前对象 + * @param resultData 结果数据 + * @param id id + * @param parentId parentId + * @param + * @return + */ + private static JSONArray ParentData(List dataAll, JSONObject json, JSONArray resultData, String id, String parentId) { + List data = dataAll.stream().filter(t -> JSONObject.parseObject(JSONObject.toJSONString(t)).get(id).equals(json.getString(parentId))).collect(Collectors.toList()); + dataAll.removeAll(data); + for (int i = 0; i < data.size(); i++) { + T entity = data.get(i); + JSONObject object = JSONObject.parseObject(JSONObject.toJSONString(entity)); + String parentIds = object.getString(parentId); + if (resultData.stream().filter(t -> t.equals(object)).count() == 0) { + resultData.add(entity); + } + if ("-1".equals(parentIds)) { + break; + } + ParentData(dataAll, object, resultData, id, parentId); + } + return resultData; + } + + /** + * 递归查询子节点 + * + * @param dataAll 所有的数据 + * @param id id + * @param parentId parentId + * @param fid 查询的父亲节点 + * @param + * @return + */ + public static JSONArray treeWhere(String fid, List dataAll, String id, String parentId) { + JSONArray resultData = new JSONArray(); + List data = dataAll.stream().filter(t -> JSONObject.parseObject(JSONObject.toJSONString(t)).get(parentId).equals(fid)).collect(Collectors.toList()); + List dataListAll = new ArrayList<>(); + CollectionUtils.addAll(dataListAll,dataAll); + dataListAll.removeAll(data); + for (int i = 0; i < data.size(); i++) { + T entity = data.get(i); + JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(entity)); + String fId = json.getString(id); + String fParentId = json.getString(parentId); + if (fid.equals(fParentId)) { + resultData.add(entity); + ChildData(fId, dataListAll, resultData, id, parentId); + } + } + return resultData; + } + + /** + * 递归查询子节点 + * + * @param data 所有的数据 + * @param fid 查询的父亲节点 + * @param + * @return + */ + public static JSONArray treeWhere(String fid, List data) { + String id = "id"; + String parentId = "parentId"; + return treeWhere(fid, data, id, parentId); + } + + /** + * 递归查询子节点 + * + * @param dataAll 所有的数据 + * @param id F_Id + * @param parentId F_ParentId + * @param fid 查询的父亲节点 + * @param + * @return + */ + public static JSONArray ChildData(String fid, List dataAll, JSONArray resultData, String id, String parentId) { + List data = dataAll.stream().filter(t -> JSONObject.parseObject(JSONObject.toJSONString(t)).get(parentId).equals(fid)).collect(Collectors.toList()); + dataAll.removeAll(data); + for (int i = 0; i < data.size(); i++) { + T entity = data.get(i); + JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(entity)); + String fId = json.getString(id); + String fParentId = json.getString(parentId); + if (fid.equals(fParentId)) { + resultData.add(entity); + ChildData(fId, dataAll, resultData, id, parentId); + } + } + return resultData; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/SumTree.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/SumTree.java new file mode 100644 index 0000000..73c6626 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/SumTree.java @@ -0,0 +1,25 @@ +package com.yunzhupaas.util.treeutil; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:56 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class SumTree { + private String id; + private String parentId; + private Boolean hasChildren; + private List> children; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/SumTree2.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/SumTree2.java new file mode 100644 index 0000000..c11b26b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/SumTree2.java @@ -0,0 +1,25 @@ +package com.yunzhupaas.util.treeutil; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:56 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class SumTree2 { + private String id; + private String parentId; + private Boolean hasChildren; + private List children; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeDotUtils.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeDotUtils.java new file mode 100644 index 0000000..b35a8eb --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeDotUtils.java @@ -0,0 +1,147 @@ +package com.yunzhupaas.util.treeutil; + +import com.yunzhupaas.util.StringUtil; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/*** + * 树工具 + * + * @ClassName TreeDotUtils + * @Author yunzhupaas + * @DateTime 2020/4/22 9:14 + */ +public class TreeDotUtils { + + /** + * 将List转换为Tree + */ + public static List> convertListToTreeDot(List tList, String parentId) { + List> sumTrees = new ArrayList<>(); + List list = new ArrayList<>(); + CollectionUtils.addAll(list, tList); + if (StringUtil.isNotEmpty(parentId)) { + List data = list.stream().filter(t -> parentId.equals(t.getParentId())).collect(Collectors.toList()); + list.removeAll(data); + for (int i = 0; i < data.size(); i++) { + T t = data.get(i); + if (!isTreeDotExist(list, t.getParentId())) { + SumTree tSumTree = getTreeDotByT(t, list); + sumTrees.add(tSumTree); + } + } + } + return sumTrees; + } + + /** + * 将List转换为Tree + */ + public static List> convertListToTreeDot(List tList) { + List> sumTrees = new ArrayList<>(); + if (tList != null && tList.size() > 0) { + List list = new ArrayList<>(); + CollectionUtils.addAll(list, tList); + for (int i = 0; i < tList.size(); i++) { + T t = tList.get(i); + if (!isTreeDotExist(tList, t.getParentId())) { + // 不存在以父ID为ID的点,说明是当前点是顶级节点 + SumTree tSumTree = getTreeDotByT(t, list); + sumTrees.add(tSumTree); + } + } + } + return sumTrees; + } + + /** + * 将List转换为Tree(个别过滤子集) + */ + public static List> convertListToTreeDotFilter(List tList) { + List> sumTrees = new ArrayList<>(); + if (tList != null && tList.size() > 0) { + List list = new ArrayList<>(); + CollectionUtils.addAll(list, tList); + for (int i = 0; i < tList.size(); i++) { + T t = tList.get(i); + if (!isTreeDotExist(tList, t.getParentId())) { + // 不存在以父ID为ID的点,说明是当前点是顶级节点 + SumTree tSumTree = getTreeDotByT(t, list); + if ("-1".equals(tSumTree.getParentId()) || "0".equals(tSumTree.getParentId())) { + sumTrees.add(tSumTree); + } + } + } + } + return sumTrees; + } + + /** + * 根据ID判断该点是否存在 + * + * @param tList + * @param id 点ID + * @return java.lang.Boolean + * @MethosName isTreeDotExist + * @Author xiaowd + * @Date 2020/4/22 9:50 + */ + private static Boolean isTreeDotExist(List tList, String id) { + for (T t : tList) { + if (t.getId().equals(id)) { + return true; + } + } + return false; + } + + /** + * 获取指定父点的子树 + * + * @param parentTreeDot 父点 + * @param tList + * @return java.util.List> + * @MethosName getChildTreeList + * @Author xiaowd + * @Date 2020/4/22 10:02 + */ + private static List> getChildTreeDotList(SumTree parentTreeDot, List tList) { + List> childTreeDotList = new ArrayList<>(); + List data = tList.stream().filter(t -> parentTreeDot.getId().equals(t.getParentId())) + .collect(Collectors.toList()); + tList.removeAll(data); + for (T t : data) { + if (parentTreeDot.getId().equals(t.getParentId())) { + // 如果父ID是传递树点的ID,那么就是传递树点的子点 + SumTree tSumTree = getTreeDotByT(t, tList); + childTreeDotList.add(tSumTree); + } + } + return childTreeDotList; + } + + /** + * 根据实体获取TreeDot + * + * @param t + * @param tList + * @return pri.xiaowd.layui.pojo.TreeDot + * @MethosName getTreeDotByT + * @Author xiaowd + * @Date 2020/5/4 22:17 + */ + private static SumTree getTreeDotByT(T t, List tList) { + SumTree sumTree = t; + List> children = getChildTreeDotList(sumTree, tList); + sumTree.setHasChildren(children.size() == 0 ? false : true); + if (children.size() == 0) { + children = null; + } + sumTree.setChildren(children); + return sumTree; + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeListModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeListModel.java new file mode 100644 index 0000000..c57b1bb --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeListModel.java @@ -0,0 +1,49 @@ +package com.yunzhupaas.util.treeutil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.Map; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Data +public class TreeListModel { + /** + *主键 + */ + private String id; + /** + *名称 + */ + private String text; + /** + *节点 + */ + private String parentId; + /** + *表示此节点是否展开 + */ + private Boolean expanded; + /** + *表示是否加载完成 + */ + private Boolean loaded; + /** + *表示此数据是否为叶子节点 + */ + private Boolean isLeaf; + /** + *表示此数据在哪一级 + */ + private Integer level; + /** + *存储对象 + */ + private Map ht; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeModel.java new file mode 100644 index 0000000..02f295c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeModel.java @@ -0,0 +1,24 @@ +package com.yunzhupaas.util.treeutil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * 需要实现树的类可以继承该类,手写set方法,在设定本身属性值时同时设置该类中的相关属性 + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:56 + */ +@Data +public class TreeModel { + private String id; + private String fullName; + private String parentId; + private Boolean hasChildren = true; + private String icon; + private List> children = new ArrayList<>(); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeViewModel.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeViewModel.java new file mode 100644 index 0000000..85ad08c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/TreeViewModel.java @@ -0,0 +1,33 @@ +package com.yunzhupaas.util.treeutil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:56 + */ +@Data +public class TreeViewModel { + private String id; + private String code; + private String text; + private String title; + private String parentId; + private Integer checkstate; + private Boolean showcheck = true; + private Boolean isexpand = true; + private Boolean complete = true; + private String img; + private String cssClass; + private Boolean hasChildren; + private Map ht; + private Boolean click; + private List childNodes; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/newtreeutil/TreeDotUtils.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/newtreeutil/TreeDotUtils.java new file mode 100644 index 0000000..40cb96b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/newtreeutil/TreeDotUtils.java @@ -0,0 +1,183 @@ +package com.yunzhupaas.util.treeutil.newtreeutil; + +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.treeutil.SumTree; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.*; +import java.util.stream.Collectors; + +/*** + * 树工具 + * + * @ClassName TreeDotUtils + * @Author yunzhupaas + * @DateTime 2020/4/22 9:14 + */ +public class TreeDotUtils { + + /** + * 获取指定对象下的所有子集 + */ + public static List> convertListToTreeDot(Collection tList, String parentId) { + List> sumTrees = new ArrayList<>(); + List list = new ArrayList<>(); + CollectionUtils.addAll(list, tList); + if (StringUtil.isNotEmpty(parentId)) { + List data = list.stream().filter(t -> parentId.equals(t.getParentId())).collect(Collectors.toList()); + list.removeAll(data); + Map maps = tList.stream().collect( + Collectors.toMap(T::getId, v -> v, (k1, k2) -> k2, () -> new LinkedHashMap<>(tList.size(), 1))); + Map>> parentsMap = getParentsMap(maps); + for (int i = 0; i < data.size(); i++) { + T t = data.get(i); + if (!maps.containsKey(t.getParentId())) { + parentsMap.remove(t.getParentId()); + SumTree tSumTree = getTreeDotByT(t, maps, parentsMap); + sumTrees.add(tSumTree); + } + } + } + return sumTrees; + } + + /** + * 将List转换为Tree + */ + public static List> convertListToTreeDot(Collection tList) { + Map maps = tList.stream().collect( + Collectors.toMap(T::getId, v -> v, (k1, k2) -> k2, () -> new LinkedHashMap<>(tList.size(), 1))); + return convertMapsToTreeDot(maps); + } + + /** + * 将List转换为Tree + */ + public static List> convertMapsToTreeDot(Map maps) { + List> sumTrees = new ArrayList<>(); + Map>> parentsMap = getParentsMap(maps); + if (maps != null && maps.size() > 0) { + for (T t : maps.values()) { + if (!maps.containsKey(t.getParentId())) { + parentsMap.remove(t.getParentId()); + // 不存在以父ID为ID的点,说明是当前点是顶级节点 + SumTree tSumTree = getTreeDotByT(t, maps, parentsMap); + sumTrees.add(tSumTree); + } + } + } + return sumTrees; + } + + /** + * 将List转换为Tree(个别过滤子集) + */ + public static List> convertListToTreeDotFilter(Collection tList) { + Map maps = tList.stream().collect( + Collectors.toMap(T::getId, v -> v, (k1, k2) -> k2, () -> new LinkedHashMap<>(tList.size(), 1))); + return convertListToTreeDotFilterMaps(maps); + } + + /** + * 将List转换为Tree(个别过滤子集)(父ID必须为-1或者0) + */ + public static List> convertListToTreeDotFilterMaps(Map maps) { + List> sumTrees = new ArrayList<>(); + Map>> parentsMap = getParentsMap(maps); + if (maps != null && maps.size() > 0) { + for (T t : maps.values()) { + if (!maps.containsKey(t.getParentId())) { + parentsMap.remove(t.getParentId()); + // 不存在以父ID为ID的点,说明是当前点是顶级节点 + SumTree tSumTree = getTreeDotByT(t, maps, parentsMap); + if ("-1".equals(tSumTree.getParentId()) || "0".equals(tSumTree.getParentId())) { + sumTrees.add(tSumTree); + } + } + } + } + return sumTrees; + } + + private static Map>> getParentsMap(Map maps) { + Map>> parentsMap = new LinkedHashMap<>(maps.size(), 1); + for (T value : maps.values()) { + List> childs; + if (parentsMap.containsKey(value.getParentId())) { + childs = parentsMap.get(value.getParentId()); + } else { + childs = new LinkedList<>(); + } + childs.add(value); + parentsMap.put(value.getParentId(), childs); + } + return parentsMap; + } + + /** + * 根据ID判断该点是否存在 + * + * @param tList + * @param id 点ID + * @return java.lang.Boolean + * @MethosName isTreeDotExist + * @Author xiaowd + * @Date 2020/4/22 9:50 + */ + private static Boolean isTreeDotExist(List tList, String id) { + for (T t : tList) { + if (t.getId().equals(id)) { + return true; + } + } + return false; + } + + /** + * 获取指定父点的子树 + * + * @param parentTreeDot 父点 + * @param tList + * @return java.util.List> + * @MethosName getChildTreeList + * @Author xiaowd + * @Date 2020/4/22 10:02 + */ + private static List> getChildTreeDotList(SumTree parentTreeDot, + Map maps, Map>> parentsMap) { + List> childTreeDotList; + if (parentsMap.containsKey(parentTreeDot.getId())) { + childTreeDotList = parentsMap.get(parentTreeDot.getId()); + childTreeDotList.forEach(t -> { + // 如果父ID是传递树点的ID,那么就是传递树点的子点 + getTreeDotByT((T) t, maps, parentsMap); + }); + } else { + childTreeDotList = Collections.EMPTY_LIST; + } + return childTreeDotList; + } + + /** + * 根据实体获取TreeDot + * + * @param t + * @param tList + * @return pri.xiaowd.layui.pojo.TreeDot + * @MethosName getTreeDotByT + * @Author xiaowd + * @Date 2020/5/4 22:17 + */ + private static SumTree getTreeDotByT(T t, Map maps, + Map>> parentsMap) { + SumTree sumTree = t; + List> children = getChildTreeDotList(t, maps, parentsMap); + sumTree.setHasChildren(children.size() == 0 ? false : true); + if (children.size() == 0) { + children = null; + } + sumTree.setChildren(children); + return sumTree; + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/newtreeutil/TreeDotUtils2.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/newtreeutil/TreeDotUtils2.java new file mode 100644 index 0000000..e960166 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/treeutil/newtreeutil/TreeDotUtils2.java @@ -0,0 +1,144 @@ +package com.yunzhupaas.util.treeutil.newtreeutil; + +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.treeutil.SumTree; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 树工具 + * + * @author 云筑产品开发平台组 + * @version V3.3.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/1/27 + */ +public class TreeDotUtils2 { + + /** + * 将 List 转换为 Tree + */ + public static > List> convertListToTreeDot(List tList, String parentId) { + List> sumTrees = new ArrayList<>(); + List list = new ArrayList<>(); + CollectionUtils.addAll(list, tList); + if (StringUtil.isNotEmpty(parentId)) { + List data = list.stream().filter(t -> parentId.equals(t.getParentId())).collect(Collectors.toList()); + list.removeAll(data); + for (int i = 0; i < data.size(); i++) { + T t = data.get(i); + if (!isTreeDotExist(list, t.getParentId())) { + SumTree tSumTree = getTreeDotByT(t, list); + sumTrees.add(tSumTree); + } + } + } + return sumTrees; + } + + /** + * 将 List 转换为 Tree + */ + public static > List> convertListToTreeDot(List tList) { + List> sumTrees = new ArrayList<>(); + if (tList != null && tList.size() > 0) { + for (int i = 0; i < tList.size(); i++) { + T t = tList.get(i); + if (!isTreeDotExist(tList, t.getParentId())) { + // 不存在以父ID为ID的点,说明是当前点是顶级节点 + SumTree tSumTree = getTreeDotByT(t, tList); + sumTrees.add(tSumTree); + } + } + } + return sumTrees; + } + + /** + * 将 List 转换为 Tree(个别过滤子集) + */ + public static > List> convertListToTreeDotFilter(List tList) { + List> sumTrees = new ArrayList<>(); + if (tList != null && tList.size() > 0) { + for (int i = 0; i < tList.size(); i++) { + T t = tList.get(i); + if (!isTreeDotExist(tList, t.getParentId())) { + // 不存在以父ID为ID的点,说明是当前点是顶级节点 + SumTree tSumTree = getTreeDotByT(t, tList); + if ("-1".equals(tSumTree.getParentId()) || "0".equals(tSumTree.getParentId())) { + sumTrees.add(tSumTree); + } + } + } + } + return sumTrees; + } + + /** + * 根据ID判断该点是否存在 + * + * @param tList + * @param id 点ID + * @return java.lang.Boolean + * @MethosName isTreeDotExist + * @Author xiaowd + * @Date 2020/4/22 9:50 + */ + private static > Boolean isTreeDotExist(List tList, String id) { + for (T t : tList) { + if (t.getId().equals(id)) { + return true; + } + } + return false; + } + + /** + * 获取指定父点的子树 + * + * @param parentTreeDot 父点 + * @param tList + * @return java.util.List> + * @MethosName getChildTreeList + * @Author xiaowd + * @Date 2020/4/22 10:02 + */ + private static > List> getChildTreeDotList(SumTree parentTreeDot, + List tList) { + List> childTreeDotList = new ArrayList<>(); + List data = tList.stream().filter(t -> parentTreeDot.getId().equals(t.getParentId())) + .collect(Collectors.toList()); + for (T t : data) { + if (parentTreeDot.getId().equals(t.getParentId())) { + // 如果父ID是传递树点的ID,那么就是传递树点的子点 + SumTree tSumTree = getTreeDotByT(t, tList); + childTreeDotList.add(tSumTree); + } + } + return childTreeDotList; + } + + /** + * 根据实体获取 TreeDot + * + * @param t + * @param tList + * @return pri.xiaowd.layui.pojo.TreeDot + * @MethosName getTreeDotByT + * @Author xiaowd + * @Date 2020/5/4 22:17 + */ + @SuppressWarnings("unchecked") + private static > SumTree getTreeDotByT(T t, List tList) { + SumTree sumTree = (SumTree) t; + List> children = getChildTreeDotList(sumTree, tList); + sumTree.setHasChildren(children.size() == 0 ? false : true); + if (children.size() == 0) { + children = null; + } + sumTree.setChildren(children); + return sumTree; + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/AuthorizeType.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/AuthorizeType.java new file mode 100644 index 0000000..c5b5486 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/AuthorizeType.java @@ -0,0 +1,48 @@ +package com.yunzhupaas.util.type; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 权限类型常量表 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-23 + */ +@Data +public class AuthorizeType { + /** + * 用户权限 + */ + public static final String USER = "User"; + /** + * 岗位权限 + */ + public static final String POSITION = "Position"; + /** + * 角色权限 + */ + public static final String ROLE = "Role"; + /** + * 按钮权限 + */ + public static final String BUTTON = "button"; + /** + * 菜单权限 + */ + public static final String MODULE = "module"; + /** + * 列表权限 + */ + public static final String COLUMN = "column"; + /** + * 数据权限 + */ + public static final String RESOURCE = "resource"; + /** + * 表单权限 + */ + public static final String FORM = "form"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/CompareType.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/CompareType.java new file mode 100644 index 0000000..bc9518d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/CompareType.java @@ -0,0 +1,14 @@ +package com.yunzhupaas.util.type; + +/** + * 运算符常量 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-23 + */ +public class CompareType { + public static final String EQUALS = "="; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/IntegerNumber.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/IntegerNumber.java new file mode 100644 index 0000000..4bf5226 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/IntegerNumber.java @@ -0,0 +1,24 @@ +package com.yunzhupaas.util.type; + +/** + * int类型数字常用常量 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-23 + */ +public class IntegerNumber { + public static final int YUNZHUPAAS = 0; + public static final int ONE = 1; + public static final int TWO = 2; + public static final int THREE = 3; + public static final int FOUR = 4; + public static final int FIVE = 5; + public static final int SIX = 6; + public static final int SEVEN = 7; + public static final int EIGHT = 8; + public static final int NINE = 9; + public static final int TEN = 10; + public static final int ELEVEN = 11; +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/MethodType.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/MethodType.java new file mode 100644 index 0000000..6b1eaa0 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/MethodType.java @@ -0,0 +1,38 @@ +package com.yunzhupaas.util.type; + +/** + * 请求方法枚举类 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-23 + */ +public enum MethodType { + /** + * GET请求 + */ + GET("GET"), + /** + * POST 请求 + */ + POST("POST"), + /** + * PUT 请求 + */ + PUT("PUT"),; + private String method; + + MethodType(String method) { + this.method = method; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/RequestType.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/RequestType.java new file mode 100644 index 0000000..5c66ae0 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/RequestType.java @@ -0,0 +1,16 @@ +package com.yunzhupaas.util.type; + +/** + * 请求方式常量 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-23 + */ +public class RequestType { + public static final String HTTP = "http"; + + public static final String HTTPS = "https"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/SortType.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/SortType.java new file mode 100644 index 0000000..8fa446f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/SortType.java @@ -0,0 +1,24 @@ +package com.yunzhupaas.util.type; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 排序类型 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-23 + */ +@Data +public class SortType { + /** + * 升序 + */ + public static final String ASC = "asc"; + /** + * 降序 + */ + public static final String DESC = "desc"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/StringNumber.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/StringNumber.java new file mode 100644 index 0000000..656c6aa --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/type/StringNumber.java @@ -0,0 +1,25 @@ +package com.yunzhupaas.util.type; + +/** + * String类型数字常用常量 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-23 + */ +public class StringNumber { + public static final String YUNZHUPAAS = "0"; + public static final String ONE = "1"; + public static final String TWO = "2"; + public static final String THREE = "3"; + public static final String FOUR = "4"; + public static final String FIVE = "5"; + public static final String SIX = "6"; + public static final String SEVEN = "7"; + public static final String EIGHT = "8"; + public static final String NINE = "9"; + public static final String TEN = "10"; + public static final String FAILCODE = "500"; + public static final String EXCEPTIONCODE = "400"; +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/visiual/DataTypeConst.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/visiual/DataTypeConst.java new file mode 100644 index 0000000..7500878 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/visiual/DataTypeConst.java @@ -0,0 +1,50 @@ +package com.yunzhupaas.util.visiual; + +/** + * + * 模板数据类型等等常量 + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-15 + */ +public class DataTypeConst { + + /** + * 数据字典DataType + */ + public static final String DICTIONARY="dictionary"; + + /** + * 静态数据DataType + */ + public static final String STATIC="static"; + + /** + * 查询字段数据 + */ + public static final String KEY_JSON_MAP="keyJsonMap"; + + /** + * 远程数据DataType + */ + public static final String DYNAMIC="dynamic"; + + /** + * 时间控件 + */ + public static final String TIME_CONTROL="timeControl"; + + /** + * 数据字典DataType + */ + public static final String VALUE="value"; + + /** + * 可视化数据列表结果key + */ + public static final String LIST="list"; + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/visiual/YunzhupaasKeyConsts.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/visiual/YunzhupaasKeyConsts.java new file mode 100644 index 0000000..5dbb7a3 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/visiual/YunzhupaasKeyConsts.java @@ -0,0 +1,409 @@ +package com.yunzhupaas.util.visiual; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * yunzhupaasKey类型 + * + * @author lhr + * @create 2018/1/9 + */ + +public class YunzhupaasKeyConsts { + /** + * 单行 + */ + public static final String COM_INPUT = "input"; + + /** + * 多行 + */ + public static final String TEXTAREA = "textarea"; + + /** + * 单选 + */ + public static final String RADIO = "radio"; + + /** + * 开关 + */ + public static final String SWITCH = "switch"; + + /** + * 下拉框 + */ + public static final String SELECT = "select"; + + /** + * 多选框 + */ + public static final String CHECKBOX = "checkbox"; + /** + * 公司 + */ + public static final String COMSELECT = "organizeSelect"; + /** + * 部门 + */ + public static final String DEPSELECT = "depSelect"; + /** + * 數據字典 + */ + public static final String DICSELECT = "dicSelect"; + /** + * 岗位 + */ + public static final String POSSELECT = "posSelect"; + /** + * 用户 + */ + public static final String USERSELECT = "userSelect"; + + /** + * 用户 + */ + public static final String CUSTOMUSERSELECT = "usersSelect"; + + /** + * 角色选择 + */ + public static final String ROLESELECT = "roleSelect"; + + /** + * 分组选择 + */ + public static final String GROUPSELECT = "groupSelect"; + /** + * 行政区划 + */ + public static final String ADDRESS = "areaSelect"; + /** + * 时间范围 + */ + public static final String TIMERANGE = "timeRange"; + /** + * 日期范围 + */ + public static final String DATERANGE = "dateRange"; + /** + * 时间选择 + */ + public static final String TIME = "timePicker"; + /** + * 日期选择 + */ + public static final String DATE = "datePicker"; + + /** + * 评分 + */ + public static final String RATE = "rate"; + + /** + * 附件 + */ + public static final String UPLOADFZ = "uploadFile"; + /** + * 图片 + */ + public static final String UPLOADIMG = "uploadImg"; + /** + * 滑块 + */ + public static final String SLIDER = "slider"; + /** + * 所属组织 + */ + public static final String CURRORGANIZE = "currOrganize"; + /** + * 所属部门 + */ + public static final String CURRDEPT = "currDept"; + /** + * 创建用户 + */ + public static final String CREATEUSER = "createUser"; + /** + * 创建时间 + */ + public static final String CREATETIME = "createTime"; + /** + * 修改用户 + */ + public static final String MODIFYUSER = "modifyUser"; + /** + * 修改时间 + */ + public static final String MODIFYTIME = "modifyTime"; + /** + * 所属岗位 + */ + public static final String CURRPOSITION = "currPosition"; + /** + * 单据规则 + */ + public static final String BILLRULE = "billRule"; + + /** + * 功能关联表单 + */ + public static final String RELATIONFORM = "relationForm"; + + /** + * 关联表单属性 + */ + public static final String RELATIONFORM_ATTR = "relationFormAttr"; + + /** + * 工作流关联表单 + */ + public static final String RELATIONFLOW = "relationFlow"; + + /** + * 树形选择 + */ + public static final String TREESELECT = "treeSelect"; + + /** + * 级联选择 + */ + public static final String CASCADER = "cascader"; + + /** + * 子表Yunzhupaaskey + */ + public static final String CHILD_TABLE = "table"; + + /** + * 弹窗选择 + */ + public static final String POPUPSELECT = "popupSelect"; + /** + * 下拉表格 + */ + public static final String POPUPTABLESELECT = "popupTableSelect"; + /** + * 弹窗选择属性 + */ + public static final String POPUPSELECT_ATTR = "popupAttr"; + /** + * 数字输入 + */ + public static final String NUM_INPUT = "inputNumber"; + /** + * 计算公式 + */ + public static final String CALCULATE = "calculate"; + /** + * 分组标题 + */ + public static final String GROUP_TITLE = "groupTitle"; + + /** + * 二维码 + */ + public static final String QR_CODE = "qrcode"; + + /** + * 条形码 + */ + public static final String BARCODE = "barcode"; + + /** + * 富文本 + */ + public static final String EDITOR = "editor"; + + /** + * 颜色选择 + */ + public static final String CPLOR_PICKER = "colorPicker"; + + /** + * 分割线 + */ + public static final String DIVIDER = "divider"; + + /** + * 按钮 + */ + public static final String BUTTON = "button"; + + /** + * 链接 + */ + public static final String LINK = "link"; + + /** + * 提示 + */ + public static final String ALERT = "alert"; + + /** + * 卡片容器 + */ + public static final String CARD = "card"; + + /** + * 栅格容器 + */ + public static final String ROW = "row"; + + /** + * 标签面板 + */ + public static final String TAB = "tab"; + + /** + * 折叠面板 + */ + public static final String COLLAPSE = "collapse"; + + /** + * 定位 + */ + public static final String LOCATION = "location"; + + /** + * 手写签名 + */ + public static final String SIGN = "sign"; + + /** + * iframe + */ + public static final String IFRAME = "iframe"; + + /** + * 电子签章 + */ + public static final String SIGNATURE = "signature"; + + /** + * 下拉补全 + */ + public static final String AUTO_COMPLETE = "autoComplete"; + + /** + * 列表关键词-key + */ + public static final String YUNZHUPAASKEYWORD = "yunzhupaasKeyword"; + + /** + * 子表前缀 + */ + public static final String CHILD_TABLE_PREFIX = "tablefield"; + + public static final List SplitKey = new ArrayList() { + { + add(YunzhupaasKeyConsts.DATE); + add(YunzhupaasKeyConsts.TIME); + add(YunzhupaasKeyConsts.NUM_INPUT); + add(YunzhupaasKeyConsts.CREATETIME); + add(YunzhupaasKeyConsts.MODIFYTIME); + } + }; + + public static final List BaseSelect = new ArrayList() { + { + add(YunzhupaasKeyConsts.COM_INPUT); + add(YunzhupaasKeyConsts.TEXTAREA); + add(YunzhupaasKeyConsts.BILLRULE); + add(YunzhupaasKeyConsts.POPUPTABLESELECT); + add(YunzhupaasKeyConsts.RELATIONFORM); + add(YunzhupaasKeyConsts.RELATIONFORM_ATTR); + add(YunzhupaasKeyConsts.POPUPSELECT); + add(YunzhupaasKeyConsts.POPUPSELECT_ATTR); + } + }; + + public static final List SelectIgnore = new ArrayList() { + { + add(YunzhupaasKeyConsts.COMSELECT); + add(YunzhupaasKeyConsts.ADDRESS); + add(YunzhupaasKeyConsts.CASCADER); + add(YunzhupaasKeyConsts.CHECKBOX); + add(YunzhupaasKeyConsts.CURRORGANIZE); + add(YunzhupaasKeyConsts.CUSTOMUSERSELECT); + } + }; + + public static final List NumSelect = new ArrayList() { + { + add(YunzhupaasKeyConsts.CALCULATE); + add(YunzhupaasKeyConsts.NUM_INPUT); + add(YunzhupaasKeyConsts.RATE); + add(YunzhupaasKeyConsts.SLIDER); + } + }; + + public static final List DateSelect = new ArrayList() { + { + add(YunzhupaasKeyConsts.DATE); + add(YunzhupaasKeyConsts.CREATETIME); + add(YunzhupaasKeyConsts.MODIFYTIME); + } + }; + + /** + * 导入不支持控件 + */ + public static final List getUploadMaybeNull() { + return Arrays.asList(UPLOADFZ, UPLOADIMG, CPLOR_PICKER, DIVIDER, BUTTON, LINK, ALERT, POPUPTABLESELECT, + RELATIONFORM, POPUPSELECT, + RELATIONFORM_ATTR, POPUPSELECT_ATTR, QR_CODE, BARCODE, CALCULATE, GROUP_TITLE, CARD, ROW, TAB, COLLAPSE, + CREATEUSER, + CREATETIME, MODIFYUSER, MODIFYTIME, CURRORGANIZE, CURRDEPT, CURRPOSITION, SIGN, LOCATION, IFRAME, + SIGNATURE); + } + + /** + * 获取系统控件keylist + */ + public static final List getSystemKey() { + return Arrays.asList(CREATEUSER, CREATETIME, MODIFYUSER, MODIFYTIME, CURRORGANIZE, CURRDEPT, CURRPOSITION); + } + + /** + * 获取text字段(oracle和DM字段需要dbms_lob.substr()) + */ + public static final List getTextField() { + return Arrays.asList(UPLOADFZ, UPLOADIMG, EDITOR, SIGN); + } + + /** + * 存储数据结构可能为数组控件 + */ + public static final List getArraysKey() { + return Arrays.asList(UPLOADFZ, UPLOADIMG, SELECT, DEPSELECT, ROLESELECT, USERSELECT, CUSTOMUSERSELECT, + COMSELECT, + TREESELECT, POSSELECT, GROUPSELECT, ADDRESS, CASCADER, CURRORGANIZE, CHECKBOX, POPUPTABLESELECT); + } + + /** + * 日志-显示已修改控件 + */ + public static final List getNameModified() { + return Arrays.asList(RADIO, CHECKBOX, SELECT, CASCADER, TREESELECT, POPUPTABLESELECT, POPUPSELECT, RELATIONFORM, + UPLOADIMG, EDITOR); + } + + /** + * 日志-显示已修改控件 + * RADIO, CHECKBOX, SELECT,CASCADER,TREESELECT -动态接口展示为已修改 + * POPUPTABLESELECT,POPUPSELECT,RELATIONFORM,UPLOADIMG,EDITOR -都展示为已修改 + */ + public static final List getNameModifiedNotDynamic() { + return Arrays.asList(POPUPTABLESELECT, POPUPSELECT, RELATIONFORM, UPLOADIMG, EDITOR); + } + + /** + * 可直接查询字段类型 + */ + public static final List getKeyWordList() { + return Arrays.asList(COM_INPUT, NUM_INPUT, TEXTAREA, AUTO_COMPLETE); + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/wxutil/HttpUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/wxutil/HttpUtil.java new file mode 100644 index 0000000..ce53b4e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/wxutil/HttpUtil.java @@ -0,0 +1,705 @@ +package com.yunzhupaas.util.wxutil; + +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.ImmutableMap; +import com.yunzhupaas.util.*; +import com.yunzhupaas.util.context.SpringContext; +import lombok.Cleanup; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpEntity; +import org.apache.http.NameValuePair; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.entity.mime.content.FileBody; +import org.apache.http.entity.mime.content.StringBody; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.ssl.SSLContexts; +import org.apache.http.util.EntityUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; + +import javax.net.ssl.SSLContext; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:49 + */ +@Slf4j +public class HttpUtil { + + private HttpUtil() { + throw new IllegalAccessError("工具类不能实例化"); + } + + private static PoolingHttpClientConnectionManager connectionManager = null; + + private static RequestConfig requestConfig = RequestConfig.custom() + .setSocketTimeout(5000) + .setConnectTimeout(5000) + .setConnectionRequestTimeout(3000) + .build(); + + static { + SSLContext sslcontext = SSLContexts.createSystemDefault(); + Registry socketFactoryRegistry = + RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.INSTANCE) + .register("https", new SSLConnectionSocketFactory(sslcontext)).build(); + connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + connectionManager.setMaxTotal(1000); + // 每个路由最大的请求数量 + connectionManager.setDefaultMaxPerRoute(200); + } + + public static CloseableHttpClient getHttpClient() { + return getHttpClientBuilder().build(); + } + + public static CloseableHttpClient getHttpClient(SSLContext sslContext) { + return getHttpClientBuilder(sslContext).build(); + } + + public static HttpClientBuilder getHttpClientBuilder() { + return HttpClients.custom().setConnectionManager(connectionManager).setDefaultRequestConfig(requestConfig); + } + + public static HttpClientBuilder getHttpClientBuilder(SSLContext sslContext) { + if (sslContext != null) { + return getHttpClientBuilder().setSSLContext(sslContext); + } else { + return getHttpClientBuilder(); + } + + } + + /** + * post 请求 + * + * @param httpUrl 请求地址 + * @param sslContext ssl证书信息 + * @return + */ + public static String sendHttpPost(String httpUrl, SSLContext sslContext) { + // 创建httpPost + HttpPost httpPost = new HttpPost(httpUrl); + return sendHttpPost(httpPost, sslContext); + } + + /** + * 发送 post请求 + * + * @param httpUrl 地址 + */ + public static String sendHttpPost(String httpUrl) { + // 创建httpPost + HttpPost httpPost = new HttpPost(httpUrl); + return sendHttpPost(httpPost, null); + } + + /** + * 发送 post请求 + * + * @param httpUrl 地址 + * @param params 参数(格式:key1=value1&key2=value2) + */ + public static String sendHttpPost(String httpUrl, String params) { + return sendHttpPost(httpUrl, params, null); + } + + /** + * 发送 post请求 + * + * @param httpUrl 地址 + * @param params 参数(格式:key1=value1&key2=value2) + * @param sslContext ssl证书信息 + */ + public static String sendHttpPost(String httpUrl, String params, SSLContext sslContext) { + // 创建httpPost + HttpPost httpPost = new HttpPost(httpUrl); + try { + // 设置参数 + StringEntity stringEntity = new StringEntity(params, Constants.UTF8); + stringEntity.setContentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE); + httpPost.setEntity(stringEntity); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return sendHttpPost(httpPost, sslContext); + } + + /** + * 发送 post请求 + * + * @param httpUrl 地址 + * @param maps 参数 + */ + public static String sendHttpPost(String httpUrl, Map maps) { + return sendHttpPost(httpUrl, maps, null); + } + + /** + * 发送 post请求 + * + * @param httpUrl 地址 + * @param maps 参数 + * @param sslContext ssl证书信息 + */ + public static String sendHttpPost(String httpUrl, Map maps, SSLContext sslContext) { + HttpPost httpPost = wrapHttpPost(httpUrl, maps); + return sendHttpPost(httpPost, null); + } + + /** + * 封装获取HttpPost方法 + * + * @param httpUrl + * @param maps + * @return + */ + public static HttpPost wrapHttpPost(String httpUrl, Map maps) { + // 创建httpPost + HttpPost httpPost = new HttpPost(httpUrl); + // 创建参数队列 + List nameValuePairs = new ArrayList<>(); + for (Map.Entry m : maps.entrySet()) { + nameValuePairs.add(new BasicNameValuePair(m.getKey(), m.getValue())); + } + try { + httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, Constants.UTF8)); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + + return httpPost; + } + + /** + * 发送 post请求(带文件) + * + * @param httpUrl 地址 + * @param file 附件,名称和File对应 + */ + public static String sendHttpPost(String httpUrl, File file) { + return sendHttpPost(httpUrl, ImmutableMap.of("media", file), null, null); + } + + /** + * 发送 post请求(带文件) + * + * @param httpUrl 地址 + * @param file 附件,名称和File对应 + * @param maps 参数 + */ + public static String sendHttpPost(String httpUrl, File file, Map maps) { + return sendHttpPost(httpUrl, ImmutableMap.of("media", file), maps, null); + } + + /** + * 发送 post请求(带文件),默认 files 名称数组. + * + * @param httpUrl 地址 + * @param fileLists 附件 + * @param maps 参数 + */ + public static String sendHttpPost(String httpUrl, List fileLists, Map maps) { + return sendHttpPost(httpUrl, fileLists, maps, null); + } + + /** + * 发送 post请求(带文件) + * + * @param httpUrl 地址 + * @param fileMap 附件,名称和File对应 + * @param maps 参数 + */ + public static String sendHttpPost(String httpUrl, Map fileMap, Map maps) { + return sendHttpPost(httpUrl, fileMap, maps, null); + } + + /** + * 发送 post请求(带文件),默认 files 名称数组. + * + * @param httpUrl 地址 + * @param fileLists 附件 + * @param maps 参数 + * @param sslContext ssl证书信息 + */ + public static String sendHttpPost(String httpUrl, List fileLists, Map maps, + SSLContext sslContext) { + Map fileMap = new HashMap<>(16); + if (fileLists == null || fileLists.isEmpty()) { + for (File file : fileLists) { + fileMap.put("media", file); + } + } + return sendHttpPost(httpUrl, fileMap, maps, sslContext); + } + + /** + * 发送 post请求(带文件) + * + * @param httpUrl 地址 + * @param fileMap 附件,名称和File对应 + * @param maps 参数 + * @param sslContext ssl证书信息 + */ + public static String sendHttpPost(String httpUrl, Map fileMap, Map maps, + SSLContext sslContext) { + // 创建httpPost + HttpPost httpPost = new HttpPost(httpUrl); + MultipartEntityBuilder meBuilder = MultipartEntityBuilder.create(); + if (null != maps) { + for (Map.Entry m : maps.entrySet()) { + meBuilder.addPart(m.getKey(), new StringBody(m.getValue(), ContentType.TEXT_PLAIN)); + } + } + if (null != fileMap) { + for (Map.Entry m : fileMap.entrySet()) { + FileBody fileBody = new FileBody(m.getValue()); + meBuilder.addPart(m.getKey(), fileBody); + } + } + + HttpEntity reqEntity = meBuilder.build(); + httpPost.setEntity(reqEntity); + return sendHttpPost(httpPost, sslContext); + } + + /** + * 发送Post请求 + * + * @param httpPost + * @return + */ + public static String sendHttpPost(HttpPost httpPost) { + return sendHttpPost(httpPost, null); + } + + /** + * 发送Post请求 + * + * @param httpPost + * @param sslConext ssl证书信息 + * @return + */ + public static String sendHttpPost(HttpPost httpPost, SSLContext sslConext) { + CloseableHttpClient httpClient = getHttpClient(sslConext); + CloseableHttpResponse response = null; + HttpEntity entity = null; + String responseContent = null; + try { + // 执行请求 + response = httpClient.execute(httpPost); + entity = response.getEntity(); + responseContent = EntityUtils.toString(entity, Constants.UTF8); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + try { + // 关闭连接,释放资源 + if (entity != null) { + // 会自动释放连接 + EntityUtils.consumeQuietly(entity); + } + if (response != null) { + response.close(); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + return responseContent; + } + + /** + * 发送 get请求 + * + * @param httpUrl + */ + public static String sendHttpGet(String httpUrl) { + return sendHttpGet(httpUrl, null); + } + + /** + * 发送 get请求 + * + * @param httpUrl + * @param sslConext ssl证书信息 + */ + public static String sendHttpGet(String httpUrl, SSLContext sslConext) { + // 创建get请求 + HttpGet httpGet = new HttpGet(httpUrl); + return sendHttpGet(httpGet, sslConext); + } + + /** + * 发送Get请求 + * + * @param httpGet + * @return + */ + public static String sendHttpGet(HttpGet httpGet) { + return sendHttpGet(httpGet, null); + } + + /** + * 发送Get请求 + * + * @param httpGet + * @param sslConext ssl证书信息 + * @return + */ + public static String sendHttpGet(HttpGet httpGet, SSLContext sslConext) { + CloseableHttpClient httpClient = getHttpClient(sslConext); + CloseableHttpResponse response = null; + HttpEntity entity = null; + String responseContent = null; + try { + // 执行请求 + response = httpClient.execute(httpGet); + entity = response.getEntity(); + responseContent = EntityUtils.toString(entity, Constants.UTF8); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + try { + // 关闭连接,释放资源 + if (entity != null) { + // 会自动释放连接 + EntityUtils.consumeQuietly(entity); + } + if (response != null) { + response.close(); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + return responseContent; + } + + /** + * 发送 get请求 + * + * @param httpUrl 请求路径 + * @param headers 请求头参数 + * @return + */ + public static String sendHttpHeaderGet(String httpUrl, Map headers) { + // 创建get请求 + HttpGet httpGet = new HttpGet(httpUrl); + for (Map.Entry entry : headers.entrySet()) { + String key = entry.getKey().toString(); + String value = entry.getValue().toString(); + httpGet.setHeader(key, value); + } + return sendHttpGet(httpGet, null); + } + + /** + * Get 下载文件 + * + * @param httpUrl + * @param file + * @return + */ + public static File sendHttpGetFile(String httpUrl, File file) { + if (file == null) { + return null; + } + HttpGet httpGet = new HttpGet(httpUrl); + CloseableHttpClient httpClient = getHttpClient(); + CloseableHttpResponse response = null; + HttpEntity entity = null; + InputStream inputStream = null; + FileOutputStream fileOutputStream = null; + try { + // 执行请求 + response = httpClient.execute(httpGet); + entity = response.getEntity(); + inputStream = entity.getContent(); + fileOutputStream = new FileOutputStream(file); + int len = 0; + byte[] buf = new byte[1024]; + while ((len = inputStream.read(buf, 0, 1024)) != -1) { + fileOutputStream.write(buf, 0, len); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + try { + if (fileOutputStream != null) { + fileOutputStream.close(); + } + if (inputStream != null) { + inputStream.close(); + } + // 关闭连接,释放资源 + if (entity != null) { + // 会自动释放连接 + EntityUtils.consumeQuietly(entity); + } + if (response != null) { + response.close(); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + return file; + } + + /** + * Post 下载文件 + * + * @param httpUrl + * @param maps + * @param file + * @return + */ + public static File sendHttpPostFile(String httpUrl, Map maps, File file) { + if (file == null) { + return null; + } + HttpPost httpPost = wrapHttpPost(httpUrl, maps); + CloseableHttpClient httpClient = getHttpClient(); + CloseableHttpResponse response = null; + HttpEntity entity = null; + InputStream inputStream = null; + FileOutputStream fileOutputStream = null; + try { + // 执行请求 + response = httpClient.execute(httpPost); + entity = response.getEntity(); + inputStream = entity.getContent(); + fileOutputStream = new FileOutputStream(file); + int len = 0; + byte[] buf = new byte[1024]; + while ((len = inputStream.read(buf, 0, 1024)) != -1) { + fileOutputStream.write(buf, 0, len); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + try { + if (fileOutputStream != null) { + fileOutputStream.close(); + } + if (inputStream != null) { + inputStream.close(); + } + // 关闭连接,释放资源 + if (entity != null) { + // 会自动释放连接 + EntityUtils.consumeQuietly(entity); + } + if (response != null) { + response.close(); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + return file; + } + + /** + * 判断是否微信返回错误 + * + * @param jsonObject + * @return + */ + public static boolean isWxError(JSONObject jsonObject) { + if (null == jsonObject || jsonObject.getIntValue("errcode") != 0) { + return true; + } + return false; + } + + /** + * http请求 + * + * @param requestUrl url + * @param requestMethod GET/POST + * @param outputStr 参数 + * @return + */ + public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) { + return httpRequest(requestUrl,requestMethod,outputStr,null); + } + + /** + * http请求 + * + * @param requestUrl url + * @param requestMethod GET/POST + * @param outputStr 参数 + * @return + */ + public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr, String... token) { + JSONObject jsonObject = null; + try { + URL url = new URL(requestUrl); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setUseCaches(false); + conn.setRequestMethod(requestMethod); + conn.setConnectTimeout(50000); + conn.setReadTimeout(60000); + if (token != null && token.length > 2 && token[2] != null) { + if ("1".equals(token[2])) { + conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE); + } else if ("2".equals(token[2])) { + conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE); + } else if ("3".equals(token[2])) { + conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + } else if ("4".equals(token[2])) { + conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE); + } else { + conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + } + } else { + conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + } + + if (token != null && token.length > 0 && StringUtil.isNotEmpty(token[0])) { + conn.setRequestProperty(Constants.AUTHORIZATION, XSSEscape.escape(token[0])); + } + // 处理请求头参数 + if (token != null && token.length > 1 && StringUtil.isNotEmpty(token[1])) { + Map requestHeader = JsonUtil.stringToMap(token[1]); + for (String field : requestHeader.keySet()) { + conn.setRequestProperty(field, requestHeader.get(field) + ""); + } + } + String agent = ServletUtil.getUserAgent(); + if (StringUtil.isNotEmpty(agent)) { + conn.setRequestProperty(Constants.USER_AGENT, agent); + } + if (StringUtil.isNotEmpty(outputStr)) { + @Cleanup OutputStream outputStream = conn.getOutputStream(); + outputStream.write(outputStr.getBytes(Constants.UTF8)); + outputStream.close(); + } + @Cleanup InputStream inputStream = conn.getInputStream(); + @Cleanup InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Constants.UTF8); + @Cleanup BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + String str = null; + StringBuffer buffer = new StringBuffer(); + while ((str = bufferedReader.readLine()) != null) { + buffer.append(str); + } + bufferedReader.close(); + inputStreamReader.close(); + inputStream.close(); + conn.disconnect(); + jsonObject = JSONObject.parseObject(buffer.toString()); + if (jsonObject == null) { + return new JSONObject(); + } + } catch (Exception e) { + log.error(e.getMessage()); + } + return jsonObject; + } + + /** + * http请求 + * + * @param requestUrl url + * @param requestMethod GET/POST + * @param outputStr 参数 + * @return + */ + public static boolean httpCronRequest(String requestUrl, String requestMethod, String outputStr, String token) { + boolean falg = false; + try { + URL url = new URL(requestUrl); + final HttpURLConnection[] conn = {null}; + Callable task = new Callable() { + @Override + public String call() throws Exception { + //执行耗时代码 + try { + conn[0] = (HttpURLConnection) url.openConnection(); + } catch (Exception e) { + log.error(e.getMessage()); + } + conn[0].setDoOutput(true); + conn[0].setDoInput(true); + conn[0].setUseCaches(false); + conn[0].setRequestMethod(requestMethod); + conn[0].setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + if (StringUtil.isNotEmpty(token)) { + conn[0].setRequestProperty(Constants.AUTHORIZATION, token); + } + if (null != outputStr) { + @Cleanup OutputStream outputStream = conn[0].getOutputStream(); + outputStream.write(outputStr.getBytes(Constants.UTF8)); + outputStream.close(); + } + @Cleanup InputStream inputStream = conn[0].getInputStream(); + @Cleanup InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Constants.UTF8); + @Cleanup BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + String str = null; + StringBuffer buffer = new StringBuffer(); + while ((str = bufferedReader.readLine()) != null) { + buffer.append(str); + } + bufferedReader.close(); + inputStreamReader.close(); + inputStream.close(); + conn[0].disconnect(); + return "url连接ok"; + } + }; + Future future = ThreadPoolExecutorUtil.getExecutor().submit(task); + try { + //设置超时时间 + String rst = future.get(3, TimeUnit.SECONDS); + if ("url连接ok".equals(rst)) { + falg = true; + } + } catch (TimeoutException e) { + log.error("连接url超时"); + } catch (Exception e) { + log.error("获取异常," + e.getMessage()); + } + } catch (MalformedURLException e) { + e.printStackTrace(); + } + return falg; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/wxutil/MediaFileType.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/wxutil/MediaFileType.java new file mode 100644 index 0000000..a1f244b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/wxutil/MediaFileType.java @@ -0,0 +1,50 @@ +package com.yunzhupaas.util.wxutil; + +/** + * 多媒体文件类型 + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:53 + */ +public enum MediaFileType { + /** + * 图文 + */ + News("news"), + /** + * 图片 + */ + Image("image"), + /** + * 语音 + */ + Voice("voice"), + /** + * 视频 + */ + Video("video"), + /** + * 缩略图 + */ + Thumb("thumb"), + /** + * 文件 + */ + File("file"); + + private String message; + + MediaFileType(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/wxutil/SendPostUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/wxutil/SendPostUtil.java new file mode 100644 index 0000000..83a76e9 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/java/com/yunzhupaas/util/wxutil/SendPostUtil.java @@ -0,0 +1,116 @@ +package com.yunzhupaas.util.wxutil; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.URL; +import java.net.URLConnection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +public class SendPostUtil { + /** + * 向指定URL发送GET方法的请求 + */ + public static String sendGet(String url, String param, Map header) throws IOException { + String result = ""; + BufferedReader in = null; + String urlNameString = url + "?" + param; + URL realUrl = new URL(urlNameString); + // 打开和URL之间的连接 + URLConnection connection = realUrl.openConnection(); + //设置超时时间 + connection.setConnectTimeout(5000); + connection.setReadTimeout(15000); + // 设置通用的请求属性 + if (header!=null) { + Iterator> it =header.entrySet().iterator(); + while(it.hasNext()){ + Map.Entry entry = it.next(); + System.out.println(entry.getKey()+":"+entry.getValue()); + connection.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + + connection.setRequestProperty("accept", "*/*"); + connection.setRequestProperty("connection", "Keep-Alive"); + connection.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + + // 建立实际的连接 + connection.connect(); + // 获取所有响应头字段 + Map> map = connection.getHeaderFields(); + // 遍历所有的响应头字段 + for (String key : map.keySet()) { + System.out.println(key + "--->" + map.get(key)); + } + // 定义 BufferedReader输入流来读取URL的响应,设置utf8防止中文乱码 + in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8")); + String line; + while ((line = in.readLine()) != null) { + result += line; + } + if (in != null) { + in.close(); + } + return result; + } + + /** + * 向指定 URL 发送POST方法的请求 + */ + public static String sendPost(String url, String param, Map header) throws IOException { + PrintWriter out = null; + BufferedReader in = null; + String result = ""; + URL realUrl = new URL(url); + // 打开和URL之间的连接 + URLConnection conn = realUrl.openConnection(); + //设置超时时间 + conn.setConnectTimeout(30000); + conn.setReadTimeout(30000); + // 设置通用的请求属性 + if (header!=null) { + for (Map.Entry entry : header.entrySet()) { + conn.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", + "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + // 发送POST请求必须设置如下两行 + conn.setDoOutput(true); + conn.setDoInput(true); + // 获取URLConnection对象对应的输出流 + out = new PrintWriter(conn.getOutputStream()); + // 发送请求参数 + out.print(param); + // flush输出流的缓冲 + out.flush(); + // 定义BufferedReader输入流来读取URL的响应 + in = new BufferedReader( + new InputStreamReader(conn.getInputStream(), "utf8")); + String line; + while ((line = in.readLine()) != null) { + result += line; + } + if(out!=null){ + out.close(); + } + if(in!=null){ + in.close(); + } + return result; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/AntiSamy_zh_CN.properties b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/AntiSamy_zh_CN.properties new file mode 100644 index 0000000..fb19076 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/AntiSamy_zh_CN.properties @@ -0,0 +1,34 @@ +# General +error.size.toolarge=\u8F93\u5165\u592A\u5927\u3002\u5B9E\u9645\u7684\u8F93\u5165\u4E3A{0}\u5B57\u8282\u3002\u5141\u8BB8\u7684\u6700\u5927\u8F93\u5165\u4E3A{1}\u5B57\u8282\u3002 +error.comment.removed=\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6CE8\u91CA\u57DF\u5DF2\u88AB\u8FC7\u6EE4\u3002\u6CE8\u91CA\u57DF\u7684\u503C\u4E3A{0} +# Tag related +error.tag.notfound=\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6807\u8BB0{0}\u5DF2\u88AB\u8FC7\u6EE4\u3002\u6807\u8BB0\u7684\u5185\u5BB9\u4FDD\u5B58\u4E0D\u53D8\u3002 +error.tag.removed=\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6807\u8BB0{0}\u4E0D\u88AB\u5141\u8BB8\u3002\u6B64\u6807\u8BB0\u4E0D\u5E94\u8BE5\u5F71\u54CD\u8F93\u5165\u7684\u663E\u793A\u3002 +error.tag.filtered=\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6807\u8BB0{0}\u5DF2\u88AB\u8FC7\u6EE4\u3002\u6807\u8BB0\u7684\u5185\u5BB9\u4FDD\u5B58\u4E0D\u53D8\u3002 +error.tag.encoded=The {0} tag has been encoded for security reasons. The contents of the tag will remain in place. +error.tag.empty=\u5728{0}\u7684\u6807\u7B7E\u662F\u7A7A\u7684\uFF0C\u56E0\u6B64\u6211\u4EEC\u65E0\u6CD5\u5904\u7406\u5B83\u3002\u8BE5\u90AE\u4EF6\u7684\u5176\u4F59\u90E8\u5206\u662F\u5B8C\u6574\u7684\uFF0C\u5176\u642C\u8FC1\u5E94\u8BE5\u6CA1\u6709\u4EFB\u4F55\u526F\u4F5C\u7528\u3002 +error.cdata.found=\u4E00\u4E2ACDATA\u90E8\u5206\u88AB\u53D1\u73B0\uFF0C\u8FD9\u662F\u4E0D\u5141\u8BB8\u7684\u3002\u8BE5\u90AE\u4EF6\u7684\u5176\u4F59\u90E8\u5206\u662F\u5B8C\u6574\u7684\uFF0C\u5176\u642C\u8FC1\u4E0D\u5E94\u8BE5\u6709\u4EFB\u4F55\u526F\u4F5C\u7528\u3002\u5728CDATA\u7684\u5185\u5BB9\u662F \"{0}\"\u3002 +error.pi.found=XML\u5904\u7406\u6307\u4EE4\u88AB\u53D1\u73B0\uFF0C\u8FD9\u662F\u4E0D\u5141\u8BB8\u7684\u3002\u6D88\u606F\u7684\u5176\u4F59\u90E8\u5206\u662F\u5B8C\u6574\u7684\uFF0C\u5176\u642C\u8FC1\u5E94\u8BE5\u4E0D\u4F1A\u6709\u4EFB\u4F55\u526F\u4F5C\u7528\u3002\u8BE5\u6307\u4EE4\u7684\u5185\u5BB9\u4E3A \"{0}\"\u3002 +# Attribute related +error.attribute.notfound=\u6807\u8BB0{0}\u5305\u542B\u4E00\u4E2A\u6CA1\u6CD5\u5904\u7406\u7684\u5C5E\u6027\u3002\u5C5E\u6027{1}\u5DF2\u88AB\u8FC7\u6EE4\uFF0C\u4F46\u6807\u8BB0\u4FDD\u5B58\u4E0D\u53D8\u3002 +error.attribute.invalid=\u6807\u8BB0{0}\u5305\u542B\u4E00\u4E2A\u6CA1\u6CD5\u5904\u7406\u7684\u5C5E\u6027\u3002\u5C5E\u6027{1}\u5305\u542B\u4E00\u4E2A\u503C\"{2}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u8FD9\u4E2A\u503C\u6CA1\u6CD5\u88AB\u63A5\u53D7\u3002\u4E3A\u4E86\u5904\u7406\u8FD9\u4E2A\u8F93\u5165\uFF0C\u8FD9\u4E2A\u5C5E\u6027\u5DF2\u88AB\u4ECE\u8FD9\u4E2A\u6807\u8BB0\u4E2D\u53BB\u6389\uFF0C\u6807\u8BB0\u5176\u4ED6\u90E8\u5206\u4FDD\u6301\u4E0D\u53D8\u3002 +error.attribute.invalid.filtered=\u6807\u8BB0{0}\u5305\u542B\u4E00\u4E2A\u6CA1\u6CD5\u5904\u7406\u7684\u5C5E\u3002\u5C5E\u6027{1}\u5305\u542B\u4E00\u4E2A\u503C\"{2}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u8FD9\u4E2A\u503C\u6CA1\u6CD5\u88AB\u63A5\u53D7\u3002\u4E3A\u4E86\u8FDB\u4E00\u6B65\u5904\u7406\u8FD9\u4E2A\u8F93\u5165\uFF0C\u6807\u8BB0{0}\u5DF2\u88AB\u8FC7\u6EE4\u3002 +error.attribute.invalid.encoded=The {0} tag contained an attribute that we could not process. The {1} attribute had a value of \"{2}\". This value could not be accepted for security reasons. We have chosen to encode the {0} tag in order to continue processing the input. +error.attribute.invalid.removed=\u6807\u8BB0{0}\u5305\u542B\u4E00\u4E2A\u6CA1\u6CD5\u5904\u7406\u7684\u5C5E\u6027\u3002\u5C5E\u6027{1}\u5305\u542B\u4E00\u4E2A\u503C\"{2}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u8FD9\u4E2A\u503C\u6CA1\u6CD5\u88AB\u63A5\u53D7\u3002\u4E3A\u4E86\u8FDB\u4E00\u6B65\u5904\u7406\u8FD9\u4E2A\u8F93\u5165\uFF0C\u6574\u4E2A\u6807\u8BB0{0}\u5DF2\u88AB\u53BB\u6389\u3002 +# CSS related +error.css.tag.malformed=The stylesheet code \"{0}\" could not be parsed. +error.css.import.disabled=\u6837\u5F0F\u8868\u7684\u5BFC\u5165\u8FD8\u6CA1\u6709\u88AB\u6FC0\u6D3B\u3002 +error.css.import.exceeded=\u4F4D\u4E8E{0}\u7684\u6837\u5F0F\u8868\u8D85\u8FC7\u5141\u8BB8\u5BFC\u5165\u7684\u6837\u5F0F\u8868\u7684\u603B\u6570\uFF0C\u56E0\u6B64\u8BE5\u6837\u5F0F\u8868\u6CA1\u6709\u88AB\u8BFB\u53D6\u3002\u5141\u8BB8\u5BFC\u5165\u7684\u6837\u5F0F\u8868\u7684\u6700\u5927\u6570\u76EE\u4E3A{1}\u3002 +error.css.import.failure=\u8F93\u5165\u4E2D\u542B\u6709\u7684\u8FDC\u7A0B\u6837\u5F0F\u8868\u4F4D\u4E8E{0}\uFF0C\u6B64\u6837\u5F0F\u8868\u6CA1\u6CD5\u88AB\u8BFB\u53D6\u3002\u7F51\u7AD9\u53EF\u80FD\u5173\u95ED\u6216\u8005\u4E3B\u673A\u6CA1\u6CD5\u88AB\u8BBF\u95EE\u3002\u8FD9\u4E0D\u5E94\u8BE5\u5F71\u54CD\u8F93\u5165\u7684\u683C\u5F0F\u3002 +error.css.import.toolarge=\u4F4D\u4E8E{0}\u7684\u6837\u5F0F\u8868\u4F7F\u5F97\u603B\u8F93\u5165\u592A\u5927\uFF0C\u56E0\u6B64\u6CA1\u6709\u88AB\u5BFC\u5165\u3002\u5141\u8BB8\u7684\u6700\u5927\u8F93\u5165\u4E3A{1}\u5B57\u8282\u3002 +error.css.import.url.invalid=\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u7528\u4E8E\u5BFC\u5165\u6837\u5F0F\u8868\u7684url\u6CA1\u6CD5\u88AB\u63A5\u53D7\u3002\u6B64url\u662F{1}\u3002 +error.css.stylesheet.relative=\u6837\u5F0F\u8868\u5F15\u7528\u4E86\u4E00\u4E2A\u6CA1\u6CD5\u8BFB\u53D6\u7684\u76F8\u5BF9\u6837\u5F0F\u8868\"{0}\"\u3002 +error.css.tag.relative=\u6807\u8BB0{0}\u4E2D\u7684\u4E00\u4E2A\u6837\u5F0F\u5C5E\u6027\u6307\u5B9A\u4E86\u4E00\u4E2A\u6CA1\u6CD5\u8BFB\u53D6\u7684\u76F8\u5BF9\u6837\u5F0F\u8868\u5E94\u7528\"{0}\"\u3002 +error.css.stylesheet.rule.notfound=\u6837\u5F0F\u8868\u4F7F\u7528\u4E86\u4E00\u4E2A\u4E0D\u88AB\u652F\u6301\u7684\u89C4\u5219\"{0}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u89C4\u5219\u5DF2\u88AB\u53BB\u6389\u3002 +error.css.tag.rule.notfound=\u6807\u8BB0{0}\u4E2D\u7684\u4E00\u4E2A\u6837\u5F0F\u5C5E\u6027\u4F7F\u7528\u4E86\u4E00\u4E2A\u4E0D\u88AB\u652F\u6301\u7684\u89C4\u5219\"{0}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u89C4\u5219\u5DF2\u88AB\u53BB\u6389\u3002 +error.css.stylesheet.selector.notfound=\u6837\u5F0F\u8868\u4F7F\u7528\u4E86\u4E00\u4E2A\u6CA1\u6CD5\u5904\u7406\u7684\u9009\u62E9\u5668\"{0}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u9009\u62E9\u5668\u5DF2\u88AB\u53BB\u6389\u3002 +error.css.tag.selector.notfound=\u6807\u8BB0{0}\u4E2D\u7684\u4E00\u4E2A\u6837\u5F0F\u5C5E\u6027\u4F7F\u7528\u4E86\u4E00\u4E2A\u6CA1\u6CD5\u5904\u7406\u7684\u9009\u62E9\u5668\"{0}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u89C4\u5219\u5DF2\u88AB\u53BB\u6389\u3002 +error.css.stylesheet.selector.disallowed=\u6837\u5F0F\u8868\u4F7F\u7528\u4E86\u4E00\u4E2A\u9009\u62E9\u5668\"{0}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u9009\u62E9\u5668\u4E0D\u88AB\u5141\u8BB8\u3002 +error.css.tag.selector.disallowed=\u6807\u8BB0{0}\u4E2D\u7684\u4E00\u4E2A\u6837\u5F0F\u5C5E\u6027\u4F7F\u7528\u4E86\u4E00\u4E2A\u9009\u62E9\u5668\"{1}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u9009\u62E9\u5668\u4E0D\u88AB\u5141\u8BB8\u3002 +error.css.stylesheet.property.invalid=\u6837\u5F0F\u8868\u542B\u6709\u4E00\u4E2A\u5C5E\uFF08property)\"{0}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u5C5E\u6027\u4E0D\u88AB\u5141\u8BB8\u3002 +error.css.tag.property.invalid=\u6807\u8BB0{0}\u4E2D\u542B\u6709\u4E00\u4E2A\u6837\u5F0F\u5C5E\u6027\"{1}\"\u3002\u51FA\u4E8E\u5B89\u5168\u7684\u539F\u56E0\uFF0C\u6B64\u5C5E\u6027\u4E0D\u88AB\u5141\u8BB8\u3002 diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/META-INF/spring.factories b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..00d4acf --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.context.ApplicationContextInitializer=com.yunzhupaas.config.Conf2SystemConfiguration diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/antisamy-ebay-imgonlybase64.xml b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/antisamy-ebay-imgonlybase64.xml new file mode 100644 index 0000000..50ba288 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/antisamy-ebay-imgonlybase64.xml @@ -0,0 +1,2453 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g + grin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/antisamy-ebay.xml b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/antisamy-ebay.xml new file mode 100644 index 0000000..b41c619 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/antisamy-ebay.xml @@ -0,0 +1,2455 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g + grin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/antisamy-empty.xml b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/antisamy-empty.xml new file mode 100644 index 0000000..24f851c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-core/src/main/resources/antisamy-empty.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-database/pom.xml new file mode 100644 index 0000000..b51282e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/pom.xml @@ -0,0 +1,157 @@ + + + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-database + + + + + com.github.yulichang + mybatis-plus-join-boot-starter + + + + + com.mysql + mysql-connector-j + + + + com.microsoft.sqlserver + mssql-jdbc + + + + com.oracle.database.jdbc + ojdbc8 + + + com.oracle.database.nls + orai18n + + + + com.dameng + DmJdbcDriver18 + + + + cn.com.kingbase + kingbase8 + + + + org.postgresql + postgresql + + + + + + + + com.alibaba + druid + + + + + org.springframework.boot + spring-boot-starter-web + + + + com.yunzhupaas + yunzhupaas-common-auth + + + + + + + + + + + + + + + com.github.pagehelper + pagehelper + + + jsqlparser + com.github.jsqlparser + + + + + + + + boot3 + + [17,) + + + + com.baomidou + mybatis-plus-spring-boot3-starter + + com.zaxxer + HikariCP + + + + + com.baomidou + dynamic-datasource-spring-boot3-starter + + + org.springframework.boot + spring-boot-starter-undertow + + + + + + + boot2 + + (,17) + + + + com.baomidou + mybatis-plus-boot-starter + + com.zaxxer + HikariCP + + + + + com.baomidou + dynamic-datasource-spring-boot-starter + + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/controller/SuperController.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/controller/SuperController.java new file mode 100644 index 0000000..c69350b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/controller/SuperController.java @@ -0,0 +1,27 @@ +package com.yunzhupaas.base.controller; + +import com.yunzhupaas.base.service.SuperService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.lang.reflect.ParameterizedType; + +public abstract class SuperController, Entity> { + + + @Autowired + protected S baseService; + Class entityClass = null; + + public Class getEntityClass() { + if (entityClass == null) { + this.entityClass = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]; + } + return this.entityClass; + } + + public S getBaseService() { + return baseService; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/mapper/SuperMapper.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/mapper/SuperMapper.java new file mode 100644 index 0000000..143cb11 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/mapper/SuperMapper.java @@ -0,0 +1,203 @@ +package com.yunzhupaas.base.mapper; + +import com.github.yulichang.base.MPJBaseMapper; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.yunzhupaas.database.util.IgnoreLogicDeleteHolder; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.session.ResultHandler; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public interface SuperMapper extends MPJBaseMapper { + + /** + * 调用此方法后 后续SQL操作忽略逻辑删除筛选 + * 调用完成后需要调用clearIgnoreLogicDelete 清除标记 + * @return + */ + default SuperMapper setIgnoreLogicDelete(){ + IgnoreLogicDeleteHolder.setIgnoreLogicDelete(); + return this; + } + + /** + * 调用此方法后 后续SQL恢复逻辑删除筛选 + * @return + */ + default SuperMapper clearIgnoreLogicDelete(){ + IgnoreLogicDeleteHolder.clear(); + return this; + } + + + /** + * 根据 ID 删除 + * + * @param id 主键ID + */ + int deleteByIdIlg(Serializable id); + + /** + * 根据实体(ID)删除 + * + * @param entity 实体对象 + * @since 3.4.4 + */ + int deleteByIdIlg(T entity); + + + /** + * 根据 entity 条件,删除记录 + * + * @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) + */ + int deleteIlg(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 删除(根据ID或实体 批量删除) + * + * @param idList 主键ID列表或实体列表(不能为 null 以及 empty) + */ + int deleteBatchIdsIlg(@Param(Constants.COLL) Collection idList); + + /** + * 根据 ID 修改 + * + * @param entity 实体对象 + */ + int updateByIdIlg(@Param(Constants.ENTITY) T entity); + + /** + * 根据 whereEntity 条件,更新记录 + * + * @param entity 实体对象 (set 条件值,可以为 null) + * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) + */ + int updateIlg(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper updateWrapper); + + /** + * 根据 ID 查询 + * + * @param id 主键ID + */ + T selectByIdIlg(Serializable id); + + /** + * 查询(根据ID 批量查询) + * + * @param idList 主键ID列表(不能为 null 以及 empty) + */ + List selectBatchIdsIlg(@Param(Constants.COLL) Collection idList); + + /** + * 查询(根据ID 批量查询) + * + * @param idList idList 主键ID列表(不能为 null 以及 empty) + * @param resultHandler resultHandler 结果处理器 {@link ResultHandler} + * @since 3.5.4 + */ + void selectBatchIdsIlg(@Param(Constants.COLL) Collection idList, ResultHandler resultHandler); + + /** + * 根据 Wrapper 条件,查询总记录数 + * + * @param queryWrapper 实体对象封装操作类(可以为 null) + */ + Long selectCountIlg(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据 entity 条件,查询全部记录 + * + * @param queryWrapper 实体对象封装操作类(可以为 null) + */ + List selectListIlg(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据 entity 条件,查询全部记录 + * + * @param queryWrapper 实体对象封装操作类(可以为 null) + * @param resultHandler 结果处理器 {@link ResultHandler} + * @since 3.5.4 + */ + void selectListIlg(@Param(Constants.WRAPPER) Wrapper queryWrapper, ResultHandler resultHandler); + + /** + * 根据 entity 条件,查询全部记录(并翻页) + * + * @param page 分页查询条件 + * @param queryWrapper 实体对象封装操作类(可以为 null) + * @since 3.5.3.2 + */ + List selectListIlg(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据 entity 条件,查询全部记录(并翻页) + * @param page 分页查询条件 + * @param queryWrapper 实体对象封装操作类(可以为 null) + * @param resultHandler 结果处理器 {@link ResultHandler} + * @since 3.5.4 + */ + void selectListIlg(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper, ResultHandler resultHandler); + + + /** + * 根据 Wrapper 条件,查询全部记录 + * + * @param queryWrapper 实体对象封装操作类 + */ + List> selectMapsIlg(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据 Wrapper 条件,查询全部记录 + * + * @param queryWrapper 实体对象封装操作类 + * @param resultHandler 结果处理器 {@link ResultHandler} + * @since 3.5.4 + */ + void selectMapsIlg(@Param(Constants.WRAPPER) Wrapper queryWrapper, ResultHandler> resultHandler); + + /** + * 根据 Wrapper 条件,查询全部记录(并翻页) + * + * @param page 分页查询条件 + * @param queryWrapper 实体对象封装操作类 + * @since 3.5.3.2 + */ + List> selectMapsIlg(IPage> page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据 Wrapper 条件,查询全部记录(并翻页) + * + * @param page 分页查询条件 + * @param queryWrapper 实体对象封装操作类 + * @param resultHandler 结果处理器 {@link ResultHandler} + * @since 3.5.4 + */ + void selectMapsIlg(IPage> page, @Param(Constants.WRAPPER) Wrapper queryWrapper, ResultHandler> resultHandler); + + /** + * 根据 Wrapper 条件,查询全部记录 + *

注意: 只返回第一个字段的值

+ * + * @param queryWrapper 实体对象封装操作类(可以为 null) + */ + List selectObjsIlg(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据 Wrapper 条件,查询全部记录 + *

注意: 只返回第一个字段的值

+ * + * @param queryWrapper 实体对象封装操作类(可以为 null) + * @param resultHandler 结果处理器 {@link ResultHandler} + * @since 3.5.4 + */ + void selectObjsIlg(@Param(Constants.WRAPPER) Wrapper queryWrapper, ResultHandler resultHandler); + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/service/SuperService.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/service/SuperService.java new file mode 100644 index 0000000..2dd9511 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/service/SuperService.java @@ -0,0 +1,28 @@ +package com.yunzhupaas.base.service; + +import com.github.yulichang.base.MPJBaseService; +import com.yunzhupaas.database.util.IgnoreLogicDeleteHolder; + +public interface SuperService extends MPJBaseService { + + /** + * 调用此方法后 后续SQL操作忽略逻辑删除筛选 + * 调用完成后需要调用clearIgnoreLogicDelete 清除标记 + * @return + */ + default SuperService setIgnoreLogicDelete(){ + IgnoreLogicDeleteHolder.setIgnoreLogicDelete(); + return this; + } + + /** + * 调用此方法后 后续SQL恢复逻辑删除筛选 + * @return + */ + default SuperService clearIgnoreLogicDelete(){ + IgnoreLogicDeleteHolder.clear(); + return this; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/service/SuperServiceImpl.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/service/SuperServiceImpl.java new file mode 100644 index 0000000..3a69b62 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/base/service/SuperServiceImpl.java @@ -0,0 +1,83 @@ +package com.yunzhupaas.base.service; + +import com.baomidou.mybatisplus.core.enums.SqlMethod; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import com.github.yulichang.base.MPJBaseServiceImpl; +import com.yunzhupaas.base.mapper.SuperMapper; +import com.yunzhupaas.util.DateUtil; +import com.yunzhupaas.util.UserProvider; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.support.DefaultConversionService; + +import java.util.Collection; +import java.util.Date; + +public abstract class SuperServiceImpl, T> extends MPJBaseServiceImpl implements SuperService { + + private final ConversionService conversionService = DefaultConversionService.getSharedInstance(); + + /** + * 填充删除用户与删除时间 + * @param entity 实体 + * @return + */ + @Override + public boolean removeById(T entity) { + TableInfo tableInfo = TableInfoHelper.getTableInfo(getEntityClass()); + if (tableInfo.isWithLogicDelete() && tableInfo.isWithUpdateFill()) { + try{ + if(tableInfo.getPropertyValue(entity, "deleteUserId") == null){ + String userId = UserProvider.getLoginUserId(); + if (userId != null) { + Date deleteTime = DateUtil.getNowDate(); + tableInfo.setPropertyValue(entity, "deleteUserId" , userId); + tableInfo.setPropertyValue(entity, "deleteTime" , deleteTime); + } + } + }catch (Exception e){ } + } + return super.removeById(entity); + } + + /** + * 填充删除用户与删除时间 + * @param list 主键ID或实体列表 + * @param batchSize 批次大小 + * @param useFill 是否启用填充(为true的情况,会将入参转换实体进行delete删除) + * @return + */ + @Override + public boolean removeBatchByIds(Collection list, int batchSize, boolean useFill) { + String sqlStatement = getSqlStatement(SqlMethod.DELETE_BY_ID); + TableInfo tableInfo = TableInfoHelper.getTableInfo(getEntityClass()); + return executeBatch(list, batchSize, (sqlSession, e) -> { + if (useFill && tableInfo.isWithLogicDelete()) { + if (getEntityClass().isAssignableFrom(e.getClass())) { + sqlSession.update(sqlStatement, e); + } else { + T instance = tableInfo.newInstance(); + Object value = tableInfo.getKeyType() != e.getClass() ? conversionService.convert(e, tableInfo.getKeyType()) : e; + tableInfo.setPropertyValue(instance, tableInfo.getKeyProperty(), value); + try{ + if(tableInfo.getPropertyValue(instance, "deleteUserId") == null){ + String userId = UserProvider.getLoginUserId(); + if (userId != null) { + Date deleteTime = DateUtil.getNowDate(); + tableInfo.setPropertyValue(instance, "deleteUserId" , userId); + tableInfo.setPropertyValue(instance, "deleteTime" , deleteTime); + } + } + }catch (Exception ex){ } + sqlSession.update(sqlStatement, instance); + } + } else { + sqlSession.update(sqlStatement, e); + } + }); + } + + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/DruidConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/DruidConfig.java new file mode 100644 index 0000000..1e5b270 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/DruidConfig.java @@ -0,0 +1,81 @@ +package com.yunzhupaas.database.config; + + +import com.alibaba.druid.support.jakarta.StatViewServlet; +import com.alibaba.druid.support.jakarta.WebStatFilter; +import com.yunzhupaas.database.util.ConnUtil; +import com.yunzhupaas.database.util.DataSourceUtil; +import com.yunzhupaas.exception.DataException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * 数据源配置 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:49 + */ +@Configuration +public class DruidConfig { + + @Autowired + DataSourceUtil dataSourceUtil; + +// @Bean + public DataSource druid() throws DataException { + return ConnUtil.getDruidDataSource(dataSourceUtil); + } + + + /** + * 配置Druid的监控 + * 配置一个管理后台的Servlet + * @return + */ + @Bean + public ServletRegistrationBean statViewServlet(){ + ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); + Map initParams = new HashMap<>(4); + //配置druid页面监控的账户密码 + initParams.put("loginUsername", "com.yunzhupaas"); + initParams.put("loginPassword","123456"); + //默认就是允许所有访问 + initParams.put("allow",""); + //黑名单 注意 黑名单优先于 allow白名单加载 两个名单中不可重复 + initParams.put("deny","192.168.10.21"); + + bean.setInitParameters(initParams); + return bean; + } + + + /** + * 配置一个web监控的filter + * @return + */ + @Bean + public FilterRegistrationBean webStatFilter(){ + FilterRegistrationBean bean = new FilterRegistrationBean(); + bean.setFilter(new WebStatFilter()); + + Map initParams = new HashMap<>(16); + initParams.put("exclusions","*.js,*.css,/druid/*"); + + bean.setInitParameters(initParams); + + bean.setUrlPatterns(Arrays.asList("/*")); + + return bean; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/IdGeneratorConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/IdGeneratorConfig.java new file mode 100644 index 0000000..3880504 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/IdGeneratorConfig.java @@ -0,0 +1,90 @@ +package com.yunzhupaas.database.config; + +import com.github.yitter.contract.IdGeneratorOptions; +import com.github.yitter.idgen.YitIdHelper; +import jakarta.annotation.PreDestroy; +import com.yunzhupaas.util.CacheKeyUtil; +import com.yunzhupaas.util.ThreadPoolExecutorUtil; +import com.yunzhupaas.util.context.SpringContext; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.support.atomic.RedisAtomicLong; +import org.springframework.stereotype.Component; + +import java.util.Random; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Component +public class IdGeneratorConfig { + + private static final String ID_IDX = CacheKeyUtil.IDGENERATOR + "Index:"; + private RedisTemplate redisTemplate; + + //ID缓存有效时间 定时刷新有效期 + private static final long CacheTimeout = 60L * 60 * 24; + //30分钟续期一次 如果Redis被清空可以早点续期 + private static final long ScheduleTimeout = 60L * 30; + private static final byte WorkerIdBitLength = 16; + //65535 参数为shot 最大值为Short.MAX_VALUE + private static final int MaxWorkerIdNumberByMode = (1 << WorkerIdBitLength) -1 >Short.MAX_VALUE?Short.MAX_VALUE : (1 << WorkerIdBitLength) -1 ; + private static ScheduledThreadPoolExecutor scheduledThreadPoolExecutor; + + private short workerId = -1; + private String cacheKey; + + + /** + * 初始化雪花生成器WorkerID, 通过Redis实现集群获取不同的编号, 如果相同会出现ID重复 + */ + @Bean + private void initIdWorker(){ + redisTemplate = SpringContext.getBean("redisTemplate"); + if(redisTemplate != null) { + RedisAtomicLong redisAtomicLong = new RedisAtomicLong(ID_IDX, redisTemplate.getConnectionFactory()); + for (int i = 0; i <= MaxWorkerIdNumberByMode; i++) { + long andInc = redisAtomicLong.getAndIncrement(); + long result = andInc % (MaxWorkerIdNumberByMode + 1); + //计数超出上限之后重新计数 + if (andInc >= MaxWorkerIdNumberByMode) { + redisAtomicLong.set(andInc % (MaxWorkerIdNumberByMode)); + } + cacheKey = ID_IDX + result; + boolean useSuccess = redisTemplate.opsForValue().setIfAbsent(cacheKey, System.currentTimeMillis(), CacheTimeout, TimeUnit.SECONDS); + if (useSuccess) { + workerId = (short) result; + break; + } + } + if (workerId == -1) { + throw new RuntimeException(String.format("已尝试生成%d个ID生成器编号, 无法获取到可用编号", MaxWorkerIdNumberByMode + 1)); + } + }else{ + workerId = (short) new Random().nextInt(MaxWorkerIdNumberByMode); + } + log.info("当前ID生成器编号: " + workerId); + IdGeneratorOptions options = new IdGeneratorOptions(workerId); + options.WorkerIdBitLength = WorkerIdBitLength; + YitIdHelper.setIdGenerator(options); + scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1, ThreadPoolExecutorUtil.getExecutor().getThreadPoolExecutor().getThreadFactory()); + //提前一分钟续期 + scheduledThreadPoolExecutor.scheduleWithFixedDelay(resetExpire, ScheduleTimeout, ScheduleTimeout, TimeUnit.SECONDS); + } + + + private Runnable resetExpire = ()->{ + //重新设值, 如果Redis被意外清空或者掉线可以把当前编号重新锁定 + redisTemplate.opsForValue().set(cacheKey, System.currentTimeMillis(), CacheTimeout, TimeUnit.SECONDS); + }; + + @PreDestroy + private void onDestroy(){ + //正常关闭时删除当前生成器编号 + if(redisTemplate != null) { + redisTemplate.delete(cacheKey); + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/MybatisPlusConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/MybatisPlusConfig.java new file mode 100644 index 0000000..25d02ea --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/MybatisPlusConfig.java @@ -0,0 +1,423 @@ +package com.yunzhupaas.database.config; + +import com.alibaba.druid.pool.DruidDataSource; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationAdvisor; +import com.baomidou.dynamic.datasource.enums.DdConstants; +import com.baomidou.dynamic.datasource.processor.DsProcessor; +import com.baomidou.dynamic.datasource.creator.DataSourceProperty; +import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; +import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS; +import com.baomidou.mybatisplus.core.MybatisConfiguration; +import com.baomidou.mybatisplus.core.config.GlobalConfig; +import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; +import com.baomidou.mybatisplus.core.injector.ISqlInjector; +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import com.baomidou.mybatisplus.core.toolkit.StringPool; +import com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler; +import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; +import com.github.pagehelper.PageInterceptor; +import com.yunzhupaas.base.entity.SuperBaseEntity; +import com.yunzhupaas.config.ApplicationStartErrorCheck; +import com.yunzhupaas.config.ConfigValueUtil; +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.plugins.*; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.source.impl.DbOracle; +import com.yunzhupaas.database.util.ConnUtil; +import com.yunzhupaas.database.util.DataSourceUtil; +import com.yunzhupaas.database.util.DbTypeUtil; +import com.yunzhupaas.database.util.DynamicDataSourceUtil; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.ClassUtil; +import com.yunzhupaas.util.TenantHolder; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.NullValue; +import net.sf.jsqlparser.expression.StringValue; +import org.apache.ibatis.builder.MapperBuilderAssistant; +import org.apache.ibatis.logging.slf4j.Slf4jImpl; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.type.JdbcType; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.aop.Advisor; +import org.springframework.aop.Pointcut; +import org.springframework.aop.aspectj.AspectJExpressionPointcut; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.*; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; + +import javax.sql.DataSource; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.net.URISyntaxException; +import java.sql.SQLException; +import java.util.*; + +/** + * MybatisPlus配置类 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:53 + */ +@Slf4j +@Configuration +@ComponentScan("com.yunzhupaas") +@DependsOn({ "tenantDataSourceUtil", "threadPoolExecutorUtil" }) +@MapperScan(basePackages = { "com.yunzhupaas.*.mapper", "com.yunzhupaas.mapper", "com.xxl.job.admin.dao" }) +public class MybatisPlusConfig { + + /** + * 对接数据库的实体层 + */ + static final String ALIASES_PACKAGE = "com.yunzhupaas.*.entity;com.xxl.job.admin.core.model"; + + @Autowired + private DataSourceUtil dataSourceUtil; + @Autowired + private ConfigValueUtil configValueUtil; + + @Primary + @Bean(name = "dataSourceSystem") + public DataSource dataSourceOne(DynamicDataSourceProperties properties, List providers) + throws SQLException, IOException, URISyntaxException { + DataSource dataSource = dynamicDataSource(properties, providers); + initDynamicDataSource(dataSource, properties); + return dataSource; + } + + @Bean(name = "sqlSessionFactorySystem") + public SqlSessionFactory sqlSessionFactoryOne(@Qualifier("dataSourceSystem") DataSource dataSource, + @Autowired(required = false) ISqlInjector sqlInjector) throws Exception { + return createSqlSessionFactory(dataSource, sqlInjector); + } + + /** + * 服务中查询其他服务的表数据, 未引用Mapper无法初始化MybatisPlus的TableInfo对象, 无法判断逻辑删除情况, + * 初始化MybatisPlus所有Entity对象 + * 微服务的情况才进行扫描 + * + * @param sqlSessionFactory + * @return + */ + @Bean + @ConditionalOnClass(name = "org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient") + public Object scanAllEntity(SqlSessionFactory sqlSessionFactory) { + ApplicationStartErrorCheck.getApplicationInitThreadPool().execute(() -> { + Set> classes = ClassUtil.scanCandidateComponents("com.yunzhupaas", + c -> !Modifier.isAbstract(c.getModifiers()) + && SuperBaseEntity.SuperTBaseEntity.class.isAssignableFrom(c)); + for (Class aClass : classes) { + MapperBuilderAssistant builderAssistant = new MapperBuilderAssistant( + sqlSessionFactory.getConfiguration(), "resource"); + builderAssistant.setCurrentNamespace(aClass.getName()); + TableInfoHelper.initTableInfo(builderAssistant, aClass); + } + }); + return null; + } + + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + try { + // 判断是否多租户 + if (configValueUtil.isMultiTenancy()) { + interceptor.addInnerInterceptor(myTenantLineInnerInterceptor()); + interceptor.addInnerInterceptor(mySchemaInnerInterceptor()); + } + // 开启逻辑删除插件功能 + if (configValueUtil.isEnableLogicDelete()) { + interceptor.addInnerInterceptor(myLogicDeleteInnerInterceptor()); + } + // 新版本分页必须指定数据库,否则分页不生效 + // 不指定会动态生效 多数据源不能指定数据库类型 + interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); + + // 乐观锁 + interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); + } catch (Exception e) { + e.printStackTrace(); + } + return interceptor; + } + + @Bean("myLogicDeleteInnerInterceptor") + @ConditionalOnProperty(prefix = "config", name = "EnableLogicDelete", havingValue = "true") + public MyLogicDeleteInnerInterceptor myLogicDeleteInnerInterceptor() { + MyLogicDeleteInnerInterceptor myLogicDeleteInnerInterceptor = new MyLogicDeleteInnerInterceptor(); + myLogicDeleteInnerInterceptor.setLogicDeleteHandler(new LogicDeleteHandler() { + @Override + public Expression getNotDeletedValue() { + return new NullValue(); + } + + @Override + public String getLogicDeleteColumn() { + return configValueUtil.getLogicDeleteColumn(); + } + }); + return myLogicDeleteInnerInterceptor; + } + + @Bean("myTenantLineInnerInterceptor") + @ConditionalOnProperty(prefix = "config", name = "MultiTenancy", havingValue = "true") + public TenantLineInnerInterceptor myTenantLineInnerInterceptor() { + TenantLineInnerInterceptor tenantLineInnerInterceptor = new MyTenantLineInnerInterceptor(); + tenantLineInnerInterceptor.setTenantLineHandler(new TenantLineHandler() { + @Override + public Expression getTenantId() { + return new StringValue(TenantHolder.getDatasourceName()); + } + + @Override + public String getTenantIdColumn() { + return configValueUtil.getMultiTenantColumn(); + } + + @Override + public boolean ignoreTable(String tableName) { + return configValueUtil.getMultiTenantIgnoreTable().contains(tableName.toLowerCase()); + } + }); + return tenantLineInnerInterceptor; + } + + @Bean("mySchemaInnerInterceptor") + @ConditionalOnProperty(prefix = "config", name = "MultiTenancy", havingValue = "true") + public DynamicTableNameInnerInterceptor mySchemaInnerInterceptor() throws Exception { + DbLinkEntity dbLinkEntity = dataSourceUtil.init(); + DbBase dbBase = DbTypeUtil.getDb(dbLinkEntity); + DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new MySchemaInnerInterceptor(); + HashMap map = new HashMap<>(150); + // null空库保护 + List tableNames = new ArrayList<>(); + // JdbcUtil.queryCustomMods(SqlComEnum.TABLES.getPrepSqlDto(dbLinkEntity, null), + // DbTableFieldModel.class) + // .forEach(dbTableModel-> + // tableNames.add(dbTableModel.getTable().toLowerCase())); + // 将当前连接库的所有表保存, 在列表中的表才进行切库, 所有表名转小写, 后续比对转小写 + DbBase.dynamicAllTableName = tableNames; + dynamicTableNameInnerInterceptor.setTableNameHandler(dbBase.getDynamicTableNameHandler()); + return dynamicTableNameInnerInterceptor; + } + + @Bean("myTenantMasterSlaveInterceptor") + @ConditionalOnProperty(prefix = "config", name = "MultiTenancy", havingValue = "true") + public MyTenantMasterSlaveAutoRoutingPlugin myTenantMasterSlaveAutoRoutingPlugin(DataSource dataSource) { + return new MyTenantMasterSlaveAutoRoutingPlugin(dataSource); + } + + public MyDefaultMasterSlaveAutoRoutingPlugin myDefaultMasterSlaveAutoRoutingPlugin(DataSource dataSource) { + return new MyDefaultMasterSlaveAutoRoutingPlugin(dataSource); + } + + protected DataSource dynamicDataSource(DynamicDataSourceProperties properties, + List providers) { + // 动态路由数据源(关键) + DynamicRoutingDataSource dataSource = new MyDynamicRoutingDataSource(providers); + dataSource.setPrimary(properties.getPrimary()); + dataSource.setStrict(properties.getStrict()); + dataSource.setStrategy(properties.getStrategy()); + dataSource.setP6spy(properties.getP6spy()); + dataSource.setSeata(properties.getSeata()); + // 创建失败不等待 + // properties.getDruid().setBreakAfterAcquireFailure(false); + // properties.getDruid().setMaxWait(1000); + return dataSource; + } + + private void initDynamicDataSource(@Qualifier("dataSourceSystem") DataSource dataSource1, + DynamicDataSourceProperties properties) + throws DataException, SQLException, IOException, URISyntaxException { + DynamicRoutingDataSource dataSource = (DynamicRoutingDataSource) dataSource1; + // 若未配置多数据源, 从主配置复制数据库配置填充多数据源 + boolean isPresentPrimary = properties.getDatasource().entrySet().stream() + .anyMatch(ds -> ds.getKey().equals(properties.getPrimary()) + || ds.getKey().startsWith(properties.getPrimary() + "_") + || properties.getPrimary().equals(ds.getValue().getPoolName())); + if (!isPresentPrimary) { + // null多租户空库保护 + DynamicDataSourceUtil.dynamicDataSourceProperties = properties; + String url = ConnUtil.getUrl(dataSourceUtil, + configValueUtil.isMultiTenancy() ? null : dataSourceUtil.getDbName()); + DataSourceProperty dataSourceProperty = DynamicDataSourceUtil.createDataSourceProperty(dataSourceUtil, url); + dataSourceProperty.getDruid().setBreakAfterAcquireFailure(false); + dataSourceProperty.setLazy(false); + properties.getDatasource().put(properties.getPrimary(), dataSourceProperty); + } + } + + @Bean + public Advisor myDynamicDatasourceGeneratorAdvisor(DsProcessor dsProcessor) { + DynamicGeneratorInterceptor interceptor = new DynamicGeneratorInterceptor(true, dsProcessor); + return new DynamicDataSourceAnnotationAdvisor(interceptor, DS.class) { + private final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); + + { + pointcut.setExpression( + "within(com.yunzhupaas.database.plugins.DynamicSourceGeneratorInterface+) && @target(com.baomidou.dynamic.datasource.annotation.DS)"); + } + + @Override + public Pointcut getPointcut() { + return pointcut; + } + }; + } + + protected DataSource druidDataSource() throws Exception { + DbBase dbBase = DbTypeUtil.getDb(dataSourceUtil); + String userName = dataSourceUtil.getUserName(); + String password = dataSourceUtil.getPassword(); + String driver = dbBase.getDriver(); + String url = ""; + + if (configValueUtil.isMultiTenancy()) { + url = ConnUtil.getUrl(dataSourceUtil, null); + } else { + url = ConnUtil.getUrl(dataSourceUtil); + } + + DruidDataSource dataSource = new DruidDataSource(); + if (dbBase.getClass() == DbOracle.class) { + // Oracle特殊创建数据源方式 + // String logonUer = "Default"; + String logonUer = "SYSDBA"; + // String logonUer = "SYSOPER"; + Properties properties = DbOracle.setConnProp(logonUer, userName, password); + dataSource.setConnectProperties(properties); + } else { + dataSource.setUsername(userName); + dataSource.setPassword(password); + } + dataSource.setUrl(url); + dataSource.setDriverClassName(driver); + return dataSource; + } + + public Resource[] resolveMapperLocations() { + ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); + List mapperLocations = new ArrayList<>(); + mapperLocations.add("classpath*:mapper/*.xml"); + mapperLocations.add("classpath*:mapper/*/*.xml"); + mapperLocations.add("classpath*:mapper/*/*/*.xml"); + mapperLocations.add("classpath*:mybatis-mapper/*.xml"); + List resources = new ArrayList(); + for (String mapperLocation : mapperLocations) { + try { + Resource[] mappers = resourceResolver.getResources(mapperLocation); + resources.addAll(Arrays.asList(mappers)); + } catch (IOException e) { + // ignore + } + } + return resources.toArray(new Resource[0]); + } + + public SqlSessionFactory createSqlSessionFactory(DataSource dataSource, ISqlInjector sqlInjector) throws Exception { + MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean(); + bean.setDataSource(dataSource); + // 全局配置 + GlobalConfig globalConfig = new GlobalConfig(); + // 配置填充器 + globalConfig.setMetaObjectHandler(new MybatisPlusMetaObjectHandler()); + bean.setGlobalConfig(globalConfig); + if (configValueUtil.isEnableLogicDelete()) { + globalConfig.setDbConfig(new GlobalConfig.DbConfig()); + globalConfig.getDbConfig().setLogicDeleteField("deleteMark"); + globalConfig.getDbConfig().setLogicDeleteValue("1"); + globalConfig.getDbConfig().setLogicNotDeleteValue(StringPool.NULL); + } + sqlInjector = new MyDefaultSqlInjector(sqlInjector, configValueUtil); + globalConfig.setSqlInjector(sqlInjector); + List mybatisPlugins = new ArrayList<>(); + mybatisPlugins.add(new ResultSetInterceptor()); + mybatisPlugins.add(new MyDynamicDataSourceAutoRollbackInterceptor()); + mybatisPlugins.add(pageHelper()); + if (configValueUtil.isMultiTenancy()) { + mybatisPlugins.add(myTenantMasterSlaveAutoRoutingPlugin(dataSource)); + } + // 配置从库添加读写分离插件 + if (DynamicDataSourceUtil.dynamicDataSourceProperties.getDatasource().keySet().stream() + .anyMatch(k -> k.startsWith(DdConstants.SLAVE))) { + mybatisPlugins.add(myDefaultMasterSlaveAutoRoutingPlugin(dataSource)); + } + + bean.setVfs(SpringBootVFS.class); + bean.setTypeAliasesPackage(ALIASES_PACKAGE); + bean.setMapperLocations(resolveMapperLocations()); + bean.setConfiguration(configuration(dataSource)); + bean.setPlugins(mybatisPlugins.toArray(new Interceptor[mybatisPlugins.size()])); + return bean.getObject(); + } + + public PageInterceptor pageHelper() { + PageInterceptor pageHelper = new PageInterceptor(); + // 配置PageHelper参数 + Properties properties = new Properties(); + properties.setProperty("dialectAlias", "kingbase8=com.github.pagehelper.dialect.helper.MySqlDialect"); + properties.setProperty("autoRuntimeDialect", "true"); + properties.setProperty("offsetAsPageNum", "false"); + properties.setProperty("rowBoundsWithCount", "false"); + properties.setProperty("pageSizeYunzhupaas", "true"); + properties.setProperty("reasonable", "false"); + properties.setProperty("supportMethodsArguments", "false"); + properties.setProperty("returnPageInfo", "none"); + pageHelper.setProperties(properties); + return pageHelper; + } + + public MybatisConfiguration configuration(DataSource dataSource) { + MybatisConfiguration mybatisConfiguration = new MybatisConfiguration() { + @Override + public void addMappedStatement(MappedStatement ms) { + // 避免Mybatis多线程初始化问题 + synchronized (ALIASES_PACKAGE) { + super.addMappedStatement(ms); + } + } + }; + mybatisConfiguration.setMapUnderscoreToCamelCase(false); + mybatisConfiguration.setCacheEnabled(false); + mybatisConfiguration.setCallSettersOnNulls(true); + mybatisConfiguration.addInterceptor(mybatisPlusInterceptor()); + mybatisConfiguration.setLogImpl(Slf4jImpl.class); + mybatisConfiguration.setJdbcTypeForNull(JdbcType.NULL); + return mybatisConfiguration; + } + + @Bean + public IKeyGenerator keyGenerator() { + return new H2KeyGenerator(); + } + + /** + * 数据权限插件 + * + * @return DataScopeInterceptor + */ + // @Bean + // @ConditionalOnMissingBean + // public DataScopeInterceptor dataScopeInterceptor(DataSource dataSource) { + // return new DataScopeInterceptor(dataSource); + // } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/MybatisPlusMetaObjectHandler.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/MybatisPlusMetaObjectHandler.java new file mode 100644 index 0000000..58f1558 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/config/MybatisPlusMetaObjectHandler.java @@ -0,0 +1,67 @@ +package com.yunzhupaas.database.config; + +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.yunzhupaas.constant.GlobalConst; +import com.yunzhupaas.database.util.TenantDataSourceUtil; +import com.yunzhupaas.util.DateUtil; +import com.yunzhupaas.util.UserProvider; +import org.apache.ibatis.reflection.MetaObject; +import org.springframework.stereotype.Component; + +import java.util.Date; + + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024年12月22日 下午20:14 + */ +@Component +public class MybatisPlusMetaObjectHandler implements MetaObjectHandler { + + + @Override + public void insertFill(MetaObject metaObject) { + String userId = UserProvider.getLoginUserId(); + Object enabledMark = this.getFieldValByName("enabledMark", metaObject); + Object creatorUserId = this.getFieldValByName("creatorUserId", metaObject); + Object creatorTime = this.getFieldValByName("creatorTime", metaObject); + Object creatorUser = this.getFieldValByName("creatorUser", metaObject); + if (enabledMark == null) { + this.strictInsertFill(metaObject, "enabledMark", () -> 1, Integer.class); + } + if (creatorUserId == null) { + this.strictInsertFill(metaObject, "creatorUserId", () -> userId, String.class); + } + if (creatorTime == null) { + this.strictInsertFill(metaObject, "creatorTime", DateUtil::getNowDate, Date.class); + } + if (creatorUser == null) { + this.strictInsertFill(metaObject, "creatorUser", () -> userId, String.class); + } + String tenantColumn = TenantDataSourceUtil.getTenantColumn(); + if (GlobalConst.DEFAULT_TENANT_VALUE.equals(tenantColumn)) { + this.strictInsertFill(metaObject, "tenantId", () -> tenantColumn, String.class); + } else { + this.setFieldValByName("tenantId", TenantDataSourceUtil.getTenantColumn(), metaObject); + } + } + + @Override + public void updateFill(MetaObject metaObject) { + String userId = UserProvider.getLoginUserId(); + this.strictUpdateFill(metaObject, "lastModifyTime", DateUtil::getNowDate, Date.class); + this.strictUpdateFill(metaObject, "lastModifyUserId", () -> userId, String.class); + this.strictUpdateFill(metaObject, "lastModifyUser", () -> userId, String.class); + String tenantColumn = TenantDataSourceUtil.getTenantColumn(); + if (GlobalConst.DEFAULT_TENANT_VALUE.equals(tenantColumn)) { + this.strictUpdateFill(metaObject, "tenantId", () -> tenantColumn, String.class); + } else { + this.setFieldValByName("tenantId", TenantDataSourceUtil.getTenantColumn(), metaObject); + } + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/DbAliasConst.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/DbAliasConst.java new file mode 100644 index 0000000..2b73c75 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/DbAliasConst.java @@ -0,0 +1,91 @@ +package com.yunzhupaas.database.constant; + +import com.google.common.collect.ImmutableMap; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.exception.DataException; +import lombok.AllArgsConstructor; + +import java.util.Map; +import java.util.Optional; + +/** + * 字段别名特殊标识 + * + * @author 云筑产品开发平台组 + * @version v3.4.6 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2023-02-11 + */ +public class DbAliasConst { + + /** + * 允空 + */ + public static final String NULL = "NULL"; + + /** + * 非空 + */ + public static final String NOT_NULL = "NOT NULL"; + + /** + * 允空 + * 0:空值 NULL、1:非空值 NOT NULL + */ + public static final NumFieldAttr ALLOW_NULL = new NumFieldAttr<>(ImmutableMap.of( + 1, NULL, + 0, NOT_NULL, + -1, NOT_NULL + )); + + /** + * 主键 + * 0:非主键、1:主键 + */ + public static final NumFieldAttr PRIMARY_KEY = new NumFieldAttr<>(ImmutableMap.of( + 1, true, + 0, false, + -1, false + )); + + public static final NumFieldAttr AUTO_INCREMENT = new NumFieldAttr<>(ImmutableMap.of( + 1, true, + 0, false, + -1, false + )); + + /** + * 数值对应字段属性 + * @param + */ + @AllArgsConstructor + public static class NumFieldAttr{ + + private Map config; + + /** + * 获取标识 + */ + public T getSign(Integer i) { + return config.get(i == null ? -1 : i); + } + + /** + * 获取数值 + */ + public Integer getNum(T sign) throws DataException { + if(sign == null){ + return 0; + } + Optional> first = config.entrySet().stream().filter(map -> map.getValue().equals(sign)).findFirst(); + if(first.isPresent()){ + return first.get().getKey(); + }else { + throw new DataException(MsgCode.DB012.get()); + } + } + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/DbConst.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/DbConst.java new file mode 100644 index 0000000..454bc33 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/DbConst.java @@ -0,0 +1,79 @@ +package com.yunzhupaas.database.constant; + +/** + * 数据库相关静态常量 + * + * @author 云筑产品开发平台组 YY + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/06 + */ +public class DbConst { + + /** + * jdbc工具类返回数据类型 + */ + public static final String TABLE_FIELD_MOD = "tableFieldMod"; + public static final String MAP_MOD = "mapMods"; + public static final String INCLUDE_FIELD_MOD = "includeFieldMods"; + public static final String CUSTOM_MOD = "customMods"; + public static final String PAGE_MOD = "pageMod"; + + /** + * url连接 + */ + public static final String HOST = "{host}"; + public static final String PORT = "{port}"; + public static final String DB_NAME = "{dbname}"; + public static final String DB_SCHEMA = "{schema}"; + + + /** + * 默认表(不可删) + * + */ + public static final String BYO_TABLE = + "base_advanced_query_scheme,base_app_data,base_authorize,base_bill_rule,base_columns_purview,base_common_fields," + + "base_common_words,base_data_interface,base_data_interface_log,base_data_interface_oauth,base_data_interface_variate," + + "base_db_link,base_dictionary_data,base_dictionary_type,base_file,base_group,base_im_content,base_im_reply," + + "base_integrate,base_integrate_node,base_integrate_queue,base_integrate_task,base_message,base_module," + + "base_module_authorize,base_module_button,base_module_column,base_module_form,base_module_link," + + "base_module_scheme,base_msg_account,base_msg_monitor,base_msg_send,base_msg_send_template," + + "base_msg_short_link,base_msg_sms_field,base_msg_template,base_msg_template_param,base_msg_wechat_user," + + "base_notice,base_organize,base_organize_administrator,base_organize_relation,base_permission_group," + + "base_portal,base_portal_data,base_portal_manage,base_position,base_print_log,base_print_template," + + "base_province,base_province_atlas,base_role,base_schedule,base_schedule_log,base_schedule_user,base_sign_img," + + "base_socials_users,base_syn_third_info,base_sys_config,base_sys_log,base_system,base_time_task," + + "base_time_task_log,base_user,base_user_device,base_user_old_password,base_user_relation,base_visual_dev," + + "base_visual_dev_copy1,base_visual_filter,base_visual_link,base_visual_release,base_visual_release_copy1," + + "blade_visual,blade_visual_category,blade_visual_component,blade_visual_config,blade_visual_db,blade_visual_map," + + "blade_visual_record,ct293714178055641925,ct294012196562705414,ct294022926200511493,ct294031961024928774," + + "ct294031961024928775,ct294037561750363142,ct294037561750363143,ct294099893327272966,ct294376098702073542," + + "ct294382866144468678,ct395899726056134917,ct459734202267475653,ct469496947162544645,ct469499339585157637," + + "data_report,ext_big_data,ext_customer,ext_document,ext_document_share,ext_email_config,ext_email_receive," + + "ext_email_send,ext_employee,ext_order,ext_order_2,ext_order_entry,ext_order_entry_2,ext_order_receivable," + + "ext_order_receivable_2,ext_product,ext_product_classify,ext_product_entry,ext_product_goods,ext_project_gantt," + + "ext_table_example,ext_worklog,ext_worklog_share,flow_candidates,flow_comment,flow_delegate,flow_form,flow_form_copy1," + + "flow_form_relation,flow_launch_user,flow_reject_data,flow_task,flow_task_circulate,flow_task_node,flow_task_operator," + + "flow_task_operator_record,flow_task_operator_user,flow_template,flow_template_json,flow_visible,mt293714178051447621," + + "mt293732572561709893,mt293737725377420101,mt293740367726025541,mt293756710756064069,mt294012196562705413," + + "mt294022926196317189,mt294027801932110853,mt294031961024928773,mt294037561750363141,mt294090217118276613," + + "mt294099237023526085,mt294099893327272965,mt294104577349819397,mt294376098702073541,mt294382866144468677," + + "mt382811547782648325,mt385453315686752389,mt395179351563312389,mt395899725691230469,mt395964134161651973," + + "mt400655094485373381,mt420589912199274117,mt456990191458975685,mt469496947087047173,mt469499339534825989," + + "mt469502670336489989,mt470888132380721605,mt470913062111543749,mt470929966582727173,report_charts,report_department," + + "report_user,test_carapplication,test_cost,test_customer,test_details,test_position,test_projects,test_purchase," + + "test_purchase_form,test_purchase_form_order,test_purchaseorder,test_receivable,test_reimbursement,test_subpackage," + + "test_vehicleinfo,test_warehousing,test_warehousingorder,undo_log,wform_applybanquet,wform_applydelivergoods," + + "wform_applydelivergoodsentry,wform_applymeeting,wform_archivalborrow,wform_articleswarehous,wform_batchpack," + + "wform_batchtable,wform_conbilling,wform_contractapproval,wform_contractapprovalsheet,wform_debitbill," + + "wform_documentapproval,wform_documentsigning,wform_expenseexpenditure,wform_finishedproduct,wform_finishedproductentry," + + "wform_incomerecognition,wform_leaveapply,wform_letterservice,wform_materialrequisition,wform_materialrequisitionentry," + + "wform_monthlyreport,wform_officesupplies,wform_outboundorder,wform_outboundorderentry,wform_outgoingapply," + + "wform_paydistribution,wform_paymentapply,wform_postbatchtab,wform_procurementmaterial,wform_procurementmaterialentry," + + "wform_purchaselist,wform_purchaselistentry,wform_quotationapproval,wform_receiptprocessing,wform_receiptsign," + + "wform_rewardpunishment,wform_salesorder,wform_salesorderentry,wform_salessupport,wform_staffovertime," + + "wform_supplementcard,wform_travelapply,wform_travelreimbursement,wform_vehicleapply,wform_violationhandling," + + "wform_warehousereceipt,wform_warehousereceiptentry,wform_workcontactsheet,wform_zjf_wikxqi"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/DbFieldConst.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/DbFieldConst.java new file mode 100644 index 0000000..660787c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/DbFieldConst.java @@ -0,0 +1,35 @@ +package com.yunzhupaas.database.constant; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-17 + */ +public class DbFieldConst { + + /** + * 允空 + */ + public static final String NULL = "NULL"; + + /** + * 非空 + */ + public static final String NOT_NULL = "NOT NULL"; + + /** + * 主键 + */ + public static final Boolean IS_PRIMARY_KEY = true; + + /** + * 非主键 + */ + public static final Boolean NOT_PRIMARY_KEY = false; + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/RsColumnKeyConst.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/RsColumnKeyConst.java new file mode 100644 index 0000000..5971ec8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/RsColumnKeyConst.java @@ -0,0 +1,104 @@ +package com.yunzhupaas.database.constant; + +/** + * 打印模板-结果集字段Key + * + * @author 云筑产品开发平台组 YY + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-09-30 + */ +public interface RsColumnKeyConst { + /** + * 表类别 + */ + String TABLE_CAT = "TABLE_CAT"; + /** + * 表模式 + */ + String TABLE_SCHEM = "TABLE_SCHEM"; + /** + * 表名称 + */ + String TABLE_NAME = "TABLE_NAME"; + /** + * 列名称 + */ + String COLUMN_NAME = "COLUMN_NAME"; + /** + * 来自 java.sql.Types 的 SQL 类型 + */ + String DATA_TYPE = "DATA_TYPE"; + /** + * 数据源依赖的类型名称,对于 UDT,该类型名称是完全限定的 + */ + String TYPE_NAME = "TYPE_NAME"; + /** + * 列的大小 + * charLength(字符串长度) + */ + String COLUMN_SIZE = "COLUMN_SIZE"; + /** + * 基数(通常为 10 或 2) + * Precision(精度) + */ + String NUM_PREC_RADIX = "NUM_PREC_RADIX"; + /** + * 小数部分的位数。对于 DECIMAL_DIGITS 不适用的数据类型,则返回 Null + * Scale(标度) + */ + String DECIMAL_DIGITS = "DECIMAL_DIGITS"; + /** + * 是否允许使用 NULL。 columnNoNulls - 可能不允许使用NULL值, columnNullable - 明确允许使用NULL值, columnNullableUnknown - 不知道是否可使用 null + */ + String NULLABLE = "NULLABLE"; + /** + * 描述列的注释(可为null) + */ + String REMARKS = "REMARKS"; + /** + * 该列的默认值,当值在单引号内时应被解释为一个字符串(可为null) + */ + String COLUMN_DEF = "COLUMN_DEF"; + /** + * 未使用 + */ + String SQL_DATA_TYPE = "SQL_DATA_TYPE"; + /** + * 未使用 + */ + String SQL_DATETIME_SUB = "SQL_DATETIME_SUB"; + /** + * 对于 char 类型,该长度是列中的最大字节数 + */ + String CHAR_OCTET_LENGTH = "CHAR_OCTET_LENGTH"; + /** + * 表中的列的索引(从 1 开始) + */ + String ORDINAL_POSITION = "ORDINAL_POSITION"; + /** + * 是否允许使用 NULL, columnNoNulls - 可能不允许使用NULL值, columnNullable - 明确允许使用NULL值, columnNullableUnknown - 不知道是否可使用 null + */ + String IS_NULLABLE = "IS_NULLABLE"; + /** + * 表的类别,它是引用属性的作用域(如果 DATA_TYPE 不是 REF,则为null) + */ + String SCOPE_CATLOG = "SCOPE_CATLOG"; + /** + * 表的模式,它是引用属性的作用域(如果 DATA_TYPE 不是 REF,则为null) + */ + String SCOPE_SCHEMA = "SCOPE_SCHEMA"; + /** + * 表名称,它是引用属性的作用域(如果 DATA_TYPE 不是 REF,则为null) + */ + String SCOPE_TABLE = "SCOPE_TABLE"; + /** + * 不同类型或用户生成 Ref 类型、来自 java.sql.Types 的 SQL 类型的源类型(如果 DATA_TYPE 不是 DISTINCT 或用户生成的 REF,则为null) + */ + String SOURCE_DATA_TYPE = "SOURCE_DATA_TYPE"; + /** + * 指示此列是否自动增加,YES --- 如果该列自动增加 , NO --- 如果该列不自动增加, 空字符串 --- 如果不能确定该列是否是自动增加参数 + */ + String IS_AUTOINCREMENT = "IS_AUTOINCREMENT"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/RsTableKeyConst.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/RsTableKeyConst.java new file mode 100644 index 0000000..7463a10 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/constant/RsTableKeyConst.java @@ -0,0 +1,15 @@ +package com.yunzhupaas.database.constant; + +public interface RsTableKeyConst { + + /** + * 表名 + */ + String TABLE_NAME = "TABLE_NAME"; + + String TABLE_TYPE = "TABLE_TYPE"; + String REMARKS = "REMARKS"; + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtDMEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtDMEnum.java new file mode 100644 index 0000000..291fbb5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtDMEnum.java @@ -0,0 +1,94 @@ +package com.yunzhupaas.database.datatype.db; + +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.limit.*; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 达梦数据类型 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/25 + */ +@Getter +@AllArgsConstructor +public enum DtDMEnum implements DtInterface { + /*============================ 整型 ===========================*/ + TINY_INT ("TINYINT", new IntegerLimit()), + SMALL_INT ("SMALLINT", new IntegerLimit()), + /** + * 默认长度:10 + */ + INT ("INT", new IntegerLimit()), + /** + * 默认长度:19 + */ + BIGINT ("BIGINT", new IntegerLimit()), + /*============================ 文本字符串类型 ===========================*/ + CHAR ("CHAR", new StringLimit(true).charLength(32767L, 150L)), + /** + * 字节长度:32767,汉字:3字节,特殊字符:3字节 + * 达梦自带迁移使用的是 (MySQL varchar) -> VARCHAR + */ + VARCHAR ("VARCHAR", new StringLimit(true).bitLength(32767L, 150L)), + VARCHAR2 ("VARCHAR2", new StringLimit(true).bitLength(32767L, 150L)), + /** + * 默认长度:2147483647 + */ + TEXT ("TEXT", new StringLimit().fixedCharLength(2147483647L)), + /** + * 默认长度:2147483647 + */ + CLOB ("CLOB", new StringLimit().fixedCharLength(2147483647L)), + BLOB ("BLOB", new StringLimit()), + + /*============================ 时间格式 ===========================*/ + DATE ("DATE", new DateTimeLimit()), + /** + * 默认长度:36,默认精度:6 + * Mysql datetime转达梦 TIMESTAMP,手动改成DATETIME数据会报错 + * 利用 PostGreSQL进行迁移 + */ + DATE_TIME ("DATETIME", new DateTimeLimit()), + /** + * 默认长度:36,默认精度:6 + * 默认工具mysql(Timestamp)--> Dm(DateTime) + */ + TIME_STAMP ("TIMESTAMP", new DateTimeLimit()), + /** + * 默认长度:22,默认精度:6 + */ + TIME ("TIME", new DateTimeLimit()), + /** + * 默认长度:13 + */ + /*============================ 定点型 ===========================*/ + DECIMAL ("DECIMAL", new DecimalLimit(true) + .precision(38, 18).scale(38, 6, 3)), + DEC ("DEC", new DecimalLimit(true) + .precision(38, 18).scale(38, 6, 3)), + /*============================浮点===========================*/ + /** + * 显示real + */ + FLOAT ("FLOAT", new FloatLimit(true).precision(24, 18).scale(30, 3)), + DOUBLE ("DOUBLE", new FloatLimit(true).precision(53, 18).scale(30, 3)), + + ; + + /** + * 数据库字段类型 + */ + private final String dataType; + + /** + * 长度、精度、标度规则模型 + */ + private final DtLimitBase dtLimit; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtDorisEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtDorisEnum.java new file mode 100644 index 0000000..29e3786 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtDorisEnum.java @@ -0,0 +1,95 @@ +package com.yunzhupaas.database.datatype.db; + +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.limit.*; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version v3.4.5 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-12-23 + */ +@Getter +@AllArgsConstructor +public enum DtDorisEnum implements DtInterface { + + /* =============================== 整数类型: TINYINT、SMALLINT、MEDIUMINT、INT(INTEGER)、BIGINT =============================== */ + /* ============== 支持:TINYINT、INT、BIGINT ============= */ + /** + * 短整型 + * 带符号:-128 ~ 127 + * 无符号:255 + */ + TINY_INT ("tinyint", new IntegerLimit().fixedPrecision(3)), + /** + * 与TINYINT一样,0代表false,1代表true + */ + BOOLEAN ("boolean", new IntegerLimit().fixedPrecision(null)), + /** + * 字节有符号整数,范围:[-32768, 32767] + */ + SMALL_INT ("smallint", new IntegerLimit().fixedPrecision(5)), + /** + * 整型 + * -2147483648 ~ 2147483647 + */ + INT ("int", new IntegerLimit().fixedPrecision(10)), + /** + * 长整型 + * -9223372036854775808 ~ 9223372036854775807 + */ + BIGINT ("bigint", new IntegerLimit().fixedPrecision(19)), + LARGE_INT ("largeint", new IntegerLimit().fixedPrecision(null)), + /* =============================== 文本字符串类型: =============================== */ + /** + * 定长字符串,M代表的是定长字符串的长度。M的范围是1-255 + */ + CHAR ("char", new StringLimit(true).charLength(255L,50L)), + /** + * 变长字符串,M代表的是变长字符串的字节长度。M的范围是1-65533 + * 变长字符串是以UTF-8编码存储的,因此英文字符占1个字节,中文字符占3个字节 + */ + VARCHAR ("varchar", new StringLimit(true).charLength(16170L, 50L)), + /** + * 变长字符串,最大支持2147483643字节(2GB-4)。String类型的长度还受BE配置参数 string_type_soft_limit的影响, 实际能存储的最大长度取两者最小值 + * String类型只能用在value列,不能用在key列和分区分桶列 + * 变长字符串是以UTF-8编码存储的,因此英文字符占1个字节,中文字符占3个字节 + */ + STRING ("string", new StringLimit()), + /* =============================== 浮点类型: =============================== */ + FLOAT ("float", new FloatLimit(true).precision(35, 18).scale(30, 3)), + DOUBLE ("double", new FloatLimit(true).fixedPrecision(35).fixedScale(30)), + /* =============================== 定点数类型: =============================== */ + DECIMAL ("decimal", new DecimalLimit(true).precision(27, 18).scale(30, 3)), + /* =============================== 日期时间类型: =============================== */ + DATE ("date", new DateTimeLimit()), + DATE_TIME ("datetime", new DateTimeLimit()), + /* ======= 集合: ======= */ + BITMAP ("BITMAP", new StringLimit()), + /* ======= 聚合类型: ======= */ + /** + * HyperLogLog + * 1~16385 个字节。HLL不能作为key列使用,建表时配合聚合类型为HLL_UNION。用户不需要指定长度和默认值。长度根据数据的聚合程度系统内控制 + * 并且HLL列只能通过配套的hll_union_agg、hll_raw_agg、hll_cardinality、hll_hash进行查询或使用 + * HLL是模糊去重,在数据量大的情况性能优于Count Distinct。HLL的误差通常在1%左右,有时会达到2% + */ + HLL ("HLL", new StringLimit()) + ; + /** + * 数据库字段类型 + */ + private final String dataType; + + /** + * 长度、精度、标度规则模型 + */ + private final DtLimitBase dtLimit; + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtKingbaseESEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtKingbaseESEnum.java new file mode 100644 index 0000000..5c476c2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtKingbaseESEnum.java @@ -0,0 +1,86 @@ +package com.yunzhupaas.database.datatype.db; + +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.limit.*; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 金仓数据类型 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/25 + */ +@Getter +@AllArgsConstructor +public enum DtKingbaseESEnum implements DtInterface { + + /*================================== 整数型 ========================================*/ + TINY_INT ("tinyint", new IntegerLimit()), + SMALL_INT ("smallint", new IntegerLimit()), + /** + * 默认长度:无 + */ + INTEGER ("integer", new IntegerLimit()), + /** + * 默认长度:无 + */ + BIGINT ("bigint", new IntegerLimit()), + /*================================== 文本字符串类型 ========================================*/ + CHAR ("character", new StringLimit(true).charLength(10485760L, 50L)), + /** + * 显示:character varying + */ + VARCHAR ("varchar", new StringLimit(true).charLength(10485760L, 50L)), + /** + * 默认长度:无 + */ + TEXT ("text", new StringLimit()), + /*================================== 浮点型 ========================================*/ + /** + * 显示:real(不允许修改,与sqlserver一样) + */ + FLOAT4 ("float4", new FloatLimit()), + /** + * 显示: double precision + */ + FLOAT8 ("float8", new FloatLimit()), + /*================================== 定点型 ========================================*/ + /** + * 默认长度:无 + */ + NUMERIC ("numeric", new DecimalLimit(true) + .precision(1000, 38).scale(1000, 38)), + /* =============================== 日期时间类型: =============================== */ + /** + * 显示:time without time zone + */ + TIME ("time", new DateTimeLimit()), + DATE ("date", new DateTimeLimit()), + /** + * 有些版本不支持datetime + */ + DATE_TIME ("datetime", new DateTimeLimit()), + /** + * 默认长度:无 + * 显示:timestamp without time zone + */ + TIMESTAMP ("timestamp(0)", new DateTimeLimit()), + BYTEA ("bytea", new StringLimit()), + ; + + /** + * 数据库字段类型 + */ + private final String dataType; + + /** + * 长度、精度、标度规则模型 + */ + private final DtLimitBase dtLimit; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtMySQLEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtMySQLEnum.java new file mode 100644 index 0000000..7de1b40 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtMySQLEnum.java @@ -0,0 +1,119 @@ +package com.yunzhupaas.database.datatype.db; + + +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.limit.*; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * MySQL字段数据类型枚举 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/26 + */ +@Getter +@AllArgsConstructor +public enum DtMySQLEnum implements DtInterface { + + + /* =============================== 整数类型: TINYINT、SMALLINT、MEDIUMINT、INT(INTEGER)、BIGINT =============================== */ + /* ============== 支持:TINYINT、INT、BIGINT ============= */ + /** + * 短整型 + * 带符号:-128 ~ 127 + * 无符号:255 + */ + TINY_INT ("tinyint", new IntegerLimit().fixedPrecision(3)), + SMALL_INT ("smallint", new IntegerLimit().fixedPrecision(5)), + MEDIUM_INT ("mediumint", new IntegerLimit().fixedPrecision(7)), + /** + * 整型 + * -2147483648 ~ 2147483647 + */ + INT ("int", new IntegerLimit().fixedPrecision(10)), + /** + * 长整型 + * -9223372036854775808 ~ 9223372036854775807 + */ + BIGINT ("bigint", new IntegerLimit().fixedPrecision(19)), + /* =============================== 文本字符串类型: =============================== */ + BIT ("bit", new StringLimit(true).charLength(15L, 64L)), + BLOB ("blob", new StringLimit()), + CHAR ("char", new StringLimit(true).charLength(50L,255L)), + /** + * 字符串 + * 默认最大长度16170(65535 bytes) + * 标注:当varchar当主键的时候,最长是768(3072 bytes),当长度过长时推荐用text + */ + VARCHAR ("varchar", new StringLimit(true).charLength(16170L, 50L)), + /** + * 文本 + * 默认长度:0 + */ + TINY_TEXT ("tinytext", new StringLimit().fixedCharLength(225L)), + TEXT ("text", new StringLimit().fixedCharLength(65535L)), + MEDIUM_TEXT ("mediumtext", new StringLimit().fixedCharLength(16777215L)), + /** + * 长文本 + * 默认长度:0 + * longtext支持65535字节长度,utf8编码下最多支持21843个字符 + */ + LONG_TEXT ("longtext", new StringLimit().fixedBitLength(4294967295L)), + /** + * 二进制大对象 longblob (lang binary large object) + */ + LONG_BLOB ("longblob", new StringLimit().fixedCharLength(0L)), + /* =============================== 浮点类型: =============================== */ + /** + * float:单精度(4个字节,8位精度), + * double:双精度(8个字节,16位精度) + * 总结:double精度更高,占用更大,float精度更低,运算更快 + */ + FLOAT ("float", new FloatLimit(true).precision(255, 18).scale(30, 3)), + DOUBLE ("double", new FloatLimit(true).precision(255, 18).scale(30, 3)), + /* =============================== 定点数类型: =============================== */ + DECIMAL ("decimal", new DecimalLimit(true).precision(65, 18).scale(30, 3)), + /* =============================== 日期时间类型: =============================== */ + /** + * 示例:14:50:42.000000 (长度6)、14:50:42.0(长度1) + */ + TIME ("time", new DateTimeLimit(true).scale(6, 6)), + /** + * 示例:2022-06-06 14:53:12.000000(长度6)、2022-06-06 14:53:12.0(长度1) + */ + DATE_TIME ("datetime", new DateTimeLimit(true).scale(6, 6)), + /** + * 示例:2022-06-06 14:56:04.000000(长度6)、2022-06-06 14:56:04.0(长度1) + */ + TIMESTAMP ("timestamp", new DateTimeLimit(true).scale(6, 6)), + /** + * 示例:1992、2020、2060 + */ + YEAR ("year", new DateTimeLimit(true).precision(4, 4)), + DATE ("date", new DateTimeLimit()), + + + /* ======= 枚举类型: ======= */ + /* ======= 集合类型: ======= */ + /* ======= 二进制字符串类型: ======= */ + /* ======= JSON类型: ======= */ + /* ======= 空间数据类型: ======= */ + ; + /** + * 数据库字段类型 + */ + private final String dataType; + + /** + * 长度、精度、标度规则模型 + */ + private final DtLimitBase dtLimit; + + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtOracleEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtOracleEnum.java new file mode 100644 index 0000000..95a3743 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtOracleEnum.java @@ -0,0 +1,80 @@ +package com.yunzhupaas.database.datatype.db; + + +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.limit.DateTimeLimit; +import com.yunzhupaas.database.datatype.limit.FloatLimit; +import com.yunzhupaas.database.datatype.limit.NumberLimit; +import com.yunzhupaas.database.datatype.limit.StringLimit; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Oracle数据类型 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/25 + */ +@Getter +@AllArgsConstructor +public enum DtOracleEnum implements DtInterface { + + /*================================== 整数型 ========================================*/ + /** + * 长度:1---38 + * 精度:-84---127 + */ + NUMBER ("NUMBER", new NumberLimit(true).precision(38, 11).scale(127, -84)), + /* =============================== 文本字符串类型 =============================== */ + CHAR ("CHAR", new StringLimit(true).charLength(2000L, 50L)), + NCHAR ("VARCHAR2", new StringLimit(true).charLength(2000L, 50L)), + /** + * VARCHAR2支持4000个字节,4000个字母,1333个汉字,汉字:3个字节 + * NVARCHAR2支持2000个字符,2000个字母,2000个汉字,不管是汉字还是字母,每个字符的长度都是2个字节,不受数据库字符集 + */ + VARCHAR2 ("VARCHAR2", new StringLimit(true).bitLength(4000L, 50L)), + NVARCHAR2 ("NVARCHAR2", new StringLimit(true).charLength(2000L, 50L)), + /** + * 默认长度:4000 + * TEXT与BLOB的主要差别就是BLOB保存二进制数据,TEXT保存字符数据 + */ + /** + * 1.BLOB + * BLOB全称为二进制大型对象(Binary Large Object)。它用于存储数据库中的大型二进制对象。可存储的最大大小为4G字节 + * 2.CLOB + * CLOB全称为字符大型对象(Character Large Object)。它与LONG数据类型类似,只不过CLOB用于存储数据库中的大型单字节字符数据块,不支持宽度不等的字符集。可存储的最大大小为4G字节 + * 3.NCLOB + * 基于国家语言字符集的NCLOB数据类型用于存储数据库中的固定宽度单字节或多字节字符的大型数据块,不支持宽度不等的字符集。可存储的最大大小为4G字节 + */ + CLOB ("CLOB", new StringLimit()), + BLOB ("BLOB", new StringLimit()), + NCLOB ("NCLOB", new StringLimit()), + /* =============================== 浮点类型 =============================== */ + /** + * 除了oracle其他库浮点型,都无法修改参数 + */ + FLOAT ("FLOAT", new FloatLimit(true).precision(126, 18).scale(126, 3)), + /* =============================== 日期时间类型: =============================== */ + /** + * 默认长度:7 + */ + DATE ("DATE", new DateTimeLimit()), + TIMESTAMP ("TIMESTAMP", new DateTimeLimit()), + ; + + /** + * 数据库字段类型 + */ + private final String dataType; + + /** + * 长度、精度、标度规则模型 + */ + private final DtLimitBase dtLimit; + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtPostgreSQLEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtPostgreSQLEnum.java new file mode 100644 index 0000000..c313ba3 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtPostgreSQLEnum.java @@ -0,0 +1,75 @@ +package com.yunzhupaas.database.datatype.db; + + +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.limit.*; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * PostgreSQL数据类型 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/25 + */ +@Getter +@AllArgsConstructor +public enum DtPostgreSQLEnum implements DtInterface { + + /*================================== 整数型 ========================================*/ + /** + * 类型名称: smallint + */ + INT2 ("int2", new IntegerLimit()), + /** + * 类型名称: integer + * 默认长度:32 + */ + INT4 ("int4", new IntegerLimit()), + /** + * 类型名称: bigint + * 默认长度:64 + */ + INT8 ("int8", new IntegerLimit()), + /*================================== 文本字符串类型 ========================================*/ + CHAR ("char", new StringLimit(true).charLength(10485760L, 50L)), + VARCHAR ("varchar", new StringLimit(true).charLength(10485760L, 50L)), + /** + * 默认长度:无 + */ + TEXT ("text", new StringLimit()), + /*================================== 浮点型 ========================================*/ + FLOAT4 ("float4", new FloatLimit(true).precision(24, 18).scale(18, 3)), + /** + * 类型名称: double + */ + FLOAT8 ("float8", new FloatLimit(true).precision(53, 18).scale(18, 3)), + /*================================== 定点型 ========================================*/ + NUMERIC ("numeric", new DecimalLimit(true).precision(1000, 18).scale(100, 3)), + /*================================== 时间日期 ========================================*/ + TIME ("time", new DateTimeLimit()), + DATE ("date", new DateTimeLimit()), + /** + * 默认长度:6 + */ + TIMESTAMP ("timestamp", new DateTimeLimit()), + BYTEA ("bytea", new StringLimit()), + ; + + /** + * 数据库字段类型 + */ + private final String dataType; + + /** + * 长度、精度、标度规则模型 + */ + private final DtLimitBase dtLimit; + + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtSQLServerEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtSQLServerEnum.java new file mode 100644 index 0000000..770b745 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/DtSQLServerEnum.java @@ -0,0 +1,99 @@ +package com.yunzhupaas.database.datatype.db; + + +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.limit.*; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * SQLServer数据类型 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/25 + */ +@Getter +@AllArgsConstructor +public enum DtSQLServerEnum implements DtInterface { + + /* =============================== 整数类型 =============================== */ + TINY_INT ("tinyint", new IntegerLimit()), + SMALL_INT ("smallint", new IntegerLimit()), + /** + * 默认长度:无 + */ + INT ("int", new IntegerLimit()), + /** + * 默认长度:无 + */ + BIGINT ("bigint", new IntegerLimit()), + /* =============================== 文本字符串类型 =============================== */ + CHAR ("char", new StringLimit(true).charLength(8000L, 50L)), + + /** + * N 代表Unicode可变长度类型 + * NVARCHAR 字符存储,VARCHAR 字节存储 + * 推荐:使用nvarchar ,虽然varchar比nvarchar省空间,但空间相对来说已经不是奢侈的了,而且带来的问题也很严重, + * 因为varchar是非Unicode所以系统读取数据都会进行一次Unicode转码,nvarchar不会转码,这是其一,其二如果操作系统是英文操作系统, + * 那么用varchar存储的汉字会出现乱码的情况,varchar是单字节存储,nvarchar是双字节存储 + */ + NVARCHAR ("nvarchar", new StringLimit(true).charLength(8000L, 50L)), + VARCHAR ("varchar", new StringLimit(true).charLength(4000L, 50L)), + /* Text 和 Image 是可能被 SQServer 以后的版本淘汰的数据类型 + varchar(max)-------text; + nvarchar(max)-----ntext; + varbinary(max)----p_w_picpath. + nvarchar长度会显示-1 + 查询出来只能显示nvarchar,长度-1的时候代表nvarchar(max),项目中转换成text */ + /** + * 默认长度:4005 + */ + VARCHAR_MAX ("nvarchar(max)",new StringLimit().fixedCharLength(4005L)), + VARBINARY ("varbinary(max)", new StringLimit()), + /** + * 默认长度:无 + * 长度可变的非 Unicode 数据 + */ + TEXT ("text", new StringLimit()), + /** + * 长度可变的 Unicode 数据 + * + */ + N_TEXT ("ntext", new StringLimit()), + /** + * 长度可变的二进制数据 + */ + IMAGE ("image", new StringLimit()), + /* =============================== 浮点类型: =============================== */ + /** + * 显示 real + */ + FLOAT ("float", new FloatLimit().precision(53, 18).scale(18, 3)), + /* =============================== 日期时间类型: =============================== */ + DATE ("date", new DateTimeLimit()), + /** + * 默认长度:4005 + */ + TIME ("time", new DateTimeLimit()), + DATE_TIME ("datetime", new DateTimeLimit()), + DATE_TIME2 ("datetime2", new DateTimeLimit()), + TIMESTAMP ("timestamp", new DateTimeLimit()), + /* =============================== 定点数类型: =============================== */ + DECIMAL ("decimal", new DecimalLimit(true).precision(38, 18).scale(18, 3)), + ; + + /** + * 数据库字段类型 + */ + private final String dataType; + + /** + * 长度、精度、标度规则模型 + */ + private final DtLimitBase dtLimit; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/interfaces/DtInterface.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/interfaces/DtInterface.java new file mode 100644 index 0000000..938c6a7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/interfaces/DtInterface.java @@ -0,0 +1,192 @@ +package com.yunzhupaas.database.datatype.db.interfaces; + +import com.yunzhupaas.database.datatype.limit.base.DtLimitModel; +import com.yunzhupaas.database.datatype.viewshow.ViewDataTypeEnum; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.util.StringUtil; + +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * 数据库数据类型接口 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/11/26 + */ +public interface DtInterface { + + /** + * 以字符为单位的最大长度,适于二进制数据、字符数据,或者文本和图像数据。否则,返回 NULL + * 例如:text、varchar(int时为null),其中varchar为可变长度,text为固定长度 + */ + String CHARACTER_LENGTH = "CHARACTER_MAXIMUM_LENGTH"; + + /** + * precision:数值精度(整个数值的长度) + * 例如:decimal + * 注意:int(i)类型时,无论i是多少,NUMERIC_PRECISION都是10,在填充0的时候i才会起作用 + */ + String NUMERIC_PRECISION = "NUMERIC_PRECISION"; + + /** + * scale:数值标度(小数部分的长度) + */ + String NUMERIC_SCALE = "NUMERIC_SCALE"; + + /** + * 获取数据库自身数据类型 + * + * @return ignore + */ + String getDataType(); + + /** + * 获取枚举名 + * + * @return ignore + */ + String name(); + + /** + * 获取长度规则模型 + * + * @return ignore + */ + DtLimitBase getDtLimit(); + + /** + * 字符长度 + */ + default DtLimitModel getCharLengthLm() { + return getDtLimit().getCharLengthLm(); + } + + /** + * 字节长度 + */ + default DtLimitModel getBitLengthLm() { + return getDtLimit().getBitLengthLm(); + } + + /** + * 精度 + */ + default DtLimitModel getNumPrecisionLm() { + return getDtLimit().getNumPrecisionLm(); + } + + /** + * 标度 + */ + default DtLimitModel getNumScaleLm() { + return getDtLimit().getNumScaleLm(); + } + + /** + * 数据类型 + */ + default String getDtCategory() { + return getDtLimit().getDtCategory(); + } + + /** + * 是否可修改 + */ + default Boolean getIsModifyFlag() { + return getDtLimit().getIsModifyFlag(); + } + + /** + * java类型 + */ + default String getJavaType() { + return getDtLimit().getJavaType(); + } + + /** + * 数据库类型 + * + * @return dbType + */ + default String getDbType() { + return this.getClass().getSimpleName().replace("Dt", "").replace("Enum", ""); + } + + /** + * 根据数据库类型编码获取枚举类 + */ + static Class getClz(String dbType) throws Exception { + // 数据类型枚举类命名规则:Dt + yunzhupaasDbEncode + return (Class) Class.forName("com.yunzhupaas.database.datatype.db.Dt" + dbType + "Enum"); + } + + /** + * 根据前端数据类型,返回对应枚举 + * + * @param viewDataType 前端数据类型名称 + * @param dbEncode 数据类型枚数据库编码 + * @return 数据类型枚举 + */ + static DtInterface newInstanceByView(String viewDataType, String dbEncode) throws Exception { + if (StringUtil.isNotNull(viewDataType)) { + for (ViewDataTypeEnum value : ViewDataTypeEnum.values()) { + if (value.getViewFieldType().equalsIgnoreCase(viewDataType)) { + switch (dbEncode) { + case DbBase.MYSQL: + return value.getDtMySQLEnum(); + case DbBase.ORACLE: + return value.getDtOracleEnum(); + case DbBase.SQL_SERVER: + return value.getDtSQLServerEnum(); + case DbBase.DM: + return value.getDtDMEnum(); + case DbBase.KINGBASE_ES: + return value.getDtKingbaseESEnum(); + case DbBase.POSTGRE_SQL: + return value.getDtPostgreSQLEnum(); + default: + } + } + } + } + return null; + } + + /** + * 根据数据类型,返回对应枚举 + * + * @param dtDataType 数据库数据类型名称 + * @param dbEncode 数据类型枚数据库编码 + * @return 数据类型枚举 + */ + static DtInterface newInstanceByDt(String dtDataType, String dbEncode) throws Exception { + BiFunction checkDataType = (dataType, dbType) -> { + switch (dbType) { + case DbBase.MYSQL: + if (dataType.equalsIgnoreCase("INT UNSIGNED")) + return "int"; + if (dataType.equalsIgnoreCase("BIGINT UNSIGNED")) + return "bigint"; + case DbBase.ORACLE: + case DbBase.SQL_SERVER: + case DbBase.DM: + case DbBase.KINGBASE_ES: + case DbBase.POSTGRE_SQL: + default: + return dataType; + } + }; + + // 当类型无法在预设中找到时,在枚举中寻找 + for (DtInterface enumConstant : getClz(dbEncode).getEnumConstants()) { + if (enumConstant.getDataType().equalsIgnoreCase(checkDataType.apply(dtDataType, dbEncode))) { + return enumConstant; + } + } + return null; + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/interfaces/DtLimitBase.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/interfaces/DtLimitBase.java new file mode 100644 index 0000000..2f50b2e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/db/interfaces/DtLimitBase.java @@ -0,0 +1,154 @@ +package com.yunzhupaas.database.datatype.db.interfaces; + +import com.yunzhupaas.database.datatype.limit.base.DtLimitModel; +import com.yunzhupaas.database.datatype.model.DtModel; +import com.yunzhupaas.database.datatype.model.DtModelDTO; +import lombok.AccessLevel; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.Getter; + +/** + * 数据类型:长度精度限制 + * default:为可变长度时的默认值 + * fixed:不可变长度的固有值 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-05-19 + */ +@Data +public abstract class DtLimitBase { + + { + this.dtCategory = initDtCategory(); + } + + /** + * 数据类型 - 归属 + */ + protected String dtCategory; + + /** + * 数据类型 - 可修改表示 + * true:可修改 false:不可修改 + */ + protected Boolean isModifyFlag = false; + + private String javaType; + + /** + * 默认最短长度 + */ + private final static Integer YUNZHUPAAS_MIN_LENGTH = 0; + private final static Integer ONE_MIN_LENGTH = 1; + + /* 数据类型 - 长度限制模型 =========== */ + /** + * 字符长度 + * 会显示类似5E+1长度的字符串,例如:4294967295,固Long类型 + */ + @Getter(AccessLevel.PACKAGE) + private DtLimitModel charLengthLm; + + /** + * 字节长度 + */ + @Getter(AccessLevel.PACKAGE) + private DtLimitModel bitLengthLm; + + /** + * 精度(数值整体长度) + * >= 1 + */ + @Getter(AccessLevel.PACKAGE) + private DtLimitModel numPrecisionLm; + + /** + * 标度(数值小数点长度) + * >= 0 && 标度 < 精度 + * 默认为: 0 + */ + @Getter(AccessLevel.PACKAGE) + private DtLimitModel numScaleLm; + + /** + * 设置数据归档类型 + */ + public abstract String initDtCategory(); + + /** + * 转换 + * 特殊:MySQL的varchar作为主键的长度是一个特殊值 + * + * @param dtModelDTO 前端数据类型模型 + * @return 数据类型模型 + */ + public abstract DtModel convert(DtModelDTO dtModelDTO); + + /* ======================================== */ + + /** + * 精度 + */ + public DtLimitBase precision(Integer precisionMax, Integer precisionDefault) { + this.numPrecisionLm = new DtLimitModel(precisionMax, ONE_MIN_LENGTH, precisionDefault); + return this; + } + + /** + * 标度 + */ + public DtLimitBase scale(Integer scaleMax, Integer scaleDefault) { + return scale(scaleMax, YUNZHUPAAS_MIN_LENGTH, scaleDefault); + } + + public DtLimitBase scale(Integer scaleMax, Integer scaleMin, Integer scaleDefault) { + this.numScaleLm = new DtLimitModel(scaleMax, scaleMin, scaleDefault); + return this; + } + + /** + * 字符长度 + */ + + public DtLimitBase charLength(Long charLengthMax, Long defaultLength) { + this.charLengthLm = new DtLimitModel(charLengthMax, ONE_MIN_LENGTH, defaultLength); + return this; + } + + /** + * 字节长度 + */ + public DtLimitBase bitLength(Long bitLengthMax, Long defaultLength) { + this.bitLengthLm = new DtLimitModel(bitLengthMax, ONE_MIN_LENGTH, defaultLength); + return this; + } + + /* ==================== 固定长度(当没有输入默认长度时,为固定长度) ====================== */ + + /** + * 固定精度标度 + */ + public DtLimitBase fixedScale(Integer scaleFixed) { + this.numScaleLm = new DtLimitModel(scaleFixed); + return this; + } + + public DtLimitBase fixedPrecision(Integer precisionFixed) { + this.numPrecisionLm = new DtLimitModel(precisionFixed); + return this; + } + + public DtLimitBase fixedBitLength(Long bitLengthFixed) { + this.bitLengthLm = new DtLimitModel(bitLengthFixed); + return this; + } + + public DtLimitBase fixedCharLength(Long charLengthFixed) { + this.charLengthLm = new DtLimitModel(charLengthFixed); + return this; + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/DateTimeLimit.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/DateTimeLimit.java new file mode 100644 index 0000000..e2a2299 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/DateTimeLimit.java @@ -0,0 +1,41 @@ +package com.yunzhupaas.database.datatype.limit; + +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.model.DtModel; +import com.yunzhupaas.database.datatype.model.DtModelDTO; +import lombok.NoArgsConstructor; + +/** + * 时间数据类型 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-06 + */ +@NoArgsConstructor +public class DateTimeLimit extends DtLimitBase { + + public final static String CATEGORY = "type-DateTime"; + public final static String JAVA_TYPE = "date"; + + public DateTimeLimit(Boolean modify){ + this.isModifyFlag = modify; + } + + @Override + public String initDtCategory() { + return CATEGORY; + } + + @Override + public DtModel convert(DtModelDTO dtModelDTO){ + DtModel dataTypeModel = new DtModel(dtModelDTO.getConvertTargetDtEnum()); + if(this.isModifyFlag){ + dataTypeModel.setFormatLengthStr(""); + } + return dataTypeModel; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/DecimalLimit.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/DecimalLimit.java new file mode 100644 index 0000000..df97765 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/DecimalLimit.java @@ -0,0 +1,41 @@ +package com.yunzhupaas.database.datatype.limit; + +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.limit.util.DtLimitUtil; +import com.yunzhupaas.database.datatype.model.DtModel; +import com.yunzhupaas.database.datatype.model.DtModelDTO; + +/** + * 小数数据类型 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-06 + */ +public class DecimalLimit extends DtLimitBase { + + public final static String CATEGORY = "type-Decimal"; + public final static String JAVA_TYPE = "decimal"; + {this.dtCategory = CATEGORY;} + + public DecimalLimit(Boolean modify) { + this.isModifyFlag = modify; + } + + @Override + public String initDtCategory() { + return CATEGORY; + } + + @Override + public DtModel convert(DtModelDTO viewDtModel){ + DtModel dataTypeModel = DtLimitUtil.convertNumeric(viewDtModel); + if(this.isModifyFlag){ + DtLimitUtil.getNumericLength(dataTypeModel); + } + return dataTypeModel; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/FloatLimit.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/FloatLimit.java new file mode 100644 index 0000000..a56367d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/FloatLimit.java @@ -0,0 +1,42 @@ +package com.yunzhupaas.database.datatype.limit; + +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.limit.util.DtLimitUtil; +import com.yunzhupaas.database.datatype.model.DtModel; +import com.yunzhupaas.database.datatype.model.DtModelDTO; +import lombok.NoArgsConstructor; + +/** + * 浮点数据类型 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-06 + */ +@NoArgsConstructor +public class FloatLimit extends DtLimitBase { + + public final static String CATEGORY = "type-Float"; + public final static String JAVA_TYPE = "float"; + + public FloatLimit(Boolean modify){ + this.isModifyFlag = modify; + } + + @Override + public String initDtCategory() { + return CATEGORY; + } + + @Override + public DtModel convert(DtModelDTO viewDtModel){ + DtModel dataTypeModel = DtLimitUtil.convertNumeric(viewDtModel); + if(this.isModifyFlag){ + DtLimitUtil.getNumericLength(dataTypeModel); + } + return dataTypeModel; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/IntegerLimit.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/IntegerLimit.java new file mode 100644 index 0000000..ea1f42d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/IntegerLimit.java @@ -0,0 +1,73 @@ +package com.yunzhupaas.database.datatype.limit; + +import com.yunzhupaas.database.datatype.db.DtMySQLEnum; +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.model.DtModel; +import com.yunzhupaas.database.datatype.model.DtModelDTO; +import com.yunzhupaas.database.datatype.sync.util.DtSyncUtil; +import com.yunzhupaas.database.source.DbBase; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 整型数据类型 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-06 + */ +@Data +@NoArgsConstructor +public class IntegerLimit extends DtLimitBase { + + public final static String CATEGORY = "type-Integer"; + public final static String JAVA_TYPE = "int"; + + @Override + public String initDtCategory() { + return CATEGORY; + } + + @Override + public DtModel convert(DtModelDTO viewDtModel){ + DtInterface targetDtEnum = viewDtModel.getConvertTargetDtEnum(); + DtModel toModel = new DtModel(targetDtEnum); + // 当转换成Oracle的数字类型 + if(targetDtEnum.getDtCategory().equals(NumberLimit.CATEGORY)){ + try{ + // 先当前数据库转成DtMySQL枚举 + DtMySQLEnum dtEnum = (DtMySQLEnum) DtSyncUtil.getToFixCovert(targetDtEnum, DbBase.MYSQL); + // 在进行转换对比 + switch (dtEnum){ + case TINY_INT: + toModel.setNumPrecision(3); + break; + case SMALL_INT: + toModel.setNumPrecision(5); + break; + case MEDIUM_INT: + toModel.setNumPrecision(7); + break; + case INT: + toModel.setNumPrecision(10); + break; + case BIGINT: + toModel.setNumPrecision(19); + break; + default: + } + }catch (Exception e){ + e.printStackTrace(); + } + } + if(this.isModifyFlag){ + toModel.setFormatLengthStr(""); + } + return toModel; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/NumberLimit.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/NumberLimit.java new file mode 100644 index 0000000..85c7b6e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/NumberLimit.java @@ -0,0 +1,57 @@ +package com.yunzhupaas.database.datatype.limit; + +import com.yunzhupaas.database.datatype.db.DtOracleEnum; +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.limit.util.DtLimitUtil; +import com.yunzhupaas.database.datatype.model.DtModel; +import com.yunzhupaas.database.datatype.model.DtModelDTO; +import com.yunzhupaas.database.source.DbBase; + +/** + * 数字数据类型 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-06 + */ +public class NumberLimit extends DtLimitBase { + + public final static String CATEGORY = "type-Number"; + public final static String JAVA_TYPE = "number"; + + public NumberLimit(Boolean modify){ + this.isModifyFlag = modify; + } + + @Override + public String initDtCategory() { + return CATEGORY; + } + + @Override + public DtModel convert(DtModelDTO viewDtModel){ + DtModel dataTypeModel; + switch (viewDtModel.getDtEnum().getDtCategory()){ + case DecimalLimit.CATEGORY: + case IntegerLimit.CATEGORY: + case NumberLimit.CATEGORY: + dataTypeModel = DtLimitUtil.convertNumeric(viewDtModel); + break; + default: + dataTypeModel = new DtModel(viewDtModel.getDtEnum()); + } + if(viewDtModel.getConvertTargetDtEnum().getIsModifyFlag()){ + if(viewDtModel.getConvertTargetDtEnum().getDbType().equals(DbBase.ORACLE)){ + if(dataTypeModel.getNumPrecision().equals(0) && dataTypeModel.getNumScale().equals(0)){ + dataTypeModel.setNumPrecision(Integer.valueOf(DtOracleEnum.NUMBER.getNumPrecisionLm().getDefaults().toString())); + dataTypeModel.setNumScale(Integer.valueOf(DtOracleEnum.NUMBER.getNumScaleLm().getDefaults().toString())); + } + } + DtLimitUtil.getNumericLength(dataTypeModel); + } + return dataTypeModel; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/StringLimit.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/StringLimit.java new file mode 100644 index 0000000..209da60 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/StringLimit.java @@ -0,0 +1,91 @@ +package com.yunzhupaas.database.datatype.limit; + +import com.yunzhupaas.database.datatype.db.DtMySQLEnum; +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.db.interfaces.DtLimitBase; +import com.yunzhupaas.database.datatype.limit.base.DtLimitModel; +import com.yunzhupaas.database.datatype.limit.util.DtLimitUtil; +import com.yunzhupaas.database.datatype.model.DtModel; +import com.yunzhupaas.database.datatype.model.DtModelDTO; +import com.yunzhupaas.database.source.DbBase; +import lombok.NoArgsConstructor; + +import java.util.function.BiFunction; + +/** + * 字符串数据类型 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-06 + */ +@NoArgsConstructor +public class StringLimit extends DtLimitBase { + + public final static String CATEGORY = "type-String"; + public final static String JAVA_TYPE = "String"; + + @Override + public String initDtCategory() { + return CATEGORY; + } + + public StringLimit(Boolean modify){ + this.isModifyFlag = modify; + } + + @Override + public DtModel convert(DtModelDTO dto){ + DtInterface originEnum = dto.getDtEnum(); + DtInterface targetEnum = dto.getConvertTargetDtEnum(); + DtModel dataTypeModel = new DtModel(targetEnum); + special(dto); + if(this.isModifyFlag){ + // 设置模型 + BiFunction setMod = (inputVarLength, varLengthLm)->{ + // 长度设置; + Long targetLength = DtLimitUtil.convertCharacter(inputVarLength, dto.getConvertType(), varLengthLm); + // 获取字符类型显示 + dataTypeModel.setFormatLengthStr(targetLength.toString()); + return targetLength; + }; + // 字节字符转换规则 + boolean originBigFlag = originEnum.getBitLengthLm() != null; + boolean originCharFlag = originEnum.getCharLengthLm() != null; + boolean targetBigFlag = targetEnum.getBitLengthLm() != null; + boolean targetCharFlag = targetEnum.getCharLengthLm() != null; + /* GBK 1字符=2字节,UTF8 1字符=3字节 */ + if(originBigFlag && targetCharFlag){ + // 字节 -> 字符 /3 + dataTypeModel.setCharLength(setMod.apply(dto.getBitLength() / 3, targetEnum.getCharLengthLm())); + }else if(originCharFlag && targetBigFlag){ + // 字符 -> 字节 *3 + dataTypeModel.setBitLength(setMod.apply(dto.getCharLength() * 3, targetEnum.getBitLengthLm())); + }else if(originBigFlag && targetBigFlag){ + // 字节 -> 字节 == + dataTypeModel.setBitLength(setMod.apply(dto.getBitLength(), targetEnum.getBitLengthLm())); + }else if(originCharFlag){ + // 字符 -> 字符 == + dataTypeModel.setCharLength(setMod.apply(dto.getCharLength(), targetEnum.getCharLengthLm())); + } + } + return dataTypeModel; + } + + /** + * 特殊情况 + */ + public void special(DtModelDTO dto){ + DtInterface originEnum = dto.getDtEnum(); + if(originEnum.getDbType().equals(DbBase.MYSQL) && + originEnum.getDataType().equals(DtMySQLEnum.BIT.getDataType()) && + dto.getCharLength() == 1){ + /* MySQL设置tinyint类型且长度为1时,JDBC读取时会变成BIT类型,java类型为Boolean类型。 + 1:true , 0:false , 当前先转换成字符串格式,长度为5*/ + dto.setCharLength(15L); + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/base/DtLimitModel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/base/DtLimitModel.java new file mode 100644 index 0000000..27f45d7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/base/DtLimitModel.java @@ -0,0 +1,58 @@ +package com.yunzhupaas.database.datatype.limit.base; + +import lombok.AllArgsConstructor; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-06 + */ +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +public class DtLimitModel { + + /** + * 最大长度 + */ + private Object max; + + /** + * 最小长度 + */ + private Object min; + + /** + * 默认长度 + */ + private Object defaults; + + /** + * 固定长度 + */ + private Object fixed; + + public DtLimitModel(Object fixed){ + this.fixed = fixed; + } + + /** + * 生成类型限制对象 + */ + public DtLimitModel(Object maxLength, Object minLength, Object defaultLength){ + this.max = maxLength; + this.min = minLength; + this.defaults = defaultLength; + this.fixed = defaultLength; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/base/DtModelBase.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/base/DtModelBase.java new file mode 100644 index 0000000..ea59b0e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/base/DtModelBase.java @@ -0,0 +1,45 @@ +package com.yunzhupaas.database.datatype.limit.base; + +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version v3.4.5 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-12-15 + */ +@Data +public class DtModelBase { + + /** + * 数据类型枚举 + */ + protected DtInterface dtEnum; + + /** + * 字符长度(1个字母1个字节,1个汉字1个字节) + */ + protected Long charLength; + + /** + * 字节长度(1个字母1个字节,1个汉字GBK:2个字节,UTF8:3个字节) + */ + protected Long bitLength; + + /** + * 精度(数值整体长度) + */ + protected Integer numPrecision; + + /** + * 标度(数值小数点长度) + */ + protected Integer numScale; + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/util/DtLimitUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/util/DtLimitUtil.java new file mode 100644 index 0000000..00d5358 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/limit/util/DtLimitUtil.java @@ -0,0 +1,152 @@ +package com.yunzhupaas.database.datatype.limit.util; + +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.limit.base.DtLimitModel; +import com.yunzhupaas.database.datatype.model.DtModel; +import com.yunzhupaas.database.datatype.model.DtModelDTO; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-06 + */ +public class DtLimitUtil { + + + /* ============== 转换方式 =============== */ + /* + * 说明: + * 1、不可修改转可修改(按默认值) + * 2、可修改转可修改 + * 3、创建可修改 + * + * (以下都不进行长度设置) + * 4、可修改转不可修改 + * 5、不可修改转不可修改 + * 6、创建不可修改 + * */ + + /** + * 数值转换 + * @param dto 前端数据类型模型 + * @return 转换数据类型模板 + */ + public static DtModel convertNumeric(DtModelDTO dto){ + DtInterface toDtEnum = dto.getConvertTargetDtEnum(); + DtModel toModel = new DtModel(toDtEnum); + DtLimitModel numPrecisionLm = toDtEnum.getNumPrecisionLm(); + DtLimitModel numScaleLm = toDtEnum.getNumScaleLm(); + // 精度、标度:标准化 ========= + Integer numPrecision = dto.getNumPrecision(); + Integer numScale = dto.getNumScale(); + if(toDtEnum.getIsModifyFlag()){ + switch (dto.getConvertType()){ + // 1:数据库取到的值 + case DtModelDTO.DB_VAL: + break; + // 2:使用固定值 + case DtModelDTO.FIX_VAL: + numPrecision = (Integer) numPrecisionLm.getFixed(); + numScale = (Integer) numScaleLm.getFixed(); + break; + // 3:前端传来的参数 + case DtModelDTO.VIEW_VAL: + // 验证比较 + numPrecision = convertNum(numPrecision, (Integer) numPrecisionLm.getMin(), (Integer) numPrecisionLm.getMax(), (Integer)numPrecisionLm.getDefaults()); + numScale = convertNum(numScale, (Integer) numScaleLm.getMin(), (Integer) numScaleLm.getMax(), (Integer)numScaleLm.getDefaults()); + break; + default: + } + // 数据型设置 ========= + toModel.setNumPrecision(numPrecision); + toModel.setNumScale(numScale); + toModel.formatNumLength(numPrecision, numScale); + } + return toModel; + } + + /** + * 字符转换 + * @return 转换数据类型模板 + */ + public static Long convertCharacter(Long inputVarLength, String convertType, DtLimitModel varLengthLm){ + // 精度、标度:标准化 ========= + Long outVarLength = null; + switch (convertType){ + // 1:数据库取到的值,且同库(不用转换直接使用) + case DtModelDTO.DB_VAL: + outVarLength = inputVarLength; + break; + // 2:使用固定值 + case DtModelDTO.FIX_VAL: + outVarLength = (Long)varLengthLm.getFixed(); + break; + // 3:主要转换:前端传来的参数 + case DtModelDTO.VIEW_VAL: + // 验证比较 + outVarLength = convertLongNum(inputVarLength, (Long) varLengthLm.getMax(), (Long) varLengthLm.getDefaults()); + break; + default: + } + return outVarLength; + } + + /* ================ */ + + /** + * 获取数值类型显示 + */ + public static void getNumericLength(DtModel model){ + model.setFormatLengthStr(model.getNumPrecision() + "," + model.getNumScale()); + } + + /* =========== 内部使用算法 =========== */ + + /** + * originNum < [Min, Max] < originNum + */ + private static Integer convertNum(Integer originNum, Integer toMin, Integer toMax, Integer defaultNum){ + originNum = originNum == null || originNum < toMin ? defaultNum : originNum; + // 区间内 + if(originNum >= toMin && toMax >= originNum){ + return originNum; + }else if(originNum > toMax){ + // 大于区间,为保证尽可能数据不丢失,返回最大长度 + return toMax; + }else { + return toMin; + } + } + + /** + * charLength 的 Long类型 + * >= 0 + */ + private static Long convertLongNum(Long originNum, Long toMax, Long defaultNum){ + originNum = originNum == null || originNum < 1 ? defaultNum : originNum; + if(originNum <= toMax){ + return originNum; + }else{ + return toMax; + } + } + + /* + 说明: + UTF-8:一个汉字 = 3个字节,英文一个字母占用一个字节 + GBK: 一个汉字 = 2个字节,英文一个字母占用一个字节 + MySQL的char_length计算的是字符长度,而Oracle的bit_length计算的是字节长度 + + 1、GBK是在国家标准GB2312基础上扩容后兼容GB2312的标准。GBK编码专门用来解决中文编码的,是双字节的。不论中英文都是双字节的。 + 2、UTF8编码是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24位(三个字节)来编码。 + 对于英文字符较多的论坛则用UTF-8节省空间。另外,如果是外国人访问你的GBK网页,需要下载中文语言包支持。 + 访问UTF-8编码的网页则不出现这问题。可以直接访问。 + 3、GBK包含全部中文字符;UTF8则包含全世界所有国家需要用到的字符。 + */ + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/model/DtModel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/model/DtModel.java new file mode 100644 index 0000000..5083347 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/model/DtModel.java @@ -0,0 +1,61 @@ +package com.yunzhupaas.database.datatype.model; + + +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.limit.base.DtModelBase; +import com.yunzhupaas.util.StringUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 数据类型模型 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/25 + */ +@Data +public class DtModel extends DtModelBase { + + /** + * 显示长度 + */ + private String formatLengthStr; + + + public DtModel(DtInterface dtEnum){ + this.dtEnum = dtEnum; + } + + /** + * 表字段数据类型名 + */ + public String getDataType(){ + return this.dtEnum.getDataType(); + } + + /** + * java数据类型 + */ + public String getJavaType(){ + return this.dtEnum.getJavaType(); + } + + /** + * 当精度(>=1)小于标度 + * 重置标度,让其小于精度(精度-1) + */ + public void formatNumLength(Integer numPrecision, Integer numScale){ + if(numScale != null && numPrecision < numScale){ + this.numScale = numPrecision - 1; + } + } + + public String formatDataType(){ + String lengthInfo = getFormatLengthStr(); + return getDataType() + (StringUtil.isNotEmpty(lengthInfo) ? "(" + lengthInfo + ")" : ""); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/model/DtModelDTO.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/model/DtModelDTO.java new file mode 100644 index 0000000..3d10626 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/model/DtModelDTO.java @@ -0,0 +1,125 @@ +package com.yunzhupaas.database.datatype.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.limit.base.DtModelBase; +import com.yunzhupaas.database.datatype.utils.DataTypeUtil; +import com.yunzhupaas.database.datatype.viewshow.ViewDataTypeEnum; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.StringUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * 前端数据类型模型 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/25 + */ +@Data +@Accessors(chain = true) +@NoArgsConstructor +public class DtModelDTO extends DtModelBase { + + /** + * 转换目标类型 + */ + @JsonIgnore + private DtInterface convertTargetDtEnum; + + /** + * 数据库取到的值(不用转换直接使用) + */ + public final static String DB_VAL = "DB_VAL"; + /** + * 使用固定值 + */ + public final static String FIX_VAL = "FIX_VAL"; + /** + * 主要转换:前端传来的参数 + */ + public final static String VIEW_VAL = "VIEW_VAL"; + /** + * 转换类型 + */ + private String convertType = VIEW_VAL; + + /** + * 初始化创建表使用 + * + * 析长度信息,例如 decimal(18,3) 中的 18,3 + * @param dataType 数据类型 + * @param dtLength 数据精度、标度信息 + * @param dbEncode 数据库类型 + */ + public DtModelDTO(String dataType, String dtLength, String dbEncode, boolean viewFlag) throws Exception { + // 设置长度 + if (StringUtil.isEmpty(dtLength)) dtLength = "-1"; + if (dtLength.contains(",")) { + String[] split = dtLength.split(","); + if (DataTypeUtil.numFlag(split[0], split[1])) { + charLength = Long.parseLong(split[0]); + bitLength = Long.parseLong(split[0]); + numPrecision = Integer.parseInt(split[0]); + numScale = Integer.parseInt(split[1]); + } + } else { + if (DataTypeUtil.numFlag(dtLength)) { + charLength = Long.parseLong(dtLength); + bitLength = Long.parseLong(dtLength); + numPrecision = Integer.parseInt(dtLength); + } + } + // 1、根据前端信息判断内置数据标准类型枚举 + if(viewFlag) dtEnum = DtInterface.newInstanceByView(dataType, dbEncode); + // 2、直接使用前端数据类型作为数据库类型查询 + if (dtEnum == null) dtEnum = DtInterface.newInstanceByDt(dataType, dbEncode); + if (dtEnum == null) new DataException(MsgCode.DB013.get(dbEncode, dataType)).printStackTrace(); + convertTargetDtEnum = dtEnum; + } + + /** + * 初始化显示表使用 + * + * @param charLength 字符串长度 + * @param numPrecision 精度 + * @param numScale 标度 + */ + public DtModelDTO(DtInterface dtEnum, Long charLength, Integer numPrecision, Integer numScale) { + this.dtEnum = dtEnum; + this.numPrecision = numPrecision; + this.numScale = numScale; + if (dtEnum.getCharLengthLm() != null) { + this.charLength = charLength; + } else if(dtEnum.getBitLengthLm() != null){ + this.bitLength = charLength; + } + } + + /** + * 默认建表字符串数据类型(当数据类型失败时候,使用这个减低错误率) + * + * @param dbEncode 数据类型编码 + * @return 字符串数据类型Sql片段 + */ + public static String getStringFixedDt(String dbEncode) throws Exception { + DtInterface dtEnum = DtInterface.newInstanceByView(ViewDataTypeEnum.VARCHAR.getViewFieldType(), dbEncode); + if (dtEnum != null) { + DtModelDTO dto = new DtModelDTO(dtEnum, -1L, -1, -1); + dto.setConvertType(FIX_VAL); + return dto.convert().formatDataType(); + } + return "varchar(50)"; + } + + public DtModel convert() { + return dtEnum.getDtLimit().convert(this); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/enums/DtConvertEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/enums/DtConvertEnum.java new file mode 100644 index 0000000..25b1dfd --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/enums/DtConvertEnum.java @@ -0,0 +1,771 @@ +package com.yunzhupaas.database.datatype.sync.enums; + +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.database.datatype.db.*; +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.sync.model.DtConvertModel; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.exception.DataException; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 数据库相对应一些方法 + * 固定转换关系 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-05-31 + */ +@Getter +@AllArgsConstructor +public enum DtConvertEnum { + + /** + * 根据数据选择的方法枚举 + */ + MYSQL(DbBase.MYSQL){ + /** + * DtMutualConvertEnum(默认原始搭配),在这个地方重复的枚举会重写覆盖原来的搭配 + */ + @Override + public DtConvertModel getModel(T dtEnum){ + DtConvertModel model = new DtConvertModel<>(); + switch ((DtMySQLEnum)dtEnum){ + /* =============================== 整数类型 =============================== */ + case TINY_INT: convert(model, + DtOracleEnum.NUMBER, + DtSQLServerEnum.TINY_INT, + DtDMEnum.TINY_INT, + DtKingbaseESEnum.TINY_INT, + DtPostgreSQLEnum.INT2, + DtDorisEnum.TINY_INT + ); break; + case SMALL_INT: convert(model, + DtOracleEnum.NUMBER, + DtSQLServerEnum.SMALL_INT, + DtDMEnum.SMALL_INT, + DtKingbaseESEnum.SMALL_INT, + DtPostgreSQLEnum.INT2, + DtDorisEnum.SMALL_INT + ); break; + case MEDIUM_INT: + case INT: convert(model, + DtOracleEnum.NUMBER, + DtSQLServerEnum.INT, + DtDMEnum.INT, + DtKingbaseESEnum.INTEGER, + DtPostgreSQLEnum.INT4, + DtDorisEnum.INT + ); break; + case BIGINT: convert(model, + DtOracleEnum.NUMBER, + DtSQLServerEnum.BIGINT, + DtDMEnum.BIGINT, + DtKingbaseESEnum.BIGINT, + DtPostgreSQLEnum.INT8, + DtDorisEnum.BIGINT + ); break; + // ====================== 文本字符串类型: ==========================;==== */ + // mysql(varchar) 转成 oracle(NVARCHAR2)、sqlserver(nvarchar; + case CHAR: convert(model, + DtOracleEnum.CHAR, + DtSQLServerEnum.CHAR, + DtDMEnum.CHAR, + DtKingbaseESEnum.CHAR, + DtPostgreSQLEnum.CHAR, + DtDorisEnum.CHAR + ); break; + // mysql(test) 转成 oracle(NCLOB)、sqlserver(nvarchar(max); break; + case BLOB: convert(model, + DtOracleEnum.BLOB, + DtSQLServerEnum.VARBINARY, + DtDMEnum.BLOB, + DtKingbaseESEnum.TEXT, + DtPostgreSQLEnum.BYTEA, + DtDorisEnum.STRING + ); break; + case BIT: + case VARCHAR: convert(model, + DtOracleEnum.NVARCHAR2, + DtSQLServerEnum.NVARCHAR, + DtDMEnum.VARCHAR, + DtKingbaseESEnum.VARCHAR, + DtPostgreSQLEnum.VARCHAR, + DtDorisEnum.VARCHAR + ); break; + case TINY_TEXT: + case TEXT: + case MEDIUM_TEXT: + case LONG_TEXT: convert(model, + DtOracleEnum.CLOB, + DtSQLServerEnum.VARCHAR_MAX, + DtDMEnum.CLOB, + DtKingbaseESEnum.TEXT, + DtPostgreSQLEnum.TEXT); + break; + case LONG_BLOB: convert(model, + DtOracleEnum.BLOB, + DtSQLServerEnum.VARBINARY, + DtDMEnum.BLOB, + DtKingbaseESEnum.BYTEA, + DtPostgreSQLEnum.BYTEA + ); break; + // ====================== 浮点类型: =============================;= */ + case FLOAT: convert(model, + DtDMEnum.FLOAT, + DtOracleEnum.FLOAT, + DtSQLServerEnum.FLOAT, + DtKingbaseESEnum.FLOAT4, + DtPostgreSQLEnum.FLOAT4, + DtDorisEnum.FLOAT + ); break; + case DOUBLE: convert(model, + DtOracleEnum.FLOAT, + DtSQLServerEnum.FLOAT, + DtDMEnum.DOUBLE, + DtKingbaseESEnum.FLOAT8, + DtPostgreSQLEnum.FLOAT8, + DtDorisEnum.DOUBLE + ); break; + // ====================== 定点数类型: ============================;== */ + case DECIMAL: convert(model, + DtOracleEnum.NUMBER, + DtSQLServerEnum.DECIMAL, + DtDMEnum.DECIMAL, + DtKingbaseESEnum.NUMERIC, + DtPostgreSQLEnum.NUMERIC, + DtDorisEnum.DECIMAL + ); break; + // ====================== 日期时间类型: ===========================;=== */ + case YEAR: + case DATE: convert(model, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.DATE_TIME, + DtDMEnum.DATE_TIME, + DtKingbaseESEnum.DATE, + DtPostgreSQLEnum.TIMESTAMP, + DtDorisEnum.DATE + ); break; + case TIME: convert(model, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.TIME, + DtDMEnum.TIME, + DtKingbaseESEnum.TIME, + DtPostgreSQLEnum.TIME, + DtDorisEnum.DATE_TIME + ); break; + case DATE_TIME:convert(model, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.DATE_TIME, + DtDMEnum.TIME_STAMP, + DtKingbaseESEnum.TIMESTAMP, + DtPostgreSQLEnum.TIMESTAMP, + DtDorisEnum.DATE_TIME + ); break; + case TIMESTAMP: convert(model, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.TIMESTAMP, + DtDMEnum.TIME_STAMP, + DtKingbaseESEnum.TIMESTAMP, + DtPostgreSQLEnum.TIMESTAMP, + DtDorisEnum.DATE_TIME + ); break; + default: + } + model.setDtMySQLEnum((DtMySQLEnum) dtEnum); + return model; + } + }, + ORACLE(DbBase.ORACLE){ + @Override + public DtConvertModel getModel(T dtEnum){ + DtConvertModel model = new DtConvertModel<>(); + switch ((DtOracleEnum)dtEnum){ + /* =============================== 整数类型 =============================== */ + case NUMBER: convert(model, + DtMySQLEnum.BIGINT, + DtSQLServerEnum.BIGINT, + DtDMEnum.BIGINT, + DtKingbaseESEnum.BIGINT, + DtPostgreSQLEnum.INT8 + ); break; + // ===================== 文本字符串类型 ===========================;= */ + case CHAR: + case NCHAR: convert(model, + DtMySQLEnum.CHAR, + DtSQLServerEnum.CHAR, + DtDMEnum.CHAR, + DtKingbaseESEnum.CHAR, + DtPostgreSQLEnum.CHAR + ); break; + case VARCHAR2: convert(model, + DtMySQLEnum.VARCHAR, + DtSQLServerEnum.NVARCHAR, + DtDMEnum.VARCHAR, + DtKingbaseESEnum.VARCHAR, + DtPostgreSQLEnum.VARCHAR + ); break; + case NVARCHAR2: convert(model, + DtMySQLEnum.VARCHAR, + DtSQLServerEnum.NVARCHAR, + DtDMEnum.VARCHAR2, + DtKingbaseESEnum.VARCHAR, + DtPostgreSQLEnum.VARCHAR + ); break; + case CLOB: convert(model, + DtMySQLEnum.TEXT, + DtSQLServerEnum.TEXT, + DtDMEnum.TEXT, + DtKingbaseESEnum.TEXT, + DtPostgreSQLEnum.TEXT + ); break; + case NCLOB: convert(model, + DtMySQLEnum.LONG_TEXT, + DtSQLServerEnum.N_TEXT, + DtDMEnum.CLOB, + DtKingbaseESEnum.TEXT, + DtPostgreSQLEnum.TEXT + ); break; + // ===================== 浮点类型 =============================;*/ + case FLOAT: convert(model, + DtMySQLEnum.FLOAT, + DtDMEnum.FLOAT, + DtSQLServerEnum.FLOAT, + DtKingbaseESEnum.FLOAT4, + DtPostgreSQLEnum.FLOAT4 + ); break; + // ===================== 日期时间类型: ==========================;== */ + case DATE: convert(model, + DtMySQLEnum.DATE, + DtSQLServerEnum.DATE, + DtDMEnum.DATE, + DtKingbaseESEnum.DATE, + DtPostgreSQLEnum.DATE + ); break; + case TIMESTAMP: convert(model, + DtMySQLEnum.TIMESTAMP, + DtSQLServerEnum.TIMESTAMP, + DtDMEnum.TIME_STAMP, + DtKingbaseESEnum.TIMESTAMP, + DtPostgreSQLEnum.TIMESTAMP + ); break; + default: + } + model.setDtOracleEnum((DtOracleEnum) dtEnum); + return model; + } + }, + SQL_SERVER(DbBase.SQL_SERVER){ + @Override + public DtConvertModel getModel(T dtEnum){ + DtConvertModel model = new DtConvertModel<>(); + switch ((DtSQLServerEnum)dtEnum){ + /* =============================== 整数类型 =============================== */ + case TINY_INT: convert(model, + DtMySQLEnum.TINY_INT, + DtOracleEnum.NUMBER, + DtDMEnum.TINY_INT, + DtKingbaseESEnum.TINY_INT, + DtPostgreSQLEnum.INT2 + ); break; + case SMALL_INT: convert(model, + DtMySQLEnum.SMALL_INT, + DtOracleEnum.NUMBER, + DtDMEnum.SMALL_INT, + DtKingbaseESEnum.SMALL_INT, + DtPostgreSQLEnum.INT2 + ); break; + case INT: convert(model, + DtMySQLEnum.INT, + DtOracleEnum.NUMBER, + DtDMEnum.INT, + DtKingbaseESEnum.INTEGER, + DtPostgreSQLEnum.INT4 + ); break; + case BIGINT: convert(model, + DtMySQLEnum.BIGINT, + DtOracleEnum.NUMBER, + DtDMEnum.BIGINT, + DtKingbaseESEnum.BIGINT, + DtPostgreSQLEnum.INT8 + ); break; + // ================== 文本字符串类型 =============================== *; + case CHAR: convert(model, + DtMySQLEnum.CHAR, + DtOracleEnum.CHAR, + DtDMEnum.CHAR, + DtKingbaseESEnum.CHAR, + DtPostgreSQLEnum.CHAR + ); break; + case NVARCHAR: convert(model, + DtMySQLEnum.VARCHAR, + DtOracleEnum.NVARCHAR2, + DtDMEnum.VARCHAR2, + DtKingbaseESEnum.VARCHAR, + DtPostgreSQLEnum.VARCHAR + ); break; + case VARCHAR: convert(model, + DtMySQLEnum.VARCHAR, + DtOracleEnum.NVARCHAR2, + DtDMEnum.VARCHAR, + DtKingbaseESEnum.VARCHAR, + DtPostgreSQLEnum.VARCHAR + ); break; + case VARCHAR_MAX: + case IMAGE: + case TEXT: convert(model, + DtMySQLEnum.TEXT, + DtOracleEnum.CLOB, + DtDMEnum.CLOB, + DtKingbaseESEnum.TEXT, + DtPostgreSQLEnum.TEXT + ); break; + case N_TEXT: convert(model, + DtMySQLEnum.LONG_TEXT, + DtOracleEnum.NCLOB, + DtDMEnum.CLOB, + DtKingbaseESEnum.TEXT, + DtPostgreSQLEnum.TEXT + ); break; + // ================== 日期时间类型: =============================== *; + case DATE: convert(model, + DtMySQLEnum.DATE, + DtOracleEnum.DATE, + DtDMEnum.DATE, + DtKingbaseESEnum.DATE, + DtPostgreSQLEnum.DATE + ); break; + case TIME: convert(model, + DtMySQLEnum.TIME, + DtOracleEnum.TIMESTAMP, + DtDMEnum.TIME, + DtKingbaseESEnum.TIME, + DtPostgreSQLEnum.TIME + ); break; + case DATE_TIME: convert(model, + DtMySQLEnum.DATE_TIME, + DtOracleEnum.TIMESTAMP, + DtDMEnum.DATE_TIME, + DtKingbaseESEnum.DATE_TIME, + DtPostgreSQLEnum.TIMESTAMP + ); break; + case TIMESTAMP: convert(model, + DtMySQLEnum.TIMESTAMP, + DtOracleEnum.TIMESTAMP, + DtDMEnum.TIME_STAMP, + DtKingbaseESEnum.TIMESTAMP, + DtPostgreSQLEnum.TIMESTAMP + ); break; + // ===================== 浮点类型 =============================;*/ + case FLOAT: convert(model, + DtMySQLEnum.FLOAT, + DtDMEnum.FLOAT, + DtOracleEnum.FLOAT, + DtKingbaseESEnum.FLOAT4, + DtPostgreSQLEnum.FLOAT4 + ); break; + // ================== 定点数类型: =============================== *; + case DECIMAL: convert(model, + DtMySQLEnum.DECIMAL, + DtOracleEnum.NUMBER, + DtDMEnum.DECIMAL, + DtKingbaseESEnum.NUMERIC, + DtPostgreSQLEnum.NUMERIC + ); break; + default: + } + model.setDtSQLServerEnum((DtSQLServerEnum) dtEnum); + return model; + } + }, + DM(DbBase.DM){ + @Override + public DtConvertModel getModel(T dtEnum){ + DtConvertModel model = new DtConvertModel<>(); + switch ((DtDMEnum)dtEnum){ + /* =============================== 整数类型 =============================== */ + case TINY_INT: convert(model, + DtMySQLEnum.TINY_INT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.TINY_INT, + DtKingbaseESEnum.TINY_INT, + DtPostgreSQLEnum.INT2 + ); break; + case SMALL_INT: convert(model, + DtMySQLEnum.SMALL_INT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.SMALL_INT, + DtKingbaseESEnum.SMALL_INT, + DtPostgreSQLEnum.INT2 + ); break; + case INT: convert(model, + DtMySQLEnum.INT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.INT, + DtKingbaseESEnum.INTEGER, + DtPostgreSQLEnum.INT4 + ); break; + case BIGINT: convert(model, + DtMySQLEnum.BIGINT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.BIGINT, + DtKingbaseESEnum.BIGINT, + DtPostgreSQLEnum.INT8 + ); break; + // ===================== 文本字符串类型 ===========================*; + case CHAR: convert(model, + DtMySQLEnum.CHAR, + DtOracleEnum.CHAR, + DtSQLServerEnum.CHAR, + DtKingbaseESEnum.CHAR, + DtPostgreSQLEnum.CHAR + ); break; + case VARCHAR: + case VARCHAR2: convert(model, + DtMySQLEnum.VARCHAR, + DtOracleEnum.NVARCHAR2, + DtSQLServerEnum.NVARCHAR, + DtKingbaseESEnum.VARCHAR, + DtPostgreSQLEnum.VARCHAR + ); break; + case TEXT: + case CLOB: convert(model, + DtMySQLEnum.TEXT, + DtOracleEnum.CLOB, + DtSQLServerEnum.TEXT, + DtKingbaseESEnum.TEXT, + DtPostgreSQLEnum.TEXT + ); break; + // ===================== 时间格式 ===========================*; + case DATE: convert(model, + DtMySQLEnum.DATE, + DtSQLServerEnum.DATE, + DtOracleEnum.DATE, + DtKingbaseESEnum.DATE, + DtPostgreSQLEnum.DATE + ); break; + case DATE_TIME: convert(model, + DtMySQLEnum.DATE_TIME, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.DATE_TIME, + DtKingbaseESEnum.DATE_TIME, + DtPostgreSQLEnum.TIMESTAMP + ); break; + case TIME_STAMP: convert(model, + DtMySQLEnum.TIMESTAMP, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.TIMESTAMP, + DtKingbaseESEnum.TIMESTAMP, + DtPostgreSQLEnum.TIMESTAMP + ); break; + case TIME: convert(model, + DtMySQLEnum.TIME, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.TIME, + DtKingbaseESEnum.TIME, + DtPostgreSQLEnum.TIME + ); break; + // =====================浮点===========================*; + case FLOAT: convert(model, + DtMySQLEnum.FLOAT, + DtOracleEnum.FLOAT, + DtSQLServerEnum.FLOAT, + DtKingbaseESEnum.FLOAT4, + DtPostgreSQLEnum.FLOAT4 + ); break; + case DOUBLE: convert(model, + DtMySQLEnum.DOUBLE, + DtOracleEnum.FLOAT, + DtSQLServerEnum.FLOAT, + DtKingbaseESEnum.FLOAT8, + DtPostgreSQLEnum.FLOAT8 + ); break; + // ===================== 定点型 ===========================* + case DECIMAL: + case DEC: convert(model, + DtMySQLEnum.DECIMAL, + DtOracleEnum.NUMBER, + DtSQLServerEnum.DECIMAL, + DtKingbaseESEnum.NUMERIC, + DtPostgreSQLEnum.NUMERIC + ); break; + default: + } + model.setDtDMEnum((DtDMEnum) dtEnum); + return model; + } + }, + KINGBASE(DbBase.KINGBASE_ES){ + @Override + public DtConvertModel getModel(T dtEnum){ + DtConvertModel model = new DtConvertModel<>(); + switch ((DtKingbaseESEnum)dtEnum){ + /* =============================== 整数类型 =============================== */ + case TINY_INT: convert(model, + DtMySQLEnum.TINY_INT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.TINY_INT, + DtDMEnum.TINY_INT, + DtPostgreSQLEnum.INT2 + ); break; + case SMALL_INT: convert(model, + DtMySQLEnum.SMALL_INT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.SMALL_INT, + DtDMEnum.SMALL_INT, + DtPostgreSQLEnum.INT2 + ); break; + case INTEGER: convert(model, + DtMySQLEnum.INT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.INT, + DtDMEnum.INT, + DtPostgreSQLEnum.INT4 + ); break; + case BIGINT: convert(model, + DtMySQLEnum.BIGINT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.BIGINT, + DtDMEnum.BIGINT, + DtPostgreSQLEnum.INT8 + ); break; + // ============= 文本字符串类型 ===========================*; + case CHAR: convert(model, + DtMySQLEnum.CHAR, + DtOracleEnum.CHAR, + DtSQLServerEnum.CHAR, + DtDMEnum.CHAR, + DtPostgreSQLEnum.CHAR + ); break; + case VARCHAR: convert(model, + DtMySQLEnum.VARCHAR, + DtOracleEnum.NVARCHAR2, + DtSQLServerEnum.NVARCHAR, + DtDMEnum.VARCHAR, + DtPostgreSQLEnum.VARCHAR + ); break; + case TEXT: convert(model, + DtMySQLEnum.TEXT, + DtOracleEnum.CLOB, + DtSQLServerEnum.TEXT, + DtDMEnum.TEXT, + DtPostgreSQLEnum.TEXT + ); break; + // =============浮点===========================*; + case FLOAT4: convert(model, + DtMySQLEnum.FLOAT, + DtDMEnum.FLOAT, + DtOracleEnum.FLOAT, + DtSQLServerEnum.FLOAT, + DtPostgreSQLEnum.FLOAT4 + ); break; + case FLOAT8: convert(model, + DtMySQLEnum.DOUBLE, + DtOracleEnum.FLOAT, + DtSQLServerEnum.FLOAT, + DtDMEnum.DOUBLE, + DtPostgreSQLEnum.FLOAT8 + ); break; + // =================== 定点型 ========================================*; + case NUMERIC: convert(model, + DtMySQLEnum.DECIMAL, + DtOracleEnum.NUMBER, + DtSQLServerEnum.DECIMAL, + DtDMEnum.DECIMAL, + DtPostgreSQLEnum.NUMERIC + ); break; + // ============= 时间格式 ===========================*; + case TIME: convert(model, + DtMySQLEnum.TIME, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.TIME, + DtDMEnum.TIME, + DtPostgreSQLEnum.TIME + ); break; + case DATE: convert(model, + DtMySQLEnum.DATE, + DtSQLServerEnum.DATE, + DtOracleEnum.DATE, + DtDMEnum.DATE, + DtPostgreSQLEnum.DATE + ); break; + case DATE_TIME: convert(model, + DtMySQLEnum.DATE_TIME, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.DATE_TIME, + DtDMEnum.DATE_TIME, + DtPostgreSQLEnum.TIMESTAMP + ); break; + case TIMESTAMP: convert(model, + DtMySQLEnum.TIMESTAMP, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.TIMESTAMP, + DtDMEnum.TIME_STAMP, + DtPostgreSQLEnum.TIMESTAMP + ); break; + default: + } + model.setDtKingbaseESEnum((DtKingbaseESEnum) dtEnum); + return model; + } + }, + POSTGRE(DbBase.POSTGRE_SQL){ + @Override + public DtConvertModel getModel(T dtEnum){ + DtConvertModel model = new DtConvertModel<>(); + switch ((DtPostgreSQLEnum)dtEnum){ + /* =============================== 整数类型 =============================== */ + case INT2: convert(model, + DtMySQLEnum.SMALL_INT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.SMALL_INT, + DtDMEnum.SMALL_INT, + DtKingbaseESEnum.SMALL_INT + ); break; + case INT4: convert(model, + DtMySQLEnum.INT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.INT, + DtDMEnum.INT, + DtKingbaseESEnum.INTEGER + ); break; + case INT8: convert(model, + DtMySQLEnum.BIGINT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.BIGINT, + DtDMEnum.BIGINT, + DtKingbaseESEnum.BIGINT + ); break; + // =================== 文本字符串类型 =======================================*/ + case CHAR: convert(model, + DtMySQLEnum.CHAR, + DtOracleEnum.CHAR, + DtSQLServerEnum.CHAR, + DtDMEnum.CHAR, + DtKingbaseESEnum.CHAR + ); break; + case VARCHAR: convert(model, + DtMySQLEnum.VARCHAR, + DtOracleEnum.NVARCHAR2, + DtSQLServerEnum.NVARCHAR, + DtDMEnum.VARCHAR, + DtKingbaseESEnum.VARCHAR + ); break; + case TEXT: convert(model, + DtMySQLEnum.TEXT, + DtOracleEnum.CLOB, + DtSQLServerEnum.TEXT, + DtDMEnum.TEXT, + DtKingbaseESEnum.TEXT + ); break; + // ====================浮点===========================*/ + case FLOAT4: convert(model, + DtMySQLEnum.FLOAT, + DtDMEnum.FLOAT, + DtOracleEnum.FLOAT, + DtSQLServerEnum.FLOAT, + DtKingbaseESEnum.FLOAT4 + ); break; + case FLOAT8: convert(model, + DtMySQLEnum.DOUBLE, + DtOracleEnum.FLOAT, + DtSQLServerEnum.FLOAT, + DtDMEnum.DOUBLE, + DtKingbaseESEnum.FLOAT8 + ); break; + // =================== 定点型 =======================================*/ + case NUMERIC: convert(model, + DtMySQLEnum.DECIMAL, + DtOracleEnum.NUMBER, + DtSQLServerEnum.DECIMAL, + DtDMEnum.DECIMAL, + DtKingbaseESEnum.NUMERIC + ); break; + // =================== 时间日期 =======================================*/ + case TIME: convert(model, + DtMySQLEnum.TIME, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.TIME, + DtDMEnum.TIME, + DtKingbaseESEnum.TIME + ); break; + case DATE: convert(model, + DtMySQLEnum.DATE, + DtSQLServerEnum.DATE, + DtOracleEnum.DATE, + DtDMEnum.DATE, + DtKingbaseESEnum.DATE + ); break; + case TIMESTAMP: convert(model, + DtMySQLEnum.TIMESTAMP, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.TIMESTAMP, + DtDMEnum.TIME_STAMP, + DtKingbaseESEnum.TIMESTAMP + ); break; + default: + } + model.setDtPostgreSQLEnum((DtPostgreSQLEnum)dtEnum); + return model; + } + }, + + ; + + private final String dbType; + + /** + * 获取转换模型 + * @param fromDtEnum 数据类型枚举 + * @return 转换模型 + * @throws DataException ignore + */ + public static DtConvertModel getConvertModel(T fromDtEnum) throws DataException { + return choose(fromDtEnum.getDbType()).getModel(fromDtEnum); + } + + /* ================================ 内部方法 ================================== */ + + /** + * 根据数据类型枚举获取对应转换模型 + * @param dtEnum 数据类型枚举 + * @return ignore + */ + protected DtConvertModel getModel(T dtEnum){return null;} + + /** + * 根据数据获取其转换规则枚举 + * @param dbType 数据库类型 + * @return 转换规则枚举 + * @throws DataException ignore + */ + private static DtConvertEnum choose(String dbType) throws DataException { + for (DtConvertEnum dbMethod : DtConvertEnum.values()) { + if(dbMethod.getDbType().equals(dbType)){ + return dbMethod; + } + } + throw new DataException(MsgCode.DB005.get()); + } + + /** + * 内部特殊转换 + * @param model 转换模型 + * @param convertDtEnums 特殊转换集合 + */ + protected void convert(DtConvertModel model, DtInterface... convertDtEnums){ + try{ + // 特殊的转换关系 + for (DtInterface convertDtEnum : convertDtEnums) { + model.setDtEnum(convertDtEnum); + } + }catch (Exception e){ + e.printStackTrace(); + } + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/enums/DtConvertMultiEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/enums/DtConvertMultiEnum.java new file mode 100644 index 0000000..c69fdb8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/enums/DtConvertMultiEnum.java @@ -0,0 +1,112 @@ +package com.yunzhupaas.database.datatype.sync.enums; + +import com.yunzhupaas.database.datatype.db.*; +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 多个转换对应关系 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-05-31 + */ +@Getter +@AllArgsConstructor +public enum DtConvertMultiEnum { + + /** + * 整数型 + */ + INTEGER( + new DtMySQLEnum[] { DtMySQLEnum.TINY_INT, DtMySQLEnum.SMALL_INT, DtMySQLEnum.INT, DtMySQLEnum.BIGINT, DtMySQLEnum.MEDIUM_INT }, + new DtOracleEnum[] { DtOracleEnum.NUMBER }, + new DtSQLServerEnum[] { DtSQLServerEnum.TINY_INT, DtSQLServerEnum.SMALL_INT, DtSQLServerEnum.INT, DtSQLServerEnum.BIGINT }, + new DtDMEnum[] { DtDMEnum.TINY_INT, DtDMEnum.SMALL_INT, DtDMEnum.INT, DtDMEnum.BIGINT }, + new DtKingbaseESEnum[] { DtKingbaseESEnum.TINY_INT, DtKingbaseESEnum.SMALL_INT, DtKingbaseESEnum.INTEGER, DtKingbaseESEnum.BIGINT }, + new DtPostgreSQLEnum[] { DtPostgreSQLEnum.INT2, DtPostgreSQLEnum.INT4, DtPostgreSQLEnum.INT8 }, + new DtDorisEnum[] { DtDorisEnum.TINY_INT, DtDorisEnum.SMALL_INT, DtDorisEnum.INT, DtDorisEnum.BIGINT } + ), + /** + * 字符串、文本 + */ + STRING( + new DtMySQLEnum[] { DtMySQLEnum.CHAR, DtMySQLEnum.VARCHAR, DtMySQLEnum.TINY_TEXT, DtMySQLEnum.TEXT, DtMySQLEnum.MEDIUM_TEXT, DtMySQLEnum.LONG_TEXT }, + new DtOracleEnum[] { DtOracleEnum.CHAR, DtOracleEnum.NCHAR, DtOracleEnum.VARCHAR2, DtOracleEnum.NVARCHAR2 , DtOracleEnum.CLOB, DtOracleEnum.NCLOB }, + new DtSQLServerEnum[] { DtSQLServerEnum.CHAR, DtSQLServerEnum.VARCHAR, DtSQLServerEnum.NVARCHAR, DtSQLServerEnum.VARCHAR_MAX, DtSQLServerEnum.TEXT, DtSQLServerEnum.N_TEXT, DtSQLServerEnum.IMAGE }, + new DtDMEnum[] { DtDMEnum.CHAR, DtDMEnum.VARCHAR, DtDMEnum.VARCHAR2, DtDMEnum.TEXT , DtDMEnum.CLOB }, + new DtKingbaseESEnum[] { DtKingbaseESEnum.CHAR, DtKingbaseESEnum.VARCHAR, DtKingbaseESEnum.TEXT }, + new DtPostgreSQLEnum[] { DtPostgreSQLEnum.CHAR, DtPostgreSQLEnum.VARCHAR, DtPostgreSQLEnum.TEXT }, + new DtDorisEnum[] { DtDorisEnum.CHAR, DtDorisEnum.VARCHAR, } + ), + /** + * 浮点型 + */ + FLOAT( + new DtMySQLEnum[] { DtMySQLEnum.FLOAT, DtMySQLEnum.DOUBLE }, + new DtOracleEnum[] { DtOracleEnum.FLOAT }, + new DtSQLServerEnum[] { DtSQLServerEnum.FLOAT }, + new DtDMEnum[] { DtDMEnum.FLOAT, DtDMEnum.DOUBLE }, + new DtKingbaseESEnum[] { DtKingbaseESEnum.FLOAT4, DtKingbaseESEnum.FLOAT8 }, + new DtPostgreSQLEnum[] { DtPostgreSQLEnum.FLOAT4, DtPostgreSQLEnum.FLOAT8 }, + new DtDorisEnum[] { DtDorisEnum.FLOAT, DtDorisEnum.DOUBLE } + ), + /** + * 定点型 + */ + DECIMAL( + new DtMySQLEnum[] { DtMySQLEnum.DECIMAL }, + new DtOracleEnum[] { DtOracleEnum.NUMBER }, + new DtSQLServerEnum[] { DtSQLServerEnum.DECIMAL }, + new DtDMEnum[] { DtDMEnum.DECIMAL, DtDMEnum.DEC }, + new DtKingbaseESEnum[] { DtKingbaseESEnum.NUMERIC }, + new DtPostgreSQLEnum[] { DtPostgreSQLEnum.NUMERIC }, + new DtDorisEnum[] { DtDorisEnum.DECIMAL } + ), + /** + * 时间日期型 + */ + DATE_TIME( + new DtMySQLEnum[] { DtMySQLEnum.YEAR, DtMySQLEnum.TIME, DtMySQLEnum.DATE, DtMySQLEnum.DATE_TIME, DtMySQLEnum.TIMESTAMP }, + new DtOracleEnum[] { DtOracleEnum.DATE, DtOracleEnum.TIMESTAMP }, + new DtSQLServerEnum[] { DtSQLServerEnum.DATE, DtSQLServerEnum.TIME, DtSQLServerEnum.DATE_TIME, DtSQLServerEnum.TIMESTAMP }, + new DtDMEnum[] { DtDMEnum.DATE, DtDMEnum.DATE_TIME, DtDMEnum.TIME_STAMP, DtDMEnum.TIME }, + new DtKingbaseESEnum[] { DtKingbaseESEnum.TIME, DtKingbaseESEnum.DATE, DtKingbaseESEnum.DATE_TIME, DtKingbaseESEnum.TIMESTAMP }, + new DtPostgreSQLEnum[] { DtPostgreSQLEnum.TIME, DtPostgreSQLEnum.DATE, DtPostgreSQLEnum.TIMESTAMP }, + new DtDorisEnum[] { DtDorisEnum.DATE, DtDorisEnum.DATE_TIME } + ), + ; + + private final DtMySQLEnum[] dtMySQLEnums; + private final DtOracleEnum[] dtOracleEnums; + private final DtSQLServerEnum[] dtSQLServerEnums; + private final DtDMEnum[] dtDMEnums; + private final DtKingbaseESEnum[] dtKingbaseESEnums; + private final DtPostgreSQLEnum[] dtPostgreSQLEnums; + private final DtDorisEnum[] dtDorisEnums; + + public static DtInterface[] getConverts(String dbType, DtConvertMultiEnum cEnum) throws Exception { + Method method = DtConvertMultiEnum.class.getMethod("getDt" + dbType + "Enums"); + return (DtInterface[])method.invoke(cEnum); + } + + public List getAllConverts(){ + List list = new ArrayList<>(); + list.addAll(Arrays.asList(this.getDtMySQLEnums())); + list.addAll(Arrays.asList(this.getDtOracleEnums())); + list.addAll(Arrays.asList(this.getDtSQLServerEnums())); + list.addAll(Arrays.asList(this.getDtDMEnums())); + list.addAll(Arrays.asList(this.getDtKingbaseESEnums())); + list.addAll(Arrays.asList(this.getDtPostgreSQLEnums())); + return list; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/model/DtConvertModel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/model/DtConvertModel.java new file mode 100644 index 0000000..a561cef --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/model/DtConvertModel.java @@ -0,0 +1,53 @@ +package com.yunzhupaas.database.datatype.sync.model; + +import com.yunzhupaas.database.datatype.db.*; +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.lang.reflect.Method; + +/** + * 数据类型互相转换模型 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-05-25 + */ +@Data +@NoArgsConstructor +public class DtConvertModel { + + private T majorEnumClz; + + /** + * 各数据库数据类型枚举 + */ + private DtMySQLEnum dtMySQLEnum; + private DtOracleEnum dtOracleEnum; + private DtSQLServerEnum dtSQLServerEnum; + private DtDMEnum dtDMEnum; + private DtKingbaseESEnum dtKingbaseESEnum; + private DtPostgreSQLEnum dtPostgreSQLEnum; + private DtDorisEnum dtDorisEnum; + + /** + * 获取数据类型枚举 + * @param convertDbEncode 转换数据库类型 + * @return ignore + * @throws Exception ignore + */ + public DtInterface getDtEnum(String convertDbEncode) throws Exception { + Method method = DtConvertModel.class.getMethod("getDt" + convertDbEncode + "Enum"); + return (DtInterface) method.invoke(this); + } + + public void setDtEnum(DtInterface dtEnum) throws Exception { + Method method = DtConvertModel.class.getMethod("setDt" + dtEnum.getDbType() + "Enum", DtInterface.getClz(dtEnum.getDbType())); + method.invoke(this, dtEnum); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/util/DtSyncTest.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/util/DtSyncTest.java new file mode 100644 index 0000000..7cc29ee --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/util/DtSyncTest.java @@ -0,0 +1,160 @@ +package com.yunzhupaas.database.datatype.sync.util; + +import com.yunzhupaas.base.ActionResult; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.database.datatype.db.*; +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.sync.enums.DtConvertMultiEnum; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.exception.DataException; + +import java.util.*; + +/** + * 测试数据类型完整性 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-01 + */ +public class DtSyncTest { + + public static void main(String[] args) throws Exception { + checkDataType(true, true, true); + } + + public static ActionResult>> getConvertRules(String fromDbType, String toDbType) throws Exception{ + Map> map = new LinkedHashMap<>(); + for (DtInterface dtInterface : DtInterface.getClz(fromDbType).getEnumConstants()) { + List list = new LinkedList<>(); + DtInterface[] allConverts = DtSyncUtil.getAllConverts(dtInterface, toDbType); + for (DtInterface allConvert : allConverts) { + list.add(allConvert.getDataType()); + } + map.put(dtInterface.getDataType(), list); + } + return ActionResult.success(map); + } + + public static ActionResult> getDefaultRules(String fromDbType, String toDbType) throws Exception{ + Map map = new LinkedHashMap<>(); + for (DtInterface dtInterface : DtInterface.getClz(fromDbType).getEnumConstants()) { + DtInterface toFixCovert = DtSyncUtil.getToFixCovert(dtInterface, toDbType); + if(toFixCovert != null){ + map.put(dtInterface.getDataType(), toFixCovert.getDataType()); + }else { + throw new DataException(MsgCode.DB006.get()); + } + } + return ActionResult.success(map); + } + + /** + * 检测各数据库 + * 数据类型对应关系是否缺失 + */ + public static void checkDataType(Boolean oneFlag, Boolean multiFlag, Boolean mutualFlag) throws Exception { + // 1、检测一对一固定转换 + if(oneFlag){ + for (String fromDbEncode : DbBase.DB_ENCODES) { + for (String toDbEncode : DbBase.DB_ENCODES) { + if(fromDbEncode.equals(toDbEncode)){ + continue; + } + System.out.println("================ " + fromDbEncode + " 转 " + toDbEncode + " =============="); + Map resultMap = getDefaultRules(fromDbEncode, toDbEncode).getData(); + for (String key : resultMap.keySet()) { + System.out.println(key + getTab(key, fromDbEncode) + ": \t" + resultMap.get(key)); + } + } + } + } + + // 2、检测一对多选择转换 + if(multiFlag){ + System.out.println("\n\n"); + for (String fromDbEncode : DbBase.DB_ENCODES) { + for (String toDbEncode : DbBase.DB_ENCODES) { + if(fromDbEncode.equals(toDbEncode)){ + continue; + } + System.out.println("================ " + fromDbEncode + " 转 " + toDbEncode + " =============="); + Map> resultMap = getConvertRules(fromDbEncode, toDbEncode).getData(); + for (String key : resultMap.keySet()) { + System.out.println(key + getTab(key, fromDbEncode) + ": \t" + resultMap.get(key).toString()); + } + } + } + } + + // 3、多对多 + if(mutualFlag){ + System.out.println("\n\n"); + for (DtConvertMultiEnum value : DtConvertMultiEnum.values()) { + System.out.println("================ " + value + " =============="); + System.out.println(DbBase.MYSQL + "\t\t:" + Arrays.asList(value.getDtMySQLEnums()).toString()); + System.out.println(DbBase.ORACLE + "\t\t:" + Arrays.asList(value.getDtOracleEnums()).toString()); + System.out.println(DbBase.SQL_SERVER + "\t:" + Arrays.asList(value.getDtDMEnums()).toString()); + System.out.println(DbBase.DM + "\t\t\t:" + Arrays.asList(value.getDtSQLServerEnums()).toString()); + System.out.println(DbBase.KINGBASE_ES + "\t:" + Arrays.asList(value.getDtKingbaseESEnums()).toString()); + System.out.println(DbBase.POSTGRE_SQL + "\t:" + Arrays.asList(value.getDtPostgreSQLEnums()).toString()); + } + } + + // 4、数据库类型 + System.out.println("\n\n"); + System.out.println("================ " + DbBase.MYSQL + " =============="); + for (DtMySQLEnum value : DtMySQLEnum.values()) { + System.out.println(value.getDataType()); + } + System.out.println("================ " + DbBase.ORACLE + " =============="); + for (DtOracleEnum value : DtOracleEnum.values()) { + System.out.println(value.getDataType()); + } + System.out.println("================ " + DbBase.SQL_SERVER + " =============="); + for (DtSQLServerEnum value : DtSQLServerEnum.values()) { + System.out.println(value.getDataType()); + } + System.out.println("================ " + DbBase.DM + " =============="); + for (DtDMEnum value : DtDMEnum.values()) { + System.out.println(value.getDataType()); + } + System.out.println("================ " + DbBase.KINGBASE_ES + " =============="); + for (DtKingbaseESEnum value : DtKingbaseESEnum.values()) { + System.out.println(value.getDataType()); + } + System.out.println("================ " + DbBase.POSTGRE_SQL + " =============="); + for (DtPostgreSQLEnum value : DtPostgreSQLEnum.values()) { + System.out.println(value.getDataType()); + } + + // 5、数据库类型固定转换 +// System.out.println("\n\n"); +// for (DtConvertFixEnum value : DtConvertFixEnum.values()) { +// System.out.println("================ " + value.name() + " =============="); +// for (DtInterface dtMutualConvert : value.getDtMutualConverts()) { +// System.out.println(dtMutualConvert.getDbType() + "\t:" + dtMutualConvert.getDataType()); +// } +// } + + } + + // 制表符 + public static String getTab(String str, String dbType){ + int num = str.length(); + String tab = "\t\t"; + if(DbBase.ORACLE.equals(dbType) || DbBase.DM.equals(dbType)){ + if(num >= 8){ + tab = "\t"; + } + }else { + if(num > 8){ + tab = "\t"; + } + } + return tab; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/util/DtSyncUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/util/DtSyncUtil.java new file mode 100644 index 0000000..dfee973 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/sync/util/DtSyncUtil.java @@ -0,0 +1,75 @@ +package com.yunzhupaas.database.datatype.sync.util; + +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.sync.enums.DtConvertEnum; +import com.yunzhupaas.database.datatype.sync.enums.DtConvertMultiEnum; +import com.yunzhupaas.exception.DataException; + +import java.util.Map; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-05-31 + */ +public class DtSyncUtil { + + /** + * 返回数据类型转换结果 + * @param fromDbType 被转化数据库类型 + * @param toDbType 转换数据数库类型 + * @param dataTypeName 转换数据类型 + * @param convertRuleMap 转换规则 + */ + public static DtInterface getToCovert(String fromDbType, String toDbType, String dataTypeName, Map convertRuleMap) throws Exception { + // 存在规则类型配对 + if(convertRuleMap != null) { + for (String key : convertRuleMap.keySet()) { + if (key.equalsIgnoreCase(dataTypeName)) { + String toDataType = convertRuleMap.get(key); + // 直接通过转换类型、数据库类型获取数据类型枚举 + return DtInterface.newInstanceByDt(toDataType, toDbType); + } + } + } + // 获取被同步数据类型枚举 + DtInterface formDtEnum = DtInterface.newInstanceByDt(dataTypeName, fromDbType); + if(formDtEnum != null){ + return getToFixCovert(formDtEnum, toDbType); + } + throw new DataException(MsgCode.DB005.get(fromDbType, dataTypeName)); + } + + /** + * 获取固定转换后数据类型枚举 + * @param fromDtEnum 被转换类型 + * @param toDbType 转换数据库类型 + * @return 数据类型枚举 + * @throws DataException ignore + */ + public static DtInterface getToFixCovert(DtInterface fromDtEnum, String toDbType) throws Exception { + return DtConvertEnum.getConvertModel(fromDtEnum).getDtEnum(toDbType); + } + + /** + * 获取所有可转换数据类型枚举集合 + * @param fromDtEnum 被转换类型 + * @param toDbType 转换数据库类型 + * @return 数据类型枚举集合 + * @throws Exception ignore + */ + public static DtInterface[] getAllConverts(DtInterface fromDtEnum, String toDbType) throws Exception { + for (DtConvertMultiEnum convertEnum : DtConvertMultiEnum.values()) { + if(convertEnum.getAllConverts().contains(fromDtEnum)){ + return DtConvertMultiEnum.getConverts(toDbType, convertEnum); + } + } + return null; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/utils/DataTypeUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/utils/DataTypeUtil.java new file mode 100644 index 0000000..822217d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/utils/DataTypeUtil.java @@ -0,0 +1,28 @@ +package com.yunzhupaas.database.datatype.utils; + +import java.util.regex.Pattern; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-07 + */ +public class DataTypeUtil { + + /** + * 数据类型判断 + */ + public static Boolean numFlag(String... nums){ + for (String num : nums) { + if(!(Pattern.compile("^[-\\+]?[\\d]*$").matcher(num).matches())){ + return false; + } + } + return true; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/viewshow/DtViewEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/viewshow/DtViewEnum.java new file mode 100644 index 0000000..bbdbb26 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/viewshow/DtViewEnum.java @@ -0,0 +1,63 @@ +package com.yunzhupaas.database.datatype.viewshow; + + +import com.yunzhupaas.database.datatype.db.DtMySQLEnum; +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; + +/** + * 数据库数据类型向前端显示 + * 转换规则 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-05-26 + */ +public enum DtViewEnum { + /** + * 整型 + */ + INT("int", new DtInterface[]{ + DtMySQLEnum.INT, + }), + /** + * 长整型 + */ + BIGINT("bigint", new DtInterface[]{ + DtMySQLEnum.BIGINT, + }), + /** + * 字符串 + */ + VARCHAR("varchar", new DtInterface[]{ + DtMySQLEnum.CHAR, + DtMySQLEnum.VARCHAR, + }), + /** + * 文本 + */ + TEXT("text", new DtInterface[]{ + DtMySQLEnum.TINY_TEXT, + DtMySQLEnum.TEXT, + DtMySQLEnum.MEDIUM_TEXT, + DtMySQLEnum.LONG_TEXT, + }), + /** + * 浮点型 + */ + DECIMAL("decimal", new DtInterface[]{ + DtMySQLEnum.DECIMAL, + }), + /** + * 日期时间 + */ + DATE_TIME("datetime", new DtInterface[]{ + DtMySQLEnum.DATE, + DtMySQLEnum.DATE_TIME, + }), + ; + + DtViewEnum(String view, DtInterface[] dtEnums){} + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/viewshow/ViewDataTypeEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/viewshow/ViewDataTypeEnum.java new file mode 100644 index 0000000..f8e53e6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/viewshow/ViewDataTypeEnum.java @@ -0,0 +1,118 @@ +package com.yunzhupaas.database.datatype.viewshow; + +import com.yunzhupaas.database.datatype.db.*; +import com.yunzhupaas.database.datatype.viewshow.constant.DtViewConst; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 字段类型枚举 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/6/29 + */ +@Getter +@AllArgsConstructor +public enum ViewDataTypeEnum { + + /* 如{主类型},{次类型}:({默认字符长度},{限制长度}(*:不允许设置))*/ + + /** + * 字符 + */ + VARCHAR( + DtViewConst.VARCHAR, + DtMySQLEnum.VARCHAR, + DtOracleEnum.VARCHAR2, + DtSQLServerEnum.VARCHAR, + DtDMEnum.VARCHAR, + DtKingbaseESEnum.VARCHAR, + DtPostgreSQLEnum.VARCHAR + ), + /** + * 日期时间 + * 日期统一不指定长度 + */ + DATE_TIME( + DtViewConst.DATE_TIME, + DtMySQLEnum.DATE_TIME, + DtOracleEnum.TIMESTAMP, + DtSQLServerEnum.DATE_TIME, + DtDMEnum.DATE_TIME, + DtKingbaseESEnum.TIMESTAMP, + DtPostgreSQLEnum.TIMESTAMP + ), + /** + * 浮点 + */ + DECIMAL( + DtViewConst.DECIMAL, + DtMySQLEnum.DECIMAL, + DtOracleEnum.NUMBER, + DtSQLServerEnum.DECIMAL, + DtDMEnum.DECIMAL, + DtKingbaseESEnum.NUMERIC, + DtPostgreSQLEnum.NUMERIC + ), + /** + * 文本 + */ + TEXT( + DtViewConst.TEXT, + DtMySQLEnum.TEXT, + DtOracleEnum.CLOB, + DtSQLServerEnum.TEXT, + DtDMEnum.TEXT, + DtKingbaseESEnum.TEXT, + DtPostgreSQLEnum.TEXT + ), + /** + * 整型 + * SqlServer、PostGre:int不能指定长度 + */ + INT( + DtViewConst.INT, + DtMySQLEnum.INT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.INT, + DtDMEnum.INT, + DtKingbaseESEnum.INTEGER, + DtPostgreSQLEnum.INT4 + ), + /** + * 长整型 + */ + BIGINT( + DtViewConst.BIGINT, + DtMySQLEnum.BIGINT, + DtOracleEnum.NUMBER, + DtSQLServerEnum.BIGINT, + DtDMEnum.BIGINT, + DtKingbaseESEnum.BIGINT, + DtPostgreSQLEnum.INT8 + ), + /** + * oracle数字类型 + */ + ORACLE_NUMBER( + DtViewConst.ORACLE_NUMBER, + null, + DtOracleEnum.NUMBER, + null, + null, + null, + null + ); + + private final String viewFieldType; + private final DtMySQLEnum dtMySQLEnum; + private final DtOracleEnum dtOracleEnum; + private final DtSQLServerEnum dtSQLServerEnum; + private final DtDMEnum dtDMEnum; + private final DtKingbaseESEnum dtKingbaseESEnum; + private final DtPostgreSQLEnum dtPostgreSQLEnum; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/viewshow/constant/DtViewConst.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/viewshow/constant/DtViewConst.java new file mode 100644 index 0000000..1839d52 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/datatype/viewshow/constant/DtViewConst.java @@ -0,0 +1,54 @@ +package com.yunzhupaas.database.datatype.viewshow.constant; + +/** + * 前端数据类型标准 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/25 + */ +public class DtViewConst { + + /** + * 字符串 + */ + public static final String VARCHAR = "varchar"; + + /** + * 日期时间 + */ + public static final String DATE_TIME = "datetime"; + + /** + * 整型 + */ + public static final String INT = "int"; + + /** + * 浮点 + */ + public static final String DECIMAL = "decimal"; + + /** + * 长整型 + */ + public static final String BIGINT = "bigint"; + + /** + * 文本 + */ + public static final String TEXT = "text"; + + /** + * 显示默认 + */ + public static final String DEFAULT = "默认"; + + /** + * Oracle 整型,长征 + */ + public static final String ORACLE_NUMBER = "数字类型"; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/enums/DbAliasEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/enums/DbAliasEnum.java new file mode 100644 index 0000000..2b25076 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/enums/DbAliasEnum.java @@ -0,0 +1,149 @@ +package com.yunzhupaas.database.enums; + +import com.yunzhupaas.database.source.DbBase; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version v3.4.6 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2023-02-10 + */ +@AllArgsConstructor +@Getter +public enum DbAliasEnum { + + /* =========================== 表 ============================ */ + /** + * 表大小 + */ + TABLE_SIZE("F_TABLE_SIZE"), + + /** + * 表名 + */ + TABLE_NAME("F_TABLE_NAME"), + + /** + * 表注释 + */ + TABLE_COMMENT("F_TABLE_COMMENT"), + + /** + * 类型 + */ + TABLE_TYPE("F_TABLE_TYPE"), + + /** + * 表总数 + */ + TABLE_SUM("F_TABLE_SUM"), + + /* =========================== 字段 ============================ */ + /** + * 字段名 + */ + FIELD("F_FIELD"), + + /** + * 字段注释 + */ + FIELD_COMMENT("F_FIELD_COMMENT"), + + /** + * 字段默认值 + */ + DEFAULT_VALUE("F_DEFAULT_VALUE"), + + /** + * 自增 + */ + AUTO_INCREMENT("F_AUTO_INCREMENT"), + + /** + * 默认值(用于判断自增长) + */ + COLUMN_DEFAULT("F_COLUMN_DEFAULT"), + + /** + * 自增 + */ + IS_IDENTITY("F_IS_IDENTITY"), + + /** + * 允空 + */ + ALLOW_NULL("F_ALLOW_NULL"), + + /** + * 主键 + */ + PRIMARY_KEY("F_PRIMARY_KEY"), + + /* ------------- 字段数据类型 ------------- */ + + /** + * 类型 + */ + DATA_TYPE("F_DATA_TYPE"), + + /** + * 以字符为单位的最大长度,适于二进制数据、字符数据,或者文本和图像数据。否则,返回 NULL + * 例如:text、varchar(int时为null),其中varchar为可变长度,text为固定长度 + */ + CHAR_LENGTH("F_CHAR_LENGTH"), + + /** + * precision:数值精度(整个数值的长度) + * 例如:decimal + * 注意:int(i)类型时,无论i是多少,NUMERIC_PRECISION都是10,在填充0的时候i才会起作用 + */ + NUM_PRECISION("F_NUM_PRECISION"), + + /** + * scale:数值标度(小数部分的长度) + */ + NUM_SCALE("F_NUM_SCALE"), + + + /* =========================== 其他 ============================ */ + + /** + * 总数返回 + */ + TOTAL_RECORD("totalRecord"), + + /** + * 总数 + */ + TOTAL("total"), + + /** + * 自增主键触发器判断 + */ + AUTO_TRIGGER("F_AUTO_TRIGGER"), + + ; + private final String alias; + + public String getAlias(String dbEncode) { + return getAlias(dbEncode, alias); + } + + public static String getAlias(String dbEncode, String keyWord){ + if (DbBase.POSTGRE_SQL.equals(dbEncode)) { + //postgre别名只能输出小写,Oracle只能大写 + //Mysql默认,SqlServer默认 + return keyWord.toLowerCase(); + } else if (DbBase.ORACLE.equals(dbEncode)) { + return keyWord.toUpperCase(); + } else { + return keyWord; + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/enums/ParamEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/enums/ParamEnum.java new file mode 100644 index 0000000..1a3927d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/enums/ParamEnum.java @@ -0,0 +1,75 @@ +package com.yunzhupaas.database.enums; + +/** + * 数据库 结构、参数 替换枚举 structure + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/6/29 + */ +public enum ParamEnum { + + /** + * 数据库 + */ + DB_URL("{dbUrl}"), + /** + * 数据库名 + */ + DB_NAME("{dbName}"), + /** + * 用户名 + */ + USER_NAME("{userName}"), + /** + * 模式 + * schema关键字,加前缀 + */ + DB_SCHEMA("{dbSchema}"), + /** + * 表空间 + */ + TABLE_SPACE("{tableSpace}"), + /** + * 表 + */ + TABLE("{table}"), + /** + * 替换符 + */ + SPLIT("split"), + /** + * 字段名 + */ + FILED("{filed}"), + /** + * 字段长度 + */ + DATA_LENGTH("{dataLength}"), + /** + * 字段注释 + */ + COMMENT("{comment}") + ; + + /** + * 替换目标 + */ + private final String target; + + public String getTarget(){ + return this.target; + } + + public String getParamSign(){ + return "?"; + } + + ParamEnum(String target){ + this.target = target; + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/mapper/JdbcMapper.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/mapper/JdbcMapper.java new file mode 100644 index 0000000..387bb23 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/mapper/JdbcMapper.java @@ -0,0 +1,19 @@ +package com.yunzhupaas.database.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version v3.4.3 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-10-18 + */ +@Mapper +public interface JdbcMapper extends BaseMapper { + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbfield/DbFieldModel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbfield/DbFieldModel.java new file mode 100644 index 0000000..56d3eb7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbfield/DbFieldModel.java @@ -0,0 +1,117 @@ +package com.yunzhupaas.database.model.dbfield; + +import com.yunzhupaas.database.constant.DbAliasConst; +import com.yunzhupaas.database.datatype.model.DtModel; +import com.yunzhupaas.database.datatype.model.DtModelDTO; +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.model.dbfield.base.DbFieldModelBase; +import com.yunzhupaas.database.model.dto.ModelDTO; +import com.yunzhupaas.database.model.interfaces.JdbcGetMod; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.util.DbTypeUtil; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.StringUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * 表字段模型 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/12 15:31 + */ +@Data +public class DbFieldModel extends DbFieldModelBase implements JdbcGetMod { + + /** + * 数据类型传递对象 + */ + private DtModelDTO dtModelDTO; + + /** + * 早期注释叫法 + */ + public String getFieldName(){ + return super.getComment(); + } + + /** + * 数据类型格式化 + * -- 创表 + */ + public String formatDataTypeByView(String dbEncode) throws Exception { + DtModel dataTypeModel; + try{ + // 1、前端指定数据类型转换 + if(dtModelDTO == null) dtModelDTO = new DtModelDTO(getDataType(), getLength(), dbEncode, true); + // 2、标准数据类型对象转换 + dataTypeModel = dtModelDTO.convert(); + }catch (DataException e){ + e.printStackTrace(); + return getDataType(); + }catch (Exception e){ + e.printStackTrace(); + // 准备异常时,使用默认可执行数据类型 + dtModelDTO.setConvertType(DtModelDTO.FIX_VAL); + dataTypeModel = dtModelDTO.convert(); + } + return dataTypeModel.formatDataType(); + } + + @Override + public void setMod(ModelDTO modelDTO) throws SQLException { + ResultSet result = modelDTO.getResultSet(); + String dbEncode = modelDTO.getDbEncode(); + // 根据不同的库进行字段处理 + // ============== 字段数据类型 =============== + this.dataType = result.getString(DbAliasEnum.DATA_TYPE.getAlias(dbEncode)); + // ============== 字段类型、长度 =============== + try{ + DbTypeUtil.getEncodeDb(dbEncode).setPartFieldModel(this, result); + this.dtModelDTO.setConvertType(DtModelDTO.DB_VAL).setConvertTargetDtEnum(this.dtModelDTO.getDtEnum()); + this.setLength(this.dtModelDTO.convert().getFormatLengthStr()); + }catch (Exception e){ + e.printStackTrace(); + } + // ============== 字段名 =============== + if(this.field == null) this.field = result.getString(DbAliasEnum.FIELD.getAlias(dbEncode)); + // ============== 字段注释 =============== + if(this.comment == null) this.comment = result.getString(DbAliasEnum.FIELD_COMMENT.getAlias(dbEncode)); + // ============== 字段主键(0:非主键、1:主键) ============== + if(this.isPrimaryKey == null) this.isPrimaryKey = DbAliasConst.PRIMARY_KEY.getSign(result.getInt(DbAliasEnum.PRIMARY_KEY.getAlias(dbEncode))); + // ============== 字段允空(0:空值 NULL、1:非空值 NOT NULL) ============== + if(this.nullSign == null) this.nullSign = DbAliasConst.ALLOW_NULL.getSign(result.getInt(DbAliasEnum.ALLOW_NULL.getAlias(dbEncode))); + // ============== 自增(0:非自增 1:自增) ============== + + try{ + if(this.isAutoIncrement == null && DbBase.MYSQL.equals(dbEncode)){ + this.isAutoIncrement = DbAliasConst.AUTO_INCREMENT.getSign(result.getInt(DbAliasEnum.AUTO_INCREMENT.getAlias(dbEncode))); + } + }catch (Exception ignore){} + + if(this.isAutoIncrement == null && DbBase.DM.equals(dbEncode)) this.isAutoIncrement = result.getInt(DbAliasEnum.AUTO_INCREMENT.getAlias(dbEncode)) == 1; + + if(DbBase.POSTGRE_SQL.equals(dbEncode) || DbBase.KINGBASE_ES.equals(dbEncode)){ + String columnDefault = result.getString(DbAliasEnum.COLUMN_DEFAULT.getAlias(dbEncode)); + String tableName = result.getString(DbAliasEnum.TABLE_NAME.getAlias(dbEncode)); + if(StringUtil.isNotEmpty(columnDefault) && StringUtil.isNotEmpty(tableName) && this.field != null) { + this.isAutoIncrement = ("nextval(\'" + tableName + '_' + this.field + "_seq" + "\'::regclass)").equals(columnDefault); + } + } + + if(DbBase.ORACLE.equals(dbEncode)){ + if(this.isPrimaryKey){ + this.isAutoIncrement = result.getInt(DbAliasEnum.AUTO_TRIGGER.getAlias(dbEncode)) > 0; + } + } + + if(this.isAutoIncrement == null && DbBase.SQL_SERVER.equals(dbEncode)) this.isAutoIncrement = result.getInt(DbAliasEnum.IS_IDENTITY.getAlias(dbEncode)) == 1; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbfield/JdbcColumnModel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbfield/JdbcColumnModel.java new file mode 100644 index 0000000..46ab0cd --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbfield/JdbcColumnModel.java @@ -0,0 +1,243 @@ +package com.yunzhupaas.database.model.dbfield; + +import com.yunzhupaas.database.constant.DbAliasConst; +import com.yunzhupaas.database.constant.RsColumnKeyConst; +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.model.DtModelDTO; +import com.yunzhupaas.database.model.dbfield.base.DbFieldModelBase; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.util.DbTypeUtil; +import lombok.Cleanup; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +/** + * JDBC元数据表模型类型 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/06 + */ +@Data +@NoArgsConstructor +public class JdbcColumnModel extends DbFieldModelBase { + + /** + * 字段别名 + */ + private String label; + + /** + * 字段类型jdbc编码 + */ + private Integer dtJdbcEncode; + + /** + * 字段值 + */ + private Object value; + + /** + * 默认值 + */ + protected String defaultValue; + + /** + * 所属表名 + */ + private String table; + + /** + * 字段长度 + */ + private String size; + + /** + * 字符长度 + * (charLength) + */ + private Long columnSize; + /** + * 标度 + * (precision) + */ + private Integer numPrecRadix; + /** + * 精度 + * (scale) + */ + private Integer decimalDigits; + /** + * 字段位置 + */ + private String ordinalPosition; + + /** + * 自增 + */ + private String autoIncrement; + + /** + * java对应数据类型 + */ + private String javaDataType; + + /* ================== 内部方法 ================= */ + + /** + * 字段结构 + */ + public DbFieldModel convertDbFieldModel(String dbEncode) throws Exception { + DbFieldModel dbFieldModel = new DbFieldModel(); + dbFieldModel.setField(getField()); + dbFieldModel.setComment(getComment()); + dbFieldModel.setDataType(getDataType()); + dbFieldModel.setIsPrimaryKey(getIsPrimaryKey()); + dbFieldModel.setIsAutoIncrement(convertIsAutoIncrement(dbEncode, getAutoIncrement())); + dbFieldModel.setNullSign(getNullSign()); + dbFieldModel.setDefaultValue(getDefaultValue()); + DtInterface dtEnum = DtInterface.newInstanceByDt(getDataType(), dbEncode); + assert dtEnum != null; + dbFieldModel.setDtModelDTO(new DtModelDTO(dtEnum, this.columnSize, Integer.parseInt(this.columnSize.toString()), + this.decimalDigits)); + return dbFieldModel; + } + + /** + * 自增判断 + */ + private static Boolean convertIsAutoIncrement(String dbEncode, String sign) { + switch (dbEncode) { + case DbBase.MYSQL: + return sign.equalsIgnoreCase("YES"); + case DbBase.ORACLE: + case DbBase.SQL_SERVER: + case DbBase.KINGBASE_ES: + case DbBase.DM: + case DbBase.POSTGRE_SQL: + // TODO 等待补充 + default: + return false; + } + } + + /* ================== 静态方法 ================= */ + + /** + * 获取字段元数据对象集合(所有字段) + * 注意:只能获取结构,无法获取值 + * + * @param conn 数据连接 + * @param table 表名 + * @return ignore + * @throws SQLException ignore + */ + public static List getList(Connection conn, String table, List primaryFields) + throws Exception { + @Cleanup + ResultSet rs = getColumnMetaDateRs(conn, table); + List list = new ArrayList<>(); + while (rs.next()) { + JdbcColumnModel column = new JdbcColumnModel(); + // 表名 + column.setTable(rs.getString(RsColumnKeyConst.TABLE_NAME)); + // 列名称: + column.setField(rs.getString(RsColumnKeyConst.COLUMN_NAME)); + // java.sql.Types + column.setJavaDataType(rs.getString(RsColumnKeyConst.DATA_TYPE)); + // 字段类型: + column.setDataType(rs.getString(RsColumnKeyConst.TYPE_NAME)); + // 列的大小(标度):当字符类型表示CharLength,数字类型表示Precision + column.setColumnSize(rs.getLong(RsColumnKeyConst.COLUMN_SIZE)); + // 小数部分的位数(精度): + column.setDecimalDigits(rs.getInt(RsColumnKeyConst.DECIMAL_DIGITS)); + // 描述列的注释: + column.setComment(rs.getString(RsColumnKeyConst.REMARKS)); + // 该列的默认值: + column.setDefaultValue(rs.getString(RsColumnKeyConst.COLUMN_DEF)); + // 列中的最大字节数: + column.setLength(rs.getString(RsColumnKeyConst.CHAR_OCTET_LENGTH)); + // 列的索引: + column.setOrdinalPosition(rs.getString(RsColumnKeyConst.ORDINAL_POSITION)); + // 是否允许使用 NULL: + String isNull = rs.getString(RsColumnKeyConst.IS_NULLABLE); + column.setNullSign(isNull.equalsIgnoreCase("YES") ? DbAliasConst.NULL : DbAliasConst.NOT_NULL); + // 指示此列是否自动增加:(部分数据库不支持) + try { + column.setAutoIncrement(rs.getString(RsColumnKeyConst.IS_AUTOINCREMENT)); + } catch (Exception ignore) { + } + // 是否是主键主键 + column.setIsPrimaryKey(primaryFields.stream().anyMatch(o -> o.equalsIgnoreCase(column.getField()))); + list.add(column); + } + return list; + } + + /** + * 获取字段值相对元数据结果集 + * + * @param rs 结果集 + * @param isLowercase 别名大小写 + * @param isValue 是否取值 + * @return 字段集合 + * @throws SQLException ignore + */ + public static List getList(ResultSet rs, Boolean isLowercase, Boolean isValue) + throws SQLException { + ResultSetMetaData md = rs.getMetaData(); + List dbColumnModelList = new ArrayList<>(); + for (int i = 1; i <= md.getColumnCount(); i++) { + JdbcColumnModel model = new JdbcColumnModel(); + model.setTable(md.getTableName(i)); + model.setField(md.getColumnName(i)); + // 非空判断 + model.setNullSign(md.isNullable(i) == 1 ? DbAliasConst.NULL : DbAliasConst.NOT_NULL); + model.setLabel(isLowercase ? md.getColumnLabel(i).toLowerCase() : md.getColumnLabel(i)); + model.setDataType(md.getColumnTypeName(i)); + model.setValue(isValue ? rs.getObject(i) : null); + dbColumnModelList.add(model); + } + return dbColumnModelList; + } + + public void getOracle() { + + } + + /* ================================== 结果集 ================================== */ + + /** + * 从conn中获取数据库的表元数据 + * + * @param conn 数据连接 + * @return 返回表元数据 + * @throws SQLException ignore + */ + public static ResultSet getColumnMetaDateRs(Connection conn, String table) throws Exception { + DatabaseMetaData dbMetaData = conn.getMetaData(); + /* + * % 代表 * , + * ResultSet rs = dbMetaData.getColumns(conn.getCatalog(), "%", table, "%"); + */ + switch (DbTypeUtil.getDb(conn).getYunzhupaasDbEncode()) { + case DbBase.SQL_SERVER: + return dbMetaData.getColumns(conn.getCatalog(), "dbo", table, null); + case DbBase.POSTGRE_SQL: + return dbMetaData.getColumns(conn.getCatalog(), "public", table, null); + case DbBase.KINGBASE_ES: + return dbMetaData.getColumns(conn.getCatalog(), conn.getSchema(), table, null); + case DbBase.MYSQL: + default: + return dbMetaData.getColumns(conn.getCatalog(), dbMetaData.getUserName(), table, null); + } + + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbfield/base/DbFieldModelBase.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbfield/base/DbFieldModelBase.java new file mode 100644 index 0000000..3ca99d0 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbfield/base/DbFieldModelBase.java @@ -0,0 +1,59 @@ +package com.yunzhupaas.database.model.dbfield.base; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-09 + */ +@Data +public class DbFieldModelBase { + + /** + * 数据长度 + */ + protected String length; + + /** + * 数据类型 + */ + protected String dataType; + + /** + * 字段名 + */ + protected String field; + + /** + * 是否主键 + */ + protected Boolean isPrimaryKey; + + /** + * 是否非空 + * (允空非空及0与1较容易混淆,故使用标识传作参数) + */ + protected String nullSign; + + /** + * 是否自增 + */ + protected Boolean isAutoIncrement; + + /** + * 注释 + */ + protected String comment; + + /** + * 默认值 + */ + protected String defaultValue; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbtable/DbTableFieldModel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbtable/DbTableFieldModel.java new file mode 100644 index 0000000..7726671 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbtable/DbTableFieldModel.java @@ -0,0 +1,153 @@ +package com.yunzhupaas.database.model.dbtable; +import com.yunzhupaas.database.constant.DbAliasConst; +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.model.dbfield.DbFieldModel; +import com.yunzhupaas.database.model.dbtable.base.DbTableModelBase; +import com.yunzhupaas.database.model.dto.ModelDTO; +import com.yunzhupaas.database.model.interfaces.JdbcGetMod; +import io.swagger.v3.oas.annotations.media.Schema; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.util.StringUtil; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.Accessors; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/06/18 By:YanYu + */ +@Data +@NoArgsConstructor +@ToString(callSuper=true) +@Accessors(chain = true) +public class DbTableFieldModel extends DbTableModelBase implements JdbcGetMod { + + /** + * 标识 + */ + @Schema(description = "标识") + private String id; + + /** + * 数据源主键 + */ + @Schema(description = "数据源主键") + private String dbLinkId; + + /** + * 数据库编码 + */ + @Schema(description = "数据库编码") + private String dbEncode; + + /** + * 更新时新表名 + */ + @Schema(description = "更新时新表名") + private String updateNewTable; + + /** + * 更新前的旧表名 + */ + @Schema(description = "更新前的旧表名") + private String updateOldTable; + + /** + * 字段信息集合 + */ + @Schema(description = "字段信息集合") + private List dbFieldModelList; + + /** + * 表是否存在信息 + */ + @Schema(description = "表是否存在信息") + private Boolean hasTableData; + + /** + * 类型 0-表 1-视图 + */ + @Schema(description = "类型 0-表 1-视图") + private Integer type; + + /** + * 前端注释 + */ + public String getTableName(){ + return getComment(); + } + + public void setTableName(String comment) { + super.setComment(comment); + } + + public DbTableFieldModel(String table, String tableComment, List dbFieldModelList){ + this.setTable(table); + this.setComment(tableComment); + this.dbFieldModelList = dbFieldModelList; + } + + @Override + public void setMod(ModelDTO modelDTO) { + try { + String dbEncode = modelDTO.getDbEncode(); + ResultSet resultSet = modelDTO.getResultSet(); + // ============== 表名 ============== + try { + String table = resultSet.getString(DbAliasEnum.TABLE_NAME.getAlias(dbEncode)); + this.setTable(table); + } catch (Exception e) { + + } + // ============== 表注释 ============== + try { + String tableComment = resultSet.getString(DbAliasEnum.TABLE_COMMENT.getAlias(dbEncode)); + this.setComment(tableComment); + } catch (Exception e) { + + } + + // ============== 表总数 ============== + this.setSum("0"); + try { + String sum = resultSet.getString(DbAliasEnum.TABLE_SUM.getAlias(dbEncode)); + if(sum != null) + this.setSum(sum); + } catch (Exception e) { + + } + this.setType(0); + try { + String tableType = resultSet.getString(DbAliasEnum.TABLE_TYPE.getAlias(dbEncode)); + if (StringUtil.isNotEmpty(tableType)) { + if (dbEncode.equals(DbBase.SQL_SERVER) && tableType.equalsIgnoreCase("V ")) { + this.setType(1); + } else if ((dbEncode.equals(DbBase.ORACLE) || dbEncode.equals(DbBase.MYSQL) + || dbEncode.equals(DbBase.DM) || dbEncode.equals(DbBase.POSTGRE_SQL) || dbEncode.equals(DbBase.KINGBASE_ES) + ) + && tableType.equalsIgnoreCase("VIEW")) { + this.setType(1); + } + } + } catch (Exception e) { + + } + // ============== 表大小(由于部分数据库,版本取消了此功能)============== + /*String size = resultSet.getString(DbAliasEnum.TABLE_SIZE.AS());*/ + this.setDbEncode(dbEncode); +// this.setSize(size); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbtable/JdbcTableModel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbtable/JdbcTableModel.java new file mode 100644 index 0000000..bfdf465 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbtable/JdbcTableModel.java @@ -0,0 +1,256 @@ +package com.yunzhupaas.database.model.dbtable; + +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.constant.TableFieldsNameConst; +import com.yunzhupaas.database.constant.RsColumnKeyConst; +import com.yunzhupaas.database.constant.RsTableKeyConst; +import com.yunzhupaas.database.model.dbfield.DbFieldModel; +import com.yunzhupaas.database.model.dbfield.JdbcColumnModel; +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.model.interfaces.DbSourceOrDbLink; +import com.yunzhupaas.database.util.ConnUtil; +import com.yunzhupaas.exception.DataException; +import lombok.Cleanup; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * JDBC元数据字段模型类型 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/21 + */ +@Data +@NoArgsConstructor +public class JdbcTableModel { + + /** + * 数据库类型 + */ + private String dbEncode; + + /** + * 表名 + */ + private String table; + + /** + * 表类型 + */ + private String tableType; + + /** + * 表注释 + */ + private String comment; + + /** + * 主键字段 + */ + private String primaryField; + + /** + * 主键字段列表 + */ + private List primaryFields; + + /** + * jdbc字段集合 + */ + private List jdbcColumnModelList; + + /* ================== 构造方法 ================= */ + + public JdbcTableModel(DbLinkEntity dbLinkEntity, String table) throws Exception { +// @Cleanup Connection conn = PrepSqlDTO.getConn(dbLinkEntity); + @Cleanup Connection conn = ConnUtil.ConnCommon.getConnRemarks(dbLinkEntity); + @Cleanup ResultSet rs = getTableMetaDateRs(conn, table); + List primaryKeys = getPrimaryKeys(conn, table).stream().sorted((o1, o2) -> { + return (TableFieldsNameConst.F_ID.equalsIgnoreCase(o2) || TableFieldsNameConst.ID.equalsIgnoreCase(o2)) ? 1 : 0; + }).collect(Collectors.toList()); + if (rs.next()) { + this.dbEncode = dbLinkEntity.getDbType(); + this.table = rs.getString(RsTableKeyConst.TABLE_NAME); + this.tableType = rs.getString(RsTableKeyConst.TABLE_TYPE); + this.comment = rs.getString(RsTableKeyConst.REMARKS); + this.primaryField = primaryKeys.isEmpty() ? null : primaryKeys.get(0); + this.primaryFields = primaryKeys; + this.jdbcColumnModelList = JdbcColumnModel.getList(conn, table, primaryFields); + }else { + throw new DataException(MsgCode.DB009.get(table)); + } + } + + /* ================== 内部方法 ================= */ + + public DbTableFieldModel convertDbTableFieldModel() throws Exception { + // 转换表 + DbTableFieldModel dbTableFieldModel = new DbTableFieldModel(); + dbTableFieldModel.setTable(this.table); + dbTableFieldModel.setComment(this.comment); + // 转换字段集合 + List dbFieldModelList = new ArrayList<>(); + for (JdbcColumnModel jdbcColumnModel : this.jdbcColumnModelList) { + dbFieldModelList.add(jdbcColumnModel.convertDbFieldModel(this.dbEncode)); + } + dbTableFieldModel.setDbFieldModelList(dbFieldModelList); + return dbTableFieldModel; + } + + /* ================== 静态方法 ================= */ + + /** + * 获取表元数据对象(所有表) + * @param conn 数据连接 + * @return ignore + * @throws SQLException ignore + */ + public static List getList(Connection conn) throws Exception { + @Cleanup ResultSet rs = getTableMetaDateRs(conn); + List list = new ArrayList<>(); + while (rs.next()) { + JdbcTableModel jdbcTableModel = new JdbcTableModel(); + jdbcTableModel.setTable(rs.getString(RsTableKeyConst.TABLE_NAME)); + jdbcTableModel.setTableType(rs.getString(RsTableKeyConst.TABLE_TYPE)); + jdbcTableModel.setComment(rs.getString(RsTableKeyConst.REMARKS)); + jdbcTableModel.setJdbcColumnModelList(JdbcColumnModel.getList(conn, jdbcTableModel.getTable(), jdbcTableModel.getPrimaryFields())); + list.add(jdbcTableModel); + } + return list; + } + + + public static String getPrimary(DbSourceOrDbLink dbSourceOrDbLink, String table) throws SQLException { + @Cleanup Connection conn = ConnUtil.getConnOrDefault(dbSourceOrDbLink); + return getPrimary(conn, table); + } + + /** + * 获取第一个主键, 排除某些主键 + */ + public static String getPrimaryExculde(Connection conn, String table, String... excludeField) throws SQLException { + List primaryKeys = getPrimaryKeys(conn, table); + if(!primaryKeys.isEmpty()){ + for (String primaryKey : primaryKeys) { + boolean exlude = false; + for (String exclude : excludeField) { + if(primaryKey.equalsIgnoreCase(exclude)){ + exlude = true; + break; + } + } + if(!exlude){ + return primaryKey; + } + } + } + return ""; + } + + + /** + * 获取第一个主键, 排除某些主键 + */ + public static String getPrimaryExculde(DbSourceOrDbLink dbSourceOrDbLink, String table, String... excludeField) throws SQLException { + @Cleanup Connection conn = ConnUtil.getConnOrDefault(dbSourceOrDbLink); + return getPrimaryExculde(conn, table, excludeField); + } + + /** + * 如有多个主键返回第一个主键 + */ + public static String getPrimary(Connection conn, String table) throws SQLException { + List primaryKeys = getPrimaryKeys(conn, table); + return primaryKeys.isEmpty()? "" : primaryKeys.get(0); + } + + + public static String getPrimaryIdFirst(DbSourceOrDbLink dbSourceOrDbLink, String table) throws SQLException { + @Cleanup Connection conn = ConnUtil.getConnOrDefault(dbSourceOrDbLink); + return getPrimaryIdFirst(conn, table); + } + + /** + * 如有多个主键返回第一个主键, id优先返回 + */ + public static String getPrimaryIdFirst(Connection conn, String table) throws SQLException { + List primaryKeys = getPrimaryKeys(conn, table); + String findedId = ""; + for (String primaryKey : primaryKeys) { + findedId = primaryKey; + // 联合主键优先返回f_id, id字段 + if(TableFieldsNameConst.F_ID.equalsIgnoreCase(findedId) || TableFieldsNameConst.ID.equalsIgnoreCase(findedId)){ + break; + } + } + return findedId; + } + + + /** + * 返回全部主键 + */ + public static List getPrimaryKeys(DbSourceOrDbLink dbSourceOrDbLink, String table) throws SQLException { + @Cleanup Connection conn = ConnUtil.getConnOrDefault(dbSourceOrDbLink); + return getPrimaryKeys(conn, table); + } + + /** + * 返回全部主键 + */ + public static List getPrimaryKeys(Connection conn, String table) throws SQLException { + //获取表主键 + @Cleanup ResultSet rs = conn.getMetaData().getPrimaryKeys(conn.getCatalog(), null, table); + List primaryKeys = new ArrayList<>(); + while(rs.next()){ + primaryKeys.add(rs.getString(RsColumnKeyConst.COLUMN_NAME)); + } + return primaryKeys; + } + + /** + * 返回全部表的主键信息 + * @return [{表名:主键名}] + */ + public static List> getPrimaryMapList(Connection conn, String schema) throws SQLException { + //获取表主键 + @Cleanup ResultSet rs = conn.getMetaData().getPrimaryKeys(conn.getCatalog(), schema, null); + List> list = new ArrayList<>(); + while (rs.next()){ + Map map = new HashMap<>(); + map.put(rs.getString(RsColumnKeyConst.TABLE_NAME), rs.getString(RsColumnKeyConst.COLUMN_NAME)); + list.add(map); + } + return list; + } + + /* ================================== 结果集 ================================== */ + + /** + * 从conn中获取数据库的表元数据 + * @param conn 数据连接 + * @return 返回表元数据 + * @throws SQLException ignore + */ + public static ResultSet getTableMetaDateRs(Connection conn, String table) throws SQLException { + return conn.getMetaData().getTables(conn.getCatalog(), null, table, new String[]{"TABLE"}); + } + + private static ResultSet getTableMetaDateRs(Connection conn) throws SQLException { + return getTableMetaDateRs(conn, null); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbtable/base/DbTableModelBase.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbtable/base/DbTableModelBase.java new file mode 100644 index 0000000..cc43791 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dbtable/base/DbTableModelBase.java @@ -0,0 +1,42 @@ +package com.yunzhupaas.database.model.dbtable.base; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-09 + */ +@Data +public class DbTableModelBase { + + /** + * 表名 + */ + private String table; + + /** + * 表说明 + */ + private String comment; + + /** + * 大小 + */ + private String size; + + /** + * 数据条数 + */ + private String sum; + + /** + * 主键 + */ + private String primaryKeyField; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/DataSourceDTO.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/DataSourceDTO.java new file mode 100644 index 0000000..8465815 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/DataSourceDTO.java @@ -0,0 +1,35 @@ +package com.yunzhupaas.database.model.dto;//package com.yunzhupaas.database.model.dto; +// +//import com.yunzhupaas.database.sql.model.DbStruct; +//import com.yunzhupaas.database.util.DataSourceUtil; +//import com.yunzhupaas.util.StringUtil; +//import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +// +///** +// * 数据源参数传输对象 +// * -- 注意:这里的参数dataSourceUtil是spring托管的全局唯一变量,此数据传输对象防止数据源互串 +// * +// * @author 云筑产品开发平台组 +// * @version V3.2.0 +// * @copyright 深圳市乐程软件有限公司 +// * @date 2024/10/28 +// */ +//@Data +//public class DataSourceDTO extends DataSourceUtil{ +// +// /** +// * 数据来源 +// * 0:自身创建 1:配置 2:数据连接 +// */ +// private Integer dataSourceFrom; +// +// /** +// * 表名 +// */ +// private String tableName; +// +// +// +//} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/DbConnDTO.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/DbConnDTO.java new file mode 100644 index 0000000..f46488d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/DbConnDTO.java @@ -0,0 +1,50 @@ +package com.yunzhupaas.database.model.dto; + +import com.yunzhupaas.database.model.interfaces.DbSourceOrDbLink; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.util.DataSourceUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.sql.Connection; +import java.util.function.Function; + +/** + * 数据连接相关数据传输对象 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/12 + */ +@Data +@NoArgsConstructor +public class DbConnDTO { + + public DbConnDTO(DbBase dbBase, DataSourceUtil dbSource, Connection conn){ + this.dbBase = dbBase; + this.dbSourceInfo = dbSource; + this.conn = conn; + } + + /** + * 数据库基类 + */ + private DbBase dbBase; + + /** + * 数据源信息 + */ + private DbSourceOrDbLink dbSourceInfo; + + /** + * 数据连接 + */ + private Connection conn; + + + private Function connFunc; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/JdbcResult.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/JdbcResult.java new file mode 100644 index 0000000..bc6e69e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/JdbcResult.java @@ -0,0 +1,54 @@ +package com.yunzhupaas.database.model.dto; + +import lombok.*; +import lombok.experimental.Accessors; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version v3.4.3 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-10-20 + */ +@Data +@Accessors(chain = true) +public class JdbcResult { + + /** + * 别名小写开关 + */ + private Boolean isLowerCase = false; + + /** + * 别名开关 + */ + private Boolean isAlias = false; + + /** + * 是查询结构还是查询值 + */ + private Boolean isValue = true; + + @Getter(value = AccessLevel.NONE) + @Setter(value = AccessLevel.NONE) + private MyFunction, R> func; + + public JdbcResult(MyFunction, R> func){ + this.func = func; + } + + /** + * 在get的时候才进行查询操作 + */ + public R get() throws Exception { + return this.func.apply(this); + } + + @FunctionalInterface + public static interface MyFunction{ + R apply(T t) throws Exception; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/ModelDTO.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/ModelDTO.java new file mode 100644 index 0000000..8522245 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/ModelDTO.java @@ -0,0 +1,40 @@ +package com.yunzhupaas.database.model.dto; + +import com.yunzhupaas.database.source.DbBase; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.sql.ResultSet; + +/** + * 自定义模板参数对象 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/18 + */ +@Data +public class ModelDTO { + + public ModelDTO(ResultSet resultSet, String dbEncode){ + this.resultSet = resultSet; + this.dbEncode = dbEncode; + } + + public ModelDTO(ResultSet resultSet, DbBase dbBase){ + this.resultSet = resultSet; + } + + /** + * 结果集 + */ + private ResultSet resultSet; + + /** + * 数据基类 + */ + private String dbEncode; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/PrepSqlDTO.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/PrepSqlDTO.java new file mode 100644 index 0000000..b68f886 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/dto/PrepSqlDTO.java @@ -0,0 +1,222 @@ +package com.yunzhupaas.database.model.dto; + +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.util.ConnUtil; +import com.yunzhupaas.database.util.DataSourceUtil; +import com.yunzhupaas.database.util.DynamicDataSourceUtil; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.XSSEscape; +import com.yunzhupaas.util.context.SpringContext; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.*; +import java.util.function.Function; + +/** + * Dynamic SQL参数传输对象 + * + * @author 云筑产品开发平台组 GuanMengYu,YanYu + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/6/21 + */ + +@Data +@NoArgsConstructor +@Accessors(chain = true) +public class PrepSqlDTO { + + private static DataSource getDataSource(){ + return SpringContext.getBean(DataSource.class); + } + + /** + * 数据连接方法接口函数 + */ + public static Function DB_LINK_FUN; + + /** + * conn连接 + */ +// @Getter(value = AccessLevel.NONE) +// @Setter(value = AccessLevel.NONE) +// private Connection connection; + + private DbLinkEntity dbLinkEntity; + private Connection preConnection; + + /** + * 执行的sql语句用占位符代替 + * 注意:一个对象只对应一条SQL + */ + private String sql; + + /** + * sql对应占位符的值 + */ + private List dataList = new ArrayList<>(); + + /** + * 批量参数 + */ + private List> multiDataList = new ArrayList<>(); + + /** + * SQL命令类型 + */ + private String sqlCommandType; + public final static String INSERT = "insert"; + public final static String DELETE = "delete"; + public final static String UPDATE = "update"; + public final static String SELECT = "select"; + public final static String CRE_UP_DE = "creUpDe"; + + /** + * 获取切源后的数据源连接, 并清除自动切源记录 + * @param dbLinkEntity + * @return + * @throws DataException + */ + public static Connection getConn(DbLinkEntity dbLinkEntity) throws DataException { + try{ + return new PrepSqlDTO().withConn(dbLinkEntity).switchConn().getConnection(); + }catch (SQLException d){ + d.printStackTrace(); + throw new DataException(d.getMessage()); + } + } + + /** + * 获取切源后的数据源连接, 并清除自动切源记录 + * @return + * @throws SQLException + */ + private Connection getConnection() throws SQLException { + try { + Connection conn = DynamicDataSourceUtil.getCurrentConnection(); + ConnUtil.switchConnectionSchema(conn); + return conn; + } finally{ + DynamicDataSourceUtil.clearSwitchDataSource(); + } + } + + /** + * 该方法会自动将数据源切换至配置的目标源 + * 调用完后若没有使用获取Connection方法需要手动调用 DynamicDataSourceUtil.clearSwitchDataSource()清除切源记录 + * + * @return + * @throws SQLException + * @throws DataException + */ + public PrepSqlDTO switchConn() throws SQLException, DataException { + if(preConnection == null){ + if (this.dbLinkEntity != null) { + if (this.dbLinkEntity.getId() != null && !"0".equals(this.dbLinkEntity.getId())) { + // 增加并切换数据源 + DynamicDataSourceUtil.switchToDataSource(dbLinkEntity); + } else { + if (dbLinkEntity.getUrl() != null) { + DynamicDataSourceUtil.switchToDataSource(dbLinkEntity.getUserName(), dbLinkEntity.getPassword(), dbLinkEntity.getUrl(), dbLinkEntity.getDbType()); + } else { + //切换只主库 + DynamicDataSourceUtil.switchToDataSource(null); + } + } + } else { + throw new SQLException("dbLinkEntity数据库连接对象不能为空"); + } + } + return this; + } + + /* =============================== 构造方法 ============================== */ + + /** + * 无参数SQL语句 + */ + public PrepSqlDTO(String sql){ + this.sql = sql; + } + + /** + * 快捷有参SQL语句 + */ + public PrepSqlDTO(String sql, Object ...objs){ + this.sql = sql; + this.dataList = Arrays.asList(objs); + } + /** + * 有参SQL语句 + */ + public PrepSqlDTO(String sql, List prepareDataList){ + this.sql = sql; + this.dataList = prepareDataList; + } + +// public PrepSqlDTO withConn(Connection conn){ +// this.connection = conn; +// return this; +// } + + public PrepSqlDTO withConn(String dbLinkId){ + this.dbLinkEntity = DB_LINK_FUN.apply(dbLinkId); + return this; + } + + public PrepSqlDTO withConn(DbLinkEntity dbLinkEntity){ + this.dbLinkEntity = dbLinkEntity; + return this; + } + + public PrepSqlDTO withConn(DataSourceUtil dataSourceUtil, String dbName){ + this.dbLinkEntity = dataSourceUtil.init(dbName); + return this; + } + + public PrepSqlDTO withConn(String user, String password, String url){ + this.dbLinkEntity = new DbLinkEntity(); + dbLinkEntity.setUserName(user); + dbLinkEntity.setPassword(password); + dbLinkEntity.setUrl(url); + return this; + } + + public PrepSqlDTO withConn(Connection conn){ + preConnection = conn; + return this; + } + + /* =================== 同一条语句,多个组参数 ======================== */ + + public void addMultiData(List prepareDataList){ + this.multiDataList.add(prepareDataList); + } + + public void addMultiData(Object ...objs){ + this.multiDataList.add(Arrays.asList(objs)); + } + + public Map getMapParams() { + String sql = XSSEscape.escapeEmpty(this.sql); + int index = 0; + while (sql.contains("?") && index <= this.dataList.size()){ + sql = sql.replaceFirst("\\?", "\\#{param_" + index + "}"); + index++; + } + Map params = new HashMap<>(); + params.put("sql", sql); + for (int i = 0 ; i < this.dataList.size() ; i++) { + Object dataObject = this.dataList.get(i); + params.put("param_" + i, dataObject); + } + return params; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/entity/DbLinkEntity.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/entity/DbLinkEntity.java new file mode 100644 index 0000000..13f5902 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/entity/DbLinkEntity.java @@ -0,0 +1,54 @@ +package com.yunzhupaas.database.model.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.yunzhupaas.database.model.dto.PrepSqlDTO; +import com.yunzhupaas.database.util.DataSourceUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 数据连接 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2023/09/27 + */ +@Data +@TableName("base_db_link") +@NoArgsConstructor +public class DbLinkEntity extends DataSourceUtil { + /** + * 连接主键 + */ + @TableId("f_id") + private String id; + + /** + * 连接名称 + */ + @TableField("f_full_name") + private String fullName; + + /** + * Oracle扩展开关 + */ + @TableField("f_oracle_extend") + private Integer oracleExtend; + + public static DbLinkEntity newInstance(String dbLinkId){ + return PrepSqlDTO.DB_LINK_FUN.apply(dbLinkId); + } + + public DbLinkEntity(String dbType){ + super.setDbType(dbType); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/interfaces/DbSourceOrDbLink.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/interfaces/DbSourceOrDbLink.java new file mode 100644 index 0000000..71af431 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/interfaces/DbSourceOrDbLink.java @@ -0,0 +1,24 @@ +package com.yunzhupaas.database.model.interfaces; + + +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.sql.model.DbStruct; + +/** + * 数据源接口 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/28 + */ +public interface DbSourceOrDbLink { + + DbStruct getDbStruct(); + + DbLinkEntity init(); + + DbLinkEntity init(String dbName); + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/interfaces/JdbcCreUpDel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/interfaces/JdbcCreUpDel.java new file mode 100644 index 0000000..fa9e4af --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/interfaces/JdbcCreUpDel.java @@ -0,0 +1,47 @@ +package com.yunzhupaas.database.model.interfaces; + +import com.yunzhupaas.exception.DataException; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.List; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.4.2 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/8/17 0017 + */ +@FunctionalInterface +public interface JdbcCreUpDel { + + T execute() throws SQLException; + + /** + * 参数配置 + */ + static void setData(PreparedStatement preparedStatement, List data) throws SQLException { + if(data != null){ + for (int i = 0; i < data.size(); i++) { + preparedStatement.setObject(i + 1, data.get(i)); + } + } + } + + static T get(Connection conn, JdbcCreUpDel creUpDel) throws SQLException { + try{ + conn.setAutoCommit(false); + T result= creUpDel.execute(); + conn.commit(); + return result; + } catch (SQLException e) { + //捕捉回滚操作 + throw DataException.rollbackDataException(e, conn); + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/interfaces/JdbcGetMod.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/interfaces/JdbcGetMod.java new file mode 100644 index 0000000..b899393 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/interfaces/JdbcGetMod.java @@ -0,0 +1,25 @@ +package com.yunzhupaas.database.model.interfaces; + +import com.yunzhupaas.database.model.dto.ModelDTO; + +import java.sql.SQLException; + +/** + * 数据模板接口 + * + * @author 云筑产品开发平台组 YY + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/06 + */ +public interface JdbcGetMod { + + /** + * 设置自定义模板接口 + * @param modelDTO 模板相关参数 + * @throws SQLException ignore + */ + void setMod(ModelDTO modelDTO) throws SQLException; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/page/DbTableDataForm.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/page/DbTableDataForm.java new file mode 100644 index 0000000..ddaf086 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/page/DbTableDataForm.java @@ -0,0 +1,19 @@ +package com.yunzhupaas.database.model.page; + +import com.yunzhupaas.base.Pagination; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 表数据页面对象 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/12 15:31 + */ +@Data +public class DbTableDataForm extends Pagination { + private String field; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/page/JdbcPageMod.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/page/JdbcPageMod.java new file mode 100644 index 0000000..d79d497 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/page/JdbcPageMod.java @@ -0,0 +1,39 @@ +package com.yunzhupaas.database.model.page; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * jdbc分页模型 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/11/3 + */ +@Data +public class JdbcPageMod { + + /** + * 页面大小 + */ + private Integer pageSize; + + /** + * 当前页 + */ + private Integer currentPage; + + /** + * 数据总条数 + */ + private Integer totalRecord; + + /** + * 数据 + */ + private List dataList; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/ConditionJsonModel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/ConditionJsonModel.java new file mode 100644 index 0000000..2588069 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/ConditionJsonModel.java @@ -0,0 +1,27 @@ +package com.yunzhupaas.database.model.superQuery; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 高级查询 + * + * @author 云筑产品开发平台组 + * @version V3.4.2 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2022/5/31 + */ +@Data +public class ConditionJsonModel { + private String field; + private String fieldValue; + private String symbol; + private String tableName; + private String yunzhupaasKey; + private String defaultValue; + private String attr; + /** + * 表单字段是否多选 + */ + private boolean formMultiple; +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/SuperJsonModel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/SuperJsonModel.java new file mode 100644 index 0000000..b8af713 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/SuperJsonModel.java @@ -0,0 +1,15 @@ +package com.yunzhupaas.database.model.superQuery; + +import com.yunzhupaas.emnus.SearchMethodEnum; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class SuperJsonModel { + private Boolean authorizeLogic = true; + private String matchLogic = SearchMethodEnum.And.getSymbol(); + private List conditionList = new ArrayList<>(); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/SuperQueryConditionModel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/SuperQueryConditionModel.java new file mode 100644 index 0000000..c9414cb --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/SuperQueryConditionModel.java @@ -0,0 +1,26 @@ +package com.yunzhupaas.database.model.superQuery; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.AllArgsConstructor; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 高级查询(代码生成器) + * + * @author 云筑产品开发平台组 + * @version V3.4.2 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2022/6/23 + */ +@Data +@AllArgsConstructor +public class SuperQueryConditionModel { + private QueryWrapper obj; + private List conditionList; + private String matchLogic; + private String tableName; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/SuperQueryJsonModel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/SuperQueryJsonModel.java new file mode 100644 index 0000000..565a59e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/model/superQuery/SuperQueryJsonModel.java @@ -0,0 +1,23 @@ +package com.yunzhupaas.database.model.superQuery; + +import com.yunzhupaas.emnus.SearchMethodEnum; +import com.yunzhupaas.model.visualJson.FieLdsModel; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * 高级查询 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2022/6/1 + */ +@Data +public class SuperQueryJsonModel { + private String logic = SearchMethodEnum.And.getSymbol(); + private List groups = new ArrayList<>(); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/DynamicGeneratorInterceptor.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/DynamicGeneratorInterceptor.java new file mode 100644 index 0000000..10a18d1 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/DynamicGeneratorInterceptor.java @@ -0,0 +1,76 @@ +package com.yunzhupaas.database.plugins; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationInterceptor; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; +import com.baomidou.dynamic.datasource.processor.DsProcessor; +import com.baomidou.dynamic.datasource.creator.DataSourceProperty; +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; +import com.yunzhupaas.database.util.ConnUtil; +import com.yunzhupaas.database.util.DataSourceUtil; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.context.SpringContext; +import org.aopalliance.intercept.MethodInvocation; + +public class DynamicGeneratorInterceptor extends DynamicDataSourceAnnotationInterceptor { + + private DynamicRoutingDataSource dynamicRoutingDataSource; + private DefaultDataSourceCreator dataSourceCreator; + + public DynamicGeneratorInterceptor(Boolean allowedPublicOnly, DsProcessor dsProcessor) { + super(allowedPublicOnly, dsProcessor); + } + + @Override + public Object invoke(MethodInvocation methodInvocation) throws Throwable { + try { + //是否继承动态生成源接口 + if (methodInvocation.getThis() instanceof DynamicSourceGeneratorInterface) { + DS ds = methodInvocation.getThis().getClass().getAnnotation(DS.class); + if (ds != null && StringUtil.isNotEmpty(ds.value())) { + String datasourceName = ds.value(); + DynamicSourceGeneratorInterface m = (DynamicSourceGeneratorInterface) methodInvocation.getThis(); + String now = null; + try { + boolean invalid = true; + if (Boolean.TRUE.equals(m.cachedConnection())) { + if (dynamicRoutingDataSource == null) { + dynamicRoutingDataSource = SpringContext.getBean(DynamicRoutingDataSource.class); + dataSourceCreator = SpringContext.getBean(DefaultDataSourceCreator.class); + } + if (dynamicRoutingDataSource.getDataSources().containsKey(datasourceName)) { +// if (dynamicRoutingDataSource.getCurrentDataSources().get(datasourceName).getConnection().isValid(5)) { + //已存在当前动态数据源且数据源可用则不重新获取数据源配置 + invalid = false; +// } + } + } + if (invalid) { + //重新生成动态数据源 + //设置为默认数据源获取动态数据源信息 + now = DynamicDataSourceContextHolder.push(null); + DataSourceUtil dataSource = m.getDataSource(); + if (dataSource != null) { + DataSourceProperty dataSourceProperty = new DataSourceProperty(); + dataSourceProperty.setUsername(dataSource.getUserName()); + dataSourceProperty.setPassword(dataSource.getPassword()); + dataSourceProperty.setUrl(ConnUtil.getUrl(dataSource)); + dataSourceProperty.setDriverClassName(dataSource.getDriver()); + dynamicRoutingDataSource.addDataSource(datasourceName, dataSourceCreator.createDataSource(dataSourceProperty)); + } + } + } finally { + if (now != null) { + DynamicDataSourceContextHolder.poll(); + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return methodInvocation.proceed(); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/DynamicSourceGeneratorInterface.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/DynamicSourceGeneratorInterface.java new file mode 100644 index 0000000..c5f67de --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/DynamicSourceGeneratorInterface.java @@ -0,0 +1,29 @@ +package com.yunzhupaas.database.plugins; + + +import com.yunzhupaas.database.util.DataSourceUtil; + +/** + * 动态生成数据源接口 + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +public interface DynamicSourceGeneratorInterface { + + /** + * 获取当前需要切换的数据源配置 + * @return + */ + DataSourceUtil getDataSource(); + + /** + * 是否缓存链接 + * @return true: 不可用时重新获取, false: 每次都重新获取配置 + */ + default boolean cachedConnection(){ + return true; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/ITenantPlugin.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/ITenantPlugin.java new file mode 100644 index 0000000..4cd21a6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/ITenantPlugin.java @@ -0,0 +1,40 @@ +package com.yunzhupaas.database.plugins; + +import cn.dev33.satoken.context.SaHolder; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.UserProvider; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.function.Consumer; + +public interface ITenantPlugin { + + default void printNoTenant(Consumer logConsumer){ + String token = null; + String url = null; + String stack = null; + String userId = UserProvider.getUser().getTenantId(); + try{ + token = UserProvider.getToken(); + url = SaHolder.getRequest().getRequestPath(); + }catch (Exception e){} + if(url == null){ + try{ + stack = StringUtil.join(Thread.currentThread().getStackTrace(), "\n"); + }catch (Exception e){} + } + logConsumer.accept(new NoTenantInfoModel(token, url, stack, userId)); + } + +} + +@Data +@AllArgsConstructor +class NoTenantInfoModel{ + private String token; + private String url; + private String stack; + private String userId; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/LogicDeleteHandler.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/LogicDeleteHandler.java new file mode 100644 index 0000000..22252ca --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/LogicDeleteHandler.java @@ -0,0 +1,76 @@ +package com.yunzhupaas.database.plugins; + +import com.yunzhupaas.constant.TableFieldsNameConst; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.schema.Column; + +import java.util.List; + +/** + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2023/1/3 15:07 + */ +public interface LogicDeleteHandler { + + String DELETE_FIELD = TableFieldsNameConst.F_DELETE_MARK; + String DELETESQL = "UPDATE a SET " + DELETE_FIELD + " = 1"; + + + /** + * 获取租户 ID 值表达式,只支持单个 ID 值 + *

+ * + * @return 租户 ID 值表达式 + */ + Expression getNotDeletedValue(); + + /** + * 获取租户字段名 + *

+ * 默认字段名叫: tenant_id + * + * @return 租户字段名 + */ + default String getLogicDeleteColumn() { + return DELETE_FIELD; + } + + /** + * 获取租户字段名 + *

+ * 默认字段名叫: tenant_id + * + * @return 租户字段名 + */ + default String getDeleteSql() { + return DELETESQL; + } + + /** + * 根据表名判断是否忽略拼接多租户条件 + *

+ * 默认都要进行解析并拼接多租户条件 + * + * @param tableName 表名 + * @return 是否忽略, true:表示忽略,false:需要解析并拼接多租户条件 + */ + default boolean ignoreTable(String tableName) { + return false; + } + + /** + * 忽略插入租户字段逻辑 + * + * @param columns 插入字段 + * @param tenantIdColumn 租户 ID 字段 + * @return + */ + default boolean ignoreInsert(List columns, String tenantIdColumn) { + return columns.stream().map(Column::getColumnName).anyMatch(i -> i.equalsIgnoreCase(tenantIdColumn)); + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDefaultMasterSlaveAutoRoutingPlugin.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDefaultMasterSlaveAutoRoutingPlugin.java new file mode 100644 index 0000000..fb2f04d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDefaultMasterSlaveAutoRoutingPlugin.java @@ -0,0 +1,69 @@ +package com.yunzhupaas.database.plugins; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.enums.DdConstants; +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; +import com.baomidou.dynamic.datasource.tx.TransactionContext; +import com.yunzhupaas.database.util.DynamicDataSourceUtil; +import com.yunzhupaas.util.TenantHolder; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.cache.CacheKey; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.plugin.Intercepts; +import org.apache.ibatis.plugin.Invocation; +import org.apache.ibatis.plugin.Signature; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.util.StringUtils; + +import javax.sql.DataSource; + +/** + * 主库读写分离 + */ +@Intercepts({ + @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), + @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), + @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) +@Slf4j +public class MyDefaultMasterSlaveAutoRoutingPlugin implements Interceptor { + + protected DynamicRoutingDataSource dynamicDataSource; + + public MyDefaultMasterSlaveAutoRoutingPlugin(DataSource dataSource){ + this.dynamicDataSource = (DynamicRoutingDataSource) dataSource; + } + + @Override + public Object intercept(Invocation invocation) throws Throwable { + // 连接隔离模式多租户不处理, 当前非主数据源不处理, 未添加从库不处理 + if (TenantHolder.isRemote() + || !DynamicDataSourceUtil.isPrimaryDataSoure() + || !dynamicDataSource.getGroupDataSources().containsKey(DdConstants.SLAVE)) { + return invocation.proceed(); + } + Object[] args = invocation.getArgs(); + MappedStatement ms = (MappedStatement) args[0]; + String pushedDataSource = null; + try { + // 存在事务只使用主库 + boolean hasTrans = TransactionSynchronizationManager.isActualTransactionActive(); + if (!hasTrans) { + hasTrans = StringUtils.hasText(TransactionContext.getXID()); + } + String dataSource = !hasTrans && SqlCommandType.SELECT == ms.getSqlCommandType() ? DdConstants.SLAVE : DynamicDataSourceUtil.dynamicDataSourceProperties.getPrimary(); + pushedDataSource = DynamicDataSourceContextHolder.push(dataSource); + return invocation.proceed(); + } finally { + if (pushedDataSource != null) { + DynamicDataSourceContextHolder.poll(); + } + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDefaultSqlInjector.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDefaultSqlInjector.java new file mode 100644 index 0000000..e50d5b7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDefaultSqlInjector.java @@ -0,0 +1,163 @@ +package com.yunzhupaas.database.plugins; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.injector.AbstractMethod; +import com.baomidou.mybatisplus.core.injector.AbstractSqlInjector; +import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; +import com.baomidou.mybatisplus.core.injector.ISqlInjector; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import com.yunzhupaas.config.ApplicationStartErrorCheck; +import com.yunzhupaas.config.ConfigValueUtil; +import com.yunzhupaas.util.ReflectionUtil; +import org.apache.ibatis.builder.MapperBuilderAssistant; +import org.springframework.cglib.proxy.Enhancer; +import org.springframework.cglib.proxy.MethodInterceptor; +import org.springframework.cglib.proxy.MethodProxy; +import org.springframework.util.ReflectionUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; + + +/** + * MyBatisPlus自定义方法实现 + * 给默认方法新增IgnoreLogic结尾的方法用于操作已逻辑删除的数据 + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2023/02/06 10:29 + */ +public class MyDefaultSqlInjector extends DefaultSqlInjector { + + private AbstractSqlInjector sqlInjector; + private ConfigValueUtil configValueUtil; + public static final String ignoreLogicPrefix = "Ilg"; + + //MP、MPJ的MP方法名集合 + public static final Set IGNOREMETHOD = new HashSet<>(); + + public MyDefaultSqlInjector(ConfigValueUtil configValueUtil) { + this(null, configValueUtil); + } + + public MyDefaultSqlInjector(ISqlInjector sqlInjector, ConfigValueUtil configValueUtil) { + this.configValueUtil = configValueUtil; + if (Objects.nonNull(sqlInjector) && sqlInjector instanceof AbstractSqlInjector) { + this.sqlInjector = (AbstractSqlInjector) sqlInjector; + } + } + + @Override + public List getMethodList(Class mapperClass, TableInfo tableInfo) { + List innerMethod; + if (Objects.nonNull(sqlInjector)) { + innerMethod = methodFilter(sqlInjector.getMethodList(mapperClass, tableInfo)); + } else { + innerMethod = methodFilter(super.getMethodList(mapperClass, tableInfo)); + } + //将内置列表加入排除列表 + return innerMethod; + } + + @Override + public void inspectInject(MapperBuilderAssistant builderAssistant, Class mapperClass) { + // 多线程初始化Mybatis接口 + ApplicationStartErrorCheck.getApplicationInitThreadPool().execute(() -> { + try { + super.inspectInject(builderAssistant, mapperClass); + } catch (Exception e) { + ApplicationStartErrorCheck.setStartError(); + throw e; + } + }); + } + + private List methodFilter(List list) { + if (!configValueUtil.isEnableLogicDelete()) { + return list; + } + for (int i = 0; i < list.size(); i++) { + AbstractMethod abstractMethod = list.get(i); + abstractMethod = enhancerMethod(abstractMethod); + list.set(i, abstractMethod); + } + return list; + } + + private AbstractMethod enhancerMethod(AbstractMethod method) { + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(method.getClass()); + enhancer.setCallback(new MethodInterceptor() { + @Override + public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { + handleAddMappedStatement(o, method, objects, methodProxy); + handleInject(o, method, objects, methodProxy); + return methodProxy.invokeSuper(o, objects); + } + }); + return (AbstractMethod) enhancer.create(new Class[]{String.class}, new Object[]{ReflectionUtil.getFieldValue(method, "methodName")}); + } + + public void handleAddMappedStatement(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws IllegalAccessException { + //记录自带的方法 + if (method.getName().equals("addMappedStatement") && objects.length > 1 && objects[1] instanceof String) { + String id = (String) objects[1]; + Field builderAssistantField = ReflectionUtils.findField(AbstractMethod.class, "builderAssistant"); + if (builderAssistantField != null) { + ReflectionUtils.makeAccessible(builderAssistantField); + MapperBuilderAssistant builderAssistant = (MapperBuilderAssistant) ReflectionUtils.getField(builderAssistantField, o); + String namespace = builderAssistant.getCurrentNamespace(); + String msId = builderAssistant.applyCurrentNamespace(id, false); + Field ignoreCacheField = ReflectionUtils.findField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_CACHE"); + if (ignoreCacheField != null) { + ReflectionUtils.makeAccessible(ignoreCacheField); + Map cache = (Map) ignoreCacheField.get(null); + //将自带方法加入排除列表 + IgnoreStrategy ignoreStrategy; + if (cache.containsKey(msId)) { + ignoreStrategy = cache.get(msId); + } else { + ignoreStrategy = IgnoreStrategy.builder().build(); + if (cache.containsKey(namespace)) { + BeanUtil.copyProperties(cache.get(namespace), ignoreStrategy); + } + cache.put(msId, ignoreStrategy); + } + Map others = ignoreStrategy.getOthers(); + if (others == null) { + others = new HashMap<>(); + ignoreStrategy.setOthers(others); + } + others.putIfAbsent(ignoreLogicPrefix, true); + } + } + } + } + + public void handleInject(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { + String packageName = o.getClass().getPackage().getName(); + //生成忽略逻辑删除的MP、MPJ的MP自带方法 + if (method.getName().equals("inject") && + (packageName.startsWith("com.baomidou.mybatisplus.core.injector.methods") || packageName.startsWith("com.github.yulichang.method.mp"))) { + TableInfo tableInfo = (TableInfo) objects[3]; + if (tableInfo.isWithLogicDelete()) { + String methodName = (String) ReflectionUtil.getFieldValue(o, "methodName"); + try { + ReflectionUtil.setFieldValue(tableInfo, "withLogicDelete", false); + ReflectionUtil.setFieldValue(o, "methodName", methodName + ignoreLogicPrefix); + methodProxy.invokeSuper(o, objects); + IGNOREMETHOD.add(methodName); + } finally { + ReflectionUtil.setFieldValue(o, "methodName", methodName); + ReflectionUtil.setFieldValue(tableInfo, "withLogicDelete", true); + } + + } + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDynamicDataSourceAutoRollbackInterceptor.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDynamicDataSourceAutoRollbackInterceptor.java new file mode 100644 index 0000000..20e127c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDynamicDataSourceAutoRollbackInterceptor.java @@ -0,0 +1,75 @@ +package com.yunzhupaas.database.plugins; + +import com.baomidou.dynamic.datasource.tx.TransactionContext; +import com.yunzhupaas.database.util.ConnUtil; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.plugin.Intercepts; +import org.apache.ibatis.plugin.Invocation; +import org.apache.ibatis.plugin.Signature; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.util.StringUtils; + +import java.sql.Connection; +import java.sql.Savepoint; +import java.util.Properties; + +/** + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/28 17:42 + */ +@Intercepts( + { + @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}), + } +) +public class MyDynamicDataSourceAutoRollbackInterceptor implements Interceptor { + + + @Override + public Object intercept(Invocation invocation) throws Throwable { + boolean hasTrans = TransactionSynchronizationManager.isActualTransactionActive(); + if (!hasTrans) { + hasTrans = StringUtils.hasText(TransactionContext.getXID()); + } + //Postgre Oracle Kingbase 连接报错后连接不可使用必须主动调用回滚才可以继续使用当前连接 + Savepoint savepoint = null; + Connection connection = null; + if(hasTrans){ + Executor executor = (Executor) invocation.getTarget(); + Connection conn = executor.getTransaction().getConnection(); + if(conn != null && !conn.getAutoCommit()){ + connection = ConnUtil.getRealConnection(conn); + try { + savepoint = connection.setSavepoint(); + }catch (Exception e){ } + } + } + try { + return invocation.proceed(); + } catch (Throwable e) { + if(connection != null) { + if (savepoint != null) { + connection.rollback(savepoint); + }else{ + connection.rollback(); + } + } + throw e; + } + } + + @Override + public Object plugin(Object target) { + return Interceptor.super.plugin(target); + } + + @Override + public void setProperties(Properties properties) { + Interceptor.super.setProperties(properties); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDynamicRoutingDataSource.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDynamicRoutingDataSource.java new file mode 100644 index 0000000..976970e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyDynamicRoutingDataSource.java @@ -0,0 +1,88 @@ +package com.yunzhupaas.database.plugins; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider; +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; +import com.baomidou.dynamic.datasource.tx.ConnectionFactory; +import com.baomidou.dynamic.datasource.tx.ConnectionProxy; +import com.baomidou.dynamic.datasource.tx.TransactionContext; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.database.util.ConnUtil; +import com.yunzhupaas.database.util.DynamicDataSourceUtil; +import com.yunzhupaas.database.util.TenantDataSourceUtil; +import com.yunzhupaas.exception.ConnectDatabaseException; +import com.yunzhupaas.util.TenantHolder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; + +/** + * 自定义动态数据源类 + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/8 16:06 + */ +@Slf4j +public class MyDynamicRoutingDataSource extends DynamicRoutingDataSource { + + public MyDynamicRoutingDataSource(List providers) { + super(providers); + } + + @Override + public Connection getConnection() throws SQLException { + String xid = TransactionContext.getXID(); + String ds = DynamicDataSourceContextHolder.peek(); + if(DynamicDataSourceUtil.isPrimaryDataSoure() && TenantHolder.isRemote()){ + //租户系统指定数据源, 如果当前源为主库 直接切换至指定源, 处理事务开启时Spring先行获取连接未切库问题 + ds = TenantDataSourceUtil.getTenantAssignDataSourceMasterKeyName(); + } + if (!StringUtils.hasText(xid)) { + return getMyDataSource(ds); + } else { + String tKey = !StringUtils.hasText(ds) ? "default" : ds; + ConnectionProxy connection = ConnectionFactory.getConnection(xid, tKey); + return connection == null ? getConnectionProxy(xid, tKey, getMyDataSource(ds)) : connection; + } + } + + private Connection getMyDataSource(String dsKey) throws SQLException { + try{ + DataSource dataSource = getDataSource(dsKey); + Connection connection = dataSource.getConnection(); + ConnUtil.switchConnectionSchema(connection); + return connection; + }catch (SQLException e){ + //移除运行中动态创建的数据源 + //避免第三方数据库关闭后一直尝试重新创建连接 + if (DynamicDataSourceUtil.containsLink(dsKey)) { + try { + //Druid数据源如果正在获取数据源 有概率连接创建线程无法停止 + //if(((ItemDataSource) dataSource).getRealDataSource() instanceof DruidDataSource){ + // ((DruidDataSource) ((ItemDataSource) dataSource).getRealDataSource()).setBreakAfterAcquireFailure(true); + //} + removeDataSource(dsKey); + } catch (Exception ee) { + log.error("关闭动态数据源【" + dsKey + "】失败", ee); + } + }else if(TenantHolder.isRemote()){ + //租户指定数据源 连接失败全部移除 + TenantDataSourceUtil.removeAllAssignDataSource(); + } + throw new ConnectDatabaseException(MsgCode.DB302.get(), e); + } + } + + + private Connection getConnectionProxy(String xid, String ds, Connection connection) { + ConnectionProxy connectionProxy = new ConnectionProxy(connection, ds); + ConnectionFactory.putConnection(xid, ds, connectionProxy); + return connectionProxy; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyLogicDeleteInnerInterceptor.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyLogicDeleteInnerInterceptor.java new file mode 100644 index 0000000..e735b6a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyLogicDeleteInnerInterceptor.java @@ -0,0 +1,340 @@ +package com.yunzhupaas.database.plugins; + +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import com.baomidou.mybatisplus.core.toolkit.*; +import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import com.baomidou.mybatisplus.extension.toolkit.PropertyMapper; +import com.yunzhupaas.database.util.IgnoreLogicDeleteHolder; +import com.yunzhupaas.util.StringUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.*; +import net.sf.jsqlparser.expression.operators.conditional.AndExpression; +import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +import net.sf.jsqlparser.expression.operators.relational.*; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.select.*; +import net.sf.jsqlparser.statement.update.Update; +import net.sf.jsqlparser.statement.update.UpdateSet; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 逻辑删除插件 + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/14 10:29 + */ +@Data +@Slf4j +public class MyLogicDeleteInnerInterceptor extends TenantLineInnerInterceptor implements InnerInterceptor { + + private LogicDeleteHandler logicDeleteHandler; + + private static List tableName = new ArrayList<>(); + + + public MyLogicDeleteInnerInterceptor() { + super.setTenantLineHandler(new TenantLineHandler() { + + @Override + public String getTenantIdColumn() { + return logicDeleteHandler.getLogicDeleteColumn(); + } + + @Override + public Expression getTenantId() { + return logicDeleteHandler.getNotDeletedValue(); + } + }); + } + + + @Override + public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { + //MybatisPlus自带方法不处理, 兼容Plus、PlusJoin 见MyDefaultSqlInjector + if (InterceptorIgnoreHelper.willIgnoreOthersByKey(ms.getId(), MyDefaultSqlInjector.ignoreLogicPrefix)) return; + //代码中临时标记忽略逻辑删除不处理 + if(IgnoreLogicDeleteHolder.isIgnoreLogicDelete()){ + return; + } + //方法名包含ignorelogic不过滤 + if (ms.getId().endsWith(MyDefaultSqlInjector.ignoreLogicPrefix)) return; + try { + if(boundSql.getSql().toLowerCase().contains(logicDeleteHandler.getLogicDeleteColumn().toLowerCase())){ + //包含逻辑删除字段不处理 + return; + } + PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); + mpBs.sql(parserSingle(mpBs.sql(), null)); + } catch (Exception e){ + //特殊语句解析失败 + if(log.isDebugEnabled()){ + log.debug("语句解析失败", e); + } + } + } + + @Override + public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { + PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); + //代码中临时标记忽略逻辑删除不处理 + if(IgnoreLogicDeleteHolder.isIgnoreLogicDelete()){ + return; + } + MappedStatement ms = mpSh.mappedStatement(); + //MybatisPlus自带方法不处理, 兼容Plus、PlusJoin 见MyDefaultSqlInjector + if (InterceptorIgnoreHelper.willIgnoreOthersByKey(ms.getId(), MyDefaultSqlInjector.ignoreLogicPrefix)) { + return; + } + //方法名包含ignorelogic不过滤 + if (ms.getId().endsWith(MyDefaultSqlInjector.ignoreLogicPrefix)) return; + SqlCommandType sct = ms.getSqlCommandType(); + if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { + if(mpSh.mPBoundSql().sql().toLowerCase().contains(logicDeleteHandler.getLogicDeleteColumn().toLowerCase())){ + //包含逻辑删除字段不处理 + return; + } + try { + PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); + mpBs.sql(parserMulti(mpBs.sql(), null)); + } catch (Exception e){ + //特殊语句解析失败 + if(log.isDebugEnabled()){ + log.debug("语句解析失败", e); + } + } + } + } + + @Override + protected String processParser(Statement statement, int index, String sql, Object obj) { + if (logger.isDebugEnabled()) { + logger.debug("SQL to parse, SQL: " + sql); + } + if (statement instanceof Insert) { + this.processInsert((Insert) statement, index, sql, obj); + } else if (statement instanceof Select) { + this.processSelect((Select) statement, index, sql, obj); + } else if (statement instanceof Update) { + this.processUpdate((Update) statement, index, sql, obj); + } else if (statement instanceof Delete) { + //把删除语句替换为修改语句 + statement = this.processDeleteToLogicDelete((Delete) statement, index, sql, obj); + } + sql = statement.toString(); + if (logger.isDebugEnabled()) { + logger.debug("parse the finished SQL: " + sql); + } + return sql; + } + + @Override + protected void processInsert(Insert insert, int index, String sql, Object obj) { + if (ignoreTable(insert.getTable().getName())) { + // 过滤退出执行 + return; + } + List columns = insert.getColumns(); + if (CollectionUtils.isEmpty(columns)) { + // 针对不给列名的insert 不处理 + return; + } + String logicDeleteColumn = logicDeleteHandler.getLogicDeleteColumn(); + if (logicDeleteHandler.ignoreInsert(columns, logicDeleteColumn)) { + // 针对已给出逻辑列的insert 不处理 + return; + } + columns.add(new Column(logicDeleteColumn)); + Expression notDeletedValue = logicDeleteHandler.getNotDeletedValue(); + // fixed gitee pulls/141 duplicate update + List duplicateUpdateColumns = insert.getDuplicateUpdateSets(); + if (CollectionUtils.isNotEmpty(duplicateUpdateColumns)) { + duplicateUpdateColumns.add(new UpdateSet(new Column(logicDeleteColumn), notDeletedValue)); + } + + Select select = insert.getSelect(); + if (select instanceof PlainSelect) { //fix github issue 4998 修复升级到4.5版本的问题 + this.processInsertSelect(select, (String) obj); + } else if (insert.getValues() != null) { + // fixed github pull/295 + Values values = insert.getValues(); + ExpressionList expressions = (ExpressionList) values.getExpressions(); + if (expressions instanceof ParenthesedExpressionList) { + expressions.addExpression(notDeletedValue); + } else { + if (CollectionUtils.isNotEmpty(expressions)) {//fix github issue 4998 jsqlparse 4.5 批量insert ItemsList不是MultiExpressionList 了,需要特殊处理 + int len = expressions.size(); + for (int i = 0; i < len; i++) { + Expression expression = expressions.get(i); + if (expression instanceof ParenthesedExpressionList) { + ((ParenthesedExpressionList) expression).addExpression(notDeletedValue); + } else { + expressions.add(notDeletedValue); + } + } + } else { + expressions.add(notDeletedValue); + } + } + } else { + throw ExceptionUtils.mpe("Failed to process multiple-table update, please exclude the tableName or statementId"); + } + } + + /** + * update 语句处理 + */ + @Override + protected void processUpdate(Update update, int index, String sql, Object obj) { + final Table table = update.getTable(); + if (ignoreTable(table.getName())) { + // 过滤退出执行 + return; + } + super.processUpdate(update, index, sql, obj); + } + + /** + * delete 语句处理 + */ + protected Statement processDeleteToLogicDelete(Delete delete, int index, String sql, Object obj) { + if (ignoreTable(delete.getTable().getName())) { + // 过滤退出执行 + return delete; + } + Update updateStatement = null; + try { + updateStatement = (Update) CCJSqlParserUtil.parse(logicDeleteHandler.getDeleteSql()); + } catch (JSQLParserException e) { + throw new RuntimeException(e); + } + updateStatement.setTable(delete.getTable()); + updateStatement.setWhere(delete.getWhere()); + return updateStatement; + } + + /** + * 处理条件 + */ + @Override + protected Expression builderExpression(Expression currentExpression, List tables, final String whereSegment) { + // 没有表需要处理直接返回 + if (CollectionUtils.isEmpty(tables)) { + return currentExpression; + } + // 过滤不处理的表 + tables = tables.stream() + .filter(x -> !ignoreTable(x.getName())) + .collect(Collectors.toList()); + + // 构造每张表的条件 + List expressions = tables.stream() + .map(item -> buildTableExpression(item, currentExpression, whereSegment)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + // 没有表需要处理直接返回 + if (CollectionUtils.isEmpty(expressions)) { + return currentExpression; + } + + // 注入的表达式 + Expression injectExpression = expressions.get(0); + // 如果有多表,则用 and 连接 + if (expressions.size() > 1) { + for (int i = 1; i < expressions.size(); i++) { + injectExpression = new AndExpression(injectExpression, expressions.get(i)); + } + } + + if (currentExpression == null) { + return injectExpression; + } + if (currentExpression instanceof OrExpression) { + return new AndExpression(new ParenthesedExpressionList<>(currentExpression), injectExpression); + } else { + return new AndExpression(currentExpression, injectExpression); + } + } + + protected Expression getLogicExpression(Expression column, Expression val){ + if(val.toString().equalsIgnoreCase("null")){ + IsNullExpression isNullExpression = new IsNullExpression(); + isNullExpression.setLeftExpression(column); + isNullExpression.setNot(false); + return isNullExpression; + }else { + return new EqualsTo(column, val); + } + } + + /** + * 逻辑字段别名设置 + *

F_DELETEMARK 或 tableAlias.F_DELETEMARK

+ * + * @param table 表对象 + * @return 字段 + */ + @Override + protected Column getAliasColumn(Table table) { + StringBuilder column = new StringBuilder(); + // 为了兼容隐式内连接,没有别名时条件就需要加上表名 + if (table.getAlias() != null) { + column.append(table.getAlias().getName()); + } else { + column.append(table.getName()); + } + column.append(StringPool.DOT).append(logicDeleteHandler.getLogicDeleteColumn()); + return new Column(column.toString()); + } + + private boolean ignoreTable(String table){ + if(StringUtil.isEmpty(table) || logicDeleteHandler.ignoreTable(table)){ + return true; + } + TableInfo tableInfo = TableInfoHelper.getTableInfo(table); + //无实体暂不执行, 非逻辑删除表不执行 + if(tableInfo != null){ + return !tableInfo.isWithLogicDelete(); + } + return true; + } + + @Override + public void setProperties(Properties properties) { + PropertyMapper.newInstance(properties).whenNotBlank("logicDeleteHandler", + ClassUtils::newInstance, this::setLogicDeleteHandler); + } + + @Override + public Expression buildTableExpression(Table table, Expression where, String whereSegment) { + if(ignoreTable(table.getName())){ + return null; + } + return getLogicExpression(this.getAliasColumn(table), logicDeleteHandler.getNotDeletedValue()); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyLogicServiceBeanPostProcessor.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyLogicServiceBeanPostProcessor.java new file mode 100644 index 0000000..de2a202 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyLogicServiceBeanPostProcessor.java @@ -0,0 +1,92 @@ +package com.yunzhupaas.database.plugins; + +import com.baomidou.mybatisplus.core.override.MybatisMapperProxy; +import com.yunzhupaas.base.mapper.SuperMapper; +import com.yunzhupaas.database.util.IgnoreLogicDeleteHolder; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.apache.ibatis.session.SqlSession; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.ReflectionUtils; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** + * 开启逻辑删除之后, 调用Mapper方法时, 若设置忽略逻辑删除强制替换调用的方法 + * 可调用mapper.setIgnoreLogicDelete service.setIgnoreLogicDelete 设置忽略标记 + * 调用mapper.clearIgnoreLogicDelete service.clearIgnoreLogicDelete 清除忽略标记 + * 例: + * mapper.setIgnoreLogicDelete(); + * mapper.list(); //调用list方法会动态替换为listIgnoreLogicDelete方法 + * mapper.clearIgnoreLogicDelete(); + * + * @see MyDefaultSqlInjector 生成Mapper实现类的非逻辑删除版本SQL代码 + * @see IgnoreLogicDeleteHolder 存储是否暂时忽略逻辑删除标记 + */ +@Configuration +@ConditionalOnProperty(prefix = "config", name = "EnableLogicDelete", havingValue = "true", matchIfMissing = false) +public class MyLogicServiceBeanPostProcessor implements BeanPostProcessor { + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + Object obj = BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName); + if(obj != null && SuperMapper.class.isAssignableFrom(obj.getClass())){ + ProxyFactory factory = new ProxyFactory(); + factory.setTarget(obj); + factory.addAdvice(new MethodInterceptor() { + @Nullable + @Override + public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable { + if(IgnoreLogicDeleteHolder.isIgnoreLogicDelete()) { + try { + Method invokeMethod = invocation.getMethod(); + // 非Object自带方法 且是MP、MPJ的自带方法 + if (!Object.class.equals(invokeMethod.getDeclaringClass()) && MyDefaultSqlInjector.IGNOREMETHOD.contains(invokeMethod.getName())) { + if (invocation.getThis() != null && Proxy.isProxyClass(invocation.getThis().getClass())) { + InvocationHandler proxyHandler = Proxy.getInvocationHandler(invocation.getThis()); + if(proxyHandler instanceof MybatisMapperProxy) { + //从MybatisMapperProxy中获取原Mapper接口 + Field mapperInterfaceField = ReflectionUtils.findField(proxyHandler.getClass(), "mapperInterface"); + Field sqlSessionField = ReflectionUtils.findField(proxyHandler.getClass(), "sqlSession"); + if (mapperInterfaceField != null && sqlSessionField != null) { + ReflectionUtils.makeAccessible(mapperInterfaceField); + ReflectionUtils.makeAccessible(sqlSessionField); + Class mapperInterface = (Class) ReflectionUtils.getField(mapperInterfaceField, proxyHandler); + SqlSession sqlSession = (SqlSession) ReflectionUtils.getField(sqlSessionField, proxyHandler); + if (mapperInterface != null && sqlSession != null) { + Method newInvokeMathod = ReflectionUtils.findMethod(mapperInterface, invocation.getMethod().getName() + MyDefaultSqlInjector.ignoreLogicPrefix, invokeMethod.getParameterTypes()); + if(newInvokeMathod != null){ + Field methodField = ReflectionUtils.findField(invocation.getClass(), "method"); + if (methodField != null) { + //直接替换Method Mybatis调用根据方法名称获取对应的SQL + ReflectionUtils.makeAccessible(methodField); + ReflectionUtils.setField(methodField, invocation, newInvokeMathod); + } + } + } + } + } + } + } + } catch (Exception e){ + e.printStackTrace(); + } + } + return invocation.proceed(); + } + }); + return factory.getProxy(); + } + return obj; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MySchemaInnerInterceptor.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MySchemaInnerInterceptor.java new file mode 100644 index 0000000..6be2322 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MySchemaInnerInterceptor.java @@ -0,0 +1,161 @@ +package com.yunzhupaas.database.plugins; + +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils; +import com.baomidou.mybatisplus.core.toolkit.PluginUtils; +import com.baomidou.mybatisplus.core.toolkit.TableNameParser; +import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.database.util.DataSourceUtil; +import com.yunzhupaas.database.util.DynamicDataSourceUtil; +import com.yunzhupaas.database.util.NotTenantPluginHolder; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.TenantHolder; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.springframework.beans.factory.annotation.Autowired; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Schema模式租户插件 + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/14 10:35 + */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Slf4j +public class MySchemaInnerInterceptor extends DynamicTableNameInnerInterceptor implements ITenantPlugin { + + private Runnable hook; + + public void setHook(Runnable hook) { + this.hook = hook; + } + + /** + * 表名处理器,是否处理表名的情况都在该处理器中自行判断 + */ + private TableNameHandler tableNameHandler; + @Autowired + private DataSourceUtil dataSourceUtil; + + @Override + public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { + if(TenantHolder.getLocalTenantCache() == null){ + printNoTenant(v -> log.warn("未获取到线程租户ID, 跳过切库, {}, {}, {}, {}", v.getUserId(), v.getUrl(), v.getToken(), v.getStack())); + //未设置租户信息不允许操作数据库 + throw new DataException(MsgCode.LOG113.get()); + } + //租户指定数据源不处理 + if (!TenantHolder.getLocalTenantCache().isSchema()) { + return; + } + if (NotTenantPluginHolder.isNotSwitch()) { + NotTenantPluginHolder.clearNotSwitchFlag(); + return; + } + //非主库不切库 + if(!DynamicDataSourceUtil.isPrimaryDataSoure()){ + return; + } + //不绑定数据源的接口不切库 + /*if(NotTenantPluginHolder.isNotSwitchAlways()){ + return; + }*/ + PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); + if (!InterceptorIgnoreHelper.willIgnoreDynamicTableName(ms.getId())) { + // 非忽略执行 + mpBs.sql(this.changeTable(mpBs.sql())); + } + } + + @Override + public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { + if(TenantHolder.getLocalTenantCache() == null){ + printNoTenant(v -> log.warn("未获取到线程租户ID, 跳过切库, {}, {}, {}, {}", v.getUserId(), v.getUrl(), v.getToken(), v.getStack())); + //未设置租户信息不允许操作数据库 + throw new DataException(MsgCode.LOG113.get()); + } + //租户指定数据源不处理 + if (!TenantHolder.getLocalTenantCache().isSchema()) { + return; + } + if (NotTenantPluginHolder.isNotSwitch()) { + NotTenantPluginHolder.clearNotSwitchFlag(); + return; + } + //非主库不切库 + if(!DynamicDataSourceUtil.isPrimaryDataSoure()){ + return; + } + //不绑定数据源的接口不切库 + /*if(NotTenantPluginHolder.isNotSwitchAlways()){ + return; + }*/ + PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); + MappedStatement ms = mpSh.mappedStatement(); + SqlCommandType sct = ms.getSqlCommandType(); + if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { + if (!InterceptorIgnoreHelper.willIgnoreDynamicTableName(ms.getId())) { + // 非忽略执行 + PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); + mpBs.sql(this.changeTable(mpBs.sql())); + + /* + //只有修改、新增、删除数据才切库 + //先保留代码看后续需求 + SQLStatement sqlStatement = SQLParserUtils.createSQLStatementParser(mpBs.sql(), DbTypeUtil.getDb(dataSourceUtil).getDruidDbType()).parseStatement(); + if (sqlStatement instanceof SQLSelectStatement + || sqlStatement instanceof SQLUpdateStatement + || sqlStatement instanceof SQLInsertStatement + || sqlStatement instanceof SQLDeleteStatement) { + mpBs.sql(this.changeTable(mpBs.sql())); + }*/ + } + } + } + + public String changeTable(String sql) { + ExceptionUtils.throwMpe(null == tableNameHandler, "Please implement TableNameHandler processing logic"); + TableNameParser parser = new TableNameParser(sql); + List names = new ArrayList<>(); + parser.accept(names::add); + StringBuilder builder = new StringBuilder(); + int last = 0; + for (TableNameParser.SqlToken name : names) { + int start = name.getStart(); + if (start != last) { + builder.append(sql, last, start); + builder.append(tableNameHandler.dynamicTableName(sql, name.getValue())); + } + last = name.getEnd(); + } + if (last != sql.length()) { + builder.append(sql.substring(last)); + } + if (hook != null) { + hook.run(); + } + return builder.toString(); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyTenantLineInnerInterceptor.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyTenantLineInnerInterceptor.java new file mode 100644 index 0000000..6b7f0c7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyTenantLineInnerInterceptor.java @@ -0,0 +1,159 @@ +package com.yunzhupaas.database.plugins; + +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.database.util.DynamicDataSourceUtil; +import com.yunzhupaas.database.util.NotTenantPluginHolder; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.TenantHolder; +import jodd.util.StringPool; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.select.*; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; + +/** + * Column模式租户插件 + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/14 10:29 + */ +@Slf4j +public class MyTenantLineInnerInterceptor extends TenantLineInnerInterceptor implements ITenantPlugin { + + @Override + public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { + if(TenantHolder.getLocalTenantCache() == null){ + printNoTenant(v -> log.warn("未获取到线程租户ID, 跳过切库, {}, {}, {}, {}", v.getUserId(), v.getUrl(), v.getToken(), v.getStack())); + //未设置租户信息不允许操作数据库 + throw new DataException(MsgCode.LOG113.get()); + } + //租户指定数据源不处理 + if (!TenantHolder.getLocalTenantCache().isColumn()) { + return; + } + if (NotTenantPluginHolder.isNotSwitch()) { + NotTenantPluginHolder.clearNotSwitchFlag(); + return; + } + //非主库不切库 + if(!DynamicDataSourceUtil.isPrimaryDataSoure()){ + return; + } + //不绑定数据源的接口不切库 + /*if(NotTenantPluginHolder.isNotSwitchAlways()){ + return; + }*/ + try { + super.beforeQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql); + } catch (Exception e){ + //特殊语句解析失败 + if(log.isDebugEnabled()){ + log.debug("语句解析失败", e); + } + } + } + + @Override + public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { + if(TenantHolder.getLocalTenantCache() == null){ + printNoTenant(v -> log.warn("未获取到线程租户ID, 跳过切库, {}, {}, {}, {}", v.getUserId(), v.getUrl(), v.getToken(), v.getStack())); + //未设置租户信息不允许操作数据库 + throw new DataException(MsgCode.LOG113.get()); + } + //租户指定数据源不处理 + if (!TenantHolder.getLocalTenantCache().isColumn()) { + return; + } + if (NotTenantPluginHolder.isNotSwitch()) { + NotTenantPluginHolder.clearNotSwitchFlag(); + return; + } + //非主库不切库 + if(!DynamicDataSourceUtil.isPrimaryDataSoure()){ + return; + } + //不绑定数据源的接口不切库 + /*if(NotTenantPluginHolder.isNotSwitchAlways()){ + return; + }*/ + try { + super.beforePrepare(sh, connection, transactionTimeout); + } catch (Exception e){ + //特殊语句解析失败 + if(log.isDebugEnabled()){ + log.debug("语句解析失败", e); + } + } + } + + @Override + protected Column getAliasColumn(Table table) { + return getAliasColumnWithFromItem(table); + } + + protected Column getAliasColumnWithFromItem(FromItem table) { + StringBuilder column = new StringBuilder(); + if (table.getAlias() != null) { + column.append(table.getAlias().getName()); + }else{ + if(table instanceof Table){ + column.append(((Table)table).getName()); + } + } + column.append(StringPool.DOT).append(super.getTenantLineHandler().getTenantIdColumn()); + return new Column(column.toString()); + } + + protected void appendSelectItem(List> selectItems, FromItem from) { + if (CollectionUtils.isEmpty(selectItems)) { + return; + } + if (selectItems.size() == 1) { + SelectItem item = selectItems.get(0); + Expression expression = item.getExpression(); + if (expression instanceof AllColumns) { + return; + } + } + // 改 + selectItems.add(new SelectItem<>(getAliasColumnWithFromItem(from))); + } + + + @Override + protected void processInsertSelect(Select selectBody, final String whereSegment) { + if (selectBody instanceof PlainSelect) { + PlainSelect plainSelect = (PlainSelect)selectBody; + FromItem fromItem = plainSelect.getFromItem(); + if (fromItem instanceof Table) { + this.processPlainSelect(plainSelect, whereSegment); + // 改 + this.appendSelectItem(plainSelect.getSelectItems(), fromItem); + } else if (fromItem instanceof Select) { + Select subSelect = (Select)fromItem; + // 改 + this.appendSelectItem(plainSelect.getSelectItems(), fromItem); + this.processInsertSelect(subSelect, whereSegment); + } + } else if (selectBody instanceof ParenthesedSelect) { + ParenthesedSelect parenthesedSelect = (ParenthesedSelect)selectBody; + this.processInsertSelect(parenthesedSelect.getSelect(), whereSegment); + } + + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyTenantMasterSlaveAutoRoutingPlugin.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyTenantMasterSlaveAutoRoutingPlugin.java new file mode 100644 index 0000000..e4d7943 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/MyTenantMasterSlaveAutoRoutingPlugin.java @@ -0,0 +1,76 @@ +package com.yunzhupaas.database.plugins; + +import cn.hutool.core.text.StrPool; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.enums.DdConstants; +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; +import com.baomidou.dynamic.datasource.tx.TransactionContext; +import com.yunzhupaas.database.util.DynamicDataSourceUtil; +import com.yunzhupaas.util.TenantHolder; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.cache.CacheKey; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.plugin.*; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.util.StringUtils; + +import javax.sql.DataSource; +import java.util.Optional; + +/** + * 租户连接模式读写分离 + * + * @author TaoYu + * @since 2.5.1 + */ +@Intercepts({ + @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), + @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), + @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) +@Slf4j +public class MyTenantMasterSlaveAutoRoutingPlugin implements Interceptor { + + protected DynamicRoutingDataSource dynamicDataSource; + + public MyTenantMasterSlaveAutoRoutingPlugin(DataSource dataSource){ + this.dynamicDataSource = (DynamicRoutingDataSource) dataSource; + } + + @Override + public Object intercept(Invocation invocation) throws Throwable { + if (TenantHolder.getLocalTenantCache() == null + || !TenantHolder.getLocalTenantCache().isRemote() + || !DynamicDataSourceUtil.isPrimaryDataSoure()) { + return invocation.proceed(); + } + Object[] args = invocation.getArgs(); + MappedStatement ms = (MappedStatement) args[0]; + String pushedDataSource = null; + try { + String tenantId = Optional.ofNullable(TenantHolder.getLocalTenantCache().getEnCode()).orElse(""); + String masterKey = tenantId + StrPool.DASHED +DdConstants.MASTER; + String slaveKey = tenantId + StrPool.DASHED +DdConstants.SLAVE; + // 存在事务只使用主库 + boolean hasTrans = TransactionSynchronizationManager.isActualTransactionActive(); + if (!hasTrans) { + hasTrans = StringUtils.hasText(TransactionContext.getXID()); + } + // 判断切库 + String dataSource = SqlCommandType.SELECT == ms.getSqlCommandType() ? slaveKey :masterKey; + if (hasTrans || !dynamicDataSource.getGroupDataSources().containsKey(dataSource)) { + dataSource = masterKey; + } + pushedDataSource = DynamicDataSourceContextHolder.push(dataSource); + return invocation.proceed(); + } finally { + if (pushedDataSource != null) { + DynamicDataSourceContextHolder.poll(); + } + } + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/ResultSetInterceptor.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/ResultSetInterceptor.java new file mode 100644 index 0000000..87cdcdd --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/plugins/ResultSetInterceptor.java @@ -0,0 +1,56 @@ +package com.yunzhupaas.database.plugins; + +import com.yunzhupaas.database.util.ResetSetHolder; +import org.apache.ibatis.executor.resultset.ResultSetHandler; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.plugin.Intercepts; +import org.apache.ibatis.plugin.Invocation; +import org.apache.ibatis.plugin.Signature; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +/** + * Mybatis ResultSet拦截器 + * @see ResetSetHolder + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/14 16:29 + */ +@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})}) +public class ResultSetInterceptor implements Interceptor { + + + @Override + public Object intercept(Invocation invocation) throws Throwable { + Object[] args = invocation.getArgs(); + Statement statement = (Statement) args[0]; + ResultSet rs = getFirstResultSet(statement); + if (rs != null) { + ResetSetHolder.setResultSet(rs); + } + Object result; + try{ + result = invocation.proceed(); + }finally{ + ResetSetHolder.clear(); + } + return result; + } + + + private ResultSet getFirstResultSet(Statement stmt) throws SQLException { + ResultSet rs = stmt.getResultSet(); + while (rs == null) { + if (stmt.getMoreResults()) { + rs = stmt.getResultSet(); + } else if (stmt.getUpdateCount() == -1) { + break; + } + } + return rs; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/DbBase.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/DbBase.java new file mode 100644 index 0000000..ff5ad1b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/DbBase.java @@ -0,0 +1,210 @@ +package com.yunzhupaas.database.source; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler; +import com.yunzhupaas.database.constant.DbConst; +import com.yunzhupaas.database.datatype.db.interfaces.DtInterface; +import com.yunzhupaas.database.datatype.model.DtModelDTO; +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.model.dbfield.DbFieldModel; +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.model.interfaces.DbSourceOrDbLink; +import com.yunzhupaas.database.source.impl.*; +import com.yunzhupaas.database.sql.model.DbStruct; +import com.yunzhupaas.database.util.DbTypeUtil; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.TenantHolder; +import lombok.Data; + +import java.sql.ResultSet; +import java.util.Collections; +import java.util.List; + +/** + * 数据库基础模型表 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/6/21 + */ +@Data +public abstract class DbBase { + + /** + * YUNZHUPAAS数据库编码标准 + */ + public static final String MYSQL = "MySQL"; + public static final String DM = "DM"; + public static final String KINGBASE_ES = "KingbaseES"; + public static final String ORACLE = "Oracle"; + public static final String POSTGRE_SQL = "PostgreSQL"; + public static final String SQL_SERVER = "SQLServer"; + public static final String DORIS = "Doris"; + + public static final DbBase[] DB_BASES = { new DbMySQL(), new DbSQLServer(), new DbDM(), + new DbOracle(), new DbKingbase(), new DbPostgre(), new DbDoris() }; + + public static final String[] DB_ENCODES = { MYSQL, ORACLE, SQL_SERVER, DM, KINGBASE_ES, POSTGRE_SQL, DORIS }; + + /** + * YUNZHUPAAS数据库编码 + */ + protected String yunzhupaasDbEncode; + /** + * MybatisPlus数据库编码 + */ + protected DbType mpDbType; + /** + * DruidDbType + */ + protected com.alibaba.druid.DbType druidDbType; + /** + * url里数据库标识 + */ + protected String connUrlEncode; + /** + * 数据库驱动 + */ + protected String driver; + /** + * 默认端口 + */ + protected String defaultPort; + /** + * 管理员用户名 + */ + protected String dbaUsername; + /** + * 默认预备url + */ + protected String defaultPrepareUrl; + + /** + * oracle连接扩展参数 + */ + public String oracleParam; + + /** + * 无参构造 + */ + protected DbBase() { + init(); + } + + /** + * 初始赋值 + */ + protected abstract void init(); + + /** + * 数据库对象初始化 + * 指定子类被创建时,需要提供的参数 + */ + protected void setInstance(String yunzhupaasDbEncode, DbType mpDbType, com.alibaba.druid.DbType druidDbType, + String defaultPort, String dbaUsername, String connUrlEncode, + String driver, String defaultPrepareUrl) { + // 绑定:YUNZHUPAAS数据库编码 + this.yunzhupaasDbEncode = yunzhupaasDbEncode; + // 绑定:MybatisPlus数据库编码 + this.mpDbType = mpDbType; + this.druidDbType = druidDbType; + // 绑定:Url数据库标识 + this.connUrlEncode = connUrlEncode; + this.driver = driver; + this.defaultPrepareUrl = defaultPrepareUrl; + // 默认端口 + this.defaultPort = defaultPort; + this.dbaUsername = dbaUsername; + } + + public static List dynamicAllTableName = Collections.emptyList(); + + public DbBase[] DB_BASES() { + return null; + } + + /** + * 获取最终动态表名, 处理是否动态表名 + * + * @return + */ + public TableNameHandler getDynamicTableNameHandler() { + return (sql, tableName) -> { + // 是否指定数据源, 且在初始库中包含的表 + if (StringUtil.isNotEmpty(TenantHolder.getDatasourceName())) { + return getDynamicTableName(tableName); + } + return tableName; + }; + } + + /** + * 获取动态组合表名 + * + * @param tableName + * @return + */ + protected String getDynamicTableName(String tableName) { + return TenantHolder.getDatasourceName() + "." + tableName; + } + + /** + * 不同库间设置字段信息 + * + * @param model 字段模型 + * @param result 结果集 + * @return 表字段模型 + * @throws DataException ignore + */ + public void setPartFieldModel(DbFieldModel model, ResultSet result) throws Exception { + model.setDtModelDTO(new DtModelDTO( + DtInterface.newInstanceByDt(model.getDataType(), this.getYunzhupaasDbEncode()), + result.getLong(DbAliasEnum.CHAR_LENGTH.getAlias(yunzhupaasDbEncode)), + result.getInt(DbAliasEnum.NUM_PRECISION.getAlias(yunzhupaasDbEncode)), + result.getInt(DbAliasEnum.NUM_SCALE.getAlias(yunzhupaasDbEncode)))); + } + + /** + * 获取数据库连接Url 关键参数: + * 1、地址 + * 2、端口 + * 3、数据库名 + * 4、模式 (参数:?currentSchema = schema) + * 5、jdbc-url自定义参数 + * + * 此方法对DbTypeUtil与内部开放,对外关闭。外部调用url,用DbTypeUtil.getUrl()方法 + * + * @return String 连接 + */ + protected String getConnUrl(String prepareUrl, String host, Integer port, DbStruct struct) { + // 配置文件是否存在自定义数据连接url + prepareUrl = StringUtil.isNotEmpty(prepareUrl) ? prepareUrl : defaultPrepareUrl; + // 当地址为空,用本地回环地址 + prepareUrl = prepareUrl.replace(DbConst.HOST, StringUtil.isNotEmpty(host) ? host : "127.0.0.1"); + // 当端口为空,用数据库一般默认端口 + prepareUrl = prepareUrl.replace(DbConst.PORT, port != null ? port.toString() : defaultPort); + return prepareUrl; + } + + /* + * 提供内部封装方法所独有的方法调用 + * 保持全局只有一处显性getUrl,getConn的方法(即在ConnUtil里)===================================== + * = + */ + + public static class BaseCommon { + public static String getDbBaseConnUrl(DbSourceOrDbLink dbSourceOrDbLink, String dbName) { + DbLinkEntity dsd = dbSourceOrDbLink.init(dbName); + try { + return DbTypeUtil.getDb(dbSourceOrDbLink).getConnUrl(dsd.getPrepareUrl(), dsd.getHost(), dsd.getPort(), + dsd.getDbStruct()); + } catch (DataException e) { + e.printStackTrace(); + } + return ""; + } + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/DbModel.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/DbModel.java new file mode 100644 index 0000000..879f288 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/DbModel.java @@ -0,0 +1,65 @@ +package com.yunzhupaas.database.source; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/21 + */ +@Data +public class DbModel { + + public DbModel(Connection connection){ + try { + //从conn中获取数据库的元数据 + DatabaseMetaData databaseMetaData = connection.getMetaData(); + /*============库信息===========*/ + //连接的库名目录 + this.catalog = connection.getCatalog(); + //数据库类型 MYSQL ORACLE + this.jdbcDbType = databaseMetaData.getDatabaseProductName(); + //数据库版本号 8.0.15 + this.version = databaseMetaData.getDatabaseProductVersion(); + //数据库大版本 8 + this.majorVersion = databaseMetaData.getDatabaseMajorVersion(); + //jdbc连接的url + this.url = databaseMetaData.getURL(); + }catch (Exception e){ + e.printStackTrace(); + } + } + + /** + * 数据库目录 + */ + private String catalog; + + /** + * jdbc数据库类型 + */ + private String jdbcDbType; + + /** + * 数据库版本号 例:8.0.15 + */ + private String version; + + /** + * 数据库大版本 例:8 + */ + private Integer majorVersion; + + /** + * 数据库连接 + */ + private String url; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbDM.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbDM.java new file mode 100644 index 0000000..5c49ec7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbDM.java @@ -0,0 +1,60 @@ +package com.yunzhupaas.database.source.impl; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.yunzhupaas.database.constant.DbConst; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.model.DbStruct; + +/** + * 达梦模型 + * + * @author 云筑产品开发平台组 YY + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/06 + */ +public class DbDM extends DbBase { + + @Override + protected void init() { + setInstance( + DM, + DbType.DM, + com.alibaba.druid.DbType.dm, + "5236", + "SYSDBA", + "dm", + "dm.jdbc.driver.DmDriver", + "jdbc:dm://{host}:{port}/{schema}"); + } + + @Override + protected String getConnUrl(String prepareUrl, String host, Integer port, DbStruct struct){ + prepareUrl = super.getConnUrl(prepareUrl, host, port, null); + return prepareUrl.replace(DbConst.DB_SCHEMA, struct.getDmDbSchema()); + } + +// public static void setDmTableModel(DbConnDTO connDTO, List tableModelList) { +// //达梦特殊方法 +// try { +// @Cleanup Connection dmConn = connDTO.getConn(); +// tableModelList.forEach(tm -> { +// try { +// Integer sum = DbDM.getSum(dmConn, tm.getTable()); +// tm.setSum(sum); +// } catch (DataException e) { +// e.printStackTrace(); +// } +// }); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } +// +// private static Integer getSum(Connection connection, String table) throws DataException { +// String sql = "SELECT COUNT(*) as F_SUM FROM " + table; +// return JdbcUtil.queryOneInt(connection, sql, "F_SUM"); +// } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbDoris.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbDoris.java new file mode 100644 index 0000000..8b1894f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbDoris.java @@ -0,0 +1,54 @@ +package com.yunzhupaas.database.source.impl; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.yunzhupaas.database.constant.DbConst; +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.model.dbfield.DbFieldModel; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.model.DbStruct; + +import java.sql.ResultSet; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version v3.4.5 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-12-08 + */ +public class DbDoris extends DbBase { + + @Override + protected void init() { + setInstance( + DORIS, + DbType.MYSQL, + com.alibaba.druid.DbType.mysql, + "9030", + "root", + "mysql", + "com.mysql.cj.jdbc.Driver", + "jdbc:mysql://{host}:{port}/{dbname}?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false" + // connUrl = + // "jdbc:mysql://{host}:{port}/{dbname}?useUnicode=true&autoReconnect=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8"; + ); + } + + @Override + public String getConnUrl(String prepareUrl, String host, Integer port, DbStruct struct) { + prepareUrl = super.getConnUrl(prepareUrl, host, port, null); + return prepareUrl.replace(DbConst.DB_NAME, struct.getMysqlDbName()); + } + + @Override + public void setPartFieldModel(DbFieldModel model, ResultSet result) throws Exception { + long charLength = result.getLong(DbAliasEnum.CHAR_LENGTH.getAlias(this.getYunzhupaasDbEncode())); + // Doris 长文本格式为String,但Jdbc查出的数据类型为:varchar & charLength = 2147483643 + if (model.getDataType().equalsIgnoreCase("varchar") && charLength == 2147483643) { + model.setDataType("text"); + } + super.setPartFieldModel(model, result); + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbKingbase.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbKingbase.java new file mode 100644 index 0000000..0374e13 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbKingbase.java @@ -0,0 +1,57 @@ +package com.yunzhupaas.database.source.impl; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.yunzhupaas.database.constant.DbConst; +import com.yunzhupaas.database.model.dbfield.DbFieldModel; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.model.DbStruct; +import com.yunzhupaas.util.StringUtil; + +import java.sql.ResultSet; + +/** + * 金仓模型 + * + * @author 云筑产品开发平台组 YY + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/06 + */ +public class DbKingbase extends DbBase { + + public static String DEF_SCHEMA = "public"; + + @Override + protected void init() { + setInstance( + KINGBASE_ES, + DbType.KINGBASE_ES, + com.alibaba.druid.DbType.kingbase, + "54321", + "system", + "kingbase8", + "com.kingbase8.Driver", + "jdbc:kingbase8://{host}:{port}/{dbname}?currentSchema={schema}"); + } + + @Override + public String getConnUrl(String prepareUrl, String host, Integer port, DbStruct struct) { + prepareUrl = super.getConnUrl(prepareUrl, host, port, null); + return prepareUrl.replace(DbConst.DB_NAME, struct.getKingBaseDbName()).replace(DbConst.DB_SCHEMA, struct.getKingBaseDbSchema()); + } + + @Override + public void setPartFieldModel(DbFieldModel model, ResultSet result) throws Exception { + new DbPostgre().setPartFieldModel(model, result); + } + + private String getCheckSchema(String schema){ + if(StringUtil.isEmpty(schema)){ + // 默认public模式 + schema = DEF_SCHEMA; + } + return schema; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbMySQL.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbMySQL.java new file mode 100644 index 0000000..6b1cced --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbMySQL.java @@ -0,0 +1,40 @@ +package com.yunzhupaas.database.source.impl; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.yunzhupaas.database.constant.DbConst; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.model.DbStruct; + +/** + * MySQL模型 + * + * @author 云筑产品开发平台组 YY + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/06 + */ +public class DbMySQL extends DbBase { + + @Override + protected void init(){ + setInstance( + MYSQL, + DbType.MYSQL, + com.alibaba.druid.DbType.mysql, + "3306", + "root", + "mysql", + "com.mysql.cj.jdbc.Driver", + "jdbc:mysql://{host}:{port}/{dbname}?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true" + //connUrl = "jdbc:mysql://{host}:{port}/{dbname}?useUnicode=true&autoReconnect=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8"; + ); + } + + @Override + public String getConnUrl(String prepareUrl, String host, Integer port, DbStruct struct) { + prepareUrl = super.getConnUrl(prepareUrl, host, port, null); + return prepareUrl.replace(DbConst.DB_NAME, struct.getMysqlDbName()); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbOracle.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbOracle.java new file mode 100644 index 0000000..c4b58e8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbOracle.java @@ -0,0 +1,156 @@ +package com.yunzhupaas.database.source.impl; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.yunzhupaas.database.constant.DbConst; +import com.yunzhupaas.database.model.dbfield.DbFieldModel; +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.model.DbStruct; +import com.yunzhupaas.database.util.ConnUtil; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.JsonUtil; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.TenantHolder; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.util.Map; +import java.util.Properties; + +/** + * Oracle模型 + * + * @author 云筑产品开发平台组 YY + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/06 + */ +public class DbOracle extends DbBase { + + /*================Oracle4种数据库连接url=================*/ + /** + * SID + * 或:jdbc:oracle:thin:@{host}:{port}/{SID} + */ + private static final String SID_URL = "jdbc:oracle:thin:@{host}:{port}:{schema}"; + private static final String SID_SIGN = "SID"; + /** + * SERVICE:服务名 + */ + private static final String SERVICE_URL = "jdbc:oracle:thin:@//{host}:{port}/{schema}"; + private static final String SERVICE_SIGN = "SERVICE"; + /** + * SCHEMA:模式 + */ + private static final String SCHEMA_URL = + "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST={host})(PORT={port})))(CONNECT_DATA=(SERVICE_NAME={schema})))"; + private static final String SCHEMA_SIGN = "SCHEMA"; + /** + * TNS + */ + private static final String TNS_URL = "jdbc:oracle:thin:@{schema}"; + private static final String TNS_SIGN = "TNS"; + + public static final String ORACLE_SERVICE = "oracleService"; + /** + * 连接扩展参数 + */ + public static final String ORACLE_LINK_TYPE = "oracleLinkType"; + public static final String ORACLE_ROLE = "oracleRole"; + + @Override + protected void init() { + setInstance( + ORACLE, + DbType.ORACLE, + com.alibaba.druid.DbType.oracle, + "1521", + "sys", + "oracle", + "oracle.jdbc.OracleDriver", + ""); + } + + @Override + public String getConnUrl(String prepareUrl, String host, Integer port, DbStruct struct) { + String schema = struct.getOracleDbSchema(); + if(StringUtil.isNotEmpty(struct.getOracleParam()) && StringUtil.isEmpty(prepareUrl)) { + Map oracleParamMap = JsonUtil.stringToMap(struct.getOracleParam()); + if (oracleParamMap.size() > 0) { + schema = oracleParamMap.get(DbOracle.ORACLE_SERVICE).toString(); + String urlType = oracleParamMap.get(DbOracle.ORACLE_LINK_TYPE).toString(); + switch (urlType) { + case SID_SIGN: + prepareUrl = SID_URL; + break; + case SERVICE_SIGN: + prepareUrl = SERVICE_URL; + break; + case SCHEMA_SIGN: + prepareUrl = SCHEMA_URL; + break; + case TNS_SIGN: + prepareUrl = TNS_URL; + break; + default: + // throw new DataException("Oracle连接类型指定失败"); + break; + } + } + } + if(StringUtil.isEmpty(prepareUrl)){ + prepareUrl = SID_URL; + } + return super.getConnUrl(prepareUrl, host, port, null).replace(DbConst.DB_SCHEMA, schema); + } + + @Override + protected String getDynamicTableName(String tableName) { + return TenantHolder.getDatasourceName().toUpperCase()+"."+tableName; + } + + public void setPartFieldModel(DbFieldModel model, ResultSet result) throws Exception{ + if(model.getDataType().toUpperCase().contains("TIMESTAMP")){ + model.setDataType("TIMESTAMP"); + } + super.setPartFieldModel(model, result); + } + + /** + * Oracle特殊添加数据连接方式 + */ + public Connection getOracleConn(DbLinkEntity dsd, String url) throws DataException { + String logonUser = ""; + if(StringUtil.isNotEmpty(dsd.getOracleParam())){ + Map oracleParamMap = JsonUtil.stringToMap(dsd.getOracleParam()); + if(oracleParamMap.size() > 0){ + logonUser = oracleParamMap.get(DbOracle.ORACLE_ROLE).toString(); + } + } + return createOracleConn(driver, logonUser, dsd.getUserName(), dsd.getPassword(), url); + } + + private static Connection createOracleConn(String driver, String logonUser, String userName, String password, String url) throws DataException { + //Oracle登录角色设置(Default,SYSDBA,SYSOPER) + Properties conProps = DbOracle.setConnProp(logonUser, userName, password); + return ConnUtil.ConnCommon.createConnByProp(driver, conProps.getProperty("user"), password, url, conProps); + } + + public static Properties setConnProp(String logonUser, String userName, String password){ + Properties conProps = new Properties(); + // 使用角色登录:userName + :@{角色} + if(!logonUser.isEmpty()){ + //defaultRowPrefetch:从服务器预取的默认行数(默认值为“10”) String (containing integer value) + conProps.put("defaultRowPrefetch", "15"); + /* 这里有一个风险:由于客户userName中含有一个或多个:@导致连接失败 */ + //internal_logon:允许您作为sys登录的权限,如sysdba或sysoper + conProps.put("internal_logon", logonUser); + conProps.put("user", userName); + } + conProps.put("user", userName); + conProps.setProperty("password", password); + return conProps; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbPostgre.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbPostgre.java new file mode 100644 index 0000000..6d1d8a7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbPostgre.java @@ -0,0 +1,82 @@ +package com.yunzhupaas.database.source.impl; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.yunzhupaas.database.constant.DbAliasConst; +import com.yunzhupaas.database.constant.DbConst; +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.model.dbfield.DbFieldModel; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.model.DbStruct; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.TenantHolder; + +import java.sql.ResultSet; +import java.util.regex.Pattern; + +/** + * PostgreSQL模型 + * + * @author 云筑产品开发平台组 YY + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/06 + */ +public class DbPostgre extends DbBase { + + public static String DEF_SCHEMA = "public"; + + @Override + protected void init() { + setInstance( + POSTGRE_SQL, + DbType.POSTGRE_SQL, + com.alibaba.druid.DbType.postgresql, + "5432", + "postgres", + "postgresql", + "org.postgresql.Driver", + "jdbc:postgresql://{host}:{port}/{dbname}"); + } + + @Override + public String getConnUrl(String prepareUrl, String host, Integer port, DbStruct struct) { + prepareUrl = super.getConnUrl(prepareUrl, host, port, null); + return prepareUrl.replace(DbConst.DB_NAME, struct.getPostGreDbName()).replace(DbConst.DB_SCHEMA, + struct.getPostGreDbSchema()); + } + + @Override + protected String getDynamicTableName(String tableName) { + return TenantHolder.getDatasourceName().toLowerCase() + "." + tableName; + } + + @Override + public void setPartFieldModel(DbFieldModel model, ResultSet result) throws Exception { + String nullSignStr = result.getString(DbAliasEnum.ALLOW_NULL.getAlias(this.getYunzhupaasDbEncode())); + model.setNullSign(DbAliasConst.ALLOW_NULL.getSign(nullSignStr.equals("YES") ? 1 : 0)); + super.setPartFieldModel(model, result); + } + + private String getCheckSchema(String schema) { + if (StringUtil.isEmpty(schema)) { + // 默认public模式 + schema = DEF_SCHEMA; + } + return schema; + } + + /** + * 表存在大写与小写,导致大小写敏感,需要双引号 + * + * @param originTable 原始表名 + * @return 表名 + */ + public static String getTable(String originTable) { + if (Pattern.compile("[A-Z]").matcher(originTable).find()) { + return "\"" + originTable + "\""; + } else { + return originTable; + } + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbSQLServer.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbSQLServer.java new file mode 100644 index 0000000..c7b3eee --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/source/impl/DbSQLServer.java @@ -0,0 +1,50 @@ +package com.yunzhupaas.database.source.impl; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.yunzhupaas.database.constant.DbConst; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.model.DbStruct; +import com.yunzhupaas.util.TenantHolder; + +/** + * SQLServer模型 + * + * @author 云筑产品开发平台组 YY + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/06 + */ +public class DbSQLServer extends DbBase { + + /** + * 驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。 + * 错误:“sun.security.validator.ValidatorException: PKIX path building failed + * + * 可以尝试连接:jdbc:sqlserver://{host}:{port};databaseName={dbname};encrypt=true;trustServerCertificate=true + */ + @Override + protected void init() { + setInstance( + SQL_SERVER, + DbType.SQL_SERVER, + com.alibaba.druid.DbType.sqlserver, + "1433", + "sa", + "sqlserver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "jdbc:sqlserver://{host}:{port};databaseName={dbname};trustServerCertificate=true"); + } + + @Override + public String getConnUrl(String prepareUrl, String host, Integer port, DbStruct struct) { + prepareUrl = super.getConnUrl(prepareUrl, host, port, null); + return prepareUrl.replace(DbConst.DB_NAME, struct.getSqlServerDbName()).replace(DbConst.DB_SCHEMA, struct.getSqlServerDbSchema()); + } + + @Override + protected String getDynamicTableName(String tableName) { + return TenantHolder.getDatasourceName()+".dbo." + tableName; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/SqlBase.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/SqlBase.java new file mode 100644 index 0000000..0527d66 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/SqlBase.java @@ -0,0 +1,61 @@ +package com.yunzhupaas.database.sql; + +import com.yunzhupaas.database.model.dbfield.JdbcColumnModel; +import com.yunzhupaas.database.model.interfaces.DbSourceOrDbLink; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.source.impl.DbMySQL; +import com.yunzhupaas.database.util.DbTypeUtil; +import com.yunzhupaas.exception.DataException; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * SQL语句模板基类 + * 用以一些SQL语句不同库的特殊处理 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/6 + */ +@Data +public abstract class SqlBase { + + /** + * 数据基类 + */ + protected String dbEncode; + + + + + protected DbBase getDb(){ + try { + return DbTypeUtil.getEncodeDb(this.dbEncode); + } catch (DataException e) { + e.printStackTrace(); + } + return new DbMySQL(); + } + + /** + * 初始结构参数 + */ + public abstract void initStructParams(String table, DbSourceOrDbLink dbSourceOrDbLink); + + + /** + * 批量添加数据 + */ + // TODO 其余几个数据还没有添加方法 + public String batchInsertSql(List> dataList, String table) { + return ""; + } + + + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlDMEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlDMEnum.java new file mode 100644 index 0000000..bada512 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlDMEnum.java @@ -0,0 +1,257 @@ +package com.yunzhupaas.database.sql.enums; + +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.enums.ParamEnum; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.enums.base.SqlFrameBase; +import com.yunzhupaas.database.sql.model.DbStruct; +import com.yunzhupaas.util.StringUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; +import java.util.Map; + +/** + * 达梦 SQL语句模板 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/17 + */ +@Getter +@AllArgsConstructor +public enum SqlDMEnum implements SqlFrameBase{ + + /* =============================== 系统语句 ==================================== */ + FIELDS( + "SELECT \n" + + "\tA.COLUMN_NAME AS " + DbAliasEnum.FIELD.getAlias() + ",\n" + + "\tA.DATA_TYPE AS " + DbAliasEnum.DATA_TYPE.getAlias() + ",\n" + + "\tA.DATA_LENGTH AS " + DbAliasEnum.CHAR_LENGTH.getAlias() + ",\n" + + "\tA.DATA_PRECISION AS " + DbAliasEnum.NUM_PRECISION.getAlias() + ",\n" + + "\tA.DATA_SCALE AS " + DbAliasEnum.NUM_SCALE.getAlias() + ",\n" + + "\tCASE WHEN E.CONSTRAINT_TYPE IS NOT NULL THEN '1' ELSE '0' END AS " + DbAliasEnum.PRIMARY_KEY.getAlias() + ",\n" + + "\tCASE A.NULLABLE WHEN 'N' THEN '0' ELSE '1' END AS " + DbAliasEnum.ALLOW_NULL.getAlias() + ",\n" + + "\tB.COMMENTS AS " + DbAliasEnum.FIELD_COMMENT.getAlias() + ",\n" + + "\tH.IS_AUTO AS " + DbAliasEnum.AUTO_INCREMENT.getAlias() + "\n" + + "FROM \n" + + "\tALL_TAB_COLUMNS A -- 表&字段 OWNER、TABLE_NAME、COLUMN_NAME_\t\n" + + "LEFT JOIN \n" + + "\tALL_COL_COMMENTS B -- 字段注释 TABLE_NAME、COLUMN_NAME\n" + + "ON \n" + + "\tA.OWNER = B.SCHEMA_NAME AND A.TABLE_NAME = B.TABLE_NAME AND A.COLUMN_NAME = B.COLUMN_NAME \n" + + "LEFT JOIN \n" + + "\t(\n" + + "\t\tSELECT \n" + + "\t\t\tC.OWNER, C.TABLE_NAME, C.COLUMN_NAME, D.CONSTRAINT_TYPE \n" + + "\t\tFROM \n" + + "\t\t\tALL_CONS_COLUMNS C\n" + + "\t\tLEFT JOIN \n" + + "\t\t\tALL_CONSTRAINTS D \n" + + "\t\tON \n" + + "\t\t\tC.CONSTRAINT_NAME = D.CONSTRAINT_NAME AND D.CONSTRAINT_TYPE = 'P'\n" + + "\t\tWHERE\n" + + "\t\t\tC.OWNER = " + ParamEnum.DB_NAME.getParamSign() + "\n" + + "\t\t\tAND C.TABLE_NAME = " + ParamEnum.TABLE.getParamSign() + "\n" + // 添加模式与表,增加查询效率 + "\t) E\n" + + "ON\n" + + "\tA.OWNER = E.OWNER AND A.TABLE_NAME = E.TABLE_NAME AND A.COLUMN_NAME = E.COLUMN_NAME \n" + + "LEFT JOIN \n" + + "\t(\n" + + "\t\tSELECT \n"+ + "\t\t\tF.NAME, DECODE(F.INFO2,1,'1','0') AS IS_AUTO \n" + + "\t\tFROM \n"+ + "\t\t\tSYS.SYSCOLUMNS F\n" + + "\t\tWHERE\n" + + "\t\t\tID ="+ + "\t(\n"+ + "\t\tSELECT \n"+ + "\t\t\tOBJECT_ID \n" + + "\t\tFROM \n" + + "\t\t\tDBA_OBJECTS G \n"+ + "\t\tWHERE \n" + + "\t\t\tG.OWNER = " + ParamEnum.DB_NAME.getParamSign() + "\n" + + "\t\t\tAND G.OBJECT_NAME = " + ParamEnum.TABLE.getParamSign() + "\n" + + "\t\t\tAND G.OBJECT_TYPE = 'TABLE') \n" + + "\t) H\n" + + "ON \n" + + "\tA.COLUMN_NAME = H.NAME \n" + + "WHERE\n" + + " A.OWNER = " + ParamEnum.DB_NAME.getParamSign() + "\n" + + "\tAND A.TABLE_NAME = " + ParamEnum.TABLE.getParamSign() + "\n" + + "\tORDER BY A.COLUMN_ID" + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getDmDbSchema()); + list.add(table); + list.add(dbStruct.getDmDbSchema()); + list.add(table); + list.add(dbStruct.getDmDbSchema()); + list.add(table); + } + }, + TABLES( + // 作用:DBMS_STATS.GATHER_TABLE_STATS统计表,列,索引的统计信息(默认参数下是对表进行直方图信息收集, + // 包含该表的自身-表的行数、数据块数、行长等信息;列的分析--列值的重复数、列上的空值、数据在列上的分布情况; + // 索引的分析-索引页块的数量、索引的深度、索引聚合因子). +// "dbms_stats.GATHER_SCHEMA_stats (" + ParamEnum.DB_SCHEMA.getParamSign() +");\n" + + "SELECT\n" + + "ut.TABLE_NAME " + DbAliasEnum.TABLE_NAME.getAlias() + ",utc.COMMENTS " + DbAliasEnum.TABLE_COMMENT.getAlias() + "\n" + + ",ut.num_rows " + DbAliasEnum.TABLE_SUM.getAlias() + "\n" + + "FROM ALL_TABLES AS ut\n" + + "LEFT JOIN\n" + + "all_tab_comments AS utc\n" + + "ON\n" + + "ut.TABLE_NAME = utc.TABLE_NAME AND ut.OWNER = utc.OWNER\n" + + "WHERE ut.OWNER = " + ParamEnum.DB_SCHEMA.getParamSign() + "\n" + + "ORDER BY F_TABLE_NAME;" + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getDmDbSchema()); + } + }, + TABLESANDVIEW( + // 作用:DBMS_STATS.GATHER_TABLE_STATS统计表,列,索引的统计信息(默认参数下是对表进行直方图信息收集, + // 包含该表的自身-表的行数、数据块数、行长等信息;列的分析--列值的重复数、列上的空值、数据在列上的分布情况; + // 索引的分析-索引页块的数量、索引的深度、索引聚合因子). +// "dbms_stats.GATHER_SCHEMA_stats (" + ParamEnum.DB_SCHEMA.getParamSign() +");\n" + + " select\tTABLE_NAME as " + DbAliasEnum.TABLE_NAME.getAlias() + + ",'TABLE' as " + DbAliasEnum.TABLE_TYPE.getAlias() + " from all_tab_comments WHERE owner = " + ParamEnum.DB_NAME.getParamSign() + "\n" + + " UNION\n" + + " select\t view_name as " + DbAliasEnum.TABLE_NAME.getAlias() + + ",'VIEW' as " + DbAliasEnum.TABLE_TYPE.getAlias() + " from all_views WHERE owner = " + ParamEnum.DB_NAME.getParamSign() +// "select atcs.table_name " + DbAliasEnum.TABLE_NAME.getAlias() +// + ",atcs.comments " + DbAliasEnum.TABLE_COMMENT.getAlias() +// + ",atcs.table_type " + DbAliasEnum.TABLE_TYPE.getAlias() +// + "\nfrom all_views alv left join all_tab_comments atcs on alv.owner = atcs.owner where atcs.owner = " + ParamEnum.DB_NAME.getParamSign() + "" + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getDmDbSchema()); + list.add(dbStruct.getPostGreDbSchema()); + } + }, + TABLE( + TABLES.sqlFrame.replace("ORDER BY", "AND ut.TABLE_NAME = " + ParamEnum.TABLE.getParamSign() + " ORDER BY") + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getDmDbSchema()); + list.add(table); + } + }, + EXISTS_TABLE( + "SELECT COUNT (*) AS TOTAL FROM (" + + "SELECT\n" + + "ut.TABLE_NAME " + DbAliasEnum.TABLE_NAME.getAlias() + " FROM ALL_TABLES AS ut\n" + + "WHERE ut.OWNER = " + ParamEnum.DB_SCHEMA.getParamSign() + + " and ut.TABLE_NAME = "+ ParamEnum.TABLE.getParamSign() + + ") AS TOTAL" + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getDmDbSchema()); + list.add(table); + } + }, + + + /* =============================== 定义语句 ==================================== */ + // (Data Definition Language)简称 DDL:用来建立数据库、数据库对象和定义列的命令。包括:create、alter、drop + /*=============================== ALTER ====================================*/ + CREATE_TABLE ( + "
{table}<(>\n" + + "【{column} {dataType} [[NOT] [NULL]] [ {defaultValue}] 】" + + "\n{primarykeys}" + + "\n<)>" + ){ + @Override + public String createIncrement(String sqlFrame, Map paramsMap) { + // 自增标识:IDENTITY(1, 1) + if (StringUtil.isNotEmpty(paramsMap.get("[AUTO_INCREMENT]"))){ + sqlFrame = super.createIncrement(sqlFrame, paramsMap) + .replace("{dataType}", "{dataType} IDENTITY(1, 1)"); + String openIdentity = OPEN_IDENTITY.sqlFrame + .replace("{table}", paramsMap.get("{table}")) + .replace("", "ON"); + return sqlFrame + ";\n" + openIdentity; + } + return sqlFrame; + } + + @Override + public String createIndex(){ + + + // 添加唯一索引 + String createIndex = "CREATE UNIQUE {uniqueName} TO {table}【{column}】"; + + + return null; + } + + }, + OPEN_IDENTITY("SET IDENTITY_INSERT {table} "), + ALTER_DROP("ALTER TABLE 《schema》.{table} DROP COLUMN {column}"), + /** + * 添加字段 + */ + ALTER_ADD("ALTER TABLE 《schema》.{table} ADD {column} {dataType}"), + /** + * 修改字段 + */ + ALTER_TYPE("ALTER TABLE 《schema》.{table} {column} {dataType}"), + /** + * 修改表名 + */ + ALTER_TABLE_NAME("ALTER TABLE 《schema》.{table} ALTER column {oldColumn} RENAME TO {newColumn};"), + + + /* =============================== DML操作语句 ==================================== */ + // (Data Manipulation Language)简称 DML:用来操纵数据库中数据的命令。包括:select、insert、update、delete。 + + DB_TIME_SQL ("select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') as TIME "), + INSERT( + "INSERT INTO 《schema》.{table} (【{column},】) VALUES (【{value},】)" + ), + /** + * + */ + CREATE_SCHEMA( + "CREATE SCHEMA \"{schema}\";" + ), + DROP_SCHEMA( + "DROP SCHEMA \"{schema}\" RESTRICT" + ), + DROP_TABLE( + SqlPostgreSQLEnum.DROP_TABLE + ), + COMMENT_COLUMN( + SqlPostgreSQLEnum.COMMENT_COLUMN + ), + COMMENT_TABLE( + SqlPostgreSQLEnum.COMMENT_TABLE + ), + CREATE( + SqlPostgreSQLEnum.CREATE + ), + + + + /*=============================== 其他 ====================================*/ + + ; + + private final String dbEncode = DbBase.DM; + private final String sqlFrame; + + SqlDMEnum(SqlFrameBase sqlEnum){ + this.sqlFrame = sqlEnum.getSqlFrame(); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlKingbaseESEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlKingbaseESEnum.java new file mode 100644 index 0000000..ba96682 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlKingbaseESEnum.java @@ -0,0 +1,182 @@ +package com.yunzhupaas.database.sql.enums; + +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.enums.ParamEnum; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.enums.base.SqlFrameBase; +import com.yunzhupaas.database.sql.model.DbStruct; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; +import java.util.Map; + +/** + * 金仓 SQL语句模板 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/17 + */ +@Getter +@AllArgsConstructor +public enum SqlKingbaseESEnum implements SqlFrameBase { + /* =============================== 系统语句 ==================================== */ + FIELDS( + SqlPostgreSQLEnum.FIELDS.getSqlFrame() + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + SqlPostgreSQLEnum.FIELDS.setStructParams(table, dbStruct, list); + } + }, + TABLES( + "SELECT DISTINCT t.TABLE_NAME AS " + DbAliasEnum.TABLE_NAME.getAlias() + ",c.DESCRIPTION AS " + DbAliasEnum.TABLE_COMMENT.getAlias() + ", 0 AS " + DbAliasEnum.TABLE_SUM.getAlias() + " FROM\n" + + "information_schema.TABLES AS t\n" + + "LEFT JOIN\n" + + "(SELECT * FROM PG_DESCRIPTION WHERE OBJSUBID = 0)AS c\n" + + "ON\n" + + "TABLE_NAME::REGCLASS::OID = C.OBJOID\n" + + "WHERE\n" + + " TABLE_SCHEMA = " + ParamEnum.DB_SCHEMA.getParamSign() + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getKingBaseDbSchema()); + } + }, + TABLESANDVIEW( + "SELECT t.table_name AS " + DbAliasEnum.TABLE_NAME.getAlias() + + ",c.DESCRIPTION AS " + DbAliasEnum.TABLE_COMMENT.getAlias() + + ",t.table_type AS " + DbAliasEnum.TABLE_TYPE.getAlias() + + "\n FROM information_schema.TABLES\n" + + "\tAS T LEFT JOIN " + + "(SELECT * FROM PG_DESCRIPTION WHERE OBJSUBID = 0)AS c\n" + + "ON\n" + + "TABLE_NAME::REGCLASS::OID = C.OBJOID\n" + + "WHERE\n" + + "\tTABLE_SCHEMA = " + ParamEnum.DB_SCHEMA.getParamSign() + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getKingBaseDbSchema()); + } + }, + SqlKingbaseESEnum( + "SELECT t.TABLE_NAME AS " + DbAliasEnum.TABLE_NAME.getAlias() + ",c.DESCRIPTION AS " + DbAliasEnum.TABLE_COMMENT.getAlias() + ", 0 AS " + DbAliasEnum.TABLE_SUM.getAlias() + " FROM\n" + + "information_schema.TABLES AS t\n" + + "LEFT JOIN\n" + + "(SELECT * FROM PG_DESCRIPTION WHERE OBJSUBID = 0)AS c\n" + + "ON\n" + + "TABLE_NAME::REGCLASS::OID = C.OBJOID\n" + + "WHERE\n" + + " TABLE_SCHEMA = " + ParamEnum.DB_SCHEMA.getParamSign() + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getKingBaseDbSchema()); + } + }, + TABLE( + TABLES.sqlFrame + " AND t.TABLE_NAME = " + ParamEnum.TABLE.getParamSign() + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getKingBaseDbSchema()); + list.add(table); + } + }, + EXISTS_TABLE( + "SELECT COUNT (*) AS TOTAL FROM (" + + "SELECT t.TABLE_NAME AS " + DbAliasEnum.TABLE_NAME.getAlias() + " FROM\n" + + "information_schema.TABLES AS t WHERE TABLE_SCHEMA = " + ParamEnum.DB_SCHEMA.getParamSign() + + " and t.TABLE_NAME = " + ParamEnum.TABLE.getParamSign() + + ") AS COUNT_TAB" + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getKingBaseDbSchema()); + list.add(table); + } + }, + + + /** + * 建库 + */ + CREATE_DATABASE( + "CREATE DATABASE WITH owner=\"{database}\" " + ), + DROP_DATABASE( + "DROP DATABASE \"{database}\"" + ), + CREATE_SCHEMA( + "CREATE SCHEMA AUTHORIZATION \"{schema}\"" + ), + DROP_SCHEMA( + "DROP SCHEMA \"{schema}\" CASCADE;" + ), + + /*==================== 操作表 ======================*/ + DROP( + "DROP TABLE {table}" + ), + DROP_TABLE( + SqlPostgreSQLEnum.DROP_TABLE + ), + COMMENT_COLUMN( + SqlPostgreSQLEnum.COMMENT_COLUMN + ), + COMMENT_TABLE( + SqlPostgreSQLEnum.COMMENT_TABLE + ), + CREATE( + SqlPostgreSQLEnum.CREATE + ), + + /*=============================== ALTER ====================================*/ + CREATE_TABLE(SqlPostgreSQLEnum.CREATE_TABLE.getSqlFrame()){ + @Override + public String createIncrement(String sqlFrame, Map paramsMap) { + return SqlPostgreSQLEnum.CREATE_TABLE.createIncrement(sqlFrame, paramsMap); + } + }, + ALTER_DROP( + "ALTER TABLE 《schema》.{table} DROP COLUMN {column}" + ), + /** + * 添加字段 + */ + ALTER_ADD( + "ALTER TABLE 《schema》.{table} ADD COLUMN {column} {dataType}" + ), + /** + * 修改字段 + */ + ALTER_TYPE( + "ALTER TABLE 《schema》.{table} ALTER COLUMN {column} TYPE {dataType}" + ), + /** + * 修改: 表名 + */ + RE_TABLE_NAME( + SqlPostgreSQLEnum.RE_TABLE_NAME + ), + /*=============================== ALTER ====================================*/ + + INSERT( + "INSERT INTO 《schema》.{table} (【{column},】) VALUES (【{value},】)" + ), + ; + // ALTER TABLE flow_taskoperator DROP COLUMN F_DraftData + + private final String dbEncode = DbBase.KINGBASE_ES; + private String sqlFrame; + + SqlKingbaseESEnum(SqlFrameBase sqlEnum){ + this.sqlFrame = sqlEnum.getSqlFrame(); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlMySQLEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlMySQLEnum.java new file mode 100644 index 0000000..24d1583 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlMySQLEnum.java @@ -0,0 +1,171 @@ +package com.yunzhupaas.database.sql.enums; + +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.enums.ParamEnum; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.enums.base.SqlFrameBase; +import com.yunzhupaas.database.sql.model.DbStruct; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +/** + * MySQL SQL语句模板 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/17 + */ +@Getter +@AllArgsConstructor +public enum SqlMySQLEnum implements SqlFrameBase { + + /* =============================== 系统语句 ==================================== */ + FIELDS("SELECT\n" + + "\tNUMERIC_SCALE AS " + DbAliasEnum.NUM_SCALE.getAlias() + ",\n" + + "\tNUMERIC_PRECISION AS " + DbAliasEnum.NUM_PRECISION.getAlias() + ",\n" + + "\tCHARACTER_MAXIMUM_LENGTH AS " + DbAliasEnum.CHAR_LENGTH.getAlias() + ",\n" + + "\tCOLUMN_NAME AS " + DbAliasEnum.FIELD.getAlias() + ",\n" + + "\tDATA_TYPE AS " + DbAliasEnum.DATA_TYPE.getAlias() + ",\n" + + "\tCOLUMN_COMMENT AS " + DbAliasEnum.FIELD_COMMENT.getAlias() + ",\n" + + "\tCOLUMN_DEFAULT AS " + DbAliasEnum.DEFAULT_VALUE.getAlias() + ",\n" + + " IF( EXTRA = 'auto_increment', '1', '0') AS " + DbAliasEnum.AUTO_INCREMENT.getAlias() + ",\n" + + " IF( IS_NULLABLE = 'YES', '1', '0' ) AS " + DbAliasEnum.ALLOW_NULL.getAlias() + ",\n" + + " IF( COLUMN_KEY = 'PRI', '1', '0' ) AS " + DbAliasEnum.PRIMARY_KEY.getAlias() + " \n" + + "FROM\n" + + "\tINFORMATION_SCHEMA.COLUMNS \n" + + "WHERE\n" + + "\tTABLE_NAME = " + ParamEnum.TABLE.getParamSign() + "\n" + + "\tAND TABLE_SCHEMA = " + ParamEnum.DB_SCHEMA.getParamSign() + " \n" + + "ORDER BY\n" + + "\tORDINAL_POSITION;") { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(table); + list.add(dbStruct.getMysqlDbName()); + } + }, + TABLES( + "SELECT\n" + + "\ttable_name AS " + DbAliasEnum.TABLE_NAME.getAlias() + ",\n" + + "\ttable_rows AS " + DbAliasEnum.TABLE_SUM.getAlias() + ",\n" + + "\tdata_length AS " + DbAliasEnum.TABLE_SIZE.getAlias() + ",\n" + + "\ttable_comment AS " + DbAliasEnum.TABLE_COMMENT.getAlias() + "\n" + + "FROM\n" + + "\tINFORMATION_SCHEMA.TABLES \n" + + "WHERE\n" + + "\tTABLE_SCHEMA = " + ParamEnum.DB_NAME.getParamSign() + "\n" + + "AND \n" + + "\tTABLE_TYPE != 'VIEW'") { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getMysqlDbName()); + } + }, + TABLESANDVIEW( + "SELECT\n" + + "\ttable_name AS " + DbAliasEnum.TABLE_NAME.getAlias() + ",\n" + + "\ttable_rows AS " + DbAliasEnum.TABLE_SUM.getAlias() + ",\n" + + "\tdata_length AS " + DbAliasEnum.TABLE_SIZE.getAlias() + ",\n" + + "\ttable_comment AS " + DbAliasEnum.TABLE_COMMENT.getAlias() + ",\n" + + "\ttable_type AS " + DbAliasEnum.TABLE_TYPE.getAlias() + "\n" + + "FROM\n" + + "\tINFORMATION_SCHEMA.TABLES \n" + + "WHERE\n" + + "\tTABLE_SCHEMA = " + ParamEnum.DB_NAME.getParamSign() + "\n") { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getMysqlDbName()); + } + }, + TABLE( + TABLES.sqlFrame + "AND table_name = " + ParamEnum.TABLE.getParamSign()) { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getMysqlDbName()); + list.add(table); + } + }, + EXISTS_TABLE( + "SELECT COUNT(*) AS TOTAL FROM (" + + "SELECT " + + "table_name AS " + DbAliasEnum.TABLE_NAME.getAlias() + " " + + "FROM " + + "information_schema.TABLES " + + "WHERE " + + "TABLE_SCHEMA = " + ParamEnum.DB_NAME.getParamSign() + " " + + "and " + + "table_name = " + ParamEnum.TABLE.getParamSign() + + ") AS COUNT_TAB") { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getMysqlDbName()); + list.add(table); + } + }, + /* =============================== 定义语句 ==================================== */ + // (Data Definition Language)简称 DDL:用来建立数据库、数据库对象和定义列的命令。包括:create、alter、drop + CREATE_TABLE("
{table} <(>\n" + + "【{column} {dataType} [[NOT] [NULL]] [ {defaultValue}] [AUTO_INCREMENT] [ {comment}]】" + + "\n{primarykeys}" + + "\n<)> "), + + CREATE( + "
{table} <(>\n" + + "【\r" + + "1:( <(>{primaryColumn}<)> [ {useValue}])|" + + "3:( {indexValue} <(>{column}<)>)|" + + "2:({column} {dataType} [[NOT] [NULL]] [ {defaultValue}] [ {comment}])" + + ",\n】" + + "<)> [ <=> {comment}]"), + DROP_TABLE("
[ ] {table}"), + /** + * 表重命名 + */ + RE_TABLE_NAME("ALTER TABLE {oldTable} RENAME [TO] {newTable}"), + ALTER_ADD_MODIFY( + "
{table} [COLUMN] {column} {dataType} [[NOT] [NULL]] [ {defaultValue}] [ {comment}]"), + ALTER_ADD_MODIFY_MULTI( + "
{table} <(>\n" + + "【[COLUMN] {column} {dataType} [[NOT] [NULL]] [ {defaultValue}] [ {comment}],\n】" + + + "<)>"), + ALTER_CHANGE( + "
{table} {oldColumn} {newColumn} {dataType} [[NOT] [NULL]] [ {defaultValue}] [ {comment}]"), + COMMENT_TABLE("
{table} = '{comment}'"), + COMMENT_COLUMN( + "
{table} `{column}` {dataType} [DEFAULT {defaultValue}] '{comment}'"), + + /* + * =============================== DML操作语句 ==================================== + */ + // (Data Manipulation Language)简称 + // DML:用来操纵数据库中数据的命令。包括:select、insert、update、delete。 + /* + * mysql可以用 SELECT SQL_CALC_FOUND_ROWS * FROM table + * LIMIT index;SELECT FOUND_ROWS();方法获得两个结果集 + */ + SELECT_TABLE("SELECT * FROM {table}"), + DB_TIME_SQL("SELECT DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%s') as TIME"), + COUNT_SIZE("SELECT COUNT(*) AS {totalAlias} FROM ({selectSql}) YUNZHUPAAS_TABLE"), + COUNT_TABLE_SIZE(COUNT_SIZE.sqlFrame.replace("({selectSql})", "{table}")), + INSERT(" {table} ([【{column},】]) (【{value},】)"), + DELETE_ALL("DELETE FROM {table}"), + /* =============================== 后缀 ==================================== */ + // LIMIT必须在ORDER之后,在前报错。顺序先排序再分页。 + ORDER_PAGE("{selectSql} ORDER BY {orderColumn} [DESC] LIMIT {beginIndex},{pageSize}"), + PAGE("{selectSql} LIMIT {beginIndex},{pageSize}"), + ORDER("{selectSql} ORDER BY {column} [DESC]"), + LIKE("{selectSql} WHERE {column} like {condition}"), + + ; + + /** + * + */ + private final String sqlFrame; + private final String dbEncode = DbBase.MYSQL; + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlOracleEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlOracleEnum.java new file mode 100644 index 0000000..aa5f58a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlOracleEnum.java @@ -0,0 +1,304 @@ +package com.yunzhupaas.database.sql.enums; + +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.enums.ParamEnum; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.enums.base.SqlFrameBase; +import com.yunzhupaas.database.sql.model.DbStruct; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.List; + +/** + * Oracle SQL语句模板 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/30 + */ +@Getter +@AllArgsConstructor +public enum SqlOracleEnum implements SqlFrameBase { + + /* =============================== 系统语句 ==================================== */ + FIELDS( + "SELECT \n" + + "\tA.COLUMN_NAME AS " + DbAliasEnum.FIELD.getAlias() + ",\n" + + "\tA.DATA_TYPE AS " + DbAliasEnum.DATA_TYPE.getAlias() + ",\n" + + "\tA.DATA_LENGTH AS " + DbAliasEnum.CHAR_LENGTH.getAlias() + ",\n" + + "\tA.DATA_PRECISION AS " + DbAliasEnum.NUM_PRECISION.getAlias() + ",\n" + + "\tA.DATA_SCALE AS " + DbAliasEnum.NUM_SCALE.getAlias() + ",\n" + + "\tCASE WHEN E.CONSTRAINT_TYPE IS NOT NULL THEN '1' ELSE '0' END AS " + + DbAliasEnum.PRIMARY_KEY.getAlias() + ",\n" + + "\tCASE A.NULLABLE WHEN 'N' THEN '0' ELSE '1' END AS " + DbAliasEnum.ALLOW_NULL.getAlias() + ",\n" + + "\t(SELECT COUNT(*) FROM ALL_TRIGGERS WHERE TABLE_NAME = A.TABLE_NAME AND TABLE_OWNER = A.OWNER AND INSTR(TRIGGER_NAME, 'AUTO_') >0) AS " + + DbAliasEnum.AUTO_TRIGGER.getAlias() + ",\n" + + "\tB.COMMENTS AS " + DbAliasEnum.FIELD_COMMENT.getAlias() + "\n" + + "FROM \n" + + "\tALL_TAB_COLUMNS A -- 表&字段 OWNER、TABLE_NAME、COLUMN_NAME_\t\n" + + "LEFT JOIN \n" + + "\tALL_COL_COMMENTS B -- 字段注释 TABLE_NAME、COLUMN_NAME\n" + + "ON \n" + + "\tA.OWNER = B.OWNER AND A.TABLE_NAME = B.TABLE_NAME AND A.COLUMN_NAME = B.COLUMN_NAME \n" + + "LEFT JOIN \n" + + "\t(SELECT \n" + + "\t\t\tC.OWNER, C.TABLE_NAME, C.COLUMN_NAME, D.CONSTRAINT_TYPE \n" + + "\t\tFROM \n" + + "\t\t\tALL_CONS_COLUMNS C, ALL_CONSTRAINTS D \n" + + "\t\tWHERE \n" + + "\t\t\tC.CONSTRAINT_NAME = D.CONSTRAINT_NAME AND D.CONSTRAINT_TYPE = 'P'\n" + + "\t) E\n" + + "ON\n" + + "\tA.OWNER = E.OWNER AND A.TABLE_NAME = E.TABLE_NAME AND A.COLUMN_NAME = E.COLUMN_NAME \n" + + "WHERE\n" + + " A.OWNER = " + ParamEnum.DB_NAME.getParamSign() + "\n" + + "\tAND A.TABLE_NAME = " + ParamEnum.TABLE.getParamSign()) { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getOracleDbSchema()); + list.add(table); + } + }, + // "SELECT atcs.table_name " + DbAliasConst.TABLE_NAME + ", atcs.comments " + + // DbAliasConst.TABLE_COMMENT + ", ats.num_rows " + DbAliasConst.TABLE_SUM + + // "\n" + + // "FROM user_tab_comments atcs,all_tables ats WHERE atcs.table_name = + // ats.table_name AND ats.owner = '" + ParamEnum.DB_NAME.getParamSign() + "'" + TABLES("SELECT atcs.table_name " + DbAliasEnum.TABLE_NAME.getAlias() + ", atcs.comments " + + DbAliasEnum.TABLE_COMMENT.getAlias() + ", ats.num_rows " + DbAliasEnum.TABLE_SUM.getAlias() + "\n" + + "FROM all_tab_comments atcs,all_tables ats WHERE atcs.table_name = ats.table_name AND ats.owner = atcs.owner AND ats.owner = " + + ParamEnum.DB_NAME.getParamSign() + "" + // "SELECT " + + // "a.TABLE_NAME " + DbAliasConst.TABLE_NAME + ", " + + // "b.COMMENTS " + DbAliasConst.TABLE_COMMENT + ", " + + // "a.num_rows " + DbAliasConst.TABLE_SUM + + // "\nFROM user_tables a, user_tab_comments b " + // + "WHERE a.TABLE_NAME = b.TABLE_NAME " + /* + "and a.TABLESPACE_NAME='"+ ParamEnum.TABLE_SPACE.getTarget()+"'" */ + ) { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getOracleDbSchema()); + } + }, + TABLESANDVIEW("SELECT\n" + + "\tatcs.table_name " + DbAliasEnum.TABLE_NAME.getAlias() + ",\n" + + "\tatcs.comments " + DbAliasEnum.TABLE_COMMENT.getAlias() + ",\n" + + "\tatcs.table_type " + DbAliasEnum.TABLE_TYPE.getAlias() + " \n" + + "FROM\n" + + "\tall_tab_comments atcs\n" + + "\tLEFT JOIN all_views alv ON alv.owner = atcs.owner \n" + + "WHERE\n" + + "\tatcs.owner = " + ParamEnum.DB_NAME.getParamSign() + + ) { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getOracleDbSchema()); + } + }, + TABLE( + TABLES.sqlFrame + " AND ats.TABLE_NAME = " + ParamEnum.TABLE.getParamSign()) { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getOracleDbSchema()); + list.add(table); + } + }, + EXISTS_TABLE( + "SELECT COUNT(*) AS TOTAL FROM ALL_TABLES WHERE OWNER = UPPER(" + ParamEnum.DB_NAME.getParamSign() + + ") AND TABLE_NAME = UPPER(" + ParamEnum.TABLE.getParamSign() + ")") { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getOracleDbSchema()); + list.add(table); + } + }, + + /* =============================== 定义语句 ==================================== */ + // (Data Definition Language)简称 DDL:用来建立数据库、数据库对象和定义列的命令。包括:create、alter、drop + + CREATE_TABLE("
{table} <(>\n" + + "【{column} {dataType} [[NOT] [NULL]] [ {defaultValue}] 】" + + "\n{primarykeys}" + + "\n<)>") { + + public String createIndex() { + String model = "CREATE UNIQUE INDEX {indexName} ON {table}(【column】)"; + + return null; + } + + }, + // 添加自增 + CREATE_AUTO_INCREMENT( + "CREATE SEQUENCE {table}_seq\n" + + "INCREMENT by 1\n" + // 每次增加1 + "START WITH 1\n" + // 从1开始计数 + "NOMAXVALUE\n" + // 无最大值 + "NOCYCLE\n" + // 一直累加,不循环 + "NOCACHE"), + // 添加自增触发器(1、结尾需要用斜杠/,;代表行结束,/代表块结束。2、触发器与序列名字长度有限制) + // select 1 from dual:用来做过渡;封号 + CREATE_AUTO_INCREMENT_TRIGGER( + "CREATE OR REPLACE TRIGGER AUTO_{table}_tg\n" + + "BEFORE INSERT ON {table}\n" + + "FOR EACH ROW\n" + + "BEGIN\n" + + "\tSELECT {table}_seq.NEXTVAL INTO :new.{autoInc_field} FROM dual;\n" + + "END;"), + DROP_SEQ( + "DROP sequence {seqName}"), + DROP_TRIGGER( + "DROP trigger {triggerName}"), + CREATE("CREATE TABLE 《schema》.{table}(\n" + + "【 " + + "1:(PRIMARY KEY ({primaryColumn}))|" + + "2:({column} {dataType} [[NOT] [NULL]] [DEFAULT {defaultValue}])" + + ",\n】)"), + DROP_TABLE("DROP TABLE {table}"), + /** + * 注意:Oracle DDL:COMMENT 无法在Mybatis Mapper.xml里面使用?占位符 + * 会出现:ORA-01780: 要求文字字符串 + */ + COMMENT_TABLE("COMMENT ON TABLE 《schema》.{table} IS '{comment}'"), + COMMENT_COLUMN("COMMENT ON COLUMN 《schema》.{table}.{column} IS '{comment}'"), + DROP_COLUMN("ALTER TABLE 《schema》.{table} DROP COLUMN {column}"), + ADD_COLUMN("ALTER TABLE 《schema》.{table} ADD {column} {dataType}"), + MODIFY_TYPE("ALTER TABLE 《schema》.{table} ALTER COLUMN {column} TYPE {dataType}"), + ALTER_TABLE("ALTER TABLE 《schema》.{oldTable} RENAME TO {newTable}"), + + /* + * =============================== DML操作语句 ==================================== + */ + /* + * (Data Manipulation Language)简称 + * DML:用来操纵数据库中数据的命令。包括:select、insert、update、delete。 + * 注意:有一些Oracle版本中的语法子查询不支持别名关键词 AS + */ + /* =============================== ALTER ==================================== */ + ORDER_PAGE("SELECT * FROM " + + "(SELECT YUNZHUPAAS_TEMP.*, ROWNUM YUNZHUPAAS_RowNo " + + "FROM " + + "({selectSql}) YUNZHUPAAS_TEMP " + + "ORDER BY {orderColumn} [DESC]) YUNZHUPAAS_TAB " + + "WHERE YUNZHUPAAS_TAB.YUNZHUPAAS_RowNo BETWEEN {beginIndex} AND {endIndex}"), + DB_TIME_SQL("select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') as TIME from dual"), + INSERT("INSERT INTO 《schema》.{table} (【{column},】) VALUES (【{value},】)"), + /** + * 【注意:Oracle所有插入字符,也就是''之间的内容都会隐式转成varchar2类型,都不得超过4000】 + * 尾部用;结尾,不然会报错 + */ + CLOB_INSERT("DECLARE\n" + + "\tclobVal {table}.{column}%TYPE;\n" + + "BEGIN\t\n" + + "\tclobVal := '{value}';\n" + + "INSERT INTO {table} (【{clobColumn},{column},】) VALUES (【{clobVal},{value},】);\n" + + "END"), + CLOB_UPDATE( + "DECLARE \n" + + "-- 此表为:{table}\n" + + "\tv_context NCLOB;\n" + + "BEGIN\n" + + "\tDBMS_LOB.CREATETEMPORARY(v_context,TRUE);\n" + + // "\tcontext := '' ;\n" + + "\t【DBMS_LOB.APPEND(v_context, '{context}');】\n" + + "\tUPDATE {table} SET {column} = v_context WHERE {key} = '{value}';\n" + + "END") { + @Override + public String getFastSql(List values) { + String sql = this.getSqlFrame(); + List keys = Arrays.asList( + "{table}", + "{column}", + "\t【DBMS_LOB.APPEND(v_context, '{context}');】\n", + "{key}", + "{value}"); + for (int i = 0; i < values.size(); i++) { + if (values.get(i) != null) { + sql = sql.replace(keys.get(i), values.get(i)); + } + } + return sql; + } + + }, + CLOB_APPEND("DBMS_LOB.APPEND(v_context, '{context}')"), + BLOB_UPDATE( + "DECLARE \n" + + "-- 此表为:{table}\n" + + "\tv_context BLOB;\n" + + "BEGIN\n" + + "\tDBMS_LOB.CREATETEMPORARY(v_context,TRUE);\n" + + "\t【DBMS_LOB.APPEND(v_context, HEXTORAW('{context}'))】\n" + + "\tUPDATE {table} SET {column} = v_context WHERE {key} = '{value}';\n" + + "END") { + @Override + public String getFastSql(List values) { + String sql = this.getSqlFrame(); + List keys = Arrays.asList( + "{table}", + "{column}", + "\t【DBMS_LOB.APPEND(v_context, HEXTORAW('{context}'))】\n", + "{key}", + "{value}"); + for (int i = 0; i < values.size(); i++) { + if (values.get(i) != null) { + sql = sql.replace(keys.get(i), values.get(i)); + } + } + return sql; + } + + }, + BLOB_APPEND("DBMS_LOB.APPEND(v_context, HEXTORAW('{context}'))"), + /* =============================== 其他 ==================================== */ + /** + * oracle 时间格式转换 + */ + TO_TIME("TO_DATE('{datetime}','YYYY-MM-DD HH24:MI:SS')"), + /** + * 查看现有表空间信息 + */ + SELECT_TABLESPACE( + "SELECT TABLESPACE_NAME,FILE_ID,FILE_NAME,round(bytes/(1024*1024),0) total_space FROM DBA_DATA_FILES ORDER BY TABLESPACE_NAME"), + /** + * 创建临时表空间 + */ + CREATE_TEMP_TABLESPACE("CREATE TEMPORARY TABLESPACE UQSM_TEMP TEMPFILE '/{path}/{tempTablespaceName}.dbf' " + + "size 8000m autoextend on next 50m maxsize unlimited extent management local;"), + /** + * 创建表空间 + */ + CREATE_TABLESPACE("\n" + "CREATE TABLESPACE UQSM_DATA LOGGING DATAFILE '/{path}/{tempTablespaceName}.dbf' " + + "SIZE 8000m autoextendon next 50M maxsize unlimited extent management local;\n"), + /** + * 创建用户 + */ + CREATE_USER( + "CREATE USER {user} IDENTIFIED BY {password} DEFAULT TABLESPACE {tablespace} TEMPORARY TABLESPACE {tempTablespace}"), + /** + * 删除用户 + */ + DROP_USER("DROP USER {user}"), + /** + * 给用户授予权限 + */ + GRANT_ROLE("GRANT connect,RESOURCE,dba to {user};"), + /** + * 修改用户的密码 + */ + ALTER_USER_PASSWORD("ALTER USER {user} IDENTIFIED BY {password}"), + ; + + private final String sqlFrame; + private final String dbEncode = DbBase.ORACLE; + + public String getFastSql(List values) { + return this.getSqlFrame(); + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlPostgreSQLEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlPostgreSQLEnum.java new file mode 100644 index 0000000..3f6077d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlPostgreSQLEnum.java @@ -0,0 +1,219 @@ +package com.yunzhupaas.database.sql.enums; + +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.enums.ParamEnum; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.enums.base.SqlFrameBase; +import com.yunzhupaas.database.sql.model.DbStruct; +import com.yunzhupaas.util.StringUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; +import java.util.Map; + +/** + * Postgre SQL语句模板 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/17 + */ +@Getter +@AllArgsConstructor +public enum SqlPostgreSQLEnum implements SqlFrameBase { + + /* =============================== 系统语句 ==================================== */ + FIELDS( + "SELECT\n" + + "\tcol.column_name AS " + DbAliasEnum.FIELD.getAlias() + ",\n" + + "\tcol.udt_name AS " + DbAliasEnum.DATA_TYPE.getAlias() + ",\n" + + "\tis_nullable AS " + DbAliasEnum.ALLOW_NULL.getAlias() + ",\n" + + "\tcol_description (pa.pg_oid, attnum) " + DbAliasEnum.FIELD_COMMENT.getAlias() + ",\n" + + "\tcharacter_maximum_length AS " + DbAliasEnum.CHAR_LENGTH.getAlias() + ",\n" + + "\tnumeric_precision AS " + DbAliasEnum.NUM_PRECISION.getAlias() + ",\n" + + "\tcolumn_default AS " + DbAliasEnum.COLUMN_DEFAULT.getAlias() + ",\n" + + "\ttable_name AS " + DbAliasEnum.TABLE_NAME.getAlias() + ",\n" + + "\tnumeric_scale AS " + DbAliasEnum.NUM_SCALE.getAlias() + ",\n" + + "\t(CASE WHEN ( SELECT pa.attnum = ANY ( conkey ) FROM pg_constraint WHERE conrelid = pa.pg_oid AND contype = 'p' ) = 't' \n" + + "\tTHEN 1 ELSE 0 END ) " + DbAliasEnum.PRIMARY_KEY.getAlias() + "\t\n" + + "FROM\n" + + "\tinformation_schema.COLUMNS AS col\n" + + "LEFT JOIN (\n" + + "\tSELECT\n" + + "\t\t\t\t\t* \n" + + "\tFROM\n" + + " (SELECT *,oid AS pg_oid FROM pg_class WHERE relnamespace IN ( SELECT oid FROM pg_namespace WHERE nspname = " + ParamEnum.DB_SCHEMA.getParamSign() + " )) AS pc\n" + + "\tLEFT JOIN\n" + + "\t pg_attribute AS pat \n" + + "\tON \n" + + "\t\tpat.attrelid = pc.pg_oid\n" + + "\tWHERE \n" + + "\t\t\tpc.relname = " + ParamEnum.TABLE.getParamSign() + "\n" + + "\t) AS pa \n" + + "ON \n" + + "\tpa.attname = col.column_name \n" + + "WHERE\n" + + "\tcol.table_schema = " + ParamEnum.DB_SCHEMA.getParamSign() + " \n" + + "\tAND TABLE_NAME = " + ParamEnum.TABLE.getParamSign() + + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getPostGreDbSchema()); + list.add(table); + list.add(dbStruct.getPostGreDbSchema()); + list.add(table); + } + }, + /* POSITION()函数返回一个整数,该整数表示子字符串在字符串中的位置。如果在字符串中未找到子字符串,则POSITION()函数将返回零(0)。 + 如果子字符串或字符串参数为null,则返回null */ + TABLES( + "SELECT\n" + + " pt.*,\n" + + " pg_tab.relname AS " + DbAliasEnum.TABLE_NAME.getAlias() + ",\n" + + " pg_tab.reltuples AS " + DbAliasEnum.TABLE_SUM.getAlias() + ",\n" + + " pg_tab.nspname,\n" + + " CAST ( obj_description ( pg_tab.relfilenode, 'pg_class' ) AS VARCHAR ) AS " + DbAliasEnum.TABLE_COMMENT.getAlias() + "\n" + + "FROM\n" + + " pg_tables pt\n" + + "LEFT JOIN \n" + + "(SELECT \n" + + " * \n" + + "FROM\n" + + " pg_class pc\n" + + "LEFT JOIN \n" + + " pg_namespace pns\n" + + "ON\n" + + " pns.oid = pc.relnamespace\n" + + "WHERE\n" + + " pns.nspname = " + ParamEnum.DB_SCHEMA.getParamSign() + ") AS pg_tab\n" + + "ON\n" + + " pt.tablename = pg_tab.relname\n" + + "WHERE pt.schemaname = " + ParamEnum.DB_SCHEMA.getParamSign() + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getPostGreDbSchema()); + list.add(dbStruct.getPostGreDbSchema()); + } + }, + /* POSITION()函数返回一个整数,该整数表示子字符串在字符串中的位置。如果在字符串中未找到子字符串,则POSITION()函数将返回零(0)。 + 如果子字符串或字符串参数为null,则返回null */ + TABLESANDVIEW( + "SELECT viewname as " + DbAliasEnum.TABLE_NAME.getAlias() + ", 'VIEW' as " + DbAliasEnum.TABLE_TYPE.getAlias() + " FROM pg_views WHERE schemaname = " + ParamEnum.DB_SCHEMA.getParamSign() + "\n" + + "UNION\n" + + "SELECT tablename as " + DbAliasEnum.TABLE_NAME.getAlias() + ",'TABLE' as " + DbAliasEnum.TABLE_TYPE.getAlias() + " FROM pg_tables WHERE schemaname = " + ParamEnum.DB_SCHEMA.getParamSign() + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getPostGreDbSchema()); + list.add(dbStruct.getPostGreDbSchema()); + } + }, + TABLE( + TABLES.sqlFrame + " AND pg_tab.relname = " + ParamEnum.TABLE.getParamSign() + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getPostGreDbSchema()); + list.add(dbStruct.getPostGreDbSchema()); + list.add(table); + } + }, + EXISTS_TABLE( + "SELECT COUNT (*) AS TOTAL \n" + + "FROM\n" + + "( \n" + + " SELECT relname AS F_TABLE_NAME FROM pg_class C WHERE relname = lower(" + ParamEnum.TABLE.getParamSign() + ") AND relnamespace IN \n" + + " ( \n" + + " SELECT oid FROM pg_namespace WHERE nspname = " + ParamEnum.DB_SCHEMA.getParamSign() + "\n" + + " ) \n" + + ") AS COUNT_TAB" + ){ + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(table); + list.add(dbStruct.getPostGreDbSchema()); + } + }, + + /* =============================== 定义语句 ==================================== */ + // (Data Definition Language)简称 DDL:用来建立数据库、数据库对象和定义列的命令。包括:create、alter、drop + /** + * 建表语句 + */ + CREATE( + "CREATE TABLE 《schema》.{table}(\n" + + "【 " + + "1:(PRIMARY KEY ({primaryColumn}))|" + + "2:({column} {dataType} [[NOT] [NULL]] [DEFAULT {defaultValue}])" + + ",\n】)" + ), + // SERIAL自增标识,自增时:1、不定义数据类型;2、不定义默认值;3、非空; + CREATE_TABLE ("
《schema》.{table} <(>\n" + + "【{column} {dataType} [[NOT] [NULL]] [ {defaultValue}] 】" + + "\n{primarykeys}" + + "\n<)>"){ + @Override + public String createIncrement(String sqlFrame, Map paramsMap) { + // 自增标识:SERIAL + if(StringUtil.isNotEmpty(paramsMap.get("[AUTO_INCREMENT]"))){ + sqlFrame = super.createIncrement(sqlFrame, paramsMap) + .replace("{dataType}", "[SERIAL]"); + } + return sqlFrame; + } + + + public String createIndex(){ + String model = "CREATE UNIQUE INDEX {indexName} ON {table}(【column】)"; + + + return null; + } + + + }, + COMMENT_TABLE ("COMMENT ON TABLE 《schema》.{table} IS {comment}"), + COMMENT_COLUMN ("COMMENT ON COLUMN 《schema》.{table}.{column} IS {comment}"), + DROP_TABLE ("DROP TABLE IF EXISTS 《schema》.{table}"), + ADD_COLUMN ("
《schema》.{table} ADD {column} {dataType}"), + DROP_COLUMN ("ALTER TABLE 《schema》.{table} DROP {column}"), + MODIFY_TYPE ("
《schema》.{table} {column} {dataType}"), + RE_COLUMN_NAME ("
《schema》.{table} RENAME {oldColumn} {newColumn}"), + RE_TABLE_NAME ("
《schema》.{oldTable} RENAME {newTable}"), + /** + * 修改: NOT NULL 约束 + */ + ALTER_NOT_NULL ("
《schema》.{table} {column} {datatype} [[NOT] [NULL]]"), + /** + * 修改: 默认值 + */ + ALTER_DEFAULT ("
《schema》.{table} {column} {defaultValue}"), + /** + * 添加: 主键约束 + */ + ALTER_PRIMARY ("
《schema》.{table} CONSTRAINT {primaryKey} PRIMARY KEY (【{column},】)"), + + /* =============================== DML操作语句 ==================================== */ + // (Data Manipulation Language)简称 DML:用来操纵数据库中数据的命令。包括:select、insert、update、delete。 + INSERT ("INSERT INTO 《schema》.{table}(【{column},】) VALUES (【{value},】)"), + DELETE_INFO ("DELETE FROM 《schema》.{table} WHERE {column} = {value}"), + ORDER_PAGE ("{selectSql} ORDER BY {orderColumn} [DESC] LIMIT {pageSize} OFFSET {beginIndex}"), + + /* =============================== 其他 ==================================== */ + + + CREATE_DATABASE("CREATE DATABASE \"{database}\""), + DROP_DATABASE("DROP DATABASE [IF EXISTS] {database}"), + CREATE_SCHEMA("CREATE SCHEMA \"{schema}\";"), + DROP_SCHEMA("DROP SCHEMA \"{schema}\" CASCADE"), + ; + + private String sqlFrame; + private final String dbEncode = DbBase.POSTGRE_SQL; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlSQLServerEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlSQLServerEnum.java new file mode 100644 index 0000000..42b9da8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/SqlSQLServerEnum.java @@ -0,0 +1,233 @@ +package com.yunzhupaas.database.sql.enums; + +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.enums.ParamEnum; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.enums.base.SqlFrameBase; +import com.yunzhupaas.database.sql.model.DbStruct; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; +import java.util.Map; + +/** + * SqlServer SQL语句模板 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/30 + */ +@Getter +@AllArgsConstructor +public enum SqlSQLServerEnum implements SqlFrameBase { + + /* =============================== 系统语句 ==================================== */ + FIELDS("SELECT cast(a.name as varchar(50)) " + DbAliasEnum.FIELD.getAlias() + " ," + + " cast(case when exists(SELECT 1 FROM sysobjects where xtype='PK' and name in ( " + + " SELECT name FROM sysindexes WHERE indid in( " + + " SELECT indid FROM sysindexkeys WHERE id = a.id AND colid=a.colid ))) " + + " then '1' else '0' end as varchar(50)) " + DbAliasEnum.PRIMARY_KEY.getAlias() + ", " + + " cast(b.name as varchar(50)) " + DbAliasEnum.DATA_TYPE.getAlias() + ", " + + // " cast(COLUMNPROPERTY(a.id,a.name,'PRECISION') as varchar(50)) " + + // DbAliasConst.DATA_LENGTH + ", " + + " a.length " + DbAliasEnum.CHAR_LENGTH.getAlias() + ", " + + " a.xprec " + DbAliasEnum.NUM_PRECISION.getAlias() + ", " + + " a.xscale " + DbAliasEnum.NUM_SCALE.getAlias() + ", " + + " h.is_identity " + DbAliasEnum.IS_IDENTITY.getAlias() + ", " + + " cast(case when a.isnullable=0 then '0'else '1' end as varchar(50)) " + DbAliasEnum.ALLOW_NULL.getAlias() + + ", " + + " cast(isnull(e.text,'') as varchar(50)) " + DbAliasEnum.DEFAULT_VALUE.getAlias() + ", " + + " cast(isnull(g.[value],'') as varchar(50)) " + DbAliasEnum.FIELD_COMMENT.getAlias() + + "\nFROM syscolumns a " + + "left join systypes b on a.xusertype=b.xusertype " + + "inner join sysobjects d on a.id=d.id and (d.xtype='U' or d.xtype='V') and d.name<>'dtproperties' " + + "left join syscomments e on a.cdefault=e.id " + + "left join sys.extended_properties g on a.id=g.major_id and a.colid=g.minor_id " + + "left join sys.extended_properties f on d.id=f.major_id and f.minor_id=0 " + + "left join sys.columns h ON d.id= h.object_id and a.name = h.name " + + "where d.name = " + ParamEnum.DB_NAME.getParamSign() + + "\norder by a.id,a.colorder") { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(table); + } + }, + TABLES( + "SET NOCOUNT ON DECLARE\n" + + "@TABLEINFO TABLE (\n" + + "\tNAME VARCHAR ( 50 ),\n" + + "\tSUMROWS VARCHAR ( 11 ),\n" + + "\tRESERVED VARCHAR ( 50 ),\n" + + "\tDATA VARCHAR ( 50 ),\n" + + "\tINDEX_SIZE VARCHAR ( 50 ),\n" + + "\tUNUSED VARCHAR ( 50 ),\n" + + "\tPK VARCHAR ( 50 ) \n" + + ") DECLARE\n" + + "@TABLENAME TABLE ( NAME VARCHAR ( 50 ) ) DECLARE\n" + + "@NAME VARCHAR ( 50 ) DECLARE\n" + + "@PK VARCHAR ( 50 ) INSERT INTO @TABLENAME ( NAME ) SELECT\n" + + "O.NAME \n" + + "FROM\n" + + "\tsysobjects O,\n" + + "\tsysindexes I \n" + + "WHERE\n" + + "\tO.ID = I.ID \n" + + "\tAND O.XTYPE = 'U' \n" + + "\tAND I.INDID < 2 \n" + + "\tAND O.UID = (SELECT schema_id FROM sys.schemas where name = " + + ParamEnum.DB_SCHEMA.getParamSign() + ")\n" + + "ORDER BY\n" + + "\tI.ROWS DESC,\n" + + "\tO.NAME\n" + + "WHILE\n" + + "\t\tEXISTS ( SELECT 1 FROM @TABLENAME ) BEGIN\n" + + "\t\tSELECT TOP\n" + + "\t\t\t1 @NAME = NAME \n" + + "\t\tFROM\n" + + "\t\t\t@TABLENAME DELETE @TABLENAME \n" + + "\t\tWHERE\n" + + "\t\t\tNAME = @NAME DECLARE\n" + + "\t\t\t@OBJECTID INT \n" + + "\t\t\tSET @OBJECTID = OBJECT_ID( @NAME ) SELECT\n" + + "\t\t\t@PK = COL_NAME( @OBJECTID, COLID ) \n" + + "\t\tFROM\n" + + "\t\t\tsysobjects AS O\n" + + "\t\t\tINNER JOIN sysindexes AS I ON I.NAME = O.NAME\n" + + "\t\t\tINNER JOIN sysindexkeys AS K ON K.INDID = I.INDID \n" + + "\t\tWHERE\n" + + "\t\t\tO.XTYPE = 'PK' \n" + + "\t\t\tAND PARENT_OBJ = @OBJECTID \n" + + "\t\t\tAND K.ID = @OBJECTID INSERT INTO @TABLEINFO ( NAME, SUMROWS, RESERVED, DATA, INDEX_SIZE, UNUSED ) EXEC sys.sp_spaceused @NAME UPDATE @TABLEINFO \n" + + + "\t\t\tSET PK = @PK \n" + + "\t\tWHERE\n" + + "\t\t\tNAME = @NAME \n" + + "\tEND SELECT CAST\n" + + "\t\t( F.NAME AS VARCHAR ( 50 ) ) " + DbAliasEnum.TABLE_NAME.getAlias() + ",\n" + + "\t\tCAST ( ISNULL( P.TDESCRIPTION, F.NAME ) AS VARCHAR ( 50 ) ) " + + DbAliasEnum.TABLE_COMMENT.getAlias() + ",\n" + + "\t\tCAST ( F.RESERVED AS VARCHAR ( 50 ) ) " + DbAliasEnum.TABLE_SIZE.getAlias() + ",\n" + + "\t\tCAST ( RTRIM( F.SUMROWS ) AS VARCHAR ( 50 ) ) " + DbAliasEnum.TABLE_SUM.getAlias() + ",\n" + + "\t\tCAST ( F.PK AS VARCHAR ( 50 ) ) " + DbAliasEnum.PRIMARY_KEY.getAlias() + " \n" + + "\tFROM\n" + + "\t\t@TABLEINFO F\n" + + "\t\tLEFT JOIN (\n" + + "\t\tSELECT\n" + + "\t\t\tNAME =\n" + + "\t\tCASE\n" + + "\t\t\t\t\n" + + "\t\t\t\tWHEN A.COLORDER = 1 THEN\n" + + "\t\t\t\tD.NAME ELSE '' \n" + + "\t\t\tEND,\n" + + "\t\t\tTDESCRIPTION =\n" + + "\t\tCASE\n" + + "\t\t\t\t\n" + + "\t\t\t\tWHEN A.COLORDER = 1 THEN\n" + + "\t\t\t\tISNULL( F.VALUE, '' ) ELSE '' \n" + + "\t\t\tEND \n" + + "\t\t\tFROM\n" + + "\t\t\t\tsyscolumns A\n" + + "\t\t\t\tLEFT JOIN systypes B ON A.XUSERTYPE = B.XUSERTYPE\n" + + "\t\t\t\tINNER JOIN sysobjects D ON A.ID = D.ID \n" + + "\t\t\t\tAND D.XTYPE = 'U' \n" + + "\t\t\t\tAND D.NAME <> 'DTPROPERTIES'\n" + + "\t\t\t\tLEFT JOIN sys.extended_properties F ON D.ID = F.MAJOR_ID \n" + + "\t\t\tWHERE\n" + + "\t\t\t\tA.COLORDER = 1 \n" + + "\t\t\t\tAND F.MINOR_ID = 0 \n" + + "\t\t\t) P ON F.NAME = P.NAME \n" + + "\t\tWHERE\n" + + "\t\t\t1 = 1 \n" + + "\tORDER BY\n" + + "\t" + DbAliasEnum.TABLE_NAME.getAlias()) { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getSqlServerDbSchema()); + } + }, + TABLESANDVIEW( + "SELECT s.Name as " + DbAliasEnum.TABLE_NAME.getAlias() + + ",Convert(varchar(max),tbp.value) as " + DbAliasEnum.TABLE_COMMENT.getAlias() + + ",s.type as " + DbAliasEnum.TABLE_TYPE.getAlias() + + "\nFROM sysobjects s\n" + + "LEFT JOIN sys.extended_properties as tbp ON s.id=tbp.major_id and tbp.minor_id=0 AND (tbp.Name='MS_Description' OR tbp.Name is null) WHERE s.xtype IN('V','U')") { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getSqlServerDbSchema()); + } + }, + TABLE( + TABLES.sqlFrame.replace("1 = 1", "F.NAME = " + ParamEnum.TABLE.getParamSign())) { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(dbStruct.getSqlServerDbSchema()); + list.add(table); + } + }, + EXISTS_TABLE( + "SELECT COUNT (*) AS TOTAL FROM (" + + "SELECT table_name FROM INFORMATION_SCHEMA.TABLES where table_type = 'BASE TABLE' and TABLE_NAME = " + + ParamEnum.TABLE.getParamSign() + + ") AS COUNT_TAB") { + @Override + public void setStructParams(String table, DbStruct dbStruct, List list) { + list.add(table); + } + }, + + /* =============================== 定义语句 ==================================== */ + CREATE_TABLE(SqlDMEnum.CREATE_TABLE.getSqlFrame()) { + @Override + public String createIncrement(String sqlFrame, Map paramsMap) { + return SqlDMEnum.CREATE_TABLE.createIncrement(sqlFrame, paramsMap); + } + }, + // (Data Definition Language)简称 DDL:用来建立数据库、数据库对象和定义列的命令。包括:create、alter、drop + RE_TABLE_NAME("EXEC sp_rename {oldTable}, {newTable}"), + + COMMENT_TABLE("EXEC sp_addextendedproperty 'MS_Description',N'{comment}','SCHEMA',N'dbo','TABLE',N'{table}'"), + COMMENT_COLUMN( + "EXEC sp_addextendedproperty 'MS_Description',N'{comment}','SCHEMA',N'dbo','TABLE',N'{table}','COLUMN',N'{column}'"), + ALTER_COLUMN("
{table} {column} {dataType} [[NOT] [NULL]] [ {defaultValue}]"), + + /* + * =============================== DML操作语句 ==================================== + */ + // (Data Manipulation Language)简称 + // DML:用来操纵数据库中数据的命令。包括:select、insert、update、delete。 + + /* 第二种方式:offset fetch next方式(SQL2012以上的版本才支持:推荐使用 )- */ + SELECT_PAGE_NEW("{selectSql} [orderSql] OFFSET {beginIndex} rows fetch next {pageSize} rows only"), + /* + * row_number() over(order by {column}) + * row_number() over(order by RAND()) 随机字段 + * row_number() over(order by NEWID()) 临时ID + */ + ORDER_PAGE("SELECT * " + + "FROM " + + "(SELECT TOP {endIndex} ROW_NUMBER() OVER(ORDER BY {orderColumn}) YUNZHUPAAS_ROW,* " + + "FROM " + + "({selectSql}) AS YUNZHUPAAS_TAB ORDER BY YUNZHUPAAS_ROW) AS YUNZHUPAAS_TEMP_TABLE " + + "WHERE " + + "YUNZHUPAAS_ROW BETWEEN ({beginIndex}+1) AND {endIndex}"), + // offset /fetch next关键字 2012版本及以上才有 + ORDER_PAGE2( + "SELECT \n" + + "\t*\n" + + "FROM\n" + + "\t({selectSql}) AS YUNZHUPAAS_TAB \n" + + "ORDER BY\n" + + "\t{orderColumn} \n" + + "OFFSET {beginIndex} ROWS FETCH NEXT {pageSize} ROWS ONLY"), + DB_TIME_SQL("Select CONVERT(varchar(100), GETDATE(), 120) as TIME"), + + /* =============================== 其他 ==================================== */ + + ; + + public String sqlFrame; + private final String dbEncode = DbBase.SQL_SERVER; + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/base/SqlComEnum.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/base/SqlComEnum.java new file mode 100644 index 0000000..8273631 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/base/SqlComEnum.java @@ -0,0 +1,302 @@ +package com.yunzhupaas.database.sql.enums.base; + +import com.yunzhupaas.database.model.dto.PrepSqlDTO; +import com.yunzhupaas.database.model.interfaces.DbSourceOrDbLink; +import com.yunzhupaas.database.sql.enums.*; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * 通用 SQL语句模板 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/17 + */ +@Getter +@AllArgsConstructor +public enum SqlComEnum implements SqlFrameBase { + + /* + * []:可选、<>:必填 《》:配置开关填写、{}:参数、【】:循环 N:(选择框架 ========================================= + */ + /* =============================== 系统语句 ==================================== */ + TABLES( SqlMySQLEnum.TABLES, + SqlOracleEnum.TABLES, + SqlSQLServerEnum.TABLES, + SqlDMEnum.TABLES, + SqlKingbaseESEnum.TABLES, + SqlPostgreSQLEnum.TABLES + ), + TABLESANDVIEW( SqlMySQLEnum.TABLESANDVIEW, + SqlOracleEnum.TABLESANDVIEW, + SqlSQLServerEnum.TABLESANDVIEW, + SqlDMEnum.TABLESANDVIEW, + SqlKingbaseESEnum.TABLESANDVIEW, + SqlPostgreSQLEnum.TABLESANDVIEW + ), + TABLE( SqlMySQLEnum.TABLE, + SqlOracleEnum.TABLE, + SqlSQLServerEnum.TABLE, + SqlDMEnum.TABLE, + SqlKingbaseESEnum.TABLE, + SqlPostgreSQLEnum.TABLE + ), + FIELDS( SqlMySQLEnum.FIELDS, + SqlOracleEnum.FIELDS, + SqlSQLServerEnum.FIELDS, + SqlDMEnum.FIELDS, + SqlKingbaseESEnum.FIELDS, + SqlPostgreSQLEnum.FIELDS + ), + EXISTS_TABLE( SqlMySQLEnum.EXISTS_TABLE, + SqlOracleEnum.EXISTS_TABLE, + SqlSQLServerEnum.EXISTS_TABLE, + SqlDMEnum.EXISTS_TABLE, + SqlKingbaseESEnum.EXISTS_TABLE, + SqlPostgreSQLEnum.EXISTS_TABLE + ), + /* =============================== 定义语句 ==================================== */ + // (Data Definition Language)简称 DDL:用来建立数据库、数据库对象和定义列的命令。包括:create、alter、drop + /** + * 创表 + */ + CREATE_TABLE (SqlOracleEnum.CREATE_TABLE, + Arrays.asList( + "{table}", + "{column}", + "{dataType}", + "[ {defaultValue}]", + "[[NOT] [NULL]]", + "[AUTO_INCREMENT]", + "[ {comment}]", + "{primarykeys}" + ), + SqlMySQLEnum.CREATE_TABLE, + SqlSQLServerEnum.CREATE_TABLE, + SqlDMEnum.CREATE_TABLE, + SqlKingbaseESEnum.CREATE_TABLE, + SqlPostgreSQLEnum.CREATE_TABLE + ), + ADD_COLUMN (SqlMySQLEnum.ALTER_ADD_MODIFY, + Arrays.asList( + "", + "{table}", + "{column}", + "{dataType}", + "[[NOT] [NULL]]", + "[ {defaultValue}]", + "{comment}" + ), + SqlOracleEnum.ADD_COLUMN, + SqlPostgreSQLEnum.ADD_COLUMN, + SqlDMEnum.ALTER_ADD, + SqlKingbaseESEnum.ALTER_ADD, + SqlSQLServerEnum.ALTER_COLUMN + ), + /** + * 删除表 + */ + DROP_TABLE (SqlOracleEnum.DROP_TABLE, + Arrays.asList( + "{table}" + ), + SqlMySQLEnum.DROP_TABLE + ), + /** + * 表重命名 + */ + RE_TABLE_NAME (SqlMySQLEnum.RE_TABLE_NAME, + Arrays.asList( + "{oldTable}", + "{newTable}" + ), + SqlKingbaseESEnum.RE_TABLE_NAME, + SqlPostgreSQLEnum.RE_TABLE_NAME, + SqlSQLServerEnum.RE_TABLE_NAME + ), + /** + * 表注释 + */ + COMMENT_TABLE (SqlOracleEnum.COMMENT_TABLE, + Arrays.asList( + "{table}", + "'{comment}'" + ), + SqlMySQLEnum.COMMENT_TABLE, + SqlSQLServerEnum.COMMENT_TABLE + ), + /** + * 字段注释 + */ + COMMENT_COLUMN (SqlOracleEnum.COMMENT_COLUMN, + Arrays.asList( + "{table}", + "{column}", + "'{comment}'", + "{dataType}", + "[DEFAULT {defaultValue}]" + ), + SqlMySQLEnum.COMMENT_COLUMN, + SqlSQLServerEnum.COMMENT_COLUMN + ), + /* =============================== DML操作语句 ==================================== */ + // (Data Manipulation Language)简称 DML:用来操纵数据库中数据的命令。包括:select、insert、update、delete。 + /** + * 获取表数据SQL + */ + SELECT_TABLE (SqlMySQLEnum.SELECT_TABLE, + Arrays.asList( + "{table}" + ) + ), + COUNT_SIZE (SqlMySQLEnum.COUNT_SIZE, + Arrays.asList( + "{totalAlias}", + "{selectSql}" + ) + ), + COUNT_SIZE_TABLE(SqlMySQLEnum.COUNT_TABLE_SIZE, + Arrays.asList( + "{totalAlias}", + "{table}" + ) + ), + INSERT (SqlMySQLEnum.INSERT, + Arrays.asList( + "{table}", + "[【{column},】]", + "【{value},】" + ) + ), + DELETE_ALL (SqlMySQLEnum.DELETE_ALL, + Collections.singletonList( + "{table}" + ) + + ), + /* =============================== 后缀 ==================================== */ + /** + * beginIndex(起始下标) + * = (currentPage - 1) * pageSize(当前页 * 页大小) + * endIndex(结束下标) + * = currentPage * pageSize + * 先查询还是先排序 + */ + ORDER_PAGE (SqlMySQLEnum.ORDER_PAGE, + Arrays.asList( + "{selectSql}", + "{orderColumn}", + "{beginIndex}", + "{endIndex}", + "{pageSize}", + "[DESC]" + ), + SqlOracleEnum.ORDER_PAGE, + SqlSQLServerEnum.ORDER_PAGE, + SqlPostgreSQLEnum.ORDER_PAGE + ), + /** + * ASC(ascend):升序 1234 放空默认 + * DESC(descend):降序 4321 + */ + ORDER (SqlMySQLEnum.ORDER, + Arrays.asList( + "{column}", + "[DESC]" + ) + ), + /** + * 模糊查询 + * * : 多字符, c*c代表cc,cBc,cbc,cabdfec等 + * % : 多个字符, %c%代表agdcagd等 + * ? : 单个字符, %c%代表agdcagd等 + * # : 单数字, k#k代表k1k,k8k,k0k + * [*] : 特殊字符, a[*]a代表a*a + * [a-z] : 字符范围, [a-z]代表a到z的26个字母中任意一个 指定一个范围中任意一个 + */ + LIKE (SqlMySQLEnum.LIKE, + Arrays.asList( + "{selectSql}", + "{column}", + "{condition}" + ) + ), + + + ; + + private String sqlFrame; + private SqlFrameBase baseSqlEnum; + private List frameEnums; + private List frameParamList; + private final String dbEncode = "common"; + + /** + * 构造 + * @param baseSqlEnum 基础枚举(其他数据库没有独特SQL,遵循这个枚举的SQL) + */ + SqlComEnum(SqlFrameBase baseSqlEnum, List frameParamList) { + this.baseSqlEnum = baseSqlEnum; + this.sqlFrame = baseSqlEnum.getSqlFrame(); + this.frameParamList = frameParamList; + this.frameEnums = new ArrayList<>(); + this.frameEnums.add(baseSqlEnum); + } + + /** + * 构造 + * @param frameEnums 不同库自身对应的SQL框架 + */ + SqlComEnum(SqlFrameBase baseSqlEnum, List frameParamList, SqlFrameBase... frameEnums) { + this.baseSqlEnum = baseSqlEnum; + this.sqlFrame = baseSqlEnum.getSqlFrame(); + this.frameParamList = frameParamList; + List frameEnumsList = new ArrayList<>(Arrays.asList(frameEnums)); + frameEnumsList.add(baseSqlEnum); + this.frameEnums = frameEnumsList; + } + + SqlComEnum(SqlFrameBase... frameEnums) { + this.frameEnums = Arrays.asList(frameEnums); + } + + /** + * 获取子类的枚举 + * @return 返回子类枚举 + */ + public SqlFrameBase getSqlFrameEnum(String dbEncode){ + if(this.getFrameEnums() != null){ + for (SqlFrameBase sqlEnum : this.getFrameEnums()) { + if(sqlEnum.getDbEncode().equals(dbEncode)){ + return sqlEnum; + } + } + } + return null; + } + + public SqlFrameBase getSqlFrameEnum(SqlFrameBase sqlFrameBase){ + if(this.getFrameEnums() != null){ + for (SqlFrameBase sqlEnum : this.getFrameEnums()) { + if(sqlEnum.equals(sqlFrameBase)){ + return sqlEnum; + } + } + } + return null; + } + + public PrepSqlDTO getPrepSqlDto(DbSourceOrDbLink dataSourceMod, String table){ + SqlFrameBase sysTemSqlEnum = getSqlFrameEnum(dataSourceMod.init().getDbType()); + return sysTemSqlEnum.getPrepSqlDto(dataSourceMod, table); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/base/SqlFrameBase.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/base/SqlFrameBase.java new file mode 100644 index 0000000..b13147a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/enums/base/SqlFrameBase.java @@ -0,0 +1,146 @@ +package com.yunzhupaas.database.sql.enums.base; + +import com.yunzhupaas.database.model.dto.PrepSqlDTO; +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.model.interfaces.DbSourceOrDbLink; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.model.DbStruct; +import com.yunzhupaas.database.sql.util.SqlFrameUtil; +import com.yunzhupaas.database.util.DbTypeUtil; +import com.yunzhupaas.database.util.TenantDataSourceUtil; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.StringUtil; + +import java.util.*; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 + */ +public interface SqlFrameBase { + + /** + * 获取SQL框架 + * @return ignore + */ + String getSqlFrame(); + + /** + * 获取数据库编码 + * @return ignore + */ + String getDbEncode(); + + /** + * 获取枚举名 + * @return ignore + */ + String name(); + + /** + * 设置结构性参数 + * @param table 表 + * @param dbStruct 结构模型 + * @param list 参数 + */ + default void setStructParams(String table, DbStruct dbStruct, List list){} + + /** + * 获取数据库结构性参数 + * @param table 表 + * @return 结构参数 + */ + default PrepSqlDTO getPrepSqlDto(DbSourceOrDbLink dataSourceMod, String table){ + List list = new ArrayList<>(); + TenantDataSourceUtil.initDataSourceTenantDbName(dataSourceMod); + setStructParams(table, dataSourceMod.getDbStruct(), list); + return new PrepSqlDTO(getSqlFrame(), list).withConn((DbLinkEntity) dataSourceMod); + } + + /** + * 自动获取数据库SQL框架处理 + * 下标(在SQL框架枚举里面找对应关系) + * @param params 参数集 + * @return ignore + */ + default String getOutSql(String... params) throws DataException { + return getOutSqlByDb(null, params); + } + + /** + * 指定数据库SQL框架处理 + * @param params SQL参数 + * @return SQL语句 + * @throws DataException 枚举使用限制 + */ + default String getOutSqlByDb(String dbEncode, String... params) throws DataException { + SqlComEnum sqlComEnum = null; + SqlFrameBase sqlFrameBase = null; + /* 确定SQL框架枚举 */ + // 第一种:未明确引用枚举,提供数据库类型 + DbBase dbBase; + try{ + dbBase = DbTypeUtil.getEncodeDb(dbEncode); + }catch (Exception e){ + dbBase = null; + } + if(this instanceof SqlComEnum){ + sqlComEnum = ((SqlComEnum)this); + if(dbBase != null){ + sqlFrameBase = sqlComEnum.getSqlFrameEnum(dbEncode); + } + if(sqlFrameBase == null){ + sqlFrameBase = sqlComEnum.getBaseSqlEnum(); + } + // 第二种:明确引用枚举 + }else if(dbBase == null){ + for (SqlComEnum conEnum : SqlComEnum.values()) { + sqlFrameBase = conEnum.getSqlFrameEnum(this); + if(sqlFrameBase != null){ + sqlComEnum = conEnum; + break; + } + } + // 当引用枚举明确指出时,不允许引用其他枚举 + if(sqlFrameBase == null){throw new DataException("此枚举SQL框架未被引用");} + // 第三种:明确引用枚举,提供数据库类型(冲突) + }else { + throw new DataException("请使用SqlComEnum来做引用"); + } + return SqlFrameUtil.outSqlCommon(sqlFrameBase, sqlComEnum.getFrameParamList(), params); + } + + /** + * SQL框架的一些各自的特殊处理 + * @param sqlFrame SQL框架 + * @param paramsMap 对应提供参数集合 + * @return SQL语句 + */ + default String createIncrement(String sqlFrame, Map paramsMap){ + if (StringUtil.isNotEmpty(paramsMap.get("[AUTO_INCREMENT]"))){ + // 当自增时,字段非空且不需要默认值 + sqlFrame = sqlFrame + .replace("[[NOT] [NULL]]", "") + .replace("[ {defaultValue}]", ""); + } + return sqlFrame; + } + + default String createPrimaryKeys(String sqlFrame, Map paramsMap){ + String primaryStr = ""; + if (StringUtil.isNotEmpty(paramsMap.get("{primarykeys}"))){ + primaryStr = "\n, PRIMARY KEY (" + paramsMap.get("{primarykeys}") + ")"; + } + return sqlFrame.replace("{primarykeys}", primaryStr); + } + + default String createIndex(){ + return ""; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/model/DbStruct.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/model/DbStruct.java new file mode 100644 index 0000000..1c1928f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/model/DbStruct.java @@ -0,0 +1,92 @@ +package com.yunzhupaas.database.sql.model; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-10 + */ +@Data +public class DbStruct { + + /* ============= 通用 ============= */ + /** + * 用户名 + */ + private String userName; + + /** + * 表空间 + */ + private String dbTableSpace; + + /* ============= Mysql ============= */ + /** + * 库名 + * Mysql目前没有使用到模式 + */ + private String mysqlDbName; + + /* ============= Oracle ============= */ + /** + * 模式 + * Oracle目前没有使用库名 + * 与用户同名 + */ + private String oracleDbSchema; + + /** + * Oracle 额外参数 + */ + private String oracleParam; + /* ============= SqlServer ============= */ + /** + * 库名 + */ + private String sqlServerDbName; + /** + * 模式(暂时不使用) + * 默认:dbo + * 可选:guest + */ + private String sqlServerDbSchema = "dbo"; + + /* ============= Dm ============= */ + /** + * 模式 + * Dm目前没有使用库名 + * 与用户同名 + */ + private String dmDbSchema; + + /* ============= KingBase ============= */ + + /** + * 库名 + */ + private String kingBaseDbName; + /** + * 模式 + * 默认:public + */ + private String kingBaseDbSchema = "public"; + + /* ============= PostGre ============= */ + + /** + * 库名 + */ + private String postGreDbName; + /** + * 模式(暂时不使用) + * 默认:public + */ + private String postGreDbSchema = "public"; + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/model/SqlPrintHandler.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/model/SqlPrintHandler.java new file mode 100644 index 0000000..37353bd --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/model/SqlPrintHandler.java @@ -0,0 +1,228 @@ +package com.yunzhupaas.database.sql.model; + +import lombok.AccessLevel; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.Setter; +import lombok.ToString; +import org.springframework.stereotype.Component; + +import java.io.*; + +/** + * 打印SQL语句功能类 + * + * @author 云筑产品开发平台组 + * @version v3.4.5 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-12-06 + */ +@Component +@ToString +@Data +public class SqlPrintHandler { + + /** + * 打印使用的SQL + */ + private StringBuffer sql = new StringBuffer(); + private StringBuffer sql2 = new StringBuffer(); + + /** + * 将要转换成的数据库类型 + */ + private String toDbType; + + /** + * 创表开关 + */ + private Boolean creFlag = false; + + /** + * 注释开关 + */ + private Boolean commentFlag = false; + + /** + * 插入开关 + */ + private Boolean insertFlag = false; + + /** + * 打印开关 + */ + private Boolean printFlag = false; + + /** + * 执行开关 + */ + private Boolean executeFlag = true; + + /** + * 文件 + */ + @Setter(value = AccessLevel.NONE) + private File sqlFile; + + private File sqlFile2; + + /** + * 开启打印状态 + */ + public void start(String outPath, Boolean creFlag, Boolean commentFlag, Boolean insertFlag, String toDbType) throws Exception { + printFlag = true; + this.executeFlag = false; + this.sqlFile = formatOutPath(outPath); + this.creFlag = creFlag; + this.commentFlag = commentFlag; + this.insertFlag = insertFlag; + this.toDbType = toDbType; + } + + /** + * 格式化路径 + * @param outPath 输出路径 + */ + public static File formatOutPath(String outPath) throws Exception{ + File file = new File(outPath); + if(file.exists()){ + if(file.isDirectory()) { + return file; + }else if(file.isFile()){ + return new File(file.getParent()); + }else { + throw new Exception("路径异常"); + } + }else { + boolean flag = file.mkdir(); + if(!flag) throw new Exception("路径异常"); + return file; + } + } + + /** + * 关闭打印状态 + */ + public void close(){ + this.printFlag = false; + this.creFlag = false; + this.commentFlag = false; + this.insertFlag = false; + this.executeFlag = true; + this.sqlFile = null; + this.sqlFile2 = null; + clear(); + } + + private void clear(){ + this.sql = new StringBuffer(); + this.sql2 = new StringBuffer(); + } + + public void setToDbType(String toDbType){ + this.toDbType = toDbType; + } + + public void setFileName(String fileName){ + if(sqlFile.isFile()){ + sqlFile = new File(sqlFile.getPath().replace(sqlFile.getName(), fileName)); + }else if(this.sqlFile.isDirectory()){ + sqlFile = new File(sqlFile.getPath() + "/" + fileName); + } + } + + public Boolean creTable(String sql){ + if(this.printFlag && this.creFlag) this.sql.append(sql).append(";\n"); + return this.printFlag; + } + + public Boolean dropTable(String sql){ + if(this.printFlag && this.creFlag) this.sql.append(sql).append(";\n"); + return this.printFlag; + } + + public Boolean oracleAutoIncrement(String sql){ + if(this.printFlag) this.sql.append(sql).append(";\n"); + return this.printFlag; + } + + public Boolean comment(String sql){ + if(this.printFlag && this.commentFlag) this.sql.append(sql).append(";\n"); + return this.printFlag; + } + + public void deleteAllInfo(String sql){ + if(this.insertFlag) this.sql.append(sql).append(";\n"); + } + + public Boolean insert(String sql){ + if(this.printFlag && this.insertFlag) this.sql.append(sql); + return this.printFlag; + } + + /** + * Oracle使用 + */ + public void updateClob(String sql){ + if(this.insertFlag) this.sql2.append(";\n/\n").append(sql); + } + + public void tableInfo(String table){ + table = "-- ----------------------------\n" + + "-- 表名:" + table + "\n" + + "-- ----------------------------\n"; + if(insertFlag) this.sql.append(table); + } + + public SqlPrintHandler append(String sql){ + if(this.insertFlag) this.sql.append(sql); + return this; + } + + public void print() throws Exception { + if(printFlag){ + createSqlFile(sql.toString(), this.sqlFile); +// if(sqlFile2 != null) createSqlFile(sql2.toString(), this.sqlFile2); + } + // 打印完清理SQL语句 + clear(); + } + + private void createSqlFile(String outSql, File file) throws Exception { + OutputStream outputStream = new FileOutputStream(file); + String CHARSET_UTF8 = "UTF-8"; + OutputStreamWriter writer = new OutputStreamWriter(outputStream, CHARSET_UTF8); + writer.append(outSql); + writer.close(); + } + + /** + * 打开文件夹 + * @param folder 文件路径 + */ + public static void openDirectory(String folder) { + File file = new File(folder); + if (!file.exists()) { + return; + } + Runtime runtime = null; + try { + runtime = Runtime.getRuntime(); +// if (!SystemUtil.isWindows) { + if (true) { + runtime.exec("cmd /c start explorer " + folder); + } else { + // System.out.println("is linux"); + runtime.exec("nautilus " + folder); + } + } catch (IOException ex) { + ex.printStackTrace(); + } finally { + if (null != runtime) { + runtime.runFinalization(); + } + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlDM.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlDM.java new file mode 100644 index 0000000..642d130 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlDM.java @@ -0,0 +1,29 @@ +package com.yunzhupaas.database.sql.param; + +import com.alibaba.druid.proxy.jdbc.NClobProxyImpl; + +import java.io.BufferedReader; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version v3.4.5 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-12-06 + */ +public class FormatSqlDM { + + public static String getClob(NClobProxyImpl nClobProxy) throws Exception { + BufferedReader br = new BufferedReader(nClobProxy.getCharacterStream()); + String s = br.readLine(); + StringBuilder sb = new StringBuilder(); + while (s != null) {// 执行循环将字符串全部取出付值给StringBuffer由StringBuffer转成STRING + sb.append(s).append("\n"); + s = br.readLine(); + } + return sb.toString(); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlDoris.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlDoris.java new file mode 100644 index 0000000..63f8d25 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlDoris.java @@ -0,0 +1,63 @@ +package com.yunzhupaas.database.sql.param; + +import com.yunzhupaas.database.model.dbfield.DbFieldModel; +import com.yunzhupaas.database.model.dbtable.DbTableFieldModel; +import com.yunzhupaas.database.source.DbBase; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version v3.4.5 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-12-23 + */ +@Data +public class FormatSqlDoris { + + private String primaryField; + + /** + * 添加主键相关内容 + * @param sql 建表SQL + * @param dbTableFieldModel 表字段对象 + * @param dbType 数据类型 + * @return sql语句 + */ + public static String getPrimaryFieldSql(String sql, DbTableFieldModel dbTableFieldModel, String dbType){ + if(dbType.equals(DbBase.DORIS)) { + List dbFieldModelList = dbTableFieldModel.getDbFieldModelList(); + for (DbFieldModel dbFieldModel : dbFieldModelList) { + if (dbFieldModel.getIsPrimaryKey()) { + sql = sql.replace("{primary_column}", dbFieldModel.getField()); + } + } + sql = sql.replace("{tableComment}", dbTableFieldModel.getComment()); + } + return sql; + } + + + public static void orderUniqueColumn(String dbType, List columnSqlList, DbTableFieldModel dbTableFieldModel){ + if(dbType.equals(DbBase.DORIS)) { + for (DbFieldModel dbFieldModel : dbTableFieldModel.getDbFieldModelList()) { + if (dbFieldModel.getIsPrimaryKey()) { + for (int i = 0; i < columnSqlList.size(); i++) { + if(columnSqlList.get(i).contains("\t" + dbFieldModel.getField())){ + columnSqlList.add(0, columnSqlList.remove(i)); + } + } + } + } + + } + + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlKingbaseES.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlKingbaseES.java new file mode 100644 index 0000000..bd137e2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlKingbaseES.java @@ -0,0 +1,33 @@ +package com.yunzhupaas.database.sql.param; + +import com.yunzhupaas.database.constant.DbFieldConst; +import com.yunzhupaas.database.model.dbfield.JdbcColumnModel; +import com.yunzhupaas.database.source.DbBase; + +import java.util.Map; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version v3.4.5 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-12-06 + */ +public class FormatSqlKingbaseES { + + /** + * 非空时空串报错,因Oracle空串存储为NULL,用一个空格代替空串 + */ + public static void nullValue(String dbEncode, JdbcColumnModel model, Map map){ + if(DbBase.KINGBASE_ES.equals(dbEncode)){ + // 字符串类型 && 字符串不为空 && 空串 + if(model.getValue() instanceof String && model.getNullSign().equals(DbFieldConst.NOT_NULL) + && model.getValue().toString().equals("")){ + map.put(model.getField(), " "); + } + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlMySQL.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlMySQL.java new file mode 100644 index 0000000..6f00861 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlMySQL.java @@ -0,0 +1,56 @@ +package com.yunzhupaas.database.sql.param; + +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.database.datatype.db.DtMySQLEnum; +import com.yunzhupaas.database.model.dbfield.DbFieldModel; +import com.yunzhupaas.database.model.dbfield.JdbcColumnModel; +import com.yunzhupaas.exception.DataTypeException; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version v3.4.5 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-12-06 + */ +public class FormatSqlMySQL { + + /** + * 处理单引号 '' + */ + public static String singleQuotes(String value){ + return value.replace("'", "\\'"); + } + + /** + * Mysql一些类型的特殊处理 + */ + public static Object getMysqlValue(JdbcColumnModel dbColumnModel) { + return dbColumnModel.getValue(); + } + + public static void checkMysqlFieldPrimary(DbFieldModel field, String table) throws DataTypeException { + // Mysql对主键的一些限制 + if(field.getIsPrimaryKey()){ + // Mysql 字段为主键的时候,不能为BLOB/TEXT/tinytext的类型 + switch ((DtMySQLEnum)field.getDtModelDTO().getConvertTargetDtEnum()){ + case BLOB: + case TINY_TEXT: + case MEDIUM_TEXT: + case TEXT: + case LONG_TEXT: + throw new DataTypeException(MsgCode.DB014.get(table, field.getField(), field.getDtModelDTO().getDtEnum().getDataType())); + case VARCHAR: + // varchar作为主键的时候,长度不允许超过768 + if(field.getDtModelDTO().getCharLength() > 768L){ + field.getDtModelDTO().setCharLength(768L); + } + break; + default: + } + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlOracle.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlOracle.java new file mode 100644 index 0000000..75a42f9 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlOracle.java @@ -0,0 +1,186 @@ +package com.yunzhupaas.database.sql.param; + +import cn.hutool.core.util.HexUtil; +import com.yunzhupaas.constant.TableFieldsNameConst; +import com.yunzhupaas.database.constant.DbFieldConst; +import com.yunzhupaas.database.model.dbfield.DbFieldModel; +import com.yunzhupaas.database.model.dbfield.JdbcColumnModel; +import com.yunzhupaas.database.model.dbtable.DbTableFieldModel; +import com.yunzhupaas.database.model.dto.PrepSqlDTO; +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.enums.SqlOracleEnum; +import com.yunzhupaas.database.sql.model.SqlPrintHandler; +import com.yunzhupaas.database.sql.util.SqlFrameUtil; +import com.yunzhupaas.database.util.DbTypeUtil; +import com.yunzhupaas.database.util.JdbcUtil; +import com.yunzhupaas.database.util.NotTenantPluginHolder; +import com.yunzhupaas.util.context.SpringContext; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import oracle.sql.TIMESTAMP; + +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * Oracle一些语句的特殊处理 + * + * @author 云筑产品开发平台组 + * @version v3.4.5 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-12-06 + */ +@Data +public class FormatSqlOracle { + + private static SqlPrintHandler sqlPrintHandler = SpringContext.getBean(SqlPrintHandler.class); + + /** + * 时间格式化 + * "TO_DATE('2022-12-12 00:00:00','YYYY-MM-DD HH24:MI:SS')" + * to_date('2022-12-12 00:00:00', 'yyyy-mm-dd hh24:mi:ss') + */ + public static String dateTime(String dbEncode, String dateTime){ + if(DbBase.ORACLE.equals(dbEncode)){ + return "to_date(" + dateTime + ", 'yyyy-mm-dd hh24:mi:ss')"; + }else { + return dateTime; + } + } + + /** + * 格式Oracle时间戳类型 + */ + public static Object timestamp(Object value){ + if(value instanceof TIMESTAMP){ + try { + return ((TIMESTAMP)value).dateValue(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + return value; + } + + /** + * 非空时空串报错,因Oracle空串存储为NULL,用一个空格代替空串 + */ + public static void nullValue(String dbEncode, JdbcColumnModel model, Map map){ + if(DbBase.ORACLE.equals(dbEncode) || DbBase.DM.equals(dbEncode)){ + // 字符串类型 && 字符串不为空 && 空串 + if(model.getValue() instanceof String && model.getNullSign().equals(DbFieldConst.NOT_NULL) + && model.getValue().toString().equals("")){ + map.put(model.getField(), " "); + } + } + } + + /** + * 获取主键值 + */ + public static Function,Map.Entry> getPrimaryVal = (fieldMap)->{ + for (Map.Entry field : fieldMap.entrySet()) { + String primaryKey = field.getKey(); + if (primaryKey.equalsIgnoreCase(TableFieldsNameConst.F_ID) || primaryKey.equalsIgnoreCase(TableFieldsNameConst.ID) || primaryKey.equalsIgnoreCase("ID_")) { + return field; + } + } + return null; + }; + + public static Object clobExecute(String dbEncode, Object context, String table, String column, Map dataMap, StringBuilder sqlBuilder){ + if(DbBase.ORACLE.equals(dbEncode) && context instanceof String){ + Map.Entry field = FormatSqlOracle.getPrimaryVal.apply(dataMap); + if(field != null){ + String clobUpdateSql = FormatSqlOracle.clobUpdate(context.toString(), table, column, field.getKey(), field.getValue().toString()); + if(clobUpdateSql != null){ + sqlPrintHandler.updateClob(clobUpdateSql); + // 连续的匿名存储过程块,结尾都必须跟上 ; / 隔离 + sqlBuilder.append(clobUpdateSql).append(";\n/\n"); + return "context"; + } + } + } + return context; + } + + + public static Object blobExecute(String dbEncode, Object context, String table, String column, Map dataMap, StringBuilder sqlBuilder){ + if(DbBase.ORACLE.equals(dbEncode) && (context instanceof byte[])){ + Map.Entry field = FormatSqlOracle.getPrimaryVal.apply(dataMap); + if(field != null){ + String clobUpdateSql = FormatSqlOracle.blobUpdate(HexUtil.encodeHexStr((byte[]) context), table, column, field.getKey(), field.getValue().toString()); + if(clobUpdateSql != null){ + sqlPrintHandler.updateClob(clobUpdateSql); + // 连续的匿名存储过程块,结尾都必须跟上 ; / 隔离 + sqlBuilder.append(clobUpdateSql).append(";\n/\n"); + // 字符串0 HEX 30 + return "30"; + } + } + } + return context; + } + + /** + * Oracle处理超2000字符 + */ + public static String clobUpdate(String context, String table, String column, String primaryColumn, String primaryValue){ + if(context.length() > 1500){ + context = context.replace("'", "''"); + List splitStrList = SqlFrameUtil.splitStrRepeat(context, 1500); + StringBuilder contextInfo = new StringBuilder(); + for (String contextFragment : splitStrList) { + contextInfo.append("\t").append(SqlOracleEnum.CLOB_APPEND.getSqlFrame().replace("{context}", contextFragment)).append(";\n"); + } + return SqlOracleEnum.CLOB_UPDATE.getFastSql(Arrays.asList(table, column, contextInfo.toString(), primaryColumn, primaryValue)); + } else { + return null; + } + } + + + /** + * Oracle处理Blob + */ + public static String blobUpdate(String context, String table, String column, String primaryColumn, String primaryValue){ + context = context.replace("'", "''"); + List splitStrList = SqlFrameUtil.splitStrRepeat(context, 1500); + StringBuilder contextInfo = new StringBuilder(); + for (String contextFragment : splitStrList) { + contextInfo.append("\t").append(SqlOracleEnum.BLOB_APPEND.getSqlFrame().replace("{context}", contextFragment)).append(";\n"); + } + return SqlOracleEnum.BLOB_UPDATE.getFastSql(Arrays.asList(table, column, contextInfo.toString(), primaryColumn, primaryValue)); + } + + + public static void autoIncrement(DbLinkEntity dbLinkEntity, DbTableFieldModel dbTableFieldModel) throws Exception { + if (DbTypeUtil.checkOracle(dbLinkEntity)) { + String table = dbTableFieldModel.getTable(); + boolean autoInc = false; + String autoIncField = ""; + for (DbFieldModel dbFieldModel : dbTableFieldModel.getDbFieldModelList()) { + if(dbFieldModel.getIsAutoIncrement() != null && dbFieldModel.getIsAutoIncrement()){ + autoInc = true; + autoIncField = dbFieldModel.getField(); + } + } + if (autoInc) { + NotTenantPluginHolder.setNotSwitchFlag(); + String autoIncrement = SqlOracleEnum.CREATE_AUTO_INCREMENT.getSqlFrame().replace("{table}", table); + String autoIncrementTrigger = SqlOracleEnum.CREATE_AUTO_INCREMENT_TRIGGER.getSqlFrame().replace("{table}", table).replace("{autoInc_field}", autoIncField); + if(!sqlPrintHandler.oracleAutoIncrement(autoIncrement)){ + JdbcUtil.creUpDe(new PrepSqlDTO(autoIncrement).withConn(dbLinkEntity)); + NotTenantPluginHolder.setNotSwitchFlag(); + JdbcUtil.update(new PrepSqlDTO(autoIncrementTrigger).withConn(dbLinkEntity)); + } + } + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlPostgreSQL.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlPostgreSQL.java new file mode 100644 index 0000000..b812d56 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlPostgreSQL.java @@ -0,0 +1,13 @@ +package com.yunzhupaas.database.sql.param; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version v3.4.5 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-12-06 + */ +public class FormatSqlPostgreSQL { +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlSQLServer.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlSQLServer.java new file mode 100644 index 0000000..d221398 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/FormatSqlSQLServer.java @@ -0,0 +1,13 @@ +package com.yunzhupaas.database.sql.param; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version v3.4.5 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-12-06 + */ +public class FormatSqlSQLServer { +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/base/FormatSql.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/base/FormatSql.java new file mode 100644 index 0000000..321b810 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/param/base/FormatSql.java @@ -0,0 +1,125 @@ +package com.yunzhupaas.database.sql.param.base; + +import com.yunzhupaas.database.model.dbfield.DbFieldModel; +import com.yunzhupaas.database.model.dbfield.JdbcColumnModel; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.model.SqlPrintHandler; +import com.yunzhupaas.database.sql.param.FormatSqlMySQL; +import com.yunzhupaas.database.sql.param.FormatSqlOracle; +import com.yunzhupaas.util.context.SpringContext; +import lombok.AllArgsConstructor; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; + +/** + * 数据一些特殊处理 + * + * @author 云筑产品开发平台组 + * @version v3.4.5 + * @copyrignt 深圳市乐程软件有限公司 + * @date 2024-12-05 + */ +@Data +@AllArgsConstructor +public class FormatSql { + + + /* =========================== 字段值处理 ============================ */ + + public static Object convertValue(JdbcColumnModel dbColumnModel, DbBase toDb) throws Exception { + switch (toDb.getYunzhupaasDbEncode()){ + case DbBase.ORACLE: + case DbBase.POSTGRE_SQL: + return getPostgreValue(dbColumnModel); + case DbBase.MYSQL: + return FormatSqlMySQL.getMysqlValue(dbColumnModel); + default: + } + return dbColumnModel.getValue(); + } + + /** + * Postgre一些类型的特殊处理 + */ + public static Object getPostgreValue(JdbcColumnModel dbColumnModel) { +// DtInterface dtEnum = DtInterface.newInstance(dataType, DbBase.MYSQL, false); +// DtInterface toEnum = DtSyncUtil.getToFixCovert(dtEnum, DbBase.POSTGRE_SQL); + return dbColumnModel.getValue(); + } + + + + + private static SqlPrintHandler sqlPrintHandler = SpringContext.getBean(SqlPrintHandler.class); + + /** + * 数据库类型编码 + */ + private String dbEncode; + + public static String getFieldName(String fieldName, String dbEncode){ + switch (dbEncode){ + case DbBase.MYSQL: + return "`" + fieldName + "`"; + case DbBase.SQL_SERVER: + return fieldName; + case DbBase.ORACLE: + case DbBase.DM: + return "\"" + fieldName.toUpperCase() + "\""; + case DbBase.POSTGRE_SQL: + return "\"" + fieldName.toLowerCase() + "\""; + default: + return fieldName; + } + } + public static String formatValue(Object value, String dbEncode) { + // NULL空值 ======================================= + if(value == null){ + return "Null"; + // 时间值 ======================================= + }else if(value instanceof LocalDateTime || value instanceof Date){ + Date date; + if(value instanceof LocalDateTime){ + date = Date.from(((LocalDateTime)value).atZone(ZoneId.systemDefault()).toInstant()); + }else{ + date = (Date) value; + } + String dateInfo = "'" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date) + "'"; + // Oracle时间处理 + dateInfo = FormatSqlOracle.dateTime(dbEncode, dateInfo); + return dateInfo; + // 字符串值 ======================================= + }else if(value instanceof String){ + // 对单引号转义 :两个单引号 + String context = value.toString().replace("'", "''"); + return "'" + context + "'"; + // 数值 ======================================= + }else if(value instanceof Integer){ + return value.toString(); + } + return value.toString(); + } + + public static String defaultCheck(DbFieldModel fieldModel, String dbEncode){ + if(fieldModel.getDefaultValue() != null) { + String defaultValue = "'" + fieldModel.getDefaultValue() + "'"; + if(DbBase.ORACLE.equals(dbEncode)){ + fieldModel.setNullSign(""); + if(fieldModel.getDataType().equalsIgnoreCase("DATETIME")){ + defaultValue = "to_date(" + defaultValue + ", 'yyyy-mm-dd hh24:mi:ss')"; + } + } + return "DEFAULT " + defaultValue; + }else { + return ""; + } + } + +} + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/util/SqlFastUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/util/SqlFastUtil.java new file mode 100644 index 0000000..4e2b542 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/util/SqlFastUtil.java @@ -0,0 +1,365 @@ +package com.yunzhupaas.database.sql.util; + +import com.yunzhupaas.base.Pagination; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.database.constant.DbAliasConst; +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.model.dbfield.DbFieldModel; +import com.yunzhupaas.database.model.dbtable.DbTableFieldModel; +import com.yunzhupaas.database.model.dto.PrepSqlDTO; +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.sql.enums.SqlOracleEnum; +import com.yunzhupaas.database.sql.enums.base.SqlComEnum; +import com.yunzhupaas.database.sql.model.SqlPrintHandler; +import com.yunzhupaas.database.sql.param.FormatSqlOracle; +import com.yunzhupaas.database.sql.param.base.FormatSql; +import com.yunzhupaas.database.util.DbTypeUtil; +import com.yunzhupaas.database.util.JdbcUtil; +import com.yunzhupaas.database.util.NotTenantPluginHolder; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.context.SpringContext; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * 常用SQL快捷使用工具 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-11 + */ +@Slf4j +public class SqlFastUtil { + + private static SqlPrintHandler sqlPrintHandler = SpringContext.getBean(SqlPrintHandler.class); + + /** + * 添加表 + */ + public static void creTable(DbLinkEntity dbLinkEntity, DbTableFieldModel dbTableFieldModel) throws Exception { + List dbFieldModelList = dbTableFieldModel.getDbFieldModelList(); + // 生成表 + List fieldSqlList = new ArrayList<>(); + if(CollectionUtils.isNotEmpty(dbFieldModelList)){ + List primaryKeys = new ArrayList<>(); + for(DbFieldModel fieldModel : dbFieldModelList){ + String fieldSql = SqlComEnum.CREATE_TABLE.getOutSqlByDb( + dbLinkEntity.getDbType(), + // 表 + "", + // 字段 + FormatSql.getFieldName(fieldModel.getField(), dbLinkEntity.getDbType()), + // 数据类型 + fieldModel.formatDataTypeByView(dbLinkEntity.getDbType()), + // 默认值 + FormatSql.defaultCheck(fieldModel, dbLinkEntity.getDbType()), + // 非空(默认允空NULL) + fieldModel.getNullSign().equals(DbAliasConst.NOT_NULL) ? fieldModel.getNullSign() : "", + // 主键 + //fieldModel.getIsPrimaryKey() != null && fieldModel.getIsPrimaryKey() ? "PRIMARY KEY" : "", + // 自增 + fieldModel.getIsAutoIncrement() != null && fieldModel.getIsAutoIncrement() ? "AUTO_INCREMENT" : "", + // 注释 + "COMMENT '" + fieldModel.getComment() + "'" + ); + if(fieldModel.getIsPrimaryKey()){ + primaryKeys.add(fieldModel.getField()); + } + Matcher matcher = Pattern.compile("【([\\s\\S]+)】").matcher(fieldSql); + if (matcher.find()){ + String fieldSqlFragment = matcher.group(1); + fieldSqlList.add("\t" + (fieldSqlFragment.replaceAll("\\s+", " ").trim())); + } else { + throw new DataException(MsgCode.DB015.get()); + } + } + String sql = SqlComEnum.CREATE_TABLE.getOutSqlByDb(dbLinkEntity.getDbType(), + SqlFrameUtil.htmlE(dbTableFieldModel.getTable()), null, null, null, null, null, null, StringUtil.join(primaryKeys, ",")).replaceAll("【.+】", StringUtil.join(fieldSqlList, ",\n")); + NotTenantPluginHolder.setNotSwitchFlag(); + // 打印或生成 + if (!sqlPrintHandler.creTable(sql)) JdbcUtil.creUpDe(new PrepSqlDTO(sql).withConn(dbLinkEntity)); + // ORACLE特殊自增方式 + FormatSqlOracle.autoIncrement(dbLinkEntity, dbTableFieldModel); + }else { + throw new DataException(MsgCode.DB016.get()); + } + // 生成注释 + commentTable(dbLinkEntity, dbTableFieldModel.getTable(), dbTableFieldModel.getComment()); + if(!DbTypeUtil.checkMySQL(dbLinkEntity)){ + creTableCommentFiled(dbLinkEntity, dbTableFieldModel.getTable(), dbFieldModelList); + } + } + + /** + * 添加字段 + */ + public static List addField(DbLinkEntity dbLinkEntity, String table, List dbFieldModelList) throws Exception { + // 原表字段集合 + List originFieldList = getFieldList(dbLinkEntity, table); + List existsFieldFlagList = new ArrayList<>(); + for (DbFieldModel dbFieldModel : dbFieldModelList) { + boolean existsFieldFlag = false; + // 查询表添加这个的字段是否已存在,不存在则执行添加 + for (DbFieldModel originFile : originFieldList) { + if(originFile.getField().equalsIgnoreCase(dbFieldModel.getField())){ + existsFieldFlag = true; + break; + } + } + existsFieldFlagList.add(existsFieldFlag); + if(existsFieldFlag){ + continue; + } + String sql = SqlComEnum.ADD_COLUMN.getOutSqlByDb( + dbLinkEntity.getDbType(), + "ADD", + table, + dbFieldModel.getField(), + dbFieldModel.formatDataTypeByView(dbLinkEntity.getDbType()), + dbFieldModel.getNullSign(), + "", + "'" + dbFieldModel.getComment() + "'" + ); + NotTenantPluginHolder.setNotSwitchFlag(); + JdbcUtil.creUpDe(new PrepSqlDTO(sql).withConn(dbLinkEntity)); + // 字段注释 + if(!DbTypeUtil.checkMySQL(dbLinkEntity)){ + commentFiled(dbLinkEntity, table, dbFieldModel.getField(), dbFieldModel.getDataType(), dbFieldModel.getComment()); + } + } + return existsFieldFlagList; + } + + /** + * 删表 + */ + public static Boolean dropTable(DbLinkEntity dbLinkEntity, String table) throws Exception { + NotTenantPluginHolder.setNotSwitchFlag(); + String sql = SqlComEnum.DROP_TABLE.getOutSql(SqlFrameUtil.htmlE(table)); + int flag = 0; + if (!sqlPrintHandler.dropTable(sql)){ + flag = JdbcUtil.delete(new PrepSqlDTO(sql).withConn(dbLinkEntity)); + } + return flag > 0; + } + + /** + * 表重命名 + */ + public static Boolean reTableName(DbLinkEntity dbLinkEntity, String oldTable, String newTable) throws Exception { + NotTenantPluginHolder.setNotSwitchFlag(); + int i = JdbcUtil.creUpDe(new PrepSqlDTO(SqlComEnum.RE_TABLE_NAME.getOutSqlByDb(dbLinkEntity.getDbType(), oldTable, newTable)).withConn(dbLinkEntity)); + return i > 0; + } + + /** + * 表注释 + */ + public static Boolean commentTable(DbLinkEntity dbLinkEntity, String table, String comment) throws Exception { + String sql = SqlComEnum.COMMENT_TABLE.getOutSqlByDb(dbLinkEntity.getDbType(), SqlFrameUtil.htmlE(table), "'" + SqlFrameUtil.htmlE(comment) + "'"); + NotTenantPluginHolder.setNotSwitchFlag(); + if (!sqlPrintHandler.comment(sql)) JdbcUtil.creUpDe(new PrepSqlDTO(sql).withConn(dbLinkEntity)); + return true; + } + + /** + * 批量字段注释 + */ + private static Boolean creTableCommentFiled(DbLinkEntity dbLinkEntity, String table, List dbFieldModelList) throws Exception { + String dbEncode = dbLinkEntity.getDbType(); + for (DbFieldModel dbFieldModel : dbFieldModelList) { + String sql = SqlComEnum.COMMENT_COLUMN.getOutSqlByDb(dbEncode, + table, + FormatSql.getFieldName(dbFieldModel.getField(), dbEncode), + "'" + dbFieldModel.getComment() + "'", + dbFieldModel.formatDataTypeByView(dbEncode), + null); + if (!sqlPrintHandler.comment(sql)) JdbcUtil.update(new PrepSqlDTO(sql).withConn(dbLinkEntity)); + } + return true; + } + + /** + * 字段注释 + */ + public static Boolean commentFiled(DbLinkEntity dbLinkEntity, String table, String column, String dataType, String comment) throws Exception { + String sql = SqlComEnum.COMMENT_COLUMN.getOutSqlByDb(dbLinkEntity.getDbType(), table, column, "'" + comment + "'", dataType, null); + NotTenantPluginHolder.setNotSwitchFlag(); + int i = JdbcUtil.creUpDe(new PrepSqlDTO(sql).withConn(dbLinkEntity)); + return i > 0; + } + + /** + * 获取分页SQL语句 + * @param selectSql 查询SQL语句 + * @param orderColumn 排序字段 + * @param orderSign + * ASC(ascend):升序 1234 放空默认 + * DESC(descend):降序 4321batchInsert + * @param currentPage 当前页 + * @param pageSize 页面大小 + * @return String[] 0:分页查询语句 1:统计条数语句 + */ + public static String[] getPageSql(String dbEncode, String selectSql, String orderColumn, String orderSign, Integer currentPage, Integer pageSize) throws DataException{ + // 排序 + if(StringUtil.isEmpty(orderColumn)) throw new DataException("分页查询缺少排序字段"); + orderSign = StringUtil.isEmpty(orderSign) ? "" : orderSign; + // 起始下标 + String beginIndex = Integer.toString((currentPage - 1) * pageSize); + // 结束下标 + String endIndex = Integer.toString(currentPage * pageSize); + return new String[]{ + SqlComEnum.ORDER_PAGE.getOutSqlByDb(dbEncode, selectSql, orderColumn, beginIndex, endIndex, pageSize.toString(), orderSign), + SqlComEnum.COUNT_SIZE.getOutSqlByDb(dbEncode, DbAliasEnum.TOTAL_RECORD.getAlias(dbEncode), selectSql) + }; + } + + public static String[] getPageSql(String dbEncode, String selectSql, Pagination pagination) throws DataException{ + return getPageSql(dbEncode, selectSql, + pagination.getSidx(), + pagination.getSort(), + Long.valueOf(pagination.getCurrentPage()).intValue(), + Long.valueOf(pagination.getPageSize()).intValue()); + } + + /** + * 批量添加 + */ + public static void batchInsert(String table, DbLinkEntity dbLinkEntity, List> multiDataMapList) throws Exception { + // 表数据清空语句打印 + if(sqlPrintHandler.getPrintFlag()){ + if(multiDataMapList.size() > 0) sqlPrintHandler.deleteAllInfo(SqlComEnum.DELETE_ALL.getOutSqlByDb(dbLinkEntity.getDbType(), table)); + } + int total = multiDataMapList.size(); + int start = 1; + for (Map dataMap : multiDataMapList) { + if(total > 100){ + log.info("表:" + table + "_数据:(" + start + "/" + total + ")"); + start++; + } + insert(dbLinkEntity, table, dataMap); + } + } + + /** + * 单条插入 + */ + public static void insert(DbLinkEntity dbLinkEntity, String table, Map dataMap) throws Exception { + String dbEncode = dbLinkEntity.getDbType(); + // 插入语句打印 + if(sqlPrintHandler.getPrintFlag()){ + sqlPrintHandler.insert(formatInsertSql(dataMap, table, dbEncode)); + }else { + List formatFieldList = new ArrayList<>(); + List signList = new ArrayList<>(); + List valueList = new ArrayList<>(); + for (Map.Entry map : dataMap.entrySet()) { + signList.add("?"); + valueList.add(map.getValue()); + formatFieldList.add(FormatSql.getFieldName(map.getKey(), dbEncode)); + } + PrepSqlDTO prepSqlDTO = new PrepSqlDTO(SqlComEnum.INSERT.getOutSqlByDb(dbEncode, table, + String.join(",", formatFieldList), String.join(",", signList)), valueList).withConn(dbLinkEntity); + JdbcUtil.insert(prepSqlDTO); + } + } + + private static String formatInsertSql(Map dataMap, String table, String dbEncode) { + List fieldList = new ArrayList<>(); + List valueList = new ArrayList<>(); + StringBuilder oracleClobUpdate = new StringBuilder(); + for (Map.Entry field : dataMap.entrySet()) { + String column = field.getKey(); + Object columnValue = field.getValue(); + // 特殊处理:存在值超过2000的字符 + columnValue = FormatSqlOracle.clobExecute(dbEncode, columnValue, table, field.getKey(), dataMap, oracleClobUpdate); + columnValue = FormatSqlOracle.blobExecute(dbEncode, columnValue, table, field.getKey(), dataMap, oracleClobUpdate); + fieldList.add(FormatSql.getFieldName(column, dbEncode)); // 字段处理 + valueList.add(FormatSql.formatValue(columnValue, dbEncode)); // 值处理 + } + return SqlComEnum.INSERT.getOutSqlByDb(dbEncode, table, String.join(",", fieldList), String.join(",", valueList)) + + ";\n" + (StringUtils.isNotEmpty(oracleClobUpdate) ? oracleClobUpdate.toString() : ""); + } + + /** + * 模糊查询 + */ + public static String getFuzzyQuerySql(String selectSql, String column, String keyWord) throws DataException { + if (StringUtil.isNotEmpty(keyWord)) { + return SqlComEnum.LIKE.getOutSql(selectSql, column, "%" + keyWord + "%"); + } + return selectSql; + } + + /** + * 判断表数据存在 + */ + public static Boolean tableDataExist(String dbLinkId, String table) throws Exception { + DbLinkEntity dbLinkEntity = PrepSqlDTO.DB_LINK_FUN.apply(dbLinkId); + String sql = SqlComEnum.COUNT_SIZE_TABLE.getOutSqlByDb(dbLinkEntity.getDbType(),"F_COUNT", table); + NotTenantPluginHolder.setNotSwitchFlag(); + return JdbcUtil.queryOneInt(new PrepSqlDTO(sql).withConn(dbLinkId),"F_COUNT") > 0; + } + + /** + * 统计表数据行数 + */ + public static int getSum(DbLinkEntity dbLinkEntity, String table) throws Exception { + PrepSqlDTO dto = new PrepSqlDTO(SqlComEnum.COUNT_SIZE.getOutSql("COUNT_SUM", "SELECT * FROM " + FormatSql.getFieldName(table, dbLinkEntity.getDbType()))).withConn(dbLinkEntity); + NotTenantPluginHolder.setNotSwitchFlag(); + return JdbcUtil.queryOneInt(dto, "COUNT_SUM"); + } + + public static List getFieldList(DbLinkEntity dbLinkEntity, String table) throws Exception { + NotTenantPluginHolder.setNotSwitchFlag(); + return JdbcUtil.queryCustomMods( + SqlComEnum.FIELDS.getPrepSqlDto(dbLinkEntity, table), + DbFieldModel.class); + } + + public static boolean isExistTable(DbLinkEntity dbLinkEntity, String table) throws Exception { + NotTenantPluginHolder.setNotSwitchFlag(); + Integer total = JdbcUtil.queryOneInt(SqlComEnum.EXISTS_TABLE.getPrepSqlDto(dbLinkEntity, table), DbAliasEnum.TOTAL.getAlias()); + return total > 0; + } + + public static List getTableList(DbLinkEntity dbLinkEntity, String methodName) throws Exception { + NotTenantPluginHolder.setNotSwitchFlag(); + List list; + if (StringUtil.isNotEmpty(methodName) && DbAliasEnum.TABLE_TYPE.getAlias().equals(methodName)) { + list = JdbcUtil.queryCustomMods(SqlComEnum.TABLESANDVIEW.getPrepSqlDto(dbLinkEntity, ""), DbTableFieldModel.class); + return list.stream().sorted(Comparator.comparing(DbTableFieldModel::getType).thenComparing(DbTableFieldModel::getTable)).collect(Collectors.toList()); + } else { + list = JdbcUtil.queryCustomMods(SqlComEnum.TABLES.getPrepSqlDto(dbLinkEntity, ""), DbTableFieldModel.class); + } + // 排序 + return list.stream().sorted(Comparator.comparing(DbTableFieldModel::getTable)).collect(Collectors.toList()); + } + + public static List getTableList(DbLinkEntity dbLinkEntity) throws Exception { + return getTableList(dbLinkEntity, null); + } + + public static DbTableFieldModel getTable(DbLinkEntity dbLinkEntity, String table) throws Exception { + NotTenantPluginHolder.setNotSwitchFlag(); + List dbTableFieldModelList = + JdbcUtil.queryCustomMods(SqlComEnum.TABLE.getPrepSqlDto(dbLinkEntity, table), DbTableFieldModel.class); + if(dbTableFieldModelList.size() < 1){ + throw new DataException(MsgCode.DB010.get(dbLinkEntity.getDbName(), table)); + } + DbTableFieldModel dbTableFieldModel = dbTableFieldModelList.get(0); + dbTableFieldModel.setDbEncode(dbLinkEntity.getDbType()); + return dbTableFieldModel; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/util/SqlFrameFastUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/util/SqlFrameFastUtil.java new file mode 100644 index 0000000..7e579a5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/util/SqlFrameFastUtil.java @@ -0,0 +1,28 @@ +package com.yunzhupaas.database.sql.util; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-13 + */ +public class SqlFrameFastUtil { + + /** + * 增填权限 + */ + public final static String INSERT_AUTHORIZE = "INSERT INTO base_authorize (F_ID, f_item_type, f_item_id, f_object_type, f_object_id, f_sort_code, f_creator_time, f_creator_user_id %COLUMN_KEY% ) VALUES (?,?,?,?,?,?,?,? %COLUMN_PLACEHOLDER%)"; + public final static String INSERT_AUTHORIZE2 = "INSERT INTO base_authorize (F_ID, f_item_type, f_item_id, f_object_type, f_object_id, f_sort_code, f_creator_time, f_creator_user_id %COLUMN_KEY% ) VALUES (?,?,?,?,?,?,TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),? %COLUMN_PLACEHOLDER%)"; + public final static String AUTHOR_DEL = "DELETE FROM base_authorize WHERE (f_object_id in( '{authorizeIds}') AND f_item_type in( 'system','module','button','column','form','resource'))"; + + + + public final static String INSERT_ADMINISTRATOR = "INSERT INTO base_organize_administrator (f_id, f_user_id, f_organize_id, f_organize_type, f_this_layer_add, f_this_layer_edit, f_this_layer_delete, f_sub_layer_add, f_sub_layer_edit, f_sub_layer_delete, f_this_layer_select, f_sub_layer_select, f_manager_group, f_creator_time, f_creator_user_id,f_enabled_mark %COLUMN_KEY% ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,? %COLUMN_PLACEHOLDER%)"; + public final static String INSERT_ADMINISTRATOR2 = "INSERT INTO base_organize_administrator (f_id, f_user_id, f_organize_id, f_organize_type, f_this_layer_add, f_this_layer_edit, f_this_layer_delete, f_sub_layer_add, f_sub_layer_edit, f_sub_layer_delete, f_this_layer_select, f_sub_layer_select, f_manager_group, f_creator_time, f_creator_user_id,f_enabled_mark %COLUMN_KEY% ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,TO_TIMESTAMP(?,'yyyy-mm-dd hh24:mi:ss'),?,? %COLUMN_PLACEHOLDER%)"; + public final static String ADMINISTRATOR_DEL = "DELETE FROM base_organize_administrator WHERE (f_user_id in( '{userId}') )"; + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/util/SqlFrameUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/util/SqlFrameUtil.java new file mode 100644 index 0000000..1b4de73 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/sql/util/SqlFrameUtil.java @@ -0,0 +1,102 @@ +package com.yunzhupaas.database.sql.util; + +import com.yunzhupaas.database.sql.enums.base.SqlFrameBase; +import com.yunzhupaas.util.text.CharsetKit; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.util.HtmlUtils; + +import java.util.*; +import java.util.regex.Pattern; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/1/14 + */ +public class SqlFrameUtil { + + /** + * 去除模糊查询前后空白 + */ + public static String keyWordTrim(String keyWord){ + return keyWord.trim(); + } + + public static String htmlE(String str){ + if (str != null){ + return HtmlUtils.htmlEscape(str, CharsetKit.UTF_8); + } + return null; + } + + private static final Pattern BRACKET = Pattern.compile("\\<.+?\\>"); + + private static final Pattern BRACKET2 = Pattern.compile("\\[.+?\\]"); + + /** + * 正则处理 + */ + public static String formatSqlFrame(String sqlFrame){ + sqlFrame = sqlFrame.replace("<", "").replace(">", "") + .replace("[", "").replace("]", ""); +// if (StringUtil.isEmpty(TenantDataSourceUtil.getTenantSchema())) { +// // 去除的<>框架,<>:固定关键词,{}:参数,[]:可选关键词 +// return sqlFrame.replace("《schema》.", ""); +// } + + // 去除的<>框架,<>:固定关键词,{}:参数,[]:可选关键词 + return sqlFrame.replace("《schema》.", ""); + } + + /** + * Sql框架参数设置 + * @param sqlFrameEnum SQL框架枚举 + * @param frameParamList 框架指定参数集合 + * @param params 实际参数集合 + * @return Sql语句 + */ + public static String outSqlCommon(SqlFrameBase sqlFrameEnum, List frameParamList, String... params){ + String sqlFrame = sqlFrameEnum.getSqlFrame(); + List paramList = Arrays.asList(params); + // 组成paramsMap + Map paramsMap = new HashMap<>(); + for (int i = 0; i < paramList.size(); i++) { + paramsMap.put(frameParamList.get(i), paramList.get(i)); + } + sqlFrame = sqlFrameEnum.createIncrement(sqlFrame, paramsMap); + sqlFrame = sqlFrameEnum.createPrimaryKeys(sqlFrame, paramsMap); + // 对SQL框架指定参数设置为占位符 + for (int i = 0; i < frameParamList.size(); i++) { + sqlFrame = sqlFrame.replace(frameParamList.get(i), "?_" + i); + } + sqlFrame = SqlFrameUtil.formatSqlFrame(sqlFrame); + for (int i = 0; i < paramList.size(); i++) { + String param = paramList.get(i) != null ? paramList.get(i) : ""; + sqlFrame = sqlFrame.replace("?_" + i, param); + } + return sqlFrame; + } + + /** + * 按下标循环分割字符串 + */ + public static List splitStrRepeat(String str, Integer index){ + List splitList = new ArrayList<>(); + while (str.length() > index){ + String[] splitStrArrays = {str.substring(0, index), str.substring(index)}; + splitList.add(splitStrArrays[0]); + str = splitStrArrays[1]; + } + // 最后一个小于index的字符串 + if(StringUtils.isNotEmpty(str)){ + splitList.add(str); + } + return splitList; + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/ConnUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/ConnUtil.java new file mode 100644 index 0000000..57b9c3c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/ConnUtil.java @@ -0,0 +1,303 @@ +package com.yunzhupaas.database.util; + +import cn.hutool.core.util.ReflectUtil; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.proxy.jdbc.ConnectionProxy; +import com.yunzhupaas.database.model.dto.PrepSqlDTO; +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.model.interfaces.DbSourceOrDbLink; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.source.impl.DbOracle; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.TenantHolder; +import lombok.extern.slf4j.Slf4j; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Objects; +import java.util.Properties; + +/** + * Connection数据连接相关工具类 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/6 + */ +@Slf4j +public class ConnUtil { + + public static Connection getConnOrDefault(DbSourceOrDbLink dbSourceOrDbLink) throws DataException { + if (dbSourceOrDbLink == null) { + dbSourceOrDbLink = DynamicDataSourceUtil.getDataSourceUtil(); + } + return PrepSqlDTO.getConn(dbSourceOrDbLink.init()); + } + + public static Connection getConn(DbSourceOrDbLink dbSourceOrDbLink) throws DataException { + return PrepSqlDTO.getConn(dbSourceOrDbLink.init()); + } + + public static Connection getConn(DbSourceOrDbLink dbSourceOrDbLink, String dbName) throws DataException { + return PrepSqlDTO.getConn(dbSourceOrDbLink.init(dbName)); + } + + public static Connection getConn(String userName, String password, String url) throws DataException { + DbLinkEntity dbLinkEntity = new DbLinkEntity(); + dbLinkEntity.setUserName(userName); + dbLinkEntity.setPassword(password); + dbLinkEntity.setUrl(url); + dbLinkEntity.setDbType(DbTypeUtil.getDb(url).getYunzhupaasDbEncode()); + return PrepSqlDTO.getConn(dbLinkEntity); + } + + /** + * 连接Connection + */ + @Deprecated + private static Connection getConnection(DbSourceOrDbLink dbSourceOrDbLink) throws DataException { + return getConnection(dbSourceOrDbLink, null); + } + + /** + * 指定库名(多租户) + */ + @Deprecated + private static Connection getConnection(DbSourceOrDbLink dataSourceUtil, String dbName) throws DataException { + DbLinkEntity dbLinkEntity = dataSourceUtil.init(); + // Oracle特殊连接 + if (DbTypeUtil.checkOracle(dbLinkEntity)) { + return getOracleConn(dbLinkEntity); + } + return getConnection(dbLinkEntity.getAutoUsername(), dbLinkEntity.getAutoPassword(), getUrl(dbLinkEntity)); + } + + /** + * 基础连接方式 + */ + @Deprecated + private static Connection getConnection(String userName, String password, String url) throws DataException { + DbBase db = DbTypeUtil.getDb(url); + return ConnCommon.createConn(db.getDriver(), userName, password, url); + } + + /* ==================================================== */ + + /** + * oracle特殊连接方式 + */ + private static Connection getOracleConn(DbLinkEntity dsd) throws DataException { + DbOracle dbOracle = new DbOracle(); + return dbOracle.getOracleConn(dsd, getUrl(dsd)); + } + + /* ==============获取数据连接URL============== */ + + public static String getUrl(DbSourceOrDbLink dbSourceOrDbLink) { + return getUrl(dbSourceOrDbLink, null); + } + + /** + * 指定库名(多租户) + * + * @param dbSourceOrDbLink 数据源 + * @param dbName 数据库名 + * @return url连接 + */ + public static String getUrl(DbSourceOrDbLink dbSourceOrDbLink, String dbName) { + return DbBase.BaseCommon.getDbBaseConnUrl(dbSourceOrDbLink, dbName); + } + + public static void switchConnectionSchema(Connection conn) throws SQLException { + if (TenantDataSourceUtil.isMultiTenancy() && DynamicDataSourceUtil.isPrimaryDataSoure() + && TenantHolder.getLocalTenantCache() != null) { + String schema = TenantDataSourceUtil.getTenantDbName(); + if (StringUtil.isNotEmpty(schema)) { + Connection tmpConnection = getRealConnection(conn); + // 多租户模式, Schema模式下降连接切换至租户库 + // 判断数据库类型 + try { + switch (DynamicDataSourceUtil.getPrimaryDbType()) { + case DbBase.SQL_SERVER: + case DbBase.MYSQL: + if (!Objects.equals(tmpConnection.getCatalog(), schema)) { + tmpConnection.setCatalog(schema); + } + break; + case DbBase.POSTGRE_SQL: + // POSTGRE转小写 + schema = schema.toLowerCase(); + if (!Objects.equals(tmpConnection.getSchema(), schema)) { + tmpConnection.setSchema(schema); + } + break; + case DbBase.ORACLE: + // Oracle转大写 + schema = schema.toUpperCase(); + if (!Objects.equals(tmpConnection.getSchema(), schema)) { + tmpConnection.setSchema(schema); + } + break; + case DbBase.KINGBASE_ES: + case DbBase.DM: + default: + if (!Objects.equals(tmpConnection.getSchema(), schema)) { + tmpConnection.setSchema(schema); + } + } + } catch (Exception e) { + // 切库失败 连接不可用 需要先手动关闭链接 + conn.close(); + String url = ""; + if (tmpConnection instanceof ConnectionProxy) { + try { + url = ((ConnectionProxy) tmpConnection).getDirectDataSource().getUrl(); + } catch (Exception ee) { + } + } + log.error("切库失败, 租户:{}, URL: {}, Msg: {}", TenantHolder.getDatasourceId(), url, e.getMessage()); + throw e; + } + } + } + } + + public static String getConnectionDbName(Connection conn) throws SQLException { + Connection tmpConnection = getRealConnection(conn); + String dbName; + String dbCode = DbTypeUtil.getDb(tmpConnection.getMetaData().getURL()).getYunzhupaasDbEncode(); + // 多租户模式, Schema模式下降连接切换至租户库 + // 判断数据库类型 + switch (dbCode) { + case DbBase.ORACLE:// DBName:Schema + case DbBase.DM:// DBName:Schema + dbName = tmpConnection.getSchema(); + break; + case DbBase.SQL_SERVER:// DBName:CataLog + case DbBase.MYSQL:// DBName:CataLog + case DbBase.POSTGRE_SQL:// DBName:CataLog, Schema:Schema + case DbBase.KINGBASE_ES:// DBName:CataLog, Schema:Schema + default: + dbName = tmpConnection.getCatalog(); + } + return dbName; + } + + public static String getConnectionSchema(Connection conn) throws SQLException { + Connection tmpConnection = getRealConnection(conn); + String dbName; + String dbCode = DbTypeUtil.getDb(tmpConnection.getMetaData().getURL()).getYunzhupaasDbEncode(); + // 多租户模式, Schema模式下降连接切换至租户库 + // 判断数据库类型 + switch (dbCode) { + case DbBase.ORACLE:// DBName:Schema + case DbBase.DM:// DBName:Schema + case DbBase.POSTGRE_SQL:// DBName:CataLog, Schema:Schema + case DbBase.KINGBASE_ES:// DBName:CataLog, Schema:Schema + case DbBase.SQL_SERVER:// DBName:CataLog + dbName = tmpConnection.getSchema(); + break; + case DbBase.MYSQL:// DBName:CataLog + default: + dbName = tmpConnection.getCatalog(); + } + return dbName; + } + + /** + * 获取包装连接中的数据连接 + * + * @param connection + * @return + */ + public static Connection getRealConnection(Connection connection) { + Connection tmpConnection = connection; + // Druid连接包装只允许Mysql切换Schema + for (int i = 0; i < 6; i++) { + // 最大6次避免有不知名的数据源自己获取自己无限循环 + try { + tmpConnection = ReflectUtil.invoke(tmpConnection, "getConnection"); + } catch (Exception e) { + break; + } + } + return tmpConnection; + } + + /** + * 获取DruidDataSource + */ + public static DruidDataSource getDruidDataSource(DataSourceUtil dataSourceUtil) throws DataException { + DruidDataSource druidDataSource = new DruidDataSource(); + druidDataSource.setUsername(dataSourceUtil.getUserName()); + druidDataSource.setPassword(dataSourceUtil.getPassword()); + // jdbc-url + druidDataSource.setUrl(ConnUtil.getUrl(dataSourceUtil)); + // 数据库驱动 + druidDataSource.setDriverClassName(DbTypeUtil.getDb(dataSourceUtil).getDriver()); + return druidDataSource; + } + + /** + * 以下为ConnUtil上面非显性的公开方法 + * 让调用者只关注getConn方法而不造成干扰 + */ + public static class ConnCommon { + + /** + * (基础)获取数据连接 + * + * @param driver 驱动 + * @param userName 用户 + * @param password 密码 + * @param url url + * @return 数据库连接 + * @throws DataException ignore + */ + public static Connection createConn(String driver, String userName, String password, String url) + throws DataException { + try { + Class.forName(driver); + return DriverManager.getConnection(url, userName, password); + } catch (Exception e) { + e.printStackTrace(); + throw DataException.errorLink(e.getMessage()); + } + } + + public static Connection createConnByProp(String driver, String userName, String password, String url, + Properties conProps) throws DataException { + try { + conProps.put("user", userName); + conProps.put("password", password); + Class.forName(driver); + return DriverManager.getConnection(url, conProps); + } catch (Exception e) { + throw new DataException(e.getMessage()); + } + } + + /** + * 开启数据库获取表注解连接 + * + * @param dbSourceOrDbLink 数据源对象 + * @return ignore + */ + public static Connection getConnRemarks(DataSourceUtil dbSourceOrDbLink) throws DataException { + Properties props = new Properties(); + // 设置可以获取remarks信息 + props.setProperty("remarks", "true"); + props.setProperty("remarksReporting", "true"); + // 设置可以获取tables remarks信息 + props.setProperty("useInformationSchema", "true"); + return createConnByProp(DbTypeUtil.getDb(getUrl(dbSourceOrDbLink)).getDriver(), + dbSourceOrDbLink.getUserName(), dbSourceOrDbLink.getPassword(), + getUrl(dbSourceOrDbLink), props); + } + + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/DataSourceUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/DataSourceUtil.java new file mode 100644 index 0000000..8e42fcb --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/DataSourceUtil.java @@ -0,0 +1,176 @@ +package com.yunzhupaas.database.util; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.yunzhupaas.base.entity.SuperExtendEntity; +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.model.interfaces.DbSourceOrDbLink; +import com.yunzhupaas.database.sql.model.DbStruct; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.StringUtil; +import lombok.Data; +import org.springframework.beans.BeanUtils; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 数据源基础工具类 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 8:49 + */ +@Data +@Component +@ConfigurationProperties(prefix = "spring.datasource") +public class DataSourceUtil extends SuperExtendEntity.SuperExtendDescriptionEntity implements DbSourceOrDbLink { + + /** + * 数据库类型 + */ + @TableField("f_db_type") + private String dbType; + + /** + * 主机ip + */ + @TableField("f_host") + private String host; + + /** + * 端口 + */ + @TableField("f_port") + private Integer port; + + /** + * 库名 + */ + @TableField("f_service_name") + private String dbName; + + /** + * 用户 + */ + @TableField("f_user_name") + private String userName; + + /** + * 密码 + */ + @TableField("f_password") + private String password; + + /** + * 表空间 + */ + @TableField(value = "f_table_space") + private String dbTableSpace; + + /** + * 模式 + */ + @TableField(value = "f_db_schema") + private String dbSchema; + + /** + * 数据连接jdbc-url参数 + */ + @TableField(exist = false) + private String urlParams; + + /** + * url地址 + */ + @TableField(exist = false) + private String url; + + /** + * 数据连接jdbc-url参数 + */ + @TableField(exist = false) + private String prepareUrl; + + /** + * 驱动包 + */ + @TableField(exist = false) + private String driver; + + /** + * oracle多方式登录参数 + */ + @TableField(value = "f_oracle_param") + private String oracleParam; + + public String getAutoUsername() throws DataException { + if(StringUtil.isEmpty(this.userName)){ + return DbTypeUtil.getEncodeDb(this.dbType).getDbaUsername(); + }else { + return this.userName; + } + } + + public String getAutoPassword() throws DataException { + if(StringUtil.isEmpty(this.password)){ + return getAutoUsername(); + }else { + return this.password; + } + } + + /** + * -- 这里的参数dataSourceUtil是spring托管的全局唯一变量, + * New对象防止数据源互串,防止Bean覆盖 + * 获取数据源参数传参对象 + * 注意:此处方法不能命名为 get开头的名字, + * 会出现copy bean转换时候的错误 + */ + public DbLinkEntity init(){ + return init(null); + } + + /** + * 多租户:获取数据源参数传参对象 + * @param dbName 库名 + * @return ignore + */ + public DbLinkEntity init(String dbName){ + DbLinkEntity dbLinkEntity = new DbLinkEntity(); + BeanUtils.copyProperties(this, dbLinkEntity); + if(StringUtil.isNotEmpty(dbName)){ + dbLinkEntity.setDbName(dbName); + } + return dbLinkEntity; + } + + /** + * 数据基础结构信息 + */ + public DbStruct getDbStruct(){ + DbStruct dbStruct = new DbStruct(); + // 用户名对应 (当数据库为Oracle与DM的时,schema默认与用户同名) + dbStruct.setUserName(getUserName()); + dbStruct.setOracleDbSchema(getUserName()); + dbStruct.setDmDbSchema(getUserName()); + // 表空间 + dbStruct.setDbTableSpace(getDbTableSpace()); + //库名 + dbStruct.setMysqlDbName(getDbName()); + dbStruct.setSqlServerDbName(getDbName()); + dbStruct.setKingBaseDbName(getDbName()); + dbStruct.setPostGreDbName(getDbName()); + // 模式 + if(StringUtil.isNotEmpty(getDbSchema())){ + dbStruct.setOracleDbSchema(getDbSchema()); + dbStruct.setDmDbSchema(getDbSchema()); + dbStruct.setSqlServerDbSchema(getDbSchema()); + dbStruct.setKingBaseDbSchema(getDbSchema()); + dbStruct.setPostGreDbSchema(getDbSchema()); + } + dbStruct.setOracleParam(getOracleParam()); + return dbStruct; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/DbTypeUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/DbTypeUtil.java new file mode 100644 index 0000000..42fb585 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/DbTypeUtil.java @@ -0,0 +1,246 @@ +package com.yunzhupaas.database.util; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.model.interfaces.DbSourceOrDbLink; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.exception.DataException; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * 处理判断数据库类型有关工具类 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/6 + */ +public class DbTypeUtil { + + /* ===========================数据库对象(重载)===================================== */ + + /** + * 根据数据库名获取数据库对象 + * Case insensitive 大小写不敏感 + * + * @param dbSourceOrDbLink 数据源 + * @return DbTableEnum2 数据表枚举类 + */ + public static DbBase getDb(DbSourceOrDbLink dbSourceOrDbLink) throws DataException { + String dbSourceOrDbLinkEncode = getEncode(dbSourceOrDbLink.init()); + return getDbCommon(dbSourceOrDbLinkEncode); + } + + public static DbBase getDb(Connection conn) throws DataException { + try { + return getDb(conn.getMetaData().getURL()); + } catch (SQLException | DataException e) { + e.printStackTrace(); + } + throw new DataException(MsgCode.DB005.get()); + } + + public static DbBase getDb(String url) throws DataException { + String dbType = url.split(":")[1]; + for (DbBase dbBase : DbBase.DB_BASES) { + if (dbType.equals(dbBase.getConnUrlEncode())) { + return dbBase; + } + } + throw new DataException(MsgCode.DB003.get()); + } + + public static DbBase getEncodeDb(String dbEncode) throws DataException { + for (DbBase dbBase : DbBase.DB_BASES) { + if (dbEncode.equals(dbBase.getYunzhupaasDbEncode())) { + return dbBase; + } + } + throw new DataException(MsgCode.DB003.get()); + } + + public static DbBase getDriver(String dbType) throws DataException { + for (DbBase dbBase : DbBase.DB_BASES) { + if (dbBase.getYunzhupaasDbEncode().contains(dbType)) { + return dbBase; + } + } + throw new DataException(MsgCode.DB003.get()); + } + + /* ===========================校验数据库类型============================= */ + + /** + * IOC思想 + * + * @return 是否匹配 + */ + private static Boolean checkDb(DbSourceOrDbLink dataSourceMod, String encode) { + DbLinkEntity dataSourceDTO = dataSourceMod.init(); + String dataSourDbEncode = null; + try { + dataSourDbEncode = getEncode(dataSourceDTO); + } catch (DataException e) { + e.printStackTrace(); + } + return encode.equals(dataSourDbEncode); + } + + public static Boolean checkOracle(DbSourceOrDbLink dataSourceMod) { + return checkDb(dataSourceMod, DbBase.ORACLE); + } + + public static Boolean checkMySQL(DbSourceOrDbLink dataSourceMod) { + return checkDb(dataSourceMod, DbBase.MYSQL); + } + + public static Boolean checkSQLServer(DbSourceOrDbLink dataSourceMod) { + return checkDb(dataSourceMod, DbBase.SQL_SERVER); + } + + public static Boolean checkDM(DbSourceOrDbLink dataSourceMod) { + return checkDb(dataSourceMod, DbBase.DM); + } + + public static Boolean checkKingbase(DbSourceOrDbLink dataSourceMod) { + return checkDb(dataSourceMod, DbBase.KINGBASE_ES); + } + + public static Boolean checkPostgre(DbSourceOrDbLink dataSourceMod) { + return checkDb(dataSourceMod, DbBase.POSTGRE_SQL); + } + + /* ============================专用代码区域========================= */ + + /** + * MybatisPlusConfig + */ + public static DbType getMybatisEnum(T dataSourceUtil) throws DataException { + return getDb(dataSourceUtil).getMpDbType(); + } + + /** + * 默认数据库与数据连接判断 + */ + public static Boolean compare(String dbType1, String dbType2) throws DataException { + dbType1 = checkDbTypeExist(dbType1, false); + dbType2 = checkDbTypeExist(dbType2, false); + if (dbType1 != null && dbType2 != null) { + return dbType1.equals(dbType2); + } else { + return false; + } + } + + /* =========================内部复用代码================================ */ + + /* ====标准类型(重载)== */ + + /** + * 获取标准类型编码 + * 根据DbType + * + * @param dataSourceDTO 数据源 + * @return String + */ + private static String getEncode(DbLinkEntity dataSourceDTO) throws DataException { + return checkDbTypeExist(dataSourceDTO.getDbType(), true); + } + + /** + * ============** + *

+ * /** + * 获取数据库对象 + * + * @param encode 数据标准编码 + * @return 数据库基类 + */ + private static DbBase getDbCommon(String encode) { + for (DbBase db : DbBase.DB_BASES) { + if (db.getYunzhupaasDbEncode().equalsIgnoreCase(encode)) { + return db; + } + } + return null; + } + + /** + * 0、校验数据类型是否符合编码标准(包含即可) + * + * @param dbType 数据类型 + * @param exceptionOnOff 无匹配是否抛异常 + * @return 数据标准编码 + * @throws DataException 数据库类型不符合编码 + */ + private static String checkDbTypeExist(String dbType, Boolean exceptionOnOff) throws DataException { + for (String enEncode : DbBase.DB_ENCODES) { + if (enEncode.equals(dbType)) { + return enEncode; + } + } + if (exceptionOnOff) { + throw new DataException(MsgCode.DB001.get()); + } + return null; + } + + /** + * 根据数据库连接获取的产品名称获取数据库类型编码 + * + * @param databaseProductName + * @return + */ + public static String getDbEncodeByProductName(String databaseProductName) { + switch (databaseProductName.toUpperCase()) { + case "MYSQL": + return DbBase.MYSQL; + case "ORACLE": + return DbBase.ORACLE; + case "POSTGRESQL": + return DbBase.POSTGRE_SQL; + case "KINGBASEES": + return DbBase.KINGBASE_ES; + case "MICROSOFT SQL SERVER": + return DbBase.SQL_SERVER; + case "DM DBMS": + return DbBase.DM; + default: + return databaseProductName.toUpperCase(); + } + } + + /** + * 数据库字段是否转小写 + * + * @param dbType (getDbEncodeByProductName转换后值) + * @return + */ + public static boolean needToLowerCase(String dbType) { + List lowerDb = new ArrayList<>(); + lowerDb.add(DbBase.POSTGRE_SQL); + lowerDb.add(DbBase.KINGBASE_ES); + if (lowerDb.contains(dbType)) { + return true; + } + return false; + } + + /** + * 数据库字段是否转大写 + * + * @param databaseProductName + * @return + */ + public static boolean needToUpperCase(String databaseProductName) { + if (databaseProductName.contains(DbBase.ORACLE) || databaseProductName.contains(DbBase.DM)) { + return true; + } + return false; + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/DynamicDataSourceUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/DynamicDataSourceUtil.java new file mode 100644 index 0000000..03fcc99 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/DynamicDataSourceUtil.java @@ -0,0 +1,271 @@ +package com.yunzhupaas.database.util; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.text.StrPool; +import com.alibaba.druid.pool.DruidDataSource; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; +import com.baomidou.dynamic.datasource.creator.druid.DruidConfig; +import com.baomidou.dynamic.datasource.ds.ItemDataSource; +import com.baomidou.dynamic.datasource.creator.DataSourceProperty; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; +import com.baomidou.dynamic.datasource.enums.DdConstants; +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; +import com.yunzhupaas.config.ConfigValueUtil; +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.source.impl.DbOracle; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.LockObjectUtil; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.TenantHolder; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.map.LRUMap; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Optional; + +/** + * 动态切换数据源, 配合DynamicDatasource数据源 + * + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/9/26 20:57 + */ +@Setter +@Slf4j +@Component +public class DynamicDataSourceUtil { + + private static int MAX_DATASOURCE_COUNT = 300; + + // 最多保存三百个数据源, 按使用率淘汰 + private static LRUMap linksProperties = new LRUMap(MAX_DATASOURCE_COUNT); + + public static DataSourceUtil dataSourceUtil; + public static DynamicRoutingDataSource dynamicRoutingDataSource; + public static DynamicDataSourceProperties dynamicDataSourceProperties; + private static DefaultDataSourceCreator defaultDataSourceCreator; + private static ConfigValueUtil configValueUtil; + + public DynamicDataSourceUtil(@Qualifier("dataSourceSystem") DataSource dynamicRoutingDataSource, + DynamicDataSourceProperties dynamicDataSourceProperties, DefaultDataSourceCreator defaultDataSourceCreator, + ConfigValueUtil configValueUtil, DataSourceUtil dataSourceUtil) { + DynamicDataSourceUtil.dynamicRoutingDataSource = (DynamicRoutingDataSource) dynamicRoutingDataSource; + DynamicDataSourceUtil.dynamicDataSourceProperties = dynamicDataSourceProperties; + DynamicDataSourceUtil.defaultDataSourceCreator = defaultDataSourceCreator; + DynamicDataSourceUtil.configValueUtil = configValueUtil; + DynamicDataSourceUtil.dataSourceUtil = new DataSourceUtil(); + BeanUtils.copyProperties(dataSourceUtil, DynamicDataSourceUtil.dataSourceUtil); + } + + /** + * 创建并切换至远程数据源 + * + * @param userName + * @param password + * @param url + * @throws DataException + * @throws SQLException + */ + public static DbLinkEntity switchToDataSource(String userName, String password, String url, String dbType) + throws DataException, SQLException { + String tenantId = Optional.ofNullable(TenantHolder.getDatasourceId()).orElse(""); + String dbKey = tenantId + userName + password + url; + DbLinkEntity dbLinkEntity = new DbLinkEntity(); + dbLinkEntity.setId(dbKey); + dbLinkEntity.setUserName(userName); + dbLinkEntity.setPassword(password); + dbLinkEntity.setUrl(url); + if (StringUtil.isEmpty(dbType)) { + dbLinkEntity.setDbType(DbTypeUtil.getDb(url).getYunzhupaasDbEncode()); + } else { + dbLinkEntity.setDbType(dbType); + } + switchToDataSource(dbLinkEntity); + return dbLinkEntity; + } + + /** + * 创建并切换至远程数据源 + * dbLinkEntity 为空不或ID为空切换为默认数据源 多数据源层级 +1 + * + * @param dbLinkEntity + * @throws DataException + */ + public static void switchToDataSource(DbLinkEntity dbLinkEntity) throws DataException, SQLException { + // 切换目标为系统主库 数据源层级+1 + if (dbLinkEntity == null || StringUtil.isEmpty(dbLinkEntity.getId()) || "0".equals(dbLinkEntity.getId())) { + if (TenantHolder.isRemote()) { + // 租户指定数据源 + String dbKey = TenantHolder.getDatasourceId() + StrPool.DASHED + DdConstants.MASTER; + DynamicDataSourceContextHolder.push(dbKey); + } else { + DynamicDataSourceContextHolder.push(null); + } + // DataSourceContextHolder.addDynamicDatasourceLevel(); + return; + } + String tenantId = Optional.ofNullable(TenantHolder.getDatasourceId()).orElse(""); + String dbKey = tenantId + dbLinkEntity.getId(); + String removeKey = null; + boolean insert = true; + synchronized (LockObjectUtil.addLockKey(dbKey)) { + if (dynamicRoutingDataSource.getDataSources().containsKey(dbKey)) { + synchronized (linksProperties) { + if (linksProperties.get(dbKey).equals(dbLinkEntity)) { + insert = false; + } + } + } + if (insert) { + DataSource ds = createDataSource(dbLinkEntity); + // 单独设置动态切换的数据源参数 + if (ds instanceof ItemDataSource) { + if (((ItemDataSource) ds).getRealDataSource() instanceof DruidDataSource) { + // 运行中创建的连接, 30分钟空闲后不保留 + ((DruidDataSource) ((ItemDataSource) ds).getRealDataSource()).setMinIdle(0); + // ((DruidDataSource)((ItemDataSource)ds).getRealDataSource()).setTimeBetweenConnectErrorMillis(DruidAbstractDataSource.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS); + } + } + dynamicRoutingDataSource.addDataSource(dbKey, ds); + synchronized (linksProperties) { + if (linksProperties.size() == MAX_DATASOURCE_COUNT) { + removeKey = linksProperties.firstKey(); + } + linksProperties.put(dbKey, dbLinkEntity); + } + } + } + /* + * if(dbKey.contains("_")){ + * //分组数据源 + * dbKey = dbKey.split("_")[0]; + * } + */ + DynamicDataSourceContextHolder.push(dbKey); + // DataSourceContextHolder.addDynamicDatasourceLevel(); + if (removeKey != null) { + try { + dynamicRoutingDataSource.removeDataSource(removeKey); + } catch (Exception e) { + log.error("移除数据源失败:{}", e.getMessage()); + } + } + } + + /** + * 移除当前设置的远程数据源, 清除上次清除之后切换的所有数据源 + * 需要先调用 switchToDataSource切换数据源 + */ + public static void clearSwitchDataSource() { + DynamicDataSourceContextHolder.poll(); + // for (int i = 0; i < DataSourceContextHolder.getDynamicDatasourceLevel(); i++) + // { + // DynamicDataSourceContextHolder.poll(); + // } + // DataSourceContextHolder.clearDynamicDatasourceLevel(); + } + + /** + * 获取当前数据源的数据链接(切库后的) + * 用完之后一定要关闭 + * + * @return + * @throws SQLException + */ + public static Connection getCurrentConnection() throws SQLException { + return dynamicRoutingDataSource.getConnection(); + } + + /** + * 创建数据源 + * + * @param dbLinkEntity + * @param + * @return + * @throws DataException + * @throws SQLException + */ + public static DataSource createDataSource(T dbLinkEntity) + throws DataException, SQLException { + return createDataSource(dbLinkEntity, dbLinkEntity.getUrl()); + } + + /** + * 创建数据源 + * + * @param dbLinkEntity + * @param url 覆盖自动生成的连接地址 + * @param + * @return + * @throws DataException + * @throws SQLException + */ + public static DataSource createDataSource(T dbLinkEntity, String url) + throws DataException { + DataSourceProperty dataSourceProperty = createDataSourceProperty(dbLinkEntity, url); + DataSource ds = defaultDataSourceCreator.createDataSource(dataSourceProperty); + return ds; + } + + public static DataSourceProperty createDataSourceProperty(T dbLinkEntity, String url) { + if (StringUtil.isEmpty(url)) { + url = ConnUtil.getUrl(dbLinkEntity, dbLinkEntity.getDbName()); + } + DataSourceProperty dataSourceProperty = new DataSourceProperty(); + dataSourceProperty.setUsername(dbLinkEntity.getAutoUsername()); + dataSourceProperty.setPassword(dbLinkEntity.getAutoPassword()); + dataSourceProperty.setUrl(url); + dataSourceProperty.setDriverClassName(DbTypeUtil.getDb(dbLinkEntity).getDriver()); + DruidConfig druidConfig = BeanUtil.copyProperties(dynamicDataSourceProperties.getDruid(), DruidConfig.class); + dataSourceProperty.setLazy(true); + druidConfig.setBreakAfterAcquireFailure(true); + // 不同库设置检查SQL语句,SqlServer, Mysql, Oracle, Postgre已有默认SQL检查器 + if (druidConfig.getValidationQuery() == null + && (DbTypeUtil.checkKingbase(dbLinkEntity) || DbTypeUtil.checkDM(dbLinkEntity))) { + druidConfig.setValidationQuery("select 1;"); + } + // oracle参数处理 + if (DbTypeUtil.checkOracle(dbLinkEntity)) { + druidConfig.setConnectionProperties( + DbOracle.setConnProp("Default", dbLinkEntity.getUserName(), dbLinkEntity.getPassword())); + } + dataSourceProperty.setDruid(druidConfig); + return dataSourceProperty; + } + + /** + * 当前是否是主库环境 + * + * @return + */ + public static boolean isPrimaryDataSoure() { + String dsKey = DynamicDataSourceContextHolder.peek(); + return StringUtil.isEmpty(dsKey) || dynamicDataSourceProperties.getPrimary().equals(dsKey); + } + + /** + * 获取主库数据源类型 + * + * @return + */ + public static String getPrimaryDbType() { + return dataSourceUtil.getDbType(); + } + + public static DataSourceUtil getDataSourceUtil() { + return dataSourceUtil; + } + + public static boolean containsLink(String key) { + return linksProperties.containsKey(key); + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/IgnoreLogicDeleteHolder.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/IgnoreLogicDeleteHolder.java new file mode 100644 index 0000000..5ade5c8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/IgnoreLogicDeleteHolder.java @@ -0,0 +1,29 @@ +package com.yunzhupaas.database.util; + +/** + * 调用setIsIgnoreLogicDelete 设置后续Mapper查询忽略字段多租户 + * + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/14 17:12 + */ +public class IgnoreLogicDeleteHolder { + + + private static final ThreadLocal ISIGNORELOGICDELETE_HOLDER = new ThreadLocal<>(); + + public static boolean isIgnoreLogicDelete(){ + return Boolean.TRUE.equals(ISIGNORELOGICDELETE_HOLDER.get()); + } + + public static void setIgnoreLogicDelete(){ + ISIGNORELOGICDELETE_HOLDER.set(true); + } + + public static void clear(){ + ISIGNORELOGICDELETE_HOLDER.remove(); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/JdbcOriginUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/JdbcOriginUtil.java new file mode 100644 index 0000000..490f54c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/JdbcOriginUtil.java @@ -0,0 +1,69 @@ +package com.yunzhupaas.database.util; + +import com.yunzhupaas.database.model.dbfield.JdbcColumnModel; +import com.yunzhupaas.database.model.dbtable.JdbcTableModel; +import lombok.Cleanup; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 类功能 + * + * @author 云筑产品开发平台组 + * @version V3.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/21 + */ +public class JdbcOriginUtil { + + /** + * 获取字段元数据map集合(所有表) + * @param conn 数据连接 + * @return ignore + * @throws SQLException ignore + */ + public static List> getColumnMataMapList(Connection conn, String table) throws Exception { + @Cleanup ResultSet rs = JdbcColumnModel.getColumnMetaDateRs(conn, table); + List> mapList = new ArrayList<>(); + while (rs.next()) { + /*===================遍历表字段所有元数据=====================*/; + Map map = new HashMap<>(16); + for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) { + map.put(rs.getMetaData().getColumnName(i), rs.getString(i)); + } + mapList.add(map); + } + return mapList; + } + + /** + * 获取表元数据map集合 + * @param conn 数据连接 + * @return ignore + * @throws SQLException ignore + */ + public static List> getTableMapList(Connection conn) throws SQLException { + @Cleanup ResultSet rs = JdbcTableModel.getTableMetaDateRs(conn, null); + List> mapList = new ArrayList<>(); + while (rs.next()) { + Map map = new HashMap<>(); + // 模式下所有表元数据 + ResultSetMetaData resultSetMetaData = rs.getMetaData(); + // 遍历表所有元数据信息,一个map包含一张表 + for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { + map.put(resultSetMetaData.getColumnName(i), rs.getString(i)); + } + mapList.add(map); + } + return mapList; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/JdbcUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/JdbcUtil.java new file mode 100644 index 0000000..4c41837 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/JdbcUtil.java @@ -0,0 +1,314 @@ +package com.yunzhupaas.database.util; + +import com.yunzhupaas.base.Pagination; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.database.enums.DbAliasEnum; +import com.yunzhupaas.database.model.dbfield.JdbcColumnModel; +import com.yunzhupaas.database.model.dto.JdbcResult; +import com.yunzhupaas.database.model.dto.ModelDTO; +import com.yunzhupaas.database.model.dto.PrepSqlDTO; +import com.yunzhupaas.database.model.interfaces.JdbcCreUpDel; +import com.yunzhupaas.database.model.interfaces.JdbcGetMod; +import com.yunzhupaas.database.model.page.JdbcPageMod; +import com.yunzhupaas.database.sql.util.SqlFastUtil; +import com.yunzhupaas.exception.DataException; +import com.yunzhupaas.util.XSSEscape; +import com.yunzhupaas.util.context.SpringContext; +import lombok.Cleanup; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; + +import java.sql.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * JDBC Dynamic + * + * @author 云筑产品开发平台组 + * @version V3.4.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/10 + */ +@Slf4j +public class JdbcUtil { + + private final static String SELECT_MAPPER = "com.yunzhupaas.database.mapper.JdbcMapper.getListSql"; + private final static String UPDATE_MAPPER = "com.yunzhupaas.database.mapper.JdbcMapper.updateSql"; + private final static String UPDATE_MAPPERS = "com.yunzhupaas.database.mapper.JdbcMapper.updatesSql"; + private final static String DELETE_MAPPER = "com.yunzhupaas.database.mapper.JdbcMapper.deleteSql"; + private final static String INSERT_MAPPER = "com.yunzhupaas.database.mapper.JdbcMapper.insertSql"; + + private static SqlSessionFactory getSqlSessionFactory(){ + return SpringContext.getBean(SqlSessionFactory.class); + } + + /** + * 批量执行一条SQL语句(适合增、删、改) + * CRUD:增加(Create)、检索(Retrieve)、更新(Update)、删除(Delete) + * @return 返回值:i>0 成功条数,i=0 执行失败 + */ + public static int creUpDe(PrepSqlDTO dto) throws Exception { + dto.switchConn(); + try{ + @Cleanup SqlSession sqlSession = getSqlSessionFactory().openSession(); + return sqlSession.update(UPDATE_MAPPER, dto.getMapParams()); + }finally{ + DynamicDataSourceUtil.clearSwitchDataSource(); + } + } + + /** + * update更新语句 + */ + public static int update(PrepSqlDTO dto) throws Exception { + dto.switchConn(); + try{ + @Cleanup SqlSession sqlSession = getSqlSessionFactory().openSession(); + return sqlSession.update(UPDATE_MAPPERS, dto.getMapParams()); + }finally{ + DynamicDataSourceUtil.clearSwitchDataSource(); + } + } + + public static int delete(PrepSqlDTO dto) throws Exception { + dto.switchConn(); + try{ + @Cleanup SqlSession sqlSession = getSqlSessionFactory().openSession(); + return sqlSession.update(DELETE_MAPPER, dto.getMapParams()); + }finally{ + DynamicDataSourceUtil.clearSwitchDataSource(); + } + } + + public static int insert(PrepSqlDTO dto) throws Exception { + dto.switchConn(); + try{ + @Cleanup SqlSession sqlSession = getSqlSessionFactory().openSession(); + return sqlSession.update(INSERT_MAPPER, dto.getMapParams()); + }finally{ + DynamicDataSourceUtil.clearSwitchDataSource(); + } + } + + /** + * 同一条语句批量执行 + * 同数据源 + * @param dto SQL语句参数对象 + * @return 执行结果 + * @throws SQLException ignore + */ + public static int[] creUpDeBatchOneSql(PrepSqlDTO dto) throws Exception { + @Cleanup Connection conn = ConnUtil.getConnOrDefault(dto.getDbLinkEntity()); + return JdbcCreUpDel.get(conn, () -> { + @Cleanup PreparedStatement statement = conn.prepareStatement(dto.getSql()); + for(List data : dto.getMultiDataList()){ + JdbcCreUpDel.setData(statement, data); + statement.addBatch(); + } + return statement.executeBatch(); + }); + } + + /*========================query查询语句==============================*/ + + /*============ 模式一:MapList ============*/ + /** + * 通用:单字段多条查询 + */ + public static JdbcResult>> queryList(PrepSqlDTO dto) throws Exception { + return new JdbcResult<>((jdbcResult)-> JdbcUtil.getMybatisModel0(dto, jdbcResult.getIsLowerCase(), jdbcResult.getIsAlias())); + } + + /** + * 通用:单字段单条查询 + */ + public static Map queryOne(PrepSqlDTO dto) throws Exception { + List> mapList = queryList(dto).get(); + return mapList.size() > 0 ? mapList.get(0) : new HashMap<>(); + } + + /** + * 查单条Int类型返回值 + */ + public static Integer queryOneInt(PrepSqlDTO dto, String keyWord) throws Exception { + Map map = queryOne(dto); + if (map != null && map.size() > 0) { + for (Map.Entry mapEntity : map.entrySet()) { + if(mapEntity.getKey().equalsIgnoreCase(keyWord)){ + return Integer.parseInt(String.valueOf(mapEntity.getValue())); + } + } + } + throw new DataException(MsgCode.FA020.get()); + } + + public static JdbcResult queryPage(PrepSqlDTO dto, String sortType, Integer currentPage, Integer pageSize) throws Exception { + final String finalSortType = sortType; + return new JdbcResult<>((jdbcResult)-> { + String sortTypeStr = finalSortType; + String orderSign = null; + String dbEncode = dto.getDbLinkEntity().getDbType(); + String[] split = sortTypeStr.split(","); + if (split.length > 1) { + sortTypeStr = split[0]; + orderSign = split[1]; + } + String selectSql = ""; + JdbcPageMod pageModel = new JdbcPageMod(); + try { + String[] sqlArray = SqlFastUtil.getPageSql(dbEncode, dto.getSql(), sortTypeStr, orderSign, currentPage, pageSize); + selectSql = sqlArray[0]; + //方便测试打印到控制台 + System.out.println("列表sql语句为:" + selectSql); + dto.setSql(selectSql); + List resultData = getMybatisModel0(dto, jdbcResult.getIsLowerCase(), jdbcResult.getIsAlias()); + pageModel.setDataList(resultData); + selectSql = sqlArray[1]; + dto.setSql(selectSql); + pageModel.setTotalRecord(queryOneInt(dto, DbAliasEnum.TOTAL_RECORD.getAlias(dbEncode))); + pageModel.setCurrentPage(currentPage); + pageModel.setPageSize(pageSize); + } catch (Exception e) { + log.error("在线列表sql语句错误:" + selectSql); + throw new DataException(MsgCode.DB017.get(selectSql)); + } + return pageModel; + }); + } + + public static JdbcResult queryModelPage(PrepSqlDTO dto, Pagination pagination, Class modType) throws Exception { + return new JdbcResult<>((jdbcResult)-> { + String dbEncode = dto.getDbLinkEntity().getDbType(); + String[] sqlArray = SqlFastUtil.getPageSql(dbEncode, dto.getSql(), pagination); + pagination.setData( + getMybatisModel2(dto.setSql(sqlArray[0]), modType), + queryOneInt(dto.setSql(sqlArray[1]), DbAliasEnum.TOTAL_RECORD.getAlias(dbEncode))); + return pagination; + }); + } + + /*============ 模式二:JdbcColumnModel ============*/ + /** + * 专用:查询模板 + * 说明:DbJdbcModel对象,为通用的数据返回对象,每条信息不同字段对应的数据,包含此相应字段的信息 + */ + public static JdbcResult>> queryJdbcColumns(PrepSqlDTO dto) throws Exception { + return new JdbcResult<>((jdbcResult)-> getMybatisModel1(dto, jdbcResult.getIsLowerCase(), jdbcResult.getIsValue())); + } + + /*============ 模式三:JdbcColumnModel ============*/ + /** + * 自定义模板查询 + */ + public static List queryCustomMods(PrepSqlDTO dto, Class modType) throws Exception { + return getMybatisModel2(dto, modType); + } + + /*=========================== 基础方法 ==========================*/ + + /** + * 模式一: + * ResultSet转Map + * + * @return 结果集的Map集合 + */ + public static List> getMybatisModel0(PrepSqlDTO dto, Boolean isLowercase, Boolean isAlias) throws Exception { + dto.switchConn(); + try { + List> mapMods = new ArrayList<>(); + ResultHandler handler = (handle) -> { + try { + ResultSet rs = ResetSetHolder.getResultSet(); + ResultSetMetaData md = rs.getMetaData(); + Map map = new HashMap<>(); + //获取字段集合信息 + int columnCount = md.getColumnCount(); + for (int i = 1; i <= columnCount; i++) { + String fieldName = isAlias ? md.getColumnLabel(i) : md.getColumnName(i); + fieldName = isLowercase ? fieldName.toLowerCase() : fieldName; + map.put(fieldName, XSSEscape.escapeObj(rs.getObject(i))); + } + mapMods.add(map); + } catch (Exception e) { + e.printStackTrace(); + } + }; + @Cleanup SqlSession sqlSession = getSqlSessionFactory().openSession(); + sqlSession.select(SELECT_MAPPER, dto.getMapParams(), handler); + return mapMods; + }finally { + DynamicDataSourceUtil.clearSwitchDataSource(); + } + } + + /** + * 模式二: + * 内置基础结果对象 (包含类型) + * + * @return 包含字段信息的结果集对象 + */ + public static List> getMybatisModel1(PrepSqlDTO dto, Boolean isLowercase, Boolean isValue) throws Exception { + dto.switchConn(); + try { + List> includeFieldMods = new ArrayList<>(); + ResultHandler handler = (handle) -> { + try { + ResultSet rs = ResetSetHolder.getResultSet(); + do{ + includeFieldMods.add(JdbcColumnModel.getList(rs, isLowercase, isValue)); + }while (rs.next()); + } catch (Exception e) { + e.printStackTrace(); + } + }; + @Cleanup SqlSession sqlSession = getSqlSessionFactory().openSession(); + sqlSession.select(SELECT_MAPPER, dto.getMapParams(), handler); + return includeFieldMods; + }finally { + DynamicDataSourceUtil.clearSwitchDataSource(); + } + } + + /** + * 模式三: + * 获取自定义对象模型集合 + * + * @param 自定义对象模型类型 + * @return 自定义对象集合 + * @throws SQLException ignore + */ + public static List getMybatisModel2(PrepSqlDTO dto, Class modType) throws Exception { + dto.switchConn(); + try { + List customMods = new ArrayList<>(); + String dbEncode = dto.getDbLinkEntity().getDbType(); + ResultHandler handler = (handle) -> { + try { + T t = modType.newInstance(); + t.setMod(new ModelDTO(ResetSetHolder.getResultSet(), dbEncode)); + t = XSSEscape.escapeObj(t); + customMods.add(t); + } catch (Exception e) { + e.printStackTrace(); + } + }; + + @Cleanup SqlSession sqlSession = getSqlSessionFactory().openSession(); + sqlSession.select(SELECT_MAPPER, dto.getMapParams(), handler); + //返回值:自定义jdbc模型对象 + return customMods; + }finally{ + DynamicDataSourceUtil.clearSwitchDataSource(); + } + } + + + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/NotTenantPluginHolder.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/NotTenantPluginHolder.java new file mode 100644 index 0000000..bfe1bd2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/NotTenantPluginHolder.java @@ -0,0 +1,51 @@ +package com.yunzhupaas.database.util; + + +/** + * 不执行多租户切库,字段拼接插件 + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/25 17:16 + */ +public class NotTenantPluginHolder { + + + private static final ThreadLocal CONTEXT_NOTSWITCH_HOLDER = ThreadLocal.withInitial(()->Boolean.FALSE); + private static final ThreadLocal CONTEXT_NOTSWITCH_ALWAYS_HOLDER = ThreadLocal.withInitial(()->Boolean.FALSE); + + /** + * 只能生效一次查询 + */ + public static void setNotSwitchFlag(){ + CONTEXT_NOTSWITCH_HOLDER.set(Boolean.TRUE); + } + + public static Boolean isNotSwitch(){ + return CONTEXT_NOTSWITCH_HOLDER.get(); + } + + public static void clearNotSwitchFlag(){ + CONTEXT_NOTSWITCH_HOLDER.remove(); + } + + + /** + * 只能生效一次查询 + */ + public static void setNotSwitchAlwaysFlag(){ + CONTEXT_NOTSWITCH_ALWAYS_HOLDER.set(Boolean.TRUE); + } + + public static Boolean isNotSwitchAlways(){ + return CONTEXT_NOTSWITCH_ALWAYS_HOLDER.get(); + } + + public static void clearNotSwitchAlwaysFlag(){ + CONTEXT_NOTSWITCH_ALWAYS_HOLDER.remove(); + } + + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/ResetSetHolder.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/ResetSetHolder.java new file mode 100644 index 0000000..7234f5d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/ResetSetHolder.java @@ -0,0 +1,34 @@ +package com.yunzhupaas.database.util; + +import java.sql.ResultSet; + +/** + * 在SqlSessionFactory.openSession().select方法里ResultHandler中获取 + * mybatis执行完后resultSet已关闭不可用 + * + * 此缓存会在ResultSetInterceptor自动清空, 无需手动清空 + * + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/14 17:12 + */ +public class ResetSetHolder { + + + private static final ThreadLocal RESULTSET_HOLDER = new ThreadLocal<>(); + + public static ResultSet getResultSet(){ + return RESULTSET_HOLDER.get(); + } + + public static void setResultSet(ResultSet resultSet){ + RESULTSET_HOLDER.set(resultSet); + } + + public static void clear(){ + RESULTSET_HOLDER.remove(); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/TableUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/TableUtil.java new file mode 100644 index 0000000..be9f38f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/TableUtil.java @@ -0,0 +1,61 @@ +package com.yunzhupaas.database.util; + +import com.yunzhupaas.database.constant.DbConst; + +import java.util.Random; + +/** + * 表字段相关工具类 + * + * @author 云筑产品开发平台组 + * @version V3.3 + * @copyright 深圳市乐程软件有限公司 + * @date 2024-06-08 + */ +public class TableUtil { + + + /** + * 随机生成包含大小写字母及数字的字符串 + * + * @param length 随机字符串长度 + * @return 随机字符串 + */ + public static String getStringRandom(int length) { + StringBuilder val = new StringBuilder(); + Random random = new Random(); + //参数length,表示生成几位随机数 + for (int i = 0; i < length; i++) { + String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num"; + //输出字母还是数字 + if ("char".equalsIgnoreCase(charOrNum)) { + //输出是大写字母还是小写字母 + int temp = random.nextInt(2) % 2 == 0 ? 65 : 97; + val.append((char) (random.nextInt(26) + temp)); + } else { + val.append(random.nextInt(10)); + } + } + return val.toString(); + } + + /** + * 检测自带表 + * + * @param tableName 表明 + * @return ignore + */ + public static Boolean checkByoTable(String tableName) { + String[] tables = DbConst.BYO_TABLE.split(","); + boolean exists; + for (String table : tables) { + exists = tableName.toLowerCase().equals(table); + if (exists) { + return true; + } + } + return false; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/TenantDataSourceUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/TenantDataSourceUtil.java new file mode 100644 index 0000000..efbd0e6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/java/com/yunzhupaas/database/util/TenantDataSourceUtil.java @@ -0,0 +1,653 @@ +package com.yunzhupaas.database.util; + +import cn.hutool.core.text.StrPool; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.dynamic.datasource.ds.ItemDataSource; +import com.baomidou.dynamic.datasource.enums.DdConstants; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.config.ConfigValueUtil; +import com.yunzhupaas.constant.GlobalConst; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.consts.AuthConsts; +import com.yunzhupaas.exception.TenantInvalidException; +import com.yunzhupaas.model.tenant.TenantAuthorizeModel; +import com.yunzhupaas.model.tenant.TenantLinkModel; +import com.yunzhupaas.model.tenant.TenantMenuModel; +import com.yunzhupaas.model.tenant.TenantVO; +import com.yunzhupaas.database.model.entity.DbLinkEntity; +import com.yunzhupaas.database.model.interfaces.DbSourceOrDbLink; +import com.yunzhupaas.database.plugins.MySchemaInnerInterceptor; +import com.yunzhupaas.database.plugins.MyTenantLineInnerInterceptor; +import com.yunzhupaas.database.source.DbBase; +import com.yunzhupaas.database.source.impl.DbKingbase; +import com.yunzhupaas.database.source.impl.DbPostgre; +import com.yunzhupaas.exception.LoginException; +import com.yunzhupaas.util.*; +import com.yunzhupaas.util.data.DataSourceContextHolder; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.select.Select; +import org.apache.http.HttpStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import javax.sql.DataSource; +import java.sql.SQLException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 租户数据工具类 + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/10/13 16:16 + */ +@Slf4j +@Component +public class TenantDataSourceUtil { + + public static final String DBLINK_KEY = "TenantInfo"; + + public static final String MODULEID_KEY = "ModuleAuthorize"; + + private static ConfigValueUtil configValueUtil; + + private static MyTenantLineInnerInterceptor myTenantLineInnerInterceptor; + + private static MySchemaInnerInterceptor mySchemaInnerInterceptor; + + private static boolean absentPermittionApi = false; + + + @Autowired(required = false) + public void setDynamicTableNameInnerInterceptor(MySchemaInnerInterceptor mySchemaInnerInterceptor) { + TenantDataSourceUtil.mySchemaInnerInterceptor = mySchemaInnerInterceptor; + } + + @Autowired(required = false) + public void setMyTenantLineInnerInterceptor(MyTenantLineInnerInterceptor myTenantLineInnerInterceptor) { + TenantDataSourceUtil.myTenantLineInnerInterceptor = myTenantLineInnerInterceptor; + } + + @Autowired + public void setConfigValueUtil(ConfigValueUtil configValueUtil) { + TenantDataSourceUtil.configValueUtil = configValueUtil; + } + + + /** + * 清空本地租户缓存信息 + */ + public static void clearLocalTenantInfo(){ + TenantHolder.clearLocalTenantCache(); + DataSourceContextHolder.clearDatasourceType(); + } + + /** + * 设置租户信息到Redis缓存中 + * + * @param tenantCode + * @param tenant + */ + public static void setCacheTenantInfo(String tenantCode, TenantVO tenant) { + TenantProvider.putTenantCache(tenantCode, DBLINK_KEY, tenant); + } + + /** + * 设置租户菜单权限信息到Redis缓存中 + * + * @param tenantCode + * @param tenantAuthorizeModel + */ + public static void setCacheModuleAuthorize(String tenantCode, TenantAuthorizeModel tenantAuthorizeModel) { + TenantProvider.putTenantCache(tenantCode, MODULEID_KEY, tenantAuthorizeModel); + } + + /** + * 设置租户信息到Redis缓存、线程缓存中 + * @param tenantInfo + */ + public static void setTenantInfo(TenantVO tenantInfo){ + setCacheTenantInfo(tenantInfo.getEnCode(), tenantInfo); + TenantHolder.setLocalTenantCache(tenantInfo); + + } + + /** + * 获取当前租户信息 + * + * @return + */ + public static TenantVO getTenantInfo() { + return getTenantInfo(null); + } + + /** + * 从本地线程、Redis缓存或远程获取租户信息 + * + * @param tenantCode + * @return + */ + public static TenantVO getTenantInfo(String tenantCode) { + if(!isMultiTenancy()) return null; + TenantVO tenantVO = TenantHolder.getLocalTenantCache(); + if(StringUtil.isEmpty(tenantCode)) { + if (tenantCode == null) { + UserInfo userInfo = UserProvider.getUser(); + if (userInfo != null && userInfo.getUserId() != null) { + tenantCode = userInfo.getTenantId(); + } + } + } + //判断线程缓存中的租户信息是否是当前需要获取的租户 + if(tenantVO != null && StringUtil.isNotEmpty(tenantCode) && !Objects.equals(tenantVO.getEnCode(), tenantCode)){ + tenantVO = null; + } + if(StringUtil.isEmpty(tenantCode) && tenantVO == null){ + return null; + } + if(tenantVO == null) { + tenantVO = TenantDataSourceUtil.getCacheTenantInfo(tenantCode); + if (tenantVO == null) { + tenantVO = TenantDataSourceUtil.getRemoteTenantInfo(tenantCode); + } + } + return tenantVO; + } + + /** + * 从Redis缓存中获取租户信息 + * + * @param tenantCode + * @return + */ + public static TenantVO getCacheTenantInfo(String tenantCode) { + return TenantProvider.getTenantCache(tenantCode, DBLINK_KEY); + } + /** + * 从Redis缓存中获取租户信息 + * + * @param tenantCode + * @return + */ + public static TenantAuthorizeModel getCacheModuleAuthorize(String tenantCode) { + TenantAuthorizeModel tenantCache = TenantProvider.getTenantCache(tenantCode, MODULEID_KEY); + return Optional.ofNullable(tenantCache).isPresent() ? tenantCache : new TenantAuthorizeModel(); + } + + + /** + * 从租户系统获取租户信息 + * + * @param tenantCode + * @return + * @throws LoginException + */ + public static TenantVO getRemoteTenantInfo(String tenantCode) throws LoginException { + if(!isMultiTenancy()) return null; + if(StringUtil.isEmpty(tenantCode)){ + throw new LoginException(MsgCode.LOG114.get()); + } + Map headers = new HashMap<>(2,1); + headers.put(AuthConsts.INNER_TOKEN_KEY, UserProvider.getInnerAuthToken()); + try{ + String ip = IpUtil.getIpAddr(); + if(StringUtil.isNotEmpty(ip) && !Objects.equals("127.0.0.1", ip)) { + headers.put("X-Forwarded-For", ip); + } + }catch (Exception e){} + JSONObject object = null; + try (HttpResponse execute = HttpRequest.get(configValueUtil.getMultiTenancyUrl() + tenantCode) + .addHeaders(headers) + .execute()) { + object = JSON.parseObject(execute.body()); + }catch (Exception e){ + log.error("获取远端多租户信息失败: {}", e.getMessage()); + } + if (object == null || "500".equals(object.get("code").toString())) { + throw new LoginException(MsgCode.LOG105.get()); + } + if ("400".equals(object.getString("code"))) { + log.error("获取多租户信息失败:{}", object.getString("msg")); + JSON data = null; + if(object.containsKey("data")){ + data = object.getJSONObject("data"); + } + throw new TenantInvalidException(object.getString("msg")).setData(data); + } + JSONObject resulList = object.getJSONObject("data"); + // 租户库名 + TenantVO vo; + if (resulList.containsKey("db_names")){ + vo = JsonUtil.getJsonToBean(resulList.getJSONObject("db_names"), TenantVO.class); + if(vo.getDbName() == null){ + vo.setDbName((String) resulList.getJSONObject("db_names").get("java")); + } + vo.setWl_qrcode(resulList.getObject("wl_qrcode", new TypeReference>(){})); + } else{ + vo = new TenantVO(); + vo.setDbName(resulList.getString("java")); + } + if(Objects.equals(vo.getType(), TenantVO.REMOTE)){ + //取主库库名作为租户库名 + vo.setDbName(vo.getLinkList().stream().filter(l->l.getConfigType().equals(0)).findFirst().get().getServiceName()); + }else{ + if(StringUtil.isEmpty(vo.getDbName())){ + throw new TenantInvalidException().setLogMsg(MsgCode.LOG118.get()); + } + } + vo.setEnCode(tenantCode); + TenantDataSourceUtil.setCacheTenantInfo(tenantCode, vo); + if(!absentPermittionApi) { + try (HttpResponse execute = HttpRequest.get(configValueUtil.getMultiTenancyUrl() + "authorize/" + tenantCode) + .addHeaders(headers) + .execute()) { + switch (execute.getStatus()){ + case HttpStatus.SC_OK: + TenantMenuModel model = JsonUtil.getJsonToBean(execute.body(), TenantMenuModel.class); + TenantAuthorizeModel tenantAuthorizeModel = new TenantAuthorizeModel(model.getIds(), model.getUrlAddressList()); + TenantDataSourceUtil.setCacheModuleAuthorize(tenantCode, tenantAuthorizeModel); + break; + case HttpStatus.SC_NOT_FOUND: + absentPermittionApi = true; + log.error("租户系统不存在权限管理接口, 关闭权限请求功能"); + break; + default: + log.error("获取远端多租户菜单权限失败: {}, {}", tenantCode, execute.body()); + } + } catch (Exception e) { + TenantDataSourceUtil.setCacheModuleAuthorize(tenantCode, new TenantAuthorizeModel()); + log.error("获取远端多租户菜单权限失败: {}, {}", tenantCode, e.getMessage()); + } + } + + return vo; + } + + + /** + * 获取租户指定库主库 + * @param tenantCode + * @return + */ + public static TenantLinkModel getTenantAssignDataSource(String tenantCode){ + List linkList = getTenantAssignDataSourceList(tenantCode); + return linkList.stream().filter(link->link.getConfigType().equals(0)).findFirst().orElse(null); + } + + /** + * 获取租户指定库列表 + * @param tenantCode + * @return + */ + public static List getTenantAssignDataSourceList(String tenantCode){ + if(isMultiTenancy()){ + TenantVO tenantVO = getTenantInfo(tenantCode); + List linkList = tenantVO.getLinkList(); + return linkList; + } + return Collections.EMPTY_LIST; + } + + /** + * 切换至当前用户的租户 + */ + public static void resetUserTenant(){ + + } + + /** + * 切换租户, 先从Redis缓存中获取, 再从租户系统中获取 + * + * @param tenantCode + */ + public static TenantVO switchTenant(String tenantCode) { + if(!isMultiTenancy()) return null; + TenantHolder.clearLocalTenantCache(); + TenantVO tenantVO = TenantDataSourceUtil.getTenantInfo(tenantCode); + switchTenant(tenantCode, tenantVO); + return tenantVO; + } + + + /** + * 切换租户 + */ + public static void switchTenant(String tenantCode, TenantVO tenantVO) throws LoginException { + if(!isMultiTenancy()) return; + if (!Optional.ofNullable(tenantVO).isPresent()) { + throw new LoginException(MsgCode.LOG115.get()); + } + boolean isAssign = Objects.equals(tenantVO.getType(), TenantVO.REMOTE); + TenantHolder.setLocalTenantCache(tenantVO); + try { + initTenantAssignDataSource(tenantVO); + } catch (SQLException e) { + throw new RuntimeException(e); + } + DataSourceContextHolder.setDatasource(tenantCode, tenantVO.getDbName(), isAssign); + } + + /** + * 获取库隔离模式的租户库名称 + * + * @return + */ + public static String getTenantSchema() { + String result = StringUtil.EMPTY; + if (isTenantSchema()) { + result = getTenantName(); + } + return result; + } + + /** + * 获取字段隔离的租户库名称, 非字段隔离返回默认值 0 + * + * @return + */ + public static String getTenantColumn() { + String result = GlobalConst.DEFAULT_TENANT_VALUE; + if (isTenantColumn()) { + result = getTenantName(); + } + return result; + } + + /** + * 获取当前租户名 + * 字段模式返回对应数据库默认隔离实现方式的库名 Postgre、Kingbase模式隔离 Mysql、Sqlserver、Oracle、DM库隔离 + * 租户指定数据源和Schema模式返回租户库名 + * + * @return + */ + public static String getTenantDbName() { + String result = StringUtil.EMPTY; + if (isMultiTenancy()) { + DataSourceUtil dataSourceUtil = DynamicDataSourceUtil.getDataSourceUtil(); + if(isTenantColumn()){ + switch (dataSourceUtil.getDbType()){ + case DbBase.POSTGRE_SQL: + result = StringUtil.isEmpty(dataSourceUtil.getDbSchema()) ? DbPostgre.DEF_SCHEMA : dataSourceUtil.getDbSchema(); + break; + case DbBase.KINGBASE_ES: + result = StringUtil.isEmpty(dataSourceUtil.getDbSchema()) ? DbKingbase.DEF_SCHEMA : dataSourceUtil.getDbSchema(); + break; + case DbBase.ORACLE: + default: + result = dataSourceUtil.getDbName(); + } + }else{ + result = TenantHolder.getDatasourceName(); + result = convertSchemaName(result); + } + } + return result; + } + + public static void initDataSourceTenantDbName(DbSourceOrDbLink dataSourceUtil){ + if(isMultiTenancy()) { + if(isTenantAssignDataSource()){ + return; + } + if (!(dataSourceUtil instanceof DataSourceUtil) || (dataSourceUtil instanceof DbLinkEntity && !"0".equals(((DbLinkEntity) dataSourceUtil).getId()) && ((DbLinkEntity) dataSourceUtil).getId() != null)) { + return; + } + boolean isColumn = isTenantColumn(); + //默认库在多租户Schema模式情况下需要切库 + //字段多租户模式下, Schema为空设置默认值 + DataSourceUtil ds = (DataSourceUtil) dataSourceUtil; + switch (ds.getDbType()){ + case DbBase.POSTGRE_SQL: + if(isColumn){ + if(StringUtil.isEmpty(ds.getDbSchema())) { + ds.setDbSchema(DbPostgre.DEF_SCHEMA); + } + }else { + ds.setDbSchema(TenantDataSourceUtil.getTenantDbName()); + } + break; + case DbBase.KINGBASE_ES: + if(isColumn){ + if(StringUtil.isEmpty(ds.getDbSchema())) { + ds.setDbSchema(DbKingbase.DEF_SCHEMA); + } + }else { + ds.setDbSchema(TenantDataSourceUtil.getTenantDbName()); + } + break; + case DbBase.DM: + case DbBase.ORACLE: + ds.setDbSchema(TenantDataSourceUtil.getTenantDbName()); + break; + default: + ds.setDbName(TenantDataSourceUtil.getTenantDbName()); + } + } + + } + + + /** + * 获取当前租户名 + * + * @return + */ + public static String getTenantName() { + String result = StringUtil.EMPTY; + if (isMultiTenancy() && !getTenantInfo().isRemote()) { + result = TenantHolder.getDatasourceName(); + result = convertSchemaName(result); + } + return result; + } + + /** + * 转换不同数据库租户模式名 + * @param dbName + * @return + */ + public static String convertSchemaName(String dbName){ + if(StringUtil.isNotEmpty(dbName)) { + switch (DynamicDataSourceUtil.dataSourceUtil.getDbType()) { + case DbBase.POSTGRE_SQL: + dbName = dbName.toLowerCase(); + break; + case DbBase.ORACLE: + dbName = dbName.toUpperCase(); + break; + } + } + return dbName; + } + + /** + * 初始化连接隔离数据源 + * @throws SQLException + */ + public static void initTenantAssignDataSource(TenantVO tenantVO) throws SQLException { + if(isTenantAssignDataSource()){ + String tenantId = TenantHolder.getDatasourceId(); + String dbKey = tenantId + StrPool.DASHED + DdConstants.MASTER; + synchronized (LockObjectUtil.addLockKey(tenantId)) { + if(!DynamicDataSourceUtil.dynamicRoutingDataSource.getGroupDataSources().containsKey(dbKey)) { + List list = new ArrayList<>(16); + List linkList = tenantVO.getLinkList(); + Assert.notNull(linkList, MsgCode.FA035.get()); + // 添加数据源信息到redis中 + String mKey = dbKey + StrPool.UNDERLINE; + String sKey = tenantId + StrPool.DASHED + DdConstants.SLAVE + StrPool.UNDERLINE; + for (TenantLinkModel model : linkList) { + DbLinkEntity dbLinkEntity = model.toDbLink(new DbLinkEntity()); + if ("0".equals(String.valueOf(model.getConfigType()))) { + dbLinkEntity.setId(mKey + dbLinkEntity.getId()); + } else { + dbLinkEntity.setId(sKey + dbLinkEntity.getId()); + } + try { + DataSource dataSource = DynamicDataSourceUtil.createDataSource(dbLinkEntity); + dataSource.getConnection().close(); + list.add(dbLinkEntity.getId()); + DynamicDataSourceUtil.dynamicRoutingDataSource.addDataSource(dbLinkEntity.getId(), dataSource); + } catch (SQLException e) { + for (String s : list) { + try { + DynamicDataSourceUtil.dynamicRoutingDataSource.removeDataSource(s); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + throw e; + } + } + } + } + } + } + + /** + * 移除当前租户的指定数据源信息 + */ + public static void removeAllAssignDataSource(){ + if(isTenantAssignDataSource()) { + String tenantId = TenantHolder.getDatasourceId(); + String dbKey = tenantId + StrPool.DASHED + DdConstants.MASTER; + TenantVO tenantVO = TenantDataSourceUtil.getTenantInfo(); + if(tenantVO != null) { + List linkList = tenantVO.getLinkList(); + if (linkList != null) { + // 添加数据源信息到redis中 + String mKey = dbKey + StrPool.UNDERLINE; + String sKey = tenantId + StrPool.DASHED + DdConstants.SLAVE + StrPool.UNDERLINE; + for (TenantLinkModel model : linkList) { + DbLinkEntity dbLinkEntity = model.toDbLink(new DbLinkEntity()); + String key; + if ("0".equals(String.valueOf(model.getConfigType()))) { + key = mKey + dbLinkEntity.getId(); + } else { + key = sKey + dbLinkEntity.getId(); + } + try { + DataSource dataSource = DynamicDataSourceUtil.dynamicRoutingDataSource.getDataSources().get(key); + if (dataSource instanceof ItemDataSource && ((ItemDataSource) dataSource).getRealDataSource() instanceof DruidDataSource) { + //Druid数据源如果正在获取数据源 有概率连接创建线程无法停止 + ((DruidDataSource) ((ItemDataSource) dataSource).getRealDataSource()).setBreakAfterAcquireFailure(true); + } + DynamicDataSourceUtil.dynamicRoutingDataSource.removeDataSource(key); + } catch (Exception e) { + + } + } + } + }else{ + log.error("获取缓存租户库列表失败: {}", tenantId); + } + } + } + + /** + * 获取租户指定数据源 在连接池中的主库KEY + * @return + */ + public static String getTenantAssignDataSourceMasterKeyName(){ + if(isTenantAssignDataSource()){ + return TenantHolder.getDatasourceId() + StrPool.DASHED +DdConstants.MASTER; + } + return StringUtil.EMPTY; + } + + public static boolean isMultiTenancy(){ + return configValueUtil.isMultiTenancy(); + } + + public static boolean isTenantAssignDataSource(){ + return isMultiTenancy() && getTenantInfo().isRemote(); + } + + /** + * 是否开启多租户, 且Column模式 + * @return + */ + public static boolean isTenantColumn(){ + return isMultiTenancy() && getTenantInfo().isColumn(); + } + + /** + * 是否开启多租户, 且Schema模式 + * @return + */ + public static boolean isTenantSchema(){ + return isMultiTenancy() && getTenantInfo().isSchema(); + } + + + /** + * 将SQL语句添加多租户过滤 + * @param sql + * @return + */ + public static String parseTenantSql(String sql){ + if (isTenantColumn()) { + try { + Statement statement = CCJSqlParserUtil.parse(sql); + if (statement instanceof Select) { + return myTenantLineInnerInterceptor.parserSingle(sql, null); + } else { + return myTenantLineInnerInterceptor.parserMulti(sql, null); + } + } catch(JSQLParserException e){ + throw new RuntimeException(e); + } + }else if(isTenantSchema()){ + return mySchemaInnerInterceptor.changeTable(sql); + } + return sql; + } + + /** + * 官网租户短信验证码专用 + * @param mobile 手机号 + * @param code 验证码 + * @param type 验证类型, 1:登录, 2:重置密码 + * @return + */ + public static boolean checkOfficialSmsCode(String mobile, String code, int type) throws LoginException { + String url; + switch (type){ + case 1: + url = configValueUtil.getMultiTenancyOfficialLoginCodeUrl(); + break; + case 2: + url = configValueUtil.getMultiTenancyOfficialResetCodeUrl(); + break; + default: + throw new RuntimeException(MsgCode.LOG116.get()); + } + JSONObject object = null; + try (HttpResponse execute = HttpRequest.get(String.format("%s%s/%s", url, mobile, code)) + .execute()) { + object = JSON.parseObject(execute.body()); + }catch (Exception e){ + log.error("校验官网短信失败", e); + } + if (object == null || Objects.equals(500, object.getIntValue("code"))) { + throw new LoginException(MsgCode.LOG105.get()); + } + if (!Objects.equals(200, object.getIntValue("code"))) { + throw new LoginException(MsgCode.LOG117.get(object.getString("msg"))); + } + return true; + + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/resources/mapper/JdbcMapper.xml b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/resources/mapper/JdbcMapper.xml new file mode 100644 index 0000000..10297c3 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-database/src/main/resources/mapper/JdbcMapper.xml @@ -0,0 +1,25 @@ + + + + + + + + ${sql} + + + + ${sql} + + + + ${sql} + + + + ${sql} + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-event/pom.xml new file mode 100644 index 0000000..98d6263 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + com.yunzhupaas + yunzhupaas-boot-common + 5.2.0-RELEASE + ../pom.xml + + + yunzhupaas-common-event + + + + com.yunzhupaas + yunzhupaas-common-database + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/config/ProjectEventAutoConfiguration.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/config/ProjectEventAutoConfiguration.java new file mode 100644 index 0000000..6ae8b36 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/config/ProjectEventAutoConfiguration.java @@ -0,0 +1,63 @@ +package com.yunzhupaas.config; + +import com.baomidou.lock.LockTemplate; +import com.yunzhupaas.consts.ProjectEventConst; +import com.yunzhupaas.event.*; +import com.yunzhupaas.handler.ProjectEventRedisMessageHandler; +import com.yunzhupaas.handler.ProjectEventRedisSender; +import com.yunzhupaas.event.ProjectEventSender; +import com.yunzhupaas.properties.EventProperty; +import com.yunzhupaas.util.PublishEventUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; + +@Configuration(proxyBeanMethods = false) +public class ProjectEventAutoConfiguration { + + + + @Bean + @ConfigurationProperties(prefix = EventProperty.PREFIX) + public EventProperty getEventProperties(){ + return new EventProperty(); + } + + + @Bean + public ProjectEventListenerAnnotationBeanPostProcessor getProjectEventListenerAnnotationBeanPostProcessor(){ + return new ProjectEventListenerAnnotationBeanPostProcessor(); + } + + @Bean + public ProjectEventProccess getProjectEventProccess(LockTemplate lockTemplate, ConfigValueUtil configValueUtil){ + return new ProjectEventProccess(lockTemplate, configValueUtil); + } + + @Bean + @ConditionalOnProperty(prefix = "event", name = "event-publish-type", havingValue = ProjectEventConst.EVENT_PUBLISH_TYPE_REDIS, matchIfMissing = true) + public ProjectEventRedisMessageHandler getProjectEventRedisMessageHandler(RedisMessageListenerContainer container, EventProperty eventProperty){ + return new ProjectEventRedisMessageHandler(container, eventProperty); + } + + /** + * 自定义事件发布渠道为QUEUE + */ + @Bean + @ConditionalOnProperty(prefix = "event", name = "event-publish-type", havingValue = ProjectEventConst.EVENT_PUBLISH_TYPE_REDIS, matchIfMissing = true) + public ProjectEventRedisSender getProjectEventRedisSender(RedisTemplate redisTemplate, EventProperty eventProperty){ + return new ProjectEventRedisSender(redisTemplate, eventProperty); + } + + + @Bean + public PublishEventUtil getPublishEventUtil(@Autowired(required = false) ProjectEventSender eventSender){ + return new PublishEventUtil(eventSender); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/consts/ProjectEventConst.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/consts/ProjectEventConst.java new file mode 100644 index 0000000..a0d4e1d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/consts/ProjectEventConst.java @@ -0,0 +1,56 @@ +package com.yunzhupaas.consts; + +/** + * 自定义事件常量 + */ +public class ProjectEventConst { + + public static final String DEFAULT_TOPIC_NAME = "defMsgToptic"; + + + + /** + * 自定义通知渠道 Redis + */ + public static final String EVENT_PUBLISH_TYPE_REDIS = "redis"; + /** + * 自定义通知渠道 MQ + */ + public static final String EVENT_PUBLISH_TYPE_QUEUE = "mq"; + + + + + /** + * Redis事件监听模式, 当前DB + */ + public static final String REDIS_PUBLISH_TYPE_CURRENT = "current"; + + /** + * Redis事件监听模式, 相同Redis(全部DB) 多个环境使用相同的Redis实例都会触发事件 + */ + public static final String REDIS_PUBLISH_TYPE_ALL = "all"; + + /** + * Redis事件消息监听前缀 + */ + public static final String DEFAULT_CHANNEL_PREFIX = "myevent_"; + + + + /** + * 集群消费, 只有一个服务消费成功 + */ + public static final int EVENT_PUBLISH_MODEL_CLUSTERING = 1; + + /** + * 广播消费, 所有服务都可以消费 + */ + public static final int EVENT_PUBLISH_MODEL_BROADCASTING = 2; + + /** + * 本地消息, 只在当前进程触发事件 + */ + public static final int EVENT_PUBLISH_MODEL_LOCAL = 3; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventHolder.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventHolder.java new file mode 100644 index 0000000..29ddef7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventHolder.java @@ -0,0 +1,58 @@ +package com.yunzhupaas.event; + +import com.yunzhupaas.consts.ProjectEventConst; +import com.yunzhupaas.module.ProjectEvent; + +import java.util.*; +import java.util.function.Consumer; + +/** + * 自定义事件注册 + */ +public class ProjectEventHolder { + + private ProjectEventHolder() { + } + + /** + * {topic:{keymatcher:consumer}} + */ + private static final Map>> events = new HashMap<>(); + + /** + * 添加事件处理器, 默认主题 + */ + public static void addEventListener(ProjectEventKeyMatcher keyMatcher, Consumer consumer) { + addEventListener(ProjectEventConst.DEFAULT_TOPIC_NAME, keyMatcher, consumer); + } + + /** + * 添加事件处理器 + */ + public static void addEventListener(String topic, ProjectEventKeyMatcher keyMatcher, Consumer consumer) { + Map> topicEvents = events.computeIfAbsent(topic, k -> new HashMap<>()); + topicEvents.put(keyMatcher, consumer); + } + + /** + * 获取事件匹配的处理器, 默认主题 + */ + public static List> getEventListener(ProjectEvent event) { + return getEventListener(ProjectEventConst.DEFAULT_TOPIC_NAME, event); + } + + /** + * 获取事件匹配的处理器 + */ + public static List> getEventListener(String topic, ProjectEvent event) { + Map> topicEvents = events.getOrDefault(topic, Collections.emptyMap()); + List> consumers = new ArrayList<>(); + for (Map.Entry> entry : topicEvents.entrySet()) { + if(entry.getKey().isMatch(event)){ + consumers.add(entry.getValue()); + } + } + return consumers; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventKeyMatcher.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventKeyMatcher.java new file mode 100644 index 0000000..5453cbd --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventKeyMatcher.java @@ -0,0 +1,94 @@ +package com.yunzhupaas.event; + +import com.yunzhupaas.module.ProjectEvent; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; + +import java.util.Objects; +import java.util.function.Predicate; + +/** + * 事件匹配 + */ +public class ProjectEventKeyMatcher { + + + protected String expression; + + public ProjectEventKeyMatcher(String expression) { + this.expression = expression; + } + + public Predicate getMatcher() { + return null; + } + + protected String getExpression() { + return expression; + } + + public boolean isMatch(ProjectEvent event){ + return getMatcher().test(event); + } + + /** + * 文本直接匹配 + */ + public static class Text extends ProjectEventKeyMatcher { + + public Text(String expression) { + super(expression); + } + + private final Predicate matcher = target -> Objects.equals(target.getChannel(), getExpression()); + + @Override + public Predicate getMatcher() { + return matcher; + } + } + + + /** + * 正则匹配 String.matches匹配 + */ + public static class Pattern extends ProjectEventKeyMatcher { + + public Pattern(String expression) { + super(expression); + } + + private final Predicate matcher = target -> target.getChannel().matches(expression); + + @Override + public Predicate getMatcher() { + return matcher; + } + } + + /** + * SpEL表达式匹配 + */ + public static class Spel extends ProjectEventKeyMatcher { + + private static final ExpressionParser spelExpressionParserarser = new SpelExpressionParser(); + + public Spel(String expression) { + super(expression); + } + + private final Predicate matcher = target -> { + Expression expression1 = spelExpressionParserarser.parseExpression(expression); + return Boolean.TRUE.equals(expression1.getValue(target, Boolean.TYPE)); + }; + + @Override + public Predicate getMatcher() { + return matcher; + } + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventListener.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventListener.java new file mode 100644 index 0000000..be8ba8c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventListener.java @@ -0,0 +1,36 @@ +package com.yunzhupaas.event; + +import com.yunzhupaas.consts.ProjectEventConst; +import org.springframework.context.event.EventListener; + +import java.lang.annotation.*; + +/** + * 自定义事件处理器注解 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface ProjectEventListener { + + String toptic() default ProjectEventConst.DEFAULT_TOPIC_NAME; + + /** + * 直接匹配 + */ + String[] channel() default {}; + + /** + * 正则匹配 + */ + String[] channelRegex() default {}; + + /** + * SpELl表达式匹配, 结果必须boolean类型 + * @see EventListener#condition() + */ + String[] channelSpel() default {}; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventListenerAnnotationBeanPostProcessor.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventListenerAnnotationBeanPostProcessor.java new file mode 100644 index 0000000..9bcd16b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventListenerAnnotationBeanPostProcessor.java @@ -0,0 +1,110 @@ +package com.yunzhupaas.event; + +import cn.hutool.core.util.ReflectUtil; +import com.yunzhupaas.config.ApplicationStartErrorCheck; +import com.yunzhupaas.constant.GlobalConst; +import com.yunzhupaas.module.ProjectEvent; +import com.yunzhupaas.module.ProjectEventInstance; +import com.yunzhupaas.util.StringUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 自定义事件处理器扫描 + */ +@Slf4j +public class ProjectEventListenerAnnotationBeanPostProcessor implements BeanPostProcessor{ + + private List scanPackages = Arrays.asList(GlobalConst.PROJECT_SCAN_PACKAGES.split(";")); + private List initedClass = new ArrayList<>(); + + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + Class targetClass = AopUtils.isAopProxy(bean) ? AopUtils.getTargetClass(bean) + : bean.getClass(); + boolean isMatch = scanPackages.stream().anyMatch(s -> targetClass.getName().startsWith(s)); + if(isMatch) { + if(!initedClass.contains(targetClass)) { + ApplicationStartErrorCheck.getApplicationInitThreadPool().execute(() -> { + try { + initedClass.add(targetClass); + Method[] uniqueDeclaredMethods = ReflectionUtils + .getUniqueDeclaredMethods(targetClass, ReflectionUtils.USER_DECLARED_METHODS); + for (Method method : uniqueDeclaredMethods) { + ProjectEventListener listener = AnnotatedElementUtils + .findMergedAnnotation(method, ProjectEventListener.class); + if (listener != null) { + String[] channel = listener.channel(); + String[] channelPattern = listener.channelRegex(); + String[] channelSpel = listener.channelSpel(); + Set channelSet = Arrays.stream(channel).filter(StringUtil::isNotEmpty).collect(Collectors.toSet()); + Set channelPatternSet = Arrays.stream(channelPattern).filter(StringUtil::isNotEmpty).collect(Collectors.toSet()); + Set channelSpelSet = Arrays.stream(channelSpel).filter(StringUtil::isNotEmpty).collect(Collectors.toSet()); + if (channelSet.isEmpty() && channelPatternSet.isEmpty() && channelSpelSet.isEmpty()) { + throw new IllegalArgumentException(getLogText(beanName, method.getName(), "channel和channelPattern和channelSpel必须填写一个")); + } + + // 检查参数数量小于等于1 + int paramCount = method.getParameterCount(); + if (paramCount > 1) { + throw new IllegalArgumentException(getLogText(beanName, method.getName(), "参数只能小于1个")); + } else if (paramCount == 1) { + if (!method.getParameterTypes()[0].equals(ProjectEventInstance.class)) { + throw new IllegalArgumentException(getLogText(beanName, method.getName(), "参数只能是com.yunzhupaas.module.ProjectEventInstance")); + } + } + + String topic = listener.toptic(); + Assert.hasLength(topic, "主题不允许为空"); + for (String s : channelSet) { + ProjectEventHolder.addEventListener(topic, new ProjectEventKeyMatcher.Text(s), event -> { + invokeMethod(bean, method, event); + }); + } + for (String s : channelPatternSet) { + ProjectEventHolder.addEventListener(topic, new ProjectEventKeyMatcher.Pattern(s), event -> { + invokeMethod(bean, method, event); + }); + } + for (String s : channelSpelSet) { + ProjectEventHolder.addEventListener(topic, new ProjectEventKeyMatcher.Spel(s), event -> { + invokeMethod(bean, method, event); + }); + } + if(log.isDebugEnabled()) { + log.debug(getLogText(beanName, method.getName(), "注册成功")); + } + } + } + } catch (Exception e) { + ApplicationStartErrorCheck.setStartError(); + throw e; + } + }); + } + } + return bean; + } + + private void invokeMethod(Object bean, Method method, ProjectEvent topicEvent) { + ReflectUtil.invoke(bean, method, topicEvent); + } + + private String getLogText(String bean, String method, String text) { + return "@ProjectEventListener注解的对象[" + bean + "]方法[" + method + "]" + text; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventProccess.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventProccess.java new file mode 100644 index 0000000..b5d822c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventProccess.java @@ -0,0 +1,110 @@ +package com.yunzhupaas.event; + +import cn.hutool.core.text.StrPool; +import com.alibaba.fastjson.JSON; +import com.baomidou.lock.LockInfo; +import com.baomidou.lock.LockTemplate; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.config.ConfigValueUtil; +import com.yunzhupaas.consts.ProjectEventConst; +import com.yunzhupaas.consts.RedisConst; +import com.yunzhupaas.database.util.TenantDataSourceUtil; +import com.yunzhupaas.module.ProjectEvent; +import com.yunzhupaas.module.ProjectEventInstance; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.UserProvider; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; + +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; + +/** + * 自定义事件执行 + */ +@Slf4j +public class ProjectEventProccess { + + private final LockTemplate lockTemplate; + private final ConfigValueUtil configValueUtil; + + /** + * 集群模式锁定事件 + */ + private final long LOCK_TIME = 24 * 60 * 60000L; + + public ProjectEventProccess(LockTemplate lockTemplate, ConfigValueUtil configValueUtil) { + this.lockTemplate = lockTemplate; + this.configValueUtil = configValueUtil; + } + + /** + * 同步执行 + * + * @param event + */ + @EventListener(condition = "!#event.async") + public void onApplicationEvent(ProjectEventInstance event) { + processEvent(event); + } + + /** + * 异步执行 + * + * @param event + */ + @Async + @EventListener(condition = "#event.async") + public void onApplicationEventAsync(ProjectEventInstance event) { + processEvent(event); + } + + private void processEvent(ProjectEvent event) { + String topic = event.getToptic(); + List> eventListener = ProjectEventHolder.getEventListener(topic, event); + LockInfo lock = null; + // 集群消费模式, 添加Redis锁 + if (!eventListener.isEmpty() && Objects.equals(event.getMessageModel(), ProjectEventConst.EVENT_PUBLISH_MODEL_CLUSTERING)) { + // lock:服务名:事件编号 + String key = RedisConst.REDIS_LOCK4J_PREFIX + StrPool.COLON + configValueUtil.getApplicationName() + StrPool.COLON + event.getEventId().toString(); + lock = lockTemplate.lock(key, LOCK_TIME, 0L); + if (lock == null) { + if (log.isDebugEnabled()) { + log.debug("事件在其他服务已经处理: {}", JSON.toJSONString(event)); + } + return; + } + } + try { + // 设置用户信息 + if (!eventListener.isEmpty()) { + UserInfo userInfo = null; + // 初始化线程用户信息 + if (event.getToken() != null) { + userInfo = UserProvider.getUser(event.getToken()); + UserProvider.setLocalLoginUser(userInfo); + } + // 开启多租户 切库 + if (configValueUtil.isEnableLogicDelete()) { + if (userInfo != null && StringUtil.isNotEmpty(userInfo.getTenantId())) { + // 优先从用户获取多租户 + TenantDataSourceUtil.switchTenant(userInfo.getTenantId()); + } else if (event.getTenantId() != null) { + // 从事件里获取多租户 + TenantDataSourceUtil.switchTenant(event.getTenantId()); + } + } + } + for (Consumer consumer : eventListener) { + consumer.accept(event); + } + } catch (Exception e) { + lockTemplate.releaseLock(lock); + log.error("事件处理失败: {}", event, e); + throw e; + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventSender.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventSender.java new file mode 100644 index 0000000..99e7901 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/event/ProjectEventSender.java @@ -0,0 +1,12 @@ +package com.yunzhupaas.event; + +import com.yunzhupaas.module.ProjectEvent; + +/** + * 事件发送渠道 + */ +public interface ProjectEventSender { + + void send(ProjectEvent projectEvent); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/handler/ProjectEventRedisMessageHandler.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/handler/ProjectEventRedisMessageHandler.java new file mode 100644 index 0000000..1add3a6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/handler/ProjectEventRedisMessageHandler.java @@ -0,0 +1,86 @@ +package com.yunzhupaas.handler; + +import com.alibaba.fastjson.JSON; +import jakarta.validation.constraints.NotNull; +import com.yunzhupaas.constant.GlobalConst; +import com.yunzhupaas.consts.ProjectEventConst; +import com.yunzhupaas.consts.RedisConst; +import com.yunzhupaas.module.ProjectEvent; +import com.yunzhupaas.module.ProjectEventInstance; +import com.yunzhupaas.properties.EventProperty; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.listener.KeyspaceEventMessageListener; +import org.springframework.data.redis.listener.PatternTopic; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.data.redis.listener.Topic; +import org.springframework.lang.Nullable; + +import java.util.Objects; + +/** + * 自定义事件监听, Redis渠道, 收到通知后发送Spring事件(RedisEventInstance) + */ +@Slf4j +public class ProjectEventRedisMessageHandler extends KeyspaceEventMessageListener implements ApplicationEventPublisherAware { + + private static Topic TOPIC_ALL_KEYEVENTS; + private String keyprefix; + + private @Nullable ApplicationEventPublisher publisher; + + + + + /** + * Creates new {@link KeyspaceEventMessageListener}. + * + * @param listenerContainer must not be {@literal null}. + */ + public ProjectEventRedisMessageHandler(RedisMessageListenerContainer listenerContainer, EventProperty eventProperties) { + super(listenerContainer); + if(Objects.equals(eventProperties.getRedisPublishType(), ProjectEventConst.REDIS_PUBLISH_TYPE_ALL)){ + // 只订阅当前配置的库索引 + keyprefix = ProjectEventConst.DEFAULT_CHANNEL_PREFIX; + }else{ + // 订阅同一个Redis里的所有消息 + keyprefix = RedisConst.REDIS_EVENT_KEY + ProjectEventConst.DEFAULT_CHANNEL_PREFIX; + } + TOPIC_ALL_KEYEVENTS = new PatternTopic(keyprefix + "*"); + log.info("初始化自定义事件Redis监听器"); + } + + @Override + protected void doRegister(RedisMessageListenerContainer container) { + container.addMessageListener(this, TOPIC_ALL_KEYEVENTS); + } + + @Override + protected void doHandleMessage(@NotNull Message message) { + String channel = new String(message.getChannel(), GlobalConst.DEFAULT_CHARSET); + if (log.isDebugEnabled()) { + log.debug("事件监听收到Redis消息, channel: {}, body: {}", channel, new String(message.getBody(), GlobalConst.DEFAULT_CHARSET)); + } + publishEvent(JSON.parseObject(message.getBody(), ProjectEventInstance.class)); + } + + /** + * Publish the event in case an {@link ApplicationEventPublisher} is set. + * + * @param event can be {@literal null}. + */ + protected void publishEvent(ProjectEvent event) { + if (publisher != null) { + event.setAsync(true); + this.publisher.publishEvent(event); + } + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + publisher = applicationEventPublisher; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/handler/ProjectEventRedisSender.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/handler/ProjectEventRedisSender.java new file mode 100644 index 0000000..c3a1f8d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/handler/ProjectEventRedisSender.java @@ -0,0 +1,46 @@ +package com.yunzhupaas.handler; + +import com.alibaba.fastjson.JSON; +import com.yunzhupaas.consts.ProjectEventConst; +import com.yunzhupaas.consts.RedisConst; +import com.yunzhupaas.module.ProjectEvent; +import com.yunzhupaas.event.ProjectEventSender; +import com.yunzhupaas.properties.EventProperty; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.Objects; + +/** + * 自定义事件发布 Redis渠道 + */ +@Slf4j +public class ProjectEventRedisSender implements ProjectEventSender { + + + private RedisTemplate redisTemplate; + private EventProperty eventProperties; + + public ProjectEventRedisSender(RedisTemplate redisTemplate, EventProperty eventProperties) { + this.redisTemplate = redisTemplate; + this.eventProperties = eventProperties; + } + + @Override + public void send(ProjectEvent event) { + String channel = event.getChannel(); + // channel 加上指定前缀 + if(Objects.equals(eventProperties.getRedisPublishType(), ProjectEventConst.REDIS_PUBLISH_TYPE_ALL)){ + // 订阅同一个Redis里的所有消息 + channel = ProjectEventConst.DEFAULT_CHANNEL_PREFIX + channel; + }else{ + // 只订阅当前配置的库索引 + channel = RedisConst.REDIS_EVENT_KEY + ProjectEventConst.DEFAULT_CHANNEL_PREFIX + channel; + } + redisTemplate.convertAndSend(channel, event); + if (log.isDebugEnabled()) { + log.debug("发送Redis自定义事件: {}", JSON.toJSONString(event)); + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEvent.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEvent.java new file mode 100644 index 0000000..2ce65ab --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEvent.java @@ -0,0 +1,84 @@ +package com.yunzhupaas.module; + +import com.github.yitter.idgen.YitIdHelper; +import com.yunzhupaas.consts.ProjectEventConst; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Optional; + +/** + * 项目事件基础类 + */ +@Data +@Accessors(chain = true) +public class ProjectEvent{ + + + /** + * 数据 + */ + private Object source; + + /** + * 消息ID + */ + private Long eventId; + + /** + * 主题 + */ + private String toptic; + + /** + * 频道 + */ + private String channel; + + /** + * 是否异步 + */ + private boolean async; + + /** + * 1:集群, 2:广播, 3:本地 + * @see com.yunzhupaas.consts.ProjectEventConst#EVENT_PUBLISH_MODEL_CLUSTERING + * @see com.yunzhupaas.consts.ProjectEventConst#EVENT_PUBLISH_MODEL_BROADCASTING + * @see com.yunzhupaas.consts.ProjectEventConst#EVENT_PUBLISH_MODEL_LOCAL + */ + private int messageModel; + + /** + * 是否事务提交后才发送 + */ + private boolean afterCommitTransaction; + + /** + * 用户TOKEN + */ + private String token; + + /** + * 租户编码 + */ + private String tenantId; + + public ProjectEvent(){ + } + + public ProjectEvent(String topic, String channel, Object source) { + this(null, topic, channel, source, null, true, false); + } + + public ProjectEvent(Long eventId, String topic, String channel, Object source, Integer messageModel, boolean async, boolean afterCommitTransaction) { + this.source = source; + this.eventId = Optional.ofNullable(eventId).orElseGet(YitIdHelper::nextId); + this.toptic = Optional.ofNullable(topic).orElse(ProjectEventConst.DEFAULT_TOPIC_NAME); + this.messageModel = Optional.ofNullable(messageModel).orElse(ProjectEventConst.EVENT_PUBLISH_MODEL_CLUSTERING); + this.channel = channel; + this.async = async; + this.afterCommitTransaction = afterCommitTransaction; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventBuilder.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventBuilder.java new file mode 100644 index 0000000..45db2c0 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventBuilder.java @@ -0,0 +1,46 @@ +package com.yunzhupaas.module; + + +/** + * 发送自定义事件模型 + */ +public class ProjectEventBuilder extends ProjectEvent{ + + public ProjectEventBuilder(String channel, Object source) { + super(null, channel, source); + } + + public ProjectEventBuilder(String topic, String channel, Object source) { + super(topic, channel, source); + } + + public ProjectEventBuilder(Long eventId, String topic, String channel, Object source, Integer messageModel, boolean async, boolean afterCommitTransaction) { + super(eventId, topic, channel, source, messageModel, async, afterCommitTransaction); + } + + @Override + public ProjectEventBuilder setSource(Object source) { + return (ProjectEventBuilder) super.setSource(source); + } + + @Override + public ProjectEventBuilder setEventId(Long eventId) { + return (ProjectEventBuilder) super.setEventId(eventId); + } + + @Override + public ProjectEventBuilder setAsync(boolean async) { + return (ProjectEventBuilder) super.setAsync(async); + } + + @Override + public ProjectEventBuilder setMessageModel(int messageModel) { + return (ProjectEventBuilder) super.setMessageModel(messageModel); + } + + @Override + public ProjectEventBuilder setAfterCommitTransaction(boolean afterCommitTransaction) { + return (ProjectEventBuilder) super.setAfterCommitTransaction(afterCommitTransaction); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventInstance.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventInstance.java new file mode 100644 index 0000000..fc00665 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventInstance.java @@ -0,0 +1,28 @@ +package com.yunzhupaas.module; + + +/** + * 最终事件触发模型 + */ +public class ProjectEventInstance extends ProjectEvent{ + + public ProjectEventInstance() { + } + + public ProjectEventInstance(String topic, String channel, Object source) { + super(topic, channel, source); + } + + public ProjectEventInstance(Long eventId, String topic, String channel, Object source, Integer messageModel, boolean async, boolean afterCommitTransaction) { + super(eventId, topic, channel, source, messageModel, async, afterCommitTransaction); + } + + public static ProjectEventInstance parseEvent(ProjectEvent event){ + return new ProjectEventInstance(event.getEventId() + , event.getToptic(), event.getChannel(), event.getSource() + , event.getMessageModel(), event.isAsync(), event.isAfterCommitTransaction()); + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventPublish.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventPublish.java new file mode 100644 index 0000000..dee612e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventPublish.java @@ -0,0 +1,21 @@ +package com.yunzhupaas.module; + +import lombok.experimental.Accessors; + +/** + * 自定义事件内部无事务流转模型 + */ +@Accessors(chain = true) +public class ProjectEventPublish extends ProjectEvent{ + + public ProjectEventPublish(Long eventId, String topic, String channel, Object source, Integer messageModel, boolean async, boolean afterCommitTransaction) { + super(eventId, topic, channel, source, messageModel, async, afterCommitTransaction); + } + + public static ProjectEventPublish parseEvent(ProjectEvent event){ + return new ProjectEventPublish(event.getEventId() + , event.getToptic(), event.getChannel(), event.getSource() + , event.getMessageModel(), event.isAsync(), event.isAfterCommitTransaction()); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventPublishTransaction.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventPublishTransaction.java new file mode 100644 index 0000000..c8d79af --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/module/ProjectEventPublishTransaction.java @@ -0,0 +1,21 @@ +package com.yunzhupaas.module; + +import lombok.experimental.Accessors; + +/** + * 自定义事件内部存在事务流转模型 + */ +@Accessors(chain = true) +public class ProjectEventPublishTransaction extends ProjectEvent { + + public ProjectEventPublishTransaction(Long eventId, String topic, String channel, Object source, Integer messageModel, boolean async, boolean afterCommitTransaction) { + super(eventId, topic, channel, source, messageModel, async, afterCommitTransaction); + } + + public static ProjectEventPublishTransaction parseEvent(ProjectEvent event){ + return new ProjectEventPublishTransaction(event.getEventId() + , event.getToptic(), event.getChannel(), event.getSource() + , event.getMessageModel(), event.isAsync(), event.isAfterCommitTransaction()); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/properties/EventProperty.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/properties/EventProperty.java new file mode 100644 index 0000000..bde64da --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/properties/EventProperty.java @@ -0,0 +1,24 @@ +package com.yunzhupaas.properties; + + +import com.yunzhupaas.consts.ProjectEventConst; +import lombok.Data; + +/** + * 事件模块配置 + */ +@Data +public class EventProperty { + public static final String PREFIX = "event"; + + /** + * 默认时间发布、监听渠道: redis, mq + */ + public String eventPublishType = ProjectEventConst.EVENT_PUBLISH_TYPE_REDIS; + + /** + * Redis监听模式:current, all + */ + public String redisPublishType = ProjectEventConst.REDIS_PUBLISH_TYPE_CURRENT; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/util/PublishEventUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/util/PublishEventUtil.java new file mode 100644 index 0000000..7f9fc52 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-event/src/main/java/com/yunzhupaas/util/PublishEventUtil.java @@ -0,0 +1,100 @@ +package com.yunzhupaas.util; + +import com.baomidou.dynamic.datasource.annotation.DsTxEventListener; +import com.baomidou.dynamic.datasource.tx.TransactionContext; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.consts.ProjectEventConst; +import com.yunzhupaas.event.ProjectEventSender; +import com.yunzhupaas.module.*; +import lombok.Getter; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.context.event.EventListener; +import org.springframework.transaction.event.TransactionalEventListener; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import java.util.Objects; + +public class PublishEventUtil implements ApplicationEventPublisherAware { + + @Getter + private static ApplicationEventPublisher publisher; + private static ProjectEventSender eventSender = null; + + public PublishEventUtil(ProjectEventSender eventSender) { + PublishEventUtil.eventSender = eventSender; + } + + /** + * 发布自定义事件 + * async: 是否异步 | 默认异步 + * messageModel: 1:集群(相同的服务中只有一个服务消费), 2:广播(所有服务都消费), 3:本地消息(当前进程消费) | 默认集群模式 + * afterCommitTransaction: 如果当前存在事务, 通知在事务提交成功后 |默认否 + * Redis渠道不支持重试, 禁用同步模式 + * QUEUE渠道同步模式如果报错可以触发MQ重试 + */ + public static void publish(ProjectEventBuilder eventBuilder) { + ProjectEvent newEvent = null; + if (eventBuilder.isAfterCommitTransaction()) { + // 开启提交事务后发送, 且当前存在事务 + if (!TransactionSynchronizationManager.isActualTransactionActive() && !StringUtils.hasText(TransactionContext.getXID())) { + newEvent = ProjectEventPublishTransaction.parseEvent(eventBuilder); + } + } + if(newEvent == null){ + newEvent = ProjectEventPublish.parseEvent(eventBuilder); + } + PublishEventUtil.getPublisher().publishEvent(newEvent); + } + + /** + * 发送本地事件 + * @see #publish(ProjectEventBuilder) + */ + public static void publishLocalEvent(ProjectEventBuilder eventBuilder) { + eventBuilder.setMessageModel(ProjectEventConst.EVENT_PUBLISH_MODEL_LOCAL); + publish(eventBuilder); + } + + + @EventListener + public void onPublishEvent(ProjectEventPublish event) { + processPublishEvent(event); + } + + @TransactionalEventListener + @DsTxEventListener + public void onPublishTransactionEvent(ProjectEventPublishTransaction event) { + processPublishEvent(event); + } + + private void processPublishEvent(ProjectEvent event) { + Assert.notNull(eventSender, "当前发布渠道未配置"); + if(event.getToken() == null){ + String token = UserProvider.getToken(); + if(token == null){ + UserInfo userInfo = UserProvider.getLocalLoginUser(); + if(userInfo != null){ + token = userInfo.getToken(); + } + } + event.setToken(token); + } + if(event.getTenantId() == null){ + event.setTenantId(TenantHolder.getDatasourceId()); + } + if(Objects.equals(event.getMessageModel(), ProjectEventConst.EVENT_PUBLISH_MODEL_LOCAL)){ + PublishEventUtil.getPublisher().publishEvent(ProjectEventInstance.parseEvent(event)); + }else { + eventSender.send(event); + } + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + PublishEventUtil.publisher = applicationEventPublisher; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-file/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-file/pom.xml new file mode 100644 index 0000000..ac7345e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-file/pom.xml @@ -0,0 +1,131 @@ + + + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-file + + + + com.yunzhupaas + yunzhupaas-common-database + + + com.yunzhupaas + yunzhupaas-common-auth + + + org.bouncycastle + bcprov-jdk18on + + + + + com.yunzhupaas + yunzhupaas-file-core-starter + + + + + + + + + + + + + + + + + + + + + + + + + io.minio + minio + + + + + + + + + + + + + + + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/aspect/LogFileStorageAspect.java b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/aspect/LogFileStorageAspect.java new file mode 100644 index 0000000..fec5442 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/aspect/LogFileStorageAspect.java @@ -0,0 +1,74 @@ +package com.yunzhupaas.aspect; + +import cn.xuyanwu.spring.file.storage.FileInfo; +import cn.xuyanwu.spring.file.storage.UploadPretreatment; +import cn.xuyanwu.spring.file.storage.aspect.*; +import cn.xuyanwu.spring.file.storage.platform.FileStorage; +import cn.xuyanwu.spring.file.storage.recorder.FileRecorder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.InputStream; +import java.util.function.Consumer; + +/** + * 使用切面打印文件上传和删除的日志 + */ +@Slf4j +@Component +public class LogFileStorageAspect implements FileStorageAspect { + + /** + * 上传,成功返回文件信息,失败返回 null + */ + @Override + public FileInfo uploadAround(UploadAspectChain chain,FileInfo fileInfo,UploadPretreatment pre,FileStorage fileStorage,FileRecorder fileRecorder) { + log.info("上传文件 before -> {}",fileInfo); + fileInfo = chain.next(fileInfo,pre,fileStorage,fileRecorder); + log.info("上传文件 after -> {}",fileInfo); + return fileInfo; + } + + /** + * 删除文件,成功返回 true + */ + @Override + public boolean deleteAround(DeleteAspectChain chain,FileInfo fileInfo,FileStorage fileStorage,FileRecorder fileRecorder) { + log.info("删除文件 before -> {}",fileInfo); + boolean res = chain.next(fileInfo,fileStorage,fileRecorder); + log.info("删除文件 after -> {}",res); + return res; + } + + /** + * 文件是否存在 + */ + @Override + public boolean existsAround(ExistsAspectChain chain,FileInfo fileInfo,FileStorage fileStorage) { + log.info("文件是否存在 before -> {}",fileInfo); + boolean res = chain.next(fileInfo,fileStorage); + log.info("文件是否存在 after -> {}",res); + return res; + } + + /** + * 下载文件 + */ + @Override + public void downloadAround(DownloadAspectChain chain, FileInfo fileInfo, FileStorage fileStorage, Consumer consumer) { + log.info("下载文件 before -> {}",fileInfo); + chain.next(fileInfo,fileStorage,consumer); + log.info("下载文件 after -> {}",fileInfo); + } + + /** + * 下载缩略图文件 + */ + @Override + public void downloadThAround(DownloadThAspectChain chain, FileInfo fileInfo, FileStorage fileStorage, Consumer consumer) { + log.info("下载缩略图文件 before -> {}",fileInfo); + chain.next(fileInfo,fileStorage,consumer); + log.info("下载缩略图文件 after -> {}",fileInfo); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/config/LocalPathConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/config/LocalPathConfig.java new file mode 100644 index 0000000..29769a8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/config/LocalPathConfig.java @@ -0,0 +1,126 @@ +package com.yunzhupaas.config; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * 本地存储文件路径配置 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-08-24 + */ +@Component +@Data +public class LocalPathConfig { + + /** + * 数据库备份文件路径 + */ + @Value("${config.DataBackupFilePath:}") + private String dataBackupFilePath; + /** + * 临时文件存储路径 + */ + @Value("${config.TemporaryFilePath:}") + private String temporaryFilePath; + /** + * 系统文件存储路径 + */ + @Value("${config.SystemFilePath:}") + private String systemFilePath; + /** + * 文件模板存储路径 + */ + @Value("${config.TemplateFilePath:}") + private String templateFilePath; + /** + * 代码模板存储路径 + */ + @Value("${config.TemplateCodePath:}") + private String templateCodePath; + /** + * 邮件文件存储路径 + */ + @Value("${config.EmailFilePath:}") + private String emailFilePath; + /** + * 大屏图片存储目录 + */ + @Value("${config.BiVisualPath:}") + private String biVisualPath; + /** + * 文档管理存储路径 + */ + @Value("${config.DocumentFilePath:}") + private String documentFilePath; + /** + * 文件在线预览存储pdf + */ + @Value("${config.DocumentPreviewPath:}") + private String documentPreviewPath; + /** + * 用户头像存储路径 + */ + @Value("${config.UserAvatarFilePath:}") + private String userAvatarFilePath; + /** + * IM聊天图片+语音存储路径 + */ + @Value("${config.IMContentFilePath:}") + private String imContentFilePath; + /** + * 微信公众号资源文件存储路径 + */ + @Value("${config.MPMaterialFilePath:}") + private String mpMaterialFilePath; + /** + * 微信公众号允许上传文件类型 + */ + @Value("${config.MPUploadFileType:}") + private String mpUploadFileType; + /** + * 微信允许上传文件类型 + */ + @Value("${config.WeChatUploadFileType:}") + private String weChatUploadFileType; + /** + * 允许上传文件类型 + */ + @Value("${config.AllowUploadFileType:}") + private String allowUploadFileType; + /** + * 允许图片类型 + */ + @Value("${config.AllowUploadImageType:}") + private String allowUploadImageType; + /** + * 后端文件目录 + */ + @Value("${config.WebDirectoryPath:}") + private String webDirectoryPath; + /** + * 前端附件文件目录 + */ + @Value("${config.WebAnnexFilePath:}") + private String webAnnexFilePath; + /** + * 允许预览类型 + */ + @Value("${config.AllowPreviewFileType:}") + private String allowPreviewFileType; + /** + * 预览方式 + */ + @Value("${config.PreviewType:}") + private String previewType; + /** + * kk服务地址 + */ + @Value("${config.kkFileUrl:}") + private String kkFileUrl; + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/entity/FileDetail.java b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/entity/FileDetail.java new file mode 100644 index 0000000..b85d573 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/entity/FileDetail.java @@ -0,0 +1,162 @@ +package com.yunzhupaas.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 lombok.Data; + +import java.util.Date; + +/** + * 文件记录表 + */ +@Data +@TableName(value = "file_detail") +public class FileDetail { + /** + * 文件id + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 文件访问地址 + */ + @TableField(value = "url") + private String url; + + /** + * 文件大小,单位字节 + */ + @TableField(value = "size") + private Long size; + + /** + * 文件名称 + */ + @TableField(value = "filename") + private String filename; + + /** + * 原始文件名 + */ + @TableField(value = "original_filename") + private String originalFilename; + + /** + * 基础存储路径 + */ + @TableField(value = "base_path") + private String basePath; + + /** + * 存储路径 + */ + @TableField(value = "path") + private String path; + + /** + * 文件扩展名 + */ + @TableField(value = "ext") + private String ext; + + /** + * MIME类型 + */ + @TableField(value = "content_type") + private String contentType; + + /** + * 存储平台 + */ + @TableField(value = "platform") + private String platform; + + /** + * 缩略图访问路径 + */ + @TableField(value = "th_url") + private String thUrl; + + /** + * 缩略图名称 + */ + @TableField(value = "th_filename") + private String thFilename; + + /** + * 缩略图大小,单位字节 + */ + @TableField(value = "th_size") + private Long thSize; + + /** + * 缩略图MIME类型 + */ + @TableField(value = "th_content_type") + private String thContentType; + + /** + * 文件所属对象id + */ + @TableField(value = "object_id") + private String objectId; + + /** + * 文件所属对象类型,例如用户头像,评价图片 + */ + @TableField(value = "object_type") + private String objectType; + + /** + * 附加属性 + */ + @TableField(value = "attr") + private String attr; + + /** + * 创建时间 + */ + @TableField(value = "create_time") + private Date createTime; + + public static final String COL_ID = "id"; + + public static final String COL_URL = "url"; + + public static final String COL_SIZE = "size"; + + public static final String COL_FILENAME = "filename"; + + public static final String COL_ORIGINAL_FILENAME = "original_filename"; + + public static final String COL_BASE_PATH = "base_path"; + + public static final String COL_PATH = "path"; + + public static final String COL_EXT = "ext"; + + public static final String COL_CONTENT_TYPE = "content_type"; + + public static final String COL_PLATFORM = "platform"; + + public static final String COL_TH_URL = "th_url"; + + public static final String COL_TH_FILENAME = "th_filename"; + + public static final String COL_TH_SIZE = "th_size"; + + public static final String COL_TH_CONTENT_TYPE = "th_content_type"; + + public static final String COL_OBJECT_ID = "object_id"; + + public static final String COL_OBJECT_TYPE = "object_type"; + + public static final String COL_ATTR = "attr"; + + public static final String COL_CREATE_TIME = "create_time"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/mapper/FileDetailMapper.java b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/mapper/FileDetailMapper.java new file mode 100644 index 0000000..fa0cf69 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/mapper/FileDetailMapper.java @@ -0,0 +1,10 @@ +package com.yunzhupaas.mapper; + +import com.yunzhupaas.base.mapper.SuperMapper; +import com.yunzhupaas.entity.FileDetail; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface FileDetailMapper extends SuperMapper { +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/service/FileDetailService.java b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/service/FileDetailService.java new file mode 100644 index 0000000..10e396d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/service/FileDetailService.java @@ -0,0 +1,69 @@ +package com.yunzhupaas.service; + +import cn.xuyanwu.spring.file.storage.FileInfo; +import cn.xuyanwu.spring.file.storage.recorder.FileRecorder; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yunzhupaas.entity.FileDetail; +import com.yunzhupaas.mapper.FileDetailMapper; +import lombok.SneakyThrows; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 用来将文件上传记录保存到数据库,这里使用了 MyBatis-Plus 和 Hutool 工具类 + */ +@Service +public class FileDetailService extends ServiceImpl implements FileRecorder { + + + /** + * 保存文件信息到数据库 + */ + @SneakyThrows + @Override + public boolean record(FileInfo info) { + return true; + } + + /** + * 根据 url 查询文件信息 + */ + @SneakyThrows + @Override + public FileInfo getByUrl(String url) { + return null; + } + + /** + * 根据 url 删除文件信息 + */ + @Override + public boolean delete(String url) { + return true; + } + + /** + * 通过路径获取文件列表 + * + * @param path + * @return + */ + public List getFileList(String path) { + return null; + } + + /** + * 获取文件信息 + * + * @param path + * @param fileName + * @return + */ + public FileDetail getFileDetail(String path, String fileName, String platform) { + return null; + } +} + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/DataFileExport.java b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/DataFileExport.java new file mode 100644 index 0000000..1726302 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/DataFileExport.java @@ -0,0 +1,60 @@ +package com.yunzhupaas.util; + +import cn.xuyanwu.spring.file.storage.FileInfo; +import com.yunzhupaas.base.vo.DownloadVO; +import com.yunzhupaas.constant.DbSensitiveConstant; +import com.yunzhupaas.constant.GlobalConst; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; +import java.util.Date; + +/** + * 数据接口文件导入导出 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-06-04 + */ +@Component +@Slf4j +public class DataFileExport implements FileExport { + + @Override + public DownloadVO exportFile(Object clazz, String filePath, String fileName, String tableName) { + fileName = containsSensitive(fileName); + //model拼凑成Json字符串 + String json = JsonUtil.getObjectToString(clazz); + if (json == null) { + json = ""; + } + //写入到文件中 + /** 2.写入到文件中 */ + fileName += "_" + DateUtil.dateFormatByPattern(new Date(), "yyyyMMddHHmmss") + "." + tableName; + //是否需要上产到存储空间 + FileInfo fileInfo = FileUploadUtils.uploadFile(json.getBytes(GlobalConst.DEFAULT_CHARSET), filePath, fileName); + //生成下载下载文件路径 + DownloadVO vo = DownloadVO.builder().name(fileInfo.getFilename()).url(UploaderUtil.uploaderFile(fileInfo.getFilename() + "#" + "export") + "&name=" + fileName).build(); + return vo; + } + + /** + * 替换敏感字 + * + * @param fileName + * @return + */ + private String containsSensitive(String fileName) { + if (StringUtil.isNotEmpty(fileName)) { + String[] split = DbSensitiveConstant.FILE_SENSITIVE.split(","); + for (String str : split) { + fileName = fileName.replaceAll(str, ""); + } + } + return fileName; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/FileExport.java b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/FileExport.java new file mode 100644 index 0000000..f53f772 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/FileExport.java @@ -0,0 +1,26 @@ +package com.yunzhupaas.util; + +import com.yunzhupaas.base.vo.DownloadVO; + +/** + * 导入导出工厂类 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-06-04 + */ +public interface FileExport { + + /** + * 导出 + * @param clazz 要转成Json的类 + * @param filePath 写入位置 + * @param fileName 文件名 + * @param tableName 表明 + * @return + */ + DownloadVO exportFile(Object clazz, String filePath, String fileName, String tableName); + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/FilePathUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/FilePathUtil.java new file mode 100644 index 0000000..6b18588 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/FilePathUtil.java @@ -0,0 +1,108 @@ +package com.yunzhupaas.util; + +import com.yunzhupaas.config.LocalPathConfig; +import com.yunzhupaas.constant.FileTypeConstant; +import com.yunzhupaas.util.context.SpringContext; + +/** + * @author :云筑产品开发平台组 + * @version: V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date :2022/4/26 15:58 + */ +public class FilePathUtil { + + private static LocalPathConfig configValueUtil = SpringContext.getBean(LocalPathConfig.class); + + /** + * 通过fileType获取文件夹名称 + * + * @param fileType 文件类型 + * @return + */ + public static String getFilePath(String fileType) { + String filePath = fileType; + //判断是那种类型得到相应的文件夹 + switch (fileType.toLowerCase()) { + //用户头像存储路径 + case FileTypeConstant.USERAVATAR: + filePath = configValueUtil.getUserAvatarFilePath() + "/"; + break; + //邮件文件存储路径 + case FileTypeConstant.MAIL: + filePath = configValueUtil.getEmailFilePath() + "/"; + break; + //前端附件文件目录 + case FileTypeConstant.ANNEX: + filePath = configValueUtil.getWebAnnexFilePath() + "/"; + break; + case FileTypeConstant.ANNEXPIC: + filePath = configValueUtil.getWebAnnexFilePath() + "/"; + break; + //IM聊天图片+语音存储路径 + case FileTypeConstant.IM: + filePath = configValueUtil.getImContentFilePath() + "/"; + break; + //临时文件存储路径 + case FileTypeConstant.WORKFLOW: + filePath = configValueUtil.getSystemFilePath() + "/"; + break; + //文档管理存储路径 + case FileTypeConstant.DOCUMENT: + filePath = configValueUtil.getDocumentFilePath() + "/"; + break; + //数据库备份文件路径 + case FileTypeConstant.DATABACKUP: + filePath = configValueUtil.getDataBackupFilePath() + "/"; + break; + //临时文件存储路径 + case FileTypeConstant.TEMPORARY: + filePath = configValueUtil.getTemporaryFilePath() + "/"; + break; + //允许上传文件类型 + case FileTypeConstant.ALLOWUPLOADFILETYPE: + filePath = configValueUtil.getAllowUploadFileType() + "/"; + break; + //文件在线预览存储pdf + case FileTypeConstant.DOCUMENTPREVIEWPATH: + filePath = configValueUtil.getDocumentPreviewPath() + "/"; + break; + //文件模板存储路径 + case FileTypeConstant.TEMPLATEFILE: + filePath = configValueUtil.getTemplateFilePath() + "/"; + break; + //前端文件目录 + case FileTypeConstant.SERVICEDIRECTORY: + break; +// //后端文件目录 +// case FileTypeConstant.WEBDIRECTORY: +// filePath = configValueUtil.getWebDirectoryPath(); +// break; + // 文档预览 + case FileTypeConstant.DOCUMENTPREVIEW: + filePath = configValueUtil.getDocumentPreviewPath() + "/"; + break; + //导出 + case FileTypeConstant.EXPORT: + filePath = configValueUtil.getTemporaryFilePath() + "/"; + break; + // 大屏相关图片 + case FileTypeConstant.BIVISUALPATH: + filePath = configValueUtil.getBiVisualPath() + "/"; + break; + case FileTypeConstant.CODETEMP: + filePath = "CodeTemp/"; + break; + case FileTypeConstant.TEMPLATECODEPATH: + filePath = configValueUtil.getTemplateCodePath() + "/"; + break; + case FileTypeConstant.FILEZIPDOWNTEMPPATH: + filePath = "FileTemp/"; + break; + default: + break; + } + return filePath; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/FileUploadUtils.java b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/FileUploadUtils.java new file mode 100644 index 0000000..c935671 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/FileUploadUtils.java @@ -0,0 +1,324 @@ +package com.yunzhupaas.util; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Assert; +import cn.xuyanwu.spring.file.storage.FileInfo; +import cn.xuyanwu.spring.file.storage.FileStorageProperties; +import cn.xuyanwu.spring.file.storage.FileStorageService; +import cn.xuyanwu.spring.file.storage.platform.FileStorage; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.entity.FileDetail; +import com.yunzhupaas.model.FileListVO; +import com.yunzhupaas.service.FileDetailService; +import com.yunzhupaas.util.context.SpringContext; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +public class FileUploadUtils { + + private static FileStorageService fileStorageService; + private static FileDetailService fileDetailService; + private static FileStorageProperties fileStorageProperties; + + static { + fileStorageService = SpringContext.getBean(FileStorageService.class); + fileDetailService = SpringContext.getBean(FileDetailService.class); + fileStorageProperties = SpringContext.getBean(FileStorageProperties.class); + } + + /** + * 获取文件信息 + * + * @param path + * @param fileName + * @param origin + * @return + */ + public static FileDetail getFileDetail(String path, String fileName, boolean origin) { + FileDetail fileDetail = new FileDetail(); + fileDetail.setPath(path); + fileDetail.setFilename(fileName); + String basePath; + String platform; + FileStorage fileStorage = fileStorageService.getFileStorage(); + if (origin) { + basePath = fileStorage.getLocalPath(); + platform = "local-plus-1"; + } else { + basePath = fileStorage.getBasePath(); + platform = getDefaultPlatform(); + } + fileDetail.setBasePath(basePath); + fileDetail.setPlatform(platform); + return fileDetail; + } + +// /** +// * 获取文件url +// * +// * @param path +// * @param fileName +// * @return +// */ +// public static String getFileUrl(String path, String fileName) { +// FileDetail fileDetail = getFileDetail(path, fileName, ); +// String url = null; +// if (fileDetail == null) { +// url = fileStorageService.getFileStorage().getBasePath() + path + fileName; +// } else { +// url = fileDetail.getUrl(); +// } +// return url; +// } + + /** + * 返回本地地址且固定为local-plus-1 + * + * @return + */ + public static String getLocalBasePath() { + return fileStorageService.getFileStorage().getLocalPath(); + } + + /** + * 获取文件服务器基础路径 + * + * @return + */ + public static String getBasePath() { + return fileStorageService.getFileStorage().getBasePath(); + } + + /** + * 获取文件信息 + * + * @param path + * @param fileName + * @param origin + * @return + */ + public static FileInfo getFileInfo(String path, String fileName, boolean origin) { + FileDetail fileDetail = getFileDetail(path, fileName, origin); + return BeanUtil.copyProperties(fileDetail,FileInfo.class,"attr"); + } + + /** + * 上传文件,通过字节数组 + * + * @param bytes 内容 + * @param path 路径 + * @param fileName 文件名 + */ + public static FileInfo uploadFile(byte[] bytes, String path, String fileName) { + FileInfo fileInfo = fileStorageService.of(bytes) + .setPath(path) + .setOriginalFilename(fileName) + .upload(); + Assert.notNull(fileInfo, MsgCode.FA033.getCode()); + return fileInfo; + } + + /** + * 上传文件,MultipartFile + * + * @param multipartFile 文件 + * @param path 路径 + * @param fileName 文件名 + */ + public static FileInfo uploadFile(MultipartFile multipartFile, String path, String fileName) { + FileInfo fileInfo = null; + try { + fileInfo = fileStorageService.of(multipartFile) + .setPath(path) + .setThumbnailBytes(multipartFile.getBytes()) + .upload(); + } catch (IOException e) { + e.printStackTrace(); + } + Assert.notNull(fileInfo, "文件上传失败!"); + return fileInfo; + } + + /** + * 上传文件,File + * + * @param file 文件 + * @param path 路径 + * @param fileName 文件名 + */ + public static FileInfo uploadFile(File file, String path, String fileName) { + FileInfo fileInfo = fileStorageService.of(file) + .setPath(path) + .upload(); + Assert.notNull(fileInfo, MsgCode.FA033.getCode()); + return fileInfo; + } + + /** + * 获取文件列表 + * + * @param path 路径 + */ + public static List getFileList(String path) { + return fileStorageService.getFileStorage().conversionList(path); + } + + /** + * 获取命名空间 + * + */ + public static String getBucketName() { + String bucketName = fileStorageService.getFileStorage().getBucketName(); + if (StringUtil.isNotEmpty(bucketName)) { + return bucketName + "/"; + } + return bucketName; + } + + /** + * 获取命名空间 + * + */ + public static String getDomain() { + return fileStorageService.getFileStorage().getDomain(); + } + + /** + * 删除文件 + * + * @param path + * @param fileName + */ + public static boolean removeFile(String path, String fileName) { + FileDetail fileDetail = getFileDetail(path, fileName, false); + return fileStorageService.delete(fileDetail.getUrl()); + } + +// /** +// * 下载文件 +// * +// * @param path +// * @param fileName +// */ +// public static void downloadFile(String path, String fileName) { +// String fileUrl = getFileUrl(path, fileName); +// FileInfo fileInfo = fileStorageService.getFileInfoByUrl(fileUrl); +// fileStorageService.download(fileInfo).file(fileUrl); +// } + + /** + * 下载文件 + * + * @param path + * @param fileName + */ + public static void downloadFile(String path, String fileName) { + FileInfo fileInfo = getFileInfo(path, fileName, false); + fileStorageService.download(fileInfo).file(fileInfo.getBasePath() + fileInfo.getPath() + fileInfo.getFilename()); + } + + /** + * 下载文件得到字节数组 + * @param path + * @param fileName + * @param origin + */ + public static byte[] downloadFileByte(String path, String fileName, boolean origin) { + FileInfo fileInfo = getFileInfo(path, fileName, origin); + return fileStorageService.download(fileInfo).bytes(); + } + +// /** +// * 下载文件得到流 +// * +// * @param path +// * @param fileName +// * @param origin +// */ +// public static ByteArrayOutputStream downloadFilStream(String path, String fileName, boolean origin) { +// FileInfo fileInfo = getFileInfo(path, fileName, origin); +// ByteArrayOutputStream out = new ByteArrayOutputStream(); +// fileStorageService.download(fileInfo).outputStream(out); +// return out; +// } + + /** + * 获取文件信息 + * + * + * @param folderName + * @param id + * @return + */ + public static FileListVO getFileDetail(String folderName, String id) { + List fileList = getFileList(folderName); + Integer integer = Integer.valueOf(id); + if (fileList.size() > integer) { + return fileList.get(integer); + } + return null; + } + + /** + * 默认存储平台 + * + * @param + * @return + */ + public static String getDefaultPlatform() { + return fileStorageProperties.getDefaultPlatform(); + } + + /** + * 下载到本地 + * + * @param folderName 文件夹名 + * @param filePath 下载到本地文件路径 + * @param objectName 文件名 + */ + public static void downLocal(String folderName, String filePath, String objectName) { + fileStorageService.getFileStorage().downLocal(folderName, filePath, objectName); + } + + /** + * 下载到本地 + * + * @param folderName 文件夹名 + */ + public static List getDefaultFileList(String folderName) { + return fileStorageService.getFileStorage().conversionList(folderName); + } + + /** + * 判断文件是否存在 + * + * @param type + * @param fileName + * @return + */ + public static boolean exists(String type, String fileName) { + String typePath = FilePathUtil.getFilePath(type); + if(fileName.indexOf(",") >= 0) { + typePath += fileName.substring(0, fileName.lastIndexOf(",")+1).replaceAll(",", "/"); + fileName = fileName.substring(fileName.lastIndexOf(",")+1); + } + FileInfo fileInfo = getFileInfo(typePath, fileName, false); + return fileStorageService.exists(fileInfo); + } + + /** + * 根据路径和文件名删除文件 + * @param path + * @param fileName + * @return + */ + public static boolean deleteFileByPathAndFileName(String path, String fileName) { + FileInfo fileInfo = getFileInfo(path, fileName, false); + return fileStorageService.delete(fileInfo); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/UploaderUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/UploaderUtil.java new file mode 100644 index 0000000..e4d2fff --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/java/com/yunzhupaas/util/UploaderUtil.java @@ -0,0 +1,71 @@ +package com.yunzhupaas.util; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:56 + */ +public class UploaderUtil { + + /** + * 头像名称处理 + * @param fileName + * @return + */ + public static String uploaderImg(String fileName) { + return uploaderImg(null, fileName); + } + + /** + * 头像名称处理 + * @param url + * @param fileName + * @return + */ + public static String uploaderImg(String url, String fileName) { + if (url == null) { + url = "/api/file/Image/userAvatar/"; + } + return url + fileName; + } + + /** + * 附件名称处理 + * @param url + * @param fileName + * @return + */ + public static String uploaderFile(String url, String fileName) { + if (url == null) { + url = "/api/file/Download?encryption="; + } + String ticket = TicketUtil.createTicket("", 60); + String name = DesUtil.aesEncode(ticket + "#" + fileName); + return url + name; + } + + /** + * 附件名称处理 + * @param fileName + * @return + */ + public static String uploaderFile(String fileName) { + return uploaderFile(null, fileName); + } + + /** + * 代码生成器附件名称处理 + * @param fileName + * @return + */ + public static String uploaderVisualFile(String fileName) { + String url = "/api/visualdev/Generater/DownloadVisCode?encryption="; + String ticket = TicketUtil.createTicket("", 60); + String name = DesUtil.aesEncode(ticket + "#" + fileName); + return url + name; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/resources/FileDetailMapper.xml b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/resources/FileDetailMapper.xml new file mode 100644 index 0000000..cafc75b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-file/src/main/resources/FileDetailMapper.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + id, url, `size`, filename, original_filename, base_path, `path`, ext, content_type, + platform, th_url, th_filename, th_size, th_content_type, object_id, object_type, + attr, create_time + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-i18n/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-i18n/pom.xml new file mode 100644 index 0000000..01d4cb0 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-i18n/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + com.yunzhupaas + yunzhupaas-boot-common + 5.2.0-RELEASE + ../pom.xml + + + yunzhupaas-common-i18n + + + + + com.yunzhupaas + yunzhupaas-common-event + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/config/I18nAutoConfiguration.java b/yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/config/I18nAutoConfiguration.java new file mode 100644 index 0000000..f451de5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/config/I18nAutoConfiguration.java @@ -0,0 +1,75 @@ +package com.yunzhupaas.i18n.config; + +import com.yunzhupaas.config.ConfigValueUtil; +import com.yunzhupaas.i18n.constant.I18nApiConst; +import com.yunzhupaas.i18n.core.DynamicMessageSource; +import com.yunzhupaas.i18n.core.MyReloadableResourceBundleMessageSource; +import com.yunzhupaas.i18n.provider.*; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.context.MessageSourceProperties; +import org.springframework.context.MessageSource; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ReloadableResourceBundleMessageSource; +import org.springframework.util.StringUtils; + +import java.time.Duration; +import java.util.List; + +/** + * 国际化语言配置类 + */ +@Configuration(proxyBeanMethods = false) +public class I18nAutoConfiguration { + + @Primary + @Bean(AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME) + public MessageSource messageSource(MessageSourceProperties properties, List messageSourceProviders, DynamicMessageSource dynamicMessageSource) { + ReloadableResourceBundleMessageSource messageSource = new MyReloadableResourceBundleMessageSource(messageSourceProviders); + if (StringUtils.hasText(properties.getBasename())) { + messageSource.setBasenames(StringUtils + .commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename()))); + } + if (properties.getEncoding() != null) { + messageSource.setDefaultEncoding(properties.getEncoding().name()); + } + messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale()); + Duration cacheDuration = properties.getCacheDuration(); + if (cacheDuration != null) { + messageSource.setCacheMillis(cacheDuration.toMillis()); + } + messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat()); + messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage()); + + dynamicMessageSource.setParentMessageSource(messageSource); + return dynamicMessageSource; + } + + @Bean + @ConditionalOnMissingBean + public DynamicMessageSource getDynamicMessageSource(I18nMessageProvider i18nMessageProvider){ + return new DynamicMessageSource(i18nMessageProvider); + } + + @Bean + @ConditionalOnMissingBean + public DynamicMessageProvider getDynamicMessageProvider(){ + return new MyDynamicMessageProvider(); + } + + @Bean + @ConditionalOnMissingBean + public I18nMessageProvider getI18nMessageProvider(ConfigValueUtil configValueUtil, DynamicMessageProvider dynamicMessageProvider){ + return new MyI18nMessageProvider(configValueUtil, dynamicMessageProvider); + } + + @Bean + public I18nApiConst getI18nApiConst(ConfigValueUtil configValueUtil){ + return new I18nApiConst(configValueUtil.getApiDomain()); + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/config/I18nRefreshListenerConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/config/I18nRefreshListenerConfig.java new file mode 100644 index 0000000..35dfc37 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/config/I18nRefreshListenerConfig.java @@ -0,0 +1,31 @@ +package com.yunzhupaas.i18n.config; + +import jakarta.annotation.Resource; +import com.yunzhupaas.event.ProjectEventListener; +import com.yunzhupaas.i18n.constant.I18nConst; +import com.yunzhupaas.i18n.provider.MyI18nMessageProvider; +import com.yunzhupaas.module.ProjectEventInstance; +import org.springframework.context.annotation.Configuration; + + +/** + * 国际化语言Redis缓存监听配置 + * 收到租户多语言缓存变动时清空租户多语言缓存 + */ +@Configuration(proxyBeanMethods = false) +public class I18nRefreshListenerConfig { + + @Resource + private MyI18nMessageProvider myI18nMessageProvider; + + @ProjectEventListener(channelRegex = {I18nConst.CACHE_KEY_SERVER + ".*", I18nConst.CACHE_KEY_FRONT + ".*"}) +// @ProjectEventListener(channelSpel = {"#root.channel.startsWith(T(com.yunzhupaas.i18n.constant.I18nConst).CACHE_KEY_SERVER) || #root.channel.startsWith(T(com.yunzhupaas.i18n.constant.I18nConst).CACHE_KEY_FRONT)"}) + public void onRedisKeySetEvent(ProjectEventInstance redisEvent){ + String key = redisEvent.getChannel(); + // 获取多租户编码 + key = key.replace(I18nConst.CACHE_KEY_SERVER, "").replace(I18nConst.CACHE_KEY_FRONT, ""); + myI18nMessageProvider.removeTenantCache(key); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/provider/MyDynamicMessageProvider.java b/yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/provider/MyDynamicMessageProvider.java new file mode 100644 index 0000000..d6478aa --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/provider/MyDynamicMessageProvider.java @@ -0,0 +1,63 @@ +package com.yunzhupaas.i18n.provider; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.yunzhupaas.base.ActionResult; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.i18n.constant.I18nApiConst; +import com.yunzhupaas.util.Constants; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.UserProvider; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; + +import java.util.Locale; +import java.util.Objects; + +/** + * 国际化翻译源提供者 + */ +@Slf4j +public class MyDynamicMessageProvider implements DynamicMessageProvider { + + private int timeout = 3000; + + @Override + public String getI18nList(Locale locale) { + UserInfo userInfo = UserProvider.getUser(); + String token = userInfo.getToken(); + if(StringUtil.isNotEmpty(token)) { + try (HttpResponse httpResponse = HttpRequest.get(I18nApiConst.i18nListUrl) + .timeout(timeout) + .setReadTimeout(timeout) + .setConnectionTimeout(timeout) + .header(Constants.AUTHORIZATION, token) + .header(HttpHeaders.ACCEPT_LANGUAGE, locale.toLanguageTag()) + .execute()) { + if (httpResponse.isOk()) { + String result = httpResponse.body(); + ActionResult out = JSON.parseObject(result, new TypeReference>() {}); + if (Objects.equals(Constants.SUCCESS, out.getCode())) { + JSONArray messages = out.getData(); + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < messages.size(); i++) { + JSONObject obj = messages.getJSONObject(i); + String code = obj.getString("enCode"); + String msg = obj.getString("fullName"); + stringBuilder.append(String.format("%s=%s%n", code, msg)); + } + return stringBuilder.toString(); + } + } + } catch (Exception e) { + log.error("语言翻译内容获取失败: {}", e.getMessage()); + } + } + return null; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/provider/MyI18nMessageProvider.java b/yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/provider/MyI18nMessageProvider.java new file mode 100644 index 0000000..708281a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-i18n/src/main/java/com/yunzhupaas/i18n/provider/MyI18nMessageProvider.java @@ -0,0 +1,108 @@ +package com.yunzhupaas.i18n.provider; + +import cn.hutool.cache.CacheUtil; +import cn.hutool.cache.impl.TimedCache; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.config.ConfigValueUtil; +import com.yunzhupaas.constant.GlobalConst; +import com.yunzhupaas.constant.model.MCode; +import com.yunzhupaas.util.TenantHolder; +import com.yunzhupaas.util.UserProvider; +import lombok.extern.slf4j.Slf4j; + +import java.util.Locale; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + +/** + * 国际化语言翻译 + */ +@Slf4j +public class MyI18nMessageProvider implements I18nMessageProvider { + + private ConfigValueUtil configValueUtil; + + private final long CACHE_TIME = 48 * 60 * 60000L; + + // 未使用的情况下, 默认48小时失效, 使用后重新计算缓存时效 + private TimedCache> tenantMessageProperties = CacheUtil.newTimedCache(CACHE_TIME); + // 翻译内容提供者 + private DynamicMessageProvider dynamicMessageProvider; + // 租户语言加载锁 + private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); + private Properties emptyProperties = new Properties(); + + public MyI18nMessageProvider(ConfigValueUtil configValueUtil, DynamicMessageProvider dynamicMessageProvider) { + this.configValueUtil = configValueUtil; + this.dynamicMessageProvider = dynamicMessageProvider; + // 执行定时清理 + tenantMessageProperties.schedulePrune(CACHE_TIME); + } + + public void removeTenantCache(String tenantId) { + tenantMessageProperties.remove(tenantId); + } + + public void loadTenantMessage(String tenantId, Locale locale) { + Properties i18nListProperties = dynamicMessageProvider.getI18nListProperties(locale); + TimedCache tenantProperties = tenantMessageProperties.get(tenantId); + if (tenantProperties == null) { + tenantProperties = CacheUtil.newTimedCache(CACHE_TIME); + tenantMessageProperties.put(tenantId, tenantProperties); + } + if (i18nListProperties == null) { + // 语言加载失败, 一分钟后重新加载, 避免高频请求 + tenantProperties.put(locale.toLanguageTag(), emptyProperties, 60000L); + } else { + // 无论是否有内容返回都是加载成功, 如果properties为空没有翻译数据, 服务端新增翻译时会清空缓存重新加载 + tenantProperties.put(locale.toLanguageTag(), i18nListProperties); + } + } + + @Override + public MCode getI18nMessage(String code, Locale locale) { + UserInfo userInfo = UserProvider.getUser(); + // 未登录不获取 + if (userInfo.getToken() == null) { + return null; + } + // 默认租户或者当前租户 + String tenantId = GlobalConst.DEFAULT_TENANT_VALUE; + if (configValueUtil.isMultiTenancy()) { + tenantId = TenantHolder.getDatasourceId(); + } + // 开启租户未获取到租户 不进行翻译获取 + if (tenantId != null) { + // 租户配置中的语言配置 + String languageTag = locale.toLanguageTag(); + if (!tenantMessageProperties.containsKey(tenantId) || !tenantMessageProperties.get(tenantId).containsKey(languageTag)) { + // 租户其他线程正在加载多语言则直接返回 + ReentrantLock lock = lockMap.computeIfAbsent(tenantId, k -> new ReentrantLock()); + boolean isLock = false; + try { + isLock = lock.tryLock(); + if (isLock) { + loadTenantMessage(tenantId, locale); + } else { + log.debug("[{}]语言加载中, 直接返回", tenantId); + return null; + } + } finally { + if (isLock) { + lock.unlock(); + } + } + } + Properties languageProperty = tenantMessageProperties.get(tenantId).get(languageTag, false); + if (languageProperty != null) { + Object message = languageProperty.get(code); + if (message != null) { + return new MCode("", code, message.toString()); + } + } + } + return null; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-office/pom.xml new file mode 100644 index 0000000..6b6c308 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/pom.xml @@ -0,0 +1,41 @@ + + + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-office + + + + com.yunzhupaas + yunzhupaas-common-core + + + cn.afterturn + easypoi-base + + + validation-api + javax.validation + + + + + com.github.librepdf + openpdf + + + com.github.librepdf + openpdf-fonts-extra + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelExportStyler.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelExportStyler.java new file mode 100644 index 0000000..61d7e66 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelExportStyler.java @@ -0,0 +1,118 @@ +package com.yunzhupaas.excel; + +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import cn.afterturn.easypoi.excel.entity.params.ExcelForEachParams; +import cn.afterturn.easypoi.excel.export.styler.IExcelExportStyler; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.DefaultIndexedColorMap; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.apache.poi.xssf.usermodel.XSSFColor; + +public class ExcelExportStyler implements IExcelExportStyler { + + private static final short FONT_SIZE_TWELVE = 12; + + private Workbook workbook; + + private CellStyle headStyle; + + private XSSFCellStyle cellStyle; + + public ExcelExportStyler(Workbook workbook) { + this.workbook = workbook; + this.headStyle = getBaseCellStyle(); + this.cellStyle = (XSSFCellStyle) workbook.createCellStyle(); + } + + @Override + public CellStyle getHeaderStyle(short color) { + CellStyle style = this.headStyle; + return style; + } + + @Override + public CellStyle getTitleStyle(short color) { + XSSFCellStyle style = (XSSFCellStyle) this.headStyle; + style.setFont(getFont(workbook, FONT_SIZE_TWELVE, true)); + // 自定义背景颜色 + byte[] rgb = new byte[]{(byte) 221, (byte) 220, (byte) 223}; // RGB值 + XSSFColor customColor = new XSSFColor(rgb, new DefaultIndexedColorMap()); + style.setFillForegroundColor(customColor); + //设置填充模式为实心填充 + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + return style; + } + + public void setBlackBorder(CellStyle style) { + // 设置边框样式为细线 + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderTop(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + // 设置单元格颜色 + style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); + style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); + style.setRightBorderColor(IndexedColors.BLACK.getIndex()); + style.setTopBorderColor(IndexedColors.BLACK.getIndex()); + // 单元格内容水平居中 + style.setAlignment(HorizontalAlignment.LEFT); + // 单元格内容垂直居中 + style.setVerticalAlignment(VerticalAlignment.CENTER); + // 单元格内的文本超出单元格宽度时自动换行 + style.setWrapText(true); + } + + + @Override + public CellStyle getStyles(boolean parity, ExcelExportEntity entity) { + XSSFCellStyle style = cellStyle; + this.setBlackBorder(style); + // 单元格内容水平居中 + style.setAlignment(HorizontalAlignment.LEFT); + // 单元格内容垂直居中 + style.setVerticalAlignment(VerticalAlignment.CENTER); + // 单元格内的文本超出单元格宽度时自动换行 + style.setWrapText(true); + return style; + } + + + @Override + public CellStyle getStyles(Cell cell, int dataRow, ExcelExportEntity entity, Object obj, Object data) { + return getStyles(true, entity); + } + + @Override + public CellStyle getTemplateStyles(boolean isSingle, ExcelForEachParams excelForEachParams) { + return null; + } + + /** + * 表头单元格样式 + * + * @return + */ + private CellStyle getBaseCellStyle() { + CellStyle style = workbook.createCellStyle(); + this.setBlackBorder(style); + // 单元格内容水平居中 + style.setAlignment(HorizontalAlignment.CENTER); + return style; + } + + /** + * 字体修改 + * + * @param size 字号 + * @param isBold 加粗 + * @return + */ + private Font getFont(Workbook workbook, short size, boolean isBold) { + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setBold(isBold); + font.setFontHeightInPoints(size); + return font; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelFunction.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelFunction.java new file mode 100644 index 0000000..9a02191 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelFunction.java @@ -0,0 +1,10 @@ +package com.yunzhupaas.excel; + + +import java.util.Map; + +@FunctionalInterface +public interface ExcelFunction { + void apply(ExcelHelper compute, Map params); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelHelper.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelHelper.java new file mode 100644 index 0000000..af16599 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelHelper.java @@ -0,0 +1,158 @@ +package com.yunzhupaas.excel; + +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import com.yunzhupaas.excel.handle.ExcelCommentHandle; +import com.yunzhupaas.excel.handle.ExcelDataValidation; +import com.yunzhupaas.excel.handle.ExcelRequireRedColor; +import com.yunzhupaas.model.ExcelColumnAttr; +import com.yunzhupaas.model.ExcelModel; +import com.yunzhupaas.util.ExcelUtil; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFCell; + +import java.util.*; +import java.util.stream.Collectors; + +@Data +@NoArgsConstructor +public class ExcelHelper { + // 是否生成示例数据 + public boolean needExampleData = false; + boolean initPre = false; + boolean initPost = false; + /** + * 控件信息 + */ + List models; + /** + * 控件信息和excel导出的key对应关系 + */ + Map modelMap = new HashMap<>(); + /** + * excel参数 + */ + ExportParams exportParams; + /** + * 导出字段信息 + */ + List entities; + private Workbook workbook; + private List preHandleFunctions = new ArrayList<>(); + private List postHandleFunctions = new ArrayList<>(); + private Map optionMap; + /** + * 额外参数 + */ + private Map extraParams = new HashMap<>(); + /** + * 存在子表 + */ + private boolean complexTable; + + private void preDataHandle() { + for (ExcelExportEntity entity : this.entities) { + if (CollectionUtils.isNotEmpty(entity.getList())) { + this.complexTable = true; + break; + } + } + // 控件映射 + for (ExcelColumnAttr model : this.models) { + String key = model.getKey(); + modelMap.put(key, model); + } + } + + public void init(Workbook workbook, ExportParams exportParams, List entities, ExcelModel excelModel) { + this.workbook = workbook; + this.exportParams = exportParams != null ? exportParams : new ExportParams(); + this.models = excelModel.getModels() != null ? excelModel.getModels() : new ArrayList<>(); + this.entities = entities != null ? entities : new ArrayList<>(); + this.optionMap = excelModel.getOptionMap() != null ? excelModel.getOptionMap() : new HashMap<>(); + this.preDataHandle(); + } + + private void initPreHandle() { + addPreHandle(new ExcelCommentHandle()::execute); + this.initPre = true; + } + + private void initPostHandle() { + addPostHandle(new ExcelDataValidation()::execute); + addPostHandle(new ExcelRequireRedColor()::execute); + this.initPost = true; + } + + public void doPreHandle() { + if (!initPre) { + this.initPreHandle(); + } + addPreHandle(new ExcelCommentHandle()::execute); + preHandleFunctions.stream().filter(Objects::nonNull).collect(Collectors.toList()).forEach(item -> item.apply(this, this.extraParams)); + } + + public void doPostHandle() { + if (!initPost) { + this.initPostHandle(); + } + postHandleFunctions.stream().filter(Objects::nonNull).collect(Collectors.toList()).forEach(item -> item.apply(this, this.extraParams)); + // 移除标题的括号文字 + this.removeTitleConclusion(); + // 添加border线 + this.addCellBorder(); + } + + private void addCellBorder() { + Sheet sheet = workbook.getSheet(exportParams.getSheetName()); + int rowLen = sheet.getLastRowNum(); + int startRowLen = complexTable ? 2 : 1; + int lastCellNum = sheet.getRow(startRowLen - 1).getLastCellNum(); + CellStyle style = workbook.createCellStyle(); + ExcelExportStyler excelExportStyler = new ExcelExportStyler(workbook); + for (int i = startRowLen; i <= rowLen; i++) { + Row row = sheet.getRow(i); + + for (int j = 0; j < lastCellNum; j++) { + Cell cell = row.getCell(j); + if (cell == null) cell = row.createCell(j); + excelExportStyler.setBlackBorder(style); + //设置单元格为文本格式 + DataFormat dataFormat = workbook.createDataFormat(); + style.setDataFormat(dataFormat.getFormat("@")); + cell.setCellStyle(style); + } + } + } + + private void removeTitleConclusion() { + Sheet sheet = workbook.getSheet(exportParams.getSheetName()); + int rowLen = complexTable ? 2 : 1; + for (int i = 0; i < rowLen; i++) { + Row headerRow = sheet.getRow(i); + int lastCellNum = headerRow.getLastCellNum(); + for (int j = 0; j < lastCellNum; j++) { + Cell cell = headerRow.getCell(j); + if (cell == null) continue; + String name = ((XSSFCell) cell).getRichStringCellValue().getString(); + if (ExcelUtil.matcherFind(name)) { + ((XSSFCell) cell).getRichStringCellValue().setString(name.substring(0, name.lastIndexOf("("))); + } + } + } + } + + public void addPreHandle(ExcelFunction... functions) { + Collections.addAll(preHandleFunctions, functions); + } + + public void addPostHandle(ExcelFunction... functions) { + Collections.addAll(postHandleFunctions, functions); + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelPostHandle.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelPostHandle.java new file mode 100644 index 0000000..a39edaf --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelPostHandle.java @@ -0,0 +1,8 @@ +package com.yunzhupaas.excel; + +import java.util.Map; + +public interface ExcelPostHandle { + void execute(ExcelHelper data, Map params); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelPreHandle.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelPreHandle.java new file mode 100644 index 0000000..38f664f --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/ExcelPreHandle.java @@ -0,0 +1,8 @@ +package com.yunzhupaas.excel; + +import java.util.Map; + +public interface ExcelPreHandle { + void execute(ExcelHelper data, Map params); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/handle/ExcelCommentHandle.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/handle/ExcelCommentHandle.java new file mode 100644 index 0000000..5f4c676 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/handle/ExcelCommentHandle.java @@ -0,0 +1,86 @@ +package com.yunzhupaas.excel.handle; + +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import com.yunzhupaas.excel.ExcelHelper; +import com.yunzhupaas.excel.ExcelPreHandle; +import com.yunzhupaas.util.ExcelUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFCell; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * excel添加批注 + */ +public class ExcelCommentHandle implements ExcelPreHandle { + String sheetName; + Workbook workbook; + int headerRowLen; + int lastRowNum; + + /** + * workbook增加标题批注 + * + * @param workbook 工作簿 + * @param sheetName 工作表名称 + * @param columnIndex 列索引,从0开始 + * @param comment 批注内容 + */ + public void addComment(Workbook workbook, String sheetName, int rowIndex, int columnIndex, String comment) { + Sheet sheet = workbook.getSheet(sheetName); + Row headerRow = sheet.getRow(rowIndex); + Cell headerCell = headerRow.getCell(columnIndex); + // 判断是否存在批注 + Comment cellComment = headerCell.getCellComment(); + if (!Objects.isNull(cellComment)) { + headerCell.setCellComment(null); + } + Drawing drawing = sheet.createDrawingPatriarch(); + CreationHelper factory = workbook.getCreationHelper(); + ClientAnchor anchor = factory.createClientAnchor(); + anchor.setRow1(rowIndex); + anchor.setCol1(columnIndex); + Comment headerComment = drawing.createCellComment(anchor); + RichTextString str = factory.createRichTextString(comment); + headerComment.setString(str); + headerCell.setCellComment(headerComment); + } + + @Override + public void execute(ExcelHelper data, Map params) { + List list = data.getEntities(); + ExportParams exportParams = data.getExportParams(); + workbook = data.getWorkbook(); + params.put("sheetName", sheetName); + this.sheetName = exportParams.getSheetName(); + Sheet sheet = workbook.getSheet(exportParams.getSheetName()); + headerRowLen = data.isComplexTable() ? 2 : 1; + sheet.createFreezePane(exportParams.getFreezeCol(),headerRowLen); + lastRowNum = sheet.getLastRowNum(); + for (int i = 0; i < headerRowLen; i++) { + Row headerRow = sheet.getRow(i); + int lastCellNum = headerRow.getLastCellNum(); + for (int j = 0; j < lastCellNum; j++) { + Cell cell = headerRow.getCell(j); + this.addComment(cell, i, j); + } + } + } + + + private void addComment(Cell cell, int rowIndex, int columnIndex) { + if (cell == null) return; + String name = ((XSSFCell) cell).getRichStringCellValue().getString(); + if (StringUtils.isBlank(name)) return; + String id = ExcelUtil.getIdFromCellValue(name); + if (StringUtils.isNotBlank(id)) { + this.addComment(workbook, sheetName, rowIndex, columnIndex, id); + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/handle/ExcelDataValidation.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/handle/ExcelDataValidation.java new file mode 100644 index 0000000..d26d56b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/handle/ExcelDataValidation.java @@ -0,0 +1,122 @@ +package com.yunzhupaas.excel.handle; + +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import com.yunzhupaas.excel.ExcelHelper; +import com.yunzhupaas.excel.ExcelPostHandle; +import com.yunzhupaas.model.ExcelColumnAttr; +import com.yunzhupaas.util.ExcelUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.xssf.usermodel.XSSFCell; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * excel添加数据下拉校验 + * 下拉选择(单选)、单选框组、开关导入EXCEL内生成【数据验证】下拉框 + */ +public class ExcelDataValidation implements ExcelPostHandle { + String sheetName; + Map modelMap; + ExcelHelper data; + private Workbook workbook; + int hiddenIndex = 0; + int headerRowLen = 0; + int lastRowNum = 0; + Map optionMap; + + /** + * 用于下拉内容很多,字符超过255 + *

+ * 下拉选项(先将数据放到另一个sheet页,然后下拉的数据再去sheet页读取,解决普通下拉数据量太多下拉不显示问题) + *

+ * firstRow 开始行号(下标0开始) + *

+ * lastRow 结束行号,最大65535 + *

+ * firstCol 区域中第一个单元格的列号 (下标0开始) + *

+ * lastCol 区域中最后一个单元格的列号 + *

+ * sheetIndex 创建的sheet的index。如果有多个下拉想放到sheet页,则需要设置不同的sheetIndex,(注意不能设置为0,0为主数据页) + *

+ * selectList 下拉内容 + */ + + public void selectLargeList(Workbook workbook, int firstRow, int lastRow, int firstCol, int lastCol, int sheetIndex, String[] selectList) { + Sheet sheet = workbook.getSheetAt(0); + //将下拉框数据放到新的sheet里,然后excle通过新的sheet数据加载下拉框数据 + String sheetName = "sheetName" + sheetIndex; + Sheet hidden = workbook.createSheet(sheetName); + //创建单元格对象 + Cell cell = null; + //遍历我们上面的数组,将数据取出来放到新sheet的单元格中 + for (int i = 0, length = selectList.length; i < length; i++) { + //取出数组中的每个元素 + String name = selectList[i]; + //根据i创建相应的行对象(说明我们将会把每个元素单独放一行) + Row row = hidden.createRow(i); + //创建每一行中的第一个单元格 + cell = row.createCell(0); + //然后将数组中的元素赋值给这个单元格 + cell.setCellValue(name); + } + // 创建名称,可被其他单元格引用 + String refers = sheetName + "!$A$1:$A$" + selectList.length; + //这个3代表我的下拉数据从第三行开始生效,前面1,2行不显示下拉,你们根据自己情况修改。 + CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(firstRow, lastRow, firstCol, lastCol); + DataValidationHelper helper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = helper.createFormulaListConstraint(refers); + DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList); + //将第sheetIndex个sheet设置为隐藏 + sheet.addValidationData(dataValidation); + hiddenIndex++; + } + + @Override + public void execute(ExcelHelper data, Map params) { + hiddenIndex = 0; + workbook = data.getWorkbook(); + optionMap = data.getOptionMap() != null ? data.getOptionMap() : new HashMap<>(); + List list = data.getEntities(); + ExportParams exportParams = data.getExportParams(); + this.sheetName = exportParams.getSheetName(); + this.data = data; + modelMap = data.getModelMap() != null ? data.getModelMap() : new HashMap<>(); + Sheet sheet = workbook.getSheet(exportParams.getSheetName()); + headerRowLen = data.isComplexTable() ? 2 : 1; + lastRowNum = sheet.getLastRowNum(); + + for (int i = 0; i < headerRowLen; i++) { + Row headerRow = sheet.getRow(i); + int lastCellNum = headerRow.getLastCellNum(); + for (int j = 0; j < lastCellNum; j++) { + Cell cell = headerRow.getCell(j); + addDataValidation(cell, j); + } + } + // 隐藏校验sheet + for (int i = 1; i <= hiddenIndex; i++) { + workbook.setSheetHidden(i, true); + } + } + + private void addDataValidation(Cell cell, int columnIndex) { + if (cell == null) return; + String key = ((XSSFCell) cell).getRichStringCellValue().getString(); + if (StringUtils.isBlank(key)) return; + String id = ExcelUtil.getIdFromCellValue(key); + ExcelColumnAttr model = modelMap.get(id); + if (Objects.isNull(model)) return; + String[] options = optionMap.get(id); + if (options != null && options.length > 0) { + selectLargeList(workbook, headerRowLen, lastRowNum, columnIndex, columnIndex, columnIndex, options); + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/handle/ExcelRequireRedColor.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/handle/ExcelRequireRedColor.java new file mode 100644 index 0000000..5c56e67 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/excel/handle/ExcelRequireRedColor.java @@ -0,0 +1,61 @@ +package com.yunzhupaas.excel.handle; + +import cn.afterturn.easypoi.excel.entity.ExportParams; +import com.yunzhupaas.excel.ExcelHelper; +import com.yunzhupaas.excel.ExcelPostHandle; +import com.yunzhupaas.model.ExcelColumnAttr; +import com.yunzhupaas.util.ExcelUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFCell; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * excel必填字段的字体颜色修改为红色 + */ +public class ExcelRequireRedColor implements ExcelPostHandle { + Map modelMap; + Workbook workbook; + + @Override + public void execute(ExcelHelper data, Map params) { + ExportParams exportParams = data.getExportParams(); + workbook = data.getWorkbook(); + modelMap = data.getModelMap() != null ? data.getModelMap() : new HashMap<>(); + Sheet sheet = workbook.getSheet(exportParams.getSheetName()); + int rowLen = data.isComplexTable() ? 2 : 1; + for (int i = 0; i < rowLen; i++) { + Row headerRow = sheet.getRow(i); + int lastCellNum = headerRow.getLastCellNum(); + for (int j = 0; j < lastCellNum; j++) { + Cell cell = headerRow.getCell(j); + judgeRequired(cell); + } + } + } + + private void judgeRequired(Cell cell) { + if (cell == null) return; + String key = ((XSSFCell) cell).getRichStringCellValue().getString(); + if (StringUtils.isNotBlank(key)) { + String id = ExcelUtil.getIdFromCellValue(key); + ExcelColumnAttr model = modelMap.get(id); + if (Objects.isNull(model)) return; + if (model.isRequire()) { + ((XSSFCell) cell).getRichStringCellValue().setString("*" + key); + CellStyle originalCellStyle = cell.getCellStyle(); + Font font = workbook.createFont(); + font.setColor(model.getFontColor()); + font.setBold(true); + CellStyle redCellStyle = workbook.createCellStyle(); + redCellStyle.cloneStyleFrom(originalCellStyle); // 复制原有样式避免覆盖其他设置 + redCellStyle.setFont(font); + cell.setCellStyle(redCellStyle); + } + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelColumnAttr.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelColumnAttr.java new file mode 100644 index 0000000..b1363cc --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelColumnAttr.java @@ -0,0 +1,34 @@ +package com.yunzhupaas.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.poi.ss.usermodel.IndexedColors; + +/** + * 表头属性 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ExcelColumnAttr { + /** + * key + */ + private String key; + /** + * 字段名称 + */ + private String name; + /** + * 是否必填 + */ + private boolean require; + /** + * 标题字体颜色 + */ + private short fontColor; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelImportForm.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelImportForm.java new file mode 100644 index 0000000..0619ade --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelImportForm.java @@ -0,0 +1,37 @@ +package com.yunzhupaas.model; + +import lombok.Data; + +import java.util.List; +import java.util.Map; + +/** + * 导入数据表单 + * + * @author 云筑产品开发平台组 + * @version v5.0.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/5/18 11:45:52 + */ +@Data +public class ExcelImportForm { + /** + * 数据数组 + */ + private List> list; + /** + * 菜单ID + */ + private String menuId; + + /** + * 跳过数据预览 + */ + private boolean type; + + /** + * 文件名称 + */ + private String fileName; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelImportVO.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelImportVO.java new file mode 100644 index 0000000..5a0c731 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelImportVO.java @@ -0,0 +1,41 @@ +package com.yunzhupaas.model; + +import lombok.Data; + +import java.util.List; +import java.util.Map; + +/** + * 导入结果展示对象 + * + * @author 云筑产品开发平台组 + * @version v5.0.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/5/18 11:44:31 + */ +@Data +public class ExcelImportVO { + /** + * 导入成功条数 + */ + private int snum; + /** + * 导入失败条数 + */ + private int fnum; + /** + * 导入结果状态(0,成功 1,失败) + */ + private int resultType; + + /** + * 失败结果 + */ + private List> failResult; + + /** + * 失败结果 + */ + private List> headerRow; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelModel.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelModel.java new file mode 100644 index 0000000..61e3be9 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelModel.java @@ -0,0 +1,54 @@ +package com.yunzhupaas.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 表工具通用参数 + * + * @author 云筑产品开发平台组 + * @version v5.0.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/5/18 11:46:16 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ExcelModel { + /** + * 选中得字段key + */ + List selectKey; + /** + * 控件信息 + */ + List models; + + /** + * 一条数据 + */ + Map dataMap; + + /** + * 下拉数据 + */ + private Map optionMap; + + /** + * excel抬头 + */ + private boolean hasHeader = false; + + /** + * excel抬头-内容 + */ + private List headerContent = new ArrayList<>(); +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelViewFieldModel.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelViewFieldModel.java new file mode 100644 index 0000000..7b9e397 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/model/ExcelViewFieldModel.java @@ -0,0 +1,45 @@ +package com.yunzhupaas.model; + +import lombok.Data; + +import java.util.List; + +/** + * 导入预览表头对象 + * + * @author 云筑产品开发平台组 + * @version v5.0.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/5/18 11:38:15 + */ +@Data +public class ExcelViewFieldModel { + private String id; + private String fullName; + private String yunzhupaasKey; + private List children; + + public ExcelViewFieldModel(String id, String fullName, List children) { + this.id = id; + this.fullName = fullName; + this.children = children; + } + + public ExcelViewFieldModel(String id, String fullName) { + this.id = id; + this.fullName = fullName; + } + + public ExcelViewFieldModel(String id, String fullName, String yunzhupaasKey, List children) { + this.id = id; + this.fullName = fullName; + this.yunzhupaasKey = yunzhupaasKey; + this.children = children; + } + + public ExcelViewFieldModel(String id, String fullName, String yunzhupaasKey) { + this.id = id; + this.fullName = fullName; + this.yunzhupaasKey = yunzhupaasKey; + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/util/ExcelUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/util/ExcelUtil.java new file mode 100644 index 0000000..a4925be --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/util/ExcelUtil.java @@ -0,0 +1,308 @@ +package com.yunzhupaas.util; + +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import jakarta.servlet.http.HttpServletResponse; +import com.yunzhupaas.exception.ImportException; +import com.yunzhupaas.support.MyStandardMultipartFile; +import lombok.Cleanup; +import org.apache.catalina.core.ApplicationPart; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.apache.tomcat.util.http.fileupload.FileItem; +import org.apache.tomcat.util.http.fileupload.FileItemFactory; +import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.net.URLEncoder; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +public class ExcelUtil { + + /** + * Workbook 转 MultipartFile + * + * @param workbook excel文档 + * @param fileName 文件名 + * @return + */ + public static MultipartFile workbookToCommonsMultipartFile(Workbook workbook, String fileName) { + //Workbook转FileItem + FileItemFactory factory = new DiskFileItemFactory(16, null); + FileItem fileItem = factory.createItem("textField", "text/plain", true, fileName); + try { + OutputStream os = fileItem.getOutputStream(); + workbook.write(os); + os.close(); + //FileItem转MultipartFile + MultipartFile multipartFile = new MyStandardMultipartFile(new ApplicationPart(fileItem, null), fileName); + return multipartFile; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 下载excel + * + * @param fileName excel名称 + * @param workbook + */ + public static void dowloadExcel(Workbook workbook, String fileName) { + try { + HttpServletResponse response = ServletUtil.getResponse(); + response.setCharacterEncoding("UTF-8"); + response.setHeader("content-Type", "application/vnd.ms-excel"); + response.setHeader("Content-Disposition", + "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); + workbook.write(response.getOutputStream()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * excel转成实体 + * + * @param filePath 路径 + * @param titleRows 行 + * @param headerRows 列 + * @param pojoClass 实体 + * @param + * @return + */ + public static List importExcel(String filePath, Integer titleRows, Integer headerRows, Class pojoClass) { + if (StringUtils.isBlank(filePath)) { + return null; + } + ImportParams params = new ImportParams(); + params.setTitleRows(titleRows); + params.setHeadRows(headerRows); + List list = null; + try { + list = ExcelImportUtil.importExcel(new File(com.yunzhupaas.util.XSSEscape.escapePath(filePath)), pojoClass, params); + } catch (Exception e) { + e.printStackTrace(); + } + return list; + } + + /** + * excel转成实体 + * + * @param file 文件 + * @param titleRows 行 + * @param headerRows 列 + * @param pojoClass 实体 + * @param + * @return + */ + public static List importExcel(File file, Integer titleRows, Integer headerRows, Class pojoClass) throws ImportException { + if (file == null) { + return null; + } + ImportParams params = new ImportParams(); + params.setTitleRows(titleRows); + params.setHeadRows(headerRows); + List list = null; + try { + list = ExcelImportUtil.importExcel(file, pojoClass, params); + } catch (Exception e) { + throw new ImportException(e.getMessage()); + } + return list; + } + + /** + * excel转成实体 + * + * @param inputStream 文件流 + * @param titleRows 行 + * @param headerRows 列 + * @param pojoClass 实体 + * @param + * @return + */ + public static List importExcelByInputStream(InputStream inputStream, Integer titleRows, Integer headerRows, Class pojoClass) throws Exception { + if (inputStream == null) { + return null; + } + ImportParams params = new ImportParams(); + params.setTitleRows(titleRows); + params.setHeadRows(headerRows); + List list = null; + list = ExcelImportUtil.importExcel(inputStream, pojoClass, params); + return list; + } + + /** + * excel转成实体 + * + * @param file 文件 + * @param titleRows 行 + * @param headerRows 列 + * @param pojoClass 实体 + * @param + * @return + */ + public static List importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class pojoClass) { + ImportParams params = new ImportParams(); + params.setTitleRows(titleRows); + params.setHeadRows(headerRows); + List list = null; + try { + list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params); + } catch (Exception e) { + e.printStackTrace(); + } + return list; + } + + /** + * 备用方案,读取不到时间暂用此方法 + * 通过基础poi读取NUMERIC转换成时间格式 + * + * @param + * @return + * @copyright 深圳市乐程软件有限公司 + * @date 2023/2/3 + */ + public static void imoportExcelToMap(File file, Integer titleIndex, List excelDataList) { + List> mapList = new ArrayList<>(); + FileInputStream inputStream = null; + try { + String fileName = file.getName(); + @Cleanup Workbook workbook = null; + inputStream = new FileInputStream(file); + try { + workbook = new HSSFWorkbook(inputStream); + } catch (Exception e) { + inputStream = new FileInputStream(file); + workbook = new XSSFWorkbook(inputStream); + } + + Sheet sheet = workbook.getSheetAt(0); + Row titleRow = sheet.getRow(titleIndex - 1); + + for (int i = titleIndex; i < sheet.getPhysicalNumberOfRows(); i++) { + Row row = sheet.getRow(i); + Map map = new HashMap<>(); + for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) { + Cell cell = row.getCell(j); + Cell titleCell = titleRow.getCell(j); + if (cell != null && org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) { + short format = cell.getCellStyle().getDataFormat(); + if (cell.getDateCellValue() != null && format > 0) { + //表头数据 + String titleName = titleCell.getStringCellValue(); + if (StringUtil.isEmpty(titleName)) { + titleName = sheet.getRow(titleIndex - 2).getCell(j).getStringCellValue(); + } + //单元格内容 + Date dateCellValue = cell.getDateCellValue(); + String valueName = DateUtil.daFormat(dateCellValue); + map.put(titleName, valueName); + } + } + } + mapList.add(map); + } + //基础poi读取到时间同步到easypoi读取到的数据中去 + if (!CollectionUtils.sizeIsEmpty(mapList)) { + for (int n = 0; n < mapList.size(); n++) { + Map a = mapList.get(n); + Map b = excelDataList.get(n); + if (a != null) { + for (String key : a.keySet()) { + if (b.containsKey(key)) b.put(key, a.get(key)); + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static InputStream solveOrginTitle(File file, Integer rowLen) throws IOException { + return solveOrginTitle(file, 0, rowLen); + } + + public static InputStream solveOrginTitle(File file, Integer titleIndex, Integer rowLen) throws IOException { + @Cleanup Workbook workbook = WorkbookFactory.create(file); + Sheet sheet = workbook.getSheetAt(0); + + for (int i = titleIndex; i < titleIndex + rowLen; i++) { + Row headerRow = sheet.getRow(i); + int lastCellNum = headerRow.getLastCellNum(); + for (int j = 0; j < lastCellNum; j++) { + Cell cell = headerRow.getCell(j); + if (cell == null) { + continue; + } + String name = cell.getStringCellValue(); + Comment cellComment = cell.getCellComment(); + //都没有标题就跳过 + if (StringUtils.isEmpty(name) && cellComment == null) { + continue; + } + //有标题没批注,说明表头有问题 + if (Objects.isNull(cellComment)) { + throw new RuntimeException(); + } + name = name + "(" + cellComment.getString().getString() + ")"; + cell.setCellValue(name); + } + } + MultipartFile multipartFile = ExcelUtil.workbookToCommonsMultipartFile(workbook, file.getName()); + InputStream inputStream = multipartFile.getInputStream(); + return inputStream; + } + + /** + * 判断字符串内有没有括号 + * + * @param str + * @return + */ + public static boolean matcherFind(String str) { + Pattern pattern = Pattern.compile("(.*)\\((.*?)\\)"); + Matcher matcher = pattern.matcher(str); + return matcher.find(); + } + + /** + * 获取标题括号内得id + * + * @param cellValue + * @return + */ + public static String getIdFromCellValue(String cellValue) { + String id = ""; + if (matcherFind(cellValue)) { + id = cellValue.substring(cellValue.lastIndexOf("(") + 1, cellValue.lastIndexOf(")")); + } + return id; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/util/PdfUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/util/PdfUtil.java new file mode 100644 index 0000000..144691d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/util/PdfUtil.java @@ -0,0 +1,52 @@ +package com.yunzhupaas.util; + +import com.lowagie.text.pdf.PdfReader; +import lombok.Cleanup; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +/** + * PDF工具 + * @author 云筑产品开发平台组 + * @version V5.2.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2025/1/14 15:00 + */ +@Slf4j +public class PdfUtil { + + + /** + * 校验pdf文件是否包含js脚本 + **/ + public static boolean containsJavaScript(File file) { + try { + return containsJavaScript(Files.readAllBytes(file.toPath())); + } catch (IOException e) { + log.error("PDF文档解析失败: {}", e.getMessage()); + } + return false; + } + + + /** + * 校验pdf文件是否包含js脚本 + **/ + public static boolean containsJavaScript(byte[] filebyte) { + try { + @Cleanup PdfReader reader = new PdfReader(filebyte); + String javaScript = reader.getJavaScript(); + if(StringUtil.isNotEmpty(javaScript)) { + return true; + } + } catch (Exception e) { + log.error("PDF文档解析失败: {}", e.getMessage()); + } + return false; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/util/WordUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/util/WordUtil.java new file mode 100644 index 0000000..713c78c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-office/src/main/java/com/yunzhupaas/util/WordUtil.java @@ -0,0 +1,161 @@ +package com.yunzhupaas.util; + +import lombok.Cleanup; +import org.apache.poi.ooxml.POIXMLDocument; +import org.apache.poi.xwpf.usermodel.*; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:57 + */ +public class WordUtil { + + /** + * 根据模板生成新word文档 + * 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入 + * @param inputUrl 模板存放地址 + * @param outputUrl 新文档存放地址 + * @param textMap 需要替换的信息集合 + * @param tableList 需要插入的表格信息集合 + * @return 成功返回true,失败返回false + */ + public static void changWord(String inputUrl, String outputUrl, Map textMap, List tableList) { + boolean changeFlag = true; + try { + XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl)); + changeText(document, textMap); + changeTable(document, textMap, tableList); + File file = new File(com.yunzhupaas.util.XSSEscape.escapePath(outputUrl)); + @Cleanup FileOutputStream stream = new FileOutputStream(file); + document.write(stream); + stream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 替换段落文本 + * @param document docx解析对象 + * @param textMap 需要替换的信息集合 + */ + public static void changeText(XWPFDocument document, Map textMap){ + List paragraphs = document.getParagraphs(); + for (XWPFParagraph paragraph : paragraphs) { + String text = paragraph.getText(); + if(checkText(text)){ + List runs = paragraph.getRuns(); + for (XWPFRun run : runs) { + run.setText(changeValue(run.toString(), textMap),0); + } + } + } + } + + /** + * 替换表格对象方法 + * @param document docx解析对象 + * @param textMap 需要替换的信息集合 + * @param tableList 需要插入的表格信息集合 + */ + public static void changeTable(XWPFDocument document, Map textMap, List tableList){ + List tables = document.getTables(); + for (int i = 0; i < tables.size(); i++) { + XWPFTable table = tables.get(i); + if(table.getRows().size()>1){ + if(checkText(table.getText())){ + List rows = table.getRows(); + eachTable(rows, textMap); + }else{ + insertTable(table, tableList); + } + } + } + } + + /** + * 遍历表格 + * @param rows 表格行对象 + * @param textMap 需要替换的信息集合 + */ + public static void eachTable(List rows , Map textMap){ + for (XWPFTableRow row : rows) { + List cells = row.getTableCells(); + for (XWPFTableCell cell : cells) { + if(checkText(cell.getText())){ + List paragraphs = cell.getParagraphs(); + for (XWPFParagraph paragraph : paragraphs) { + List runs = paragraph.getRuns(); + for (XWPFRun run : runs) { + run.setText(changeValue(run.toString(), textMap),0); + } + } + } + } + } + } + + /** + * 为表格插入数据,行数不够添加新行 + * @param table 需要插入数据的表格 + * @param tableList 插入数据集合 + */ + public static void insertTable(XWPFTable table, List tableList){ + for(int i = 1; i < tableList.size(); i++){ + XWPFTableRow row =table.createRow(); + } + List rows = table.getRows(); + for(int i = 1; i < rows.size(); i++){ + XWPFTableRow newRow = table.getRow(i); + List cells = newRow.getTableCells(); + for(int j = 0; j < cells.size(); j++){ + XWPFTableCell cell = cells.get(j); + cell.setText(tableList.get(i-1)[j]); + } + } + } + + /** + * 判断文本中时候包含$ + * @param text 文本 + * @return 包含返回true,不包含返回false + */ + public static boolean checkText(String text){ + boolean check = false; + if(text.indexOf("$")!= -1){ + check = true; + } + return check; + } + + /** + * 匹配传入信息集合与模板 + * @param value 模板需要替换的区域 + * @param textMap 传入信息集合 + * @return 模板需要替换区域信息集合对应值 + */ + public static String changeValue(String value, Map textMap){ + Set> textSets = textMap.entrySet(); + for (Map.Entry textSet : textSets) { + String key = "${"+textSet.getKey()+"}"; + if(value.indexOf(key)!= -1){ + value = textSet.getValue(); + } + } + if(checkText(value)){ + value = ""; + } + return value; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-redis/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-redis/pom.xml new file mode 100644 index 0000000..4cead0c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-redis/pom.xml @@ -0,0 +1,36 @@ + + + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-redis + + + + com.yunzhupaas + yunzhupaas-common-core + + + com.baomidou + lock4j-redisson-spring-boot-starter + + + org.redisson + redisson-spring-boot-starter + + + org.springframework.boot + spring-boot-starter-actuator + + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/FastJsonRedis.java b/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/FastJsonRedis.java new file mode 100644 index 0000000..88dc55e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/FastJsonRedis.java @@ -0,0 +1,50 @@ +package com.yunzhupaas.config; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializerFeature; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.SerializationException; + +import java.nio.charset.Charset; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +public class FastJsonRedis implements RedisSerializer +{ + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + private Class clazz; + + public FastJsonRedis(Class clazz) + { + super(); + this.clazz = clazz; + } + + @Override + public byte[] serialize(T t) throws SerializationException + { + if (t == null) + { + return new byte[0]; + } + return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); + } + + @Override + public T deserialize(byte[] bytes) throws SerializationException + { + if (bytes == null || bytes.length <= 0) + { + return null; + } + String str = new String(bytes, DEFAULT_CHARSET); + return (T) JSON.parseObject(str, clazz); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/Lock4jAutoConfiguration.java b/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/Lock4jAutoConfiguration.java new file mode 100644 index 0000000..597b4b5 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/Lock4jAutoConfiguration.java @@ -0,0 +1,51 @@ +package com.yunzhupaas.config; + +import com.baomidou.lock.aop.LockAnnotationAdvisor; +import com.baomidou.lock.aop.LockInterceptor; +import org.springframework.aop.Pointcut; +import org.springframework.aop.aspectj.AspectJExpressionPointcut; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; + +/** + * Lock4jAop开关 + */ +@Configuration(proxyBeanMethods = false) +public class Lock4jAutoConfiguration { + + @Bean + @ConditionalOnProperty(prefix = "lock4j.aop", name = "enabled", havingValue = "true", matchIfMissing = false) + public LockAnnotationAdvisor lockAnnotationAdvisor(LockInterceptor lockInterceptor) { + return new LockAnnotationAdvisor(lockInterceptor, Ordered.HIGHEST_PRECEDENCE){ + private final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); + + { + pointcut.setExpression("within(com.yunzhupaas..*) && @annotation(com.baomidou.lock.annotation.Lock4j)"); + } + + @Override + public Pointcut getPointcut() { + return pointcut; + } + }; + } + + @Bean + @ConditionalOnProperty(prefix = "lock4j.aop", name = "enabled", havingValue = "false", matchIfMissing = true) + public LockAnnotationAdvisor lockAnnotationAdvisor2(LockInterceptor lockInterceptor) { + return new LockAnnotationAdvisor(lockInterceptor, Integer.MIN_VALUE) { + private final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); + + { + this.pointcut.setExpression("within(com.yunzhupaas.config.*) && @annotation(com.baomidou.lock.annotation.Lock4j)"); + } + + public Pointcut getPointcut() { + return this.pointcut; + } + }; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/RedisConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/RedisConfig.java new file mode 100644 index 0000000..fba347b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/RedisConfig.java @@ -0,0 +1,101 @@ +package com.yunzhupaas.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.*; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Configuration +public class RedisConfig { + /** + * 注入 RedisConnectionFactory + */ + @Autowired + private RedisConnectionFactory factory; + + /** + * 实例化 RedisTemplate 对象 + * + * @return + */ + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(factory); + StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); + redisTemplate.setKeySerializer(stringRedisSerializer); + redisTemplate.setHashKeySerializer(stringRedisSerializer); + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); + redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); + redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } + + /** + * 实例化 HashOperations 对象,可以使用 Hash 类型操作 + * + * @param redisTemplate + * @return + */ + @Bean + public HashOperations hashOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForHash(); + } + + /** + * 实例化 ValueOperations 对象,可以使用 String 操作 + * + * @param redisTemplate + * @return + */ + @Bean + public ValueOperations valueOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForValue(); + } + + /** + * 实例化 ListOperations 对象,可以使用 List 操作 + * + * @param redisTemplate + * @return + */ + @Bean + public ListOperations listOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForList(); + } + + /** + * 实例化 SetOperations 对象,可以使用 Set 操作 + * + * @param redisTemplate + * @return + */ + @Bean + public SetOperations setOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForSet(); + } + + /** + * 实例化 ZSetOperations 对象,可以使用 ZSet 操作 + * + * @param redisTemplate + * @return + */ + @Bean + public ZSetOperations zSetOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForZSet(); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/RedisListenerConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/RedisListenerConfig.java new file mode 100644 index 0000000..b4ecb60 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/config/RedisListenerConfig.java @@ -0,0 +1,31 @@ +package com.yunzhupaas.config; + +import com.yunzhupaas.consts.RedisConst; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; + + +/** + * Redis 监听配置 + */ +@Configuration(proxyBeanMethods = false) +public class RedisListenerConfig { + + @Bean + public RedisConst getRedisConst(RedisProperties redisProperties){ + return new RedisConst(redisProperties); + } + + + @Bean + public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) { + RedisMessageListenerContainer container = new RedisMessageListenerContainer(); + container.setConnectionFactory(connectionFactory); + return container; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/consts/RedisConst.java b/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/consts/RedisConst.java new file mode 100644 index 0000000..6005af9 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/consts/RedisConst.java @@ -0,0 +1,18 @@ +package com.yunzhupaas.consts; + +import com.yunzhupaas.util.CacheKeyUtil; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; + +public class RedisConst { + + public RedisConst(RedisProperties redisProperties) { + REDIS_EVENT_KEY = "__keyevent@" + redisProperties.getDatabase() + "__:"; + } + + public static String REDIS_EVENT_KEY; + + public static String REDIS_LOCK4J_PREFIX = CacheKeyUtil.LOCK; + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/util/RedisUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/util/RedisUtil.java new file mode 100644 index 0000000..0b0f22a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-redis/src/main/java/com/yunzhupaas/util/RedisUtil.java @@ -0,0 +1,396 @@ +package com.yunzhupaas.util; + +import com.yunzhupaas.consts.RedisConst; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Slf4j +@Component +public class RedisUtil { + + /** + * 默认缓存时间 60S + */ + public final static int CAHCETIME = 60; + /** + * 默认缓存时间 1hr + */ + public final static int CAHCEHOUR = 60 * 60; + /** + * 默认缓存时间 1Day + */ + public final static int CAHCEDAY = 60 * 60 * 24; + /** + * 默认缓存时间 1week + */ + public final static int CAHCEWEEK = 60 * 60 * 24 * 7; + /** + * 默认缓存时间 1month + */ + public final static int CAHCEMONTH = 60 * 60 * 24 * 7 * 30; + /** + * 默认缓存时间 1年 + */ + public final static int CAHCEYEAR = 60 * 60 * 24 * 7 * 30 * 12; + + private static long expiresIn = TimeUnit.SECONDS.toSeconds(CAHCEHOUR * 8); + + @Autowired + private RedisTemplate redisTemplate; + @Autowired + private CacheKeyUtil cacheKeyUtil; + + // =============================common============================ + + /** + * 获取所有的key + * + * @return + */ + public Set getAllVisiualKeys() { + Set allKey = new HashSet<>(16); + allKey.addAll(Objects.requireNonNull(redisTemplate.keys("*" + cacheKeyUtil.getAllUser() + "*"))); + allKey.addAll(Objects.requireNonNull(redisTemplate.keys("*" + cacheKeyUtil.getCompanySelect() + "*"))); + allKey.addAll(Objects.requireNonNull(redisTemplate.keys("*" + cacheKeyUtil.getDictionary() + "*"))); + allKey.addAll(Objects.requireNonNull(redisTemplate.keys("*" + cacheKeyUtil.getDynamic() + "*"))); + allKey.addAll(Objects.requireNonNull(redisTemplate.keys("*" + cacheKeyUtil.getOrganizeList() + "*"))); + allKey.addAll(Objects.requireNonNull(redisTemplate.keys("*" + cacheKeyUtil.getPositionList() + "*"))); + allKey.addAll(Objects.requireNonNull(redisTemplate.keys("*" + cacheKeyUtil.getVisiualData() + "*"))); + return allKey; + } + + /** + * 获取所有的key + * + * @return + */ + public Set getAllKeys() { + Set keys = redisTemplate.keys("*"); + if (CollectionUtils.isNotEmpty(keys)) { + // 排除ID生成器的缓存记录, 如果删除在集群情况下ID生成器的机器编号可能会重复导致生成的ID重复 + keys = keys.stream().filter( + s -> !s.startsWith(CacheKeyUtil.IDGENERATOR) && !s.startsWith(RedisConst.REDIS_LOCK4J_PREFIX)) + .collect(Collectors.toSet()); + } + return keys; + } + + /** + * 返回 key 的剩余的过期时间 + * + * @param key + * @return + */ + public Long getLiveTime(String key) { + return redisTemplate.getExpire(key); + } + + /** + * 删除指定key + * + * @param key + */ + public void remove(String key) { + if (exists(key)) { + redisTemplate.delete(key); + } + } + + /** + * 删除全部redis + */ + public void removeAll() { + Set keys = getAllKeys(); + if (CollectionUtils.isNotEmpty(keys)) { + // 兼容Redis集群, 不同的KEY在不同服务器上不允许同时联合操作 + keys.forEach(k -> redisTemplate.delete(k)); + } + } + + /** + * 判断缓存中是否有对应的value + * + * @param key + * @return + */ + public boolean exists(final String key) { + return redisTemplate.hasKey(key); + } + + /** + * 指定缓存失效时间 + * + * @param key + * @param time + * @return + */ + public void expire(String key, long time) { + if (time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } else { + redisTemplate.expire(key, expiresIn, TimeUnit.SECONDS); + } + } + + /** + * 插入缓存(无时间) + * + * @param key + * @param object + */ + public void insert(String key, Object object) { + insert(key, object, 0); + } + + /** + * 插入缓存(有时间) + * + * @param key + * @param object + */ + public void insert(String key, Object object, long time) { + if (object instanceof Map) { + redisTemplate.opsForHash().putAll(key, (Map) object); + } else if (object instanceof List) { + redisTemplate.opsForList().rightPushAll(key, (List) object); + } else if (object instanceof Set) { + redisTemplate.opsForSet().add(key, ((Set) object).toArray()); + } else { + redisTemplate.opsForValue().set(key, toJson(object)); + } + expire(key, time); + } + + /** + * Object转成JSON数据 + */ + private String toJson(Object object) { + if (object instanceof Integer || object instanceof Long || object instanceof Float || + object instanceof Double || object instanceof Boolean || object instanceof String) { + return String.valueOf(object); + } + return JsonUtil.getObjectToString(object); + } + + /** + * 修改key + * + * @param oldKey 旧的key + * @param newKey 新的key + */ + public void rename(String oldKey, String newKey) { + redisTemplate.rename(oldKey, newKey); + } + + /** + * 返回key存储的类型 + * + * @param key + */ + public String getType(String key) { + return redisTemplate.type(key).code(); + } + + // ============================String============================= + + /** + * 获取redis的String值 + * + * @param key + * @return + */ + public Object getString(String key) { + return redisTemplate.opsForValue().get(key); + } + + // ============================Map============================= + + /** + * 判断hash表中是否有对应的value + * + * @param hashId + * @param key + * @return + */ + public boolean hasKey(String hashId, String key) { + return redisTemplate.opsForHash().hasKey(hashId, key); + } + + /** + * 获取hashKey对应的所有键 + * + * @param hashId 键 + */ + public List getHashKeys(String hashId) { + List list = new ArrayList<>(); + Map map = this.getMap(hashId); + for (Object object : map.keySet()) { + if (object instanceof String) { + list.add(String.valueOf(object)); + } + } + return list; + } + + /** + * 获取hashKey对应的所有值 + * + * @param hashId 键 + */ + public List getHashValues(String hashId) { + List list = new ArrayList<>(); + Map map = this.getMap(hashId); + for (Object object : map.keySet()) { + if (map.get(object) instanceof String) { + list.add(String.valueOf(map.get(object))); + } + } + return list; + } + + /** + * 查询具体map的值 + * + * @param hashId + * @param key + * @return + */ + public String getHashValues(String hashId, String key) { + Object object = redisTemplate.opsForHash().get(hashId, key); + if (object != null) { + return String.valueOf(object); + } else { + return null; + } + } + + /** + * 删除指定map的key + * + * @param key + */ + public void removeHash(String hashId, String key) { + if (hasKey(hashId, key)) { + redisTemplate.opsForHash().delete(hashId, key); + } + } + + /** + * 获取所有的map缓存 + * + * @param key + * @return + */ + public Map getMap(String key) { + return (Map) redisTemplate.opsForHash().entries(key); + } + + /** + * 插入map的值 + * + * @param hashId 主键id + * @param key map的key + * @param value map的值 + */ + public void insertHash(String hashId, String key, String value) { + redisTemplate.opsForHash().put(hashId, key, value); + } + + // ============================set============================= + + /** + * 根据key获取Set中的所有值 + * + * @param key 键 + * @return + */ + public Set getSet(String key) { + try { + return redisTemplate.opsForSet().members(key); + } catch (Exception e) { + log.error(key, e); + return null; + } + } + + /** + * 获取set缓存的长度 + * + * @param key 键 + * @return + */ + public long getSetSize(String key) { + try { + return redisTemplate.opsForSet().size(key); + } catch (Exception e) { + log.error(key, e); + return 0; + } + } + + // ===============================list================================= + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @param start 开始 0 是第一个元素 + * @param end 结束 -1代表所有值 + * @return + * @取出来的元素 总数 end-start+1 + */ + public List get(String key, long start, long end) { + try { + return redisTemplate.opsForList().range(key, start, end); + } catch (Exception e) { + log.error(key, e); + return null; + } + } + + /** + * 获取list缓存的长度 + * + * @param key 键 + * @return + */ + public long getListSize(String key) { + try { + return redisTemplate.opsForList().size(key); + } catch (Exception e) { + log.error(key, e); + return 0; + } + } + + /** + * 通过索引 获取list中的值 + * + * @param key 键 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 + * @return + */ + public Object getIndex(String key, long index) { + try { + return redisTemplate.opsForList().index(key, index); + } catch (Exception e) { + log.error(key, e); + return null; + } + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-scheduletask/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-scheduletask/pom.xml new file mode 100644 index 0000000..0202528 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-scheduletask/pom.xml @@ -0,0 +1,35 @@ + + + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-scheduletask + + + + com.yunzhupaas + yunzhupaas-common-core + + + com.yunzhupaas + yunzhupaas-scheduletask-client + + + com.yunzhupaas + yunzhupaas-scheduletask-model + + + com.yunzhupaas + xxl-job-core + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-scheduletask/src/main/java/com/yunzhupaas/scheduletask/rest/RestScheduleTaskUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-scheduletask/src/main/java/com/yunzhupaas/scheduletask/rest/RestScheduleTaskUtil.java new file mode 100644 index 0000000..9acf82b --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-scheduletask/src/main/java/com/yunzhupaas/scheduletask/rest/RestScheduleTaskUtil.java @@ -0,0 +1,182 @@ +package com.yunzhupaas.scheduletask.rest; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import com.yunzhupaas.base.Pagination; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.base.vo.PaginationVO; +import com.yunzhupaas.scheduletask.config.RegisterAddressConfig; +import com.yunzhupaas.scheduletask.entity.*; +import com.yunzhupaas.scheduletask.model.*; +import com.yunzhupaas.util.JsonUtil; +import com.yunzhupaas.util.context.SpringContext; +import com.yunzhupaas.util.wxutil.HttpUtil; +import lombok.extern.slf4j.Slf4j; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +public class RestScheduleTaskUtil { + + private static RegisterAddressConfig registerAddressConfig; + + static { + RegisterAddressConfig bean = SpringContext.getBean(RegisterAddressConfig.class); + if (bean == null) { + log.error("RegisterAddressConfig Bean未加载成功"); + } + registerAddressConfig = bean; + } + + /** + * 获取执行器列表 + * + * @return + */ + public static List getHandlerList() { + String handlerList = cn.hutool.http.HttpUtil.get(registerAddressConfig.getHandle_query_address()); + if (handlerList == null) { + return new ArrayList<>(); + } + return JsonUtil.getJsonToList(handlerList, HandlerNameEntity.class); + } + + /** + * 通过任务id获取日志列表 + * + * @param id 任务id + * @param userInfo + * @param taskPage 分页参数 + * @return + */ + public static JSONObject getLogList(String id, UserInfo userInfo, TaskPage taskPage) { + String param = taskPage.getRunResult() == null ? "&runResult=" + : "&runResult=" + taskPage.getRunResult().toString(); + String timeSelect = ""; + if (ObjectUtil.isNotNull(taskPage.getStartTime()) || ObjectUtil.isNotNull(taskPage.getEndTime())) { + timeSelect = "&startTime=" + taskPage.getStartTime() + + "&endTime=" + taskPage.getEndTime(); + } + JSONObject get = HttpUtil.httpRequest(registerAddressConfig.getLog_query_address() + "/" + id + + "?currentPage=" + taskPage.getCurrentPage() + + "&pageSize=" + taskPage.getPageSize() + + "&sort=" + taskPage.getSort() + + "&sidx=" + taskPage.getSidx() + param + timeSelect, + "POST", JsonUtil.getObjectToString(userInfo)); + JSONObject jsonObject = (JSONObject) get.get("data"); + List data = JsonUtil.getJsonToList(jsonObject.get("list"), TaskLogVO.class); + PaginationVO page = JsonUtil.getJsonToBean(jsonObject.get("pagination"), PaginationVO.class); + jsonObject.put("list", data); + jsonObject.put("pagination", page); + get.put("data", jsonObject); + return get; + } + + /** + * 获取分页数据 + * + * @param pagination 分页参数 + * @return + */ + public static JSONObject getList(Pagination pagination, UserInfo userInfo) { + JSONObject get = null; + try { + get = HttpUtil.httpRequest(registerAddressConfig.getTask_list_address() + + "?currentPage=" + pagination.getCurrentPage() + + "&pageSize=" + pagination.getPageSize() + + "&keyword=" + URLEncoder.encode(pagination.getKeyword(), "utf-8"), + "POST", JsonUtil.getObjectToString(userInfo)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + JSONObject jsonObject = (JSONObject) get.get("data"); + List data = JsonUtil.getJsonToList(jsonObject.get("list"), TaskVO.class); + PaginationVO page = JsonUtil.getJsonToBean(jsonObject.get("pagination"), PaginationVO.class); + jsonObject.put("list", data); + jsonObject.put("pagination", page); + get.put("data", jsonObject); + return get; + } + + /** + * 通过任务id获取任务详情 + * + * @param id 任务id + * @return + */ + public static TimeTaskEntity getInfo(String id, UserInfo userInfo) { + JSONObject get = HttpUtil.httpRequest(registerAddressConfig.getTask_info_address() + "?taskId=" + id, + "POST", JsonUtil.getObjectToString(userInfo)); + return JsonUtil.getJsonToBean(get, TimeTaskEntity.class); + } + + /** + * 保存任务调度 + * + * @param taskCrForm + * @return + */ + public static JSONObject create(TaskCrForm taskCrForm) { + JSONObject get = HttpUtil.httpRequest(registerAddressConfig.getTask_save_address(), + "POST", JsonUtil.getObjectToString(taskCrForm)); + return get; + } + + /** + * 日程任务调度 + * + * @param taskCrForm + * @return + */ + public static JSONObject schedule(TaskCrForm taskCrForm) { + JSONObject get = HttpUtil.httpRequest(registerAddressConfig.getTask_save_address() + "/schedule", + "POST", JsonUtil.getObjectToString(taskCrForm)); + return get; + } + + /** + * 修改任务调度 + * + * @param id + * @param taskUpForm + * @return + */ + public static JSONObject update(String id, TaskUpForm taskUpForm) { + JSONObject get = HttpUtil.httpRequest(registerAddressConfig.getTask_update_address() + "/" + id, + "PUT", JsonUtil.getObjectToString(taskUpForm)); + return get; + } + + /** + * 删除任务调度 + * + * @param id + * @return + */ + public static JSONObject delete(String id, UserInfo userInfo) { + JSONObject get = HttpUtil.httpRequest(registerAddressConfig.getTask_remove_address() + "/" + id, + "POST", JsonUtil.getObjectToString(userInfo)); + return get; + } + + /** + * 启动任务调度 + * + * @param updateTaskModel + * @return + */ + public static JSONObject updateTask(UpdateTaskModel updateTaskModel) { + JSONObject get = HttpUtil.httpRequest(registerAddressConfig.getTask_startOrRemove_address(), + "POST", JsonUtil.getObjectToString(updateTaskModel)); + return get; + } + + public static XxlJobInfo getInfoByTaskId(String taskId) { + JSONObject get = HttpUtil.httpRequest(registerAddressConfig.getJob_info_address() + "?taskId=" + taskId, + "GET", null); + return JsonUtil.getJsonToBean(get, XxlJobInfo.class); + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-security/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-security/pom.xml new file mode 100644 index 0000000..f0665bd --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-security/pom.xml @@ -0,0 +1,27 @@ + + + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-security + + + + com.yunzhupaas + yunzhupaas-common-auth + + + com.yunzhupaas + yunzhupaas-common-database + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/config/SecurityConfiguration.java b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/config/SecurityConfiguration.java new file mode 100644 index 0000000..fa7826d --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/config/SecurityConfiguration.java @@ -0,0 +1,150 @@ +package com.yunzhupaas.config; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.fun.strategy.SaCheckElementAnnotationFunction; +import cn.dev33.satoken.interceptor.SaInterceptor; +import cn.dev33.satoken.same.SaSameUtil; +import cn.dev33.satoken.strategy.SaStrategy; +import com.yunzhupaas.annotation.SaCheckSame; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.consts.AuthConsts; +import com.yunzhupaas.filter.ClearThreadContextFilter; +import com.yunzhupaas.filter.RequestWrapperFilter; +import com.yunzhupaas.filter.SecurityFilter; +import com.yunzhupaas.handler.IRestHandler; +import com.yunzhupaas.encrypt.EncryptRestInterceptor; +import com.yunzhupaas.properties.SecurityProperties; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.UserProvider; +import com.yunzhupaas.util.context.SpringContext; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import jakarta.servlet.*; +import java.util.List; +import java.util.function.BiFunction; + +/** + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +@Slf4j +@Configuration +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) +public class SecurityConfiguration implements WebMvcConfigurer { + + + @Autowired + private SecurityProperties securityProperties; + + /** + * 注册sa-token的拦截器 + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + initSaInterfaceAuth(registry); + initEncryptRestInterceptor(registry); + } + + /** + * 请求封装过滤器 + */ + @Bean("myRequestWrapperFilter") + @ConditionalOnMissingBean(name = "myRequestWrapperFilter") + public Filter getRequestWrapperFilter(List handlers){ + return new RequestWrapperFilter(handlers, securityProperties); + } + + /** + * 线程变量清除过滤器 + */ + @Bean("myClearThreadContextFilter") + @ConditionalOnMissingBean(name = "myClearThreadContextFilter") + public Filter getClearThreadContextFilter(){ + return new ClearThreadContextFilter(); + } + + /** + * 来源验证、用户、租户设置过滤器 + */ + @Bean("mySecurityFilter") + @ConditionalOnMissingBean(name = "mySecurityFilter") + public Filter getSecurityFilter(SecurityProperties securityProperties, ConfigValueUtil configValueUtil){ + return new SecurityFilter(securityProperties, configValueUtil).addInclude("/**"); + } + /** + * 传输加密 + */ + @Bean("myEncryptRestInterceptor") + @ConditionalOnMissingBean(name = "myEncryptRestInterceptor") + @ConditionalOnProperty(prefix = "security", name = "enable-rest-encrypt", havingValue = "true") + public HandlerInterceptor getEncryptRestInterceptor(){ + return new EncryptRestInterceptor(); + } + + protected void initEncryptRestInterceptor(InterceptorRegistry registry){ + if(securityProperties.isEnableRestEncrypt()){ + registry.addInterceptor(SpringContext.getBean("myEncryptRestInterceptor")); + } + } + + protected void initSaInterfaceAuth(InterceptorRegistry registry){ + if(securityProperties.isEnablePreAuth()) { + // 旧注解校验方法 + SaCheckElementAnnotationFunction oldCheckElementAnnotation = SaStrategy.instance.checkElementAnnotation; + SaStrategy.instance.checkElementAnnotation = (element) -> { + // 添加内部请求校验 + SaCheckSame checkRole = (SaCheckSame) SaStrategy.instance.getAnnotation.apply(element, SaCheckSame.class); + if(checkRole != null){ + SaSameUtil.checkToken(SaHolder.getRequest().getHeader(AuthConsts.INNER_TOKEN_KEY)); + } + // 调用旧注解校验 + oldCheckElementAnnotation.accept(element); + }; + // 开启接口请求权限控制 + registry.addInterceptor(new SaInterceptor((handler) -> { + + }).isAnnotation(securityProperties.isEnablePreAuth())).addPathPatterns("/**"); + } + //接口鉴权忽略管理员、内部请求 + BiFunction, String, Boolean> oldCheckFunc = SaStrategy.instance.hasElement; + SaStrategy.instance.hasElement = (list, element) -> { + //启用之后才验证 + if (securityProperties.isEnablePreAuth()) { + UserInfo userInfo = UserProvider.getUser(); + //未获取到用户信息返回false + if (StringUtil.isEmpty(userInfo.getUserId())) { + return false; + } + //管理员返回true + if (userInfo.getIsAdministrator()) { + return true; + } + boolean result = oldCheckFunc.apply(list, element); + //如果鉴权失败, 检测是否来自内部请求 + if (!result) { + String innerToken = SaHolder.getRequest().getHeader(AuthConsts.INNER_TOKEN_KEY); + //来自内部请求(非网关) 无需鉴权 + if (UserProvider.isValidInnerToken(innerToken)) { + result = true; + } + } + return result; + } + return true; + }; + } + + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/encrypt/EmptyEncryptRestRequestHandler.java b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/encrypt/EmptyEncryptRestRequestHandler.java new file mode 100644 index 0000000..ffa9863 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/encrypt/EmptyEncryptRestRequestHandler.java @@ -0,0 +1,27 @@ +package com.yunzhupaas.encrypt; + +import com.yunzhupaas.handler.IRestHandler; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +@Slf4j +@Order(0) +@Component +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) +@ConditionalOnProperty(prefix = "security", name = "enable-rest-encrypt", havingValue = "true") +public class EmptyEncryptRestRequestHandler implements IRestHandler { + + @Override + public boolean supportParameter() { + return true; + } + + @Override + public boolean supportBodyJson() { + return true; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/encrypt/EncryptResponseAdvice.java b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/encrypt/EncryptResponseAdvice.java new file mode 100644 index 0000000..b140e00 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/encrypt/EncryptResponseAdvice.java @@ -0,0 +1,43 @@ +package com.yunzhupaas.encrypt; + +import cn.hutool.core.util.HexUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yunzhupaas.annotation.EncryptApi; +import com.yunzhupaas.properties.SecurityProperties; +import com.yunzhupaas.util.DesUtil; +import org.springframework.core.MethodParameter; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; + +@ControllerAdvice +public class EncryptResponseAdvice implements ResponseBodyAdvice { + + private ObjectMapper objectMapper; + + public EncryptResponseAdvice(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + @Override + public boolean supports(MethodParameter returnType, Class> converterType) { + EncryptApi methodAnnotation = returnType.getMethodAnnotation(EncryptApi.class); + return methodAnnotation != null && methodAnnotation.encryptResponse(); + } + + + @Override + public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { + try { + byte[] bytes = objectMapper.writeValueAsBytes(body); + return HexUtil.encodeHexStr(DesUtil.aesOrDecode(bytes, true, true, SecurityProperties.getInstance().getSecurityKey())); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/encrypt/EncryptRestInterceptor.java b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/encrypt/EncryptRestInterceptor.java new file mode 100644 index 0000000..99c5b54 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/encrypt/EncryptRestInterceptor.java @@ -0,0 +1,154 @@ +package com.yunzhupaas.encrypt; + +import cn.hutool.core.net.url.UrlQuery; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import com.yunzhupaas.annotation.EncryptApi; +import com.yunzhupaas.constant.GlobalConst; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.exception.EncryptFailException; +import com.yunzhupaas.util.DesUtil; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.wrapper.MyRequestWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; +import org.springframework.util.StringUtils; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.AsyncHandlerInterceptor; + +import java.net.URLDecoder; +import java.util.*; + +/** + * 接口传输加密 + * 支持请求类型: + * application/json + * application/x-www-form-urlencoded + */ +@Slf4j +public class EncryptRestInterceptor implements AsyncHandlerInterceptor { + + private static final String ENCRYPT_KEY = "encryptData"; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + try { + if (handler instanceof HandlerMethod && request instanceof MyRequestWrapper) { + HandlerMethod method = (HandlerMethod) handler; + EncryptApi methodAnnotation = method.getMethodAnnotation(EncryptApi.class); + if (methodAnnotation != null && methodAnnotation.encryptRequest()) { + MyRequestWrapper myRequest = (MyRequestWrapper) request; + // 需要对数据进行加密解密 + // application/json + // application/x-www-form-urlencoded + String contentType = request.getContentType(); + if (contentType != null) { + String requestBody = null; + boolean canEncrypt = false; + if ((StringUtils.substringMatch(contentType, 0, + MediaType.APPLICATION_FORM_URLENCODED_VALUE)) + || "get".equalsIgnoreCase(request.getMethod())) { + // 1.application/x-www-form-urlencoded 支持参数在body或者在param + canEncrypt = true; + requestBody = convertFormToString(request); + if ("{}".equals(requestBody)) { + requestBody = URLDecoder.decode(myRequest.getRequestBody()); + Map uriToListToMap = new UrlQuery() + .parse(requestBody, GlobalConst.DEFAULT_CHARSET).getQueryMap(); + requestBody = JSONObject.toJSONString(uriToListToMap); + } + + } else if (StringUtils.substringMatch(contentType, 0, MediaType.APPLICATION_JSON_VALUE)) { + // application/json 支持加密参数在body + canEncrypt = true; + requestBody = myRequest.getRequestBody(); + } + if (canEncrypt) { + if (requestBody != null && !"{}".equals(requestBody)) { + JSONObject jsonBody = JSON.parseObject(requestBody); + JSON result = decodeApi(jsonBody); + if (result != null) { + myRequest.setRequestBody(result.toJSONString()); + if (result instanceof JSONObject) { + myRequest.addAllParameters((Map) result); + } + return true; + } + } + } + } + throw encryptFailException(); + } + } + } catch (EncryptFailException eex) { + throw eex; + } catch (Exception e) { + log.error("解密失败, 异常地址:{}", request.getServletPath(), e); + throw encryptFailException(); + } + return true; + } + + /** + * Pamams参数转JSON字符串 + * + * @param request + * @return + */ + private String convertFormToString(HttpServletRequest request) { + Map result = new HashMap<>(8); + Enumeration parameterNames = request.getParameterNames(); + while (parameterNames.hasMoreElements()) { + String name = parameterNames.nextElement(); + result.put(name, request.getParameter(name)); + } + try { + return JSON.toJSONString(result); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + /** + * 请求内容解密 + * + * @param body + * @return + */ + public JSON decodeApi(JSON body) { + try { + JSONObject jsonObject = (JSONObject) body; + String content = jsonObject.getOrDefault(ENCRYPT_KEY, "").toString(); + if (!StringUtil.isEmpty(content)) { + content = decryptData(content); + return (JSON) JSON.parse(content); + } + } catch (Exception e) { + log.error("解密失败, 文本: {}", body, e); + } + return null; + } + + /** + * 文本解密 + * + * @param data + * @return + */ + protected String decryptData(String data) { + if (StringUtil.isEmpty(data)) { + return data; + } + if (Objects.equals(data.charAt(0), '"') && Objects.equals(data.charAt(data.length() - 1), '"')) { + data = data.substring(1, data.length() - 1); + } + return DesUtil.aesOrDecode(data, false, true); + } + + private EncryptFailException encryptFailException() { + throw new EncryptFailException(MsgCode.FA051.get()); + } +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/filter/ClearThreadContextFilter.java b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/filter/ClearThreadContextFilter.java new file mode 100644 index 0000000..103dbaf --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/filter/ClearThreadContextFilter.java @@ -0,0 +1,41 @@ +package com.yunzhupaas.filter; + +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; +import com.yunzhupaas.database.util.IgnoreLogicDeleteHolder; +import com.yunzhupaas.database.util.NotTenantPluginHolder; +import com.yunzhupaas.database.util.TenantDataSourceUtil; +import com.yunzhupaas.util.TenantProvider; +import com.yunzhupaas.util.UserProvider; +import org.springframework.core.annotation.Order; +import org.springframework.web.filter.OncePerRequestFilter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 线程缓存清理 + */ +@Order(-99) +public class ClearThreadContextFilter extends OncePerRequestFilter { + + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + try { + filterChain.doFilter(request, response); + }finally { + //清除线程缓存 + UserProvider.clearLocalUser(); + TenantProvider.clearBaseSystemIfo(); + TenantDataSourceUtil.clearLocalTenantInfo(); + DynamicDataSourceContextHolder.clear(); + NotTenantPluginHolder.clearNotSwitchFlag(); + IgnoreLogicDeleteHolder.clear(); + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/filter/RequestWrapperFilter.java b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/filter/RequestWrapperFilter.java new file mode 100644 index 0000000..c8a82e2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/filter/RequestWrapperFilter.java @@ -0,0 +1,48 @@ +package com.yunzhupaas.filter; + +import cn.dev33.satoken.context.SaHolder; +import com.yunzhupaas.handler.IRestHandler; +import com.yunzhupaas.properties.SecurityProperties; +import com.yunzhupaas.util.PathUtil; +import com.yunzhupaas.wrapper.MyRequestWrapper; +import com.yunzhupaas.wrapper.MyResponseWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; +import org.springframework.web.filter.OncePerRequestFilter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + +/** + * 请求内容 + */ +@Slf4j +@Order(-97) +public class RequestWrapperFilter extends OncePerRequestFilter { + + private List handlers; + private SecurityProperties securityProperties; + + public RequestWrapperFilter(List handlers, SecurityProperties securityProperties) { + this.handlers = handlers; + this.securityProperties = securityProperties; + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + if(handlers.isEmpty()){ + filterChain.doFilter(request, response); + } else { + MyRequestWrapper myRequest = new MyRequestWrapper(request, handlers); + MyResponseWrapper wrapResponse = new MyResponseWrapper(response, handlers); + filterChain.doFilter(myRequest, wrapResponse); + wrapResponse.doFinal(); + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/filter/SecurityFilter.java b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/filter/SecurityFilter.java new file mode 100644 index 0000000..86f85b2 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/filter/SecurityFilter.java @@ -0,0 +1,83 @@ +package com.yunzhupaas.filter; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.filter.SaServletFilter; +import cn.dev33.satoken.router.SaRouter; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.config.ConfigValueUtil; +import com.yunzhupaas.constant.MsgCode; +import com.yunzhupaas.consts.AuthConsts; +import com.yunzhupaas.database.util.TenantDataSourceUtil; +import com.yunzhupaas.properties.SecurityProperties; +import com.yunzhupaas.util.StringUtil; +import com.yunzhupaas.util.UserProvider; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.core.annotation.Order; + +import jakarta.annotation.PostConstruct; +import java.util.function.Predicate; + +@Slf4j +@Order(-98) +public class SecurityFilter extends SaServletFilter { + + + private SecurityProperties securityProperties; + + private ConfigValueUtil configValueUtil; + + public SecurityFilter(SecurityProperties securityProperties, ConfigValueUtil configValueUtil) { + this.securityProperties = securityProperties; + this.configValueUtil = configValueUtil; + setAuth(o -> { + initAuthenticationInfo(); + }); + setBeforeAuth(o -> { + checkRequestOrigin.test(null); + }); + } + + /** + * 请求来源验证 + */ + private Predicate checkRequestOrigin = t -> true; + + + protected void initAuthenticationInfo(){ + //执行Token续期, 存用户信息至本地缓存后续无需重新获取 + UserProvider.renewTimeout(); + //设置租户信息 + if(configValueUtil.isMultiTenancy()) { + UserInfo userInfo = UserProvider.getUser(); + if (StringUtil.isNotEmpty(userInfo.getTenantId())) { + TenantDataSourceUtil.switchTenant(userInfo.getTenantId()); + } + } + } + + /** + * 微服务才验证请求来源 + */ + @ConditionalOnClass(name = "org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient") + @PostConstruct + public void onCloudCheckRequestOrigin(){ + checkRequestOrigin = t -> { + //验证请求来源, 网关, Feign + if(securityProperties.isEnableInnerAuth()) { + SaRouter.match("/favicon.ico").stop(); + SaRouter.match("/**").match(r->{ + String innerToken = SaHolder.getRequest().getHeader(AuthConsts.INNER_TOKEN_KEY); + String innerGatewayToken = SaHolder.getRequest().getHeader(AuthConsts.INNER_GATEWAY_TOKEN_KEY); + if(!UserProvider.isValidInnerToken(innerGatewayToken) && !UserProvider.isValidInnerToken(innerToken)){ + log.error("非法请求: {}, {}", SaHolder.getRequest().getRequestPath(), innerToken); + return true; + } + return false; + }).back(MsgCode.FA034.get()); + } + return true; + }; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/handler/IRestHandler.java b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/handler/IRestHandler.java new file mode 100644 index 0000000..cea83c7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/handler/IRestHandler.java @@ -0,0 +1,59 @@ +package com.yunzhupaas.handler; + +import com.alibaba.fastjson.JSON; + +import java.util.Map; + +public interface IRestHandler { + + /** + * 是否处理Header + */ + default boolean supportHeader(){ + return false; + } + + /** + * 是否处理Form表单数据 + */ + default boolean supportParameter(){ + return false; + } + + /** + * 是否处理Body JSON + */ + default boolean supportBodyJson(){ + return false; + } + + /** + * 是否处理返回结果 + */ + default boolean supportResponse(){ + return false; + } + + /** + * 初始化Body JSON + */ + default JSON initBodyJson(JSON jsonContent){ + return jsonContent; + } + + /** + * 初始化Form表单数据 + */ + default Map initParameter(Map parameter){ + return parameter; + } + + /** + * 处理返回结果 + */ + default String processResponse(String data) { + return data; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/permissions/PermissionInterfaceImpl.java b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/permissions/PermissionInterfaceImpl.java new file mode 100644 index 0000000..4c3c56e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/permissions/PermissionInterfaceImpl.java @@ -0,0 +1,131 @@ +package com.yunzhupaas.permissions; + +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.stp.StpInterface; +import cn.dev33.satoken.stp.StpUtil; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.model.BaseSystemInfo; +import com.yunzhupaas.properties.SecurityProperties; +import com.yunzhupaas.util.TenantProvider; +import com.yunzhupaas.util.UserProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; + +import static com.yunzhupaas.util.Constants.ADMIN_KEY; + + +/** + * 权限认证接口实现 + * + * @author 云筑产品开发平台组 + * @copyright 深圳市乐程软件有限公司 + */ +@Component +public class PermissionInterfaceImpl implements StpInterface { + + public static final String PERMISSION_KEY = "user_permission"; + public static final String ROLE_KEY = "user_roles"; + public static final String COLUMN_KEY = "user_columns"; + public static final String FORM_KEY = "user_forms"; + + @Autowired + private SecurityProperties securityProperties; + + @Override + public List getPermissionList(Object loginId, String loginType) { + if (!securityProperties.isEnablePreAuth()) { + return Collections.emptyList(); + } + UserInfo userInfo = UserProvider.getUser(); + String account = userInfo.getIsAdministrator() ? ADMIN_KEY : userInfo.getUserId(); + account = UserProvider.splicingLoginId(account); + SaSession saSession = StpUtil.getSessionByLoginId(account, false); + if (saSession == null) { + return Collections.emptyList(); + } + return saSession.get(PERMISSION_KEY, Collections.emptyList()); + } + + @Override + public List getRoleList(Object loginId, String loginType) { + if (!securityProperties.isEnablePreAuth()) { + return Collections.emptyList(); + } + UserInfo userInfo = UserProvider.getUser(); + String account = userInfo.getIsAdministrator() ? ADMIN_KEY : userInfo.getUserId(); + account = UserProvider.splicingLoginId(account); + SaSession saSession = StpUtil.getSessionByLoginId(account, false); + if (saSession == null) { + return Collections.emptyList(); + } + return saSession.get(ROLE_KEY, Collections.emptyList()); + } + + public static Map getColumnMap() { + UserInfo userInfo = UserProvider.getUser(); + String account = userInfo.getIsAdministrator() ? ADMIN_KEY : userInfo.getUserId(); + account = UserProvider.splicingLoginId(account); + SaSession saSession = StpUtil.getSessionByLoginId(account, false); + if (saSession == null) { + return Collections.emptyMap(); + } + return saSession.get(COLUMN_KEY, Collections.emptyMap()); + } + + public static Map getFormMap() { + UserInfo userInfo = UserProvider.getUser(); + String account = userInfo.getIsAdministrator() ? ADMIN_KEY : userInfo.getUserId(); + account = UserProvider.splicingLoginId(account); + SaSession saSession = StpUtil.getSessionByLoginId(account, false); + if (saSession == null) { + return Collections.emptyMap(); + } + return saSession.get(FORM_KEY, Collections.emptyMap()); + } + + + public static void setAuthorityList(String userAccount, Set authority, BaseSystemInfo baseSystemInfo) { + userAccount = UserProvider.splicingLoginId(userAccount); + try { + TenantProvider.setBaseSystemInfo(baseSystemInfo); + StpUtil.getSessionByLoginId(userAccount, true).set(PERMISSION_KEY, new ArrayList<>(authority)); + } finally { + TenantProvider.clearBaseSystemIfo(); + } + } + + public static void setRoleList(String userAccount, Set role, BaseSystemInfo baseSystemInfo) { + userAccount = UserProvider.splicingLoginId(userAccount); + try { + TenantProvider.setBaseSystemInfo(baseSystemInfo); + StpUtil.getSessionByLoginId(userAccount, true).set(ROLE_KEY, new ArrayList<>(role)); + } finally { + TenantProvider.clearBaseSystemIfo(); + } + } + + + public static void setColumnMap(String userAccount, Map>> columnList, BaseSystemInfo baseSystemInfo) { + userAccount = UserProvider.splicingLoginId(userAccount); + try { + TenantProvider.setBaseSystemInfo(baseSystemInfo); + StpUtil.getSessionByLoginId(userAccount, true).set(COLUMN_KEY, columnList); + } finally { + TenantProvider.clearBaseSystemIfo(); + } + } + + public static void setFormMap(String userAccount, Map>> formList, BaseSystemInfo baseSystemInfo) { + userAccount = UserProvider.splicingLoginId(userAccount); + try { + TenantProvider.setBaseSystemInfo(baseSystemInfo); + StpUtil.getSessionByLoginId(userAccount, true).set(FORM_KEY, formList); + } finally { + TenantProvider.clearBaseSystemIfo(); + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/wrapper/MyRequestWrapper.java b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/wrapper/MyRequestWrapper.java new file mode 100644 index 0000000..c38f420 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/wrapper/MyRequestWrapper.java @@ -0,0 +1,240 @@ +package com.yunzhupaas.wrapper; + +import cn.dev33.satoken.context.SaHolder; +import cn.hutool.core.net.url.UrlQuery; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.yunzhupaas.constant.GlobalConst; +import com.yunzhupaas.handler.IRestHandler; +import com.yunzhupaas.util.StringUtil; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; +import org.springframework.util.StreamUtils; +import org.springframework.util.StringUtils; + +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Request封装 + * 处理类型: + * application/json + * application/x-www-form-urlencoded + */ +@Slf4j +public class MyRequestWrapper extends HttpServletRequestWrapper { + + protected Map paramHashValues; + @Getter + @Setter + protected String requestBody = null; + protected HttpServletRequest req; + + private final List handlers; + + private final String[] EMPTY_ARRAY = new String[0]; + + /** + * 是否需要处理Header, Body, Form + */ + private boolean supportHeader, supportBody, supportParameter; + + public MyRequestWrapper(HttpServletRequest request, List handlers) throws IOException { + super(request); + this.req = request; + this.handlers = handlers == null ? Collections.emptyList() : handlers; + if(!handlers.isEmpty()){ + try { + if (isJsonBodyRequest()) { + processBody(); + } else if (isParameterRequest()) { + processParameter(); + processFormBody(); + } + } catch (Exception e){ + log.error("请求解析失败:{}", SaHolder.getRequest().getRequestPath()); + throw e; + } + } + } + + private void processBody() throws IOException { + List bodyHandlers = this.handlers.stream().filter(IRestHandler::supportBodyJson).collect(Collectors.toList()); + if (!bodyHandlers.isEmpty()) { + this.requestBody = convertInputStreamToString(req.getInputStream()); + if (StringUtil.isNotEmpty(this.requestBody)) { + JSON jsonData = (JSON) JSON.parse(this.requestBody); + for (IRestHandler bodyHandler : bodyHandlers) { + jsonData = bodyHandler.initBodyJson(jsonData); + } + requestBody = jsonData.toJSONString(); + supportBody = true; + } + } + } + + private void processParameter(){ + List parameterHandlers = this.handlers.stream().filter(IRestHandler::supportParameter).collect(Collectors.toList()); + if (!parameterHandlers.isEmpty()) { + paramHashValues = new HashMap<>(); + paramHashValues.putAll(req.getParameterMap()); + /* + //解除锁定直接添加 + if(paramHashValues instanceof ParameterMap){ + ((ParameterMap) paramHashValues).setLocked(false); + } + */ + parameterHandlers.forEach(h -> paramHashValues = h.initParameter(paramHashValues)); + supportParameter = true; + } + } + private void processFormBody() throws IOException { + List bodyHandlers = this.handlers.stream().filter(IRestHandler::supportBodyJson).collect(Collectors.toList()); + if (!bodyHandlers.isEmpty()) { + this.requestBody = convertInputStreamToString(req.getInputStream()); + if(StringUtil.isNotEmpty(this.requestBody)){ + Map uriToListToMap = new UrlQuery().parse(this.requestBody, GlobalConst.DEFAULT_CHARSET).getQueryMap(); + requestBody = JSONObject.toJSONString(uriToListToMap); + } + if (StringUtil.isNotEmpty(this.requestBody)) { + JSON jsonData = (JSON) JSON.parse(this.requestBody); + for (IRestHandler bodyHandler : bodyHandlers) { + jsonData = bodyHandler.initBodyJson(jsonData); + } + Map formJson = (JSONObject) jsonData; + UrlQuery urlQuery = new UrlQuery(); + for (Map.Entry entry : formJson.entrySet()) { + urlQuery.add(entry.getKey(), entry.getValue()); + } + requestBody = urlQuery.build(GlobalConst.DEFAULT_CHARSET); + supportBody = true; + } + } + } + + @Override + public BufferedReader getReader() throws IOException { + if(supportBody){ + return new BufferedReader(new StringReader(requestBody)); + }else{ + return super.getReader(); + } + } + + @Override + public ServletInputStream getInputStream() throws IOException { + if(supportBody){ + return new ServletInputStream() { + private InputStream in = new ByteArrayInputStream( + requestBody.getBytes(req.getCharacterEncoding())); + @Override + public int read() throws IOException { + return in.read(); + } + @Override + public boolean isFinished() { + return false; + } + @Override + public boolean isReady() { + return false; + } + @Override + public void setReadListener(ReadListener readListener) { + + } + }; + }else { + return super.getInputStream(); + } + } + + @Override + public Map getParameterMap() { + if(supportParameter){ + return this.paramHashValues; + }else { + return super.getParameterMap(); + } + } + + @Override + public String getParameter(String name) { + if(supportParameter){ + String[] parameter = this.paramHashValues.getOrDefault(name, EMPTY_ARRAY); + return parameter.length == 0 ? null: parameter[0]; + }else { + return super.getParameter(name); + } + } + + @Override + public String[] getParameterValues(String name) { + if(supportParameter){ + return this.paramHashValues.get(name); + }else { + return super.getParameterValues(name); + } + } + + @Override + public Enumeration getParameterNames() { + if(supportParameter){ + return Collections.enumeration(this.paramHashValues.keySet()); + }else { + return super.getParameterNames(); + } + } + + public void addAllParameters(Map otherParams) {// 增加多个参数 + for (Map.Entry entry : otherParams.entrySet()) { + addParameter(entry.getKey(), entry.getValue()); + } + } + + + public void addParameter(String name, Object value) {// 增加参数 + if (value != null && paramHashValues != null) { + if (value instanceof String[]) { + paramHashValues.put(name, (String[]) value); + } else if (value instanceof String) { + paramHashValues.put(name, new String[]{(String) value}); + } else { + paramHashValues.put(name, new String[]{String.valueOf(value)}); + } + } + } + + protected boolean isParameterRequest(){ + String contentType = this.req.getContentType(); + if(StringUtil.isNotEmpty(contentType)) { + if (StringUtils.substringMatch(contentType, 0, MediaType.APPLICATION_FORM_URLENCODED_VALUE)) { + return true; + } + } + return false; + } + + protected boolean isJsonBodyRequest(){ + String contentType = this.req.getContentType(); + if(StringUtil.isNotEmpty(contentType)) { + if (StringUtils.substringMatch(contentType, 0, MediaType.APPLICATION_JSON_VALUE)) { + return true; + } + } + return false; + } + + protected String convertInputStreamToString(InputStream inputStream) throws IOException { + return StreamUtils.copyToString(inputStream, GlobalConst.DEFAULT_CHARSET); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/wrapper/MyResponseWrapper.java b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/wrapper/MyResponseWrapper.java new file mode 100644 index 0000000..33eacd4 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-security/src/main/java/com/yunzhupaas/wrapper/MyResponseWrapper.java @@ -0,0 +1,159 @@ +package com.yunzhupaas.wrapper; + +import com.yunzhupaas.constant.GlobalConst; +import com.yunzhupaas.handler.IRestHandler; +import com.yunzhupaas.util.StringUtil; +import org.springframework.http.MediaType; +import org.springframework.util.StringUtils; + +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.WriteListener; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponseWrapper; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Response封装 + * 处理类型: + * application/json + */ +public class MyResponseWrapper extends HttpServletResponseWrapper { + private ByteArrayOutputStream buffer; + private ServletOutputStream out = null; + private PrintWriter writer = null; + + private List handlers; + private boolean supportResponse; + + public MyResponseWrapper(HttpServletResponse resp, List handlers) throws IOException { + super(resp); + this.handlers = handlers.stream().filter(IRestHandler::supportResponse).collect(Collectors.toList()); + supportResponse = !handlers.isEmpty(); + //返回处理器顺序翻转 + Collections.reverse(handlers); + if(supportResponse) { + buffer = new ByteArrayOutputStream(); + } + } + + @Override + public ServletOutputStream getOutputStream() throws IOException { + if(supportResponse) { + if (out == null) { + out = new WapperedOutputStream(buffer); + } + return out; + }else{ + return super.getOutputStream(); + } + } + + @Override + public PrintWriter getWriter() throws IOException { + if(supportResponse) { + if (writer == null) { + writer = new PrintWriter(new OutputStreamWriter(buffer, this.getCharacterEncoding())); + } + return writer; + }else{ + return super.getWriter(); + } + } + + @Override + public void flushBuffer() throws IOException { + if(supportResponse) { + if (out != null) { + out.flush(); + } + if (writer != null) { + writer.flush(); + } + }else{ + super.flushBuffer(); + } + } + + @Override + public void reset() { + if(supportResponse) { + buffer.reset(); + }else{ + super.reset(); + } + } + + public void doFinal() throws IOException{ + if(supportResponse) { + flushBuffer(); + if (buffer.size() > 0) { + byte[] byteArray = buffer.toByteArray(); + if (supportResponse && isJsonBodyRequest()) { + getResponse().setContentLength(-1); + getResponse().setCharacterEncoding(GlobalConst.DEFAULT_CHARSET_STR); + String data = new String(byteArray, GlobalConst.DEFAULT_CHARSET); + for (IRestHandler handler : handlers) { + data = handler.processResponse(data); + } + writeResponse(data); + return; + } + writeResponse(byteArray); + } + } + } + + private void writeResponse(String responseString) + throws IOException { + PrintWriter out = getResponse().getWriter(); + out.write(responseString); + out.flush(); + out.close(); + } + + private void writeResponse(byte[] responseData) throws IOException { + ServletOutputStream outputStream = getResponse().getOutputStream(); + outputStream.write(responseData); + outputStream.flush(); + outputStream.close(); + } + + private class WapperedOutputStream extends ServletOutputStream { + private ByteArrayOutputStream bos = null; + + public WapperedOutputStream(ByteArrayOutputStream stream) throws IOException { + bos = stream; + } + + @Override + public void write(int b) throws IOException { + bos.write(b); + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setWriteListener(WriteListener listener) { + + } + } + + + protected boolean isJsonBodyRequest(){ + String contentType = getResponse().getContentType(); + if(StringUtil.isNotEmpty(contentType)) { + if (StringUtils.substringMatch(contentType, 0, MediaType.APPLICATION_JSON_VALUE)) { + return true; + } + } + return false; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-selenium/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-selenium/pom.xml new file mode 100644 index 0000000..3be2885 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-selenium/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + com.yunzhupaas + yunzhupaas-boot-common + 5.2.0-RELEASE + ../pom.xml + + + yunzhupaas-common-selenium + + + + + + + + + org.springframework.boot + spring-boot-autoconfigure + + + org.springframework.boot + spring-boot-starter-logging + + + org.seleniumhq.selenium + selenium-java + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/SeleniumHelper.java b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/SeleniumHelper.java new file mode 100644 index 0000000..8cdee40 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/SeleniumHelper.java @@ -0,0 +1,34 @@ +package com.yunzhupaas.selenium; + +import com.yunzhupaas.selenium.consts.SeleniumConsts; +import com.yunzhupaas.selenium.driver.SeleniumBrowser; +import com.yunzhupaas.selenium.properties.SeleniumProperties; +import lombok.Getter; +import lombok.Setter; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +public class SeleniumHelper implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + @Getter + @Setter + private static SeleniumProperties seleniumProperties; + + + public static > T getBrowser() { + SeleniumBrowser seleniumBrowser = (SeleniumBrowser) applicationContext.getBean(SeleniumConsts.BROWSER_BEAN_PREFIX + seleniumProperties.getBrowserType()); + return (T) seleniumBrowser; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + SeleniumHelper.applicationContext = applicationContext; + SeleniumHelper.seleniumProperties =applicationContext.getBean(SeleniumProperties.class); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/autoconfiguration/SeleniumAutoConfiguration.java b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/autoconfiguration/SeleniumAutoConfiguration.java new file mode 100644 index 0000000..864ebb8 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/autoconfiguration/SeleniumAutoConfiguration.java @@ -0,0 +1,35 @@ +package com.yunzhupaas.selenium.autoconfiguration; + +import com.yunzhupaas.selenium.SeleniumHelper; +import com.yunzhupaas.selenium.consts.SeleniumConsts; +import com.yunzhupaas.selenium.driver.ChromeBrowser; +import com.yunzhupaas.selenium.properties.SeleniumProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.*; + +@Configuration(proxyBeanMethods = false) +@Import(SeleniumHelper.class) +@Slf4j +public class SeleniumAutoConfiguration { + + @Bean + @ConfigurationProperties(SeleniumConsts.SELENIUM) + public SeleniumProperties getSeleniumProperties() { + return new SeleniumProperties(); + } + + @Lazy + @ConditionalOnMissingBean(name = SeleniumConsts.BROWSER_BEAN_PREFIX + SeleniumConsts.BROWSER_TYPE_CHROME) + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + @Bean(value = SeleniumConsts.BROWSER_BEAN_PREFIX + SeleniumConsts.BROWSER_TYPE_CHROME, initMethod = "init", destroyMethod = "close") + public ChromeBrowser getChromeBrowser() { + if(log.isDebugEnabled()){ + log.debug(SeleniumConsts.MARKER, "Init New Chrome"); + } + return new ChromeBrowser(); + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/consts/SeleniumConsts.java b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/consts/SeleniumConsts.java new file mode 100644 index 0000000..8e23877 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/consts/SeleniumConsts.java @@ -0,0 +1,19 @@ +package com.yunzhupaas.selenium.consts; + +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +public class SeleniumConsts { + + private SeleniumConsts() { + } + + public static final String SELENIUM = "selenium"; + + public static final Marker MARKER = MarkerFactory.getMarker(SELENIUM); + + public static final String BROWSER_TYPE_CHROME = "chrome"; + + public static final String BROWSER_BEAN_PREFIX = "selenium_"; +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/driver/AbstractBrowser.java b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/driver/AbstractBrowser.java new file mode 100644 index 0000000..34583a6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/driver/AbstractBrowser.java @@ -0,0 +1,100 @@ +package com.yunzhupaas.selenium.driver; + +import com.yunzhupaas.selenium.SeleniumHelper; +import com.yunzhupaas.selenium.consts.SeleniumConsts; +import com.yunzhupaas.selenium.properties.SeleniumProperties; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.openqa.selenium.remote.AbstractDriverOptions; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.remote.service.DriverService; + +@Data +@Slf4j +public abstract class AbstractBrowser> implements SeleniumBrowser { + + protected D driverInstance; + protected S driverServiceInstance; + protected O driverOptionsInstance; + + + protected AbstractBrowser() { + this(null, null, null); + } + + protected AbstractBrowser(D driver, S driverService, O driverOptions) { + this.driverInstance = driver; + this.driverServiceInstance = driverService; + this.driverOptionsInstance = driverOptions; + if (this.driverInstance == null) { + if (this.driverServiceInstance == null && this.driverOptionsInstance == null) { + this.driverServiceInstance = buildDriverService(); + this.driverOptionsInstance = buildDriverOptions(); + } + if(log.isDebugEnabled()){ + log.debug(SeleniumConsts.MARKER, "创建浏览器, {}, {}", this.driverServiceInstance, this.driverOptionsInstance); + } + this.driverInstance = buildDriver(this.driverServiceInstance, this.driverOptionsInstance); + } + } + + protected static SeleniumProperties getProperties() { + return SeleniumHelper.getSeleniumProperties(); + } + + protected abstract O buildDriverOptions(); + + protected abstract S buildDriverService(); + + protected abstract D buildDriver(S driverService, O driverOptions); + + D buildDriver() { + return buildDriver(buildDriverService(), buildDriverOptions()); + } + + + @Override + public D getDriver() { + return this.driverInstance; + } + + @Override + public S getDriverService() { + return this.driverServiceInstance; + } + + @Override + public O getDriverOptions() { + return this.driverOptionsInstance; + } + + + /** + * 初始化调用 + */ + public void init() { + if(log.isDebugEnabled()){ + log.debug(SeleniumConsts.MARKER, "浏览器实例初始化方法调用"); + } + if(driverInstance != null) { + setScriptTimeout(getProperties().getScriptTimeout()); + setPageLoadTimeout(getProperties().getPageLoadTimeout()); + setImplicaitlyWaitTimeout(getProperties().getImplicaitlyWaitTimeout()); + } + } + + @Override + public void close() { + if(log.isDebugEnabled()){ + log.debug(SeleniumConsts.MARKER, "浏览器实例销毁化方法调用"); + } + if (driverInstance != null) { + try { + driverInstance.quit(); + } catch (Exception e) { + log.error(SeleniumConsts.MARKER, "关闭浏览器出错", e); + } + } + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/driver/ChromeBrowser.java b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/driver/ChromeBrowser.java new file mode 100644 index 0000000..b362b79 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/driver/ChromeBrowser.java @@ -0,0 +1,62 @@ +package com.yunzhupaas.selenium.driver; + +import lombok.extern.slf4j.Slf4j; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeDriverService; +import org.openqa.selenium.chrome.ChromeOptions; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import java.util.function.Supplier; + +@Slf4j +public class ChromeBrowser extends AbstractBrowser { + + public static Supplier defaultDriverOptionsSupplier = () -> { + System.setProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY, getProperties().getDriverPath()); + ChromeOptions options = new ChromeOptions(); + //设置浏览器参数 + options.addArguments("--headless"); + options.addArguments("--disable-gpu"); + options.addArguments("--no-sandbox"); + options.addArguments("lang=zh_CN.UTF-8"); + options.addArguments("--disable-dev-shm-usage"); + //指定浏览器分辨率 + options.addArguments("window-size=1920x1080"); + //浏览器文件 + if (StringUtils.hasText(getProperties().getBrowserPath())) { + options.setBinary(getProperties().getBrowserPath()); + } + return options; + }; + public static Supplier defaultDriverServiceSupplier = () -> null; + + + @Override + public ChromeOptions buildDriverOptions() { + return defaultDriverOptionsSupplier.get(); + } + + @Override + public ChromeDriverService buildDriverService() { + return defaultDriverServiceSupplier.get(); + } + + @Override + public ChromeDriver buildDriver(ChromeDriverService driverService, ChromeOptions driverOptions) { + Assert.notNull(System.getProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY), "未设置浏览器驱动路径"); + ChromeDriver driver; + if (driverService != null && driverOptions != null) { + driver = new ChromeDriver(driverService, driverOptions); + } else if (driverOptions != null) { + driver = new ChromeDriver(driverOptions); + } else if (driverService != null) { + driver = new ChromeDriver(driverService); + } else { + throw new IllegalArgumentException("service 或 options 不允许都为空"); + } + return driver; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/driver/SeleniumBrowser.java b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/driver/SeleniumBrowser.java new file mode 100644 index 0000000..6714b1c --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/driver/SeleniumBrowser.java @@ -0,0 +1,149 @@ +package com.yunzhupaas.selenium.driver; + +import com.yunzhupaas.selenium.SeleniumHelper; +import com.yunzhupaas.selenium.properties.SeleniumProperties; +import org.openqa.selenium.*; +import org.openqa.selenium.remote.AbstractDriverOptions; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.remote.service.DriverService; + +import java.time.Duration; +import java.util.List; +import java.util.Map; + +public interface SeleniumBrowser> { + + D getDriver(); + + S getDriverService(); + + O getDriverOptions(); + + /** + * 关闭驱动和浏览器 + */ + void close(); + + /** + * 设置页面加载超时时间 + */ + default void setPageLoadTimeout(Duration duration) { + getDriver().manage().timeouts().pageLoadTimeout(duration); + } + + /** + * 设置查找元素超时时间 + */ + default void setImplicaitlyWaitTimeout(Duration duration) { + getDriver().manage().timeouts().implicitlyWait(duration); + } + + /** + * 设置执行脚本超时时间 + */ + default void setScriptTimeout(Duration duration) { + getDriver().manage().timeouts().scriptTimeout(duration); + } + + /** + * 寻找元素, 若不存在抛出未找到元素异常 + * 如需判断元素是否存在可调用{@link #findElements} 进行判空处理, 为空获取默认超时配置 {@link SeleniumProperties#getImplicaitlyWaitTimeout()} + * + * @param locator 查找条件 + * @param findTimeout 最长等待时间 + */ + default WebElement findElement(By locator, Duration findTimeout) { + findTimeout = findTimeout == null ? SeleniumHelper.getSeleniumProperties().getImplicaitlyWaitTimeout() : findTimeout; + setImplicaitlyWaitTimeout(findTimeout); + return getDriver().findElement(locator); + } + + /** + * 寻找元素, 未找到元素返回空 + * + * @param locator 查找条件 + * @param findTimeout 最长等待时间, 为空获取默认超时配置 {@link SeleniumProperties#getImplicaitlyWaitTimeout()} + */ + default List findElements(By locator, Duration findTimeout) { + findTimeout = findTimeout == null ? SeleniumHelper.getSeleniumProperties().getImplicaitlyWaitTimeout() : findTimeout; + setImplicaitlyWaitTimeout(findTimeout); + return getDriver().findElements(locator); + } + + /** + * 加载页面 + * @param url 网页地址 + * @param loadTimeout 加载超时时间, 为空获取默认超时配置 {@link SeleniumProperties#getPageLoadTimeout()} + * @param newTab 新窗口打开链接 + */ + default void loadPage(String url, Duration loadTimeout, WindowType newTab) { + if (newTab != null) { + getDriver().switchTo().newWindow(newTab); + } + loadTimeout = loadTimeout == null ? SeleniumHelper.getSeleniumProperties().getPageLoadTimeout() : loadTimeout; + setPageLoadTimeout(loadTimeout); + getDriver().get(url); + } + + /** + * 执行JS脚本 + * @param script 脚本内容 + * @param scriptTimeout 脚本执行超时时间, 为空获取默认超时配置 {@link SeleniumProperties#getScriptTimeout()} + * @param args 脚本内容参数 + */ + default Object executeScript(String script, Duration scriptTimeout, Object... args){ + scriptTimeout = scriptTimeout == null ? SeleniumHelper.getSeleniumProperties().getScriptTimeout() : scriptTimeout; + setScriptTimeout(scriptTimeout); + return getDriver().executeScript(script, args); + } + + /** + * 获取最大的页面大小 + */ + default Dimension getDocumentSize() { + Map result = (Map) getDriver().executeScript("return {'w':Math.max(document.body.scrollWidth, document.body.offsetWidth, document.documentElement.clientWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth), 'h':Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight)}"); + return new Dimension(Math.toIntExact(result.get("w")), Math.toIntExact(result.get("h"))); + } + + /** + * 窗口最大化, 截取全部网页内容 + */ + default byte[] screenShotByWindow() { + getDriver().manage().window().setSize(getDocumentSize()); + return getDriver().getScreenshotAs(OutputType.BYTES); + } + + + /** + * 窗口最大化, 截取指定元素 + */ + default byte[] screenShotByElement(WebElement element) { + getDriver().manage().window().setSize(getDocumentSize()); + return element.getScreenshotAs(OutputType.BYTES); + } + + /** + * 可能存在懒加载, 滚动页面到底部进行触发, 每次滚动完后延时指定时间等待触发 + * @param scrollDelay 每次滚动完后延时, 等待触发 + */ + default void scrollToBottom(Duration scrollDelay) { + Dimension documentSize = getDocumentSize(); + long height = documentSize.getHeight(); + //这里需要模拟滑动,有些是滑动的时候才加载的 + long temp_height = 0; + while (true) { + temp_height += 500; + if (temp_height >= height) { + break; + } + getDriver().executeScript("window.scrollBy(0,500)"); + try { + Thread.sleep(scrollDelay.toMillis()); + } catch (Exception e) { + } + } + } + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/properties/SeleniumProperties.java b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/properties/SeleniumProperties.java new file mode 100644 index 0000000..18cba93 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/java/com/yunzhupaas/selenium/properties/SeleniumProperties.java @@ -0,0 +1,44 @@ +package com.yunzhupaas.selenium.properties; + +import com.yunzhupaas.selenium.consts.SeleniumConsts; +import lombok.Data; + +import java.time.Duration; + +@Data +public class SeleniumProperties { + + /** + * 浏览器类型 + */ + private String browserType = SeleniumConsts.BROWSER_TYPE_CHROME; + + /** + * 浏览器路径 + */ + private String browserPath; + + /** + * 浏览器驱动路径 + */ + private String driverPath; + + /** + * 页面加载超时时间 + */ + private Duration pageLoadTimeout = Duration.ofSeconds(30L); + + + /** + * 查找元素超时时间 + */ + private Duration implicaitlyWaitTimeout = Duration.ofSeconds(30L); + + + /** + * 执行脚本超时时间 + */ + private Duration scriptTimeout = Duration.ofSeconds(30L); + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..7bfe141 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-selenium/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.yunzhupaas.selenium.autoconfiguration.SeleniumAutoConfiguration diff --git a/yunzhupaas-boot-common/yunzhupaas-common-shardingsphere/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-shardingsphere/pom.xml new file mode 100644 index 0000000..815e652 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-shardingsphere/pom.xml @@ -0,0 +1,33 @@ + + + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-shardingsphere + + + + com.yunzhupaas + yunzhupaas-common-database + + + org.apache.shardingsphere + shardingsphere-jdbc-core + compile + + + log4j + log4j + + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-shardingsphere/src/main/java/com/yunzhupaas/config/ShardingSphereAutoConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-shardingsphere/src/main/java/com/yunzhupaas/config/ShardingSphereAutoConfig.java new file mode 100644 index 0000000..f9c53a7 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-shardingsphere/src/main/java/com/yunzhupaas/config/ShardingSphereAutoConfig.java @@ -0,0 +1,46 @@ +package com.yunzhupaas.config; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import org.apache.shardingsphere.driver.api.yaml.YamlShardingSphereDataSourceFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.sql.SQLException; + +/** + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/11/23 16:52 + */ +@Configuration +@ConditionalOnMissingClass( "org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient") +@ConditionalOnProperty(prefix = "config", name = "sharding-sphere-enabled", havingValue = "true") +public class ShardingSphereAutoConfig { + + public ShardingSphereAutoConfig() { + System.out.println("启用ShardingSphere"); + } + + public static final String PREFIX = "shardingsphere"; + + @Bean + public Object initShardingSphereDataSource(@Qualifier("dataSourceSystem") DynamicRoutingDataSource dataSource) throws SQLException, IOException, URISyntaxException { + // 加入ShardingSphere数据源 + File file = new File(ShardingSphereAutoConfig.class.getClassLoader().getResource("sharding-sphere.yml").toURI()); + DataSource SSDataSource = YamlShardingSphereDataSourceFactory.createDataSource(file); + dataSource.addDataSource(PREFIX, SSDataSource); + return null; + } + + + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-sms/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-sms/pom.xml new file mode 100644 index 0000000..f24364e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-sms/pom.xml @@ -0,0 +1,53 @@ + + + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-sms + + + + + com.squareup.okhttp3 + okhttp + + + com.tencentcloudapi + tencentcloud-sdk-java + + + com.aliyun + dysmsapi20170525 + + + bcpkix-jdk15on + org.bouncycastle + + + + + org.bouncycastle + bcpkix-jdk18on + + + dingtalk-sdk-java + taobao-sdk-java + + + dingtalk-sdk-java + taobao-sdk-java-source + + + com.yunzhupaas + yunzhupaas-common-core + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/message/SmsAliYunUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/message/SmsAliYunUtil.java new file mode 100644 index 0000000..51f1c23 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/message/SmsAliYunUtil.java @@ -0,0 +1,143 @@ +package com.yunzhupaas.util.message; + +import com.aliyun.dysmsapi20170525.Client; +import com.aliyun.dysmsapi20170525.models.*; +import com.aliyun.teaopenapi.models.*; +import com.yunzhupaas.util.JsonUtil; +import com.yunzhupaas.util.ParameterUtil; +import com.yunzhupaas.util.StringUtil; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 阿里云发送短信 + * + * @版本: V3.2.0 + * @版权: 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @作者: 云筑产品开发平台组 + * @日期: 2021/4/21 11:45 + */ +@Slf4j +public class SmsAliYunUtil { + + /** + * 使用AK&SK初始化账号Client + * + * @param accessKeyId + * @param accessKeySecret + * @param endpoint + * @return Client + */ + private static Client createClient(String accessKeyId, String accessKeySecret, String endpoint) { + try { + Config config = new Config() + // 您的AccessKey ID + .setAccessKeyId(accessKeyId) + // 您的AccessKey Secret + .setAccessKeySecret(accessKeySecret); + // 访问的域名 + config.endpoint = endpoint; + return new Client(config); + } catch (Exception e) { + log.error("创建阿里云短信客户端错误:" + e.getMessage()); + } + return null; + } + + /** + * 查询短信模板详情 + * + * @param accessKeyId + * @param accessKeySecret + * @param endpoint + * @param templateId + */ + public static List querySmsTemplateRequest(String accessKeyId, String accessKeySecret, String endpoint, String templateId) { + try { + Client client = createClient(accessKeyId, accessKeySecret, endpoint); + QuerySmsTemplateRequest querySmsTemplateRequest = new QuerySmsTemplateRequest() + .setTemplateCode(templateId); + QuerySmsTemplateResponse querySmsTemplateResponse = client.querySmsTemplate(querySmsTemplateRequest); + String templateContent = querySmsTemplateResponse.getBody().templateContent; + if (StringUtil.isNotEmpty(templateContent)) { + List list = new ArrayList<>(); + ParameterUtil.parse("${", "}", templateContent, list); + return list; + } else { + return null; + } + } catch (Exception e) { + log.error("查询阿里云短信模板错误:" + e.getMessage()); + } + return null; + } + + /** + * 查询短信模板详情 + * + * @param accessKeyId + * @param accessKeySecret + * @param endpoint + * @param templateId + */ + public static String querySmsTemplateContent(String accessKeyId, String accessKeySecret, String endpoint, String templateId) { + try { + Client client = createClient(accessKeyId, accessKeySecret, endpoint); + QuerySmsTemplateRequest querySmsTemplateRequest = new QuerySmsTemplateRequest() + .setTemplateCode(templateId); + QuerySmsTemplateResponse querySmsTemplateResponse = client.querySmsTemplate(querySmsTemplateRequest); + String templateContent = querySmsTemplateResponse.getBody().templateContent; + if (StringUtil.isNotEmpty(templateContent)) { + return templateContent; + } else { + return null; + } + } catch (Exception e) { + log.error("查询阿里云短信模板错误:" + e.getMessage()); + } + return null; + } + + /** + * 发送短信 + * + * @param accessKeyId + * @param accessKeySecret + * @param endpoint + * @param phoneNumbers + * @param signContent + * @param templateId + * @param map + * @return + */ + public static String sentSms(String accessKeyId, String accessKeySecret, String endpoint, String phoneNumbers, String signContent, String templateId, Map map) { + // 复制代码运行请自行打印 API 的返回值 + try { + Client client = createClient(accessKeyId, accessKeySecret, endpoint); + SendSmsRequest sendSmsRequest = new SendSmsRequest(); + // 接收者的号码 + sendSmsRequest.setPhoneNumbers(phoneNumbers); + // 签名 + sendSmsRequest.setSignName(signContent); + // 模板id + sendSmsRequest.setTemplateCode(templateId); + // 模板参数 + sendSmsRequest.setTemplateParam(JsonUtil.getObjectToString(map)); + SendSmsResponse sendSmsResponse = client.sendSms(sendSmsRequest); + if (!"Ok".equalsIgnoreCase(sendSmsResponse.body.code)) { + log.error("发送短信失败:" + sendSmsResponse.getBody().message); + return "发送短信失败:" + sendSmsResponse.getBody().message; + } + return "Ok"; + } catch (Exception e) { + log.error("发送短信失败:" + e.getMessage()); + return "发送短信失败:" + e.getMessage(); + } +// return null; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/message/SmsTenCentCloudUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/message/SmsTenCentCloudUtil.java new file mode 100644 index 0000000..c19f29e --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/message/SmsTenCentCloudUtil.java @@ -0,0 +1,168 @@ +package com.yunzhupaas.util.message; + +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.sms.v20210111.SmsClient; +import com.tencentcloudapi.sms.v20210111.models.*; +import com.yunzhupaas.util.ParameterUtil; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 腾讯云发送短信类 + * + * @author YUNZHUPAAS + * @版本: V3.2.0 + * @版权: 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @作者: 云筑产品开发平台组 + * @日期: 2021/4/21 11:58 + */ +@Slf4j +public class SmsTenCentCloudUtil { + + /** + * 创建客户端 + * + * @param accessKeyId + * @param accessKeySecret + * @return + */ + private static SmsClient createClient(String accessKeyId, String accessKeySecret, String endpoint, String region) { + SmsClient smsClient = null; + try { + Credential cred = new Credential(accessKeyId, accessKeySecret); + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint(endpoint); + // 实例化一个client选项,可选的,没有特殊需求可以跳过 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + // 实例化要请求产品的client对象,clientProfile是可选的 + smsClient = new SmsClient(cred, region, clientProfile); + } catch (Exception e) { + log.error("创建客户端失败:" + e.getMessage()); + } + return smsClient; + } + + /** + * 查询短信模板详情 + * + * @param accessKeyId + * @param accessKeySecret + * @param templateId + */ + public static List querySmsTemplateRequest(String accessKeyId, String accessKeySecret, String endpoint, + String region, String templateId) { + try { + SmsClient smsClient = createClient(accessKeyId, accessKeySecret, endpoint, region); + // 实例化一个请求对象,每个接口都会对应一个request对象 + DescribeSmsTemplateListRequest req = new DescribeSmsTemplateListRequest(); + req.setTemplateIdSet(new Long[] { Long.valueOf(templateId) }); + req.setInternational(0L); + // 返回的resp是一个DescribeSmsTemplateListResponse的实例,与请求对象对应 + DescribeSmsTemplateListResponse resp = smsClient.DescribeSmsTemplateList(req); + // 输出json格式的字符串回包 + System.out.println(DescribeSmsTemplateListResponse.toJsonString(resp)); + DescribeTemplateListStatus[] describeTemplateStatusSet = resp.getDescribeTemplateStatusSet(); + for (DescribeTemplateListStatus describeTemplateListStatus : describeTemplateStatusSet) { + String templateContent = describeTemplateListStatus.getTemplateContent(); + List list = new ArrayList<>(); + ParameterUtil.parse("{", "}", templateContent, list); + return list; + } + } catch (Exception e) { + log.error("查询短信模板参数失败:" + e.getMessage()); + } + return null; + } + + /** + * 查询短信模板详情 + * + * @param accessKeyId + * @param accessKeySecret + * @param templateId + */ + public static String querySmsTemplateContent(String accessKeyId, String accessKeySecret, String endpoint, + String region, String templateId) { + try { + SmsClient smsClient = createClient(accessKeyId, accessKeySecret, endpoint, region); + // 实例化一个请求对象,每个接口都会对应一个request对象 + DescribeSmsTemplateListRequest req = new DescribeSmsTemplateListRequest(); + req.setTemplateIdSet(new Long[] { Long.valueOf(templateId) }); + req.setInternational(0L); + // 返回的resp是一个DescribeSmsTemplateListResponse的实例,与请求对象对应 + DescribeSmsTemplateListResponse resp = smsClient.DescribeSmsTemplateList(req); + // 输出json格式的字符串回包 + System.out.println(DescribeSmsTemplateListResponse.toJsonString(resp)); + DescribeTemplateListStatus[] describeTemplateStatusSet = resp.getDescribeTemplateStatusSet(); + for (DescribeTemplateListStatus describeTemplateListStatus : describeTemplateStatusSet) { + String templateContent = describeTemplateListStatus.getTemplateContent(); + return templateContent; + } + } catch (Exception e) { + log.error("查询短信模板参数失败:" + e.getMessage()); + } + return null; + } + + /** + * 发送短信 + * + * @param accessKeyId + * @param accessKeySecret + * @param phoneNumbers + * @param appId + * @param signContent + * @param templateId + * @param map + * @return + */ + public static String sentSms(String accessKeyId, String accessKeySecret, String endpoint, String region, + String phoneNumbers, String appId, String signContent, String templateId, Map map) { + try { + SmsClient client = createClient(accessKeyId, accessKeySecret, endpoint, region); + // 实例化一个请求对象,每个接口都会对应一个request对象 + SendSmsRequest req = new SendSmsRequest(); + // 接收人 + String[] split = phoneNumbers.split(","); + req.setPhoneNumberSet(split); + // AppId + req.setSmsSdkAppId(appId); + // TemplateId + req.setTemplateId(templateId); + // SignName + req.setSignName(signContent); + // 参数 + List list = new ArrayList<>(); + for (String key : map.keySet()) { + String value = map.get(key) != null ? String.valueOf(map.get(key)) : ""; + list.add(value); + } + req.setTemplateParamSet(list.toArray(new String[list.size()])); + // 返回的resp是一个SendSmsResponse的实例,与请求对象对应 + SendSmsResponse resp = client.SendSms(req); + // 判断是否发送成功 + SendStatus[] sendStatusSet = resp.getSendStatusSet(); + for (SendStatus sendStatus : sendStatusSet) { + String code = sendStatus.getCode(); + if ("Ok".equalsIgnoreCase(code)) { + return "Ok"; + } else { + log.error("发送短信失败:" + sendStatus.getMessage()); + return "发送短信失败:" + sendStatus.getMessage(); + } + } + } catch (Exception e) { + log.error("发送短信失败:" + e.getMessage()); + return "发送短信失败:" + e.getMessage(); + } + return null; + } + +} diff --git a/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/message/SmsUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/message/SmsUtil.java new file mode 100644 index 0000000..4922c9a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/message/SmsUtil.java @@ -0,0 +1,68 @@ +package com.yunzhupaas.util.message; + +import com.yunzhupaas.base.SmsModel; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +/** + * 短信工具类 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-12-11 + */ +@Component +public class SmsUtil { + + /** + * 获取短信模板参数 + * + * @param type + * @param smsModel + * @param templateId + * @return + */ + public static List querySmsTemplateRequest(Integer type, SmsModel smsModel, String endpoint, String region, String templateId) { + if (type == 1) { + return SmsAliYunUtil.querySmsTemplateRequest(smsModel.getAliAccessKey(), smsModel.getAliSecret(), endpoint, templateId); + } + return SmsTenCentCloudUtil.querySmsTemplateRequest(smsModel.getTencentSecretId(), smsModel.getTencentSecretKey(), endpoint , region, templateId); + } + + /** + * 获取短信模板内容 + * + * @param type + * @param smsModel + * @param templateId + * @return + */ + public static String querySmsTemplateContent(Integer type, SmsModel smsModel, String endpoint, String region, String templateId) { + if (type == 1) { + return SmsAliYunUtil.querySmsTemplateContent(smsModel.getAliAccessKey(), smsModel.getAliSecret(), endpoint, templateId); + } + return SmsTenCentCloudUtil.querySmsTemplateContent(smsModel.getTencentSecretId(), smsModel.getTencentSecretKey(), endpoint , region, templateId); + } + /** + * 发送消息 + * + * @param type + * @param smsModel + * @param phoneNumbers + * @param signContent + * @param templateId + * @param map + * @return + */ + public static String sentSms(Integer type, SmsModel smsModel, String endpoint, String region, String phoneNumbers, String signContent, String templateId, Map map) { + if (type == 1) { + return SmsAliYunUtil.sentSms(smsModel.getAliAccessKey(), smsModel.getAliSecret(), endpoint, phoneNumbers, signContent, templateId, map); + } + return SmsTenCentCloudUtil.sentSms(smsModel.getTencentSecretId(), smsModel.getTencentSecretKey(), endpoint, region, phoneNumbers, smsModel.getTencentAppId(), signContent, templateId, map); + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/third/DingTalkUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/third/DingTalkUtil.java new file mode 100644 index 0000000..b0a1f28 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/third/DingTalkUtil.java @@ -0,0 +1,141 @@ +package com.yunzhupaas.util.third; + +import com.alibaba.fastjson.JSONObject; +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiGettokenRequest; +import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request; +import com.dingtalk.api.response.OapiGettokenResponse; +import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response; +import com.taobao.api.ApiException; +import com.yunzhupaas.util.RandomUtil; + + +/** + * 通过钉钉用户ID串进行发送消息,传入就是接收人的钉钉用户ID串 + * + * @版本: V3.1.0 + * @版权: 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @作者: 云筑产品开发平台组 + * @日期: 2021/4/21 16:10 + */ +public class DingTalkUtil { + + /** + * 钉钉发送消息的接口路径 + */ + public static final String SEND_MESSAGE = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2"; + /** + * 钉钉获取TOKEN的接口路径 + */ + public static final String TOKEN = "https://oapi.dingtalk.com/gettoken"; + + /** + * 获取token + * @param appkey + * @param appsecret + * @return + */ +// public static String getToken (String appkey,String appsecret){ +// DefaultDingTalkClient client = new +// DefaultDingTalkClient(TOKEN); +// OapiGettokenRequest request = new OapiGettokenRequest(); +// request.setAppkey(appkey); +// request.setAppsecret(appsecret); +// request.setHttpMethod("GET"); +// try { +// OapiGettokenResponse response = client.execute(request); +//// LocalCacheClient.set("access_token", response.getAccessToken(),7200*1000); +// return response.getAccessToken(); +// } catch (ApiException e) { +// e.printStackTrace(); +// } +// return null; +// } + + + /** + * 获取token + * @param appkey + * @param appsecret + * @return + */ + public static JSONObject getAccessToken(String appkey, String appsecret){ + JSONObject retMsg = new JSONObject(); + retMsg.put("code",true); + retMsg.put("error",""); + try{ + DingTalkClient client = new DefaultDingTalkClient(TOKEN); + OapiGettokenRequest req = new OapiGettokenRequest(); + req.setAppkey(appkey); + req.setAppsecret(appsecret); + req.setHttpMethod("GET"); + OapiGettokenResponse rsp = client.execute(req); + retMsg.put("access_token", rsp.getAccessToken()); + if (!rsp.isSuccess()) { + retMsg.put("code", false); + retMsg.put("error",rsp.getErrmsg()); + retMsg.put("access_token", ""); + } + } catch (ApiException e) { + retMsg.put("code", false); + retMsg.put("error",e.toString()); + retMsg.put("access_token", ""); + } + + return retMsg; + } + + /** + * 给用户推送消息(文字消息) + * @param appkey + * @param appsecret + * @param agentid + * @param userIds + * @param content + * @return + * 收到消息格式如下: + * 发送的内容 + */ + public static JSONObject sendDingMessage(String appkey, String appsecret, String agentid, String userIds, String content){ + JSONObject retMsg = new JSONObject(); + DingTalkClient client = new DefaultDingTalkClient(SEND_MESSAGE); + + OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request(); + request.setUseridList(userIds); + request.setAgentId(Long.parseLong(agentid)); + request.setToAllUser(false); + + OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); + msg.setMsgtype("text"); + msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text()); + String randomCode = "随机验证码:"+ RandomUtil.uuId(); + msg.getText().setContent(content+randomCode); + request.setMsg(msg); + + try { + retMsg = getAccessToken(appkey,appsecret); + if(retMsg.getBoolean("code")){ + // OapiMessageCorpconversationAsyncsendV2Response response = client.execute(request,getToken(appkey,appsecret)); + OapiMessageCorpconversationAsyncsendV2Response response = client.execute(request,retMsg.getString("access_token")); + if(response.getErrcode()>0){ + retMsg.put("code",false); + retMsg.put("error",response.getErrmsg()); + }else{ + retMsg.put("code",true); + retMsg.put("error",""); + } + }else{ + retMsg.put("code",false); + retMsg.put("error","获取token失败:"+retMsg.getString("error")); + } + return retMsg; + } catch (ApiException e) { + retMsg.put("code",false); + retMsg.put("error",e.toString()); + return retMsg; + } + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/third/QyWebChatUtil.java b/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/third/QyWebChatUtil.java new file mode 100644 index 0000000..7f85a29 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-sms/src/main/java/com/yunzhupaas/util/third/QyWebChatUtil.java @@ -0,0 +1,92 @@ +package com.yunzhupaas.util.third; + +import com.alibaba.fastjson.JSONObject; +import com.yunzhupaas.util.wxutil.HttpUtil; + +/** + * 企业微信的接口类 + * + * @版本: V3.1.0 + * @版权: 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @作者: 云筑产品开发平台组 + * @日期: 2021/4/21 8:20 + */ +public class QyWebChatUtil { + + /** + * 获取企业微信TOKEN的接口路径 + */ + public static final String TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s"; + + /** + * 往企业微信发送消息的接口路径 + */ + public static final String SEND_MESSAGE = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%s"; + + + /** + * 获取接口访问凭证 + */ + public static JSONObject getAccessToken(String corpId, String corpSecret) { + JSONObject retMsg = new JSONObject(); + JSONObject rstObj = HttpUtil.httpRequest(String.format(TOKEN,corpId, corpSecret), "GET", null); +// JSONObject rstObj = HttpUtil.httpsRequest(QyApi.getTokenUrl(corpId, corpSecret), "GET", null); + return rstObj; + } + + + /** + * 发送消息 20210416 Add By GongXishan + * 不抛出异常,返回Json + */ + public static JSONObject sendMessage(String message, String accessToken){ + JSONObject retMsg = new JSONObject(); + boolean codeFlag = true; + String errorMsg = ""; + JSONObject rstObj = HttpUtil.httpRequest(String.format(SEND_MESSAGE, accessToken), "POST", message); +// JSONObject rstObj = HttpUtil.httpsRequest(QyApi.sendMessage(accessToken), "POST", message); + if (HttpUtil.isWxError(rstObj)) { + codeFlag = false; + errorMsg = rstObj.toString(); + } + retMsg.put("code",codeFlag); + retMsg.put("error",errorMsg); + return retMsg; + } + + + /** + * 向企业微信发送信息 + * @param corpId + * @param corpSecret + * @param agentId + * @param toUserId + * @param contents + * @return + */ + public static JSONObject sendWxMessage(String corpId,String corpSecret,String agentId,String toUserId,String contents) { + JSONObject retMsg = null; + JSONObject message = null; + JSONObject tokenObject = null; + JSONObject content = null; + + message = new JSONObject(); + message.put("touser", toUserId); + message.put("agentid", agentId); + content = new JSONObject(); + content.put("content", contents); + message.put("text", content); + message.put("msgtype", "text"); + tokenObject = getAccessToken(corpId, corpSecret); + if(tokenObject.getString("access_token")!=null && !"".equals(tokenObject.getString("access_token"))){ + retMsg = sendMessage(message.toJSONString(), tokenObject.getString("access_token")); + }else + { + retMsg.put("code",false); + retMsg.put("error","access_token值为空,不能发送信息!"); + } + return retMsg; + } + +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-swagger/pom.xml b/yunzhupaas-boot-common/yunzhupaas-common-swagger/pom.xml new file mode 100644 index 0000000..add767a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-swagger/pom.xml @@ -0,0 +1,64 @@ + + + + yunzhupaas-boot-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-swagger + + + + + com.yunzhupaas + yunzhupaas-common-core + + + + + + + + + + boot3 + + [17,) + + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + + + + + boot2 + + (,17) + + + + + com.github.xiaoymin + knife4j-openapi3-spring-boot-starter + + + + + + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-swagger/src/main/java/com/yunzhupaas/MySpringWebMvcProvider.java b/yunzhupaas-boot-common/yunzhupaas-common-swagger/src/main/java/com/yunzhupaas/MySpringWebMvcProvider.java new file mode 100644 index 0000000..37b7f6a --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-swagger/src/main/java/com/yunzhupaas/MySpringWebMvcProvider.java @@ -0,0 +1,33 @@ +package com.yunzhupaas; + +import io.swagger.v3.oas.annotations.Operation; +import org.springdoc.webmvc.core.providers.SpringWebMvcProvider; +import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * SpringDoc默认展示全部接口 + * 过滤未添加@Operation的接口 + */ +public class MySpringWebMvcProvider extends SpringWebMvcProvider { + + @Override + public Map getHandlerMethods() { + if (this.handlerMethods == null) { + Map beansOfTypeRequestMappingHandlerMapping = applicationContext.getBeansOfType(RequestMappingHandlerMapping.class); + this.handlerMethods = beansOfTypeRequestMappingHandlerMapping.values().stream() + .map(AbstractHandlerMethodMapping::getHandlerMethods) + .map(Map::entrySet) + .flatMap(Collection::stream) + .filter(v -> v.getValue().hasMethodAnnotation(Operation.class)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a1, a2) -> a1, LinkedHashMap::new)); + } + return this.handlerMethods; + } +} + diff --git a/yunzhupaas-boot-common/yunzhupaas-common-swagger/src/main/java/com/yunzhupaas/SwaggerConfig.java b/yunzhupaas-boot-common/yunzhupaas-common-swagger/src/main/java/com/yunzhupaas/SwaggerConfig.java new file mode 100644 index 0000000..bf1f1e6 --- /dev/null +++ b/yunzhupaas-boot-common/yunzhupaas-common-swagger/src/main/java/com/yunzhupaas/SwaggerConfig.java @@ -0,0 +1,109 @@ +package com.yunzhupaas; + +import cn.hutool.core.util.RandomUtil; +import io.swagger.v3.oas.models.OpenAPI; +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 com.yunzhupaas.util.Constants; +import org.springdoc.core.models.GroupedOpenApi; +import org.springdoc.core.customizers.GlobalOpenApiCustomizer; +import org.springdoc.webmvc.core.providers.SpringWebMvcProvider; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.http.HttpHeaders; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.*; + +/** + * Swagger配置类 + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司(http://www.szlecheng.cn) + * @date 2024-03-23 + */ +@Configuration +public class SwaggerConfig implements WebMvcConfigurer { + + @Value("${spring.application.name:}") + private String name; + + @Value("${config.SoftVersion:}") + private String version; + + @Bean + public OpenAPI openAPI() { + OpenAPI openAPI = new OpenAPI(); + openAPI.info(apiInfo()); + openAPI.schemaRequirement(Constants.AUTHORIZATION, security()); + return openAPI; + } + + @Bean + public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() { + return openApi -> { + if (openApi.getTags()!=null){ + openApi.getTags().forEach(tag -> { + Map map=new HashMap<>(); + map.put("x-order", RandomUtil.randomInt(0,100)); + tag.setExtensions(map); + }); + } + if(openApi.getPaths()!=null){ + openApi.addExtension("x-test123","333"); + openApi.getPaths().addExtension("x-abb",RandomUtil.randomInt(1,100)); + } + }; + } + + @Bean + public GroupedOpenApi userApi(){ + String[] paths = { "/**" }; + return GroupedOpenApi.builder().group(name) + .pathsToMatch(paths) + .addOperationCustomizer((operation, handlerMethod) -> operation.security( + Collections.singletonList(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION)) + )) + .build(); + } + + /** + * 设置文档信息 + * @return + */ + private Info apiInfo() { + return new Info() + .title("接口文档") + //描述 + .description("yunzhupaas接口文档") + .version(version); + } + + private SecurityScheme security() { + SecurityScheme securityScheme = new SecurityScheme(); + securityScheme.setType(SecurityScheme.Type.APIKEY); + securityScheme.setName(Constants.AUTHORIZATION); + securityScheme.setIn(SecurityScheme.In.HEADER); + return securityScheme; + } + + @Bean + @Lazy(false) + public SpringWebMvcProvider springWebProvider(){ + return new MySpringWebMvcProvider(); + } + + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); + } +} + + diff --git a/yunzhupaas-cloud-common/pom.xml b/yunzhupaas-cloud-common/pom.xml new file mode 100644 index 0000000..1cc4e93 --- /dev/null +++ b/yunzhupaas-cloud-common/pom.xml @@ -0,0 +1,34 @@ + + + + yunzhupaas-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-cloud-common + pom + + yunzhupaas-common-dubbo + yunzhupaas-common-feign + yunzhupaas-common-seata + yunzhupaas-common-cloudshardingsphere + yunzhupaas-common-mq + + + + + + + + + diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-cloudshardingsphere/pom.xml b/yunzhupaas-cloud-common/yunzhupaas-common-cloudshardingsphere/pom.xml new file mode 100644 index 0000000..9ae3cfd --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-cloudshardingsphere/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + com.yunzhupaas + yunzhupaas-cloud-common + 5.2.0-RELEASE + ../pom.xml + + + yunzhupaas-common-cloudshardingsphere + + + + + com.yunzhupaas + yunzhupaas-common-shardingsphere + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + provided + + + + diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-cloudshardingsphere/src/main/java/com/yunzhupaas/config/CloudShardingSphereAutoConfig.java b/yunzhupaas-cloud-common/yunzhupaas-common-cloudshardingsphere/src/main/java/com/yunzhupaas/config/CloudShardingSphereAutoConfig.java new file mode 100644 index 0000000..7805ffd --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-cloudshardingsphere/src/main/java/com/yunzhupaas/config/CloudShardingSphereAutoConfig.java @@ -0,0 +1,51 @@ +package com.yunzhupaas.config; + +import com.alibaba.cloud.nacos.NacosConfigManager; +import com.alibaba.nacos.api.exception.NacosException; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.yunzhupaas.constant.GlobalConst; +import org.apache.shardingsphere.driver.api.yaml.YamlShardingSphereDataSourceFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.sql.SQLException; + +/** + * @author 云筑产品开发平台组 + * @user N + * @copyright 深圳市乐程软件有限公司 + * @date 2024/11/23 16:52 + */ +@Configuration +@ConditionalOnClass(name = "org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient") +@ConditionalOnProperty(prefix = "config", name = "sharding-sphere-enabled", havingValue = "true") +public class CloudShardingSphereAutoConfig { + + public CloudShardingSphereAutoConfig() { + System.out.println("启用 ShardingSphere"); + } + + public static final String PREFIX = "shardingsphere"; + + @Bean + public Object initShardingSphereDataSource(@Qualifier("dataSourceSystem") DynamicRoutingDataSource dataSource, + NacosConfigManager nacosConfigManager) throws SQLException, IOException, NacosException { + String shardingContent = nacosConfigManager.getConfigService().getConfig("sharding-sphere.yaml", + "DEFAULT_GROUP", 3000L); + if (shardingContent != null) { + DataSource SSDataSource = YamlShardingSphereDataSourceFactory + .createDataSource(shardingContent.getBytes(GlobalConst.DEFAULT_CHARSET)); + dataSource.addDataSource(PREFIX, SSDataSource); + } else { + System.out.println("ShardingSphere 加载失败,缺少 sharding-sphere.yaml 配置文件"); + } + return null; + } + +} diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/pom.xml b/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/pom.xml new file mode 100644 index 0000000..847ba7b --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/pom.xml @@ -0,0 +1,39 @@ + + + + yunzhupaas-cloud-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-dubbo + + + + + com.yunzhupaas + yunzhupaas-common-auth + + + + org.apache.dubbo + dubbo-spring-boot-starter + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-sentinel + + + + com.alibaba.csp + sentinel-apache-dubbo-adapter + + + + + diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/java/com/yunzhupaas/filter/MyDubboRequestFilter.java b/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/java/com/yunzhupaas/filter/MyDubboRequestFilter.java new file mode 100644 index 0000000..7ce747e --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/java/com/yunzhupaas/filter/MyDubboRequestFilter.java @@ -0,0 +1,41 @@ +package com.yunzhupaas.filter; + +import lombok.extern.slf4j.Slf4j; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.rpc.*; + +/** + * Dubbo请求过滤器 + */ +@Slf4j +@Activate(group = { CommonConstants.PROVIDER, CommonConstants.CONSUMER }, order = 100) +public class MyDubboRequestFilter implements Filter { + + @Override + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + Result result; + // Provider端记录日志 + if (RpcContext.getContext().isProviderSide()) { + long startTime = System.currentTimeMillis(); + result = invoker.invoke(invocation); + long elapsed = System.currentTimeMillis() - startTime; + + String baselog = "Client[" + CommonConstants.PROVIDER + "],InterfaceName=[" + + invocation.getInvoker().getInterface().getSimpleName() + "],MethodName=[" + + invocation.getMethodName() + "]"; + if (result.hasException()) { + log.error("DUBBO - 处理异常: {}, Exception = {}", baselog, result.getException()); + } else { + if (log.isDebugEnabled()) { + log.debug("DUBBO - 服务响应: {}, Elapsed=[{}ms]", baselog, elapsed); + } + } + + } else { + result = invoker.invoke(invocation); + } + return result; + } + +} diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/java/com/yunzhupaas/filter/MyDubboTokenFilter.java b/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/java/com/yunzhupaas/filter/MyDubboTokenFilter.java new file mode 100644 index 0000000..0e2d832 --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/java/com/yunzhupaas/filter/MyDubboTokenFilter.java @@ -0,0 +1,67 @@ +package com.yunzhupaas.filter; + +import cn.dev33.satoken.same.SaSameUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.consts.AuthConsts; +import com.yunzhupaas.properties.SecurityProperties; +import com.yunzhupaas.util.Constants; +import com.yunzhupaas.util.UserProvider; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.rpc.*; + +/** + * Dubbo过滤器 自动传递装载UserInfo + */ +@Activate(group = { CommonConstants.PROVIDER, CommonConstants.CONSUMER }, order = 101) +public class MyDubboTokenFilter implements Filter { + + private static SecurityProperties securityProperties; + + public MyDubboTokenFilter() { + MyDubboTokenFilter.securityProperties = SpringUtil.getBean(SecurityProperties.class); + } + + @Override + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + UserInfo userInfo; + Result result; + boolean isProvider; + String url = RpcContext.getContext().getUrl().toString(); + if (url.startsWith("injvm")) { + isProvider = url.contains("side=provider"); + } else { + isProvider = RpcContext.getContext().isProviderSide(); + } + // Provider端 + if (isProvider) { + try { + // 设置本地认证信息 + userInfo = (UserInfo) RpcContext.getContext().getObjectAttachment(Constants.AUTHORIZATION); + UserProvider.setLocalLoginUser(userInfo); + if (securityProperties.isEnableInnerAuth()) { + String innerToken = invocation.getAttachment(AuthConsts.INNER_TOKEN_KEY); + SaSameUtil.checkToken(innerToken); + } + result = invoker.invoke(invocation); + } finally { + // 清除用户缓存 + UserProvider.clearLocalUser(); + } + } else { + // Consumer端 + // 传递UserInfo + userInfo = UserProvider.getUser(); + if (userInfo.getUserId() != null) { + invocation.setAttachment(Constants.AUTHORIZATION, userInfo); + } + if (securityProperties.isEnableInnerAuth()) { + invocation.setAttachment(AuthConsts.INNER_TOKEN_KEY, UserProvider.getInnerAuthToken()); + } + result = invoker.invoke(invocation); + } + return result; + } + +} diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter b/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter new file mode 100644 index 0000000..de930c2 --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter @@ -0,0 +1,2 @@ +yunzhupaasDubboToken=com.yunzhupaas.filter.MyDubboTokenFilter +yunzhupaasDubboRequest=com.yunzhupaas.filter.MyDubboRequestFilter diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/resources/security/serialize.allowlist b/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/resources/security/serialize.allowlist new file mode 100644 index 0000000..3c5f662 --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-dubbo/src/main/resources/security/serialize.allowlist @@ -0,0 +1,2 @@ +# security/serialize.allowlist +com.yunzhupaas.base.UserInfo diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-feign/pom.xml b/yunzhupaas-cloud-common/yunzhupaas-common-feign/pom.xml new file mode 100644 index 0000000..b836445 --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-feign/pom.xml @@ -0,0 +1,26 @@ + + + + yunzhupaas-cloud-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-feign + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + com.yunzhupaas + yunzhupaas-common-auth + + + + diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-feign/src/main/java/com/yunzhupaas/FeignConfig.java b/yunzhupaas-cloud-common/yunzhupaas-common-feign/src/main/java/com/yunzhupaas/FeignConfig.java new file mode 100644 index 0000000..94445ff --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-feign/src/main/java/com/yunzhupaas/FeignConfig.java @@ -0,0 +1,85 @@ +package com.yunzhupaas; + +import feign.Logger; +import feign.RequestInterceptor; +import feign.RequestTemplate; +import com.yunzhupaas.base.UserInfo; +import com.yunzhupaas.constant.GlobalConst; +import com.yunzhupaas.consts.AuthConsts; +import com.yunzhupaas.properties.SecurityProperties; +import com.yunzhupaas.util.Constants; +import com.yunzhupaas.util.ServletUtil; +import com.yunzhupaas.util.UserProvider; +import com.yunzhupaas.utils.FeignHolder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Configuration +public class FeignConfig implements RequestInterceptor { + + @Autowired + private SecurityProperties securityProperties; + + @Override + public void apply(RequestTemplate template) { + // 添加token + Map headers = FeignHolder.get(); + String token = null; + if (headers != null) { + // 通过FeignHolder调用 + template.header("User-Agent", headers.get("user-agent")); + template.header(Constants.AUTHORIZATION, headers.get(Constants.AUTHORIZATION)); + template.header("X-Real-IP", headers.get("x-real-ip")); + template.header("X-Forwarded-For", headers.get("x-forwarded-for")); + /* + * headers.entrySet().forEach((k)->{ + * template.header(k.getKey(), k.getValue()); + * }); + */ + } else { + // 先获取当前本地缓存中UserInfo的TOKEN + // 适配临时切换用户 + UserInfo userInfo = UserProvider.getLocalLoginUser(); + if (userInfo != null && userInfo.getToken() != null) { + token = userInfo.getToken(); + template.header(Constants.AUTHORIZATION, token); + } + // Web环境直接调用 + HttpServletRequest request = ServletUtil.getRequest(); + if (request != null) { + if (token == null) { + template.header(Constants.AUTHORIZATION, request.getHeader(Constants.AUTHORIZATION)); + } + template.header("User-Agent", request.getHeader("User-Agent")); + template.header("X-Real-IP", request.getHeader("X-Real-IP")); + template.header("X-Forwarded-For", request.getHeader("X-Forwarded-For")); + } + } + if (securityProperties.isEnableInnerAuth() || securityProperties.isEnablePreAuth()) { + template.header(AuthConsts.INNER_TOKEN_KEY, UserProvider.getInnerAuthToken()); + } + template.header(GlobalConst.HEADER_HOST, ServletUtil.getRequestHost()); + } + + /** + * Openfeign调用日志 + * NONE,BASIC,HEADERS,FULL共有四种等级 + * + * @return + */ + @Bean + Logger.Level feignLoggerLeave() { + return Logger.Level.FULL; + } +} diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-feign/src/main/java/com/yunzhupaas/utils/FeignHolder.java b/yunzhupaas-cloud-common/yunzhupaas-common-feign/src/main/java/com/yunzhupaas/utils/FeignHolder.java new file mode 100644 index 0000000..aad2570 --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-feign/src/main/java/com/yunzhupaas/utils/FeignHolder.java @@ -0,0 +1,68 @@ +package com.yunzhupaas.utils; + +import com.yunzhupaas.util.ThreadPoolExecutorUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.Future; +import java.util.function.Supplier; + +/** + * 异步FEIGN请求, 把当前REQUEST的HEADER存入新线程中, 在新线程中调用feign请求, FeignConfig + * 中取当前headers发送到新服务 + * 使用方式: + * 1、直接调用set设置Header, Feign请求全部调用完之后调用clear清除线程变量 + * 2、调用asyncFeign、sendFeign 调用完后自动清除线程变量 + */ +// @ConditionalOnBean(ThreadPoolTaskExecutor.class) +@Component +@Slf4j +public class FeignHolder { + private static ThreadLocal> feignHeader = new ThreadLocal<>(); + + public static void set(Map headers) { + TreeMap map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + map.putAll(headers); + feignHeader.set(map); + } + + public static Map get() { + return feignHeader.get(); + } + + public static void clear() { + feignHeader.remove(); + } + + /** + * Async异步发送请求, 完成后清空线程变量 + * + * @param headers + * @param supplier + * @return + */ + public static Future asyncFeign(Map headers, Supplier supplier) { + return ThreadPoolExecutorUtil.getExecutor().submit(() -> sendFeign(headers, supplier)); + } + + /** + * 同步发送请求, 完成后清空线程变量 + * + * @param headers + * @param supplier + */ + public static R sendFeign(Map headers, Supplier supplier) { + try { + set(headers); + return supplier.get(); + } catch (Exception e) { + log.error("同步发送Feign请求失败", e); + return null; + } finally { + clear(); + } + } + +} diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-feign/src/main/java/com/yunzhupaas/utils/FeignName.java b/yunzhupaas-cloud-common/yunzhupaas-common-feign/src/main/java/com/yunzhupaas/utils/FeignName.java new file mode 100644 index 0000000..2423cfc --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-feign/src/main/java/com/yunzhupaas/utils/FeignName.java @@ -0,0 +1,38 @@ +package com.yunzhupaas.utils; + +import com.yunzhupaas.constant.ModuleName; +import lombok.Data; + +/** + * @author 云筑产品开发平台组 + * @version V3.1.0 + * @copyright 深圳市乐程软件有限公司 + * @date 2024/3/16 10:51 + */ +@Data +public class FeignName { + public static final String SYSTEM_SERVER_NAME = ModuleName.SYSTEM_SERVER_NAME; + + public static final String MESSAGE_SERVER_NAME = ModuleName.MESSAGE_SERVER_NAME; + + public static final String VUSUALDEV_SERVER_NAME = ModuleName.VUSUALDEV_SERVER_NAME; + + public static final String EXAMPLE_SERVER_NAME = ModuleName.EXAMPLE_SERVER_NAME; + + public static final String EXTEND_SERVER_NAME = ModuleName.EXTEND_SERVER_NAME; + + public static final String APP_SERVER_NAME = ModuleName.APP_SERVER_NAME; + + public static final String WORKFLOW_SERVER_NAME = ModuleName.WORKFLOW_SERVER_NAME; + + public static final String FILE_SERVER_NAME = ModuleName.FILE_SERVER_NAME; + + public static final String PERMISSION_SERVER_NAME = ModuleName.PERMISSION_SERVER_NAME; + + public static final String FORM_SERVER_NAME = ModuleName.FORM_SERVER_NAME; + + public static final String OAUTH_SERVER_NAME = ModuleName.OAUTH_SERVER_NAME; + + public static final String SCHEDULE_SERVER_NAME = ModuleName.SCHEDULE_SERVER_NAME; + +} diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-mq/pom.xml b/yunzhupaas-cloud-common/yunzhupaas-common-mq/pom.xml new file mode 100644 index 0000000..5ec4b13 --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-mq/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + com.yunzhupaas + yunzhupaas-cloud-common + 5.2.0-RELEASE + ../pom.xml + + + yunzhupaas-common-mq + + + + com.yunzhupaas + yunzhupaas-common-event + + + + + com.alibaba.cloud + spring-cloud-starter-stream-rocketmq + + + + + + + + + + diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-mq/src/main/java/com/yunzhupaas/config/MqAutoConfiguration.java b/yunzhupaas-cloud-common/yunzhupaas-common-mq/src/main/java/com/yunzhupaas/config/MqAutoConfiguration.java new file mode 100644 index 0000000..0416246 --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-mq/src/main/java/com/yunzhupaas/config/MqAutoConfiguration.java @@ -0,0 +1,33 @@ +package com.yunzhupaas.config; + +import com.baomidou.lock.LockTemplate; +import com.yunzhupaas.consts.ProjectEventConst; +import com.yunzhupaas.handler.ProjectEventMQMessageHandler; +import com.yunzhupaas.handler.ProjectEventMQSender; +import com.yunzhupaas.properties.EventProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.stream.function.StreamBridge; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.Message; + +import java.util.function.Consumer; + +@Configuration(proxyBeanMethods = false) +public class MqAutoConfiguration { + + @Bean(ProjectEventConst.DEFAULT_TOPIC_NAME) + @ConditionalOnProperty(prefix = "event", name = "event-publish-type", havingValue = ProjectEventConst.EVENT_PUBLISH_TYPE_QUEUE) + public Consumer> getDefaultMqConsumer(LockTemplate lockTemplate) { + return new ProjectEventMQMessageHandler(lockTemplate); + } + + /** + * 自定义事件发布渠道为QUEUE + */ + @Bean + @ConditionalOnProperty(prefix = "event", name = "event-publish-type", havingValue = ProjectEventConst.EVENT_PUBLISH_TYPE_QUEUE) + public ProjectEventMQSender getProjectEventMQSender(StreamBridge streamBridge, EventProperty eventProperties) { + return new ProjectEventMQSender(streamBridge, eventProperties); + } +} diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-mq/src/main/java/com/yunzhupaas/handler/ProjectEventMQMessageHandler.java b/yunzhupaas-cloud-common/yunzhupaas-common-mq/src/main/java/com/yunzhupaas/handler/ProjectEventMQMessageHandler.java new file mode 100644 index 0000000..e60784a --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-mq/src/main/java/com/yunzhupaas/handler/ProjectEventMQMessageHandler.java @@ -0,0 +1,57 @@ +package com.yunzhupaas.handler; + +import com.alibaba.fastjson.JSON; +import com.baomidou.lock.LockTemplate; +import com.yunzhupaas.consts.ProjectEventConst; +import com.yunzhupaas.module.ProjectEventInstance; +import com.yunzhupaas.util.JsonUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.messaging.Message; + +import java.util.function.Consumer; + +/** + * 自定义事件监听, MQ渠道, 收到通知后发送Spring事件(RedisEventInstance) + */ +@Slf4j +public class ProjectEventMQMessageHandler implements Consumer>, ApplicationEventPublisherAware { + + private ApplicationEventPublisher applicationEventPublisher; + private final LockTemplate lockTemplate; + + public ProjectEventMQMessageHandler(LockTemplate lockTemplate) { + this.lockTemplate = lockTemplate; + log.info("初始化自定义事件MQ监听器"); + } + + @Override + public void accept(Message o) { + if (log.isDebugEnabled()) { + log.debug("事件监听收到MQ消息:{}", JSON.toJSONString(o)); + } + // 是否存在自定义事件的标识 + if (o.getHeaders().get(ProjectEventConst.DEFAULT_CHANNEL_PREFIX) == null) { + if (log.isDebugEnabled()) { + log.debug("事件监听忽略MQ消息:{}", JSON.toJSONString(o)); + } + return; + } + Object payload = o.getPayload(); + ProjectEventInstance instance; + if (payload instanceof byte[]) { + instance = JSON.parseObject((byte[]) payload, ProjectEventInstance.class); + } else if (payload instanceof String) { + instance = JSON.parseObject((String) payload, ProjectEventInstance.class); + } else { + instance = JsonUtil.getJsonToBean(payload, ProjectEventInstance.class); + } + applicationEventPublisher.publishEvent(instance); + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.applicationEventPublisher = applicationEventPublisher; + } +} diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-mq/src/main/java/com/yunzhupaas/handler/ProjectEventMQSender.java b/yunzhupaas-cloud-common/yunzhupaas-common-mq/src/main/java/com/yunzhupaas/handler/ProjectEventMQSender.java new file mode 100644 index 0000000..5d8f7ed --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-mq/src/main/java/com/yunzhupaas/handler/ProjectEventMQSender.java @@ -0,0 +1,37 @@ +package com.yunzhupaas.handler; + +import com.alibaba.fastjson.JSON; +import com.yunzhupaas.consts.ProjectEventConst; +import com.yunzhupaas.module.ProjectEvent; +import com.yunzhupaas.event.ProjectEventSender; +import com.yunzhupaas.properties.EventProperty; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.stream.function.StreamBridge; +import org.springframework.messaging.support.MessageBuilder; + +/** + * 自定义事件发布 MQ渠道 + */ +@Slf4j +public class ProjectEventMQSender implements ProjectEventSender { + + private StreamBridge streamBridge; + private EventProperty eventProperty; + + public ProjectEventMQSender(StreamBridge streamBridge, EventProperty eventProperty) { + this.streamBridge = streamBridge; + this.eventProperty = eventProperty; + } + + @Override + public void send(ProjectEvent event) { + streamBridge.send(ProjectEventConst.DEFAULT_TOPIC_NAME + "-out-0", MessageBuilder.withPayload(event) + // 添加自定义事件标识 + .setHeader(ProjectEventConst.DEFAULT_CHANNEL_PREFIX, event.getChannel()) + .build()); + + if (log.isDebugEnabled()) { + log.debug("发送MQ自定义事件: {}", JSON.toJSONString(event)); + } + } +} diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-seata/pom.xml b/yunzhupaas-cloud-common/yunzhupaas-common-seata/pom.xml new file mode 100644 index 0000000..73e69a5 --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-seata/pom.xml @@ -0,0 +1,35 @@ + + + + yunzhupaas-cloud-common + com.yunzhupaas + 5.2.0-RELEASE + ../pom.xml + + 4.0.0 + + yunzhupaas-common-seata + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-seata + + + io.seata + seata-spring-boot-starter + + + com.esotericsoftware + kryo + + + de.javakaffee + kryo-serializers + + + + diff --git a/yunzhupaas-cloud-common/yunzhupaas-common-seata/src/main/java/io/seata/rm/datasource/SqlGenerateUtils.java b/yunzhupaas-cloud-common/yunzhupaas-common-seata/src/main/java/io/seata/rm/datasource/SqlGenerateUtils.java new file mode 100644 index 0000000..e0b70cc --- /dev/null +++ b/yunzhupaas-cloud-common/yunzhupaas-common-seata/src/main/java/io/seata/rm/datasource/SqlGenerateUtils.java @@ -0,0 +1,159 @@ +package io.seata.rm.datasource; + +import io.seata.rm.datasource.sql.struct.Field; +import io.seata.sqlparser.util.ColumnUtils; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + +/** + * generate sql and set value to sql + * + * @author JerryYin + */ +public class SqlGenerateUtils { + + private static final int MAX_IN_SIZE = 1000; + + private SqlGenerateUtils() { + + } + + public static String buildWhereConditionByPKs(List pkNameList, int rowSize, String dbType) + throws SQLException { + return "sqlserver".equals(dbType) ? buildWhereConditionByPKsBySqlServer(pkNameList, rowSize, dbType, MAX_IN_SIZE) : buildWhereConditionByPKs(pkNameList, rowSize, dbType, MAX_IN_SIZE); + + } + + + /** + * each pk is a condition.the result will like :" (id,userCode) in ((?,?),(?,?)) or (id,userCode) in ((?,?),(?,?) + * ) or (id,userCode) in ((?,?))" + * Build where condition by pks string. + * + * @param pkNameList pk column name list + * @param rowSize the row size of records + * @param dbType the type of database + * @param maxInSize the max in size + * @return return where condition sql string.the sql can search all related records not just one. + * @throws SQLException the sql exception + */ + public static String buildWhereConditionByPKs(List pkNameList, int rowSize, String dbType, int maxInSize) + throws SQLException { + StringBuilder whereStr = new StringBuilder(); + //we must consider the situation of composite primary key + int batchSize = rowSize % maxInSize == 0 ? rowSize / maxInSize : (rowSize / maxInSize) + 1; + for (int batch = 0; batch < batchSize; batch++) { + if (batch > 0) { + whereStr.append(" or "); + } + whereStr.append("("); + for (int i = 0; i < pkNameList.size(); i++) { + if (i > 0) { + whereStr.append(","); + } + whereStr.append(ColumnUtils.addEscape(pkNameList.get(i), dbType)); + } + whereStr.append(") in ( "); + + int eachSize = (batch == batchSize - 1) ? (rowSize % maxInSize == 0 ? maxInSize : rowSize % maxInSize) + : maxInSize; + for (int i = 0; i < eachSize; i++) { + //each row is a bracket + if (i > 0) { + whereStr.append(","); + } + whereStr.append("("); + for (int x = 0; x < pkNameList.size(); x++) { + if (x > 0) { + whereStr.append(","); + } + whereStr.append("?"); + } + whereStr.append(")"); + } + whereStr.append(" )"); + } + + return whereStr.toString(); + } + + + /** + * each pk is a condition.the result will like :" (id = ? and userCode = ?) or (id = ? and userCode = ?)" + * Build where condition by pks string. + * + * @param pkNameList pk column name list + * @param rowSize the row size of records + * @param dbType the type of database + * @param maxInSize the max in size + * @return return where condition sql string.the sql can search all related records not just one. + * @throws SQLException the sql exception + */ + public static String buildWhereConditionByPKsBySqlServer(List pkNameList, int rowSize, String dbType, int maxInSize) + throws SQLException { + StringBuilder whereStr = new StringBuilder(); + //we must consider the situation of composite primary key + for (int batch = 0; batch < rowSize; batch++) { + if (batch > 0) { + whereStr.append(" or "); + } + whereStr.append("("); + for (int i = 0; i < pkNameList.size(); i++) { + if (i > 0) { + whereStr.append(" and "); + } + whereStr.append(ColumnUtils.addEscape(pkNameList.get(i), dbType)); + whereStr.append(" = ? "); + } + whereStr.append(")"); + } + + return whereStr.toString(); + } + + /** + * set parameter for PreparedStatement, this is only used in pk sql. + * + * @param pkRowsList pkRowsList + * @param pkColumnNameList pkColumnNameList + * @param pst preparedStatement + * @throws SQLException SQLException + */ + public static void setParamForPk(List> pkRowsList, List pkColumnNameList, + PreparedStatement pst) throws SQLException { + int paramIndex = 1; + for (int i = 0; i < pkRowsList.size(); i++) { + Map rowData = pkRowsList.get(i); + for (String columnName : pkColumnNameList) { + Field pkField = rowData.get(columnName); + pst.setObject(paramIndex, pkField.getValue(), pkField.getType()); + paramIndex++; + } + } + } + + /** + * each pk is a condition.the result will like :" id =? and userCode =?" + * + * @param pkNameList pkNameList + * @param dbType dbType + * @return return where condition sql string.the sql can just search one related record. + */ + public static String buildWhereConditionByPKs(List pkNameList, String dbType) { + StringBuilder whereStr = new StringBuilder(); + //we must consider the situation of composite primary key + for (int i = 0; i < pkNameList.size(); i++) { + if (i > 0) { + whereStr.append(" and "); + } + String pkName = pkNameList.get(i); + whereStr.append(ColumnUtils.addEscape(pkName, dbType)); + whereStr.append(" = ? "); + } + return whereStr.toString(); + } + +} diff --git a/yunzhupaas-dependencies/pom.xml b/yunzhupaas-dependencies/pom.xml new file mode 100644 index 0000000..6e5b085 --- /dev/null +++ b/yunzhupaas-dependencies/pom.xml @@ -0,0 +1,1029 @@ + + + 4.0.0 + + com.yunzhupaas + yunzhupaas-dependencies + 5.2.0-RELEASE + pom + + + boot2 + UTF-8 + UTF-8 + UTF-8 + 3.13.0 + 3.1.1 + 2.15.0 + + 4.5.0 + 2.2.19 + + 1.2.23 + 3.5.7 + 3.5.7 + 4.3.1 + 1.4.0 + 1.4.13 + 6.1.0 + 9.0.0 + 23.5.0.24.07 + 8.1.3.140 + 8.6.0 + 12.8.1.jre8 + 42.7.4 + 6.0.0 + 42.5.0 + + 3.3.0 + 2.5.1 + 3.5.0 + 4.1.2 + 4.4.0 + 1.2.83 + 3.12.0 + 2.6 + 2.11.1 + 3.4.0 + 0.4.17 + 2.0.1.Final + 1.0.6 + 5.2.0 + 5.8.27 + 32.1.3-jre + 9.41.2 + 2.17.0 + 1.8.7 + 1.0 + 3.1.278 + 2.1.0 + 4.5.30 + 1.0.1 + 1.7.6 + 2.0.8 + 1.10.0 + 1.0.11 + 2.1.3 + 4.8.1 + 5.4.1 + 1.2-RELEASE + 2.0.0 + 7.4 + 9.2.0 + 1.18.32 + 2.3.2 + 4.4 + 4.5.13 + 1.16.4 + 2.3 + 2.11.5 + 2.0.5 + 1.1.5 + + + + 3.22.3.1 + 3.18.1 + 7.11.0 + 5.6.98 + 0.10.344 + 4.2.3 + 8.5.12 + 1.12.777 + 3.11.1 + 0.1.55 + 5.10 + + + + 2.12.2 + 1.7.10 + 2.2 + 5.6.0 + 0.45 + 1.27.1 + 2.0.1.Final + 5.4.1 + 1.16.0 + 5.5.0 + 3.0.1 + 2.7.0 + 1.1.10.7 + 1.78.1 + 20240303 + 4.28.2 + + + + + + + org.projectlombok + lombok + ${lombok.version} + + + + + + + commons-codec + commons-codec + ${commons-codec.version} + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin-stdlib.version} + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + com.esotericsoftware + kryo + ${kryo.version} + + + de.javakaffee + kryo-serializers + ${kryo-serializers.version} + + + com.github.oshi + oshi-core + ${oshi-core.version} + + + net.java.dev.jna + jna + ${jna.version} + + + net.java.dev.jna + jna-platform + ${jna.version} + + + com.squareup.okio + okio + ${okio.version} + + + org.xerial.snappy + snappy-java + ${snappy.version} + + + org.bouncycastle + bcprov-jdk18on + ${bcprov-jdk18on.version} + + + org.bouncycastle + bcpkix-jdk18on + ${bcprov-jdk18on.version} + + + + org.json + json + ${org.json-json.version} + + + + com.google.protobuf + protobuf-java + ${protobuf-java.version} + + + + org.apache.commons + commons-compress + ${commons-compress.version} + + + + + + + org.seleniumhq.selenium + selenium-bom + ${selenium.version} + pom + import + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring-cloud-alibaba.version} + pom + import + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + com.github.xiaoymin + knife4j-gateway-spring-boot-starter + ${knife4j.version} + + + + + com.alibaba + druid + ${druid.version} + + + + + com.baomidou + mybatis-plus-annotation + ${mybatis-plus.vesion} + + + + + org.mybatis.dynamic-sql + mybatis-dynamic-sql + ${mybatis-dynamic-sql.version} + + + + + com.baomidou + mybatis-plus-generator + ${mybatis-plus.generator.vesion} + + + mybatis-plus-extension + com.baomidou + + + + + + com.github.yulichang + mybatis-plus-join-boot-starter + ${mybatis-plus-join.vesion} + + + + + com.mysql + mysql-connector-j + ${mysql.version} + + + + + com.microsoft.sqlserver + mssql-jdbc + ${sqlserver.version} + + + + + com.github.binarywang + weixin-java-miniapp + ${weixin.version} + + + + + org.apache.poi + poi + ${poi.version} + + + org.apache.poi + poi-ooxml + ${poi.version} + + + org.apache.poi + poi-ooxml-schemas + ${poi.version} + + + + + com.alibaba + fastjson + ${fastjson.version} + + + + + org.apache.commons + commons-lang3 + ${common-lang3.version} + + + commons-lang + commons-lang + ${common-lang.version} + + + + + org.apache.commons + commons-pool2 + ${common-pool.version} + + + + + com.google.zxing + core + ${zxing.version} + + + + + com.belerweb + pinyin4j + ${pinyin4j.version} + + + com.nimbusds + nimbus-jose-jwt + ${nimbus-jose-jwt.version} + + + + cn.hutool + hutool-all + ${hutool.version} + + + + com.google.guava + guava + ${guava.version} + + + + com.github.librepdf + openpdf + ${openpdf.version} + + + com.github.librepdf + openpdf-fonts-extra + ${openpdf.version} + + + + com.github.yitter + yitter-idgenerator + ${yitter-idgenerator.version} + + + + + + com.yunzhupaas + yunzhupaas-file-core-starter + ${project.version} + + + + + com.huaweicloud + esdk-obs-java + ${oss.huaweicloud.version} + + + + + com.aliyun.oss + aliyun-sdk-oss + ${oss.aliyun.version} + + + + + com.qiniu + qiniu-java-sdk + ${oss.qiniu.version} + + + + + com.qcloud + cos_api + ${oss.qcloud.version} + + + + + com.baidubce + bce-java-sdk + ${oss.baidubce.version} + + + + + com.upyun + java-sdk + ${oss.upyun.version} + + + + + io.minio + minio + ${oss.minio.version} + + + + + com.amazonaws + aws-java-sdk-s3 + ${oss.aws-s3.version} + + + + + commons-net + commons-net + ${oss.ftp.version} + + + + + com.jcraft + jsch + ${oss.sftp.version} + + + + + cn.hutool + hutool-extra + ${hutool.version} + + + + + com.github.lookfirst + sardine + ${oss.webdav.version} + + + + + commons-io + commons-io + ${commons-io.version} + + + + org.apache.dubbo + dubbo-spring-boot-starter + ${dubbo.verssion} + + + com.alibaba.spring + spring-context-support + ${spring-context-support.version} + + + + + com.alibaba.csp + sentinel-apache-dubbo-adapter + ${sentinel.version} + + + + + + dingtalk-sdk-java + taobao-sdk-java + ${dingtalk.verssion} + + + dingtalk-sdk-java + taobao-sdk-java-source + ${dingtalk.verssion} + + + + com.tencentcloudapi + tencentcloud-sdk-java + ${tencentcloud-sdk-java.version} + + + + com.aliyun + dysmsapi20170525 + ${dysmsapi.version} + + + com.aliyun + aliyun-java-sdk-core + ${aliyun-java-sdk-core.version} + + + com.aliyun + alibaba-dingtalk-service-sdk + ${alibaba-dingtalk-service-sdk.version} + + + + + org.owasp.antisamy + antisamy + ${antisamy.varsion} + + + org.slf4j + slf4j-simple + + + + + + org.apache.commons + commons-text + ${commons-text.version} + + + + com.oracle.database.jdbc + ojdbc8 + ${oracle.version} + + + com.oracle.database.nls + orai18n + ${oracle.version} + + + + com.dameng + DmJdbcDriver18 + ${dm18.version} + + + + cn.com.kingbase + kingbase8 + ${kingbase.version} + + + + org.postgresql + postgresql + ${postgre.version} + + + + + + + + com.github.pagehelper + pagehelper + ${pagehelper.version} + + + xerces + xercesImpl + ${xercesImpl.version} + + + + org.dom4j + dom4j + ${dom4j.version} + + + com.squareup.okhttp3 + okhttp + ${okhttp3.version} + + + + org.apache.shardingsphere + shardingsphere-jdbc-core + ${shardingsphere.version} + compile + + + log4j + log4j + + + + + + + cn.afterturn + easypoi-base + ${easypoi-base.version} + + + com.baomidou + lock4j-redisson-spring-boot-starter + ${lock4j-redisson-spring-boot-starter.version} + + + org.redisson + redisson-spring-boot-starter + ${redisson.version} + + + net.lingala.zip4j + zip4j + ${zip4j.version} + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + + + + org.springframework.boot + spring-boot-starter-websocket + ${spring-boot.version} + + + + + org.apache.httpcomponents + httpmime + ${httpmime.version} + + + + org.quartz-scheduler + quartz + ${quartz.version} + + + cn.dev33 + sa-token-jwt + ${satoken.version} + + + cn.hutool + hutool-jwt + + + + + cn.dev33 + sa-token-redis-jackson + ${satoken.version} + + + spring-boot-starter-data-redis + org.springframework.boot + + + + + + net.coobird + thumbnailator + ${thumbnailator.version} + + + cn.afterturn + easypoi-annotation + ${easypoi-base.version} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + org.apache.velocity + velocity-engine-core + ${velocity-engine-core.version} + + + me.zhyd.oauth + JustAuth + ${justauth.version} + + + + io.seata + seata-spring-boot-starter + ${seata.version} + + + + net.logstash.logback + logstash-logback-encoder + ${logstash.version} + + + + org.apache.skywalking + apm-toolkit-logback-1.x + ${skywalking.logback.version} + + + com.github.vertical-blank + sql-formatter + ${sql-formatter.version} + + + + com.unfbx + chatgpt-java + ${chatgpt-java.version} + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + org.codehaus.mojo + versions-maven-plugin + ${versions-maven-plugin.version} + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + true + ${maven.compiler.source} + ${maven.compiler.target} + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-deploy-plugin + + + org.codehaus.mojo + versions-maven-plugin + + false + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + + + maven-releases + maven-releases + https://xadev.szlecheng.cn/nexus/repository/maven-public/ + + + + + + + + boot3 + + [17,) + + + + 21 + + 1.8 + + 17 + + 2.7.17 + 3.3.4 + 2023.0.3 + 2023.0.1.2 + 6.0.0 + 1.37.0 + 8.0.1.Final + 2.0.1 + 2.2.7 + 3.27.2 + 3.2.11 + 15.4 + + 4.21.0 + 4.13.0 + 2.0.3 + + + + + jakarta.servlet + jakarta.servlet-api + ${servlet-api.version} + + + org.hibernate.validator + hibernate-validator + ${hibernate-validator.version} + + + cn.dev33 + sa-token-spring-boot3-starter + ${satoken.version} + + + com.sun.mail + jakarta.mail + ${sun.mail.version} + + + com.baomidou + mybatis-plus-spring-boot3-starter + ${mybatis-plus.vesion} + + + com.baomidou + dynamic-datasource-spring-boot3-starter + ${mybatis-plus.dynamic.vesion} + + + + io.swagger.core.v3 + swagger-annotations-jakarta + ${swagger-model.version} + + + io.swagger.core.v3 + swagger-models-jakarta + ${swagger-model.version} + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + ${knife4j.version} + + + + org.openjdk.nashorn + nashorn-core + ${nashorn-core.version} + + + + + + boot2 + + (,17) + + + + 17 + + 17 + + 17 + + 2.7.18 + 2.7.18 + 2021.0.9 + 2021.0.6.0 + 4.0.1 + 1.3.2 + 1.37.0 + 6.0.23.Final + 1.6.2 + 2.2.3 + 3.18.0 + 2.7.23 + + 4.13.0 + 4.13.0 + 1.3.43 + + + + + javax.servlet + javax.servlet-api + ${servlet-api.version} + + + javax.annotation + javax.annotation-api + ${servlet.annotation-api.version} + + + org.hibernate.validator + hibernate-validator + ${hibernate-validator.version} + + + cn.dev33 + sa-token-spring-boot-starter + ${satoken.version} + + + com.sun.mail + javax.mail + ${sun.mail.version} + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.vesion} + + + com.baomidou + dynamic-datasource-spring-boot-starter + ${mybatis-plus.dynamic.vesion} + + + + io.swagger.core.v3 + swagger-annotations + ${swagger-model.version} + + + io.swagger.core.v3 + swagger-models + ${swagger-model.version} + + + com.github.xiaoymin + knife4j-openapi3-spring-boot-starter + ${knife4j.version} + + + + + + +