SpringBoot+Mongodb不同用户动态切换数据源(MongoTemplate)(二)

开发(业务)环境

数据库表名(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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值