移除租户模块

This commit is contained in:
jiangdingxuan 2024-01-09 15:19:53 +08:00
parent 0547e40bd2
commit e198bc882f
51 changed files with 96 additions and 2460 deletions

View File

@ -1,30 +0,0 @@
package org.dromara.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 用户状态
*
* @author LionLi
*/
@Getter
@AllArgsConstructor
public enum TenantStatus {
/**
* 正常
*/
OK("0", "正常"),
/**
* 停用
*/
DISABLE("1", "停用"),
/**
* 删除
*/
DELETED("2", "删除");
private final String code;
private final String info;
}

View File

@ -1,101 +0,0 @@
package org.dromara.common.tenant.config;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import org.dromara.common.core.utils.reflect.ReflectUtils;
import org.dromara.common.mybatis.config.MybatisPlusConfig;
import org.dromara.common.redis.config.RedisConfig;
import org.dromara.common.redis.config.properties.RedissonProperties;
import org.dromara.common.tenant.core.TenantSaTokenDao;
import org.dromara.common.tenant.handle.PlusTenantLineHandler;
import org.dromara.common.tenant.handle.TenantKeyPrefixHandler;
import org.dromara.common.tenant.manager.TenantSpringCacheManager;
import org.dromara.common.tenant.properties.TenantProperties;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.SingleServerConfig;
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import java.util.ArrayList;
import java.util.List;
/**
* 租户配置类
*
* @author Lion Li
*/
@EnableConfigurationProperties(TenantProperties.class)
@Configuration
@ConditionalOnProperty(value = "tenant.enable", havingValue = "true")
public class TenantConfig {
/**
* 初始化租户配置
*/
@Bean
public boolean tenantInit(MybatisPlusInterceptor mybatisPlusInterceptor,
TenantProperties tenantProperties) {
List<InnerInterceptor> interceptors = new ArrayList<>();
// 多租户插件 必须放到第一位
interceptors.add(tenantLineInnerInterceptor(tenantProperties));
interceptors.addAll(mybatisPlusInterceptor.getInterceptors());
mybatisPlusInterceptor.setInterceptors(interceptors);
return true;
}
/**
* 多租户插件
*/
public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantProperties tenantProperties) {
return new TenantLineInnerInterceptor(new PlusTenantLineHandler(tenantProperties));
}
@Bean
public RedissonAutoConfigurationCustomizer tenantRedissonCustomizer(RedissonProperties redissonProperties) {
return config -> {
TenantKeyPrefixHandler nameMapper = new TenantKeyPrefixHandler(redissonProperties.getKeyPrefix());
SingleServerConfig singleServerConfig = ReflectUtils.invokeGetter(config, "singleServerConfig");
if (ObjectUtil.isNotNull(singleServerConfig)) {
// 使用单机模式
// 设置多租户 redis key前缀
singleServerConfig.setNameMapper(nameMapper);
ReflectUtils.invokeSetter(config, "singleServerConfig", singleServerConfig);
}
ClusterServersConfig clusterServersConfig = ReflectUtils.invokeGetter(config, "clusterServersConfig");
// 集群配置方式 参考下方注释
if (ObjectUtil.isNotNull(clusterServersConfig)) {
// 设置多租户 redis key前缀
clusterServersConfig.setNameMapper(nameMapper);
ReflectUtils.invokeSetter(config, "clusterServersConfig", clusterServersConfig);
}
};
}
/**
* 多租户缓存管理器
*/
@Primary
@Bean
public CacheManager tenantCacheManager() {
return new TenantSpringCacheManager();
}
/**
* 多租户鉴权dao实现
*/
@Primary
@Bean
public SaTokenDao tenantSaTokenDao() {
return new TenantSaTokenDao();
}
}

View File

@ -1,21 +0,0 @@
package org.dromara.common.tenant.core;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 租户基类
*
* @author Michelle.Chung
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TenantEntity extends BaseEntity {
/**
* 租户编号
*/
private String tenantId;
}

View File

@ -1,148 +0,0 @@
package org.dromara.common.tenant.core;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.core.dao.PlusSaTokenDao;
import java.time.Duration;
import java.util.List;
/**
* SaToken 认证数据持久层 适配多租户
*
* @author Lion Li
*/
public class TenantSaTokenDao extends PlusSaTokenDao {
@Override
public String get(String key) {
return super.get(GlobalConstants.GLOBAL_REDIS_KEY + key);
}
@Override
public void set(String key, String value, long timeout) {
super.set(GlobalConstants.GLOBAL_REDIS_KEY + key, value, timeout);
}
/**
* 修修改指定key-value键值对 (过期时间不变)
*/
@Override
public void update(String key, String value) {
long expire = getTimeout(key);
// -2 = 无此键
if (expire == NOT_VALUE_EXPIRE) {
return;
}
this.set(key, value, expire);
}
/**
* 删除Value
*/
@Override
public void delete(String key) {
super.delete(GlobalConstants.GLOBAL_REDIS_KEY + key);
}
/**
* 获取Value的剩余存活时间 (单位: )
*/
@Override
public long getTimeout(String key) {
return super.getTimeout(GlobalConstants.GLOBAL_REDIS_KEY + key);
}
/**
* 修改Value的剩余存活时间 (单位: )
*/
@Override
public void updateTimeout(String key, long timeout) {
// 判断是否想要设置为永久
if (timeout == NEVER_EXPIRE) {
long expire = getTimeout(key);
if (expire == NEVER_EXPIRE) {
// 如果其已经被设置为永久则不作任何处理
} else {
// 如果尚未被设置为永久那么再次set一次
this.set(key, this.get(key), timeout);
}
return;
}
RedisUtils.expire(GlobalConstants.GLOBAL_REDIS_KEY + key, Duration.ofSeconds(timeout));
}
/**
* 获取Object如无返空
*/
@Override
public Object getObject(String key) {
return super.getObject(GlobalConstants.GLOBAL_REDIS_KEY + key);
}
/**
* 写入Object并设定存活时间 (单位: )
*/
@Override
public void setObject(String key, Object object, long timeout) {
super.setObject(GlobalConstants.GLOBAL_REDIS_KEY + key, object, timeout);
}
/**
* 更新Object (过期时间不变)
*/
@Override
public void updateObject(String key, Object object) {
long expire = getObjectTimeout(key);
// -2 = 无此键
if (expire == NOT_VALUE_EXPIRE) {
return;
}
this.setObject(key, object, expire);
}
/**
* 删除Object
*/
@Override
public void deleteObject(String key) {
super.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + key);
}
/**
* 获取Object的剩余存活时间 (单位: )
*/
@Override
public long getObjectTimeout(String key) {
return super.getObjectTimeout(GlobalConstants.GLOBAL_REDIS_KEY + key);
}
/**
* 修改Object的剩余存活时间 (单位: )
*/
@Override
public void updateObjectTimeout(String key, long timeout) {
// 判断是否想要设置为永久
if (timeout == NEVER_EXPIRE) {
long expire = getObjectTimeout(key);
if (expire == NEVER_EXPIRE) {
// 如果其已经被设置为永久则不作任何处理
} else {
// 如果尚未被设置为永久那么再次set一次
this.setObject(key, this.getObject(key), timeout);
}
return;
}
RedisUtils.expire(GlobalConstants.GLOBAL_REDIS_KEY + key, Duration.ofSeconds(timeout));
}
/**
* 搜索数据
*/
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
return super.searchData(GlobalConstants.GLOBAL_REDIS_KEY + prefix, keyword, start, size, sortType);
}
}

View File

@ -1,20 +0,0 @@
package org.dromara.common.tenant.exception;
import org.dromara.common.core.exception.base.BaseException;
import java.io.Serial;
/**
* 租户异常类
*
* @author Lion Li
*/
public class TenantException extends BaseException {
@Serial
private static final long serialVersionUID = 1L;
public TenantException(String code, Object... args) {
super("tenant", code, args, null);
}
}

View File

