diff --git a/README.md b/README.md index 57c88d0a..1ffdf7bc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ContiNew Admin 中后台管理框架 +# ContiNew Admin 多租户中后台管理框架 Release @@ -44,9 +44,9 @@ **AI 编程纪元已经开启,基于 ContiNew 项目开发,让 AI 助手“学习”更优雅的代码规范,“写出”更优质的代码。** -ContiNew Admin(Continue New Admin)持续迭代优化的前后端分离中后台管理系统框架。开箱即用,重视每一处代码规范,重视每一种解决方案细节,持续提供舒适的前、后端开发体验。 +ContiNew Admin(Continue New Admin):持续迭代优化的,前后端分离,多租户中后台管理系统框架。开箱即用,重视每一处代码规范,重视每一种解决方案细节,持续提供舒适的前、后端开发体验。 -当前采用的技术栈:Spring Boot3(Java17)、Vue3 & Arco Design & TS & Vite、Sa-Token、MyBatis Plus、Redisson、JetCache、JustAuth、Crane4j、EasyExcel、Liquibase、Hutool 等。 +当前采用的技术栈:Spring Boot3(Java17)、Vue3 & Arco Design & TS & Vite、Sa-Token、MyBatis Plus、FastExcel、Redisson、JetCache、JustAuth、Crane4j、Hutool、Liquibase 等。 ## 项目源码 @@ -143,10 +143,13 @@ public class DeptController extends BaseControllercontinew-starter-extension-crud-mp - + top.continew.starter continew-starter-extension-tenant-mp - com.baomidou dynamic-datasource-spring-boot3-starter - \ No newline at end of file diff --git a/continew-common/src/main/java/top/continew/admin/common/config/properties/CaptchaProperties.java b/continew-common/src/main/java/top/continew/admin/common/config/CaptchaProperties.java similarity index 97% rename from continew-common/src/main/java/top/continew/admin/common/config/properties/CaptchaProperties.java rename to continew-common/src/main/java/top/continew/admin/common/config/CaptchaProperties.java index 4fe249e6..0a0e1b86 100644 --- a/continew-common/src/main/java/top/continew/admin/common/config/properties/CaptchaProperties.java +++ b/continew-common/src/main/java/top/continew/admin/common/config/CaptchaProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package top.continew.admin.common.config.properties; +package top.continew.admin.common.config; import lombok.Data; import org.springframework.beans.factory.annotation.Value; diff --git a/continew-common/src/main/java/top/continew/admin/common/config/properties/RsaProperties.java b/continew-common/src/main/java/top/continew/admin/common/config/RsaProperties.java similarity index 95% rename from continew-common/src/main/java/top/continew/admin/common/config/properties/RsaProperties.java rename to continew-common/src/main/java/top/continew/admin/common/config/RsaProperties.java index 158f62b6..91d6d6b6 100644 --- a/continew-common/src/main/java/top/continew/admin/common/config/properties/RsaProperties.java +++ b/continew-common/src/main/java/top/continew/admin/common/config/RsaProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package top.continew.admin.common.config.properties; +package top.continew.admin.common.config; import cn.hutool.extra.spring.SpringUtil; diff --git a/continew-common/src/main/java/top/continew/admin/common/config/properties/TenantProperties.java b/continew-common/src/main/java/top/continew/admin/common/config/TenantProperties.java similarity index 66% rename from continew-common/src/main/java/top/continew/admin/common/config/properties/TenantProperties.java rename to continew-common/src/main/java/top/continew/admin/common/config/TenantProperties.java index a3d09e40..464d5d8d 100644 --- a/continew-common/src/main/java/top/continew/admin/common/config/properties/TenantProperties.java +++ b/continew-common/src/main/java/top/continew/admin/common/config/TenantProperties.java @@ -14,27 +14,26 @@ * limitations under the License. */ -package top.continew.admin.common.config.properties; +package top.continew.admin.common.config; import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import top.continew.starter.core.constant.PropertiesConstants; import java.util.List; /** - * @description: 多租户配置 - * @author: 小熊 - * @create: 2024-11-29 12:05 + * 租户配置属性 + * + * @author 小熊 + * @author Charles7c + * @since 2024/11/29 12:05 */ -@Component -@ConfigurationProperties(prefix = PropertiesConstants.TENANT) @Data -public class TenantProperties { - - private boolean enabled; +@Component +public class TenantProperties extends top.continew.starter.extension.tenant.autoconfigure.TenantProperties { + /** + * 忽略菜单 ID(租户不能使用的菜单) + */ private List ignoreMenus; - } diff --git a/continew-common/src/main/java/top/continew/admin/common/constant/CacheConstants.java b/continew-common/src/main/java/top/continew/admin/common/constant/CacheConstants.java index 020d19d0..66cd0533 100644 --- a/continew-common/src/main/java/top/continew/admin/common/constant/CacheConstants.java +++ b/continew-common/src/main/java/top/continew/admin/common/constant/CacheConstants.java @@ -71,16 +71,6 @@ public class CacheConstants { */ public static final String DATA_IMPORT_KEY = "SYSTEM" + DELIMITER + "DATA_IMPORT" + DELIMITER; - /** - * 数据连接键前缀 - */ - public static final String DB_CONNECT_KEY_PREFIX = "DB_CONNECT" + DELIMITER; - - /** - * 租户信息前缀 - */ - public static final String TENANT_KEY = "TENANT" + DELIMITER; - private CacheConstants() { } } diff --git a/continew-common/src/main/java/top/continew/admin/common/constant/SysConstants.java b/continew-common/src/main/java/top/continew/admin/common/constant/SysConstants.java index 7f9bfdb2..49d26ec9 100644 --- a/continew-common/src/main/java/top/continew/admin/common/constant/SysConstants.java +++ b/continew-common/src/main/java/top/continew/admin/common/constant/SysConstants.java @@ -85,29 +85,14 @@ public class SysConstants { public static final String LOGOUT_URI = "/auth/logout"; /** - * 描述类字段后缀 + * 租户默认数据源 */ - public static final String DESCRIPTION_FIELD_SUFFIX = "String"; - - /** - * 租户数据库前缀 - */ - public static final String TENANT_DB_PREFIX = "tenant_"; - - /** - * 默认租户 - */ - public static final String DEFAULT_TENANT = "0"; - - /** - * 默认数据源 - */ - public static final String DEFAULT_DATASOURCE = "master"; + public static final String DEFAULT_TENANT_DATASOURCE = "master"; /** * 租户管理员角色编码 */ - public static final String TENANT_ADMIN_CODE = "tenant_admin"; + public static final String TENANT_ADMIN_ROLE_CODE = "tenant_admin"; private SysConstants() { } diff --git a/continew-common/src/main/java/top/continew/admin/common/context/UserContext.java b/continew-common/src/main/java/top/continew/admin/common/context/UserContext.java index 91280b9a..e177315f 100644 --- a/continew-common/src/main/java/top/continew/admin/common/context/UserContext.java +++ b/continew-common/src/main/java/top/continew/admin/common/context/UserContext.java @@ -80,7 +80,7 @@ public class UserContext implements Serializable { */ private Set roles; - /* + /** * 客户端类型 */ private String clientType; @@ -134,5 +134,4 @@ public class UserContext implements Serializable { } return this.pwdResetTime.plusDays(this.passwordExpirationDays).isBefore(LocalDateTime.now()); } - } diff --git a/continew-common/src/main/java/top/continew/admin/common/context/UserContextHolder.java b/continew-common/src/main/java/top/continew/admin/common/context/UserContextHolder.java index 019974b2..ceaa46fc 100644 --- a/continew-common/src/main/java/top/continew/admin/common/context/UserContextHolder.java +++ b/continew-common/src/main/java/top/continew/admin/common/context/UserContextHolder.java @@ -143,6 +143,15 @@ public class UserContextHolder { return ExceptionUtils.exToNull(() -> getContext().getId()); } + /** + * 获取租户 ID + * + * @return 租户 ID + */ + public static Long getTenantId() { + return ExceptionUtils.exToNull(() -> getContext().getTenantId()); + } + /** * 获取用户名 * @@ -180,11 +189,4 @@ public class UserContextHolder { StpUtil.checkLogin(); return getContext().isAdmin(); } - - /** - * 获取租户ID - */ - public static Long getTenantId() { - return ExceptionUtils.exToNull(() -> getContext().getTenantId()); - } } diff --git a/continew-common/src/main/java/top/continew/admin/common/util/SecureUtils.java b/continew-common/src/main/java/top/continew/admin/common/util/SecureUtils.java index d192d4c8..2e247370 100644 --- a/continew-common/src/main/java/top/continew/admin/common/util/SecureUtils.java +++ b/continew-common/src/main/java/top/continew/admin/common/util/SecureUtils.java @@ -20,7 +20,7 @@ import cn.hutool.core.codec.Base64; import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.extra.spring.SpringUtil; -import top.continew.admin.common.config.properties.RsaProperties; +import top.continew.admin.common.config.RsaProperties; import top.continew.starter.core.exception.BusinessException; import top.continew.starter.core.util.validation.ValidationUtils; import top.continew.starter.security.crypto.autoconfigure.CryptoProperties; diff --git a/continew-plugin/continew-plugin-open/src/main/java/top/continew/admin/open/service/AppService.java b/continew-plugin/continew-plugin-open/src/main/java/top/continew/admin/open/service/AppService.java index 59e0dcbc..469f10ef 100644 --- a/continew-plugin/continew-plugin-open/src/main/java/top/continew/admin/open/service/AppService.java +++ b/continew-plugin/continew-plugin-open/src/main/java/top/continew/admin/open/service/AppService.java @@ -55,5 +55,4 @@ public interface AppService extends BaseService continew-plugin-tenant - 多租户插件 + jar + + ${project.artifactId} + 租户插件 + + top.continew.admin continew-system - \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/annotation/ConditionalOnEnabledTenant.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/annotation/ConditionalOnEnabledTenant.java new file mode 100644 index 00000000..4baf929c --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/annotation/ConditionalOnEnabledTenant.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.annotation; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import top.continew.starter.core.constant.PropertiesConstants; + +import java.lang.annotation.*; + +/** + * 是否启用 Tenant 判断注解 + * + * @author Charles7c + * @since 2025/5/18 12:03 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +@Documented +@ConditionalOnProperty(prefix = PropertiesConstants.TENANT, name = PropertiesConstants.ENABLED, havingValue = "true", matchIfMissing = true) +public @interface ConditionalOnEnabledTenant { +} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/config/DefaultTenantProvider.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/config/DefaultTenantProvider.java new file mode 100644 index 00000000..524a7cfc --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/config/DefaultTenantProvider.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.config; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.StrUtil; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import top.continew.admin.common.config.TenantProperties; +import top.continew.admin.tenant.constant.TenantConstants; +import top.continew.admin.tenant.model.entity.DatasourceDO; +import top.continew.admin.tenant.model.entity.TenantDO; +import top.continew.admin.tenant.model.enums.DatasourceDatabaseTypeEnum; +import top.continew.admin.tenant.model.req.DatasourceReq; +import top.continew.admin.tenant.service.DatasourceService; +import top.continew.admin.tenant.service.TenantService; +import top.continew.starter.extension.tenant.config.TenantDataSource; +import top.continew.starter.extension.tenant.config.TenantProvider; +import top.continew.starter.extension.tenant.context.TenantContext; +import top.continew.starter.extension.tenant.enums.TenantIsolationLevel; + +/** + * 默认租户提供者 + * + * @author 小熊 + * @author Charles7c + * @since 2024/12/12 15:35 + */ +@Service +@RequiredArgsConstructor +public class DefaultTenantProvider implements TenantProvider { + + private final TenantProperties tenantProperties; + private final TenantService tenantService; + private final DatasourceService datasourceService; + + @Override + public TenantContext getByTenantId(String tenantIdAsString, boolean verify) { + TenantContext context = new TenantContext(); + // 超级租户默认使用行级隔离 + Long superTenantId = tenantProperties.getSuperTenantId(); + if (StrUtil.isBlank(tenantIdAsString) || superTenantId.toString().equals(tenantIdAsString)) { + context.setTenantId(superTenantId); + context.setIsolationLevel(TenantIsolationLevel.LINE); + return context; + } + // 获取租户信息 + Long tenantId = Long.valueOf(tenantIdAsString); + TenantDO tenant = tenantService.checkStatus(tenantId); + TenantIsolationLevel isolationLevel = tenant.getIsolationLevel().getLevel(); + context.setTenantId(tenantId); + context.setIsolationLevel(isolationLevel); + // 数据源级隔离级别需要提供数据源信息 + if (TenantIsolationLevel.DATASOURCE == isolationLevel) { + // 获取数据源配置 + DatasourceDO datasource = datasourceService.getById(tenant.getDatasourceId()); + DatasourceDatabaseTypeEnum databaseType = datasource.getDatabaseType(); + // 填充数据源信息 + TenantDataSource tenantDataSource = new TenantDataSource(); + tenantDataSource.setPoolName(tenantIdAsString); + tenantDataSource.setDriverClassName(databaseType.getDriverClassName()); + tenantDataSource.setUrl(databaseType.getJdbcUrl(BeanUtil + .toBean(datasource, DatasourceReq.class), TenantConstants.TENANT_DB_PREFIX + tenant.getCode())); + tenantDataSource.setUsername(datasource.getUsername()); + tenantDataSource.setPassword(datasource.getPassword()); + context.setDataSource(tenantDataSource); + } + return context; + } +} diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/config/TenantConfiguration.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/config/TenantConfiguration.java new file mode 100644 index 00000000..0af78499 --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/config/TenantConfiguration.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.config; + +import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 租户配置 + * + * @author Charles7c + * @since 2025/7/12 13:30 + */ +@Configuration +public class TenantConfiguration { + + /** + * API 文档分组配置 + */ + @Bean + public GroupedOpenApi tenantApi() { + return GroupedOpenApi.builder().group("tenant").displayName("租户").pathsToMatch("/tenant/**").build(); + } +} diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/enums/TenantConnectTypeEnum.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/constant/TenantCacheConstants.java similarity index 54% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/enums/TenantConnectTypeEnum.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/constant/TenantCacheConstants.java index 6be37cc0..fecd7e0f 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/enums/TenantConnectTypeEnum.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/constant/TenantCacheConstants.java @@ -14,25 +14,33 @@ * limitations under the License. */ -package top.continew.admin.tenant.model.enums; +package top.continew.admin.tenant.constant; -import lombok.AllArgsConstructor; -import lombok.Getter; -import top.continew.starter.core.exception.BusinessException; +import top.continew.admin.common.constant.CacheConstants; -@Getter -@AllArgsConstructor -public enum TenantConnectTypeEnum { +/** + * 租户缓存相关常量 + * + * @author Charles7c + * @since 2025/7/14 20:35 + */ +public class TenantCacheConstants { - MYSQL; + /** + * 分隔符 + */ + public static final String DELIMITER = CacheConstants.DELIMITER; - public static TenantConnectTypeEnum getByOrdinal(Integer ordinal) { - for (TenantConnectTypeEnum item : TenantConnectTypeEnum.values()) { - if (item.ordinal() == ordinal) { - return item; - } - } - throw new BusinessException("未知的连接类型"); + /** + * 租户前缀 + */ + public static final String TENANT_KEY_PREFIX = "TENANT" + DELIMITER; + + /** + * 租户数据源前缀 + */ + public static final String TENANT_DATASOURCE_KEY_PREFIX = TENANT_KEY_PREFIX + "DATASOURCE" + DELIMITER; + + private TenantCacheConstants() { } - } diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/constant/TenantConstants.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/constant/TenantConstants.java new file mode 100644 index 00000000..e9eafb48 --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/constant/TenantConstants.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.constant; + +/** + * 租户相关常量 + * + * @author Charles7c + * @since 2025/7/14 20:27 + */ +public class TenantConstants { + + /** + * 租户数据库前缀 + */ + public static final String TENANT_DB_PREFIX = "tenant_"; + + /** + * 编码生成器 KEY + */ + public static final String CODE_GENERATOR_KEY = "tenant-code"; + + private TenantConstants() { + } +} diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/DatasourceController.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/DatasourceController.java new file mode 100644 index 00000000..d6cccc6f --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/DatasourceController.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; +import top.continew.admin.common.base.controller.BaseController; +import top.continew.admin.tenant.model.query.DatasourceQuery; +import top.continew.admin.tenant.model.req.DatasourceReq; +import top.continew.admin.tenant.model.resp.DatasourceDetailResp; +import top.continew.admin.tenant.model.resp.DatasourceResp; +import top.continew.admin.tenant.service.DatasourceService; +import top.continew.starter.extension.crud.annotation.CrudRequestMapping; +import top.continew.starter.extension.crud.enums.Api; + +/** + * 数据源管理 API + * + * @author 小熊 + * @author Charles7c + * @since 2024/12/12 19:13 + */ +@Tag(name = "数据源管理 API") +@RestController +@CrudRequestMapping(value = "/tenant/datasource", api = {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE}) +public class DatasourceController extends BaseController { + + @Operation(summary = "测试连接", description = "测试数据源连接可用性") + @Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH) + @SaCheckPermission("tenant:datasource:testConnection") + @PostMapping("/{id}/test/connection") + public void testConnection(@PathVariable Long id) { + baseService.testConnection(id); + } +} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/PackageController.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/PackageController.java new file mode 100644 index 00000000..f91feaff --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/PackageController.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.lang.tree.Tree; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import top.continew.admin.common.base.controller.BaseController; +import top.continew.admin.common.enums.DisEnableStatusEnum; +import top.continew.admin.common.config.TenantProperties; +import top.continew.admin.system.model.query.MenuQuery; +import top.continew.admin.system.service.MenuService; +import top.continew.admin.tenant.model.query.PackageQuery; +import top.continew.admin.tenant.model.req.PackageReq; +import top.continew.admin.tenant.model.resp.PackageDetailResp; +import top.continew.admin.tenant.model.resp.PackageResp; +import top.continew.admin.tenant.service.PackageService; +import top.continew.starter.extension.crud.annotation.CrudRequestMapping; +import top.continew.starter.extension.crud.enums.Api; + +import java.util.List; + +/** + * 套餐管理 API + * + * @author 小熊 + * @author Charles7c + * @since 2024/11/26 11:25 + */ +@Tag(name = "套餐管理 API") +@RestController +@RequiredArgsConstructor +@CrudRequestMapping(value = "/tenant/package", api = {Api.LIST, Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE}) +public class PackageController extends BaseController { + + private final TenantProperties tenantProperties; + private final MenuService menuService; + + @Operation(summary = "查询租户套餐菜单", description = "查询租户套餐菜单树列表") + @SaCheckPermission("tenant:package:list") + @GetMapping("/menu/tree") + public List> listMenuTree() { + MenuQuery query = new MenuQuery(); + query.setStatus(DisEnableStatusEnum.ENABLE); + // 过滤掉租户不能使用的菜单 + query.setExcludeMenuIdList(tenantProperties.getIgnoreMenus()); + return menuService.tree(query, null, true); + } +} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/TenantController.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/TenantController.java index e116c277..35b3c1e2 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/TenantController.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/TenantController.java @@ -18,71 +18,52 @@ package top.continew.admin.tenant.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaIgnore; -import cn.dev33.satoken.annotation.SaMode; -import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import com.baomidou.dynamic.datasource.annotation.DSTransactional; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -import lombok.AllArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import top.continew.admin.common.base.controller.BaseController; -import top.continew.admin.common.config.properties.TenantProperties; +import top.continew.admin.common.config.TenantProperties; import top.continew.admin.common.util.SecureUtils; -import top.continew.admin.system.model.entity.MenuDO; import top.continew.admin.system.model.entity.user.UserDO; import top.continew.admin.system.model.req.user.UserPasswordResetReq; -import top.continew.admin.system.service.*; +import top.continew.admin.system.service.UserService; import top.continew.admin.tenant.model.entity.TenantDO; import top.continew.admin.tenant.model.query.TenantQuery; -import top.continew.admin.tenant.model.req.TenantLoginUserInfoReq; +import top.continew.admin.tenant.model.req.TenantAdminUserPwdUpdateReq; import top.continew.admin.tenant.model.req.TenantReq; -import top.continew.admin.tenant.model.resp.*; -import top.continew.admin.tenant.service.TenantDbConnectService; -import top.continew.admin.tenant.service.TenantPackageService; +import top.continew.admin.tenant.model.resp.TenantCommonResp; +import top.continew.admin.tenant.model.resp.TenantDetailResp; +import top.continew.admin.tenant.model.resp.TenantResp; import top.continew.admin.tenant.service.TenantService; import top.continew.starter.core.util.ExceptionUtils; -import top.continew.starter.core.util.validation.CheckUtils; import top.continew.starter.core.util.validation.ValidationUtils; import top.continew.starter.extension.crud.annotation.CrudRequestMapping; import top.continew.starter.extension.crud.enums.Api; -import top.continew.starter.extension.crud.model.entity.BaseIdDO; -import top.continew.admin.common.base.model.resp.BaseResp; -import top.continew.starter.extension.crud.model.req.IdsReq; -import top.continew.starter.extension.crud.model.resp.IdResp; import top.continew.starter.extension.tenant.TenantHandler; -import java.util.List; - /** * 租户管理 API * * @author 小熊 + * @author Charles7c * @since 2024/11/26 17:20 */ @Tag(name = "租户管理 API") @RestController -@AllArgsConstructor -@CrudRequestMapping(value = "/tenant/user", api = {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE}) +@RequiredArgsConstructor +@CrudRequestMapping(value = "/tenant/management", api = {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE}) public class TenantController extends BaseController { private final TenantProperties tenantProperties; - private final DeptService deptService; - private final MenuService menuService; - private final TenantPackageService packageService; - private final RoleService roleService; private final UserService userService; - private final TenantSysDataService tenantSysDataService; - private final RoleMenuService roleMenuService; - private final TenantDbConnectService dbConnectService; - @GetMapping("/common") @SaIgnore - @Operation(summary = "多租户通用信息查询", description = "多租户通用信息查询") + @GetMapping("/common") + @Operation(summary = "租户通用信息查询", description = "租户通用信息查询") public TenantCommonResp common() { TenantCommonResp commonResp = new TenantCommonResp(); commonResp.setIsEnabled(tenantProperties.isEnabled()); @@ -90,122 +71,20 @@ public class TenantController extends BaseController create(TenantReq req) { - //套餐菜单 - TenantPackageDetailResp detailResp = packageService.get(req.getPackageId()); - CheckUtils.throwIf(detailResp.getMenuIds().isEmpty(), "该套餐无可用菜单"); - List menuRespList = menuService.listByIds(detailResp.getMenuIds()); - //租户添加 - IdResp baseIdResp = super.create(req); - //在租户中执行数据插入 - SpringUtil.getBean(TenantHandler.class).execute(baseIdResp.getId(), () -> { - //租户部门初始化 - Long deptId = deptService.initTenantDept(req.getName()); - //租户菜单初始化 - menuService.menuInit(menuRespList, 0L, 0L); - //租户角色初始化 - Long roleId = roleService.initTenantRole(); - //角色绑定菜单 - roleMenuService.add(menuService.listAll(baseIdResp.getId()).stream().map(BaseResp::getId).toList(), roleId); - //管理用户初始化 - Long userId = userService.initTenantUser(req.getUsername(), req.getPassword(), deptId); - //用户绑定角色 - roleService.assignToUsers(roleId, ListUtil.of(userId)); - //租户绑定用户 - baseService.bindUser(baseIdResp.getId(), userId); - }); - return baseIdResp; - } - - @Override - public void delete(Long id) { - SpringUtil.getBean(TenantHandler.class).execute(id, () -> { - //系统数据清除 - tenantSysDataService.clear(); - }); - super.delete(id); - } - - @Override - public void batchDelete(@Valid IdsReq ids) { - for (Long id : ids.getIds()) { - //在租户中执行数据清除 - SpringUtil.getBean(TenantHandler.class).execute(id, () -> { - //系统数据清除 - tenantSysDataService.clear(); - }); - } - super.batchDelete(ids); - } - - /** - * 获取租户管理账号用户名 - */ - @GetMapping("/loginUser/{tenantId}") - @Operation(summary = "获取租户管理账号信息", description = "获取租户管理账号信息") - @SaCheckPermission("tenant:user:editLoginUserInfo") - public String loginUserInfo(@PathVariable Long tenantId) { - TenantDO tenantDO = baseService.getTenantById(tenantId); - CheckUtils.throwIfNull(tenantDO, "租户不存在"); - StringBuilder username = new StringBuilder(); - SpringUtil.getBean(TenantHandler.class).execute(tenantDO.getId(), () -> { - UserDO userDO = userService.getById(tenantDO.getUserId()); - CheckUtils.throwIfNull(userDO, "租户管理用户不存在"); - username.append(userDO.getUsername()); - }); - return username.toString(); - } - - /** - * 租户管理账号信息更新 - */ - @PutMapping("/loginUser") - @Operation(summary = "租户管理账号信息更新", description = "租户管理账号信息更新") - @SaCheckPermission("tenant:user:editLoginUserInfo") - @DSTransactional - public void editLoginUserInfo(@Validated @RequestBody TenantLoginUserInfoReq req) { - TenantDO tenantDO = baseService.getTenantById(req.getTenantId()); - CheckUtils.throwIfNull(tenantDO, "租户不存在"); - SpringUtil.getBean(TenantHandler.class).execute(tenantDO.getId(), () -> { - UserDO userDO = userService.getById(tenantDO.getUserId()); - CheckUtils.throwIfNull(userDO, "用户不存在"); - //修改用户名 - if (!req.getUsername().equals(userDO.getUsername())) { - userService.update(Wrappers.lambdaUpdate(UserDO.class) - .set(UserDO::getUsername, req.getUsername()) - .eq(BaseIdDO::getId, userDO.getId())); - } - //修改密码 - if (StrUtil.isNotEmpty(req.getPassword())) { - String password = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(req.getPassword())); - ValidationUtils.throwIfNull(password, "新密码解密失败"); - UserPasswordResetReq passwordResetReq = new UserPasswordResetReq(); - passwordResetReq.setNewPassword(password); - userService.resetPassword(passwordResetReq, userDO.getId()); - } + @DSTransactional(rollbackFor = Exception.class) + @Operation(summary = "修改租户管理员密码", description = "修改租户管理员密码") + @SaCheckPermission("tenant:management:updateAdminUserPwd") + @PutMapping("/{id}/admin/pwd") + public void updateAdminUserPwd(@Valid @RequestBody TenantAdminUserPwdUpdateReq req, @PathVariable Long id) { + TenantDO tenant = baseService.getById(id); + String encryptPassword = req.getPassword(); + SpringUtil.getBean(TenantHandler.class).execute(tenant.getId(), () -> { + UserDO user = userService.getById(tenant.getAdminUser()); + String password = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(encryptPassword)); + ValidationUtils.throwIfNull(password, "新密码解密失败"); + UserPasswordResetReq passwordResetReq = new UserPasswordResetReq(); + passwordResetReq.setNewPassword(password); + userService.resetPassword(passwordResetReq, user.getId()); }); } - - /** - * 查询所有租户套餐 - */ - @GetMapping("/all/package") - @Operation(summary = "查询所有租户套餐", description = "查询所有租户套餐") - @SaCheckPermission(value = {"tenant:user:add", "tenant:user:update"}, mode = SaMode.OR) - public List packageList() { - return packageService.list(null, null); - } - - /** - * 查询所有数据库连接 - */ - @GetMapping("/all/dbConnect") - @Operation(summary = "获取租户数据连接列表", description = "获取租户数据连接列表") - @SaCheckPermission(value = {"tenant:user:add", "tenant:user:update"}, mode = SaMode.OR) - public List dbConnectList() { - return dbConnectService.list(null, null); - } - } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/TenantDbConnectController.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/TenantDbConnectController.java deleted file mode 100644 index 8caf9359..00000000 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/TenantDbConnectController.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.admin.tenant.controller; - -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.RestController; -import top.continew.admin.common.base.controller.BaseController; -import top.continew.admin.tenant.model.query.TenantDbConnectQuery; -import top.continew.admin.tenant.model.req.TenantDbConnectReq; -import top.continew.admin.tenant.model.resp.TenantDbConnectDetailResp; -import top.continew.admin.tenant.model.resp.TenantDbConnectResp; -import top.continew.admin.tenant.service.TenantDbConnectService; -import top.continew.starter.extension.crud.annotation.CrudRequestMapping; -import top.continew.starter.extension.crud.enums.Api; - -/** - * 租户数据连接管理 API - * - * @author 小熊 - * @since 2024/12/12 19:13 - */ -@Tag(name = "租户数据连接管理 API") -@RestController -@CrudRequestMapping(value = "/tenant/dbConnect", api = {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE}) -public class TenantDbConnectController extends BaseController {} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/TenantPackageController.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/TenantPackageController.java deleted file mode 100644 index 2b1cdf0b..00000000 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/controller/TenantPackageController.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.admin.tenant.controller; - -import cn.dev33.satoken.annotation.SaCheckPermission; -import cn.hutool.core.lang.tree.Tree; -import cn.hutool.extra.spring.SpringUtil; -import com.baomidou.dynamic.datasource.annotation.DSTransactional; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.AllArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; -import top.continew.admin.common.base.controller.BaseController; -import top.continew.admin.common.config.properties.TenantProperties; -import top.continew.admin.common.constant.CacheConstants; -import top.continew.admin.common.enums.DisEnableStatusEnum; -import top.continew.admin.system.model.entity.MenuDO; -import top.continew.admin.system.model.query.MenuQuery; -import top.continew.admin.system.service.MenuService; -import top.continew.admin.tenant.model.entity.TenantDO; -import top.continew.admin.tenant.model.query.TenantPackageQuery; -import top.continew.admin.tenant.model.req.TenantPackageReq; -import top.continew.admin.tenant.model.resp.TenantPackageDetailResp; -import top.continew.admin.tenant.model.resp.TenantPackageResp; -import top.continew.admin.tenant.service.TenantPackageService; -import top.continew.admin.tenant.service.TenantService; -import top.continew.starter.cache.redisson.util.RedisUtils; -import top.continew.starter.core.constant.StringConstants; -import top.continew.starter.extension.crud.annotation.CrudRequestMapping; -import top.continew.starter.extension.crud.enums.Api; -import top.continew.starter.extension.tenant.TenantHandler; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * 租户套餐管理 API - * - * @author 小熊 - * @since 2024/11/26 11:25 - */ -@Tag(name = "租户套餐管理 API") -@RestController -@AllArgsConstructor -@CrudRequestMapping(value = "/tenant/package", api = {Api.LIST, Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE}) -public class TenantPackageController extends BaseController { - - private final MenuService menuService; - private final TenantProperties tenantProperties; - private final TenantService tenantService; - - @GetMapping("/menuTree") - @SaCheckPermission("tenant:package:get") - @Operation(summary = "获取租户套餐菜单", description = "获取租户套餐菜单") - public List> menuTree() { - MenuQuery query = new MenuQuery(); - //必须是启用状态的菜单 - query.setStatus(DisEnableStatusEnum.ENABLE); - //过滤掉租户不能使用的菜单 - query.setExcludeMenuIdList(tenantProperties.getIgnoreMenus()); - return menuService.tree(query, null, true); - } - - @Override - @DSTransactional - public void update(TenantPackageReq req, Long id) { - //查询套餐对应的租户 - List tenantDOList = tenantService.list(Wrappers.lambdaQuery(TenantDO.class) - .eq(TenantDO::getPackageId, id)); - if (!tenantDOList.isEmpty()) { - TenantPackageDetailResp detail = baseService.get(id); - List oldMenuIds = detail.getMenuIds(); - List newMenuIds = Arrays.stream(req.getMenuIds()).toList(); - //删除的菜单 - List deleteMenuIds = new ArrayList<>(oldMenuIds); - deleteMenuIds.removeAll(newMenuIds); - //如果有删除的菜单则绑定了套餐的租户对应的菜单也会删除 - if (!deleteMenuIds.isEmpty()) { - List deleteMenus = menuService.listByIds(deleteMenuIds); - tenantDOList.forEach(tenantDO -> SpringUtil.getBean(TenantHandler.class) - .execute(tenantDO.getId(), () -> menuService.deleteTenantMenus(deleteMenus))); - } - //新增的菜单 - List addMenuIds = new ArrayList<>(newMenuIds); - addMenuIds.removeAll(oldMenuIds); - //如果有新增的菜单则绑定了套餐的租户对应的菜单也会新增 - if (!addMenuIds.isEmpty()) { - List addMenus = menuService.listByIds(addMenuIds); - for (MenuDO addMenu : addMenus) { - MenuDO pMenu = addMenu.getParentId() != 0 ? menuService.getById(addMenu.getParentId()) : null; - tenantDOList.forEach(tenantDO -> SpringUtil.getBean(TenantHandler.class) - .execute(tenantDO.getId(), () -> menuService.addTenantMenu(addMenu, pMenu))); - } - RedisUtils.deleteByPattern(CacheConstants.ROLE_MENU_KEY_PREFIX + StringConstants.ASTERISK); - } - } - super.update(req, id); - } -} \ No newline at end of file diff --git a/continew-system/src/main/java/top/continew/admin/system/service/TenantSysDataService.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/handler/TenantDataHandler.java similarity index 65% rename from continew-system/src/main/java/top/continew/admin/system/service/TenantSysDataService.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/handler/TenantDataHandler.java index 48016d5c..6ffa5a62 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/TenantSysDataService.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/handler/TenantDataHandler.java @@ -14,18 +14,28 @@ * limitations under the License. */ -package top.continew.admin.system.service; +package top.continew.admin.tenant.handler; + +import top.continew.admin.tenant.model.req.TenantReq; /** - * @description: 多租户系统数据接口 - * @author: 小熊 - * @create: 2024-12-02 20:08 + * 租户数据处理器 + * + * @author 小熊 + * @author Charles7c + * @since 2024/12/2 20:08 */ -public interface TenantSysDataService { +public interface TenantDataHandler { /** - * 清除所有系统数据 + * 初始化数据 + * + * @param tenant 租户信息 + */ + void init(TenantReq tenant); + + /** + * 清除数据 */ void clear(); - } diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/handler/TenantDataHandlerForSystem.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/handler/TenantDataHandlerForSystem.java new file mode 100644 index 00000000..c8d48ff9 --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/handler/TenantDataHandlerForSystem.java @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.handler; + +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.ReUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import top.continew.admin.common.constant.RegexConstants; +import top.continew.admin.common.constant.SysConstants; +import top.continew.admin.common.enums.DataScopeEnum; +import top.continew.admin.common.enums.DisEnableStatusEnum; +import top.continew.admin.common.enums.GenderEnum; +import top.continew.admin.common.util.SecureUtils; +import top.continew.admin.system.mapper.*; +import top.continew.admin.system.mapper.user.UserMapper; +import top.continew.admin.system.mapper.user.UserPasswordHistoryMapper; +import top.continew.admin.system.mapper.user.UserSocialMapper; +import top.continew.admin.system.model.entity.DeptDO; +import top.continew.admin.system.model.entity.MenuDO; +import top.continew.admin.system.model.entity.RoleDO; +import top.continew.admin.system.model.entity.user.UserDO; +import top.continew.admin.system.service.FileService; +import top.continew.admin.system.service.RoleMenuService; +import top.continew.admin.system.service.RoleService; +import top.continew.admin.tenant.constant.TenantCacheConstants; +import top.continew.admin.tenant.mapper.TenantMapper; +import top.continew.admin.tenant.model.entity.TenantDO; +import top.continew.admin.tenant.model.req.TenantReq; +import top.continew.admin.tenant.service.PackageMenuService; +import top.continew.starter.cache.redisson.util.RedisUtils; +import top.continew.starter.core.util.ExceptionUtils; +import top.continew.starter.core.util.validation.ValidationUtils; +import top.continew.starter.extension.crud.model.entity.BaseIdDO; +import top.continew.starter.extension.tenant.TenantHandler; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 租户数据处理器 + * + * @author 小熊 + * @author Charles7c + * @since 2024/12/2 20:12 + */ +@Service +@RequiredArgsConstructor +public class TenantDataHandlerForSystem implements TenantDataHandler { + + private final PackageMenuService packageMenuService; + private final DeptMapper deptMapper; + private final MenuMapper menuMapper; + private final RoleMapper roleMapper; + private final RoleMenuService roleMenuService; + private final RoleMenuMapper roleMenuMapper; + private final RoleService roleService; + private final TenantMapper tenantMapper; + private final FileService fileService; + private final LogMapper logMapper; + private final MessageMapper messageMapper; + private final MessageMapper messageUserMapper; + private final NoticeMapper noticeMapper; + private final RoleDeptMapper roleDeptMapper; + private final UserMapper userMapper; + private final UserPasswordHistoryMapper userPasswordHistoryMapper; + private final UserRoleMapper userRoleMapper; + private final UserSocialMapper userSocialMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public void init(TenantReq tenant) { + Long tenantId = tenant.getId(); + SpringUtil.getBean(TenantHandler.class).execute(tenantId, () -> { + // 初始化部门 + Long deptId = this.initDeptData(tenant); + // 初始化菜单 + List menuIds = packageMenuService.listMenuIdsByPackageId(tenant.getPackageId()); + List menuList = menuMapper.lambdaQuery().in(MenuDO::getId, menuIds).list(); + this.initMenuData(menuList, 0L, 0L); + // 初始化角色 + Long roleId = this.initRoleData(tenant); + // 角色绑定菜单 + roleMenuService.add(menuIds, roleId); + // 初始化管理用户 + Long userId = this.initUserData(tenant, deptId); + // 用户绑定角色 + roleService.assignToUsers(roleId, ListUtil.of(userId)); + // 租户绑定用户 + this.bindTenantUser(tenantId, userId); + }); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void clear() { + // 退出所有用户 + List userList = userMapper.selectList(null); + for (UserDO user : userList) { + StpUtil.logout(user.getId()); + } + Wrapper dw = Wrappers.query().eq("1", 1); + // 部门清除 + deptMapper.delete(dw); + // 文件清除 + List fileIds = fileService.list().stream().map(BaseIdDO::getId).toList(); + if (!fileIds.isEmpty()) { + fileService.delete(fileIds); + } + // 日志清除 + logMapper.delete(dw); + // 菜单清除 + menuMapper.delete(dw); + // 消息清除 + messageMapper.delete(dw); + messageUserMapper.delete(dw); + // 通知清除 + noticeMapper.delete(dw); + // 角色相关数据清除 + roleMapper.delete(dw); + roleDeptMapper.delete(dw); + roleMenuMapper.delete(dw); + // 用户数据清除 + userMapper.delete(dw); + userPasswordHistoryMapper.delete(dw); + userRoleMapper.delete(dw); + userSocialMapper.delete(dw); + } + + /** + * 初始化部门数据 + * + * @param tenant 租户信息 + * @return 部门 ID + */ + private Long initDeptData(TenantReq tenant) { + DeptDO dept = new DeptDO(); + dept.setName(tenant.getName()); + dept.setParentId(SysConstants.SUPER_PARENT_ID); + dept.setAncestors("0"); + dept.setDescription("系统初始部门"); + dept.setSort(1); + dept.setStatus(DisEnableStatusEnum.ENABLE); + deptMapper.insert(dept); + return dept.getId(); + } + + /** + * 递归初始化菜单数据 + * + * @param menuList 菜单列表 + * @param oldParentId 旧父级 ID + * @param newParentId 新父级 ID + */ + private void initMenuData(List menuList, Long oldParentId, Long newParentId) { + List children = menuList.stream().filter(menuDO -> menuDO.getParentId().equals(oldParentId)).toList(); + for (MenuDO menu : children) { + Long oldId = menu.getId(); + menu.setId(null); + menu.setParentId(newParentId); + menuMapper.insert(menu); + initMenuData(menuList, oldId, menu.getId()); + } + } + + /** + * 初始化角色数据 + * + * @param tenant 租户信息 + * @return 角色 ID + */ + private Long initRoleData(TenantReq tenant) { + RoleDO role = new RoleDO(); + role.setName("系统管理员"); + role.setCode(SysConstants.TENANT_ADMIN_ROLE_CODE); + role.setDataScope(DataScopeEnum.ALL); + role.setDescription("系统初始角色"); + role.setSort(1); + role.setIsSystem(true); + role.setMenuCheckStrictly(true); + role.setDeptCheckStrictly(true); + roleMapper.insert(role); + return role.getId(); + } + + /** + * 初始化用户数据 + * + * @param tenant 租户信息 + * @param deptId 部门 ID + * @return 用户 ID + */ + private Long initUserData(TenantReq tenant, Long deptId) { + // 解密密码 + String rawPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(tenant.getPassword())); + ValidationUtils.throwIfNull(rawPassword, "密码解密失败"); + ValidationUtils.throwIf(!ReUtil + .isMatch(RegexConstants.PASSWORD, rawPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字"); + // 初始化用户 + UserDO user = new UserDO(); + user.setUsername(tenant.getUsername()); + user.setNickname("系统管理员"); + user.setPassword(rawPassword); + user.setGender(GenderEnum.UNKNOWN); + user.setDescription("系统初始用户"); + user.setStatus(DisEnableStatusEnum.ENABLE); + user.setIsSystem(true); + user.setPwdResetTime(LocalDateTime.now()); + user.setDeptId(deptId); + userMapper.insert(user); + return user.getId(); + } + + /** + * 绑定租户管理员用户 + * + * @param tenantId 租户 ID + * @param userId 用户 ID + */ + public void bindTenantUser(Long tenantId, Long userId) { + tenantMapper.lambdaUpdate().set(TenantDO::getAdminUser, userId).eq(BaseIdDO::getId, tenantId).update(); + // 更新租户缓存 + TenantDO entity = tenantMapper.selectById(tenantId); + RedisUtils.set(TenantCacheConstants.TENANT_KEY_PREFIX + tenantId, entity); + } +} diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/TenantDbConnectMapper.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/DatasourceMapper.java similarity index 79% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/TenantDbConnectMapper.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/DatasourceMapper.java index d7bd685e..c747396e 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/TenantDbConnectMapper.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/DatasourceMapper.java @@ -16,13 +16,15 @@ package top.continew.admin.tenant.mapper; -import top.continew.admin.tenant.model.entity.TenantDbConnectDO; +import org.apache.ibatis.annotations.Mapper; +import top.continew.admin.tenant.model.entity.DatasourceDO; import top.continew.starter.data.mapper.BaseMapper; /** - * 租户数据连接 Mapper + * 数据源 Mapper * * @author 小熊 * @since 2024/12/12 19:13 */ -public interface TenantDbConnectMapper extends BaseMapper {} \ No newline at end of file +@Mapper +public interface DatasourceMapper extends BaseMapper {} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/TenantPackageMapper.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/PackageMapper.java similarity index 80% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/TenantPackageMapper.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/PackageMapper.java index b42e6f50..b51aca7f 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/TenantPackageMapper.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/PackageMapper.java @@ -16,14 +16,16 @@ package top.continew.admin.tenant.mapper; +import org.apache.ibatis.annotations.Mapper; import top.continew.starter.data.mapper.BaseMapper; -import top.continew.admin.tenant.model.entity.TenantPackageDO; +import top.continew.admin.tenant.model.entity.PackageDO; /** - * 租户套餐 Mapper + * 套餐 Mapper * * @author 小熊 * @since 2024/11/26 11:25 */ -public interface TenantPackageMapper extends BaseMapper { +@Mapper +public interface PackageMapper extends BaseMapper { } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/PackageMenuMapper.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/PackageMenuMapper.java new file mode 100644 index 00000000..1d7934fa --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/PackageMenuMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.mapper; + +import org.apache.ibatis.annotations.Mapper; +import top.continew.admin.tenant.model.entity.PackageMenuDO; +import top.continew.starter.data.mapper.BaseMapper; + +/** + * 套餐和菜单关联 Mapper + * + * @author Charles7c + * @since 2025/7/13 20:24 + */ +@Mapper +public interface PackageMenuMapper extends BaseMapper { +} diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/TenantMapper.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/TenantMapper.java index cc422f96..67f99e6d 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/TenantMapper.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/mapper/TenantMapper.java @@ -16,16 +16,8 @@ package top.continew.admin.tenant.mapper; -import com.baomidou.dynamic.datasource.annotation.DS; -import com.baomidou.mybatisplus.core.conditions.Wrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.core.toolkit.Constants; import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; -import top.continew.admin.common.constant.SysConstants; import top.continew.admin.tenant.model.entity.TenantDO; -import top.continew.admin.tenant.model.resp.TenantResp; import top.continew.starter.data.mapper.BaseMapper; /** @@ -34,11 +26,6 @@ import top.continew.starter.data.mapper.BaseMapper; * @author 小熊 * @since 2024/11/26 17:20 */ -@DS(SysConstants.DEFAULT_DATASOURCE) @Mapper public interface TenantMapper extends BaseMapper { - - @Select("SELECT sys_tenant.*,sys_tenant_package.`name` as package_name FROM sys_tenant\n" + "LEFT JOIN sys_tenant_package ON sys_tenant.package_id = sys_tenant_package.id\n" + "${ew.getCustomSqlSegment}") - IPage listTenant(IPage page, @Param(Constants.WRAPPER) Wrapper wrapper); - } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/TenantDbConnectDO.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/DatasourceDO.java similarity index 66% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/TenantDbConnectDO.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/DatasourceDO.java index d5fbab31..f4f711f4 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/TenantDbConnectDO.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/DatasourceDO.java @@ -19,49 +19,60 @@ package top.continew.admin.tenant.model.entity; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import top.continew.admin.common.base.model.entity.BaseDO; +import top.continew.admin.tenant.model.enums.DatasourceDatabaseTypeEnum; +import top.continew.starter.extension.crud.annotation.DictModel; +import top.continew.starter.security.crypto.annotation.FieldEncrypt; import java.io.Serial; /** - * 租户数据连接实体 + * 数据源实体 * * @author 小熊 + * @since Charles7c * @since 2024/12/12 19:13 */ @Data -@TableName("sys_tenant_db_connect") -public class TenantDbConnectDO extends BaseDO { +@DictModel +@TableName("tenant_datasource") +public class DatasourceDO extends BaseDO { @Serial private static final long serialVersionUID = 1L; /** - * 连接名称 + * 名称 */ - private String connectName; + private String name; /** - * 连接类型 + * 数据库类型 */ - private Integer type; + private DatasourceDatabaseTypeEnum databaseType; /** - * 连接主机地址 + * 主机 */ private String host; /** - * 连接端口 + * 端口 */ private Integer port; /** - * 连接用户名 + * 用户名 */ private String username; /** - * 连接密码 + * 密码 */ + @FieldEncrypt private String password; + + /** + * 描述 + */ + private String description; } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/TenantPackageDO.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/PackageDO.java similarity index 73% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/TenantPackageDO.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/PackageDO.java index aa5bea91..b4d7a566 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/TenantPackageDO.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/PackageDO.java @@ -16,35 +16,38 @@ package top.continew.admin.tenant.model.entity; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import top.continew.admin.common.base.model.entity.BaseDO; +import top.continew.admin.common.enums.DisEnableStatusEnum; +import top.continew.starter.extension.crud.annotation.DictModel; + import java.io.Serial; -import lombok.Data; - -import com.baomidou.mybatisplus.annotation.TableName; -import top.continew.admin.common.base.model.entity.BaseDO; - /** - * 租户套餐实体 + * 套餐实体 * * @author 小熊 + * @author Charles7c * @since 2024/11/26 11:25 */ @Data -@TableName("sys_tenant_package") -public class TenantPackageDO extends BaseDO { +@DictModel +@TableName("tenant_package") +public class PackageDO extends BaseDO { @Serial private static final long serialVersionUID = 1L; /** - * 套餐名称 + * 名称 */ private String name; /** - * 关联的菜单ids + * 排序 */ - private String menuIds; + private Integer sort; /** * 菜单选择是否父子节点关联 @@ -52,7 +55,12 @@ public class TenantPackageDO extends BaseDO { private Boolean menuCheckStrictly; /** - * 状态(1:启用;2:禁用) + * 描述 */ - private Integer status; + private String description; + + /** + * 状态 + */ + private DisEnableStatusEnum status; } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/PackageMenuDO.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/PackageMenuDO.java new file mode 100644 index 00000000..64b2bcc0 --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/PackageMenuDO.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.model.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 套餐和菜单关联实体 + * + * @author Charles7c + * @since 2025/7/11 22:01 + */ +@Data +@NoArgsConstructor +@TableName("tenant_package_menu") +public class PackageMenuDO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 套餐 ID + */ + private Long packageId; + + /** + * 菜单 ID + */ + private Long menuId; + + public PackageMenuDO(Long packageId, Long menuId) { + this.packageId = packageId; + this.menuId = menuId; + } +} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/TenantDO.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/TenantDO.java index f7576a17..d05e78e8 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/TenantDO.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/entity/TenantDO.java @@ -19,6 +19,8 @@ package top.continew.admin.tenant.model.entity; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import top.continew.admin.common.base.model.entity.BaseDO; +import top.continew.admin.common.enums.DisEnableStatusEnum; +import top.continew.admin.tenant.model.enums.TenantIsolationLevelEnum; import java.io.Serial; import java.time.LocalDateTime; @@ -27,57 +29,63 @@ import java.time.LocalDateTime; * 租户实体 * * @author 小熊 + * @author Charles7c * @since 2024/11/26 17:20 */ @Data -@TableName("sys_tenant") +@TableName("tenant") public class TenantDO extends BaseDO { @Serial private static final long serialVersionUID = 1L; /** - * 租户名称 + * 名称 */ private String name; /** - * 绑定的域名 + * 编码 + */ + private String code; + + /** + * 域名 */ private String domain; /** - * 租户套餐编号 - */ - private Long packageId; - - /** - * 状态(1:启用;2:禁用) - */ - private Integer status; - - /** - * 租户过期时间 + * 过期时间 */ private LocalDateTime expireTime; - /** - * 用户ID - */ - private Long userId; - - /** - * 租户编号 - */ - private String tenantSn; - /** * 隔离级别 */ - private Integer isolationLevel; + private TenantIsolationLevelEnum isolationLevel; /** - * 数据连接ID + * 描述 */ - private Long dbConnectId; + private String description; + + /** + * 状态 + */ + private DisEnableStatusEnum status; + + /** + * 租户管理员 + */ + private Long adminUser; + + /** + * 套餐 ID + */ + private Long packageId; + + /** + * 数据源 ID + */ + private Long datasourceId; } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/enums/DatasourceDatabaseTypeEnum.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/enums/DatasourceDatabaseTypeEnum.java new file mode 100644 index 00000000..f1de6a19 --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/enums/DatasourceDatabaseTypeEnum.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.model.enums; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.URLUtil; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.jdbc.DataSourceBuilder; +import top.continew.admin.tenant.model.req.DatasourceReq; +import top.continew.starter.core.constant.StringConstants; +import top.continew.starter.core.enums.BaseEnum; +import top.continew.starter.core.exception.BusinessException; + +import javax.sql.DataSource; +import java.nio.charset.StandardCharsets; +import java.sql.Connection; +import java.util.Map; + +/** + * 数据源数据库类型枚举 + * + * @author Charles7c + * @author 小熊 + * @since 2024/11/26 17:20 + */ +@Slf4j +@Getter +@RequiredArgsConstructor +public enum DatasourceDatabaseTypeEnum implements BaseEnum { + + /** + * MySQL + */ + MYSQL(1, "MySQL", "com.mysql.cj.jdbc.Driver") { + @Override + public DataSource buildDataSource(DatasourceReq datasource) { + return DataSourceBuilder.create() + .url(this.getJdbcUrl(datasource, null)) + .driverClassName(this.getDriverClassName()) + .username(datasource.getUsername()) + .password(datasource.getPassword()) + .build(); + } + + @Override + public void testConnection(DatasourceReq datasource) { + DataSource dataSource = this.buildDataSource(datasource); + try (Connection ignored = dataSource.getConnection()) { + log.info("数据源 [{}] 测试连接成功", datasource.getName()); + } catch (Exception e) { + throw new BusinessException("数据源 [%s] 测试连接失败".formatted(datasource.getName())); + } + } + + @Override + public String getJdbcUrl(DatasourceReq datasource, String databaseName) { + StringBuilder urlBuilder = new StringBuilder("jdbc:mysql://%s:%s".formatted(datasource.getHost(), datasource + .getPort())); + if (StrUtil.isNotBlank(databaseName)) { + urlBuilder.append(StringConstants.SLASH).append(databaseName); + urlBuilder.append(StringConstants.QUESTION_MARK); + urlBuilder.append(URLUtil.buildQuery(this.getDefaultParameters(), StandardCharsets.UTF_8)); + } + return urlBuilder.toString(); + } + + @Override + public Map getDefaultParameters() { + Map parameter = MapUtil.newHashMap(8); + parameter.put("serverTimezone", "Asia/Shanghai"); + parameter.put("useSSL", "true"); + parameter.put("useUnicode", "true"); + parameter.put("characterEncoding", "utf8"); + parameter.put("rewriteBatchedStatements", "true"); + parameter.put("autoReconnect", "true"); + parameter.put("allowPublicKeyRetrieval", "true"); + parameter.put("nullCatalogMeansCurrent", "true"); + return parameter; + } + }; + + private final Integer value; + private final String description; + private final String driverClassName; + + /** + * 构建数据源 + * + * @param datasource 数据源配置 + * @return 数据源 + */ + public abstract DataSource buildDataSource(DatasourceReq datasource); + + /** + * 测试连接 + * + * @param datasource 数据源配置 + */ + public abstract void testConnection(DatasourceReq datasource); + + /** + * 获取 JDBC URL + * + * @param datasource 数据源配置 + * @param databaseName 数据库名称 + * @return JDBC URL + */ + public abstract String getJdbcUrl(DatasourceReq datasource, String databaseName); + + /** + * 获取默认数据库连接参数 + * + * @return 默认数据库连接参数 + */ + public abstract Map getDefaultParameters(); +} diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/enums/TenantIsolationLevelEnum.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/enums/TenantIsolationLevelEnum.java new file mode 100644 index 00000000..a8e73bb7 --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/enums/TenantIsolationLevelEnum.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.model.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import top.continew.starter.core.enums.BaseEnum; +import top.continew.starter.extension.tenant.enums.TenantIsolationLevel; + +/** + * 租户隔离级别枚举 + * + * @author Charles7c + * @since 2025/7/14 20:31 + */ +@Slf4j +@Getter +@RequiredArgsConstructor +public enum TenantIsolationLevelEnum implements BaseEnum { + + /** + * 行级 + */ + LINE(1, "行级", TenantIsolationLevel.LINE), + + /** + * 数据源级 + */ + DATASOURCE(2, "数据源级", TenantIsolationLevel.DATASOURCE); + + private final Integer value; + private final String description; + private final TenantIsolationLevel level; +} diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/TenantDbConnectQuery.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/DatasourceQuery.java similarity index 76% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/TenantDbConnectQuery.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/DatasourceQuery.java index b89d0651..5ff455be 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/TenantDbConnectQuery.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/DatasourceQuery.java @@ -16,34 +16,32 @@ package top.continew.admin.tenant.model.query; -import java.io.Serial; -import java.io.Serializable; -import java.time.*; - -import lombok.Data; - import io.swagger.v3.oas.annotations.media.Schema; - +import lombok.Data; import top.continew.starter.data.annotation.Query; import top.continew.starter.data.enums.QueryType; +import java.io.Serial; +import java.io.Serializable; + /** - * 租户数据连接查询条件 + * 数据源查询条件 * * @author 小熊 + * @author Charles7c * @since 2024/12/12 19:13 */ @Data -@Schema(description = "租户数据连接查询条件") -public class TenantDbConnectQuery implements Serializable { +@Schema(description = "数据源查询条件") +public class DatasourceQuery implements Serializable { @Serial private static final long serialVersionUID = 1L; /** - * 连接名称 + * 关键词 */ - @Schema(description = "连接名称") - @Query(type = QueryType.EQ) - private String connectName; + @Schema(description = "关键词", example = "数据源") + @Query(columns = {"name", "description"}, type = QueryType.LIKE) + private String description; } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/TenantPackageQuery.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/PackageQuery.java similarity index 69% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/TenantPackageQuery.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/PackageQuery.java index 0c5b5121..8922906f 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/TenantPackageQuery.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/PackageQuery.java @@ -16,40 +16,40 @@ package top.continew.admin.tenant.model.query; -import java.io.Serial; -import java.io.Serializable; -import java.time.*; - -import lombok.Data; - import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import top.continew.admin.common.enums.DisEnableStatusEnum; import top.continew.starter.data.annotation.Query; import top.continew.starter.data.enums.QueryType; +import java.io.Serial; +import java.io.Serializable; + /** - * 租户套餐查询条件 + * 套餐查询条件 * * @author 小熊 + * @author Charles7c * @since 2024/11/26 11:25 */ @Data -@Schema(description = "租户套餐查询条件") -public class TenantPackageQuery implements Serializable { +@Schema(description = "套餐查询条件") +public class PackageQuery implements Serializable { @Serial private static final long serialVersionUID = 1L; /** - * 套餐名称 + * 关键词 */ - @Schema(description = "套餐名称") - @Query(type = QueryType.EQ) - private String name; + @Schema(description = "关键词", example = "初级套餐") + @Query(columns = {"name", "description"}, type = QueryType.LIKE) + private String description; /** - * 状态(1:启用;2:禁用) + * 状态 */ - @Schema(description = "状态(1:启用;2:禁用)") + @Schema(description = "状态", example = "1") @Query(type = QueryType.EQ) - private Integer status; + private DisEnableStatusEnum status; } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/TenantQuery.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/TenantQuery.java index 98d5a652..e6ff5eaa 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/TenantQuery.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/query/TenantQuery.java @@ -28,6 +28,7 @@ import java.io.Serializable; * 租户查询条件 * * @author 小熊 + * @author Charles7c * @since 2024/11/26 17:20 */ @Data @@ -38,17 +39,16 @@ public class TenantQuery implements Serializable { private static final long serialVersionUID = 1L; /** - * 租户名称 + * 关键词 */ - @Schema(description = "租户名称") - @Query(type = QueryType.LIKE) - private String name; + @Schema(description = "关键词", example = "T0001") + @Query(columns = {"name", "description"}, type = QueryType.LIKE) + private String description; /** - * 租户套餐编号 + * 套餐 ID */ - @Schema(description = "租户套餐编号") + @Schema(description = "套餐 ID", example = "1") @Query(type = QueryType.EQ) private Long packageId; - } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/DatasourceReq.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/DatasourceReq.java new file mode 100644 index 00000000..7400fb2a --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/DatasourceReq.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.model.req; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.Length; +import top.continew.admin.tenant.model.enums.DatasourceDatabaseTypeEnum; +import top.continew.starter.extension.crud.validation.CrudValidationGroup; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 数据源创建或修改请求参数 + * + * @author 小熊 + * @author Charles7c + * @since 2024/12/12 19:13 + */ +@Data +@Schema(description = "数据源创建或修改请求参数") +public class DatasourceReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 名称 + */ + @Schema(description = "名称", example = "T0001数据源") + @NotBlank(message = "名称不能为空") + @Length(max = 30, message = "名称长度不能超过 {max} 个字符") + private String name; + + /** + * 数据库类型 + */ + @Schema(description = "数据库类型", example = "1") + @NotNull(message = "数据库类型无效") + private DatasourceDatabaseTypeEnum databaseType; + + /** + * 主机 + */ + @Schema(description = "主机", example = "123.56.195.68") + @NotBlank(message = "主机不能为空") + @Length(max = 128, message = "主机长度不能超过 {max} 个字符") + private String host; + + /** + * 端口 + */ + @Schema(description = "端口", example = "3306") + @NotNull(message = "端口不能为空") + private Integer port; + + /** + * 用户名 + */ + @Schema(description = "用户名", example = "root") + @NotBlank(message = "用户名不能为空") + @Length(max = 128, message = "用户名长度不能超过 {max} 个字符") + private String username; + + /** + * 密码 + */ + @Schema(description = "密码", example = "jXo1Mwsuoz+XhLy6tOhdzbTJ3gIDxciTAnCjcOO8akglghVDO3jR5pqOp95LkSBp1Yd9bltYzWDNjNvL6yD3TQ==") + @NotBlank(message = "密码不能为空", groups = CrudValidationGroup.Create.class) + private String password; + + /** + * 描述 + */ + @Schema(description = "描述", example = "T0001数据源描述") + @Length(max = 200, message = "描述长度不能超过 {max} 个字符") + private String description; +} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantPackageReq.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/PackageReq.java similarity index 53% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantPackageReq.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/PackageReq.java index 02713d75..9cb16efa 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantPackageReq.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/PackageReq.java @@ -16,61 +16,67 @@ package top.continew.admin.tenant.model.req; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.hibernate.validator.constraints.Length; +import top.continew.admin.common.enums.DisEnableStatusEnum; + import java.io.Serial; import java.io.Serializable; -import java.time.*; - -import jakarta.validation.constraints.*; - -import lombok.Data; - -import io.swagger.v3.oas.annotations.media.Schema; - -import org.hibernate.validator.constraints.Length; +import java.util.ArrayList; +import java.util.List; /** - * 创建或修改租户套餐参数 + * 套餐创建或修改请求参数 * * @author 小熊 + * @author Charles7c * @since 2024/11/26 11:25 */ @Data -@Schema(description = "创建或修改租户套餐参数") -public class TenantPackageReq implements Serializable { +@Schema(description = "套餐创建或修改请求参数") +public class PackageReq implements Serializable { @Serial private static final long serialVersionUID = 1L; /** - * 套餐名称 + * 名称 */ - @Schema(description = "套餐名称") - @NotBlank(message = "套餐名称不能为空") - @Length(max = 64, message = "套餐名称长度不能超过 {max} 个字符") + @Schema(description = "名称", example = "初级套餐") + @NotBlank(message = "名称不能为空") + @Length(max = 30, message = "名称长度不能超过 {max} 个字符") private String name; /** - * 关联的菜单ids + * 排序 */ - @Schema(description = "关联的菜单ids") - private Long[] menuIds; + @Schema(description = "排序", example = "1") + private Integer sort; /** * 菜单选择是否父子节点关联 */ - @Schema(description = "菜单选择是否父子节点关联") + @Schema(description = "菜单选择是否父子节点关联", example = "true") private Boolean menuCheckStrictly; + /** + * 描述 + */ + @Schema(description = "描述", example = "初级套餐描述") + @Length(max = 200, message = "描述长度不能超过 {max} 个字符") + private String description; + /** * 状态 */ - @Schema(description = "状态") - @NotNull(message = "状态不能为空") - private Integer status; + @Schema(description = "状态", example = "1") + private DisEnableStatusEnum status; /** - * ID + * 关联的菜单 ID 列表 */ - @Schema(hidden = true) - private Long id; + @Schema(description = "关联的菜单 ID 列表", example = "[1000, 1010, 1011]") + private List menuIds = new ArrayList<>(); } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantLoginUserInfoReq.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantAdminUserPwdUpdateReq.java similarity index 59% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantLoginUserInfoReq.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantAdminUserPwdUpdateReq.java index f58377f4..6f755c89 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantLoginUserInfoReq.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantAdminUserPwdUpdateReq.java @@ -17,40 +17,24 @@ package top.continew.admin.tenant.model.req; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; import lombok.Data; import java.io.Serializable; /** - * @description: 租户登录用户信息 - * @author: 小熊 - * @create: 2024-12-02 20:41 + * 租户管理员密码修改请求参数 + * + * @author 小熊 + * @since 2024/12/2 20:41 */ @Data -public class TenantLoginUserInfoReq implements Serializable { +@Schema(description = "租户管理员密码修改请求参数") +public class TenantAdminUserPwdUpdateReq implements Serializable { /** - * 租户id - */ - @NotNull(message = "租户ID不能为空") - private Long tenantId; - - /** - * 登录用户名 - */ - @NotEmpty(message = "登录用户名不能为空") - private String username; - - /** - * 登录密码 + * 新密码 */ + @NotBlank(message = "新密码不能为空") private String password; - - /** - * ID - */ - @Schema(hidden = true) - private Long id; } diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantDbConnectReq.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantDbConnectReq.java deleted file mode 100644 index 40120d6f..00000000 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantDbConnectReq.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.admin.tenant.model.req; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.Data; -import org.hibernate.validator.constraints.Length; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 创建或修改租户数据连接参数 - * - * @author 小熊 - * @since 2024/12/12 19:13 - */ -@Data -@Schema(description = "创建或修改租户数据连接参数") -public class TenantDbConnectReq implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 连接名称 - */ - @Schema(description = "连接名称") - @NotBlank(message = "连接名称不能为空") - @Length(max = 128, message = "连接名称长度不能超过 {max} 个字符") - private String connectName; - - /** - * 连接类型 - */ - @Schema(description = "连接类型") - @NotNull(message = "连接类型不能为空") - private Integer type; - - /** - * 连接主机地址 - */ - @Schema(description = "连接主机地址") - @NotBlank(message = "连接主机地址不能为空") - @Length(max = 128, message = "连接主机地址长度不能超过 {max} 个字符") - private String host; - - /** - * 连接端口 - */ - @Schema(description = "连接端口") - @NotNull(message = "连接端口不能为空") - private Integer port; - - /** - * 连接用户名 - */ - @Schema(description = "连接用户名") - @NotBlank(message = "连接用户名不能为空") - @Length(max = 128, message = "连接用户名长度不能超过 {max} 个字符") - private String username; - - /** - * 连接密码 - */ - @Schema(description = "连接密码") - @NotBlank(message = "连接密码不能为空") - @Length(max = 128, message = "连接密码长度不能超过 {max} 个字符") - private String password; - - /** - * ID - */ - @Schema(hidden = true) - private Long id; -} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantReq.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantReq.java index 3159698b..3e2dedb8 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantReq.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/req/TenantReq.java @@ -16,6 +16,8 @@ package top.continew.admin.tenant.model.req; +import cn.sticki.spel.validator.constrain.SpelNotNull; +import cn.sticki.spel.validator.jakarta.SpelValid; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Future; import jakarta.validation.constraints.NotBlank; @@ -24,6 +26,8 @@ import jakarta.validation.constraints.Pattern; import lombok.Data; import org.hibernate.validator.constraints.Length; import top.continew.admin.common.constant.RegexConstants; +import top.continew.admin.common.enums.DisEnableStatusEnum; +import top.continew.admin.tenant.model.enums.TenantIsolationLevelEnum; import top.continew.starter.extension.crud.validation.CrudValidationGroup; import java.io.Serial; @@ -31,53 +35,75 @@ import java.io.Serializable; import java.time.LocalDateTime; /** - * 创建或修改租户参数 + * 租户创建或修改请求参数 * * @author 小熊 + * @author Charles7c * @since 2024/11/26 17:20 */ @Data -@Schema(description = "创建或修改租户参数") +@SpelValid +@Schema(description = "租户创建或修改请求参数") public class TenantReq implements Serializable { @Serial private static final long serialVersionUID = 1L; /** - * 租户名称 + * 名称 */ - @Schema(description = "租户名称") - @NotBlank(message = "租户名称不能为空") - @Length(max = 64, message = "租户名称长度不能超过 {max} 个字符") + @Schema(description = "名称", example = "T0001租户") + @NotBlank(message = "名称不能为空") + @Length(max = 30, message = "名称长度不能超过 {max} 个字符") private String name; /** - * 绑定的域名 + * 域名 */ - @Schema(description = "绑定的域名") - @Length(max = 128, message = "绑定的域名长度不能超过 {max} 个字符") + @Schema(description = "域名", example = "https://t0001.continew.top/") + @Length(max = 255, message = "域名长度不能超过 {max} 个字符") private String domain; /** - * 租户套餐编号 + * 过期时间 */ - @Schema(description = "租户套餐编号") - @NotNull(message = "租户套餐编号不能为空") + @Schema(description = "过期时间", example = "2023-08-08 08:08:08", type = "string") + @Future(message = "过期时间必须是未来时间") + private LocalDateTime expireTime; + + /** + * 隔离级别 + */ + @Schema(description = "隔离级别", example = "2") + @NotNull(message = "隔离级别不能为空", groups = CrudValidationGroup.Create.class) + private TenantIsolationLevelEnum isolationLevel; + + /** + * 描述 + */ + @Schema(description = "描述", example = "T0001租户描述") + @Length(max = 200, message = "描述长度不能超过 {max} 个字符") + private String description; + + /** + * 状态 + */ + @Schema(description = "状态", example = "1") + private DisEnableStatusEnum status; + + /** + * 套餐 ID + */ + @Schema(description = "套餐 ID", example = "1") + @NotNull(message = "套餐不能为空") private Long packageId; /** - * 状态(1:启用;2:禁用) + * 数据源 ID */ - @Schema(description = "状态") - @NotNull(message = "状态不能为空") - private Integer status; - - /** - * 租户过期时间 - */ - @Schema(description = "租户过期时间") - @Future(message = "过期时间必须是未来时间") - private LocalDateTime expireTime; + @Schema(description = "数据源 ID") + @SpelNotNull(condition = "#this.isolationLevel == T(top.continew.admin.tenant.model.enums.TenantIsolationLevelEnum).DATASOURCE", message = "数据源不能为空") + private Long datasourceId; /** * 用户名 @@ -95,22 +121,10 @@ public class TenantReq implements Serializable { private String password; /** - * 租户编号 + * 编码 */ - private String tenantSn; - - /** - * 隔离级别 - */ - @Schema(description = "隔离级别") - @NotNull(message = "隔离级别不能为空", groups = CrudValidationGroup.Create.class) - private Integer isolationLevel; - - /** - * 数据连接ID - */ - @Schema(description = "数据连接ID") - private Long dbConnectId; + @Schema(hidden = true) + private String code; /** * ID diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/DatasourceDetailResp.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/DatasourceDetailResp.java new file mode 100644 index 00000000..347d697e --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/DatasourceDetailResp.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.model.resp; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; + +/** + * 数据源详情响应参数 + * + * @author 小熊 + * @author Charles7c + * @since 2024/12/12 19:13 + */ +@Data +@Schema(description = "数据源详情响应参数") +public class DatasourceDetailResp extends DatasourceResp { + + @Serial + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantDbConnectDetailResp.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/DatasourceResp.java similarity index 51% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantDbConnectDetailResp.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/DatasourceResp.java index 219e0aa2..a0b89889 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantDbConnectDetailResp.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/DatasourceResp.java @@ -21,62 +21,65 @@ import cn.idev.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import top.continew.admin.common.base.model.resp.BaseDetailResp; +import top.continew.admin.tenant.model.enums.DatasourceDatabaseTypeEnum; +import top.continew.starter.excel.converter.ExcelBaseEnumConverter; import java.io.Serial; /** - * 租户数据连接详情信息 + * 数据源响应参数 * * @author 小熊 + * @author Charles7c * @since 2024/12/12 19:13 */ @Data @ExcelIgnoreUnannotated -@Schema(description = "租户数据连接详情信息") -public class TenantDbConnectDetailResp extends BaseDetailResp { +@Schema(description = "数据源响应参数") +public class DatasourceResp extends BaseDetailResp { @Serial private static final long serialVersionUID = 1L; /** - * 连接名称 + * 名称 */ - @Schema(description = "连接名称") - @ExcelProperty(value = "连接名称") - private String connectName; + @Schema(description = "名称", example = "T0001数据源") + @ExcelProperty(value = "名称", order = 2) + private String name; /** - * 连接类型 + * 数据库类型 */ - @Schema(description = "连接类型") - @ExcelProperty(value = "连接类型") - private Integer type; + @Schema(description = "数据库类型", example = "1") + @ExcelProperty(value = "数据库类型", converter = ExcelBaseEnumConverter.class, order = 3) + private DatasourceDatabaseTypeEnum databaseType; /** - * 连接主机地址 + * 主机 */ - @Schema(description = "连接主机地址") - @ExcelProperty(value = "连接主机地址") + @Schema(description = "主机", example = "123.56.195.68") + @ExcelProperty(value = "主机", order = 4) private String host; /** - * 连接端口 + * 端口 */ - @Schema(description = "连接端口") - @ExcelProperty(value = "连接端口") + @Schema(description = "端口", example = "3306") + @ExcelProperty(value = "端口", order = 5) private Integer port; /** - * 连接用户名 + * 用户名 */ - @Schema(description = "连接用户名") - @ExcelProperty(value = "连接用户名") + @Schema(description = "用户名", example = "root") + @ExcelProperty(value = "用户名", order = 6) private String username; /** - * 连接密码 + * 描述 */ - @Schema(description = "连接密码") - @ExcelProperty(value = "连接密码") - private String password; + @Schema(description = "描述", example = "T0001数据源描述") + @ExcelProperty(value = "描述", order = 7) + private String description; } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantPackageResp.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/PackageDetailResp.java similarity index 58% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantPackageResp.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/PackageDetailResp.java index 846cebe8..aa7a3c8c 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantPackageResp.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/PackageDetailResp.java @@ -16,50 +16,34 @@ package top.continew.admin.tenant.model.resp; +import cn.crane4j.annotation.AssembleMethod; +import cn.crane4j.annotation.ContainerMethod; +import cn.crane4j.annotation.MappingType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import top.continew.admin.tenant.service.PackageMenuService; + import java.io.Serial; -import java.time.*; import java.util.List; -import lombok.Data; - -import io.swagger.v3.oas.annotations.media.Schema; - -import top.continew.admin.common.base.model.resp.BaseResp; - /** - * 租户套餐信息 + * 套餐详情响应参数 * * @author 小熊 + * @author Charles7c * @since 2024/11/26 11:25 */ @Data -@Schema(description = "租户套餐信息") -public class TenantPackageResp extends BaseResp { +@Schema(description = "套餐详情响应参数") +@AssembleMethod(key = "id", prop = ":menuIds", targetType = PackageMenuService.class, method = @ContainerMethod(bindMethod = "listMenuIdsByPackageId", type = MappingType.ORDER_OF_KEYS)) +public class PackageDetailResp extends PackageResp { @Serial private static final long serialVersionUID = 1L; /** - * 套餐名称 + * 关联的菜单 ID 列表 */ - @Schema(description = "套餐名称") - private String name; - - /** - * 关联的菜单ids - */ - @Schema(description = "关联的菜单ids") + @Schema(description = "关联的菜单 ID 列表", example = "[1000, 1010, 1011]") private List menuIds; - - /** - * 菜单选择是否父子节点关联 - */ - @Schema(description = "菜单选择是否父子节点关联") - private Boolean menuCheckStrictly; - - /** - * 状态(1:启用;2:禁用) - */ - @Schema(description = "状态(1:启用;2:禁用)") - private Integer status; } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantPackageDetailResp.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/PackageResp.java similarity index 60% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantPackageDetailResp.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/PackageResp.java index d928a390..8005a882 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantPackageDetailResp.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/PackageResp.java @@ -16,57 +16,63 @@ package top.continew.admin.tenant.model.resp; -import java.io.Serial; -import java.time.*; -import java.util.List; - -import cn.idev.excel.annotation.ExcelProperty; -import lombok.Data; - -import io.swagger.v3.oas.annotations.media.Schema; - -import top.continew.admin.common.base.model.resp.BaseDetailResp; import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import top.continew.admin.common.base.model.resp.BaseDetailResp; +import top.continew.admin.common.enums.DisEnableStatusEnum; +import top.continew.starter.excel.converter.ExcelBaseEnumConverter; + +import java.io.Serial; /** - * 租户套餐详情信息 + * 套餐响应参数 * * @author 小熊 + * @author Charles7c * @since 2024/11/26 11:25 */ @Data @ExcelIgnoreUnannotated -@Schema(description = "租户套餐详情信息") -public class TenantPackageDetailResp extends BaseDetailResp { +@Schema(description = "套餐响应参数") +public class PackageResp extends BaseDetailResp { @Serial private static final long serialVersionUID = 1L; /** - * 套餐名称 + * 名称 */ - @Schema(description = "套餐名称") - @ExcelProperty(value = "套餐名称") + @Schema(description = "名称", example = "初级套餐") + @ExcelProperty(value = "名称", order = 2) private String name; /** - * 关联的菜单ids + * 排序 */ - @Schema(description = "关联的菜单ids") - @ExcelProperty(value = "关联的菜单ids") - private List menuIds; + @Schema(description = "排序", example = "1") + @ExcelProperty(value = "排序", order = 3) + private Integer sort; /** * 菜单选择是否父子节点关联 */ - @Schema(description = "菜单选择是否父子节点关联") - @ExcelProperty(value = "菜单选择是否父子节点关联") + @Schema(description = "菜单选择是否父子节点关联", example = "true") + @ExcelProperty(value = "菜单选择是否父子节点关联", order = 4) private Boolean menuCheckStrictly; /** - * 状态(1:启用;2:禁用) + * 描述 */ - @Schema(description = "状态(1:启用;2:禁用)") - @ExcelProperty(value = "状态(1:启用;2:禁用)") - private Integer status; + @Schema(description = "描述", example = "初级套餐") + @ExcelProperty(value = "描述", order = 5) + private String description; + + /** + * 状态 + */ + @Schema(description = "状态", example = "1") + @ExcelProperty(value = "状态", converter = ExcelBaseEnumConverter.class, order = 6) + private DisEnableStatusEnum status; } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantCommonResp.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantCommonResp.java index 083a8d56..7f9ea91f 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantCommonResp.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantCommonResp.java @@ -21,15 +21,16 @@ import lombok.Data; import java.util.List; /** - * @description: 租户通用信息返回 - * @author: 小熊 - * @create: 2024-11-28 09:53 + * 租户通用信息返回 + * + * @author 小熊 + * @since 2024/11/28 09:53 */ @Data public class TenantCommonResp { /** - * 是否开启了多租户 + * 是否开启了租户 */ private Boolean isEnabled; diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantDbConnectResp.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantDbConnectResp.java deleted file mode 100644 index a7efd70f..00000000 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantDbConnectResp.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.admin.tenant.model.resp; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import top.continew.admin.common.base.model.resp.BaseResp; - -import java.io.Serial; - -/** - * 租户数据连接信息 - * - * @author 小熊 - * @since 2024/12/12 19:13 - */ -@Data -@Schema(description = "租户数据连接信息") -public class TenantDbConnectResp extends BaseResp { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 连接名称 - */ - @Schema(description = "连接名称") - private String connectName; - - /** - * 连接类型 - */ - @Schema(description = "连接类型") - private Integer type; - - /** - * 连接主机地址 - */ - @Schema(description = "连接主机地址") - private String host; - - /** - * 连接端口 - */ - @Schema(description = "连接端口") - private Integer port; - - /** - * 连接用户名 - */ - @Schema(description = "连接用户名") - private String username; - -} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantDetailResp.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantDetailResp.java index 7ce09059..3d11ce3d 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantDetailResp.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantDetailResp.java @@ -16,84 +16,30 @@ package top.continew.admin.tenant.model.resp; -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; import cn.idev.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import top.continew.admin.common.base.model.resp.BaseDetailResp; import java.io.Serial; -import java.time.LocalDateTime; -import java.util.List; /** - * 租户详情信息 + * 租户详情响应参数 * * @author 小熊 + * @author Charles7c * @since 2024/11/26 17:20 */ @Data -@ExcelIgnoreUnannotated -@Schema(description = "租户详情信息") -public class TenantDetailResp extends BaseDetailResp { +@Schema(description = "租户详情响应参数") +public class TenantDetailResp extends TenantResp { @Serial private static final long serialVersionUID = 1L; /** - * 租户名称 + * 租户管理员 */ - @Schema(description = "租户名称") - @ExcelProperty(value = "租户名称") - private String name; - - /** - * 绑定的域名 - */ - @Schema(description = "绑定的域名") - @ExcelProperty(value = "绑定的域名") - private String domain; - - /** - * 租户套餐编号 - */ - @Schema(description = "租户套餐编号") - @ExcelProperty(value = "租户套餐编号") - private Long packageId; - - /** - * 状态(1:启用;2:禁用) - */ - @Schema(description = "状态(1:启用;2:禁用)") - @ExcelProperty(value = "状态(1:启用;2:禁用)") - private Integer status; - - /** - * 租户过期时间 - */ - @Schema(description = "租户过期时间") - @ExcelProperty(value = "租户过期时间") - private LocalDateTime expireTime; - - /** - * 绑定的套餐名称 - */ - @Schema(description = "绑定的套餐名称") - private String packageName; - - /** - * 套餐关联的菜单 - */ - @Schema(description = "关联的菜单ids") - private List menuIds; - - /** - * 租户编号 - */ - private String tenantSn; - - /** - * 租户绑定的管理用户id - */ - private Long userId; + @Schema(description = "租户管理员", example = "666") + @ExcelProperty(value = "租户管理员", order = 13) + private Long adminUser; } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantResp.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantResp.java index e51ca067..3799530f 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantResp.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/model/resp/TenantResp.java @@ -16,76 +16,114 @@ package top.continew.admin.tenant.model.resp; +import cn.crane4j.annotation.AssembleMethod; +import cn.crane4j.annotation.ContainerMethod; +import cn.crane4j.annotation.Mapping; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import top.continew.admin.common.base.model.resp.BaseResp; +import top.continew.admin.common.base.model.resp.BaseDetailResp; +import top.continew.admin.common.enums.DisEnableStatusEnum; +import top.continew.admin.tenant.model.enums.TenantIsolationLevelEnum; +import top.continew.admin.tenant.service.DatasourceService; +import top.continew.admin.tenant.service.PackageService; +import top.continew.starter.excel.converter.ExcelBaseEnumConverter; import java.io.Serial; import java.time.LocalDateTime; /** - * 租户信息 + * 租户响应参数 * * @author 小熊 + * @author Charles7c * @since 2024/11/26 17:20 */ @Data -@Schema(description = "租户信息") -public class TenantResp extends BaseResp { +@ExcelIgnoreUnannotated +@Schema(description = "租户响应参数") +public class TenantResp extends BaseDetailResp { @Serial private static final long serialVersionUID = 1L; /** - * 租户名称 + * 名称 */ - @Schema(description = "租户名称") + @Schema(description = "名称", example = "T0001租户") + @ExcelProperty(value = "名称", order = 2) private String name; /** - * 绑定的域名 + * 编码 */ - @Schema(description = "绑定的域名") + @Schema(description = "编码", example = "T0001") + @ExcelProperty(value = "编码", order = 3) + private String code; + + /** + * 域名 + */ + @Schema(description = "域名", example = "https://t0001.continew.top/") + @ExcelProperty(value = "域名", order = 4) private String domain; /** - * 租户套餐编号 + * 过期时间 */ - @Schema(description = "租户套餐编号") - private Long packageId; - - /** - * 状态(1:启用;2:禁用) - */ - @Schema(description = "状态(1:启用;2:禁用)") - private Integer status; - - /** - * 租户过期时间 - */ - @Schema(description = "租户过期时间") + @Schema(description = "过期时间", example = "2023-08-08 08:08:08") + @ExcelProperty(value = "过期时间", order = 5) private LocalDateTime expireTime; - /** - * 绑定的套餐名称 - */ - @Schema(description = "绑定的套餐名称") - private String packageName; - - /** - * 租户编号 - */ - private String tenantSn; - /** * 隔离级别 */ - @Schema(description = "隔离级别") - private Integer isolationLevel; + @Schema(description = "隔离级别", example = "2") + @ExcelProperty(value = "隔离级别", converter = ExcelBaseEnumConverter.class, order = 6) + private TenantIsolationLevelEnum isolationLevel; /** - * 数据连接ID + * 描述 */ - @Schema(description = "数据连接ID") - private Long dbConnectId; + @Schema(description = "描述", example = "T0001租户描述") + @ExcelProperty(value = "描述", order = 7) + private String description; + + /** + * 状态 + */ + @Schema(description = "状态", example = "1") + @ExcelProperty(value = "状态", converter = ExcelBaseEnumConverter.class, order = 8) + private DisEnableStatusEnum status; + + /** + * 套餐 ID + */ + @Schema(description = "套餐 ID", example = "1") + @ExcelProperty(value = "套餐 ID", order = 9) + @AssembleMethod(props = @Mapping(src = "name", ref = "packageName"), targetType = PackageService.class, method = @ContainerMethod(bindMethod = "get", resultType = PackageResp.class)) + private Long packageId; + + /** + * 数据源 ID + */ + @Schema(description = "数据源 ID", example = "1") + @ExcelProperty(value = "数据源 ID", order = 10) + @AssembleMethod(props = @Mapping(src = "name", ref = "datasourceName"), targetType = DatasourceService.class, method = @ContainerMethod(bindMethod = "get", resultType = DatasourceResp.class)) + private Long datasourceId; + + /** + * 套餐名称 + */ + @Schema(description = "套餐名称", example = "初级套餐") + @ExcelProperty(value = "套餐名称", order = 11) + private String packageName; + + /** + * 数据源名称 + */ + @Schema(description = "数据源名称", example = "T0001数据源") + @ExcelProperty(value = "数据源名称", order = 12) + private String datasourceName; } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/DatasourceService.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/DatasourceService.java new file mode 100644 index 00000000..3799ccd8 --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/DatasourceService.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.service; + +import top.continew.admin.common.base.service.BaseService; +import top.continew.admin.tenant.model.entity.DatasourceDO; +import top.continew.admin.tenant.model.query.DatasourceQuery; +import top.continew.admin.tenant.model.req.DatasourceReq; +import top.continew.admin.tenant.model.resp.DatasourceDetailResp; +import top.continew.admin.tenant.model.resp.DatasourceResp; +import top.continew.starter.data.service.IService; + +/** + * 数据源业务接口 + * + * @author 小熊 + * @author Charles7c + * @since 2024/12/12 19:13 + */ +public interface DatasourceService extends BaseService, IService { + + /** + * 测试连接 + * + * @param id ID + */ + void testConnection(Long id); + + /** + * 初始化数据库 + * + * @param databaseName 数据库名称 + * @param id ID + */ + void initDb(String databaseName, Long id); +} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/PackageMenuService.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/PackageMenuService.java new file mode 100644 index 00000000..c7f84280 --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/PackageMenuService.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.service; + +import java.util.List; + +/** + * 套餐和菜单关联业务接口 + * + * @author Charles7c + * @since 2025/7/13 20:44 + */ +public interface PackageMenuService { + + /** + * 新增 + * + * @param menuIds 菜单 ID 列表 + * @param packageId 套餐 ID + * @return 是否成功(true:成功;false:无变更/失败) + */ + boolean add(List menuIds, Long packageId); + + /** + * 根据套餐 ID 查询 + * + * @param packageId 套餐 ID + * @return 菜单 ID 列表 + */ + List listMenuIdsByPackageId(Long packageId); +} diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/PackageMenuServiceImpl.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/PackageMenuServiceImpl.java new file mode 100644 index 00000000..f1f96b06 --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/PackageMenuServiceImpl.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.service; + +import cn.hutool.core.collection.CollUtil; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import top.continew.admin.tenant.mapper.PackageMenuMapper; +import top.continew.admin.tenant.model.entity.PackageMenuDO; + +import java.util.List; + +/** + * 套餐和菜单关联业务实现 + * + * @author Charles7c + * @since 2025/7/13 20:45 + */ +@Service +@RequiredArgsConstructor +public class PackageMenuServiceImpl implements PackageMenuService { + + private final PackageMenuMapper baseMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean add(List menuIds, Long packageId) { + // 检查是否有变更 + List oldMenuIdList = baseMapper.lambdaQuery() + .select(PackageMenuDO::getMenuId) + .eq(PackageMenuDO::getPackageId, packageId) + .list() + .stream() + .map(PackageMenuDO::getMenuId) + .toList(); + if (CollUtil.isEmpty(CollUtil.disjunction(menuIds, oldMenuIdList))) { + return false; + } + // 删除原有关联 + baseMapper.lambdaUpdate().eq(PackageMenuDO::getPackageId, packageId).remove(); + // 保存最新关联 + List newList = menuIds.stream().map(menuId -> new PackageMenuDO(packageId, menuId)).toList(); + return baseMapper.insertBatch(newList); + } + + @Override + public List listMenuIdsByPackageId(Long packageId) { + return baseMapper.lambdaQuery() + .select(PackageMenuDO::getMenuId) + .eq(PackageMenuDO::getPackageId, packageId) + .list() + .stream() + .map(PackageMenuDO::getMenuId) + .toList(); + } +} diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/TenantPackageService.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/PackageService.java similarity index 61% rename from continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/TenantPackageService.java rename to continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/PackageService.java index 99e29145..91fa9c46 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/TenantPackageService.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/PackageService.java @@ -17,15 +17,17 @@ package top.continew.admin.tenant.service; import top.continew.admin.common.base.service.BaseService; -import top.continew.admin.tenant.model.query.TenantPackageQuery; -import top.continew.admin.tenant.model.req.TenantPackageReq; -import top.continew.admin.tenant.model.resp.TenantPackageDetailResp; -import top.continew.admin.tenant.model.resp.TenantPackageResp; +import top.continew.admin.tenant.model.entity.PackageDO; +import top.continew.admin.tenant.model.query.PackageQuery; +import top.continew.admin.tenant.model.req.PackageReq; +import top.continew.admin.tenant.model.resp.PackageDetailResp; +import top.continew.admin.tenant.model.resp.PackageResp; +import top.continew.starter.data.service.IService; /** - * 租户套餐业务接口 + * 套餐业务接口 * * @author 小熊 * @since 2024/11/26 11:25 */ -public interface TenantPackageService extends BaseService {} \ No newline at end of file +public interface PackageService extends BaseService, IService {} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/TenantDbConnectService.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/TenantDbConnectService.java deleted file mode 100644 index fb121d5a..00000000 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/TenantDbConnectService.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.admin.tenant.service; - -import org.springframework.jdbc.core.JdbcTemplate; -import top.continew.admin.common.base.service.BaseService; -import top.continew.admin.tenant.model.query.TenantDbConnectQuery; -import top.continew.admin.tenant.model.req.TenantDbConnectReq; -import top.continew.admin.tenant.model.resp.TenantDbConnectDetailResp; -import top.continew.admin.tenant.model.resp.TenantDbConnectResp; - -/** - * 租户数据连接业务接口 - * - * @author 小熊 - * @since 2024/12/12 19:13 - */ -public interface TenantDbConnectService extends BaseService { - - JdbcTemplate getConnectJdbcTemplateById(Long id); - -} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/TenantService.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/TenantService.java index 7eb058cb..c209a646 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/TenantService.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/TenantService.java @@ -31,33 +31,21 @@ import java.util.List; * 租户业务接口 * * @author 小熊 + * @author Charles7c * @since 2024/11/26 17:20 */ public interface TenantService extends BaseService, IService { + /** + * 检查租户状态 + * + * @param id ID + * @return 租户信息 + */ + TenantDO checkStatus(Long id); + /** * 获取所有可用的租户列表 */ List getAvailableList(); - - /** - * 租户绑定用户 - */ - void bindUser(Long tenantId, Long userId); - - /** - * 检查租户状态 - */ - void checkStatus(); - - /** - * 根据id获取租户DO - */ - TenantDO getTenantById(Long id); - - /** - * 根据用户id获取租户信息 - */ - TenantDO getTenantByUserId(Long userId); - } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/DatasourceServiceImpl.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/DatasourceServiceImpl.java new file mode 100644 index 00000000..95b77f11 --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/DatasourceServiceImpl.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.io.resource.ClassPathResource; +import cn.hutool.core.io.resource.Resource; +import cn.hutool.core.util.StrUtil; +import com.alicp.jetcache.anno.Cached; +import lombok.RequiredArgsConstructor; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Service; +import top.continew.admin.common.base.service.BaseServiceImpl; +import top.continew.admin.common.util.SecureUtils; +import top.continew.admin.tenant.constant.TenantCacheConstants; +import top.continew.admin.tenant.mapper.DatasourceMapper; +import top.continew.admin.tenant.mapper.TenantMapper; +import top.continew.admin.tenant.model.entity.DatasourceDO; +import top.continew.admin.tenant.model.entity.TenantDO; +import top.continew.admin.tenant.model.query.DatasourceQuery; +import top.continew.admin.tenant.model.req.DatasourceReq; +import top.continew.admin.tenant.model.resp.DatasourceDetailResp; +import top.continew.admin.tenant.model.resp.DatasourceResp; +import top.continew.admin.tenant.service.DatasourceService; +import top.continew.starter.cache.redisson.util.RedisUtils; +import top.continew.starter.core.constant.StringConstants; +import top.continew.starter.core.util.ExceptionUtils; +import top.continew.starter.core.util.validation.CheckUtils; +import top.continew.starter.core.util.validation.ValidationUtils; + +import javax.sql.DataSource; +import java.util.Arrays; +import java.util.List; + +/** + * 数据源业务实现 + * + * @author 小熊 + * @author Charles7c + * @since 2024/12/12 19:13 + */ +@Service +@RequiredArgsConstructor +public class DatasourceServiceImpl extends BaseServiceImpl implements DatasourceService { + + private final TenantMapper tenantMapper; + + @Override + @Cached(name = TenantCacheConstants.TENANT_DATASOURCE_KEY_PREFIX, key = "#id") + public DatasourceDetailResp get(Long id) { + return super.get(id); + } + + @Override + public void beforeCreate(DatasourceReq req) { + // 解密密码 + req.setPassword(this.decryptPassword(req.getPassword(), null)); + // 检查是否重复 + this.checkRepeat(req, null); + // 测试连接 + req.getDatabaseType().testConnection(req); + } + + @Override + public void beforeUpdate(DatasourceReq req, Long id) { + DatasourceDO oldDatasource = super.getById(id); + // 解密密码 + req.setPassword(this.decryptPassword(req.getPassword(), oldDatasource)); + // 检查是否重复 + this.checkRepeat(req, id); + CheckUtils.throwIf(oldDatasource.getDatabaseType() != req.getDatabaseType(), "数据库类型不能修改"); + // 测试连接 + boolean isUpdated = this.isUpdated(req, oldDatasource); + if (isUpdated) { + req.getDatabaseType().testConnection(req); + } + } + + @Override + public void afterUpdate(DatasourceReq req, DatasourceDO entity) { + RedisUtils.delete(TenantCacheConstants.TENANT_DATASOURCE_KEY_PREFIX + entity.getId()); + } + + @Override + public void beforeDelete(List ids) { + CheckUtils.throwIf(tenantMapper.lambdaQuery().in(TenantDO::getDatasourceId, ids).exists(), "所选数据源存在关联租户,不允许删除"); + } + + @Override + public void afterDelete(List ids) { + ids.forEach(id -> RedisUtils.delete(TenantCacheConstants.TENANT_DATASOURCE_KEY_PREFIX + id)); + } + + @Override + public void testConnection(Long id) { + DatasourceDO datasource = super.getById(id); + datasource.getDatabaseType().testConnection(BeanUtil.copyProperties(datasource, DatasourceReq.class)); + } + + @Override + public void initDb(String databaseName, Long id) { + DatasourceDO datasource = super.getById(id); + DataSource ds = datasource.getDatabaseType() + .buildDataSource(BeanUtil.copyProperties(datasource, DatasourceReq.class)); + JdbcTemplate jdbcTemplate = new JdbcTemplate(ds); + // 建库 + jdbcTemplate.execute("CREATE DATABASE %s CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" + .formatted(databaseName)); + jdbcTemplate.execute("USE %s;".formatted(databaseName)); + // TODO 初始化数据 + Resource resource = new ClassPathResource("db/changelog/mysql/tenant_table.sql"); + Arrays.stream(resource.readUtf8Str().split(StringConstants.SEMICOLON)) + .map(String::trim) + .filter(StrUtil::isNotBlank) + .forEach(jdbcTemplate::execute); + } + + /** + * 解密密码 + * + * @param encryptPassword 加密的密码 + * @param oldDatasource 旧数据源 + * @return 解密后的密码 + */ + private String decryptPassword(String encryptPassword, DatasourceDO oldDatasource) { + // 修改时,密码为空将不更改密码 + if (oldDatasource != null && StrUtil.isBlank(encryptPassword)) { + return oldDatasource.getPassword(); + } + // 解密 + String decryptPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(encryptPassword)); + ValidationUtils.throwIfNull(decryptPassword, "密码解密失败"); + ValidationUtils.throwIf(decryptPassword.length() > 128, "密码长度不能超过 128 个字符"); + return decryptPassword; + } + + /** + * 检查数据源是否存在 + * + * @param req 数据源信息 + * @param id ID + */ + private void checkRepeat(DatasourceReq req, Long id) { + CheckUtils.throwIf(baseMapper.lambdaQuery() + .eq(DatasourceDO::getHost, req.getHost()) + .eq(DatasourceDO::getPort, req.getPort()) + .eq(DatasourceDO::getUsername, req.getUsername()) + .ne(id != null, DatasourceDO::getId, id) + .exists(), "相同配置数据源已存在"); + } + + /** + * 是否更新了配置 + * + * @param req 数据源请求参数 + * @param oldDatasource 旧数据源 + * @return 是否更新了配置 + */ + private boolean isUpdated(DatasourceReq req, DatasourceDO oldDatasource) { + return !(oldDatasource.getHost().equals(req.getHost()) && oldDatasource.getPort() + .equals(req.getPort()) && oldDatasource.getUsername().equals(req.getUsername()) && oldDatasource + .getPassword() + .equals(req.getPassword())); + } +} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/PackageServiceImpl.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/PackageServiceImpl.java new file mode 100644 index 00000000..5b9158ca --- /dev/null +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/PackageServiceImpl.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.tenant.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import top.continew.admin.common.base.service.BaseServiceImpl; +import top.continew.admin.system.model.entity.MenuDO; +import top.continew.admin.system.service.MenuService; +import top.continew.admin.tenant.mapper.PackageMapper; +import top.continew.admin.tenant.mapper.TenantMapper; +import top.continew.admin.tenant.model.entity.PackageDO; +import top.continew.admin.tenant.model.entity.TenantDO; +import top.continew.admin.tenant.model.query.PackageQuery; +import top.continew.admin.tenant.model.req.PackageReq; +import top.continew.admin.tenant.model.resp.PackageDetailResp; +import top.continew.admin.tenant.model.resp.PackageResp; +import top.continew.admin.tenant.service.PackageMenuService; +import top.continew.admin.tenant.service.PackageService; +import top.continew.starter.core.util.validation.CheckUtils; +import top.continew.starter.extension.tenant.TenantHandler; + +import java.util.ArrayList; +import java.util.List; + +/** + * 套餐业务实现 + * + * @author 小熊 + * @author Charles7c + * @since 2024/11/26 11:25 + */ +@Service +@RequiredArgsConstructor +public class PackageServiceImpl extends BaseServiceImpl implements PackageService { + + private final PackageMenuService packageMenuService; + private final MenuService menuService; + private final TenantMapper tenantMapper; + private final TenantHandler tenantHandler; + + @Override + @DSTransactional(rollbackFor = Exception.class) + public Long create(PackageReq req) { + this.checkNameRepeat(req.getName(), null); + // 新增信息 + Long id = super.create(req); + // 保存套餐和菜单关联 + packageMenuService.add(req.getMenuIds(), id); + return id; + } + + @Override + @DSTransactional(rollbackFor = Exception.class) + public void update(PackageReq req, Long id) { + this.checkNameRepeat(req.getName(), id); + // 更新信息 + super.update(req, id); + // 保存套餐和菜单关联 + boolean isSaveMenuSuccess = packageMenuService.add(req.getMenuIds(), id); + if (!isSaveMenuSuccess) { + return; + } + // 更新租户菜单 + List tenantIdList = tenantMapper.lambdaQuery() + .select(TenantDO::getId) + .eq(TenantDO::getPackageId, id) + .list() + .stream() + .map(TenantDO::getId) + .toList(); + if (CollUtil.isEmpty(tenantIdList)) { + return; + } + List oldMenuIds = packageMenuService.listMenuIdsByPackageId(id); + List newMenuIds = req.getMenuIds(); + // 如果有删除的菜单则绑定了套餐的租户对应的菜单也会删除 + List deleteMenuIds = new ArrayList<>(oldMenuIds); + deleteMenuIds.removeAll(newMenuIds); + if (CollUtil.isNotEmpty(deleteMenuIds)) { + List deleteMenus = menuService.listByIds(deleteMenuIds); + tenantIdList.forEach(tenantId -> tenantHandler.execute(tenantId, () -> menuService + .deleteTenantMenus(deleteMenus))); + } + // 如果有新增的菜单则绑定了套餐的租户对应的菜单也会新增 + List addMenuIds = new ArrayList<>(newMenuIds); + addMenuIds.removeAll(oldMenuIds); + if (CollUtil.isNotEmpty(addMenuIds)) { + List addMenus = menuService.listByIds(addMenuIds); + for (MenuDO addMenu : addMenus) { + MenuDO parentMenu = addMenu.getParentId() != 0 ? menuService.getById(addMenu.getParentId()) : null; + tenantIdList.forEach(tenantId -> tenantHandler.execute(tenantId, () -> menuService + .addTenantMenu(addMenu, parentMenu))); + } + } + } + + @Override + public void beforeDelete(List ids) { + CheckUtils.throwIf(tenantMapper.lambdaQuery().in(TenantDO::getPackageId, ids).exists(), "所选套餐存在关联租户,不允许删除"); + } + + /** + * 名称是否存在 + * + * @param name 名称 + * @param id ID + */ + private void checkNameRepeat(String name, Long id) { + CheckUtils.throwIf(baseMapper.lambdaQuery() + .eq(PackageDO::getName, name) + .ne(id != null, PackageDO::getId, id) + .exists(), "名称为 [{}] 的套餐已存在", name); + } +} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantDbConnectServiceImpl.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantDbConnectServiceImpl.java deleted file mode 100644 index 2962c156..00000000 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantDbConnectServiceImpl.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.admin.tenant.service.impl; - -import com.alicp.jetcache.anno.Cached; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import lombok.RequiredArgsConstructor; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Service; -import top.continew.admin.common.base.service.BaseServiceImpl; -import top.continew.admin.common.constant.CacheConstants; -import top.continew.admin.tenant.mapper.TenantDbConnectMapper; -import top.continew.admin.tenant.mapper.TenantMapper; -import top.continew.admin.tenant.model.entity.TenantDO; -import top.continew.admin.tenant.model.entity.TenantDbConnectDO; -import top.continew.admin.tenant.model.enums.TenantConnectTypeEnum; -import top.continew.admin.tenant.model.query.TenantDbConnectQuery; -import top.continew.admin.tenant.model.req.TenantDbConnectReq; -import top.continew.admin.tenant.model.resp.TenantDbConnectDetailResp; -import top.continew.admin.tenant.model.resp.TenantDbConnectResp; -import top.continew.admin.tenant.service.TenantDbConnectService; -import top.continew.admin.tenant.util.DbConnectUtil; -import top.continew.starter.cache.redisson.util.RedisUtils; -import top.continew.starter.core.util.validation.CheckUtils; - -import javax.sql.DataSource; -import java.util.List; - -/** - * 租户数据连接业务实现 - * - * @author 小熊 - * @since 2024/12/12 19:13 - */ -@Service -@RequiredArgsConstructor -public class TenantDbConnectServiceImpl extends BaseServiceImpl implements TenantDbConnectService { - - private final TenantMapper tenantMapper; - - @Override - @Cached(name = CacheConstants.DB_CONNECT_KEY_PREFIX, key = "#id") - public TenantDbConnectDetailResp get(Long id) { - return super.get(id); - } - - @Override - protected void beforeCreate(TenantDbConnectReq req) { - TenantConnectTypeEnum connectTypeEnum = TenantConnectTypeEnum.getByOrdinal(req.getType()); - if (TenantConnectTypeEnum.MYSQL.equals(connectTypeEnum)) { - DbConnectUtil.getMysqlDataSource(req.getHost(), req.getPort(), req.getUsername(), req - .getPassword(), null, null); - checkRepeat(req, null); - } - } - - /** - * 验证重复数据 - */ - private void checkRepeat(TenantDbConnectReq req, Long id) { - CheckUtils.throwIf(baseMapper.exists(Wrappers.lambdaQuery(TenantDbConnectDO.class) - .eq(TenantDbConnectDO::getHost, req.getHost()) - .eq(TenantDbConnectDO::getPort, req.getPort()) - .eq(TenantDbConnectDO::getUsername, req.getUsername()) - .ne(id != null, TenantDbConnectDO::getId, id)), "数据库连接已存在"); - } - - @Override - protected void beforeUpdate(TenantDbConnectReq req, Long id) { - TenantConnectTypeEnum connectTypeEnum = TenantConnectTypeEnum.getByOrdinal(req.getType()); - if (TenantConnectTypeEnum.MYSQL.equals(connectTypeEnum)) { - DbConnectUtil.getMysqlDataSource(req.getHost(), req.getPort(), req.getUsername(), req - .getPassword(), null, null); - checkRepeat(req, id); - } - } - - @Override - protected void beforeDelete(List ids) { - CheckUtils.throwIf(tenantMapper.selectCount(Wrappers.lambdaQuery(TenantDO.class) - .in(TenantDO::getDbConnectId, ids)) > 0, "存在关联租户无法删除"); - } - - @Override - protected void afterUpdate(TenantDbConnectReq req, TenantDbConnectDO entity) { - RedisUtils.delete(CacheConstants.DB_CONNECT_KEY_PREFIX + entity.getId()); - } - - @Override - protected void afterDelete(List ids) { - ids.forEach(id -> RedisUtils.delete(CacheConstants.DB_CONNECT_KEY_PREFIX + id)); - } - - @Override - public JdbcTemplate getConnectJdbcTemplateById(Long id) { - TenantDbConnectDetailResp dbConnectReq = get(id); - TenantConnectTypeEnum connectTypeEnum = TenantConnectTypeEnum.getByOrdinal(dbConnectReq.getType()); - if (TenantConnectTypeEnum.MYSQL.equals(connectTypeEnum)) { - DataSource dataSource = DbConnectUtil.getMysqlDataSource(dbConnectReq.getHost(), dbConnectReq - .getPort(), dbConnectReq.getUsername(), dbConnectReq.getPassword(), null, null); - return new JdbcTemplate(dataSource); - } - return null; - } - -} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantPackageServiceImpl.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantPackageServiceImpl.java deleted file mode 100644 index 2b90155e..00000000 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantPackageServiceImpl.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.admin.tenant.service.impl; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.json.JSONArray; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import top.continew.admin.common.base.service.BaseServiceImpl; -import top.continew.admin.tenant.mapper.TenantMapper; -import top.continew.admin.tenant.mapper.TenantPackageMapper; -import top.continew.admin.tenant.model.entity.TenantDO; -import top.continew.admin.tenant.model.entity.TenantPackageDO; -import top.continew.admin.tenant.model.query.TenantPackageQuery; -import top.continew.admin.tenant.model.req.TenantPackageReq; -import top.continew.admin.tenant.model.resp.TenantPackageDetailResp; -import top.continew.admin.tenant.model.resp.TenantPackageResp; -import top.continew.admin.tenant.service.TenantPackageService; -import top.continew.starter.core.util.validation.CheckUtils; - -import java.util.List; - -/** - * 租户套餐业务实现 - * - * @author 小熊 - * @since 2024/11/26 11:25 - */ -@Service -@RequiredArgsConstructor -public class TenantPackageServiceImpl extends BaseServiceImpl implements TenantPackageService { - - private final TenantMapper tenantMapper; - - @Override - public TenantPackageDetailResp get(Long id) { - TenantPackageDO tenantPackageDO = getById(id); - TenantPackageDetailResp packageDetailResp = BeanUtil - .copyProperties(tenantPackageDO, TenantPackageDetailResp.class); - packageDetailResp.setMenuIds(new JSONArray(tenantPackageDO.getMenuIds()).toList(Long.class)); - fill(packageDetailResp); - return packageDetailResp; - } - - @Override - protected void beforeCreate(TenantPackageReq req) { - CheckUtils.throwIf(baseMapper.selectCount(Wrappers.lambdaQuery(TenantPackageDO.class) - .eq(TenantPackageDO::getName, req.getName())) > 0, "租户套餐名称不能重复"); - } - - @Override - protected void beforeDelete(List ids) { - CheckUtils.throwIf(tenantMapper.selectCount(Wrappers.lambdaQuery(TenantDO.class) - .in(TenantDO::getPackageId, ids)) > 0, "存在关联租户无法删除"); - } -} \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantProviderImpl.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantProviderImpl.java deleted file mode 100644 index e5bccde9..00000000 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantProviderImpl.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.admin.tenant.service.impl; - -import cn.hutool.core.util.StrUtil; -import com.zaxxer.hikari.HikariConfig; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import top.continew.admin.common.constant.SysConstants; -import top.continew.admin.common.enums.DisEnableStatusEnum; -import top.continew.admin.tenant.model.entity.TenantDO; -import top.continew.admin.tenant.model.resp.TenantDbConnectDetailResp; -import top.continew.admin.tenant.service.TenantDbConnectService; -import top.continew.admin.tenant.service.TenantService; -import top.continew.admin.tenant.util.DbConnectUtil; -import top.continew.starter.core.util.validation.CheckUtils; -import top.continew.starter.extension.tenant.config.TenantDataSource; -import top.continew.starter.extension.tenant.config.TenantProvider; -import top.continew.starter.extension.tenant.context.TenantContext; -import top.continew.starter.extension.tenant.enums.TenantIsolationLevel; - -/** - * @description: 租户数据源提供者实现 - * @author: 小熊 - * @create: 2024-12-12 15:35 - */ -@Service -@RequiredArgsConstructor -public class TenantProviderImpl implements TenantProvider { - - private final TenantService tenantService; - private final TenantDbConnectService tenantDbConnectService; - - @Override - public TenantContext getByTenantId(String tenantId, boolean verify) { - TenantContext context = new TenantContext(); - if (StrUtil.isNotEmpty(tenantId) && !SysConstants.DEFAULT_TENANT.equals(tenantId)) { - Long longTenantId = Long.valueOf(tenantId); - TenantDO tenantDO = tenantService.getTenantById(longTenantId); - CheckUtils.throwIfNull(tenantDO, "租户[{}]不存在", tenantId); - CheckUtils.throwIf(verify && DisEnableStatusEnum.DISABLE.getValue() - .equals(tenantDO.getStatus()), "租户[{}]已被禁用", tenantId); - context.setTenantId(longTenantId); - TenantIsolationLevel isolationLevel = TenantIsolationLevel.DATASOURCE.ordinal() == tenantDO - .getIsolationLevel() ? TenantIsolationLevel.DATASOURCE : TenantIsolationLevel.LINE; - context.setIsolationLevel(isolationLevel); - if (isolationLevel.equals(TenantIsolationLevel.DATASOURCE)) { - TenantDbConnectDetailResp dbConnectReq = tenantDbConnectService.get(tenantDO.getDbConnectId()); - String dbName = SysConstants.TENANT_DB_PREFIX + tenantDO.getTenantSn(); - HikariConfig hikariConfig = DbConnectUtil.formatHikariConfig(dbConnectReq.getHost(), dbConnectReq - .getPort(), dbConnectReq.getUsername(), dbConnectReq.getPassword(), dbName, DbConnectUtil - .getDefaultMysqlConnectParameter()); - TenantDataSource source = new TenantDataSource(); - source.setPoolName(tenantId); - source.setDriverClassName(hikariConfig.getDriverClassName()); - source.setUrl(hikariConfig.getJdbcUrl()); - source.setUsername(hikariConfig.getUsername()); - source.setPassword(hikariConfig.getPassword()); - context.setDataSource(source); - } - } else { - context.setTenantId(Long.valueOf(SysConstants.DEFAULT_TENANT)); - context.setIsolationLevel(TenantIsolationLevel.LINE); - } - return context; - } - -} diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantServiceImpl.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantServiceImpl.java index 64cb4fa8..e6d4542a 100644 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantServiceImpl.java +++ b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/service/impl/TenantServiceImpl.java @@ -18,185 +18,157 @@ package top.continew.admin.tenant.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.date.DateUtil; -import cn.hutool.core.io.resource.ClassPathResource; -import cn.hutool.core.io.resource.Resource; -import cn.hutool.core.util.RandomUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONArray; +import cn.hutool.extra.spring.SpringUtil; import com.alicp.jetcache.anno.Cached; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.RequiredArgsConstructor; -import org.springframework.jdbc.core.JdbcTemplate; +import me.ahoo.cosid.provider.IdGeneratorProvider; import org.springframework.stereotype.Service; import top.continew.admin.common.base.service.BaseServiceImpl; -import top.continew.admin.common.config.properties.TenantProperties; -import top.continew.admin.common.constant.CacheConstants; -import top.continew.admin.common.constant.SysConstants; +import top.continew.admin.common.config.TenantProperties; import top.continew.admin.common.enums.DisEnableStatusEnum; +import top.continew.admin.tenant.constant.TenantCacheConstants; +import top.continew.admin.tenant.constant.TenantConstants; +import top.continew.admin.tenant.handler.TenantDataHandler; import top.continew.admin.tenant.mapper.TenantMapper; -import top.continew.admin.tenant.mapper.TenantPackageMapper; +import top.continew.admin.tenant.model.entity.PackageDO; import top.continew.admin.tenant.model.entity.TenantDO; -import top.continew.admin.tenant.model.entity.TenantPackageDO; +import top.continew.admin.tenant.model.enums.TenantIsolationLevelEnum; import top.continew.admin.tenant.model.query.TenantQuery; import top.continew.admin.tenant.model.req.TenantReq; import top.continew.admin.tenant.model.resp.TenantAvailableResp; import top.continew.admin.tenant.model.resp.TenantDetailResp; import top.continew.admin.tenant.model.resp.TenantResp; -import top.continew.admin.tenant.service.TenantDbConnectService; +import top.continew.admin.tenant.service.DatasourceService; +import top.continew.admin.tenant.service.PackageMenuService; +import top.continew.admin.tenant.service.PackageService; import top.continew.admin.tenant.service.TenantService; import top.continew.starter.cache.redisson.util.RedisUtils; import top.continew.starter.core.util.validation.CheckUtils; -import top.continew.starter.core.util.validation.ValidationUtils; import top.continew.starter.extension.crud.model.entity.BaseIdDO; -import top.continew.starter.extension.crud.model.query.PageQuery; -import top.continew.starter.extension.crud.model.resp.PageResp; -import top.continew.starter.extension.tenant.context.TenantContextHolder; -import top.continew.starter.extension.tenant.enums.TenantIsolationLevel; +import top.continew.starter.extension.tenant.TenantHandler; -import java.util.Arrays; +import java.io.Serializable; +import java.time.LocalDateTime; import java.util.List; /** * 租户业务实现 * * @author 小熊 + * @author Charles7c * @since 2024/11/26 17:20 */ @Service @RequiredArgsConstructor public class TenantServiceImpl extends BaseServiceImpl implements TenantService { - private final TenantPackageMapper packageMapper; private final TenantProperties tenantProperties; - private final TenantDbConnectService dbConnectService; + private final IdGeneratorProvider idGeneratorProvider; + private final PackageMenuService packageMenuService; + private final PackageService packageService; + private final DatasourceService datasourceService; + private final TenantDataHandler tenantDataHandler; @Override - protected void beforeCreate(TenantReq req) { - //租户名称不能重复 - ValidationUtils.throwIf(baseMapper.exists(Wrappers.lambdaQuery(TenantDO.class) - .eq(TenantDO::getName, req.getName())), "重复的租户名称"); - //录入随机的六位租户编号 - req.setTenantSn(generateTenantSn()); - } - - /** - * 生成六位随机不重复的编号 - */ - private String generateTenantSn() { - String tenantSn; - do { - tenantSn = RandomUtil.randomString(RandomUtil.BASE_CHAR_NUMBER_LOWER, 6); - } while (baseMapper.exists(Wrappers.lambdaQuery(TenantDO.class).eq(TenantDO::getTenantSn, tenantSn))); - return tenantSn; - } - - @Override - protected void afterCreate(TenantReq req, TenantDO entity) { - //数据源级别的租户需要创建数据库 - if (entity.getIsolationLevel().equals(TenantIsolationLevel.DATASOURCE.ordinal())) { - JdbcTemplate jdbcTemplate = dbConnectService.getConnectJdbcTemplateById(entity.getDbConnectId()); - String dbName = SysConstants.TENANT_DB_PREFIX + entity.getTenantSn(); - //建库 - jdbcTemplate.execute(StrUtil - .format("CREATE DATABASE {} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;", dbName)); - jdbcTemplate.execute(StrUtil.format("USE {};", dbName)); - //建表 - Resource resource = new ClassPathResource("db/changelog/mysql/tenant_table.sql"); - String tableSql = resource.readUtf8Str(); - Arrays.stream(tableSql.split(";")) - .map(String::trim) - .filter(sql -> !sql.isEmpty()) - .forEach(jdbcTemplate::execute); + @DSTransactional(rollbackFor = Exception.class) + public Long create(TenantReq req) { + this.checkNameRepeat(req.getName(), null); + // 检查租户套餐 + List menuIds = packageMenuService.listMenuIdsByPackageId(req.getPackageId()); + CheckUtils.throwIfEmpty(menuIds, "所选套餐无可用菜单"); + // 生成租户编码 + req.setCode(this.generateCode()); + // 新增信息 + Long id = super.create(req); + // 初始化数据库 + if (TenantIsolationLevelEnum.DATASOURCE.equals(req.getIsolationLevel())) { + datasourceService.initDb(TenantConstants.TENANT_DB_PREFIX + req.getCode(), req.getDatasourceId()); } + // 初始化租户数据 + req.setId(id); + tenantDataHandler.init(req); + return id; + } + + @Override + public void beforeUpdate(TenantReq req, Long id) { + this.checkNameRepeat(req.getName(), id); + } + + @Override + public void afterUpdate(TenantReq req, TenantDO entity) { + // 更新租户缓存 + RedisUtils.set(TenantCacheConstants.TENANT_KEY_PREFIX + entity.getId(), entity); + } + + @Override + public void beforeDelete(List ids) { + // 在租户中执行数据清除 + for (Long id : ids) { + SpringUtil.getBean(TenantHandler.class).execute(id, tenantDataHandler::clear); + } + } + + @Override + public void afterDelete(List ids) { + ids.forEach(id -> RedisUtils.delete(TenantCacheConstants.TENANT_KEY_PREFIX + id)); + } + + @Override + @Cached(name = TenantCacheConstants.TENANT_KEY_PREFIX, key = "#id") + public TenantDO getById(Serializable id) { + return super.getById(id); + } + + @Override + public TenantDO checkStatus(Long id) { + TenantDO tenant = this.getById(id); + if (!tenantProperties.isEnabled() || id.equals(tenantProperties.getSuperTenantId())) { + return tenant; + } + CheckUtils.throwIfNotEqual(DisEnableStatusEnum.ENABLE.getValue(), tenant.getStatus(), "此租户已被禁用"); + CheckUtils.throwIf(tenant.getExpireTime() != null && tenant.getExpireTime() + .isBefore(LocalDateTime.now()), "此租户已过期"); + // 检查套餐 + PackageDO tenantPackage = packageService.getById(tenant.getPackageId()); + CheckUtils.throwIfNotEqual(DisEnableStatusEnum.ENABLE.getValue(), tenantPackage.getStatus(), "此租户套餐已被禁用"); + return tenant; } @Override public List getAvailableList() { - List tenantDOS = baseMapper.selectList(Wrappers.lambdaQuery(TenantDO.class) + List tenantList = baseMapper.selectList(Wrappers.lambdaQuery(TenantDO.class) .select(TenantDO::getName, BaseIdDO::getId, TenantDO::getDomain) .eq(TenantDO::getStatus, DisEnableStatusEnum.ENABLE.getValue()) .and(t -> t.isNull(TenantDO::getExpireTime).or().ge(TenantDO::getExpireTime, DateUtil.date()))); - return BeanUtil.copyToList(tenantDOS, TenantAvailableResp.class); + return BeanUtil.copyToList(tenantList, TenantAvailableResp.class); } - @Override - public PageResp page(TenantQuery query, PageQuery pageQuery) { - QueryWrapper queryWrapper = Wrappers.query(TenantQuery.class) - .eq(query.getPackageId() != null, "package_id", query.getPackageId()) - .like(StrUtil.isNotEmpty(query.getName()), "sys_tenant.name", query.getName()); - this.sort(queryWrapper, pageQuery); - IPage list = baseMapper.listTenant(new Page<>(pageQuery.getPage(), pageQuery - .getSize()), queryWrapper); - PageResp pageResp = PageResp.build(list, TenantResp.class); - return pageResp; + /** + * 名称是否存在 + * + * @param name 名称 + * @param id ID + */ + private void checkNameRepeat(String name, Long id) { + CheckUtils.throwIf(baseMapper.lambdaQuery() + .eq(TenantDO::getName, name) + .ne(id != null, TenantDO::getId, id) + .exists(), "名称为 [{}] 的租户已存在", name); } - @Override - public TenantDetailResp get(Long id) { - TenantDetailResp detailResp = new TenantDetailResp(); - TenantDO tenantDO = getById(id); - if (tenantDO != null) { - BeanUtil.copyProperties(tenantDO, detailResp); - TenantPackageDO packageDO = packageMapper.selectById(tenantDO.getPackageId()); - if (packageDO != null) { - detailResp.setPackageName(packageDO.getName()); - detailResp.setMenuIds(new JSONArray(packageDO.getMenuIds()).toList(Long.class)); - } - } - fill(detailResp); - return detailResp; + /** + * 生成租户编码 + * + * @return 租户编码 + */ + private String generateCode() { + String code; + do { + code = idGeneratorProvider.getRequired(TenantConstants.CODE_GENERATOR_KEY).generateAsString(); + } while (baseMapper.lambdaQuery().eq(TenantDO::getCode, code).exists()); + return code; } - - @Override - public void bindUser(Long tenantId, Long userId) { - update(Wrappers.lambdaUpdate(TenantDO.class).set(TenantDO::getUserId, userId).eq(BaseIdDO::getId, tenantId)); - TenantDO entity = getById(tenantId); - RedisUtils.set(CacheConstants.TENANT_KEY + tenantId, entity); - } - - @Override - public void checkStatus() { - if (tenantProperties.isEnabled()) { - Long tenantId = TenantContextHolder.getTenantId(); - CheckUtils.throwIfNull(tenantId, "未选择租户"); - if (tenantId != 0) { - TenantDO tenantDO = baseMapper.selectById(tenantId); - CheckUtils.throwIfNull(tenantDO, "租户不存在"); - CheckUtils.throwIfNotEqual(DisEnableStatusEnum.ENABLE.getValue(), tenantDO.getStatus(), "此租户已被禁用"); - //租户过期 - CheckUtils.throwIf(tenantDO.getExpireTime() != null && tenantDO.getExpireTime() - .isBefore(DateUtil.date().toLocalDateTime()), "租户已过期"); - //套餐状态 - TenantPackageDO packageDO = packageMapper.selectById(tenantDO.getPackageId()); - CheckUtils.throwIfNull(tenantDO, "套餐不存在"); - CheckUtils.throwIfNotEqual(DisEnableStatusEnum.ENABLE.getValue(), packageDO.getStatus(), "此租户套餐已被禁用"); - } - } - } - - @Override - @Cached(name = CacheConstants.TENANT_KEY, key = "#id") - public TenantDO getTenantById(Long id) { - return baseMapper.selectById(id); - } - - @Override - protected void afterUpdate(TenantReq req, TenantDO entity) { - RedisUtils.set(CacheConstants.TENANT_KEY + entity.getId(), entity); - } - - @Override - protected void afterDelete(List ids) { - ids.forEach(id -> RedisUtils.delete(CacheConstants.TENANT_KEY + id)); - - } - - @Override - public TenantDO getTenantByUserId(Long userId) { - return baseMapper.selectOne(Wrappers.lambdaQuery(TenantDO.class).eq(TenantDO::getUserId, userId)); - } - } \ No newline at end of file diff --git a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/util/DbConnectUtil.java b/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/util/DbConnectUtil.java deleted file mode 100644 index e4254b7f..00000000 --- a/continew-plugin/continew-plugin-tenant/src/main/java/top/continew/admin/tenant/util/DbConnectUtil.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.admin.tenant.util; - -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.extra.spring.SpringUtil; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; -import top.continew.starter.core.exception.BusinessException; - -import javax.sql.DataSource; -import java.sql.Connection; -import java.util.HashMap; -import java.util.Map; - -/** - * @description: 数据连接工具类 - * @author: 小熊 - * @create: 2024-12-15 18:54 - */ -public class DbConnectUtil { - - /** - * 格式化HikariConfig - */ - public static HikariConfig formatHikariConfig(String host, - Integer port, - String username, - String password, - String dbName, - Map parameter) { - String activeProfile = SpringUtil.getActiveProfile(); - String jdbcUrl = StrUtil.format("jdbc:mysql://{}:{}", host, port); - String driverClassName = "com.mysql.cj.jdbc.Driver"; - if ("dev".equals(activeProfile)) { - jdbcUrl = StrUtil.format("jdbc:p6spy:mysql://{}:{}", host, port); - driverClassName = "com.p6spy.engine.spy.P6SpyDriver"; - } - if (StrUtil.isNotEmpty(dbName)) { - jdbcUrl = StrUtil.format("{}/{}", jdbcUrl, dbName); - } - if (parameter != null) { - jdbcUrl = StrUtil.format("{}?{}", jdbcUrl, MapUtil.join(parameter, "&", "=")); - } - HikariConfig configuration = new HikariConfig(); - configuration.setJdbcUrl(jdbcUrl); - configuration.setDriverClassName(driverClassName); - configuration.setUsername(username); - configuration.setPassword(password); - configuration.setConnectionTimeout(3000L); - return configuration; - } - - /** - * 验证mysql连接有效性并返回数据源 - */ - public static DataSource getMysqlDataSource(String host, - Integer port, - String username, - String password, - String dbName, - Map parameter) { - try { - DataSource dataSource = new HikariDataSource(formatHikariConfig(host, port, username, password, dbName, parameter)); - Connection connection = dataSource.getConnection(); - connection.close(); - return dataSource; - } catch (Exception e) { - throw new BusinessException("数据库连接失败,请检查基础配置信息"); - } - } - - /** - * 默认的mysql连接参数 - * - * @return - */ - public static Map getDefaultMysqlConnectParameter() { - Map parameter = new HashMap<>(); - parameter.put("serverTimezone", "Asia/Shanghai"); - parameter.put("useUnicode", "true"); - parameter.put("characterEncoding", "utf8"); - parameter.put("useSSL", "false"); - parameter.put("allowMultiQueries", "true"); - parameter.put("autoReconnect", "true"); - parameter.put("maxReconnects", "10"); - parameter.put("failOverReadOnly", "false"); - return parameter; - } - -} diff --git a/continew-plugin/pom.xml b/continew-plugin/pom.xml index 2ecaebe7..7622c290 100644 --- a/continew-plugin/pom.xml +++ b/continew-plugin/pom.xml @@ -13,13 +13,13 @@ pom ${project.artifactId} - 插件模块(存放代码生成、任务调度等扩展模块) + 插件模块(存放能力开放、租户等扩展模块) - continew-plugin-schedule continew-plugin-open - continew-plugin-generator continew-plugin-tenant + continew-plugin-schedule + continew-plugin-generator diff --git a/continew-server/pom.xml b/continew-server/pom.xml index 32bc2959..adedb318 100644 --- a/continew-server/pom.xml +++ b/continew-server/pom.xml @@ -34,18 +34,24 @@ continew-system - - - top.continew.admin - continew-plugin-schedule - - top.continew.admin continew-plugin-open + + + top.continew.admin + continew-plugin-tenant + + + + + top.continew.admin + continew-plugin-schedule + + top.continew.admin @@ -64,12 +70,6 @@ liquibase-core - - - top.continew.admin - continew-plugin-tenant - - org.springframework.boot spring-boot-starter-test diff --git a/continew-server/src/main/java/top/continew/admin/config/log/LogDaoLocalImpl.java b/continew-server/src/main/java/top/continew/admin/config/log/LogDaoLocalImpl.java index 986344c1..819325d2 100644 --- a/continew-server/src/main/java/top/continew/admin/config/log/LogDaoLocalImpl.java +++ b/continew-server/src/main/java/top/continew/admin/config/log/LogDaoLocalImpl.java @@ -89,9 +89,7 @@ public class LogDaoLocalImpl implements LogDao { // 设置操作人 this.setCreateUser(logDO, logRequest, logResponse); Long tenantId = TenantContextHolder.getTenantId(); - SpringUtil.getBean(TenantHandler.class).execute(tenantId, () -> { - logMapper.insert(logDO); - }); + SpringUtil.getBean(TenantHandler.class).execute(tenantId, () -> logMapper.insert(logDO)); } /** diff --git a/continew-server/src/main/java/top/continew/admin/config/tenant/DataSourceSwitchAspect.java b/continew-server/src/main/java/top/continew/admin/config/tenant/TenantDataSourceSwitchAspect.java similarity index 52% rename from continew-server/src/main/java/top/continew/admin/config/tenant/DataSourceSwitchAspect.java rename to continew-server/src/main/java/top/continew/admin/config/tenant/TenantDataSourceSwitchAspect.java index deecf743..60cab439 100644 --- a/continew-server/src/main/java/top/continew/admin/config/tenant/DataSourceSwitchAspect.java +++ b/continew-server/src/main/java/top/continew/admin/config/tenant/TenantDataSourceSwitchAspect.java @@ -17,43 +17,64 @@ package top.continew.admin.config.tenant; import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; +import lombok.RequiredArgsConstructor; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; import top.continew.admin.common.constant.SysConstants; -import top.continew.starter.core.constant.PropertiesConstants; +import top.continew.admin.tenant.annotation.ConditionalOnEnabledTenant; import top.continew.starter.extension.tenant.context.TenantContextHolder; import top.continew.starter.extension.tenant.enums.TenantIsolationLevel; /** - * @description: 主数据源切面 - * @author: 小熊 - * @create: 2025-01-15 16:02 + * 租户主数据源切面 + * + * @author 小熊 + * @author Charles7c + * @since 2025/1/15 16:02 */ @Aspect @Component -@ConditionalOnProperty(prefix = PropertiesConstants.TENANT, name = PropertiesConstants.ENABLED, havingValue = "true") -public class DataSourceSwitchAspect { +@ConditionalOnEnabledTenant +@RequiredArgsConstructor +public class TenantDataSourceSwitchAspect { - @Pointcut("execution(* top.continew.admin.tenant.mapper..*(..)) || " + "execution(* top.continew.admin.tenant.service..*(..)) || " + "execution(* top.continew.admin.system.mapper.ClientMapper.*(..)) || " + "execution(* top.continew.admin.system.service.ClientService.*(..)) || " + "execution(* top.continew.admin.system.mapper.DictMapper.*(..)) || " + "execution(* top.continew.admin.system.service.DictService.*(..)) || " + "execution(* top.continew.admin.system.mapper.DictItemMapper.*(..)) || " + "execution(* top.continew.admin.system.service.DictItemService.*(..)) || " + "execution(* top.continew.admin.system.mapper.OptionMapper.*(..)) || " + "execution(* top.continew.admin.system.service.OptionService.*(..)) || " + "execution(* top.continew.admin.system.mapper.StorageMapper.*(..)) || " + "execution(* top.continew.admin.system.service.StorageService.*(..))") - public void MasterDataSourceMethods() { + @Pointcut(""" + execution(* top.continew.admin.tenant.mapper..*(..)) + || execution(* top.continew.admin.tenant.service..*(..)) + || execution(* top.continew.admin.system.mapper.ClientMapper.*(..)) + || execution(* top.continew.admin.system.service.ClientService.*(..)) + || execution(* top.continew.admin.system.mapper.DictMapper.*(..)) + || execution(* top.continew.admin.system.service.DictService.*(..)) + || execution(* top.continew.admin.system.mapper.DictItemMapper.*(..)) + || execution(* top.continew.admin.system.service.DictItemService.*(..)) + || execution(* top.continew.admin.system.mapper.OptionMapper.*(..)) + || execution(* top.continew.admin.system.service.OptionService.*(..)) + || execution(* top.continew.admin.system.mapper.StorageMapper.*(..)) + || execution(* top.continew.admin.system.service.StorageService.*(..)) + """) + public void masterDataSourceMethods() { } - @Before("MasterDataSourceMethods()") + /** + * 切换到主数据源 + */ + @Before("masterDataSourceMethods()") public void switchToMasterDataSource() { if (TenantContextHolder.getIsolationLevel() == TenantIsolationLevel.DATASOURCE) { - DynamicDataSourceContextHolder.push(SysConstants.DEFAULT_DATASOURCE); + DynamicDataSourceContextHolder.push(SysConstants.DEFAULT_TENANT_DATASOURCE); } } - @After("MasterDataSourceMethods()") + /** + * 清空数据源 + */ + @After("masterDataSourceMethods()") public void clearDataSourceContext() { if (TenantContextHolder.getIsolationLevel() == TenantIsolationLevel.DATASOURCE) { DynamicDataSourceContextHolder.poll(); } } - } diff --git a/continew-server/src/main/java/top/continew/admin/controller/common/CaptchaController.java b/continew-server/src/main/java/top/continew/admin/controller/common/CaptchaController.java index 726c7499..95de8826 100644 --- a/continew-server/src/main/java/top/continew/admin/controller/common/CaptchaController.java +++ b/continew-server/src/main/java/top/continew/admin/controller/common/CaptchaController.java @@ -44,7 +44,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import top.continew.admin.auth.model.resp.CaptchaResp; -import top.continew.admin.common.config.properties.CaptchaProperties; +import top.continew.admin.common.config.CaptchaProperties; import top.continew.admin.common.constant.CacheConstants; import top.continew.admin.common.constant.SysConstants; import top.continew.admin.system.enums.OptionCategoryEnum; diff --git a/continew-server/src/main/java/top/continew/admin/controller/common/CommonController.java b/continew-server/src/main/java/top/continew/admin/controller/common/CommonController.java index 2e5ccba8..aded4625 100644 --- a/continew-server/src/main/java/top/continew/admin/controller/common/CommonController.java +++ b/continew-server/src/main/java/top/continew/admin/controller/common/CommonController.java @@ -35,6 +35,10 @@ import top.continew.admin.system.enums.OptionCategoryEnum; import top.continew.admin.system.model.query.*; import top.continew.admin.system.model.resp.file.FileUploadResp; import top.continew.admin.system.service.*; +import top.continew.admin.tenant.model.query.DatasourceQuery; +import top.continew.admin.tenant.model.query.PackageQuery; +import top.continew.admin.tenant.service.DatasourceService; +import top.continew.admin.tenant.service.PackageService; import top.continew.starter.core.util.validation.ValidationUtils; import top.continew.starter.extension.crud.model.query.SortQuery; import top.continew.starter.extension.crud.model.resp.LabelValueResp; @@ -62,6 +66,8 @@ public class CommonController { private final MenuService menuService; private final UserService userService; private final RoleService roleService; + private final PackageService packageService; + private final DatasourceService datasourceService; private final DictItemService dictItemService; private final OptionService optionService; @@ -104,6 +110,18 @@ public class CommonController { return roleService.listDict(query, sortQuery); } + @Operation(summary = "查询套餐字典", description = "查询套餐字典列表") + @GetMapping("/dict/package") + public List listPackageDict(PackageQuery query, SortQuery sortQuery) { + return packageService.listDict(query, sortQuery); + } + + @Operation(summary = "查询数据源字典", description = "查询数据源字典列表") + @GetMapping("/dict/datasource") + public List listDatasourceDict(DatasourceQuery query, SortQuery sortQuery) { + return datasourceService.listDict(query, sortQuery); + } + @Operation(summary = "查询字典", description = "查询字典列表") @Parameter(name = "code", description = "字典编码", example = "notice_type", in = ParameterIn.PATH) @GetMapping("/dict/{code}") diff --git a/continew-server/src/main/resources/config/application-dev.yml b/continew-server/src/main/resources/config/application-dev.yml index a7e88c3d..677fe793 100644 --- a/continew-server/src/main/resources/config/application-dev.yml +++ b/continew-server/src/main/resources/config/application-dev.yml @@ -22,11 +22,17 @@ spring.datasource: datasource: # 主库配置(可配多个,构成多主) master: - url: jdbc:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:continew_admin}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&autoReconnect=true&maxReconnects=10&failOverReadOnly=false + # 请务必提前创建好名为 continew_admin 的数据库,如果使用其他数据库名请注意同步修改 DB_NAME 配置 + url: jdbc:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:continew_admin}?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true username: ${DB_USER:root} password: ${DB_PWD:123456} driver-class-name: com.mysql.cj.jdbc.Driver type: ${spring.datasource.type} + # # PostgreSQL 配置 + # url: jdbc:postgresql://${DB_HOST:127.0.0.1}:${DB_PORT:5432}/${DB_NAME:continew_admin}?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&stringtype=unspecified + # username: ${DB_USER:postgres} + # password: ${DB_PWD:123456} + # driver-class-name: org.postgresql.Driver # Hikari 连接池配置(完整配置请参阅:https://github.com/brettwooldridge/HikariCP) hikari: # 最大连接数量(默认 10,根据实际环境调整) @@ -41,7 +47,6 @@ spring.datasource: # 连接最大生存时间(默认 1800000 毫秒,30 分钟) max-lifetime: 1800000 - ## Liquibase 配置 spring.liquibase: # 是否启用 @@ -176,7 +181,7 @@ captcha: expirationInMinutes: 5 --- ### 短信配置 -## 提示:配置文件方式和 [短信配置] 功能可任选其一方式使用,也可共同使用,但实际开发时建议选择一种,注释或删除另一方 +## 提示:配置文件方式和 [系统管理/系统配置/短信配置] 功能可任选其一方式使用,也可共同使用,但实际开发时建议选择一种,注释或删除另一方 sms: http-log: true is-print: true @@ -192,7 +197,7 @@ sms: # sdk-app-id: 你的应用ID --- ### 邮件配置 -## 提示:配置文件方式和 [邮件配置] 功能可任选其一方式使用,实际开发时请注释或删除另一方 +## 提示:配置文件方式和 [系统管理/系统配置/邮件配置] 功能可任选其一方式使用,实际开发时请注释或删除另一方 #spring.mail: # # 根据需要更换 # host: smtp.126.com diff --git a/continew-server/src/main/resources/config/application-prod.yml b/continew-server/src/main/resources/config/application-prod.yml index 94815ecf..d2188273 100644 --- a/continew-server/src/main/resources/config/application-prod.yml +++ b/continew-server/src/main/resources/config/application-prod.yml @@ -24,11 +24,17 @@ spring.datasource: datasource: # 主库配置(可配多个,构成多主) master: - url: jdbc:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:continew_admin}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&autoReconnect=true&maxReconnects=10&failOverReadOnly=false + # 请务必提前创建好名为 continew_admin 的数据库,如果使用其他数据库名请注意同步修改 DB_NAME 配置 + url: jdbc:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:continew_admin}?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true username: ${DB_USER:root} password: ${DB_PWD:123456} driver-class-name: com.mysql.cj.jdbc.Driver type: ${spring.datasource.type} + # # PostgreSQL 配置 + # url: jdbc:postgresql://${DB_HOST:127.0.0.1}:${DB_PORT:5432}/${DB_NAME:continew_admin}?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&stringtype=unspecified + # username: ${DB_USER:postgres} + # password: ${DB_PWD:123456} + # driver-class-name: org.postgresql.Driver # Hikari 连接池配置(完整配置请参阅:https://github.com/brettwooldridge/HikariCP) hikari: # 最大连接数量(默认 10,根据实际环境调整) diff --git a/continew-server/src/main/resources/config/application.yml b/continew-server/src/main/resources/config/application.yml index 4856d5b8..7ae121e5 100644 --- a/continew-server/src/main/resources/config/application.yml +++ b/continew-server/src/main/resources/config/application.yml @@ -182,13 +182,6 @@ continew-starter.trace: pattern: '[$spanId][$traceId]' mdc-enable: false ---- ### 全局树结构配置(简单树,对应前端 UI) -continew-starter.crud: - tree: - id-key: key - name-key: title - weight-key: sort - --- ### 安全配置:密码编码器配置 continew-starter.security: password: @@ -196,6 +189,46 @@ continew-starter.security: # BCryptPasswordEncoder(如有改动,需同步调整 top.continew.admin.common.config.mybatis.BCryptEncryptor) encoding-id: bcrypt +--- ### CRUD 配置 +continew-starter.crud: + ## 全局树结构配置(简单树,对应前端 UI) + tree: + id-key: key + name-key: title + weight-key: sort + +--- ### 租户配置 +continew-starter.tenant: + enabled: true + # 超级/默认租户 ID + super-tenant-id: 0 + # 忽略表(忽略拼接租户条件) + ignore-tables: + - gen_config # 代码生成 + - gen_field_config + - sys_dict # 字典表 + - sys_dict_item + - sys_option # 参数 + - sys_storage # 存储配置 + - tenant # 租户 + - tenant_package + - tenant_package_menu + - tenant_datasource + - sys_client # 客户端管理 + - sys_sms_config + - sys_sms_log + - sys_app # 应用 + # 忽略菜单 ID(租户不能使用的菜单) + ignore-menus: + - 1130 # 字典管理 + - 1140 # 字典项管理 + - 1150 # 系统配置 + - 2050 # 短信日志 + - 3000 # 租户管理 + - 7000 # 能力开放 + - 8000 # 任务调度 + - 9000 # 代码生成 + --- ### 限流器配置 continew-starter: rate-limiter: @@ -287,6 +320,14 @@ cosid: safe-js: machine-bit: 7 sequence-bit: 9 + # 租户编码 + tenant-code: + converter: + type: RADIX + prefix: T + radix: + char-size: 11 + pad-start: true --- ### 认证配置 auth: @@ -298,32 +339,3 @@ auth: - /auth/logout - /system/user/password -#多租户配置 -continew-starter.tenant: - enabled: true - # 多租户忽略的表 - ignore-tables: - - gen_config # 代码生成 - - gen_field_config - - sys_dict # 字典表 - - sys_dict_item - - sys_option #参数 - - sys_storage # 存储配置 - - sys_tenant # 租户 - - sys_tenant_package - - sys_tenant_db_connect - - sys_app #应用 - - sys_client #客户端管理 - - sys_sms_config - - sys_sms_log - #租户不能使用的菜单 - ignore-menus: - - 1130 #字典管理 - - 1140 - - 1150 #系统配置 - - 2050 #短信日志 - - 3000 #任务调度 - - 9000 #代码生成 - - 7000 #能力开放 - - 7010 #应用管理 - - 10010 #租户管理 \ No newline at end of file diff --git a/continew-server/src/main/resources/db/changelog/db.changelog-master.yaml b/continew-server/src/main/resources/db/changelog/db.changelog-master.yaml index fe77c111..44a1729d 100644 --- a/continew-server/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/continew-server/src/main/resources/db/changelog/db.changelog-master.yaml @@ -5,14 +5,14 @@ databaseChangeLog: file: db/changelog/mysql/main_column.sql - include: file: db/changelog/mysql/main_data.sql - - include: - file: db/changelog/mysql/plugin/plugin_schedule.sql - include: file: db/changelog/mysql/plugin/plugin_open.sql - - include: - file: db/changelog/mysql/plugin/plugin_generator.sql - include: file: db/changelog/mysql/plugin/plugin_tenant.sql + - include: + file: db/changelog/mysql/plugin/plugin_schedule.sql + - include: + file: db/changelog/mysql/plugin/plugin_generator.sql # PostgreSQL # - include: # file: db/changelog/postgresql/main_table.sql @@ -21,8 +21,10 @@ databaseChangeLog: # - include: # file: db/changelog/postgresql/main_data.sql # - include: -# file: db/changelog/postgresql/plugin/plugin_schedule.sql -# - include: # file: db/changelog/postgresql/plugin/plugin_open.sql # - include: +# file: db/changelog/postgresql/plugin/plugin_tenant.sql +# - include: +# file: db/changelog/postgresql/plugin/plugin_schedule.sql +# - include: # file: db/changelog/postgresql/plugin/plugin_generator.sql \ No newline at end of file diff --git a/continew-server/src/main/resources/db/changelog/mysql/main_data.sql b/continew-server/src/main/resources/db/changelog/mysql/main_data.sql index 524148c9..ad495826 100644 --- a/continew-server/src/main/resources/db/changelog/mysql/main_data.sql +++ b/continew-server/src/main/resources/db/changelog/mysql/main_data.sql @@ -18,7 +18,7 @@ VALUES (1018, '重置密码', 1010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:user:resetPwd', 8, 1, 1, NOW()), (1019, '分配角色', 1010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:user:updateRole', 9, 1, 1, NOW()), -(1030, '角色管理', 1000, 2, '/system/role', 'SystemRole', 'system/role/index', NULL, 'user-group', b'0', b'0', b'0', NULL, 2, 1, 1, NOW()), +(1030, '角色管理', 1000, 2, '/system/role', 'SystemRole', 'system/role/index', NULL, 'user-management', b'0', b'0', b'0', NULL, 2, 1, 1, NOW()), (1031, '列表', 1030, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:role:list', 1, 1, 1, NOW()), (1032, '详情', 1030, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:role:get', 2, 1, 1, NOW()), (1033, '新增', 1030, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:role:create', 3, 1, 1, NOW()), @@ -97,7 +97,7 @@ VALUES (1215, '删除', 1210, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'system:smsConfig:delete', 5, 1, 1, NOW()), (1216, '导出', 1210, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'system:smsConfig:export', 6, 1, 1, NOW()), (1217, '设为默认配置', 1210, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'system:smsConfig:setDefault', 7, 1, 1, NOW()), -(1230, '存储配置', 1150, 2, '/system/config?tab=storage', 'SystemStorage', 'system/config/storage/index', NULL, 'storage', b'0', b'0', b'1', NULL, 6, 1, 1, NOW()), +(1230, '存储配置', 1150, 2, '/system/config?tab=storage', 'SystemStorage', 'system/config/storage/index', NULL, 'block-storage', b'0', b'0', b'1', NULL, 6, 1, 1, NOW()), (1231, '列表', 1230, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:list', 1, 1, 1, NOW()), (1232, '详情', 1230, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:get', 2, 1, 1, NOW()), (1233, '新增', 1230, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:create', 3, 1, 1, NOW()), diff --git a/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_generator.sql b/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_generator.sql index ca16b212..af569616 100644 --- a/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_generator.sql +++ b/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_generator.sql @@ -1,7 +1,7 @@ -- liquibase formatted sql -- changeset charles7c:1 --- comment 初始化代码生成插件 +-- comment 初始化代码生成插件数据表 -- 初始化表结构 CREATE TABLE IF NOT EXISTS `gen_config` ( `table_name` varchar(64) NOT NULL COMMENT '表名称', diff --git a/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_open.sql b/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_open.sql index 5ece6906..0231af95 100644 --- a/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_open.sql +++ b/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_open.sql @@ -1,7 +1,7 @@ -- liquibase formatted sql -- changeset chengzi:1 --- comment 初始化能力开放插件 +-- comment 初始化能力开放插件数据表 -- 初始化表结构 CREATE TABLE IF NOT EXISTS `sys_app` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', diff --git a/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_schedule.sql b/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_schedule.sql index d483875d..55b7e77f 100644 --- a/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_schedule.sql +++ b/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_schedule.sql @@ -1,21 +1,22 @@ -- liquibase formatted sql -- changeset kai:1 --- comment 初始化任务调度插件 +-- comment 初始化任务调度插件数据表 -- 初始化默认菜单 INSERT INTO `sys_menu` (`id`, `title`, `parent_id`, `type`, `path`, `name`, `component`, `redirect`, `icon`, `is_external`, `is_cache`, `is_hidden`, `permission`, `sort`, `status`, `create_user`, `create_time`) VALUES -(3000, '任务调度', 0, 1, '/schedule', 'Schedule', 'Layout', '/schedule/job', 'schedule', b'0', b'0', b'0', NULL, 3, 1, 1, NOW()), -(3010, '任务管理', 3000, 2, '/schedule/job', 'ScheduleJob', 'schedule/job/index', NULL, 'select-all', b'0', b'0', b'0', NULL, 1, 1, 1, NOW()), -(3011, '列表', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:list', 1, 1, 1, NOW()), -(3012, '详情', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:get', 2, 1, 1, NOW()), -(3013, '新增', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:create', 3, 1, 1, NOW()), -(3014, '修改', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:update', 4, 1, 1, NOW()), -(3015, '删除', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:delete', 5, 1, 1, NOW()), -(3016, '执行', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:trigger', 6, 1, 1, NOW()), -(3020, '任务日志', 3000, 2, '/schedule/log', 'ScheduleLog', 'schedule/log/index', NULL, 'find-replace', b'0', b'0', b'0', NULL, 2, 1, 1, NOW()), -(3021, '列表', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:list', 1, 1, 1, NOW()), -(3022, '详情', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:get', 2, 1, 1, NOW()), -(3023, '停止', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:stop', 3, 1, 1, NOW()), -(3024, '重试', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:retry', 4, 1, 1, NOW()); +(8000, '任务调度', 0, 1, '/schedule', 'Schedule', 'Layout', '/schedule/job', 'schedule', b'0', b'0', b'0', NULL, 8, 1, 1, NOW()), +(8010, '任务管理', 8000, 2, '/schedule/job', 'ScheduleJob', 'schedule/job/index', NULL, 'select-all', b'0', b'0', b'0', NULL, 1, 1, 1, NOW()), +(8011, '列表', 8010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:list', 1, 1, 1, NOW()), +(8012, '详情', 8010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:get', 2, 1, 1, NOW()), +(8013, '新增', 8010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:create', 3, 1, 1, NOW()), +(8014, '修改', 8010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:update', 4, 1, 1, NOW()), +(8015, '删除', 8010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:delete', 5, 1, 1, NOW()), +(8016, '执行', 8010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:trigger', 6, 1, 1, NOW()), + +(8020, '任务日志', 8000, 2, '/schedule/log', 'ScheduleLog', 'schedule/log/index', NULL, 'find-replace', b'0', b'0', b'0', NULL, 2, 1, 1, NOW()), +(8021, '列表', 8020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:list', 1, 1, 1, NOW()), +(8022, '详情', 8020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:get', 2, 1, 1, NOW()), +(8023, '停止', 8020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:stop', 3, 1, 1, NOW()), +(8024, '重试', 8020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:retry', 4, 1, 1, NOW()); diff --git a/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_tenant.sql b/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_tenant.sql index 9744d9f1..a8494896 100644 --- a/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_tenant.sql +++ b/continew-server/src/main/resources/db/changelog/mysql/plugin/plugin_tenant.sql @@ -1,145 +1,171 @@ -- liquibase formatted sql -- changeset 小熊:1 --- comment 初始化表结构 +-- comment 初始化租户插件数据表 +-- 初始化表结构 +CREATE TABLE IF NOT EXISTS `tenant` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `name` varchar(30) NOT NULL COMMENT '名称', + `code` varchar(30) NOT NULL COMMENT '编码', + `domain` varchar(255) DEFAULT NULL COMMENT '域名', + `expire_time` datetime DEFAULT NULL COMMENT '过期时间', + `isolation_level` tinyint(1) UNSIGNED NOT NULL COMMENT '隔离级别', + `description` varchar(200) DEFAULT NULL COMMENT '描述', + `status` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态(1:启用;2:禁用)', + `admin_user` bigint(20) DEFAULT NULL COMMENT '租户管理员', + `package_id` bigint(20) NOT NULL COMMENT '套餐ID', + `datasource_id` bigint(20) DEFAULT NULL COMMENT '数据源ID', + `create_user` bigint(20) NOT NULL COMMENT '创建人', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE INDEX `uk_code`(`code`), + INDEX `idx_admin_user`(`admin_user`), + INDEX `idx_package_id`(`package_id`), + INDEX `idx_datasource_id`(`datasource_id`), + INDEX `idx_create_user`(`create_user`), + INDEX `idx_update_user`(`update_user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户表'; --- ---------------------------- --- Table structure for sys_tenant --- ---------------------------- -DROP TABLE IF EXISTS `sys_tenant`; -CREATE TABLE `sys_tenant` ( -`id` bigint NOT NULL COMMENT 'ID', -`name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '租户名称', -`tenant_sn` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '租户编号', -`user_id` bigint DEFAULT NULL COMMENT '租户对应的用户', -`domain` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '绑定的域名', -`package_id` bigint NOT NULL COMMENT '租户套餐编号', -`status` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '状态(1:启用;2:禁用)', -`expire_time` datetime DEFAULT NULL COMMENT '租户过期时间', -`create_user` bigint NOT NULL COMMENT '创建人', -`create_time` datetime NOT NULL COMMENT '创建时间', -`update_user` bigint DEFAULT NULL COMMENT '修改人', -`update_time` datetime DEFAULT NULL COMMENT '修改时间', -`isolation_level` tinyint unsigned NOT NULL COMMENT '隔离级别', -`db_connect_id` bigint DEFAULT NULL COMMENT '数据连接ID', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='租户表'; +CREATE TABLE IF NOT EXISTS `tenant_package` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `name` varchar(30) NOT NULL COMMENT '名称', + `sort` int NOT NULL DEFAULT 999 COMMENT '排序', + `menu_check_strictly` bit(1) DEFAULT b'1' COMMENT '菜单选择是否父子节点关联', + `description` varchar(200) DEFAULT NULL COMMENT '描述', + `status` tinyint UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态(1:启用;2:禁用)', + `create_user` bigint(20) NOT NULL COMMENT '创建人', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + PRIMARY KEY (`id`), + INDEX `idx_create_user`(`create_user`), + INDEX `idx_update_user`(`update_user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户套餐表'; --- ---------------------------- --- Table structure for sys_tenant_package --- ---------------------------- -DROP TABLE IF EXISTS `sys_tenant_package`; -CREATE TABLE `sys_tenant_package` ( - `id` bigint NOT NULL COMMENT 'ID', - `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '套餐名称', - `menu_ids` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '关联的菜单ids', - `menu_check_strictly` bit(1) DEFAULT b'0' COMMENT '菜单选择是否父子节点关联', - `status` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '状态(1:启用;2:禁用)', - `create_user` bigint NOT NULL COMMENT '创建人', - `create_time` datetime NOT NULL COMMENT '创建时间', - `update_user` bigint DEFAULT NULL COMMENT '修改人', - `update_time` datetime DEFAULT NULL COMMENT '修改时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='租户套餐表'; +CREATE TABLE IF NOT EXISTS `tenant_package_menu` ( + `package_id` bigint(20) NOT NULL COMMENT '套餐ID', + `menu_id` bigint(20) NOT NULL COMMENT '菜单ID', + PRIMARY KEY (`package_id`, `menu_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户套餐和菜单关联表'; --- ---------------------------- --- Table structure for sys_tenant_db_connect --- ---------------------------- -CREATE TABLE `sys_tenant_db_connect` ( - `id` bigint NOT NULL COMMENT 'ID', - `connect_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '连接名称', - `type` tinyint(1) NOT NULL COMMENT '连接类型', - `host` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '连接主机地址', - `port` smallint NOT NULL COMMENT '连接端口', - `username` varchar(128) NOT NULL COMMENT '连接用户名', - `password` varchar(128) NOT NULL COMMENT '连接密码', - `create_user` bigint NOT NULL COMMENT '创建人', - `create_time` datetime NOT NULL COMMENT '创建时间', - `update_user` bigint DEFAULT NULL COMMENT '修改人', - `update_time` datetime DEFAULT NULL COMMENT '修改时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='租户数据库连接表'; +CREATE TABLE IF NOT EXISTS `tenant_datasource` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `name` varchar(30) NOT NULL COMMENT '名称', + `database_type` tinyint(1) NOT NULL COMMENT '数据库类型(1:MySQL)', + `host` varchar(128) NOT NULL COMMENT '主机', + `port` int NOT NULL COMMENT '端口', + `username` varchar(128) NOT NULL COMMENT '用户名', + `password` varchar(128) NOT NULL COMMENT '密码', + `description` varchar(200) DEFAULT NULL COMMENT '描述', + `create_user` bigint(20) NOT NULL COMMENT '创建人', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + PRIMARY KEY (`id`), + INDEX `idx_create_user`(`create_user`), + INDEX `idx_update_user`(`update_user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户数据源表'; +-- 为已有表增加租户字段 +ALTER TABLE `sys_menu` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_dept` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_role` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_user` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_user_password_history` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_user_social` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_user_role` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_role_menu` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_role_dept` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_log` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_message` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_message_log` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_notice` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_notice_log` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_file` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); +ALTER TABLE `sys_app` + ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID', + ADD INDEX `idx_tenant_id` (`tenant_id`); --- changeset 小熊:2 --- comment 添加租户列和索引 -ALTER TABLE sys_app ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_app_tenant_id ON sys_app(tenant_id); -ALTER TABLE sys_dept ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_dept_tenant_id ON sys_dept(tenant_id); -ALTER TABLE sys_file ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_file_tenant_id ON sys_file(tenant_id); -ALTER TABLE sys_log ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_log_tenant_id ON sys_log(tenant_id); -ALTER TABLE sys_menu ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_menu_tenant_id ON sys_menu(tenant_id); -ALTER TABLE sys_message ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_message_tenant_id ON sys_message(tenant_id); -ALTER TABLE sys_message_log ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_message_log_tenant_id ON sys_message_log(tenant_id); -ALTER TABLE sys_notice ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_notice_tenant_id ON sys_notice(tenant_id); -ALTER TABLE sys_notice_log ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_notice_log_tenant_id ON sys_notice_log(tenant_id); -ALTER TABLE sys_role ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_role_tenant_id ON sys_role(tenant_id); -ALTER TABLE sys_user ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_user_tenant_id ON sys_user(tenant_id); -ALTER TABLE sys_role_dept ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_role_dept_tenant_id ON sys_role_dept(tenant_id); -ALTER TABLE sys_role_menu ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_role_menu_tenant_id ON sys_role_menu(tenant_id); -ALTER TABLE sys_user_password_history ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_user_password_history_tenant_id ON sys_user_password_history(tenant_id); -ALTER TABLE sys_user_role ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_user_role_tenant_id ON sys_user_role(tenant_id); -ALTER TABLE sys_user_social ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 0; -CREATE INDEX idx_sys_user_social_tenant_id ON sys_user_social(tenant_id); +-- 调整唯一索引 +ALTER TABLE `sys_menu` + DROP INDEX `uk_title_parent_id`, + ADD UNIQUE INDEX `uk_title_parent_id` (`title`, `parent_id`, `tenant_id`); +ALTER TABLE `sys_dept` + DROP INDEX `uk_name_parent_id`, + ADD UNIQUE INDEX `uk_name_parent_id` (`name`, `parent_id`, `tenant_id`); +ALTER TABLE `sys_role` + DROP INDEX `uk_name`, + DROP INDEX `uk_code`, + ADD UNIQUE INDEX `uk_name` (`name`, `tenant_id`), + ADD UNIQUE INDEX `uk_code` (`code`, `tenant_id`); +ALTER TABLE `sys_user` + DROP INDEX `uk_username`, + DROP INDEX `uk_email`, + DROP INDEX `uk_phone`, + ADD UNIQUE INDEX `uk_username` (`username`, `tenant_id`), + ADD UNIQUE INDEX `uk_email` (`email`, `tenant_id`), + ADD UNIQUE INDEX `uk_phone` (`phone`, `tenant_id`); +ALTER TABLE `sys_app` + DROP INDEX `uk_access_key`, + ADD UNIQUE INDEX `uk_access_key` (`access_key`, `tenant_id`); --- changeset 小熊:3 --- comment 唯一索引变更 -ALTER TABLE sys_app DROP INDEX `uk_access_key`; -ALTER TABLE sys_app ADD UNIQUE INDEX `uk_access_key` (`access_key`, `tenant_id`); -ALTER TABLE sys_dept DROP INDEX `uk_name_parent_id`; -ALTER TABLE sys_dept ADD UNIQUE INDEX `uk_name_parent_id` (`name`, `parent_id`, `tenant_id`); -ALTER TABLE sys_menu DROP INDEX `uk_title_parent_id`; -ALTER TABLE sys_menu ADD UNIQUE INDEX `uk_title_parent_id` (`title`, `parent_id`, `tenant_id`); -ALTER TABLE sys_role DROP INDEX `uk_name`; -ALTER TABLE sys_role ADD UNIQUE INDEX `uk_name` (`name`, `tenant_id`); -ALTER TABLE sys_role DROP INDEX `uk_code`; -ALTER TABLE sys_role ADD UNIQUE INDEX `uk_code` (`code`, `tenant_id`); -ALTER TABLE sys_user DROP INDEX `uk_username`; -ALTER TABLE sys_user ADD UNIQUE INDEX `uk_username` (`username`, `tenant_id`); -ALTER TABLE sys_user DROP INDEX `uk_email`; -ALTER TABLE sys_user ADD UNIQUE INDEX `uk_email` (`email`, `tenant_id`); -ALTER TABLE sys_user DROP INDEX `uk_phone`; -ALTER TABLE sys_user ADD UNIQUE INDEX `uk_phone` (`phone`, `tenant_id`); - --- changeset 小熊:4 --- comment 菜单录入 +-- 初始化默认菜单 INSERT INTO `sys_menu` -(`id`, `title`, `parent_id`, `type`, `path`, `name`, `component`, `redirect`, `icon`, `is_external`, `is_cache`, `is_hidden`, `permission`, `sort`, `status`, `create_user`, `create_time`, `update_user`, `update_time`, `tenant_id`) +(`id`, `title`, `parent_id`, `type`, `path`, `name`, `component`, `redirect`, `icon`, `is_external`, `is_cache`, `is_hidden`, `permission`, `sort`, `status`, `create_user`, `create_time`) VALUES -(10010, '租户管理', 0, 1, '/tenant', 'Tenant', 'Layout', '/tenant/user', 'user-group', b'0', b'0', b'0', NULL, 6, 1, 1, NOW(), NULL, NULL, 0), -(10015, '租户套餐', 10010, 2, '/tenant/package', 'TenantPackage', 'tenant/package/index', NULL, 'menu', b'0', b'0', b'0', NULL, 2, 1, 1, NOW(), NULL, NULL, 0), -(10016, '列表', 10015, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:list', 1, 1, 1, NOW(), NULL, NULL, 0), -(10017, '详情', 10015, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:detail', 2, 1, 1, NOW(), NULL, NULL, 0), -(10018, '新增', 10015, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:add', 3, 1, 1, NOW(), NULL, NULL, 0), -(10019, '修改', 10015, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:update', 4, 1, 1, NOW(), NULL, NULL, 0), -(10020, '删除', 10015, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:delete', 5, 1, 1, NOW(), NULL, NULL, 0), -(10022, '租户管理', 10010, 2, '/tenant/user', 'TenantUser', 'tenant/user/index', NULL, 'user-group', b'0', b'0', b'0', NULL, 1, 1, 1, NOW(), NULL, NULL, 0), -(10023, '列表', 10022, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:user:list', 1, 1, 1, NOW(), NULL, NULL, 0), -(10024, '详情', 10022, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:user:detail', 2, 1, 1, NOW(), NULL, NULL, 0), -(10025, '新增', 10022, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:user:add', 3, 1, 1, NOW(), NULL, NULL, 0), -(10026, '修改', 10022, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:user:update', 4, 1, 1, NOW(), NULL, NULL, 0), -(10027, '删除', 10022, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:user:delete', 5, 1, 1, NOW(), NULL, NULL, 0), -(10028, '账号更新', 10022, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:user:editLoginUserInfo', 6, 1, 1, NOW(), NULL, NULL, 0), -(10040, '数据连接', 10010, 2, '/tenant/dbConnect', 'TenantDbConnect', 'tenant/tenantDbConnect/index', NULL, 'storage', b'0', b'0', b'0', NULL, 3, 1, 1, NOW(), NULL, NULL, 0), -(10041, '列表', 10040, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:dbConnect:list', 1, 1, 1, NOW(), NULL, NULL, 0), -(10042, '详情', 10040, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:dbConnect:detail', 2, 1, 1, NOW(), NULL, NULL, 0), -(10043, '新增', 10040, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:dbConnect:add', 3, 1, 1, NOW(), NULL, NULL, 0), -(10044, '修改', 10040, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:dbConnect:update', 4, 1, 1, NOW(), NULL, NULL, 0), -(10045, '删除', 10040, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:dbConnect:delete', 5, 1, 1, NOW(), NULL, NULL, 0); +(3000, '租户管理', 0, 1, '/tenant', 'Tenant', 'Layout', '/tenant/management', 'user-group', b'0', b'0', b'0', NULL, 6, 1, 1, NOW()), +(3010, '租户管理', 3000, 2, '/tenant/management', 'TenantManagement', 'tenant/management/index', NULL, 'user-group', b'0', b'0', b'0', NULL, 1, 1, 1, NOW()), +(3011, '列表', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:management:list', 1, 1, 1, NOW()), +(3012, '详情', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:management:get', 2, 1, 1, NOW()), +(3013, '新增', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:management:create', 3, 1, 1, NOW()), +(3014, '修改', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:management:update', 4, 1, 1, NOW()), +(3015, '删除', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:management:delete', 5, 1, 1, NOW()), +(3016, '修改租户管理员密码', 3010, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:management:updateAdminUserPwd', 6, 1, 1, NOW()), +(3020, '套餐管理', 3000, 2, '/tenant/package', 'TenantPackage', 'tenant/package/index', NULL, 'project', b'0', b'0', b'0', NULL, 2, 1, 1, NOW()), +(3021, '列表', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:list', 1, 1, 1, NOW()), +(3022, '详情', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:get', 2, 1, 1, NOW()), +(3023, '新增', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:create', 3, 1, 1, NOW()), +(3024, '修改', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:update', 4, 1, 1, NOW()), +(3025, '删除', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:delete', 5, 1, 1, NOW()), +(3030, '数据源管理', 3000, 2, '/tenant/datasource', 'TenantDatasource', 'tenant/datasource/index', NULL, 'storage', b'0', b'0', b'0', NULL, 3, 1, 1, NOW()), +(3031, '列表', 3030, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:datasource:list', 1, 1, 1, NOW()), +(3032, '详情', 3030, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:datasource:get', 2, 1, 1, NOW()), +(3033, '新增', 3030, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:datasource:create', 3, 1, 1, NOW()), +(3034, '修改', 3030, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:datasource:update', 4, 1, 1, NOW()), +(3035, '删除', 3030, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:datasource:delete', 5, 1, 1, NOW()), +(3036, '测试连接', 3030, 3, NULL, NULL, NULL, NULL, NULL, b'0', b'0', b'0', 'tenant:datasource:testConnection', 6, 1, 1, NOW()); diff --git a/continew-server/src/main/resources/db/changelog/mysql/tenant_table.sql b/continew-server/src/main/resources/db/changelog/mysql/tenant_table.sql deleted file mode 100644 index 0087b12e..00000000 --- a/continew-server/src/main/resources/db/changelog/mysql/tenant_table.sql +++ /dev/null @@ -1,241 +0,0 @@ --- 数据源级别租户表结构 - -CREATE TABLE IF NOT EXISTS `sys_menu` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', - `title` varchar(30) NOT NULL COMMENT '标题', - `parent_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '上级菜单ID', - `type` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '类型(1:目录;2:菜单;3:按钮)', - `path` varchar(255) DEFAULT NULL COMMENT '路由地址', - `name` varchar(50) DEFAULT NULL COMMENT '组件名称', - `component` varchar(255) DEFAULT NULL COMMENT '组件路径', - `redirect` varchar(255) DEFAULT NULL COMMENT '重定向地址', - `icon` varchar(50) DEFAULT NULL COMMENT '图标', - `is_external` bit(1) DEFAULT b'0' COMMENT '是否外链', - `is_cache` bit(1) DEFAULT b'0' COMMENT '是否缓存', - `is_hidden` bit(1) DEFAULT b'0' COMMENT '是否隐藏', - `permission` varchar(100) DEFAULT NULL COMMENT '权限标识', - `sort` int NOT NULL DEFAULT 999 COMMENT '排序', - `status` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态(1:启用;2:禁用)', - `create_user` bigint(20) NOT NULL COMMENT '创建人', - `create_time` datetime NOT NULL COMMENT '创建时间', - `update_user` bigint(20) DEFAULT NULL COMMENT '修改人', - `update_time` datetime DEFAULT NULL COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE INDEX `uk_title_parent_id`(`title`, `parent_id`), - INDEX `idx_parent_id`(`parent_id`), - INDEX `idx_create_user`(`create_user`), - INDEX `idx_update_user`(`update_user`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菜单表'; - -CREATE TABLE IF NOT EXISTS `sys_dept` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', - `name` varchar(30) NOT NULL COMMENT '名称', - `parent_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '上级部门ID', - `ancestors` varchar(512) NOT NULL DEFAULT '' COMMENT '祖级列表', - `description` varchar(200) DEFAULT NULL COMMENT '描述', - `sort` int NOT NULL DEFAULT 999 COMMENT '排序', - `status` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态(1:启用;2:禁用)', - `is_system` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否为系统内置数据', - `create_user` bigint(20) NOT NULL COMMENT '创建人', - `create_time` datetime NOT NULL COMMENT '创建时间', - `update_user` bigint(20) DEFAULT NULL COMMENT '修改人', - `update_time` datetime DEFAULT NULL COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE INDEX `uk_name_parent_id`(`name`, `parent_id`), - INDEX `idx_parent_id`(`parent_id`), - INDEX `idx_create_user`(`create_user`), - INDEX `idx_update_user`(`update_user`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门表'; - -CREATE TABLE IF NOT EXISTS `sys_role` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', - `name` varchar(30) NOT NULL COMMENT '名称', - `code` varchar(30) NOT NULL COMMENT '编码', - `data_scope` tinyint(1) NOT NULL DEFAULT 4 COMMENT '数据权限(1:全部数据权限;2:本部门及以下数据权限;3:本部门数据权限;4:仅本人数据权限;5:自定义数据权限)', - `description` varchar(200) DEFAULT NULL COMMENT '描述', - `sort` int NOT NULL DEFAULT 999 COMMENT '排序', - `is_system` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否为系统内置数据', - `menu_check_strictly` bit(1) DEFAULT b'0' COMMENT '菜单选择是否父子节点关联', - `dept_check_strictly` bit(1) DEFAULT b'0' COMMENT '部门选择是否父子节点关联', - `create_user` bigint(20) NOT NULL COMMENT '创建人', - `create_time` datetime NOT NULL COMMENT '创建时间', - `update_user` bigint(20) DEFAULT NULL COMMENT '修改人', - `update_time` datetime DEFAULT NULL COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE INDEX `uk_name`(`name`), - UNIQUE INDEX `uk_code`(`code`), - INDEX `idx_create_user`(`create_user`), - INDEX `idx_update_user`(`update_user`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; - -CREATE TABLE IF NOT EXISTS `sys_user` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', - `username` varchar(64) NOT NULL COMMENT '用户名', - `nickname` varchar(30) NOT NULL COMMENT '昵称', - `password` varchar(255) DEFAULT NULL COMMENT '密码', - `gender` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '性别(0:未知;1:男;2:女)', - `email` varchar(255) DEFAULT NULL COMMENT '邮箱', - `phone` varchar(255) DEFAULT NULL COMMENT '手机号码', - `avatar` longtext DEFAULT NULL COMMENT '头像', - `description` varchar(200) DEFAULT NULL COMMENT '描述', - `status` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态(1:启用;2:禁用)', - `is_system` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否为系统内置数据', - `pwd_reset_time` datetime DEFAULT NULL COMMENT '最后一次修改密码时间', - `dept_id` bigint(20) NOT NULL COMMENT '部门ID', - `create_user` bigint(20) DEFAULT NULL COMMENT '创建人', - `create_time` datetime NOT NULL COMMENT '创建时间', - `update_user` bigint(20) DEFAULT NULL COMMENT '修改人', - `update_time` datetime DEFAULT NULL COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE INDEX `uk_username`(`username`), - UNIQUE INDEX `uk_email`(`email`), - UNIQUE INDEX `uk_phone`(`phone`), - INDEX `idx_dept_id`(`dept_id`), - INDEX `idx_create_user`(`create_user`), - INDEX `idx_update_user`(`update_user`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; - -CREATE TABLE IF NOT EXISTS `sys_user_password_history` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', - `user_id` bigint(20) NOT NULL COMMENT '用户ID', - `password` varchar(255) NOT NULL COMMENT '密码', - `create_time` datetime NOT NULL COMMENT '创建时间', - PRIMARY KEY (`id`), - INDEX `idx_user_id`(`user_id`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户历史密码表'; - -CREATE TABLE IF NOT EXISTS `sys_user_social` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', - `source` varchar(255) NOT NULL COMMENT '来源', - `open_id` varchar(255) NOT NULL COMMENT '开放ID', - `user_id` bigint(20) NOT NULL COMMENT '用户ID', - `meta_json` text DEFAULT NULL COMMENT '附加信息', - `last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间', - `create_time` datetime NOT NULL COMMENT '创建时间', - PRIMARY KEY (`id`), - UNIQUE INDEX `uk_source_open_id`(`source`, `open_id`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户社会化关联表'; - -CREATE TABLE IF NOT EXISTS `sys_user_role` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', - `user_id` bigint(20) NOT NULL COMMENT '用户ID', - `role_id` bigint(20) NOT NULL COMMENT '角色ID', - PRIMARY KEY (`id`), - UNIQUE INDEX `uk_user_id_role_id`(`user_id`, `role_id`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和角色关联表'; - -CREATE TABLE IF NOT EXISTS `sys_role_menu` ( - `role_id` bigint(20) NOT NULL COMMENT '角色ID', - `menu_id` bigint(20) NOT NULL COMMENT '菜单ID', - PRIMARY KEY (`role_id`, `menu_id`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和菜单关联表'; - -CREATE TABLE IF NOT EXISTS `sys_role_dept` ( - `role_id` bigint(20) NOT NULL COMMENT '角色ID', - `dept_id` bigint(20) NOT NULL COMMENT '部门ID', - PRIMARY KEY (`role_id`, `dept_id`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和部门关联表'; - - -CREATE TABLE IF NOT EXISTS `sys_log` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', - `trace_id` varchar(255) DEFAULT NULL COMMENT '链路ID', - `description` varchar(255) NOT NULL COMMENT '日志描述', - `module` varchar(100) NOT NULL COMMENT '所属模块', - `request_url` varchar(512) NOT NULL COMMENT '请求URL', - `request_method` varchar(10) NOT NULL COMMENT '请求方式', - `request_headers` text DEFAULT NULL COMMENT '请求头', - `request_body` text DEFAULT NULL COMMENT '请求体', - `status_code` int NOT NULL COMMENT '状态码', - `response_headers` text DEFAULT NULL COMMENT '响应头', - `response_body` mediumtext DEFAULT NULL COMMENT '响应体', - `time_taken` bigint(20) NOT NULL COMMENT '耗时(ms)', - `ip` varchar(100) DEFAULT NULL COMMENT 'IP', - `address` varchar(255) DEFAULT NULL COMMENT 'IP归属地', - `browser` varchar(100) DEFAULT NULL COMMENT '浏览器', - `os` varchar(100) DEFAULT NULL COMMENT '操作系统', - `status` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态(1:成功;2:失败)', - `error_msg` text DEFAULT NULL COMMENT '错误信息', - `create_user` bigint(20) DEFAULT NULL COMMENT '创建人', - `create_time` datetime NOT NULL COMMENT '创建时间', - PRIMARY KEY (`id`), - INDEX `idx_module`(`module`), - INDEX `idx_ip`(`ip`), - INDEX `idx_address`(`address`), - INDEX `idx_create_time`(`create_time`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统日志表'; - -CREATE TABLE IF NOT EXISTS `sys_message` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', - `title` varchar(50) NOT NULL COMMENT '标题', - `content` text DEFAULT NULL COMMENT '内容', - `type` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '类型(1:系统消息;2:安全消息)', - `path` varchar(255) DEFAULT NULL COMMENT '跳转路径', - `scope` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '通知范围(1:所有人;2:指定用户)', - `users` json DEFAULT NULL COMMENT '通知用户', - `create_time` datetime NOT NULL COMMENT '创建时间', - PRIMARY KEY (`id`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='消息表'; - -CREATE TABLE IF NOT EXISTS `sys_message_log` ( - `message_id` bigint(20) NOT NULL COMMENT '消息ID', - `user_id` bigint(20) NOT NULL COMMENT '用户ID', - `read_time` datetime DEFAULT NULL COMMENT '读取时间', - PRIMARY KEY (`message_id`, `user_id`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='消息日志表'; - -CREATE TABLE IF NOT EXISTS `sys_notice` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', - `title` varchar(150) NOT NULL COMMENT '标题', - `content` mediumtext NOT NULL COMMENT '内容', - `type` varchar(30) NOT NULL COMMENT '分类', - `notice_scope` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '通知范围(1:所有人;2:指定用户)', - `notice_users` json DEFAULT NULL COMMENT '通知用户', - `notice_methods` json DEFAULT NULL COMMENT '通知方式(1:系统消息;2:登录弹窗)', - `is_timing` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否定时', - `publish_time` datetime DEFAULT NULL COMMENT '发布时间', - `is_top` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否置顶', - `status` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态(1:草稿;2:待发布;3:已发布)', - `create_user` bigint(20) NOT NULL COMMENT '创建人', - `create_time` datetime NOT NULL COMMENT '创建时间', - `update_user` bigint(20) DEFAULT NULL COMMENT '修改人', - `update_time` datetime DEFAULT NULL COMMENT '修改时间', - PRIMARY KEY (`id`), - INDEX `idx_create_user`(`create_user`), - INDEX `idx_update_user`(`update_user`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='公告表'; - -CREATE TABLE IF NOT EXISTS `sys_notice_log` ( - `notice_id` bigint(20) NOT NULL COMMENT '公告ID', - `user_id` bigint(20) NOT NULL COMMENT '用户ID', - `read_time` datetime DEFAULT NULL COMMENT '读取时间', - PRIMARY KEY (`notice_id`, `user_id`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='公告日志表'; - - -CREATE TABLE IF NOT EXISTS `sys_file` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', - `name` varchar(255) NOT NULL COMMENT '名称', - `original_name` varchar(255) NOT NULL COMMENT '原始名称', - `size` bigint(20) DEFAULT NULL COMMENT '大小(字节)', - `parent_path` varchar(512) NOT NULL DEFAULT '/' COMMENT '上级目录', - `path` varchar(512) NOT NULL COMMENT '路径', - `extension` varchar(32) DEFAULT NULL COMMENT '扩展名', - `content_type` varchar(255) DEFAULT NULL COMMENT '内容类型', - `type` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '类型(0: 目录;1:其他;2:图片;3:文档;4:视频;5:音频)', - `sha256` varchar(256) DEFAULT NULL COMMENT 'SHA256值', - `metadata` text DEFAULT NULL COMMENT '元数据', - `thumbnail_name` varchar(255) DEFAULT NULL COMMENT '缩略图名称', - `thumbnail_size` bigint(20) DEFAULT NULL COMMENT '缩略图大小(字节)', - `thumbnail_metadata` text DEFAULT NULL COMMENT '缩略图元数据', - `storage_id` bigint(20) NOT NULL COMMENT '存储ID', - `create_user` bigint(20) NOT NULL COMMENT '创建人', - `create_time` datetime NOT NULL COMMENT '创建时间', - `update_user` bigint(20) DEFAULT NULL COMMENT '修改人', - `update_time` datetime DEFAULT NULL COMMENT '修改时间', - PRIMARY KEY (`id`), - INDEX `idx_type`(`type`), - INDEX `idx_sha256`(`sha256`), - INDEX `idx_storage_id`(`storage_id`), - INDEX `idx_create_user`(`create_user`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件表'; diff --git a/continew-server/src/main/resources/db/changelog/postgresql/main_data.sql b/continew-server/src/main/resources/db/changelog/postgresql/main_data.sql index 356a4b61..700777d9 100644 --- a/continew-server/src/main/resources/db/changelog/postgresql/main_data.sql +++ b/continew-server/src/main/resources/db/changelog/postgresql/main_data.sql @@ -18,7 +18,7 @@ VALUES (1018, '重置密码', 1010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:user:resetPwd', 8, 1, 1, NOW()), (1019, '分配角色', 1010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:user:updateRole', 9, 1, 1, NOW()), -(1030, '角色管理', 1000, 2, '/system/role', 'SystemRole', 'system/role/index', NULL, 'user-group', false, false, false, NULL, 2, 1, 1, NOW()), +(1030, '角色管理', 1000, 2, '/system/role', 'SystemRole', 'system/role/index', NULL, 'user-management', false, false, false, NULL, 2, 1, 1, NOW()), (1031, '列表', 1030, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:role:list', 1, 1, 1, NOW()), (1032, '详情', 1030, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:role:get', 2, 1, 1, NOW()), (1033, '新增', 1030, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:role:create', 3, 1, 1, NOW()), @@ -97,7 +97,7 @@ VALUES (1215, '删除', 1210, 3, NULL, NULL, NULL, NULL, NULL, false, false, false, 'system:smsConfig:delete', 5, 1, 1, NOW()), (1216, '导出', 1210, 3, NULL, NULL, NULL, NULL, NULL, false, false, false, 'system:smsConfig:export', 6, 1, 1, NOW()), (1217, '设为默认配置', 1210, 3, NULL, NULL, NULL, NULL, NULL, false, false, false, 'system:smsConfig:setDefault', 7, 1, 1, NOW()), -(1230, '存储配置', 1150, 2, '/system/config?tab=storage', 'SystemStorage', 'system/config/storage/index', NULL, 'storage', false, false, true, NULL, 6, 1, 1, NOW()), +(1230, '存储配置', 1150, 2, '/system/config?tab=storage', 'SystemStorage', 'system/config/storage/index', NULL, 'block-storage', false, false, true, NULL, 6, 1, 1, NOW()), (1231, '列表', 1230, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:list', 1, 1, 1, NOW()), (1232, '详情', 1230, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:get', 2, 1, 1, NOW()), (1233, '新增', 1230, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:create', 3, 1, 1, NOW()), diff --git a/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_generator.sql b/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_generator.sql index 05d37454..647bead6 100644 --- a/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_generator.sql +++ b/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_generator.sql @@ -1,7 +1,7 @@ -- liquibase formatted sql -- changeset charles7c:1 --- comment 初始化代码生成插件 +-- comment 初始化代码生成插件数据表 -- 初始化表结构 CREATE TABLE IF NOT EXISTS "gen_config" ( "table_name" varchar(64) NOT NULL, diff --git a/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_open.sql b/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_open.sql index 94e38793..008c3643 100644 --- a/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_open.sql +++ b/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_open.sql @@ -1,7 +1,7 @@ -- liquibase formatted sql -- changeset chengzi:1 --- comment 初始化能力开放插件 +-- comment 初始化能力开放插件数据表 -- 初始化表结构 CREATE TABLE IF NOT EXISTS "sys_app" ( "id" int8 NOT NULL, diff --git a/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_schedule.sql b/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_schedule.sql index d92c889b..db23c7f0 100644 --- a/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_schedule.sql +++ b/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_schedule.sql @@ -1,21 +1,22 @@ -- liquibase formatted sql -- changeset kai:1 --- comment 初始化任务调度插件 +-- comment 初始化任务调度插件数据表 -- 初始化默认菜单 INSERT INTO "sys_menu" ("id", "title", "parent_id", "type", "path", "name", "component", "redirect", "icon", "is_external", "is_cache", "is_hidden", "permission", "sort", "status", "create_user", "create_time") VALUES -(3000, '任务调度', 0, 1, '/schedule', 'Schedule', 'Layout', '/schedule/job', 'schedule', false, false, false, NULL, 3, 1, 1, NOW()), -(3010, '任务管理', 3000, 2, '/schedule/job', 'ScheduleJob', 'schedule/job/index', NULL, 'select-all', false, false, false, NULL, 1, 1, 1, NOW()), -(3011, '列表', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:list', 1, 1, 1, NOW()), -(3012, '详情', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:get', 2, 1, 1, NOW()), -(3013, '新增', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:create', 3, 1, 1, NOW()), -(3014, '修改', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:update', 4, 1, 1, NOW()), -(3015, '删除', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:delete', 5, 1, 1, NOW()), -(3016, '执行', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:trigger', 6, 1, 1, NOW()), -(3020, '任务日志', 3000, 2, '/schedule/log', 'ScheduleLog', 'schedule/log/index', NULL, 'find-replace', false, false, false, NULL, 2, 1, 1, NOW()), -(3021, '列表', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:list', 1, 1, 1, NOW()), -(3022, '详情', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:get', 2, 1, 1, NOW()), -(3023, '停止', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:stop', 3, 1, 1, NOW()), -(3024, '重试', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:retry', 4, 1, 1, NOW()); +(8000, '任务调度', 0, 1, '/schedule', 'Schedule', 'Layout', '/schedule/job', 'schedule', false, false, false, NULL, 8, 1, 1, NOW()), +(8010, '任务管理', 8000, 2, '/schedule/job', 'ScheduleJob', 'schedule/job/index', NULL, 'select-all', false, false, false, NULL, 1, 1, 1, NOW()), +(8011, '列表', 8010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:list', 1, 1, 1, NOW()), +(8012, '详情', 8010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:get', 2, 1, 1, NOW()), +(8013, '新增', 8010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:create', 3, 1, 1, NOW()), +(8014, '修改', 8010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:update', 4, 1, 1, NOW()), +(8015, '删除', 8010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:delete', 5, 1, 1, NOW()), +(8016, '执行', 8010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:trigger', 6, 1, 1, NOW()), + +(8020, '任务日志', 8000, 2, '/schedule/log', 'ScheduleLog', 'schedule/log/index', NULL, 'find-replace', false, false, false, NULL, 2, 1, 1, NOW()), +(8021, '列表', 8020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:list', 1, 1, 1, NOW()), +(8022, '详情', 8020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:get', 2, 1, 1, NOW()), +(8023, '停止', 8020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:stop', 3, 1, 1, NOW()), +(8024, '重试', 8020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:retry', 4, 1, 1, NOW()); diff --git a/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_tenant.sql b/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_tenant.sql new file mode 100644 index 00000000..024aabc8 --- /dev/null +++ b/continew-server/src/main/resources/db/changelog/postgresql/plugin/plugin_tenant.sql @@ -0,0 +1,226 @@ +-- liquibase formatted sql + +-- changeset 小熊:1 +-- comment 初始化租户插件数据表 +-- 初始化表结构 +CREATE TABLE IF NOT EXISTS "tenant" ( + "id" int8 NOT NULL, + "name" varchar(30) NOT NULL, + "code" varchar(30) NOT NULL, + "domain" varchar(255) DEFAULT NULL, + "expire_time" timestamp DEFAULT NULL, + "isolation_level" int2 NOT NULL, + "description" varchar(200) DEFAULT NULL, + "status" int2 NOT NULL DEFAULT 1, + "admin_user" int8 DEFAULT NULL, + "package_id" int8 NOT NULL, + "datasource_id" int8 DEFAULT NULL, + "create_user" int8 NOT NULL, + "create_time" timestamp NOT NULL, + "update_user" int8 DEFAULT NULL, + "update_time" timestamp DEFAULT NULL, + PRIMARY KEY ("id") +); +CREATE UNIQUE INDEX "uk_tenant_code" ON "tenant" ("code"); +CREATE INDEX "idx_tenant_admin_user" ON "tenant" ("admin_user"); +CREATE INDEX "idx_tenant_package_id" ON "tenant" ("package_id"); +CREATE INDEX "idx_tenant_datasource_id" ON "tenant" ("datasource_id"); +CREATE INDEX "idx_tenant_create_user" ON "tenant" ("create_user"); +CREATE INDEX "idx_tenant_update_user" ON "tenant" ("update_user"); +COMMENT ON COLUMN "tenant"."id" IS 'ID'; +COMMENT ON COLUMN "tenant"."name" IS '名称'; +COMMENT ON COLUMN "tenant"."code" IS '编码'; +COMMENT ON COLUMN "tenant"."domain" IS '域名'; +COMMENT ON COLUMN "tenant"."expire_time" IS '过期时间'; +COMMENT ON COLUMN "tenant"."isolation_level" IS '隔离级别'; +COMMENT ON COLUMN "tenant"."description" IS '描述'; +COMMENT ON COLUMN "tenant"."status" IS '状态(1:启用;2:禁用)'; +COMMENT ON COLUMN "tenant"."package_id" IS '套餐ID'; +COMMENT ON COLUMN "tenant"."datasource_id" IS '数据源ID'; +COMMENT ON COLUMN "tenant"."admin_user" IS '租户管理员'; +COMMENT ON COLUMN "tenant"."create_user" IS '创建人'; +COMMENT ON COLUMN "tenant"."create_time" IS '创建时间'; +COMMENT ON COLUMN "tenant"."update_user" IS '修改人'; +COMMENT ON COLUMN "tenant"."update_time" IS '修改时间'; +COMMENT ON TABLE "tenant" IS '租户表'; + +CREATE TABLE IF NOT EXISTS "tenant_package" ( + "id" int8 NOT NULL, + "name" varchar(30) NOT NULL, + "sort" int4 NOT NULL DEFAULT 999, + "menu_check_strictly" bool DEFAULT true, + "description" varchar(200) DEFAULT NULL, + "status" int2 NOT NULL DEFAULT 1, + "create_user" int8 NOT NULL, + "create_time" timestamp NOT NULL, + "update_user" int8 DEFAULT NULL, + "update_time" timestamp DEFAULT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "idx_tenant_package_create_user" ON "tenant_package" ("create_user"); +CREATE INDEX "idx_tenant_package_update_user" ON "tenant_package" ("update_user"); +COMMENT ON COLUMN "tenant_package"."id" IS 'ID'; +COMMENT ON COLUMN "tenant_package"."name" IS '名称'; +COMMENT ON COLUMN "tenant_package"."sort" IS '排序'; +COMMENT ON COLUMN "tenant_package"."menu_check_strictly" IS '菜单选择是否父子节点关联'; +COMMENT ON COLUMN "tenant_package"."description" IS '描述'; +COMMENT ON COLUMN "tenant_package"."status" IS '状态(1:启用;2:禁用)'; +COMMENT ON COLUMN "tenant_package"."create_user" IS '创建人'; +COMMENT ON COLUMN "tenant_package"."create_time" IS '创建时间'; +COMMENT ON COLUMN "tenant_package"."update_user" IS '修改人'; +COMMENT ON COLUMN "tenant_package"."update_time" IS '修改时间'; +COMMENT ON TABLE "tenant_package" IS '租户套餐表'; + +CREATE TABLE IF NOT EXISTS "tenant_package_menu" ( + "package_id" int8 NOT NULL, + "menu_id" int8 NOT NULL, + PRIMARY KEY ("package_id", "menu_id") +); +COMMENT ON COLUMN "tenant_package_menu"."package_id" IS '套餐ID'; +COMMENT ON COLUMN "tenant_package_menu"."menu_id" IS '菜单ID'; +COMMENT ON TABLE "tenant_package_menu" IS '租户套餐和菜单关联表'; + +CREATE TABLE IF NOT EXISTS "tenant_datasource" ( + "id" int8 NOT NULL, + "name" varchar(30) NOT NULL, + "database_type" int2 NOT NULL, + "host" varchar(128) NOT NULL, + "port" int4 NOT NULL, + "username" varchar(128) NOT NULL, + "password" varchar(128) NOT NULL, + "description" varchar(200) DEFAULT NULL, + "create_user" int8 NOT NULL, + "create_time" timestamp NOT NULL, + "update_user" int8 DEFAULT NULL, + "update_time" timestamp DEFAULT NULL, + PRIMARY KEY ("id") +); +CREATE INDEX "idx_tenant_datasource_create_user" ON "tenant_datasource" ("create_user"); +CREATE INDEX "idx_tenant_datasource_update_user" ON "tenant_datasource" ("update_user"); +COMMENT ON COLUMN "tenant_datasource"."id" IS 'ID'; +COMMENT ON COLUMN "tenant_datasource"."name" IS '名称'; +COMMENT ON COLUMN "tenant_datasource"."database_type" IS '数据库类型(1:MySQL)'; +COMMENT ON COLUMN "tenant_datasource"."host" IS '主机'; +COMMENT ON COLUMN "tenant_datasource"."port" IS '端口'; +COMMENT ON COLUMN "tenant_datasource"."username" IS '用户名'; +COMMENT ON COLUMN "tenant_datasource"."password" IS '密码'; +COMMENT ON COLUMN "tenant_datasource"."description" IS '描述'; +COMMENT ON COLUMN "tenant_datasource"."create_user" IS '创建人'; +COMMENT ON COLUMN "tenant_datasource"."create_time" IS '创建时间'; +COMMENT ON COLUMN "tenant_datasource"."update_user" IS '修改人'; +COMMENT ON COLUMN "tenant_datasource"."update_time" IS '修改时间'; +COMMENT ON TABLE "tenant_datasource" IS '租户数据源表'; + +-- 为已有表增加租户字段 +ALTER TABLE "sys_menu" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_menu"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_menu_tenant_id" ON "sys_menu" ("tenant_id"); + +ALTER TABLE "sys_dept" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_dept"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_dept_tenant_id" ON "sys_dept" ("tenant_id"); + +ALTER TABLE "sys_role" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_role"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_role_tenant_id" ON "sys_role" ("tenant_id"); + +ALTER TABLE "sys_user" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_user"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_user_tenant_id" ON "sys_user" ("tenant_id"); + +ALTER TABLE "sys_user_password_history" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_user_password_history"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_uph_tenant_id" ON "sys_user_password_history" ("tenant_id"); + +ALTER TABLE "sys_user_social" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_user_social"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_user_source_tenant_id" ON "sys_user_social" ("tenant_id"); + +ALTER TABLE "sys_user_role" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_user_role"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_user_role_tenant_id" ON "sys_user_role" ("tenant_id"); + +ALTER TABLE "sys_role_menu" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_role_menu"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_role_menu_tenant_id" ON "sys_role_menu" ("tenant_id"); + +ALTER TABLE "sys_role_dept" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_role_dept"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_role_dept_tenant_id" ON "sys_role_dept" ("tenant_id"); + +ALTER TABLE "sys_log" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_log"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_log_tenant_id" ON "sys_log" ("tenant_id"); + +ALTER TABLE "sys_message" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_message"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_message_tenant_id" ON "sys_message" ("tenant_id"); + +ALTER TABLE "sys_message_log" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_message_log"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_message_log_tenant_id" ON "sys_message_log" ("tenant_id"); + +ALTER TABLE "sys_notice" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_notice"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_notice_tenant_id" ON "sys_notice" ("tenant_id"); + +ALTER TABLE "sys_notice_log" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_notice_log"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_notice_log_tenant_id" ON "sys_notice_log" ("tenant_id"); + +ALTER TABLE "sys_file" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_file"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_file_tenant_id" ON "sys_file" ("tenant_id"); + +ALTER TABLE "sys_app" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; +COMMENT ON COLUMN "sys_app"."tenant_id" IS '租户ID'; +CREATE INDEX "idx_app_tenant_id" ON "sys_app" ("tenant_id"); + +-- 调整唯一索引 +ALTER TABLE "sys_menu" DROP INDEX "uk_menu_title_parent_id"; +CREATE UNIQUE INDEX "uk_menu_title_parent_id" ON "sys_menu" ("title", "parent_id", "tenant_id"); + +ALTER TABLE "sys_dept" DROP INDEX "uk_dept_name_parent_id"; +CREATE UNIQUE INDEX "uk_dept_name_parent_id" ON "sys_dept" ("name", "parent_id", "tenant_id"); + +ALTER TABLE "sys_role" DROP INDEX "uk_role_name"; +ALTER TABLE "sys_role" DROP INDEX "uk_role_code"; +CREATE UNIQUE INDEX "uk_role_name" ON "sys_role" ("name", "tenant_id"); +CREATE UNIQUE INDEX "uk_role_code" ON "sys_role" ("code", "tenant_id"); + +ALTER TABLE "sys_user" DROP INDEX "uk_user_username"; +ALTER TABLE "sys_user" DROP INDEX "uk_user_email"; +ALTER TABLE "sys_user" DROP INDEX "uk_user_phone"; +CREATE UNIQUE INDEX "uk_user_username" ON "sys_user" ("username", "tenant_id"); +CREATE UNIQUE INDEX "uk_user_email" ON "sys_user" ("email", "tenant_id"); +CREATE UNIQUE INDEX "uk_user_phone" ON "sys_user" ("phone", "tenant_id"); + +ALTER TABLE "sys_app" DROP INDEX "uk_app_access_key"; +CREATE UNIQUE INDEX "uk_app_access_key" ON "sys_app" ("access_key", "tenant_id"); + +-- 初始化默认菜单 +INSERT INTO "sys_menu" ("id", "title", "parent_id", "type", "path", "name", "component", "redirect", "icon", "is_external", "is_cache", "is_hidden", "permission", "sort", "status", "create_user", "create_time") +VALUES +(3000, '租户管理', 0, 1, '/tenant', 'Tenant', 'Layout', '/tenant/management', 'user-group', false, false, false, NULL, 6, 1, 1, NOW()), + +(3010, '租户管理', 3000, 2, '/tenant/management', 'TenantManagement', 'tenant/management/index', NULL, 'user-group', false, false, false, NULL, 1, 1, 1, NOW()), +(3011, '列表', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:management:list', 1, 1, 1, NOW()), +(3012, '详情', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:management:get', 2, 1, 1, NOW()), +(3013, '新增', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:management:create', 3, 1, 1, NOW()), +(3014, '修改', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:management:update', 4, 1, 1, NOW()), +(3015, '删除', 3010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:management:delete', 5, 1, 1, NOW()), +(3016, '修改租户管理员密码', 3010, 3, NULL, NULL, NULL, NULL, NULL, false, false, false, 'tenant:management:updateAdminUserPwd', 6, 1, 1, NOW()), + +(3020, '套餐管理', 3000, 2, '/tenant/package', 'TenantPackage', 'tenant/package/index', NULL, 'project', false, false, false, NULL, 2, 1, 1, NOW()), +(3021, '列表', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:list', 1, 1, 1, NOW()), +(3022, '详情', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:get', 2, 1, 1, NOW()), +(3023, '新增', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:create', 3, 1, 1, NOW()), +(3024, '修改', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:update', 4, 1, 1, NOW()), +(3025, '删除', 3020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'tenant:package:delete', 5, 1, 1, NOW()), + +(3030, '数据源管理', 3000, 2, '/tenant/datasource', 'TenantDatasource', 'tenant/datasource/index', NULL, 'storage', false, false, false, NULL, 3, 1, 1, NOW()), +(3031, '列表', 3030, 3, NULL, NULL, NULL, NULL, NULL, false, false, false, 'tenant:datasource:list', 1, 1, 1, NOW()), +(3032, '详情', 3030, 3, NULL, NULL, NULL, NULL, NULL, false, false, false, 'tenant:datasource:get', 2, 1, 1, NOW()), +(3033, '新增', 3030, 3, NULL, NULL, NULL, NULL, NULL, false, false, false, 'tenant:datasource:create', 3, 1, 1, NOW()), +(3034, '修改', 3030, 3, NULL, NULL, NULL, NULL, NULL, false, false, false, 'tenant:datasource:update', 4, 1, 1, NOW()), +(3035, '删除', 3030, 3, NULL, NULL, NULL, NULL, NULL, false, false, false, 'tenant:datasource:delete', 5, 1, 1, NOW()); diff --git a/continew-system/src/main/java/top/continew/admin/auth/service/impl/AuthServiceImpl.java b/continew-system/src/main/java/top/continew/admin/auth/service/impl/AuthServiceImpl.java index e7fee1ed..87bd8f9d 100644 --- a/continew-system/src/main/java/top/continew/admin/auth/service/impl/AuthServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/auth/service/impl/AuthServiceImpl.java @@ -123,5 +123,4 @@ public class AuthServiceImpl implements AuthService { }); return BeanUtil.copyToList(treeList, RouteResp.class); } - } diff --git a/continew-system/src/main/java/top/continew/admin/auth/service/impl/OnlineUserServiceImpl.java b/continew-system/src/main/java/top/continew/admin/auth/service/impl/OnlineUserServiceImpl.java index ad69e700..6709165f 100644 --- a/continew-system/src/main/java/top/continew/admin/auth/service/impl/OnlineUserServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/auth/service/impl/OnlineUserServiceImpl.java @@ -29,7 +29,7 @@ import org.springframework.stereotype.Service; import top.continew.admin.auth.model.query.OnlineUserQuery; import top.continew.admin.auth.model.resp.OnlineUserResp; import top.continew.admin.auth.service.OnlineUserService; -import top.continew.admin.common.config.properties.TenantProperties; +import top.continew.admin.common.config.TenantProperties; import top.continew.admin.common.context.UserContext; import top.continew.admin.common.context.UserContextHolder; import top.continew.admin.common.context.UserExtraContext; diff --git a/continew-system/src/main/java/top/continew/admin/system/enums/ImportPolicyEnum.java b/continew-system/src/main/java/top/continew/admin/system/enums/ImportPolicyEnum.java index 58c99efc..39db1752 100644 --- a/continew-system/src/main/java/top/continew/admin/system/enums/ImportPolicyEnum.java +++ b/continew-system/src/main/java/top/continew/admin/system/enums/ImportPolicyEnum.java @@ -27,7 +27,7 @@ import java.util.List; * 数据导入策略 * * @author Kils - * @since 2024-06-17 18:33 + * @since 2024/6/17 18:33 */ @Getter @RequiredArgsConstructor diff --git a/continew-system/src/main/java/top/continew/admin/system/mapper/RoleDeptMapper.java b/continew-system/src/main/java/top/continew/admin/system/mapper/RoleDeptMapper.java index 084b77ba..f4ed07e1 100644 --- a/continew-system/src/main/java/top/continew/admin/system/mapper/RoleDeptMapper.java +++ b/continew-system/src/main/java/top/continew/admin/system/mapper/RoleDeptMapper.java @@ -25,7 +25,7 @@ import top.continew.starter.data.mapper.BaseMapper; import java.util.List; /** - * 角色和部门 Mapper + * 角色和部门关联 Mapper * * @author Charles7c * @since 2023/2/18 21:57 diff --git a/continew-system/src/main/java/top/continew/admin/system/mapper/StorageMapper.java b/continew-system/src/main/java/top/continew/admin/system/mapper/StorageMapper.java index 75da4f86..e77de252 100644 --- a/continew-system/src/main/java/top/continew/admin/system/mapper/StorageMapper.java +++ b/continew-system/src/main/java/top/continew/admin/system/mapper/StorageMapper.java @@ -16,8 +16,6 @@ package top.continew.admin.system.mapper; -import com.baomidou.dynamic.datasource.annotation.DS; -import top.continew.admin.common.constant.SysConstants; import org.apache.ibatis.annotations.Mapper; import top.continew.admin.system.model.entity.StorageDO; import top.continew.starter.data.mapper.BaseMapper; @@ -28,7 +26,6 @@ import top.continew.starter.data.mapper.BaseMapper; * @author Charles7c * @since 2023/12/26 22:09 */ -@DS(SysConstants.DEFAULT_DATASOURCE) @Mapper public interface StorageMapper extends BaseMapper { } \ No newline at end of file diff --git a/continew-system/src/main/java/top/continew/admin/system/model/entity/RoleDeptDO.java b/continew-system/src/main/java/top/continew/admin/system/model/entity/RoleDeptDO.java index ea421d92..3818dcbc 100644 --- a/continew-system/src/main/java/top/continew/admin/system/model/entity/RoleDeptDO.java +++ b/continew-system/src/main/java/top/continew/admin/system/model/entity/RoleDeptDO.java @@ -24,7 +24,7 @@ import java.io.Serial; import java.io.Serializable; /** - * 角色和部门实体 + * 角色和部门关联实体 * * @author Charles7c * @since 2023/2/18 21:57 diff --git a/continew-system/src/main/java/top/continew/admin/system/model/query/MenuQuery.java b/continew-system/src/main/java/top/continew/admin/system/model/query/MenuQuery.java index 4a8607f3..9fa4f8f8 100644 --- a/continew-system/src/main/java/top/continew/admin/system/model/query/MenuQuery.java +++ b/continew-system/src/main/java/top/continew/admin/system/model/query/MenuQuery.java @@ -59,10 +59,9 @@ public class MenuQuery implements Serializable { } /** - * 排除的菜单 + * 排除的菜单 ID 列表 */ - @Schema(description = "排除的菜单") + @Schema(hidden = true, description = "菜单 ID 列表", example = "[9000]") @Query(columns = "id", type = QueryType.NOT_IN) private List excludeMenuIdList; - } diff --git a/continew-system/src/main/java/top/continew/admin/system/model/req/user/UserImportReq.java b/continew-system/src/main/java/top/continew/admin/system/model/req/user/UserImportReq.java index b344c794..fb10d893 100644 --- a/continew-system/src/main/java/top/continew/admin/system/model/req/user/UserImportReq.java +++ b/continew-system/src/main/java/top/continew/admin/system/model/req/user/UserImportReq.java @@ -30,7 +30,7 @@ import java.io.Serializable; * 用户导入请求参数 * * @author Kils - * @since 2024-6-17 16:42 + * @since 2024/6/17 16:42 */ @Data @Schema(description = "用户导入请求参数") diff --git a/continew-system/src/main/java/top/continew/admin/system/model/req/user/UserImportRowReq.java b/continew-system/src/main/java/top/continew/admin/system/model/req/user/UserImportRowReq.java index 666714ce..984ef64f 100644 --- a/continew-system/src/main/java/top/continew/admin/system/model/req/user/UserImportRowReq.java +++ b/continew-system/src/main/java/top/continew/admin/system/model/req/user/UserImportRowReq.java @@ -33,7 +33,7 @@ import java.io.Serializable; * 用户导入行数据请求参数 * * @author Kils - * @since 2024-6-17 16:42 + * @since 2024/6/17 16:42 */ @Data @Schema(description = "用户导入行数据请求参数") diff --git a/continew-system/src/main/java/top/continew/admin/system/model/resp/DeptResp.java b/continew-system/src/main/java/top/continew/admin/system/model/resp/DeptResp.java index e8dc9b47..f00ffefa 100644 --- a/continew-system/src/main/java/top/continew/admin/system/model/resp/DeptResp.java +++ b/continew-system/src/main/java/top/continew/admin/system/model/resp/DeptResp.java @@ -66,7 +66,7 @@ public class DeptResp extends BaseDetailResp { /** * 排序 */ - @Schema(description = "排序", example = "3") + @Schema(description = "排序", example = "1") @ExcelProperty(value = "排序", order = 6) private Integer sort; diff --git a/continew-system/src/main/java/top/continew/admin/system/model/resp/user/UserImportResp.java b/continew-system/src/main/java/top/continew/admin/system/model/resp/user/UserImportResp.java index 93ba1f19..629b89df 100644 --- a/continew-system/src/main/java/top/continew/admin/system/model/resp/user/UserImportResp.java +++ b/continew-system/src/main/java/top/continew/admin/system/model/resp/user/UserImportResp.java @@ -28,7 +28,7 @@ import java.io.Serializable; * 用户导入结果响应参数 * * @author kils - * @since 2024-06-18 14:37 + * @since 2024/6/18 14:37 */ @Data @Schema(description = "用户导入结果响应参数") diff --git a/continew-system/src/main/java/top/continew/admin/system/service/DeptService.java b/continew-system/src/main/java/top/continew/admin/system/service/DeptService.java index 1f763d05..12ef2d14 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/DeptService.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/DeptService.java @@ -56,12 +56,4 @@ public interface DeptService extends BaseService deptNames); - - /** - * 初始化租户部门 - * - * @param deptName - * @return 部门ID - */ - Long initTenantDept(String deptName); } diff --git a/continew-system/src/main/java/top/continew/admin/system/service/MenuService.java b/continew-system/src/main/java/top/continew/admin/system/service/MenuService.java index 2322a1c2..1946195d 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/MenuService.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/MenuService.java @@ -34,13 +34,6 @@ import java.util.Set; */ public interface MenuService extends BaseService, IService { - /** - * 查询全部菜单 - * - * @return 菜单列表 - */ - List listAll(Long tenantId); - /** * 根据用户 ID 查询 * @@ -50,35 +43,25 @@ public interface MenuService extends BaseService listPermissionByUserId(Long userId); /** - * 根据角色id查询 + * 根据角色 ID 查询 * - * @param roleId 角色id + * @param roleId 角色 ID * @return 菜单列表 */ List listByRoleId(Long roleId); - /** - * 递归初始化菜单 - * - * @param menuList 需要初始化的菜单ID - * @param oldParentId 原来的父级ID - * @param newParentId 新的父级ID - */ - void menuInit(List menuList, Long oldParentId, Long newParentId); - /** * 删除租户菜单 * - * @param menuList + * @param menuS 菜单列表 */ - void deleteTenantMenus(List menuList); + void deleteTenantMenus(List menuS); /** * 新增租户菜单 * - * @param menu 新增的菜单 - * @param pMenu 新增菜单的父级别 + * @param menu 新增的菜单 + * @param parentMenu 父菜单 */ - void addTenantMenu(MenuDO menu, MenuDO pMenu); - + void addTenantMenu(MenuDO menu, MenuDO parentMenu); } diff --git a/continew-system/src/main/java/top/continew/admin/system/service/RoleDeptService.java b/continew-system/src/main/java/top/continew/admin/system/service/RoleDeptService.java index 4489bf45..494d65a4 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/RoleDeptService.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/RoleDeptService.java @@ -19,7 +19,7 @@ package top.continew.admin.system.service; import java.util.List; /** - * 角色和部门业务接口 + * 角色和部门关联业务接口 * * @author Charles7c * @since 2023/2/19 10:40 diff --git a/continew-system/src/main/java/top/continew/admin/system/service/RoleMenuService.java b/continew-system/src/main/java/top/continew/admin/system/service/RoleMenuService.java index 083ba5d4..5d068da9 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/RoleMenuService.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/RoleMenuService.java @@ -16,8 +16,8 @@ package top.continew.admin.system.service; -import com.baomidou.mybatisplus.extension.service.IService; import top.continew.admin.system.model.entity.RoleMenuDO; +import top.continew.starter.data.service.IService; import java.util.List; diff --git a/continew-system/src/main/java/top/continew/admin/system/service/RoleService.java b/continew-system/src/main/java/top/continew/admin/system/service/RoleService.java index ca566926..5b9c2212 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/RoleService.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/RoleService.java @@ -100,12 +100,4 @@ public interface RoleService extends BaseService roleNames); - - /** - * 初始化租户角色 - * - * @return 角色ID - */ - Long initTenantRole(); - } diff --git a/continew-system/src/main/java/top/continew/admin/system/service/UserService.java b/continew-system/src/main/java/top/continew/admin/system/service/UserService.java index 0f0914a8..252d5548 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/UserService.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/UserService.java @@ -155,13 +155,4 @@ public interface UserService extends BaseService deptIds); - - /** - * 初始化租户管理员 - * - * @param username - * @param password - * @return 管理员id - */ - Long initTenantUser(String username, String password, Long deptId); } diff --git a/continew-system/src/main/java/top/continew/admin/system/service/impl/ClientServiceImpl.java b/continew-system/src/main/java/top/continew/admin/system/service/impl/ClientServiceImpl.java index 89272131..8cc167fc 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/impl/ClientServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/impl/ClientServiceImpl.java @@ -63,7 +63,7 @@ public class ClientServiceImpl extends BaseServiceImpl listAll(Long tenantId) { - return super.list(new MenuQuery(DisEnableStatusEnum.ENABLE), null); - } - @Override public Set listPermissionByUserId(Long userId) { return baseMapper.selectPermissionByUserId(userId); } + @Override @Cached(key = "#roleId", name = CacheConstants.ROLE_MENU_KEY_PREFIX) public List listByRoleId(Long roleId) { if (SysConstants.SUPER_ROLE_ID.equals(roleId)) { @@ -122,60 +118,53 @@ public class MenuServiceImpl extends BaseServiceImpl menuList, Long oldParentId, Long newParentId) { - List children = menuList.stream().filter(menuDO -> menuDO.getParentId().equals(oldParentId)).toList(); - for (MenuDO menuDO : children) { - Long oldId = menuDO.getId(); - menuDO.setId(null); - menuDO.setParentId(newParentId); - save(menuDO); - menuInit(menuList, oldId, menuDO.getId()); - } - } - - @Override + @Transactional(rollbackFor = Exception.class) public void deleteTenantMenus(List menuList) { - if (!menuList.isEmpty()) { - List delIds = new ArrayList<>(); - for (MenuDO menuDO : menuList) { - MenuDO tMenu = getOne(Wrappers.query(MenuDO.class) - .eq(menuDO.getType().equals(MenuTypeEnum.BUTTON.getValue()), "CONCAT(title,permission)", menuDO - .getTitle() + menuDO.getPermission()) - .eq(!menuDO.getType().equals(MenuTypeEnum.BUTTON.getValue()), "name", menuDO.getName())); - if (tMenu != null) { - delIds.add(tMenu.getId()); - } - } - if (!delIds.isEmpty()) { - //菜单删除 - delete(delIds); - //绑定关系删除 - roleMenuService.remove(Wrappers.lambdaQuery(RoleMenuDO.class).in(RoleMenuDO::getMenuId, delIds)); + if (CollUtil.isEmpty(menuList)) { + return; + } + List delIds = new ArrayList<>(); + for (MenuDO menu : menuList) { + MenuDO parentMenu = baseMapper.query() + .eq(menu.getType().equals(MenuTypeEnum.BUTTON), "CONCAT(title,permission)", menu.getTitle() + menu + .getPermission()) + .eq(!menu.getType().equals(MenuTypeEnum.BUTTON), "name", menu.getName()) + .one(); + if (parentMenu != null) { + delIds.add(parentMenu.getId()); } } + if (!delIds.isEmpty()) { + // 菜单删除 + this.delete(delIds); + // 删除绑定关系 + roleMenuService.remove(Wrappers.lambdaQuery(RoleMenuDO.class).in(RoleMenuDO::getMenuId, delIds)); + } + // 删除缓存 + RedisUtils.deleteByPattern(CacheConstants.ROLE_MENU_KEY_PREFIX + StringConstants.ASTERISK); } @Override - public void addTenantMenu(MenuDO menu, MenuDO pMenu) { - Long pId = 0l; - if (pMenu != null) { - MenuDO tPMenu = getOne(Wrappers.query(MenuDO.class) - .eq(pMenu.getType().equals(MenuTypeEnum.BUTTON.getValue()), "CONCAT(title,permission)", pMenu - .getTitle() + pMenu.getPermission()) - .eq(!pMenu.getType().equals(MenuTypeEnum.BUTTON.getValue()), "name", pMenu.getName())); - pId = tPMenu.getId(); + public void addTenantMenu(MenuDO menu, MenuDO parentMenu) { + Long parentId = SysConstants.SUPER_PARENT_ID; + if (parentMenu != null) { + MenuDO parent = baseMapper.query() + .eq(parentMenu.getType().equals(MenuTypeEnum.BUTTON), "CONCAT(title,permission)", parentMenu + .getTitle() + parentMenu.getPermission()) + .eq(!parentMenu.getType().equals(MenuTypeEnum.BUTTON), "name", parentMenu.getName()) + .one(); + parentId = parent.getId(); } menu.setId(null); - menu.setParentId(pId); - //菜单新增 - save(menu); - //管理员绑定菜单 - RoleDO roleDO = roleMapper.selectOne(Wrappers.lambdaQuery(RoleDO.class) - .eq(RoleDO::getCode, SysConstants.TENANT_ADMIN_CODE)); - RoleMenuDO roleMenuDO = new RoleMenuDO(); - roleMenuDO.setRoleId(roleDO.getId()); - roleMenuDO.setMenuId(menu.getId()); - roleMenuService.save(roleMenuDO); + menu.setParentId(parentId); + // 菜单新增 + baseMapper.insert(menu); + // 管理员绑定菜单 + RoleDO role = roleMapper.selectOne(Wrappers.lambdaQuery(RoleDO.class) + .eq(RoleDO::getCode, SysConstants.TENANT_ADMIN_ROLE_CODE)); + roleMenuService.save(new RoleMenuDO(role.getId(), menu.getId())); + // 删除缓存 + RedisUtils.deleteByPattern(CacheConstants.ROLE_MENU_KEY_PREFIX + StringConstants.ASTERISK); } /** diff --git a/continew-system/src/main/java/top/continew/admin/system/service/impl/RoleDeptServiceImpl.java b/continew-system/src/main/java/top/continew/admin/system/service/impl/RoleDeptServiceImpl.java index 9e158e17..1f64b4a3 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/impl/RoleDeptServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/impl/RoleDeptServiceImpl.java @@ -27,7 +27,7 @@ import top.continew.admin.system.service.RoleDeptService; import java.util.List; /** - * 角色和部门业务实现 + * 角色和部门关联业务实现 * * @author Charles7c * @since 2023/2/19 10:47 diff --git a/continew-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java b/continew-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java index 2052c342..412f7dbe 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java @@ -70,7 +70,7 @@ public class RoleServiceImpl extends BaseServiceImpl SecureUtils.decryptByRsaPrivateKey(encryptSecretKey)); ValidationUtils.throwIfNull(secretKey, "私有密钥解密失败"); ValidationUtils.throwIf(secretKey.length() > 255, "私有密钥长度不能超过 255 个字符"); diff --git a/continew-system/src/main/java/top/continew/admin/system/service/impl/TenantSysDataServiceImpl.java b/continew-system/src/main/java/top/continew/admin/system/service/impl/TenantSysDataServiceImpl.java deleted file mode 100644 index 8b0959e5..00000000 --- a/continew-system/src/main/java/top/continew/admin/system/service/impl/TenantSysDataServiceImpl.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.admin.system.service.impl; - -import cn.dev33.satoken.stp.StpUtil; -import com.baomidou.mybatisplus.core.conditions.Wrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import top.continew.admin.system.mapper.*; -import top.continew.admin.system.mapper.user.UserMapper; -import top.continew.admin.system.mapper.user.UserPasswordHistoryMapper; -import top.continew.admin.system.mapper.user.UserSocialMapper; -import top.continew.admin.system.model.entity.user.UserDO; -import top.continew.admin.system.service.FileService; -import top.continew.admin.system.service.TenantSysDataService; -import top.continew.starter.extension.crud.model.entity.BaseIdDO; - -import java.util.List; - -/** - * @description: 多租户系统数据接口 - * @author: 小熊 - * @create: 2024-12-02 20:12 - */ -@RequiredArgsConstructor -@Service -public class TenantSysDataServiceImpl implements TenantSysDataService { - - private final DeptMapper deptMapper; - private final FileService fileService; - private final LogMapper logMapper; - private final MenuMapper menuMapper; - private final MessageMapper messageMapper; - private final MessageMapper messageUserMapper; - private final NoticeMapper noticeMapper; - private final RoleMapper roleMapper; - private final RoleDeptMapper roleDeptMapper; - private final RoleMenuMapper roleMenuMapper; - private final UserMapper userMapper; - private final UserPasswordHistoryMapper userPasswordHistoryMapper; - private final UserRoleMapper userRoleMapper; - private final UserSocialMapper userSocialMapper; - - @Override - @Transactional - public void clear() { - //所有用户退出 - List userDOS = userMapper.selectList(null); - for (UserDO userDO : userDOS) { - StpUtil.logout(userDO.getId()); - } - Wrapper dw = Wrappers.query().eq("1", 1); - //部门清除 - deptMapper.delete(dw); - //文件清除 - List fileIds = fileService.list().stream().map(BaseIdDO::getId).toList(); - if (!fileIds.isEmpty()) { - fileService.delete(fileIds); - } - //日志清除 - logMapper.delete(dw); - //菜单清除 - menuMapper.delete(dw); - //消息清除 - messageMapper.delete(dw); - messageUserMapper.delete(dw); - //通知清除 - noticeMapper.delete(dw); - //角色相关数据清除 - roleMapper.delete(dw); - roleDeptMapper.delete(dw); - roleMenuMapper.delete(dw); - //用户数据清除 - userMapper.delete(dw); - userPasswordHistoryMapper.delete(dw); - userRoleMapper.delete(dw); - userSocialMapper.delete(dw); - } - -} diff --git a/continew-system/src/main/java/top/continew/admin/system/service/impl/UserServiceImpl.java b/continew-system/src/main/java/top/continew/admin/system/service/impl/UserServiceImpl.java index f6dddd7a..9bd3dceb 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/impl/UserServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/impl/UserServiceImpl.java @@ -23,7 +23,10 @@ import cn.hutool.core.io.file.FileNameUtil; import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.lang.UUID; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.*; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.EnumUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import cn.hutool.extra.validation.ValidationUtil; import cn.hutool.http.ContentType; import cn.hutool.json.JSONUtil; @@ -54,7 +57,6 @@ import org.springframework.web.multipart.MultipartFile; import top.continew.admin.auth.service.OnlineUserService; import top.continew.admin.common.base.service.BaseServiceImpl; import top.continew.admin.common.constant.CacheConstants; -import top.continew.admin.common.constant.RegexConstants; import top.continew.admin.common.constant.SysConstants; import top.continew.admin.common.context.UserContext; import top.continew.admin.common.context.UserContextHolder; @@ -78,10 +80,8 @@ import top.continew.admin.system.service.*; import top.continew.starter.cache.redisson.util.RedisUtils; import top.continew.starter.core.constant.StringConstants; import top.continew.starter.core.exception.BusinessException; -import top.continew.starter.core.util.ExceptionUtils; import top.continew.starter.core.util.FileUploadUtils; import top.continew.starter.core.util.validation.CheckUtils; -import top.continew.starter.core.util.validation.ValidationUtils; import top.continew.starter.extension.crud.model.query.PageQuery; import top.continew.starter.extension.crud.model.query.SortQuery; import top.continew.starter.extension.crud.model.resp.PageResp; @@ -734,26 +734,6 @@ public class UserServiceImpl extends BaseServiceImpl SecureUtils.decryptByRsaPrivateKey(password)); - ValidationUtils.throwIfNull(rawPassword, "密码解密失败"); - ValidationUtils.throwIf(!ReUtil - .isMatch(RegexConstants.PASSWORD, rawPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字"); - UserDO userDO = new UserDO(); - userDO.setUsername(username); - userDO.setNickname("系统管理员"); - userDO.setPassword(rawPassword); - userDO.setGender(GenderEnum.UNKNOWN); - userDO.setDescription("系统初始用户"); - userDO.setStatus(DisEnableStatusEnum.ENABLE); - userDO.setIsSystem(true); - userDO.setDeptId(deptId); - baseMapper.insert(userDO); - return userDO.getId(); - } - /** * 根据 ID 获取用户信息(数据权限) * diff --git a/pom.xml b/pom.xml index c6dd7695..4336c945 100644 --- a/pom.xml +++ b/pom.xml @@ -62,13 +62,6 @@ ${revision} - - - top.continew.admin - continew-plugin-schedule - ${revision} - - top.continew.admin @@ -76,11 +69,18 @@ ${revision} - + top.continew.admin continew-plugin-tenant - 4.0.0-SNAPSHOT + ${revision} + + + + + top.continew.admin + continew-plugin-schedule + ${revision}