feat(tenant): 实现租户创建时自动初始化管理员和权限体系

- 修改create方法返回类型为Long并接收CreateTenantDTO参数
- 新增createTenantWithAdmin方法实现完整的租户初始化流程
- 添加租户编码唯一性校验逻辑
- 实现根组织、管理员角色、默认菜单权限的自动创建
- 集成管理员用户的自动生成和绑定机制
- 添加密码重置标识字段到SysUser实体
- 实现事务回滚确保数据一致性
master
chenhao 2026-02-26 16:50:32 +08:00
parent 8959680d31
commit 0530605839
4 changed files with 140 additions and 4 deletions

View File

@ -48,8 +48,8 @@ public class SysTenantController {
@PostMapping
@PreAuthorize("@ss.hasPermi('sys_tenant:create')")
@Log(value = "新增租户", type = "租户管理")
public ApiResponse<Boolean> create(@RequestBody SysTenant tenant) {
return ApiResponse.ok(sysTenantService.save(tenant));
public ApiResponse<Long> create(@RequestBody com.imeeting.dto.CreateTenantDTO tenantDto) {
return ApiResponse.ok(sysTenantService.createTenantWithAdmin(tenantDto));
}
@PutMapping("/{id}")

View File

@ -15,6 +15,7 @@ public class SysUser extends BaseEntity {
private String email;
private String phone;
private String passwordHash;
private Integer pwdResetRequired;
private Boolean isPlatformAdmin;

View File

@ -1,7 +1,14 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.dto.CreateTenantDTO;
import com.imeeting.entity.SysTenant;
public interface SysTenantService extends IService<SysTenant> {
/**
*
* @param dto
* @return ID
*/
Long createTenantWithAdmin(CreateTenantDTO dto);
}

View File

@ -1,11 +1,139 @@
package com.imeeting.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.imeeting.entity.SysTenant;
import com.imeeting.dto.CreateTenantDTO;
import com.imeeting.entity.*;
import com.imeeting.mapper.SysRolePermissionMapper;
import com.imeeting.mapper.SysTenantMapper;
import com.imeeting.service.SysTenantService;
import com.imeeting.mapper.SysUserRoleMapper;
import com.imeeting.service.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant> implements SysTenantService {
private final SysUserService sysUserService;
private final SysRoleService sysRoleService;
private final SysOrgService sysOrgService;
private final SysPermissionService sysPermissionService;
private final SysParamService sysParamService;
private final SysUserRoleMapper sysUserRoleMapper;
private final SysRolePermissionMapper sysRolePermissionMapper;
private final SysTenantUserService sysTenantUserService;
private final PasswordEncoder passwordEncoder;
public SysTenantServiceImpl(SysUserService sysUserService, SysRoleService sysRoleService,
SysOrgService sysOrgService, SysPermissionService sysPermissionService,
SysParamService sysParamService, SysUserRoleMapper sysUserRoleMapper,
SysRolePermissionMapper sysRolePermissionMapper,
SysTenantUserService sysTenantUserService, PasswordEncoder passwordEncoder) {
this.sysUserService = sysUserService;
this.sysRoleService = sysRoleService;
this.sysOrgService = sysOrgService;
this.sysPermissionService = sysPermissionService;
this.sysParamService = sysParamService;
this.sysUserRoleMapper = sysUserRoleMapper;
this.sysRolePermissionMapper = sysRolePermissionMapper;
this.sysTenantUserService = sysTenantUserService;
this.passwordEncoder = passwordEncoder;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long createTenantWithAdmin(CreateTenantDTO dto) {
// 1. 校验租户编码唯一性
if (count(new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getTenantCode, dto.getTenantCode())) > 0) {
throw new RuntimeException("租户编码已存在:" + dto.getTenantCode());
}
// 2. 创建租户
SysTenant tenant = new SysTenant();
tenant.setTenantCode(dto.getTenantCode());
tenant.setTenantName(dto.getTenantName());
tenant.setContactName(dto.getContactName());
tenant.setContactPhone(dto.getContactPhone());
tenant.setRemark(dto.getRemark());
tenant.setExpireTime(dto.getExpireTime());
tenant.setStatus(1);
save(tenant);
Long tenantId = tenant.getId();
// 3. 初始化根组织
SysOrg rootOrg = new SysOrg();
rootOrg.setTenantId(tenantId);
rootOrg.setOrgName(dto.getTenantName());
rootOrg.setOrgCode(dto.getTenantCode() + "_ROOT");
rootOrg.setParentId(null);
rootOrg.setStatus(1);
sysOrgService.save(rootOrg);
Long orgId = rootOrg.getId();
// 4. 创建租户管理员角色
SysRole adminRole = new SysRole();
adminRole.setTenantId(tenantId);
adminRole.setRoleCode("TENANT_ADMIN");
adminRole.setRoleName("租户管理员");
adminRole.setStatus(1);
adminRole.setRemark("系统自动初始化的租户管理员角色");
sysRoleService.save(adminRole);
Long roleId = adminRole.getRoleId();
// 5. 分配默认菜单权限
String menuCodes = sysParamService.getParamValue("tenant.init.default.menu.codes", "");
if (menuCodes != null && !menuCodes.trim().isEmpty()) {
List<String> codes = Arrays.asList(menuCodes.split(","));
List<SysPermission> perms = sysPermissionService.list(
new LambdaQueryWrapper<SysPermission>().in(SysPermission::getCode, codes)
);
if (!perms.isEmpty()) {
for (SysPermission p : perms) {
SysRolePermission rp = new SysRolePermission();
rp.setRoleId(roleId);
rp.setPermId(p.getPermId());
sysRolePermissionMapper.insert(rp);
}
}
}
// 6. 创建管理员用户
String username = "admin_" + dto.getTenantCode();
if (sysUserService.count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username)) > 0) {
throw new RuntimeException("管理员用户名已存在:" + username);
}
String defaultPwd = sysParamService.getParamValue("tenant.init.default.password", "123456");
SysUser user = new SysUser();
user.setUsername(username);
user.setDisplayName(dto.getTenantName() + "管理员");
user.setPasswordHash(passwordEncoder.encode(defaultPwd));
user.setPwdResetRequired(1);
user.setStatus(1);
user.setIsPlatformAdmin(false);
sysUserService.save(user);
Long userId = user.getUserId();
// 7. 绑定用户与角色 (sys_user_role)
SysUserRole ur = new SysUserRole();
ur.setUserId(userId);
ur.setRoleId(roleId);
sysUserRoleMapper.insert(ur);
// 8. 绑定用户与租户/组织 (sys_tenant_user)
SysTenantUser tu = new SysTenantUser();
tu.setUserId(userId);
tu.setTenantId(tenantId);
tu.setOrgId(orgId);
tu.setStatus(1);
sysTenantUserService.save(tu);
return tenantId;
}
}