This commit is contained in:
2023-06-09 16:02:04 +08:00
parent ccf453b198
commit 4dcb7c297b
21 changed files with 412 additions and 167 deletions

View File

@ -35,7 +35,7 @@ public class SysTenant extends BaseEntity {
/**
* 数据库模式
*/
public static final String DATABASE_MODE = "2";
public static final String SCHEMA_MODE = "2";
/**
* 数据源模式

View File

@ -0,0 +1,36 @@
package com.qiaoba.module.tenant.entity.param;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
/**
* 租户数据源查询参数
*
* @author ailanyin
* @version 1.0
* @since 2023/6/9 13:18
*/
@Getter
@Setter
@NoArgsConstructor
public class SysTenantDatasourceParam implements Serializable {
private String tenantId;
private String isMaster;
private String isUse;
public SysTenantDatasourceParam(String tenantId) {
this.tenantId = tenantId;
}
public SysTenantDatasourceParam(String tenantId, String isMaster) {
this.tenantId = tenantId;
this.isMaster = isMaster;
}
}

View File

@ -0,0 +1,109 @@
package com.qiaoba.module.tenant.filters;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.qiaoba.common.base.constants.TenantConstant;
import com.qiaoba.common.base.context.BaseContext;
import com.qiaoba.common.base.enums.BaseEnum;
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
import com.qiaoba.common.database.constants.DynamicDatasourceConstant;
import com.qiaoba.common.web.utils.ResponseUtil;
import com.qiaoba.module.tenant.entity.SysTenant;
import com.qiaoba.module.tenant.service.SysTenantService;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.Objects;
/**
* 动态切换不同租户的数据源
*
* @author ailanyin
* @version 1.0
* @since 2023-04-25 22:48:43
*/
@Component
@Order(-10000)
public class DynamicDataSourceFilter extends OncePerRequestFilter {
@Resource
private SysTenantService sysTenantService;
@Resource
private DynamicDataSourceConfig dynamicDataSourceConfig;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String tenantId = request.getHeader(TenantConstant.HEADER_KEY_TENANT);
// 主库或没有tenantId
if (StrUtil.isBlank(tenantId)
|| TenantConstant.DEFAULT_TENANT_ID.equals(tenantId)
|| request.getRequestURI().startsWith("/tenant")) {
dynamicDataSourceConfig.setDefaultSetting();
filterChain.doFilter(request, response);
return;
}
SysTenant sysTenant = sysTenantService.selectById(tenantId);
if (checkTenantIsNotAllow(response, sysTenant)) {
return;
}
before(sysTenant);
filterChain.doFilter(request, response);
after();
}
private void before(SysTenant sysTenant) {
BaseContext.setTenantId(sysTenant.getTenantId());
BaseContext.setSchema(sysTenant.getMode().equals(SysTenant.SCHEMA_MODE));
// 数据源模式-设置第三方数据源
if (sysTenant.getMode().equals(SysTenant.DATASOURCE_MODE)) {
//设置当前租户对应的数据源
BaseContext.setDataSource(DynamicDatasourceConstant.MASTER_PREFIX + sysTenant.getTenantId());
}
// 字段模式/Schema模式-数据源选择默认数据源
else {
BaseContext.setDataSource(DynamicDatasourceConstant.MASTER_PREFIX + TenantConstant.DEFAULT_TENANT_ID);
}
}
private void after() {
BaseContext.clearAllHolder();
}
/**
* 检查租户是否不允许访问
*
* @param sysTenant sysTenant
* @return 是->不允许
*/
private boolean checkTenantIsNotAllow(HttpServletResponse response, SysTenant sysTenant) throws IOException {
if (Objects.isNull(sysTenant)) {
// 未找到租户信息
ResponseUtil.errorAuth(response, 401, "未找到租户信息");
return true;
}
if (sysTenant.getStatus().equals(BaseEnum.ABNORMAL.getCode())) {
// 封禁状态
ResponseUtil.errorAuth(response, 401, "租户已被封禁");
return true;
}
if (DateUtil.compare(sysTenant.getExpireTime(), new Date()) < 0) {
// 已过期
ResponseUtil.errorAuth(response, 401, "租户已过期");
return true;
}
return false;
}
}

