upgrade:多租户

This commit is contained in:
ruying408
2025-04-13 00:08:58 +08:00
parent bf8c6d711e
commit c0ff69011f
11 changed files with 95 additions and 31 deletions

View File

@@ -0,0 +1,16 @@
package com.cool.core.base;
import com.mybatisflex.core.activerecord.Model;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import lombok.Getter;
import lombok.Setter;
import org.dromara.autotable.annotation.Index;
/** 租户ID实体类 */
@Getter
@Setter
public class TenantEntity<T extends Model<T>> extends BaseEntity<T> {
@Index
@ColumnDefine(comment = "租户id")
protected Long tenantId;
}

View File

@@ -1,7 +1,11 @@
package com.cool.core.config;
import com.cool.core.tenant.CoolTenantFactory;
import com.mybatisflex.core.FlexGlobalConfig;
import com.mybatisflex.core.tenant.TenantFactory;
import com.mybatisflex.spring.boot.MyBatisFlexCustomizer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@@ -10,6 +14,14 @@ public class MyBatisFlexConfiguration implements MyBatisFlexCustomizer {
@Override
public void customize(FlexGlobalConfig globalConfig) {
// 我们可以在这里进行一些列的初始化配置
// 指定多租户列的列名
FlexGlobalConfig.getDefaultConfig().setTenantColumn("tenant_id");
}
@Bean
@ConditionalOnProperty(name = "cool.multi-tenant.enable", havingValue = "true")
public TenantFactory tenantFactory(){
return new CoolTenantFactory();
}
}

View File