@ -1,56 +0,0 @@
package org.dromara.common.tenant.handle;
import cn.hutool.core.collection.ListUtil;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.NullValue;
import net.sf.jsqlparser.expression.StringValue;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.tenant.properties.TenantProperties;
import java.util.List;
/**
* 自定义租户处理器
*
* @author Lion Li
*/
@Slf4j
@AllArgsConstructor
public class PlusTenantLineHandler implements TenantLineHandler {
private final TenantProperties tenantProperties;
@Override
public Expression getTenantId() {
String tenantId = TenantHelper.getTenantId();
if (StringUtils.isBlank(tenantId)) {
log.error("无法获取有效的租户id -> Null");
return new NullValue();
}
// 返回固定租户
return new StringValue(tenantId);
}
@Override
public boolean ignoreTable(String tableName) {
String tenantId = TenantHelper.getTenantId();
// 判断是否有租户
if (StringUtils.isNotBlank(tenantId)) {
// 不需要过滤租户的表
List<String> excludes = tenantProperties.getExcludes();
// 非业务表
List<String> tables = ListUtil.toList(
"gen_table",
"gen_table_column"
);
tables.addAll(excludes);
return tables.contains(tableName);
}
return true;
}
}

View File

@ -1,66 +0,0 @@
package org.dromara.common.tenant.handle;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.redis.handler.KeyPrefixHandler;
import org.dromara.common.tenant.helper.TenantHelper;
/**
* 多租户redis缓存key前缀处理
*
* @author Lion Li
*/
@Slf4j
public class TenantKeyPrefixHandler extends KeyPrefixHandler {
public TenantKeyPrefixHandler(String keyPrefix) {
super(keyPrefix);
}
/**
* 增加前缀
*/
@Override
public String map(String name) {
if (StringUtils.isBlank(name)) {
return null;
}
if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
return super.map(name);
}
String tenantId = TenantHelper.getTenantId();
if (StringUtils.isBlank(tenantId)) {
log.error("无法获取有效的租户id -> Null");
}
if (StringUtils.startsWith(name, tenantId + "")) {
// 如果存在则直接返回
return super.map(name);
}
return super.map(tenantId + ":" + name);
}
/**
* 去除前缀
*/
@Override
public String unmap(String name) {
String unmap = super.unmap(name);
if (StringUtils.isBlank(unmap)) {
return null;
}
if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
return super.unmap(name);
}
String tenantId = TenantHelper.getTenantId();
if (StringUtils.isBlank(tenantId)) {
log.error("无法获取有效的租户id -> Null");
}
if (StringUtils.startsWith(unmap, tenantId + "")) {
// 如果存在则删除
return unmap.substring((tenantId + ":").length());
}
return unmap;
}
}

View File

@ -1,189 +0,0 @@
package org.dromara.common.tenant.helper;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import java.util.function.Supplier;
/**
* 租户助手
*
* @author Lion Li
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class TenantHelper {
private static final String DYNAMIC_TENANT_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "dynamicTenant";
private static final ThreadLocal<String> TEMP_DYNAMIC_TENANT = new TransmittableThreadLocal<>();
/**
* 租户功能是否启用
*/
public static boolean isEnable() {
return Convert.toBool(SpringUtils.getProperty("tenant.enable"), false);
}
/**
* 开启忽略租户(开启后需手动调用 {@link #disableIgnore()} 关闭)
*/
public static void enableIgnore() {
InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build());
}
/**
* 关闭忽略租户
*/
public static void disableIgnore() {
InterceptorIgnoreHelper.clearIgnoreStrategy();
}
/**
* 在忽略租户中执行
*
* @param handle 处理执行方法
*/
public static void ignore(Runnable handle) {
enableIgnore();
try {
handle.run();
} finally {
disableIgnore();
}
}
/**
* 在忽略租户中执行
*
* @param handle 处理执行方法
*/
public static <T> T ignore(Supplier<T> handle) {
enableIgnore();
try {
return handle.get();
} finally {
disableIgnore();
}
}
/**
* 设置动态租户(一直有效 需要手动清理)
* <p>
* 如果为未登录状态下 那么只在当前线程内生效
*/
public static void setDynamic(String tenantId) {
if (!isEnable()) {
return;
}
if (!isLogin()) {
TEMP_DYNAMIC_TENANT.set(tenantId);
return;
}
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
RedisUtils.setCacheObject(cacheKey, tenantId);
SaHolder.getStorage().set(cacheKey, tenantId);
}
/**
* 获取动态租户(一直有效 需要手动清理)
* <p>
* 如果为未登录状态下 那么只在当前线程内生效
*/
public static String getDynamic() {
if (!isEnable()) {
return null;
}
if (!isLogin()) {
return TEMP_DYNAMIC_TENANT.get();
}
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
String tenantId = (String) SaHolder.getStorage().get(cacheKey);
if (StringUtils.isNotBlank(tenantId)) {
return tenantId;
}
tenantId = RedisUtils.getCacheObject(cacheKey);
SaHolder.getStorage().set(cacheKey, tenantId);
return tenantId;
}
/**
* 清除动态租户
*/
public static void clearDynamic() {
if (!isEnable()) {
return;
}
if (!isLogin()) {
TEMP_DYNAMIC_TENANT.remove();
return;
}
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
RedisUtils.deleteObject(cacheKey);
SaHolder.getStorage().delete(cacheKey);
}
/**
* 在动态租户中执行
*
* @param handle 处理执行方法
*/
public static void dynamic(String tenantId, Runnable handle) {
setDynamic(tenantId);
try {
handle.run();
} finally {
clearDynamic();
}
}
/**
* 在动态租户中执行
*
* @param handle 处理执行方法
*/
public static <T> T dynamic(String tenantId, Supplier<T> handle) {
setDynamic(tenantId);
try {
return handle.get();
} finally {
clearDynamic();
}
}
/**
* 获取当前租户id(动态租户优先)
*/
public static String getTenantId() {
if (!isEnable()) {
return null;
}
String tenantId = TenantHelper.getDynamic();
if (StringUtils.isBlank(tenantId)) {
tenantId = LoginHelper.getTenantId();
}
return tenantId;
}
private static boolean isLogin() {
try {
StpUtil.checkLogin();
return true;
} catch (Exception e) {
return false;
}
}
}

View File

@ -1,32 +0,0 @@
package org.dromara.common.tenant.manager;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.redis.manager.PlusSpringCacheManager;
import org.dromara.common.tenant.helper.TenantHelper;
import org.springframework.cache.Cache;
/**
* 重写 cacheName 处理方法 支持多租户
*
* @author Lion Li
*/
public class TenantSpringCacheManager extends PlusSpringCacheManager {
public TenantSpringCacheManager() {
}
@Override
public Cache getCache(String name) {
if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
return super.getCache(name);
}
String tenantId = TenantHelper.getTenantId();
if (StringUtils.startsWith(name, tenantId)) {
// 如果存在则直接返回
return super.getCache(name);
}
return super.getCache(tenantId + ":" + name);
}
}

View File

@ -1,27 +0,0 @@
package org.dromara.common.tenant.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* 租户 配置属性
*
* @author Lion Li
*/
@Data
@ConfigurationProperties(prefix = "tenant")
public class TenantProperties {
/**
* 是否启用
*/
private Boolean enable;
/**
* 排除表
*/
private List<String> excludes;
}

View File

