开发(业务)环境
数据库表名(tianfu_tenant)主要字段如下
`id` bigint(64) UNSIGNED NOT NULL COMMENT '主键',
`tenant_code` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '租户编码',
`is_private_db` tinyint(2) NULL DEFAULT NULL COMMENT '是否启用私有库',
`private_db_addr` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '私有数据库地址,MySQL和MongoDB一致,如果启用私有库且地址是(空、.、127.0.0.1)即表示是云平台的私有库',
`mysql_port` int(255) NULL DEFAULT NULL COMMENT 'mysql私有数据库端口',
`mysql_user` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'mysql私有数据库用户名',
`mysql_password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'mysql私有数据库密码',
`mongo_port` int(255) NULL DEFAULT NULL COMMENT 'mongo私有数据库端口',
`mongo_user` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'mongo私有数据库用户名',
`mongo_password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'mongo私有数据库密码'
业务逻辑:我使用Spring Aop切面拦截,在每个请求进去controller之前判断当前用户是否使用私有库,进行切换数据源操作
核心依赖
//mongo依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
//这个是我用到了Spring读取配置文件的注解,所以需要导一下
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
业务处理核心代码
核心配置文件
#服务器端口
server:
port: 8225
#数据源配置
spring:
#排除DruidDataSourceAutoConfigure,druid自动配置
autoconfigure:
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
datasource:
dynamic:
#设置默认的数据源或者数据源组,默认值即为master
primary: master
datasource:
master:
url: ${tfenergy.datasource.dev.url}
username: ${tfenergy.datasource.dev.username}
password: ${tfenergy.datasource.dev.password}
driver-class-name: ${tfenergy.datasource.dev.driverclassname}
#配置mongodb链接信息,我这里使用uri的方式配置mongo
data:
mongodb:
uri: mongodb://admin:密码@IP:端口/认证库
database: 链接库
#添加Swagger
swagger:
base-packages: ${swagger.base-package}
Mongo抽象类
package org.tfcloud.energy.mongo;
import com.mongodb.MongoClientURI;
import lombok.Data;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
/**
* 抽象类-Mongo
*/
@Data
public abstract class MongoConfig {
private String uri;
/*
* Method that creates MongoDbFactory Common to both of the MongoDb
* connections
*/
public MongoDbFactory mongoDbFactory() throws Exception {
return new SimpleMongoDbFactory(new MongoClientURI(uri));
}
/*
* Factory method to create the MongoTemplate
*/
abstract public MongoTemplate getMongoTemplate() throws Exception;
}
默认Mongo数据源
package org.tfcloud.energy.mongo;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* Mongo 从配置文件当中读取的
*/
@Component
@Configuration
@Data
public class AbstractMongoDbConfig extends MongoConfig {
@Value("${spring.data.mongodb.uri}")
private String uri;
@Value("${spring.data.mongodb.database}")
private String fileDatabase;
/**
* mongo默认数据源组装
* @return
* @throws Exception
*/
@SuppressWarnings("all")
@Primary
@Bean(name = "mongobaolong")
@Override
public MongoTemplate getMongoTemplate() throws Exception {
List<ServerAddress> addressList=new ArrayList<>();
List<MongoCredential> credentials=new LinkedList<>();
String newUrl = uri.replace("mongodb://", "");
String username = StringUtils.substringBefore(newUrl, ":");
String psdUrl = newUrl.replace(username + ":", "");
String password = StringUtils.substringBefore(psdUrl, "@");
String ipUrl = psdUrl.replace(password + "@", "");
String ip = StringUtils.substringBefore(ipUrl, ":");
String portUrl = ipUrl.replace(ip + ":", "");
Integer port = Integer.parseInt(StringUtils.substringBefore(portUrl, "/"));
String source = portUrl.replace(port + "/", "");
MongoCredential mongoCredential=MongoCredential
.createScramSha1Credential(username
,source,password.toCharArray());
credentials.add(mongoCredential);
ServerAddress serverAddress=new ServerAddress(ip,port);
addressList.add(serverAddress);
MongoClient mongoClient=new MongoClient(addressList, credentials);
return new MongoTemplate(new SimpleMongoDbFactory(mongoClient,fileDatabase));
}
}
私有库数据源
package org.tfcloud.energy.mongo;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import lombok.Data;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* 139mongo
*/
@Component
@Data
public class AbstractMongoDbConfigTwo extends MongoConfig{
//用户名
private String username;
//认证库
private String source;
//密码
private String password;
//IP
private String ip;
//端口
private Integer port;
//链接数据库
private String fileDatabase;
/**
* 私有数据源创建
* @return
* @throws Exception
*/
@SuppressWarnings("all")
public MongoTemplate getMongoTemplateTwo(String username,String source,String password,String ip,Integer port,String fileDatabase) throws Exception {
List<ServerAddress> addressList=new ArrayList<>();
List<MongoCredential> credentials=new LinkedList<>();
MongoCredential mongoCredential=MongoCredential
.createScramSha1Credential(username,source,password.toCharArray());
credentials.add(mongoCredential);
ServerAddress serverAddress=new ServerAddress(ip,port);
addressList.add(serverAddress);
MongoClient mongoClient=new MongoClient(addressList, credentials);
return new MongoTemplate(new SimpleMongoDbFactory(mongoClient,fileDatabase));
}
@Override
public MongoTemplate getMongoTemplate() throws Exception {
return null;
}
}
AOP切面
package org.tfcloud.energy.mongo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.entity.Tenant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.tfcloud.energy.mapper.DataSourceMapper;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
@SuppressWarnings("all")
public class MongoAspect implements Ordered {
//认证库
private static final String SROUCE_MONGO="test";
//链接库(该字段可以随用户设置进行动态切换)
private static final String AUTHORIZATION_DATABASE="TF_Iot_Energy";
@Autowired
private AbstractMongoDbConfig abstractMongoDbConfig;
@Autowired
private AbstractMongoDbConfigTwo abstractMongoDbConfigTwo;
@Autowired
private DataSourceMapper dataSourceMapper;
/**
* 我这里 创建的切入点就是我的controller的路径,这里你换成你自己的
*/
@Pointcut("execution(* org.tfcloud.energy.controller..*(..)))")
public void mongoPointcut() {
}
//请求业务之前拦截处理 切换私有库
@Before(value = "mongoPointcut()")
public void before(JoinPoint joinPoint) throws Exception {
//新建 Request域,当然也可以存储session redis等 都OK
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//获得当前租户,我这里是已经封装的工具类,这里你可以换成你的查询语句去数据库查
String tenantCode = SecureUtil.getUser().getTenantCode();
//得到用户对象
Tenant tenant = dataSourceMapper.findDataSourceByTenant(tenantCode);
/**
* 这里以0为启用私有mongo
* String username,String source,String password,String ip,Integer port,String fileDatabase
*/
if (Func.isNotEmpty(tenant.getIsPrivateDb())&&tenant.getIsPrivateDb() == 0){
//在request域中注入私有库所需要的mongo链接信息(mongoTemplate)
MongoTemplate mongoTemplateTwo = abstractMongoDbConfigTwo.getMongoTemplateTwo(tenant.getMongoUser(), SROUCE_MONGO
, tenant.getMongoPassword(), tenant.getPrivateDbAddr(), tenant.getMongoPort(), AUTHORIZATION_DATABASE);
request.setAttribute("mongoDataSource", mongoTemplateTwo);
}else {
//默认mongo数据源
request.setAttribute("mongoDataSource", abstractMongoDbConfig.getMongoTemplate());
}
}
//请求结束之后 执行
@After(value = "mongoPointcut()")
public void after(JoinPoint joinPoint) throws Exception {
//每执行完一次请求 清空request域
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
request.removeAttribute("mongoDataSource");
}
//ordered 返回数值越小 越靠前执行
@Override
public int getOrder() {
return 2;
}
}
打通Mongo测试多数据源接口(供参考)
package org.tfcloud.energy.controller;
import lombok.AllArgsConstructor;
import org.springblade.core.tool.api.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.tfcloud.energy.dto.TFlotEnergy;
import org.tfcloud.energy.mongo.AbstractMongoDbConfig;
import org.tfcloud.energy.mongo.AbstractMongoDbConfigTwo;
import org.tfcloud.energy.mongo.MongoTemplateChildren;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/**
* 打通mongo数据源接口入口
*/
@RestController
@RequestMapping("dd")
@AllArgsConstructor
@SuppressWarnings("all")
public class MongoController {
/**
* 打通mongo动态
* @return
* @throws Exception
*/
@GetMapping(value = "getMongoTestTwo")
public R<TFlotEnergy> demos(HttpServletRequest request)throws Exception {
Query query = new Query();
Criteria criterName = Criteria.where("scheme_name").is("1#染色_冷水表");
Criteria criteria = Criteria.where("_time").is("2019-12-06 13:21:35");
query.addCriteria(criterName);
query.addCriteria(criteria);
MongoTemplate mongoDataSource = (MongoTemplate)request.getAttribute("mongoDataSource");
TFlotEnergy tFlotEnergy = mongoDataSource.findOne(query, TFlotEnergy.class);
return R.data(tFlotEnergy);
}
}
后续会持续更新,优化
联系博主方式
如果有任何问题都可以向我提问
QQ:2509647976 微信: x331191249