@@ -36,9 +36,12 @@ public class RequestParamsFilter implements Filter {
HttpServletRequest request = (HttpServletRequest) servletRequest;
JSONObject requestParams = new JSONObject();
String language = request.getHeader("language");
String coolEid = request.getHeader("cool-admin-eid");
Long tenantId = StrUtil.isEmpty(coolEid) ? null : Long.parseLong(coolEid);
if (StrUtil.isNotEmpty(request.getContentType()) && request.getContentType().contains("multipart/form-data")) {
servletRequest.setAttribute("requestParams", requestParams);
servletRequest.setAttribute("cool-language", language);
servletRequest.setAttribute("tenantId", tenantId);
filterChain.doFilter(servletRequest, servletResponse);
} else {
BodyReaderHttpServletRequestWrapper requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
@@ -47,38 +50,40 @@ public class RequestParamsFilter implements Filter {
body)) {
requestParams = JSONUtil.parseObj(body);
}
// 登录状态设置用户id
setUserId(requestParams);
requestParams.set("body", body);
requestParams.putAll(getAllRequestParam(request));
Object jwtObj = request.getAttribute("tokenInfo");
if (jwtObj != null) {
requestParams.set("tokenInfo", ((JWT) jwtObj).getPayload().getClaimsJson());
}
requestWrapper.setAttribute("requestParams", requestParams);
// 登录状态设置用户id
Long currTenantId = setUserId(requestParams);
if (ObjUtil.isNotNull(currTenantId)) {
tenantId = currTenantId;
}
requestWrapper.setAttribute("cool-language", language);
request.setAttribute("tenantId", tenantId);
requestParams.set("body", body);
requestParams.putAll(getAllRequestParam(request));
requestWrapper.setAttribute("requestParams", requestParams);
filterChain.doFilter(requestWrapper, servletResponse);
}
}
private void setUserId(JSONObject requestParams) {
private Long setUserId(JSONObject requestParams) {
UserTypeEnum userTypeEnum = CoolSecurityUtil.getCurrentUserType();
switch (userTypeEnum) {
// 只有登录了,才有用户类型, 不然为 UNKNOWN 状态
case ADMIN -> {
// 管理后台由于之前已经有逻辑再了,怕会影响到,如果自己有传了值不覆盖
Object o = requestParams.get("userId");
if (ObjUtil.isNotEmpty(o)) {
return;
if (ObjUtil.isNull(o)) {
requestParams.set("userId", CoolSecurityUtil.getCurrentUserId());
}
requestParams.set("userId", CoolSecurityUtil.getCurrentUserId());
}
// app端userId 为当前登录的用户id
case APP -> requestParams.set("userId", CoolSecurityUtil.getCurrentUserId());
}
return CoolSecurityUtil.getTenantId(requestParams);
}
/**

View File

@@ -0,0 +1,14 @@
package com.cool.core.tenant;
import com.cool.core.util.TenantUtil;
import com.mybatisflex.core.tenant.TenantFactory;
public class CoolTenantFactory implements TenantFactory {
public Object[] getTenantIds(){
Long tenantId = TenantUtil.getTenantId();
if (tenantId == null) {
return null;
}
return new Object[]{tenantId};
}
}

View File

@@ -42,6 +42,14 @@ public class CoolSecurityUtil {
return tokenInfo;
}
public static Long getTenantId(JSONObject requestParams) {
JSONObject tokenInfo = requestParams.getJSONObject("tokenInfo");
if (tokenInfo != null) {
return tokenInfo.getLong("tenantId");
}
return null;
}
/**
* 后台账号退出登录
*

View File

@@ -3,7 +3,6 @@ package com.cool.core.util;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.PostConstruct;
import java.io.File;
import java.util.List;
import java.util.Map;
@@ -36,22 +35,10 @@ public class I18nUtil {
private static final Map<String, JSONObject> data = new ConcurrentHashMap<>();
@PostConstruct
public void init() {
if (!enable) {
return;
}
private void load(String key, File file) {
try {
// 获取该目录下所有的 .json 文件
List<File> jsonFiles = FileUtil.loopFiles(getPath(), file ->
file.isFile() && file.getName().endsWith(".json")
);
jsonFiles.forEach(file -> {
String parentName = file.getParentFile().getName();
String content = FileUtil.readUtf8String(file);
String key = parentName + "_" + file.getName().replace(".json", "");
data.put(key, JSONUtil.parseObj(content));
});
String content = FileUtil.readUtf8String(file);
data.put(key, JSONUtil.parseObj(content));
} catch (Exception e) {
log.error("读取国际化文件失败", e);
}
@@ -68,6 +55,8 @@ public class I18nUtil {
String key = parentName + "_" + file.getName().replace(".json", "");
if (key.equals(name)) {
flag.set(true);
// 加载
load(key, file);
}
});
return flag.get();

View File

@@ -0,0 +1,14 @@
package com.cool.core.util;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
public class TenantUtil {
public static Long getTenantId() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return null;
}
return (Long) attributes.getAttribute("tenantId", RequestAttributes.SCOPE_REQUEST);
}
}

View File

@@ -1,6 +1,6 @@
package com.cool.modules.base.entity.sys;
import com.cool.core.base.BaseEntity;
import com.cool.core.base.TenantEntity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Table;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
@@ -12,7 +12,7 @@ import org.dromara.autotable.annotation.enums.IndexTypeEnum;
@Getter
@Setter
@Table(value = "base_sys_user", comment = "系统用户表")
public class BaseSysUserEntity extends BaseEntity<BaseSysUserEntity> {
public class BaseSysUserEntity extends TenantEntity<BaseSysUserEntity> {
@Index
@ColumnDefine(comment = "部门ID", type = "bigint")
private Long departmentId;

View File

@@ -122,6 +122,7 @@ public class BaseSysLoginServiceImpl implements BaseSysLoginService {
.set("roleIds", roleIds)
.set("username", baseSysUserEntity.getUsername())
.set("userId", baseSysUserEntity.getId())
.set("tenantId", baseSysUserEntity.getTenantId())
.set("passwordVersion", baseSysUserEntity.getPasswordV());
String token = jwtTokenUtil.generateToken(tokenInfo);
if (StrUtil.isEmpty(refreshToken)) {

View File

@@ -148,6 +148,9 @@ cool:
max-pool-size-multiplier: 3
# 队列容量的倍数
queue-capacity-multiplier: 3
multi-tenant:
# 是否开启多租户,默认关闭
enable: false
# AutoTable配置根据实体类自动生成表
auto-table:
show-banner: false