@ -1,9 +1,9 @@
package org.dromara.demo.domain;
import com.baomidou.mybatisplus.annotation.*;
import org.dromara.common.tenant.core.TenantEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
@ -16,7 +16,7 @@ import java.io.Serial;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("test_demo")
public class TestDemo extends TenantEntity {
public class TestDemo extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;

View File

@ -4,9 +4,9 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.Version;
import org.dromara.common.tenant.core.TenantEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
@ -19,7 +19,7 @@ import java.io.Serial;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("test_tree")
public class TestTree extends TenantEntity {
public class TestTree extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;

View File

@ -1,177 +0,0 @@
package org.dromara.system.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import com.baomidou.lock.annotation.Lock4j;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.encrypt.annotation.ApiEncrypt;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.bo.SysTenantBo;
import org.dromara.system.domain.vo.SysTenantVo;
import org.dromara.system.service.ISysTenantService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 租户管理
*
* @author Michelle.Chung
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/system/tenant")
public class SysTenantController extends BaseController {
private final ISysTenantService tenantService;
/**
* 查询租户列表
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenant:list")
@GetMapping("/list")
public TableDataInfo<SysTenantVo> list(SysTenantBo bo, PageQuery pageQuery) {
return tenantService.queryPageList(bo, pageQuery);
}
/**
* 导出租户列表
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenant:export")
@Log(title = "租户", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(SysTenantBo bo, HttpServletResponse response) {
List<SysTenantVo> list = tenantService.queryList(bo);
ExcelUtil.exportExcel(list, "租户", SysTenantVo.class, response);
}
/**
* 获取租户详细信息
*
* @param id 主键
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenant:query")
@GetMapping("/{id}")
public R<SysTenantVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(tenantService.queryById(id));
}
/**
* 新增租户
*/
@ApiEncrypt
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenant:add")
@Log(title = "租户", businessType = BusinessType.INSERT)
@Lock4j
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody SysTenantBo bo) {
if (!tenantService.checkCompanyNameUnique(bo)) {
return R.fail("新增租户'" + bo.getCompanyName() + "'失败,企业名称已存在");
}
return toAjax(TenantHelper.ignore(() -> tenantService.insertByBo(bo)));
}
/**
* 修改租户
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenant:edit")
@Log(title = "租户", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysTenantBo bo) {
tenantService.checkTenantAllowed(bo.getTenantId());
if (!tenantService.checkCompanyNameUnique(bo)) {
return R.fail("修改租户'" + bo.getCompanyName() + "'失败,公司名称已存在");
}
return toAjax(tenantService.updateByBo(bo));
}
/**
* 状态修改
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenant:edit")
@Log(title = "租户", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public R<Void> changeStatus(@RequestBody SysTenantBo bo) {
tenantService.checkTenantAllowed(bo.getTenantId());
return toAjax(tenantService.updateTenantStatus(bo));
}
/**
* 删除租户
*
* @param ids 主键串
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenant:remove")
@Log(title = "租户", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(tenantService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 动态切换租户
*
* @param tenantId 租户ID
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@GetMapping("/dynamic/{tenantId}")
public R<Void> dynamicTenant(@NotBlank(message = "租户ID不能为空") @PathVariable String tenantId) {
TenantHelper.setDynamic(tenantId);
return R.ok();
}
/**
* 清除动态租户
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@GetMapping("/dynamic/clear")
public R<Void> dynamicClear() {
TenantHelper.clearDynamic();
return R.ok();
}
/**
* 同步租户套餐
*
* @param tenantId 租户id
* @param packageId 套餐id
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenant:edit")
@Log(title = "租户", businessType = BusinessType.UPDATE)
@GetMapping("/syncTenantPackage")
public R<Void> syncTenantPackage(@NotBlank(message = "租户ID不能为空") String tenantId,
@NotNull(message = "套餐ID不能为空") Long packageId) {
return toAjax(TenantHelper.ignore(() -> tenantService.syncTenantPackage(tenantId, packageId)));
}
}

View File

@ -1,134 +0,0 @@
package org.dromara.system.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.bo.SysTenantPackageBo;
import org.dromara.system.domain.vo.SysTenantPackageVo;
import org.dromara.system.service.ISysTenantPackageService;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 租户套餐管理
*
* @author Michelle.Chung
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/system/tenant/package")
public class SysTenantPackageController extends BaseController {
private final ISysTenantPackageService tenantPackageService;
/**
* 查询租户套餐列表
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenantPackage:list")
@GetMapping("/list")
public TableDataInfo<SysTenantPackageVo> list(SysTenantPackageBo bo, PageQuery pageQuery) {
return tenantPackageService.queryPageList(bo, pageQuery);
}
/**
* 查询租户套餐下拉选列表
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenantPackage:list")
@GetMapping("/selectList")
public R<List<SysTenantPackageVo>> selectList() {
return R.ok(tenantPackageService.selectList());
}
/**
* 导出租户套餐列表
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenantPackage:export")
@Log(title = "租户套餐", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(SysTenantPackageBo bo, HttpServletResponse response) {
List<SysTenantPackageVo> list = tenantPackageService.queryList(bo);
ExcelUtil.exportExcel(list, "租户套餐", SysTenantPackageVo.class, response);
}
/**
* 获取租户套餐详细信息
*
* @param packageId 主键
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenantPackage:query")
@GetMapping("/{packageId}")
public R<SysTenantPackageVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long packageId) {
return R.ok(tenantPackageService.queryById(packageId));
}
/**
* 新增租户套餐
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenantPackage:add")
@Log(title = "租户套餐", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody SysTenantPackageBo bo) {
return toAjax(tenantPackageService.insertByBo(bo));
}
/**
* 修改租户套餐
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenantPackage:edit")
@Log(title = "租户套餐", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysTenantPackageBo bo) {
return toAjax(tenantPackageService.updateByBo(bo));
}
/**
* 状态修改
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenantPackage:edit")
@Log(title = "租户套餐", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public R<Void> changeStatus(@RequestBody SysTenantPackageBo bo) {
return toAjax(tenantPackageService.updatePackageStatus(bo));
}
/**
* 删除租户套餐
*
* @param packageIds 主键串
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@SaCheckPermission("system:tenantPackage:remove")
@Log(title = "租户套餐", businessType = BusinessType.DELETE)
@DeleteMapping("/{packageIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] packageIds) {
return toAjax(tenantPackageService.deleteWithValidByIds(List.of(packageIds), true));
}
}

View File

@ -22,7 +22,6 @@ import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.bo.SysDeptBo;
import org.dromara.system.domain.bo.SysPostBo;
@ -30,7 +29,10 @@ import org.dromara.system.domain.bo.SysRoleBo;
import org.dromara.system.domain.bo.SysUserBo;
import org.dromara.system.domain.vo.*;
import org.dromara.system.listener.SysUserImportListener;
import org.dromara.system.service.*;
import org.dromara.system.service.ISysDeptService;
import org.dromara.system.service.ISysPostService;
import org.dromara.system.service.ISysRoleService;
import org.dromara.system.service.ISysUserService;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -54,7 +56,6 @@ public class SysUserController extends BaseController {
private final ISysRoleService roleService;
private final ISysPostService postService;
private final ISysDeptService deptService;
private final ISysTenantService tenantService;
/**
* 获取用户列表
@ -108,10 +109,6 @@ public class SysUserController extends BaseController {
public R<UserInfoVo> getInfo() {
UserInfoVo userInfoVo = new UserInfoVo();
LoginUser loginUser = LoginHelper.getLoginUser();
if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
// 超级管理员 如果重新加载用户信息需清除动态租户
TenantHelper.clearDynamic();
}
SysUserVo user = userService.selectUserById(loginUser.getUserId());
if (ObjectUtil.isNull(user)) {
return R.fail("没有权限访问用户数据!");
@ -163,11 +160,6 @@ public class SysUserController extends BaseController {
} else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
return R.fail("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}
if (TenantHelper.isEnable()) {
if (!tenantService.checkAccountBalance(TenantHelper.getTenantId())) {
return R.fail("当前租户下用户名额不足,请联系管理员");
}
}
user.setPassword(BCrypt.hashpw(user.getPassword()));
return toAjax(userService.insertUser(user));
}

View File

@ -2,9 +2,9 @@ package org.dromara.system.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import org.dromara.common.tenant.core.TenantEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
* 参数配置表 sys_config
@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_config")
public class SysConfig extends TenantEntity {
public class SysConfig extends BaseEntity {
/**
* 参数主键

View File

@ -3,9 +3,9 @@ package org.dromara.system.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import org.dromara.common.tenant.core.TenantEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
@ -18,7 +18,7 @@ import java.io.Serial;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_dept")
public class SysDept extends TenantEntity {
public class SysDept extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;

View File

@ -2,10 +2,10 @@ package org.dromara.system.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.tenant.core.TenantEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
* 字典数据表 sys_dict_data
@ -16,7 +16,7 @@ import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_dict_data")
public class SysDictData extends TenantEntity {
public class SysDictData extends BaseEntity {
/**
* 字典编码

View File

@ -2,9 +2,9 @@ package org.dromara.system.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import org.dromara.common.tenant.core.TenantEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
* 字典类型表 sys_dict_type
@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_dict_type")
public class SysDictType extends TenantEntity {
public class SysDictType extends BaseEntity {
/**
* 字典主键

View File

@ -2,9 +2,9 @@ package org.dromara.system.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import org.dromara.common.tenant.core.TenantEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_notice")
public class SysNotice extends TenantEntity {
public class SysNotice extends BaseEntity {
/**
* 公告ID

View File

@ -2,9 +2,9 @@ package org.dromara.system.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import org.dromara.common.tenant.core.TenantEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
* OSS对象存储对象
@ -14,7 +14,7 @@ import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_oss")
public class SysOss extends TenantEntity {
public class SysOss extends BaseEntity {
/**
* 对象存储主键

View File

@ -2,9 +2,9 @@ package org.dromara.system.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import org.dromara.common.tenant.core.TenantEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
* 岗位表 sys_post
@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_post")
public class SysPost extends TenantEntity {
public class SysPost extends BaseEntity {
/**
* 岗位序号

View File

@ -3,10 +3,10 @@ package org.dromara.system.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import org.dromara.common.tenant.core.TenantEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
* 角色表 sys_role
@ -18,7 +18,7 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@TableName("sys_role")
public class SysRole extends TenantEntity {
public class SysRole extends BaseEntity {
/**
* 角色ID

View File

@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
@ -16,7 +16,7 @@ import java.io.Serial;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_social")
public class SysSocial extends TenantEntity {
public class SysSocial extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;

View File

@ -1,103 +0,0 @@
package org.dromara.system.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.util.Date;
/**
* 租户对象 sys_tenant
*
* @author Michelle.Chung
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_tenant")
public class SysTenant extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(value = "id")
private Long id;
/**
* 租户编号
*/
private String tenantId;
/**
* 联系人
*/
private String contactUserName;
/**
* 联系电话
*/
private String contactPhone;
/**
* 企业名称
*/
private String companyName;
/**
* 统一社会信用代码
*/
private String licenseNumber;
/**
* 地址
*/
private String address;
/**
* 域名
*/
private String domain;
/**
* 企业简介
*/
private String intro;
/**
* 备注
*/
private String remark;
/**
* 租户套餐编号
*/
private Long packageId;
/**
* 过期时间
*/
private Date expireTime;
/**
* 用户数量-1不限制
*/
private Long accountCount;
/**
* 租户状态0正常 1停用
*/
private String status;
/**
* 删除标志0代表存在 2代表删除
*/
@TableLogic
private String delFlag;
}

View File

@ -1,54 +0,0 @@
package org.dromara.system.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
* 租户套餐对象 sys_tenant_package
*
* @author Michelle.Chung
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_tenant_package")
public class SysTenantPackage extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 租户套餐id
*/
@TableId(value = "package_id")
private Long packageId;
/**
* 套餐名称
*/
private String packageName;
/**
* 关联菜单id
*/
private String menuIds;
/**
* 备注
*/
private String remark;
/**
* 菜单树选择项是否关联显示 0父子不互相关联显示 1父子互相关联显示
*/
private Boolean menuCheckStrictly;
/**
* 状态0正常 1停用
*/
private String status;
/**
* 删除标志0代表存在 2代表删除
*/
@TableLogic
private String delFlag;
}

