Commit feba904fd88fce6815d54c832d46af122ebed48a

Authored by YunaiV
1 parent c162b39e

多租户:登录界面,根据 host 域名获取对应的租户编号

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&lt;TenantDO&gt; { @@ -42,6 +42,10 @@ public interface TenantMapper extends BaseMapperX&lt;TenantDO&gt; {
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/** # 获取图片,和租户无关