Commit feba904fd88fce6815d54c832d46af122ebed48a
1 parent
c162b39e
多租户:登录界面,根据 host 域名获取对应的租户编号
Showing
9 changed files
with
83 additions
and
14 deletions
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
| @@ -104,6 +104,7 @@ public interface ErrorCodeConstants { | @@ -104,6 +104,7 @@ public interface ErrorCodeConstants { | ||
| 104 | ErrorCode TENANT_EXPIRE = new ErrorCode(1_002_015_002, "名字为【{}】的租户已过期"); | 104 | ErrorCode TENANT_EXPIRE = new ErrorCode(1_002_015_002, "名字为【{}】的租户已过期"); |
| 105 | ErrorCode TENANT_CAN_NOT_UPDATE_SYSTEM = new ErrorCode(1_002_015_003, "系统租户不能进行修改、删除等操作!"); | 105 | ErrorCode TENANT_CAN_NOT_UPDATE_SYSTEM = new ErrorCode(1_002_015_003, "系统租户不能进行修改、删除等操作!"); |
| 106 | ErrorCode TENANT_NAME_DUPLICATE = new ErrorCode(1_002_015_004, "名字为【{}】的租户已存在"); | 106 | ErrorCode TENANT_NAME_DUPLICATE = new ErrorCode(1_002_015_004, "名字为【{}】的租户已存在"); |
| 107 | + ErrorCode TENANT_WEBSITE_DUPLICATE = new ErrorCode(1_002_015_005, "域名为【{}】的租户已存在"); | ||
| 107 | 108 | ||
| 108 | // ========== 租户套餐 1-002-016-000 ========== | 109 | // ========== 租户套餐 1-002-016-000 ========== |
| 109 | ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "租户套餐不存在"); | 110 | ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "租户套餐不存在"); |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java
| @@ -37,8 +37,17 @@ public class TenantController { | @@ -37,8 +37,17 @@ public class TenantController { | ||
| 37 | @Operation(summary = "使用租户名,获得租户编号", description = "登录界面,根据用户的租户名,获得租户编号") | 37 | @Operation(summary = "使用租户名,获得租户编号", description = "登录界面,根据用户的租户名,获得租户编号") |
| 38 | @Parameter(name = "name", description = "租户名", required = true, example = "1024") | 38 | @Parameter(name = "name", description = "租户名", required = true, example = "1024") |
| 39 | public CommonResult<Long> getTenantIdByName(@RequestParam("name") String name) { | 39 | public CommonResult<Long> getTenantIdByName(@RequestParam("name") String name) { |
| 40 | - TenantDO tenantDO = tenantService.getTenantByName(name); | ||
| 41 | - return success(tenantDO != null ? tenantDO.getId() : null); | 40 | + TenantDO tenant = tenantService.getTenantByName(name); |
| 41 | + return success(tenant != null ? tenant.getId() : null); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + @GetMapping("/get-by-website") | ||
| 45 | + @PermitAll | ||
| 46 | + @Operation(summary = "使用域名,获得租户信息", description = "登录界面,根据用户的域名,获得租户信息") | ||
| 47 | + @Parameter(name = "website", description = "域名", required = true, example = "www.iocoder.cn") | ||
| 48 | + public CommonResult<TenantSimpleRespVO> getTenantByWebsite(@RequestParam("website") String website) { | ||
| 49 | + TenantDO tenant = tenantService.getTenantByWebsite(website); | ||
| 50 | + return success(TenantConvert.INSTANCE.convert03(tenant)); | ||
| 42 | } | 51 | } |
| 43 | 52 | ||
| 44 | @PostMapping("/create") | 53 | @PostMapping("/create") |
| @@ -94,5 +103,4 @@ public class TenantController { | @@ -94,5 +103,4 @@ public class TenantController { | ||
| 94 | ExcelUtils.write(response, "租户.xls", "数据", TenantExcelVO.class, datas); | 103 | ExcelUtils.write(response, "租户.xls", "数据", TenantExcelVO.class, datas); |
| 95 | } | 104 | } |
| 96 | 105 | ||
| 97 | - | ||
| 98 | } | 106 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSimpleRespVO.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import lombok.EqualsAndHashCode; | ||
| 6 | +import lombok.ToString; | ||
| 7 | + | ||
| 8 | +@Schema(description = "管理后台 - 租户精简 Response VO") | ||
| 9 | +@Data | ||
| 10 | +@EqualsAndHashCode(callSuper = true) | ||
| 11 | +@ToString(callSuper = true) | ||
| 12 | +public class TenantSimpleRespVO extends TenantBaseVO { | ||
| 13 | + | ||
| 14 | + @Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||
| 15 | + private Long id; | ||
| 16 | + | ||
| 17 | + @Schema(description = "租户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") | ||
| 18 | + private String name; | ||
| 19 | + | ||
| 20 | +} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/tenant/TenantConvert.java
| 1 | package cn.iocoder.yudao.module.system.convert.tenant; | 1 | package cn.iocoder.yudao.module.system.convert.tenant; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | -import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantCreateReqVO; | ||
| 5 | -import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantExcelVO; | ||
| 6 | -import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantRespVO; | ||
| 7 | -import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantUpdateReqVO; | 4 | +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.*; |
| 8 | import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserCreateReqVO; | 5 | import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserCreateReqVO; |
| 9 | import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; | 6 | import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; |
| 10 | import org.mapstruct.Mapper; | 7 | import org.mapstruct.Mapper; |
| @@ -28,6 +25,8 @@ public interface TenantConvert { | @@ -28,6 +25,8 @@ public interface TenantConvert { | ||
| 28 | 25 | ||
| 29 | TenantRespVO convert(TenantDO bean); | 26 | TenantRespVO convert(TenantDO bean); |
| 30 | 27 | ||
| 28 | + TenantSimpleRespVO convert03(TenantDO bean); | ||
| 29 | + | ||
| 31 | List<TenantRespVO> convertList(List<TenantDO> list); | 30 | List<TenantRespVO> convertList(List<TenantDO> list); |
| 32 | 31 | ||
| 33 | PageResult<TenantRespVO> convertPage(PageResult<TenantDO> page); | 32 | PageResult<TenantRespVO> convertPage(PageResult<TenantDO> page); |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java
| @@ -42,6 +42,10 @@ public interface TenantMapper extends BaseMapperX<TenantDO> { | @@ -42,6 +42,10 @@ public interface TenantMapper extends BaseMapperX<TenantDO> { | ||
| 42 | return selectOne(TenantDO::getName, name); | 42 | return selectOne(TenantDO::getName, name); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | + default TenantDO selectByWebsite(String website) { | ||
| 46 | + return selectOne(TenantDO::getWebsite, website); | ||
| 47 | + } | ||
| 48 | + | ||
| 45 | default Long selectCountByPackageId(Long packageId) { | 49 | default Long selectCountByPackageId(Long packageId) { |
| 46 | return selectCount(TenantDO::getPackageId, packageId); | 50 | return selectCount(TenantDO::getPackageId, packageId); |
| 47 | } | 51 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java
| @@ -78,12 +78,20 @@ public interface TenantService { | @@ -78,12 +78,20 @@ public interface TenantService { | ||
| 78 | /** | 78 | /** |
| 79 | * 获得名字对应的租户 | 79 | * 获得名字对应的租户 |
| 80 | * | 80 | * |
| 81 | - * @param name 组户名 | 81 | + * @param name 租户名 |
| 82 | * @return 租户 | 82 | * @return 租户 |
| 83 | */ | 83 | */ |
| 84 | TenantDO getTenantByName(String name); | 84 | TenantDO getTenantByName(String name); |
| 85 | 85 | ||
| 86 | /** | 86 | /** |
| 87 | + * 获得域名对应的租户 | ||
| 88 | + * | ||
| 89 | + * @param website 域名 | ||
| 90 | + * @return 租户 | ||
| 91 | + */ | ||
| 92 | + TenantDO getTenantByWebsite(String website); | ||
| 93 | + | ||
| 94 | + /** | ||
| 87 | * 获得使用指定套餐的租户数量 | 95 | * 获得使用指定套餐的租户数量 |
| 88 | * | 96 | * |
| 89 | * @param packageId 租户套餐编号 | 97 | * @param packageId 租户套餐编号 |
| @@ -128,4 +136,5 @@ public interface TenantService { | @@ -128,4 +136,5 @@ public interface TenantService { | ||
| 128 | * @param id 租户编号 | 136 | * @param id 租户编号 |
| 129 | */ | 137 | */ |
| 130 | void validTenant(Long id); | 138 | void validTenant(Long id); |
| 139 | + | ||
| 131 | } | 140 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.tenant; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.tenant; | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.lang.Assert; | 4 | import cn.hutool.core.lang.Assert; |
| 5 | import cn.hutool.core.util.ObjectUtil; | 5 | import cn.hutool.core.util.ObjectUtil; |
| 6 | +import cn.hutool.core.util.StrUtil; | ||
| 6 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 7 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 8 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 9 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| @@ -99,6 +100,8 @@ public class TenantServiceImpl implements TenantService { | @@ -99,6 +100,8 @@ public class TenantServiceImpl implements TenantService { | ||
| 99 | public Long createTenant(TenantCreateReqVO createReqVO) { | 100 | public Long createTenant(TenantCreateReqVO createReqVO) { |
| 100 | // 校验租户名称是否重复 | 101 | // 校验租户名称是否重复 |
| 101 | validTenantNameDuplicate(createReqVO.getName(), null); | 102 | validTenantNameDuplicate(createReqVO.getName(), null); |
| 103 | + // 校验租户域名是否重复 | ||
| 104 | + validTenantWebsiteDuplicate(createReqVO.getWebsite(), null); | ||
| 102 | // 校验套餐被禁用 | 105 | // 校验套餐被禁用 |
| 103 | TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId()); | 106 | TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId()); |
| 104 | 107 | ||
| @@ -143,6 +146,8 @@ public class TenantServiceImpl implements TenantService { | @@ -143,6 +146,8 @@ public class TenantServiceImpl implements TenantService { | ||
| 143 | TenantDO tenant = validateUpdateTenant(updateReqVO.getId()); | 146 | TenantDO tenant = validateUpdateTenant(updateReqVO.getId()); |
| 144 | // 校验租户名称是否重复 | 147 | // 校验租户名称是否重复 |
| 145 | validTenantNameDuplicate(updateReqVO.getName(), updateReqVO.getId()); | 148 | validTenantNameDuplicate(updateReqVO.getName(), updateReqVO.getId()); |
| 149 | + // 校验租户域名是否重复 | ||
| 150 | + validTenantWebsiteDuplicate(updateReqVO.getWebsite(), updateReqVO.getId()); | ||
| 146 | // 校验套餐被禁用 | 151 | // 校验套餐被禁用 |
| 147 | TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId()); | 152 | TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId()); |
| 148 | 153 | ||
| @@ -169,6 +174,23 @@ public class TenantServiceImpl implements TenantService { | @@ -169,6 +174,23 @@ public class TenantServiceImpl implements TenantService { | ||
| 169 | } | 174 | } |
| 170 | } | 175 | } |
| 171 | 176 | ||
| 177 | + private void validTenantWebsiteDuplicate(String website, Long id) { | ||
| 178 | + if (StrUtil.isEmpty(website)) { | ||
| 179 | + return; | ||
| 180 | + } | ||
| 181 | + TenantDO tenant = tenantMapper.selectByWebsite(website); | ||
| 182 | + if (tenant == null) { | ||
| 183 | + return; | ||
| 184 | + } | ||
| 185 | + // 如果 id 为空,说明不用比较是否为相同名字的租户 | ||
| 186 | + if (id == null) { | ||
| 187 | + throw exception(TENANT_WEBSITE_DUPLICATE, website); | ||
| 188 | + } | ||
| 189 | + if (!tenant.getId().equals(id)) { | ||
| 190 | + throw exception(TENANT_WEBSITE_DUPLICATE, website); | ||
| 191 | + } | ||
| 192 | + } | ||
| 193 | + | ||
| 172 | @Override | 194 | @Override |
| 173 | @DSTransactional | 195 | @DSTransactional |
| 174 | public void updateTenantRoleMenu(Long tenantId, Set<Long> menuIds) { | 196 | public void updateTenantRoleMenu(Long tenantId, Set<Long> menuIds) { |
| @@ -235,6 +257,11 @@ public class TenantServiceImpl implements TenantService { | @@ -235,6 +257,11 @@ public class TenantServiceImpl implements TenantService { | ||
| 235 | } | 257 | } |
| 236 | 258 | ||
| 237 | @Override | 259 | @Override |
| 260 | + public TenantDO getTenantByWebsite(String website) { | ||
| 261 | + return tenantMapper.selectByWebsite(website); | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + @Override | ||
| 238 | public Long getTenantCountByPackageId(Long packageId) { | 265 | public Long getTenantCountByPackageId(Long packageId) { |
| 239 | return tenantMapper.selectCountByPackageId(packageId); | 266 | return tenantMapper.selectCountByPackageId(packageId); |
| 240 | } | 267 | } |
yudao-server/src/main/resources/application-local.yaml
| @@ -49,18 +49,18 @@ spring: | @@ -49,18 +49,18 @@ spring: | ||
| 49 | datasource: | 49 | datasource: |
| 50 | master: | 50 | master: |
| 51 | name: ruoyi-vue-pro | 51 | name: ruoyi-vue-pro |
| 52 | - # url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 | 52 | + url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 |
| 53 | # url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例 | 53 | # url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例 |
| 54 | # url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.master.name} # PostgreSQL 连接的示例 | 54 | # url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.master.name} # PostgreSQL 连接的示例 |
| 55 | # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 | 55 | # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 |
| 56 | # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.master.name} # SQLServer 连接的示例 | 56 | # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.master.name} # SQLServer 连接的示例 |
| 57 | - url: jdbc:dm://10.211.55.4:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 | ||
| 58 | -# username: root | ||
| 59 | -# password: 123456 | 57 | +# url: jdbc:dm://10.211.55.4:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 |
| 58 | + username: root | ||
| 59 | + password: 123456 | ||
| 60 | # username: sa | 60 | # username: sa |
| 61 | # password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W | 61 | # password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W |
| 62 | - username: SYSDBA # DM 连接的示例 | ||
| 63 | - password: SYSDBA # DM 连接的示例 | 62 | +# username: SYSDBA # DM 连接的示例 |
| 63 | +# password: SYSDBA # DM 连接的示例 | ||
| 64 | slave: # 模拟从库,可根据自己需要修改 | 64 | slave: # 模拟从库,可根据自己需要修改 |
| 65 | name: ruoyi-vue-pro | 65 | name: ruoyi-vue-pro |
| 66 | lazy: true # 开启懒加载,保证启动速度 | 66 | lazy: true # 开启懒加载,保证启动速度 |
yudao-server/src/main/resources/application.yaml
| @@ -175,6 +175,7 @@ yudao: | @@ -175,6 +175,7 @@ yudao: | ||
| 175 | enable: true | 175 | enable: true |
| 176 | ignore-urls: | 176 | ignore-urls: |
| 177 | - /admin-api/system/tenant/get-id-by-name # 基于名字获取租户,不许带租户编号 | 177 | - /admin-api/system/tenant/get-id-by-name # 基于名字获取租户,不许带租户编号 |
| 178 | + - /admin-api/system/tenant/get-by-website # 基于域名获取租户,不许带租户编号 | ||
| 178 | - /admin-api/system/captcha/get # 获取图片验证码,和租户无关 | 179 | - /admin-api/system/captcha/get # 获取图片验证码,和租户无关 |
| 179 | - /admin-api/system/captcha/check # 校验图片验证码,和租户无关 | 180 | - /admin-api/system/captcha/check # 校验图片验证码,和租户无关 |
| 180 | - /admin-api/infra/file/*/get/** # 获取图片,和租户无关 | 181 | - /admin-api/infra/file/*/get/** # 获取图片,和租户无关 |