View File

@ -1,11 +1,11 @@
package org.dromara.system.domain;
import com.baomidou.mybatisplus.annotation.*;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.tenant.core.TenantEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.util.Date;
@ -19,7 +19,7 @@ import java.util.Date;
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@TableName("sys_user")
public class SysUser extends TenantEntity {
public class SysUser extends BaseEntity {
/**
* 用户ID

View File

@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.tenant.core.TenantEntity;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.system.domain.SysSocial;
/**
@ -20,7 +20,7 @@ import org.dromara.system.domain.SysSocial;
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = SysSocial.class, reverseConvertGenerate = false)
public class SysSocialBo extends TenantEntity {
public class SysSocialBo extends BaseEntity {
/**
* 主键

View File

@ -1,114 +0,0 @@
package org.dromara.system.domain.bo;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.system.domain.SysTenant;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.Date;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
* 租户业务对象 sys_tenant
*
* @author Michelle.Chung
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = SysTenant.class, reverseConvertGenerate = false)
public class SysTenantBo extends BaseEntity {
/**
* id
*/
@NotNull(message = "id不能为空", groups = { EditGroup.class })
private Long id;
/**
* 租户编号
*/
private String tenantId;
/**
* 联系人
*/
@NotBlank(message = "联系人不能为空", groups = { AddGroup.class, EditGroup.class })
private String contactUserName;
/**
* 联系电话
*/
@NotBlank(message = "联系电话不能为空", groups = { AddGroup.class, EditGroup.class })
private String contactPhone;
/**
* 企业名称
*/
@NotBlank(message = "企业名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String companyName;
/**
* 用户名创建系统用户
*/
@NotBlank(message = "用户名不能为空", groups = { AddGroup.class })
private String username;
/**
* 密码创建系统用户
*/
@NotBlank(message = "密码不能为空", groups = { AddGroup.class })
private String password;
/**
* 统一社会信用代码
*/
private String licenseNumber;
/**
* 地址
*/
private String address;
/**
* 域名
*/
private String domain;
/**
* 企业简介
*/
private String intro;
/**
* 备注
*/
private String remark;
/**
* 租户套餐编号
*/
@NotNull(message = "租户套餐不能为空", groups = { AddGroup.class })
private Long packageId;
/**
* 过期时间
*/
private Date expireTime;
/**
* 用户数量-1不限制
*/
private Long accountCount;
/**
* 租户状态0正常 1停用
*/
private String status;
}

View File

@ -1,59 +0,0 @@
package org.dromara.system.domain.bo;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.system.domain.SysTenantPackage;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMapping;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
* 租户套餐业务对象 sys_tenant_package
*
* @author Michelle.Chung
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = SysTenantPackage.class, reverseConvertGenerate = false)
public class SysTenantPackageBo extends BaseEntity {
/**
* 租户套餐id
*/
@NotNull(message = "租户套餐id不能为空", groups = { EditGroup.class })
private Long packageId;
/**
* 套餐名称
*/
@NotBlank(message = "套餐名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String packageName;
/**
* 关联菜单id
*/
@AutoMapping(target = "menuIds", expression = "java(org.dromara.common.core.utils.StringUtils.join(source.getMenuIds(), \",\"))")
private Long[] menuIds;
/**
* 备注
*/
private String remark;
/**
* 菜单树选择项是否关联显示
*/
private Boolean menuCheckStrictly;
/**
* 状态0正常 1停用
*/
private String status;
}

View File

@ -1,66 +0,0 @@
package org.dromara.system.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.system.domain.SysTenantPackage;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 租户套餐视图对象 sys_tenant_package
*
* @author Michelle.Chung
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = SysTenantPackage.class)
public class SysTenantPackageVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 租户套餐id
*/
@ExcelProperty(value = "租户套餐id")
private Long packageId;
/**
* 套餐名称
*/
@ExcelProperty(value = "套餐名称")
private String packageName;
/**
* 关联菜单id
*/
@ExcelProperty(value = "关联菜单id")
private String menuIds;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 菜单树选择项是否关联显示
*/
@ExcelProperty(value = "菜单树选择项是否关联显示")
private Boolean menuCheckStrictly;
/**
* 状态0正常 1停用
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "0=正常,1=停用")
private String status;
}

View File

@ -1,115 +0,0 @@
package org.dromara.system.domain.vo;
import java.util.Date;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.system.domain.SysTenant;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 租户视图对象 sys_tenant
*
* @author Michelle.Chung
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = SysTenant.class)
public class SysTenantVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* id
*/
@ExcelProperty(value = "id")
private Long id;
/**
* 租户编号
*/
@ExcelProperty(value = "租户编号")
private String tenantId;
/**
* 联系人
*/
@ExcelProperty(value = "联系人")
private String contactUserName;
/**
* 联系电话
*/
@ExcelProperty(value = "联系电话")
private String contactPhone;
/**
* 企业名称
*/
@ExcelProperty(value = "企业名称")
private String companyName;
/**
* 统一社会信用代码
*/
@ExcelProperty(value = "统一社会信用代码")
private String licenseNumber;
/**
* 地址
*/
@ExcelProperty(value = "地址")
private String address;
/**
* 域名
*/
@ExcelProperty(value = "域名")
private String domain;
/**
* 企业简介
*/
@ExcelProperty(value = "企业简介")
private String intro;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 租户套餐编号
*/
@ExcelProperty(value = "租户套餐编号")
private Long packageId;
/**
* 过期时间
*/
@ExcelProperty(value = "过期时间")
private Date expireTime;
/**
* 用户数量-1不限制
*/
@ExcelProperty(value = "用户数量")
private Long accountCount;
/**
* 租户状态0正常 1停用
*/
@ExcelProperty(value = "租户状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "0=正常,1=停用")
private String status;
}

View File

@ -1,14 +0,0 @@
package org.dromara.system.mapper;
import org.dromara.system.domain.SysTenant;
import org.dromara.system.domain.vo.SysTenantVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 租户Mapper接口
*
* @author Michelle.Chung
*/
public interface SysTenantMapper extends BaseMapperPlus<SysTenant, SysTenantVo> {
}

View File

@ -1,14 +0,0 @@
package org.dromara.system.mapper;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.system.domain.SysTenantPackage;
import org.dromara.system.domain.vo.SysTenantPackageVo;
/**
* 租户套餐Mapper接口
*
* @author Michelle.Chung
*/
public interface SysTenantPackageMapper extends BaseMapperPlus<SysTenantPackage, SysTenantPackageVo> {
}

View File

@ -1,57 +0,0 @@
package org.dromara.system.service;
import org.dromara.system.domain.vo.SysTenantPackageVo;
import org.dromara.system.domain.bo.SysTenantPackageBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 租户套餐Service接口
*
* @author Michelle.Chung
*/
public interface ISysTenantPackageService {
/**
* 查询租户套餐
*/
SysTenantPackageVo queryById(Long packageId);
/**
* 查询租户套餐列表
*/
TableDataInfo<SysTenantPackageVo> queryPageList(SysTenantPackageBo bo, PageQuery pageQuery);
/**
* 查询租户套餐已启用列表
*/
List<SysTenantPackageVo> selectList();
/**
* 查询租户套餐列表
*/
List<SysTenantPackageVo> queryList(SysTenantPackageBo bo);
/**
* 新增租户套餐
*/
Boolean insertByBo(SysTenantPackageBo bo);
/**
* 修改租户套餐
*/
Boolean updateByBo(SysTenantPackageBo bo);
/**
* 修改套餐状态
*/
int updatePackageStatus(SysTenantPackageBo bo);
/**
* 校验并批量删除租户套餐信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -1,82 +0,0 @@
package org.dromara.system.service;
import org.dromara.system.domain.vo.SysTenantVo;
import org.dromara.system.domain.bo.SysTenantBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 租户Service接口
*
* @author Michelle.Chung
*/
public interface ISysTenantService {
/**
* 查询租户
*/
SysTenantVo queryById(Long id);
/**
* 基于租户ID查询租户
*/
SysTenantVo queryByTenantId(String tenantId);
/**
* 查询租户列表
*/
TableDataInfo<SysTenantVo> queryPageList(SysTenantBo bo, PageQuery pageQuery);
/**
* 查询租户列表
*/
List<SysTenantVo> queryList(SysTenantBo bo);
/**
* 新增租户
*/
Boolean insertByBo(SysTenantBo bo);
/**
* 修改租户
*/
Boolean updateByBo(SysTenantBo bo);
/**
* 修改租户状态
*/
int updateTenantStatus(SysTenantBo bo);
/**
* 校验租户是否允许操作
*/
void checkTenantAllowed(String tenantId);
/**
* 校验并批量删除租户信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 校验企业名称是否唯一
*/
boolean checkCompanyNameUnique(SysTenantBo bo);
/**
* 校验账号余额
*/
boolean checkAccountBalance(String tenantId);
/**
* 校验有效期
*/
boolean checkExpireTime(String tenantId);
/**
* 同步租户套餐
*/
Boolean syncTenantPackage(String tenantId, Long packageId);
}

View File

@ -6,6 +6,7 @@ import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.CacheNames;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.core.exception.ServiceException;
@ -16,13 +17,11 @@ import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.utils.CacheUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysConfig;
import org.dromara.system.domain.bo.SysConfigBo;
import org.dromara.system.domain.vo.SysConfigVo;
import org.dromara.system.mapper.SysConfigMapper;
import org.dromara.system.service.ISysConfigService;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@ -86,10 +85,9 @@ public class SysConfigServiceImpl implements ISysConfigService, ConfigService {
*/
@Override
public boolean selectRegisterEnabled(String tenantId) {
SysConfig retConfig = TenantHelper.dynamic(tenantId, () -> {
return baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>()
.eq(SysConfig::getConfigKey, "sys.account.registerUser"));
});
SysConfig retConfig = baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>()
.eq(SysConfig::getConfigKey, "sys.account.registerUser")
);
if (ObjectUtil.isNull(retConfig)) {
return false;
}

View File

@ -17,7 +17,6 @@ import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysMenu;
import org.dromara.system.domain.SysRole;
import org.dromara.system.domain.SysRoleMenu;
import org.dromara.system.domain.SysTenantPackage;
import org.dromara.system.domain.bo.SysMenuBo;
import org.dromara.system.domain.vo.MetaVo;
import org.dromara.system.domain.vo.RouterVo;
@ -25,7 +24,6 @@ import org.dromara.system.domain.vo.SysMenuVo;
import org.dromara.system.mapper.SysMenuMapper;
import org.dromara.system.mapper.SysRoleMapper;
import org.dromara.system.mapper.SysRoleMenuMapper;
import org.dromara.system.mapper.SysTenantPackageMapper;
import org.dromara.system.service.ISysMenuService;
import org.springframework.stereotype.Service;
@ -43,7 +41,6 @@ public class SysMenuServiceImpl implements ISysMenuService {
private final SysMenuMapper baseMapper;
private final SysRoleMapper roleMapper;
private final SysRoleMenuMapper roleMenuMapper;
private final SysTenantPackageMapper tenantPackageMapper;
/**
* 根据用户查询系统菜单列表
@ -160,20 +157,12 @@ public class SysMenuServiceImpl implements ISysMenuService {
*/
@Override
public List<Long> selectMenuListByPackageId(Long packageId) {
SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId);
List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
if (CollUtil.isEmpty(menuIds)) {
return List.of();
}
List<Long> parentIds = null;
if (tenantPackage.getMenuCheckStrictly()) {
parentIds = baseMapper.selectObjs(new LambdaQueryWrapper<SysMenu>()
.select(SysMenu::getParentId)
.in(SysMenu::getMenuId, menuIds), x -> {return Convert.toLong(x);});
}
return baseMapper.selectObjs(new LambdaQueryWrapper<SysMenu>()
.in(SysMenu::getMenuId, menuIds)
.notIn(CollUtil.isNotEmpty(parentIds), SysMenu::getMenuId, parentIds), x -> {return Convert.toLong(x);});
return baseMapper.selectObjs(
new LambdaQueryWrapper<>(),
x -> {
return Convert.toLong(x);
}
);
}
/**

View File

@ -4,7 +4,6 @@ import cn.dev33.satoken.stp.StpUtil;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.sensitive.core.SensitiveService;
import org.dromara.common.tenant.helper.TenantHelper;
import org.springframework.stereotype.Service;
/**
@ -38,9 +37,6 @@ public class SysSensitiveServiceImpl implements SensitiveService {
return false;
}
if (TenantHelper.isEnable()) {
return !LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin();
}
return !LoginHelper.isSuperAdmin();
}

View File

@ -1,145 +0,0 @@
package org.dromara.system.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.system.domain.SysTenant;
import org.dromara.system.domain.SysTenantPackage;
import org.dromara.system.domain.bo.SysTenantPackageBo;
import org.dromara.system.domain.vo.SysTenantPackageVo;
import org.dromara.system.mapper.SysTenantMapper;
import org.dromara.system.mapper.SysTenantPackageMapper;
import org.dromara.system.service.ISysTenantPackageService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* 租户套餐Service业务层处理
*
* @author Michelle.Chung
*/
@RequiredArgsConstructor
@Service
public class SysTenantPackageServiceImpl implements ISysTenantPackageService {
private final SysTenantPackageMapper baseMapper;
private final SysTenantMapper tenantMapper;
/**
* 查询租户套餐
*/
@Override
public SysTenantPackageVo queryById(Long packageId){
return baseMapper.selectVoById(packageId);
}
/**
* 查询租户套餐列表
*/
@Override
public TableDataInfo<SysTenantPackageVo> queryPageList(SysTenantPackageBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<SysTenantPackage> lqw = buildQueryWrapper(bo);
Page<SysTenantPackageVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
@Override
public List<SysTenantPackageVo> selectList() {
return baseMapper.selectVoList(new LambdaQueryWrapper<SysTenantPackage>()
.eq(SysTenantPackage::getStatus, TenantConstants.NORMAL));
}
/**
* 查询租户套餐列表
*/
@Override
public List<SysTenantPackageVo> queryList(SysTenantPackageBo bo) {
LambdaQueryWrapper<SysTenantPackage> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<SysTenantPackage> buildQueryWrapper(SysTenantPackageBo bo) {
LambdaQueryWrapper<SysTenantPackage> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getPackageName()), SysTenantPackage::getPackageName, bo.getPackageName());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenantPackage::getStatus, bo.getStatus());
lqw.orderByAsc(SysTenantPackage::getPackageId);
return lqw;
}
/**
* 新增租户套餐
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(SysTenantPackageBo bo) {
SysTenantPackage add = MapstructUtils.convert(bo, SysTenantPackage.class);
// 保存菜单id
List<Long> menuIds = Arrays.asList(bo.getMenuIds());
if (CollUtil.isNotEmpty(menuIds)) {
add.setMenuIds(StringUtils.join(menuIds, ", "));
} else {
add.setMenuIds("");
}
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setPackageId(add.getPackageId());
}
return flag;
}
/**
* 修改租户套餐
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(SysTenantPackageBo bo) {
SysTenantPackage update = MapstructUtils.convert(bo, SysTenantPackage.class);
// 保存菜单id
List<Long> menuIds = Arrays.asList(bo.getMenuIds());
if (CollUtil.isNotEmpty(menuIds)) {
update.setMenuIds(StringUtils.join(menuIds, ", "));
} else {
update.setMenuIds("");
}
return baseMapper.updateById(update) > 0;
}
/**
* 修改套餐状态
*
* @param bo 套餐信息
* @return 结果
*/
@Override
public int updatePackageStatus(SysTenantPackageBo bo) {
SysTenantPackage tenantPackage = MapstructUtils.convert(bo, SysTenantPackage.class);
return baseMapper.updateById(tenantPackage);
}
/**
* 批量删除租户套餐
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
boolean exists = tenantMapper.exists(new LambdaQueryWrapper<SysTenant>().in(SysTenant::getPackageId, ids));
if (exists) {
throw new ServiceException("租户套餐已被使用");
}
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@ -1,372 +0,0 @@
package org.dromara.system.service.impl;
import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.CacheNames;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.system.domain.*;
import org.dromara.system.domain.bo.SysTenantBo;
import org.dromara.system.domain.vo.SysTenantVo;
import org.dromara.system.mapper.*;
import org.dromara.system.service.ISysTenantService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**
* 租户Service业务层处理
*
* @author Michelle.Chung
*/
@RequiredArgsConstructor
@Service
public class SysTenantServiceImpl implements ISysTenantService {
private final SysTenantMapper baseMapper;
private final SysTenantPackageMapper tenantPackageMapper;
private final SysUserMapper userMapper;
private final SysDeptMapper deptMapper;
private final SysRoleMapper roleMapper;
private final SysRoleMenuMapper roleMenuMapper;
private final SysRoleDeptMapper roleDeptMapper;
private final SysUserRoleMapper userRoleMapper;
private final SysDictTypeMapper dictTypeMapper;
private final SysDictDataMapper dictDataMapper;
private final SysConfigMapper configMapper;
/**
* 查询租户
*/
@Override
public SysTenantVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 基于租户ID查询租户
*/
@Cacheable(cacheNames = CacheNames.SYS_TENANT, key = "#tenantId")
@Override
public SysTenantVo queryByTenantId(String tenantId) {
return baseMapper.selectVoOne(new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getTenantId, tenantId));
}
/**
* 查询租户列表
*/
@Override
public TableDataInfo<SysTenantVo> queryPageList(SysTenantBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<SysTenant> lqw = buildQueryWrapper(bo);
Page<SysTenantVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询租户列表
*/
@Override
public List<SysTenantVo> queryList(SysTenantBo bo) {
LambdaQueryWrapper<SysTenant> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<SysTenant> buildQueryWrapper(SysTenantBo bo) {
LambdaQueryWrapper<SysTenant> lqw = Wrappers.lambdaQuery();
lqw.eq(StringUtils.isNotBlank(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId());
lqw.like(StringUtils.isNotBlank(bo.getContactUserName()), SysTenant::getContactUserName, bo.getContactUserName());
lqw.eq(StringUtils.isNotBlank(bo.getContactPhone()), SysTenant::getContactPhone, bo.getContactPhone());
lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), SysTenant::getCompanyName, bo.getCompanyName());
lqw.eq(StringUtils.isNotBlank(bo.getLicenseNumber()), SysTenant::getLicenseNumber, bo.getLicenseNumber());
lqw.eq(StringUtils.isNotBlank(bo.getAddress()), SysTenant::getAddress, bo.getAddress());
lqw.eq(StringUtils.isNotBlank(bo.getIntro()), SysTenant::getIntro, bo.getIntro());
lqw.like(StringUtils.isNotBlank(bo.getDomain()), SysTenant::getDomain, bo.getDomain());
lqw.eq(bo.getPackageId() != null, SysTenant::getPackageId, bo.getPackageId());
lqw.eq(bo.getExpireTime() != null, SysTenant::getExpireTime, bo.getExpireTime());
lqw.eq(bo.getAccountCount() != null, SysTenant::getAccountCount, bo.getAccountCount());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenant::getStatus, bo.getStatus());
lqw.orderByAsc(SysTenant::getId);
return lqw;
}
/**
* 新增租户
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(SysTenantBo bo) {
SysTenant add = MapstructUtils.convert(bo, SysTenant.class);
// 获取所有租户编号
List<String> tenantIds = baseMapper.selectObjs(
new LambdaQueryWrapper<SysTenant>().select(SysTenant::getTenantId), x -> {return Convert.toStr(x);});
String tenantId = generateTenantId(tenantIds);
add.setTenantId(tenantId);
boolean flag = baseMapper.insert(add) > 0;
if (!flag) {
throw new ServiceException("创建租户失败");
}
bo.setId(add.getId());
// 根据套餐创建角色
Long roleId = createTenantRole(tenantId, bo.getPackageId());
// 创建部门: 公司名是部门名称
SysDept dept = new SysDept();
dept.setTenantId(tenantId);
dept.setDeptName(bo.getCompanyName());
dept.setParentId(Constants.TOP_PARENT_ID);
dept.setAncestors(Constants.TOP_PARENT_ID.toString());
deptMapper.insert(dept);
Long deptId = dept.getDeptId();
// 角色和部门关联表
SysRoleDept roleDept = new SysRoleDept();
roleDept.setRoleId(roleId);
roleDept.setDeptId(deptId);
roleDeptMapper.insert(roleDept);
// 创建系统用户
SysUser user = new SysUser();
user.setTenantId(tenantId);
user.setUserName(bo.getUsername());
user.setNickName(bo.getUsername());
user.setPassword(BCrypt.hashpw(bo.getPassword()));
user.setDeptId(deptId);
userMapper.insert(user);
//新增系统用户后默认当前用户为部门的负责人
SysDept sd = new SysDept();
sd.setLeader(user.getUserId());
sd.setDeptId(deptId);
deptMapper.updateById(sd);
// 用户和角色关联表
SysUserRole userRole = new SysUserRole();
userRole.setUserId(user.getUserId());
userRole.setRoleId(roleId);
userRoleMapper.insert(userRole);
String defaultTenantId = TenantConstants.DEFAULT_TENANT_ID;
List<SysDictType> dictTypeList = dictTypeMapper.selectList(
new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getTenantId, defaultTenantId));
List<SysDictData> dictDataList = dictDataMapper.selectList(
new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getTenantId, defaultTenantId));
for (SysDictType dictType : dictTypeList) {
dictType.setDictId(null);
dictType.setTenantId(tenantId);
}
for (SysDictData dictData : dictDataList) {
dictData.setDictCode(null);
dictData.setTenantId(tenantId);
}
dictTypeMapper.insertBatch(dictTypeList);
dictDataMapper.insertBatch(dictDataList);
List<SysConfig> sysConfigList = configMapper.selectList(
new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getTenantId, defaultTenantId));
for (SysConfig config : sysConfigList) {
config.setConfigId(null);
config.setTenantId(tenantId);
}
configMapper.insertBatch(sysConfigList);
return true;
}
/**
* 生成租户id
*
* @param tenantIds 已有租户id列表
* @return 租户id
*/
private String generateTenantId(List<String> tenantIds) {
// 随机生成6位
String numbers = RandomUtil.randomNumbers(6);
// 判断是否存在如果存在则重新生成
if (tenantIds.contains(numbers)) {
generateTenantId(tenantIds);
}
return numbers;
}
/**
* 根据租户菜单创建租户角色
*
* @param tenantId 租户编号
* @param packageId 租户套餐id
* @return 角色id
*/
private Long createTenantRole(String tenantId, Long packageId) {
// 获取租户套餐
SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId);
if (ObjectUtil.isNull(tenantPackage)) {
throw new ServiceException("套餐不存在");
}
// 获取套餐菜单id
List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
// 创建角色
SysRole role = new SysRole();
role.setTenantId(tenantId);
role.setRoleName(TenantConstants.TENANT_ADMIN_ROLE_NAME);
role.setRoleKey(TenantConstants.TENANT_ADMIN_ROLE_KEY);
role.setRoleSort(1);
role.setStatus(TenantConstants.NORMAL);
roleMapper.insert(role);
Long roleId = role.getRoleId();
// 创建角色菜单
List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size());
menuIds.forEach(menuId -> {
SysRoleMenu roleMenu = new SysRoleMenu();
roleMenu.setRoleId(roleId);
roleMenu.setMenuId(menuId);
roleMenus.add(roleMenu);
});
roleMenuMapper.insertBatch(roleMenus);
return roleId;
}
/**
* 修改租户
*/
@CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId")
@Override
public Boolean updateByBo(SysTenantBo bo) {
SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class);
tenant.setTenantId(null);
tenant.setPackageId(null);
return baseMapper.updateById(tenant) > 0;
}
/**
* 修改租户状态
*
* @param bo 租户信息
* @return 结果
*/
@CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId")
@Override
public int updateTenantStatus(SysTenantBo bo) {
SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class);
return baseMapper.updateById(tenant);
}
/**
* 校验租户是否允许操作
*
* @param tenantId 租户ID
*/
@Override
public void checkTenantAllowed(String tenantId) {
if (ObjectUtil.isNotNull(tenantId) && TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
throw new ServiceException("不允许操作管理租户");
}
}
/**
* 批量删除租户
*/
@CacheEvict(cacheNames = CacheNames.SYS_TENANT, allEntries = true)
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 做一些业务上的校验,判断是否需要校验
if (ids.contains(TenantConstants.SUPER_ADMIN_ID)) {
throw new ServiceException("超管租户不能删除");
}
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 校验企业名称是否唯一
*/
@Override
public boolean checkCompanyNameUnique(SysTenantBo bo) {
boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysTenant>()
.eq(SysTenant::getCompanyName, bo.getCompanyName())
.ne(ObjectUtil.isNotNull(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId()));
return !exist;
}
/**
* 校验账号余额
*/
@Override
public boolean checkAccountBalance(String tenantId) {
SysTenantVo tenant = SpringUtils.getAopProxy(this).queryByTenantId(tenantId);
// 如果余额为-1代表不限制
if (tenant.getAccountCount() == -1) {
return true;
}
Long userNumber = userMapper.selectCount(new LambdaQueryWrapper<>());
// 如果余额大于0代表还有可用名额
return tenant.getAccountCount() - userNumber > 0;
}
/**
* 校验有效期
*/
@Override
public boolean checkExpireTime(String tenantId) {
SysTenantVo tenant = SpringUtils.getAopProxy(this).queryByTenantId(tenantId);
// 如果未设置过期时间代表不限制
if (ObjectUtil.isNull(tenant.getExpireTime())) {
return true;
}
// 如果当前时间在过期时间之前则通过
return new Date().before(tenant.getExpireTime());
}
/**
* 同步租户套餐
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean syncTenantPackage(String tenantId, Long packageId) {
SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId);
List<SysRole> roles = roleMapper.selectList(
new LambdaQueryWrapper<SysRole>().eq(SysRole::getTenantId, tenantId));
List<Long> roleIds = new ArrayList<>(roles.size() - 1);
List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
roles.forEach(item -> {
if (TenantConstants.TENANT_ADMIN_ROLE_KEY.equals(item.getRoleKey())) {
List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size());
menuIds.forEach(menuId -> {
SysRoleMenu roleMenu = new SysRoleMenu();
roleMenu.setRoleId(item.getRoleId());
roleMenu.setMenuId(menuId);
roleMenus.add(roleMenu);
});
roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, item.getRoleId()));
roleMenuMapper.insertBatch(roleMenus);
} else {
roleIds.add(item.getRoleId());
}
});
if (!roleIds.isEmpty()) {
roleMenuMapper.delete(
new LambdaQueryWrapper<SysRoleMenu>().in(SysRoleMenu::getRoleId, roleIds).notIn(!menuIds.isEmpty(), SysRoleMenu::getMenuId, menuIds));
}
return true;
}
}

View File

@ -297,7 +297,6 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
user.setCreateBy(user.getUserId());
user.setUpdateBy(user.getUserId());
SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
sysUser.setTenantId(tenantId);
return baseMapper.insert(sysUser) > 0;
}

View File

@ -1,9 +1,7 @@
package org.dromara.web.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthResponse;
@ -15,34 +13,27 @@ import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginBody;
import org.dromara.common.core.domain.model.RegisterBody;
import org.dromara.common.core.domain.model.SocialLoginBody;
import org.dromara.common.core.utils.*;
import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.encrypt.annotation.ApiEncrypt;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
import org.dromara.common.social.config.properties.SocialProperties;
import org.dromara.common.social.utils.SocialUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.websocket.utils.WebSocketUtils;
import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.bo.SysTenantBo;
import org.dromara.system.domain.vo.SysTenantVo;
import org.dromara.system.service.ISysClientService;
import org.dromara.system.service.ISysConfigService;
import org.dromara.system.service.ISysSocialService;
import org.dromara.system.service.ISysTenantService;
import org.dromara.web.domain.vo.LoginTenantVo;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.domain.vo.TenantListVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.dromara.web.service.SysRegisterService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.net.URL;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@ -62,7 +53,6 @@ public class AuthController {
private final SysLoginService loginService;
private final SysRegisterService registerService;
private final ISysConfigService configService;
private final ISysTenantService tenantService;
private final ISysSocialService socialUserService;
private final ISysClientService clientService;
private final ScheduledExecutorService scheduledExecutorService;
@ -90,8 +80,6 @@ public class AuthController {
} else if (!UserConstants.NORMAL.equals(client.getStatus())) {
return R.fail(MessageUtils.message("auth.grant.type.blocked"));
}
// 校验租户
loginService.checkTenant(loginBody.getTenantId());
// 登录
LoginVo loginVo = IAuthStrategy.login(body, client, grantType);
@ -174,33 +162,4 @@ public class AuthController {
registerService.register(user);
return R.ok();
}
/**
* 登录页面租户下拉框
*
* @return 租户列表
*/
@GetMapping("/tenant/list")
public R<LoginTenantVo> tenantList(HttpServletRequest request) throws Exception {
List<SysTenantVo> tenantList = tenantService.queryList(new SysTenantBo());
List<TenantListVo> voList = MapstructUtils.convert(tenantList, TenantListVo.class);
// 获取域名
String host;
String referer = request.getHeader("referer");
if (StringUtils.isNotBlank(referer)) {
// 这里从referer中取值是为了本地使用hosts添加虚拟域名方便本地环境调试
host = referer.split("//")[1].split("/")[0];
} else {
host = new URL(request.getRequestURL().toString()).getHost();
}
// 根据域名进行筛选
List<TenantListVo> list = StreamUtils.filter(voList, vo ->
Objects.equals(vo.getDomain(), host));
// 返回对象
LoginTenantVo vo = new LoginTenantVo();
vo.setVoList(CollUtil.isNotEmpty(list) ? list : voList);
vo.setTenantEnabled(TenantHelper.isEnable());
return R.ok(vo);
}
}