View File

@ -48,7 +48,9 @@ public class MysqlDataHandler implements DataHandler {
// 手动提交
conn.setAutoCommit(false);
// 创建表
initTables(conn);
if (needCreateTables) {
initTables(conn);
}
// 处理 sys_config
handleSysConfig(conn, tenantId);
// 处理 sys_post

View File

@ -1,6 +1,7 @@
package com.qiaoba.module.tenant.service;
import com.qiaoba.module.tenant.entity.SysTenantDatasource;
import com.qiaoba.module.tenant.entity.param.SysTenantDatasourceParam;
import java.util.List;
@ -52,4 +53,12 @@ public interface SysTenantDatasourceService {
* @return list
*/
List<SysTenantDatasource> selectList(String tenantId);
/**
* 查询租户数据源
*
* @param param 条件
* @return list
*/
List<SysTenantDatasource> selectList(SysTenantDatasourceParam param);
}

View File

@ -0,0 +1,48 @@
package com.qiaoba.module.tenant.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.qiaoba.common.base.enums.BaseEnum;
import com.qiaoba.common.base.enums.DataBaseEnum;
import com.qiaoba.common.database.entity.DynamicDataSource;
import com.qiaoba.common.database.service.DynamicDatasourceService;
import com.qiaoba.module.tenant.entity.SysTenantDatasource;
import com.qiaoba.module.tenant.entity.param.SysTenantDatasourceParam;
import com.qiaoba.module.tenant.service.SysTenantDatasourceService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* 动态数据源接口
*
* @author ailanyin
* @version 1.0
* @since 2023/6/9 13:16
*/
@Service
@RequiredArgsConstructor
public class DynamicDatasourceServiceImpl implements DynamicDatasourceService {
private final SysTenantDatasourceService sysTenantDatasourceService;
@Override
public List<DynamicDataSource> loadAllTenantDatasource() {
SysTenantDatasourceParam param = new SysTenantDatasourceParam();
param.setIsUse(BaseEnum.YES.getCode());
List<SysTenantDatasource> datasourceList = sysTenantDatasourceService.selectList(param);
return transform(datasourceList);
}
private List<DynamicDataSource> transform(List<SysTenantDatasource> datasourceList) {
List<DynamicDataSource> dynamicDataSourceList = new ArrayList<>();
for (SysTenantDatasource datasource : datasourceList) {
DynamicDataSource dynamicDataSource = BeanUtil.copyProperties(datasource, DynamicDataSource.class);
dynamicDataSource.setDriver(DataBaseEnum.getDriver(datasource.getType()));
dynamicDataSource.setUrl(DataBaseEnum.getUrl(datasource.getType(), datasource.getIp(), datasource.getPort(), datasource.getName()));
dynamicDataSourceList.add(dynamicDataSource);
}
return dynamicDataSourceList;
}
}

View File

@ -1,8 +1,10 @@
package com.qiaoba.module.tenant.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qiaoba.common.base.enums.BaseEnum;
import com.qiaoba.module.tenant.entity.SysTenantDatasource;
import com.qiaoba.module.tenant.entity.param.SysTenantDatasourceParam;
import com.qiaoba.module.tenant.mapper.SysTenantDatasourceMapper;
import com.qiaoba.module.tenant.service.SysTenantDatasourceService;
import lombok.RequiredArgsConstructor;
@ -25,11 +27,7 @@ public class SysTenantDatasourceServiceImpl implements SysTenantDatasourceServic
@Override
public SysTenantDatasource selectMaster(String tenantId) {
QueryWrapper<SysTenantDatasource> wrapper = new QueryWrapper<>();
wrapper.lambda()
.eq(SysTenantDatasource::getTenantId, tenantId)
.eq(SysTenantDatasource::getIsMaster, BaseEnum.YES.getCode());
return sysTenantDatasourceMapper.selectOne(wrapper);
return sysTenantDatasourceMapper.selectOne(paramToWrapper(new SysTenantDatasourceParam(tenantId, BaseEnum.YES.getCode())));
}
@Override
@ -49,9 +47,21 @@ public class SysTenantDatasourceServiceImpl implements SysTenantDatasourceServic
@Override
public List<SysTenantDatasource> selectList(String tenantId) {
return sysTenantDatasourceMapper.selectList(paramToWrapper(new SysTenantDatasourceParam(tenantId)));
}
@Override
public List<SysTenantDatasource> selectList(SysTenantDatasourceParam param) {
return sysTenantDatasourceMapper.selectList(paramToWrapper(param));
}
private QueryWrapper<SysTenantDatasource> paramToWrapper(SysTenantDatasourceParam param) {
QueryWrapper<SysTenantDatasource> wrapper = new QueryWrapper<>();
wrapper.lambda()
.eq(SysTenantDatasource::getTenantId, tenantId);
return sysTenantDatasourceMapper.selectList(wrapper);
.eq(StrUtil.isNotBlank(param.getTenantId()), SysTenantDatasource::getTenantId, param.getTenantId())
.eq(StrUtil.isNotBlank(param.getIsUse()), SysTenantDatasource::getIsUse, param.getIsUse())
.eq(StrUtil.isNotBlank(param.getIsMaster()), SysTenantDatasource::getIsMaster, param.getIsMaster());
return wrapper;
}
}