View File

@ -1,25 +0,0 @@
package org.dromara.web.domain.vo;
import lombok.Data;
import java.util.List;
/**
* 登录租户对象
*
* @author Michelle.Chung
*/
@Data
public class LoginTenantVo {
/**
* 租户开关
*/
private Boolean tenantEnabled;
/**
* 租户对象列表
*/
private List<TenantListVo> voList;
}

View File

@ -1,22 +0,0 @@
package org.dromara.web.domain.vo;
import org.dromara.system.domain.vo.SysTenantVo;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
/**
* 租户列表
*
* @author Lion Li
*/
@Data
@AutoMapper(target = SysTenantVo.class)
public class TenantListVo {
private String tenantId;
private String companyName;
private String domain;
}

View File

@ -10,33 +10,29 @@ import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthUser;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.enums.LoginType;
import org.dromara.common.core.enums.TenantStatus;
import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.*;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.log.event.LogininforEvent;
import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.exception.TenantException;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.bo.SysSocialBo;
import org.dromara.system.domain.vo.SysSocialVo;
import org.dromara.system.domain.vo.SysTenantVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.ISysPermissionService;
import org.dromara.system.service.ISysSocialService;
import org.dromara.system.service.ISysTenantService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.function.Supplier;
@ -56,7 +52,6 @@ public class SysLoginService {
@Value("${user.password.lockTime}")
private Integer lockTime;
private final ISysTenantService tenantService;
private final ISysPermissionService permissionService;
private final ISysSocialService sysSocialService;
private final SysUserMapper userMapper;
@ -100,10 +95,6 @@ public class SysLoginService {
if (ObjectUtil.isNull(loginUser)) {
return;
}
if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
// 超级管理员 登出清除动态租户
TenantHelper.clearDynamic();
}
recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
} catch (NotLoginException ignored) {
} finally {
@ -199,34 +190,4 @@ public class SysLoginService {
// 登录成功 清空错误次数
RedisUtils.deleteObject(errorKey);
}
/**
* 校验租户
*
* @param tenantId 租户ID
*/
public void checkTenant(String tenantId) {
if (!TenantHelper.isEnable()) {
return;
}
if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
return;
}
if (StringUtils.isBlank(tenantId)) {
throw new TenantException("tenant.number.not.blank");
}
SysTenantVo tenant = tenantService.queryByTenantId(tenantId);
if (ObjectUtil.isNull(tenant)) {
log.info("登录租户:{} 不存在.", tenantId);
throw new TenantException("tenant.not.exists");
} else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) {
log.info("登录租户:{} 已被停用.", tenantId);
throw new TenantException("tenant.blocked");
} else if (ObjectUtil.isNotNull(tenant.getExpireTime())
&& new Date().after(tenant.getExpireTime())) {
log.info("登录租户:{} 已超过有效期.", tenantId);
throw new TenantException("tenant.expired");
}
}
}

View File

@ -17,7 +17,6 @@ import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.log.event.LogininforEvent;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.web.config.properties.CaptchaProperties;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.bo.SysUserBo;
@ -59,11 +58,9 @@ public class SysRegisterService {
sysUser.setPassword(BCrypt.hashpw(password));
sysUser.setUserType(userType);
boolean exist = TenantHelper.dynamic(tenantId, () -> {
return userMapper.exists(new LambdaQueryWrapper<SysUser>()
.eq(SysUser::getUserName, sysUser.getUserName())
.ne(ObjectUtil.isNotNull(sysUser.getUserId()), SysUser::getUserId, sysUser.getUserId()));
});
boolean exist = userMapper.exists(new LambdaQueryWrapper<SysUser>()
.eq(SysUser::getUserName, sysUser.getUserName())
.ne(ObjectUtil.isNotNull(sysUser.getUserId()), SysUser::getUserId, sysUser.getUserId()));
if (exist) {
throw new UserException("user.register.save.error", username);
}

View File

@ -20,7 +20,6 @@ import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysUserVo;
@ -89,19 +88,17 @@ public class EmailAuthStrategy implements IAuthStrategy {
}
private SysUserVo loadUserByEmail(String tenantId, String email) {
return TenantHelper.dynamic(tenantId, () -> {
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getEmail, SysUser::getStatus)
.eq(SysUser::getEmail, email));
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", email);
throw new UserException("user.not.exists", email);
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", email);
throw new UserException("user.blocked", email);
}
return userMapper.selectUserByEmail(email);
});
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getEmail, SysUser::getStatus)
.eq(SysUser::getEmail, email));
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", email);
throw new UserException("user.not.exists", email);
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", email);
throw new UserException("user.blocked", email);
}
return userMapper.selectUserByEmail(email);
}
}