View File

@ -3,7 +3,7 @@ package com.qiaoba.module.tenant.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qiaoba.auth.utils.SecurityUtil;
import com.qiaoba.common.base.DatasourceService;
import com.qiaoba.common.base.constants.BaseConstant;
import com.qiaoba.common.base.enums.BaseEnum;
import com.qiaoba.common.base.enums.DataBaseEnum;
import com.qiaoba.common.base.exceptions.ServiceException;
@ -38,7 +38,7 @@ import java.util.Objects;
*/
@Service
@RequiredArgsConstructor
public class SysTenantServiceImpl implements SysTenantService, DatasourceService {
public class SysTenantServiceImpl implements SysTenantService {
@Value("${qiaoba.datasource.master.driver}")
private String driver;
@ -143,8 +143,8 @@ public class SysTenantServiceImpl implements SysTenantService, DatasourceService
if (SysTenant.COLUMN_MODE.equals(sysTenant.getMode())) {
return column();
}
if (SysTenant.DATABASE_MODE.equals(sysTenant.getMode())) {
return database(sysTenant.getTenantId());
if (SysTenant.SCHEMA_MODE.equals(sysTenant.getMode())) {
return schema(sysTenant.getTenantId());
}
if (SysTenant.DATASOURCE_MODE.equals(sysTenant.getMode())) {
return datasource(sysTenant.getTenantId());
@ -163,8 +163,8 @@ public class SysTenantServiceImpl implements SysTenantService, DatasourceService
/**
* 处理数据库模式
*/
private Connection database(String tenantId) {
String realUrl = this.url.replaceFirst(baseDatabase, baseDatabase + "-" + tenantId);
private Connection schema(String tenantId) {
String realUrl = this.url.replaceFirst(baseDatabase, baseDatabase + BaseConstant.HYPHEN_JOIN_STR + tenantId);
return JdbcUtil.getConnection(driver, realUrl, username, password);
}
@ -179,13 +179,4 @@ public class SysTenantServiceImpl implements SysTenantService, DatasourceService
return JdbcUtil.getConnection(DataBaseEnum.getDriver(master.getType()), DataBaseEnum.getUrl(master.getType(), master.getIp(), master.getPort(), master.getName()), master.getUsername(), master.getPassword());
}
@Override
public boolean checkTenantInfo(String tenantId) {
SysTenant sysTenant = selectById(tenantId);
if (Objects.isNull(sysTenant)) {
return false;
}
// todo 检查租户有没有过期/禁用
return sysTenant.getStatus().equals(BaseEnum.NORMAL.getCode());
}
}