View File

@ -22,7 +22,6 @@ import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.web.config.properties.CaptchaProperties;
import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.SysUser;
@ -108,19 +107,17 @@ public class PasswordAuthStrategy implements IAuthStrategy {
}
private SysUserVo loadUserByUsername(String tenantId, String username) {
return TenantHelper.dynamic(tenantId, () -> {
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getUserName, SysUser::getStatus)
.eq(SysUser::getUserName, username));
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", username);
throw new UserException("user.not.exists", username);
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", username);
throw new UserException("user.blocked", username);
}
return userMapper.selectUserByUserName(username);
});
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getUserName, SysUser::getStatus)
.eq(SysUser::getUserName, username));
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", username);
throw new UserException("user.not.exists", username);
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", username);
throw new UserException("user.blocked", username);
}
return userMapper.selectUserByUserName(username);
}
}

View File

@ -20,7 +20,6 @@ import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysUserVo;
@ -89,19 +88,17 @@ public class SmsAuthStrategy implements IAuthStrategy {
}
private SysUserVo loadUserByPhonenumber(String tenantId, String phonenumber) {
return TenantHelper.dynamic(tenantId, () -> {
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getPhonenumber, SysUser::getStatus)
.eq(SysUser::getPhonenumber, phonenumber));
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", phonenumber);
throw new UserException("user.not.exists", phonenumber);
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", phonenumber);
throw new UserException("user.blocked", phonenumber);
}
return userMapper.selectUserByPhonenumber(phonenumber);
});
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getPhonenumber, SysUser::getStatus)
.eq(SysUser::getPhonenumber, phonenumber));
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", phonenumber);
throw new UserException("user.not.exists", phonenumber);
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", phonenumber);
throw new UserException("user.blocked", phonenumber);
}
return userMapper.selectUserByPhonenumber(phonenumber);
}
}

View File

@ -22,7 +22,6 @@ import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.social.config.properties.SocialProperties;
import org.dromara.common.social.utils.SocialUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysSocialVo;
@ -113,19 +112,17 @@ public class SocialAuthStrategy implements IAuthStrategy {
}
private SysUserVo loadUser(String tenantId, Long userId) {
return TenantHelper.dynamic(tenantId, () -> {
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getUserName, SysUser::getStatus)
.eq(SysUser::getUserId, userId));
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", "");
throw new UserException("user.not.exists", "");
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", "");
throw new UserException("user.blocked", "");
}
return userMapper.selectUserByUserName(user.getUserName());
});
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getUserName, SysUser::getStatus)
.eq(SysUser::getUserId, userId));
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", "");
throw new UserException("user.not.exists", "");
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", "");
throw new UserException("user.blocked", "");
}
return userMapper.selectUserByUserName(user.getUserName());
}
}