1.hint指定强制使用索引
使用Query.withHint方法来指定使用索引
@Testvoid testHint(){//1.设置年龄索引Index ageIndex = new Index().on("age", Sort.Direction.ASC);//2.创建索引String indexName = mongoTemplate.indexOps(Student.class).ensureIndex(ageIndex);//3.创建查询条件Query query = new Query(Criteria.where("age").is(1)).withHint(indexName);//4.指定使用年龄索引查询List<Student> students = mongoTemplate.find(query, Student.class);}
2.事务操作
前置条件
- mongo服务器版本>=4.0
- mongo服务器必须部署为副本集模式/副本集的分片模式
- mongo在事务中,只允许从主节点读取数据,不允许从从节点读取数据。因此需要视情况readPreference(读偏好)的配置
单数据源
添加事务处理器
如果提示factory找不到,不用管它。 ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.MongoTransactionManager; import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
/**
- @author: 冯铁城 [17615007230@163.com]
- @date: 2022-07-27 15:49:00
@describe: mongo事务监听器 */ @Configuration public class MongoTransactionConfiguration {
@Bean MongoTransactionManager mongoTransactionManager(SimpleMongoClientDatabaseFactory factory) {
return new MongoTransactionManager(factory);
编写方法并添加事务注解
```java import com.ftc.mongotestv2.entity.Student; import lombok.RequiredArgsConstructor; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional;
/**
- @author:冯铁城 [17615007230@163.com]
- @date:2022-07-27 15:52:12
@describe: */ @Service @RequiredArgsConstructor public class StudentService {
private final MongoTemplate mongoTemplate;
@Transactional(rollbackFor = Exception.class) public void saveStudent() {
//1.创建对象Student student = new Student();student.setId("1");//2.保存mongoTemplate.insert(student);//3.执行异常int error = 1 / 0;
验证
- 查询集合中并无数据

- 触发保存 ```java import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest class StudentServiceTest {
@Autowiredprivate StudentService studentService;@Testvoid saveStudent() {studentService.saveStudent();}
}
3. 数据并未存入,事务回滚成功<br /><a name="tobdW"></a>### 多数据源<a name="TTbL1"></a>#### 主数据源添加事务管理器重点关注两点:1. primaryMongoTransactionManager的创建2. @Bean("primaryFactory")注解一定不能少!!!少了之后事务管理器直接失效!!!!!具体为啥目前还没测试出来,但是一定不能没有!!!!```javaimport cn.hutool.core.util.StrUtil;import com.mongodb.MongoClientSettings;import com.mongodb.MongoCredential;import com.mongodb.ReadPreference;import com.mongodb.ServerAddress;import com.mongodb.client.MongoClients;import com.mongodb.connection.ConnectionPoolSettings;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import org.springframework.data.mongodb.MongoTransactionManager;import org.springframework.data.mongodb.core.MongoTemplate;import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;import org.springframework.data.mongodb.core.convert.MappingMongoConverter;import org.springframework.data.mongodb.core.convert.MongoConverter;import org.springframework.data.mongodb.core.mapping.MongoMappingContext;import org.springframework.data.mongodb.gridfs.GridFsTemplate;import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;import javax.annotation.Resource;import java.util.ArrayList;import java.util.List;import java.util.concurrent.TimeUnit;/*** @author: 冯铁城 [17615007230@163.com]* @date: 2022-07-29 15:44:02* @describe: mongo主数据源各种配置类*/@Configuration@EnableMongoRepositories(basePackages = "com.ftc.mongotest", mongoTemplateRef = "primaryTemplate")public class PrimaryMongoTemplate {@Resource@Qualifier("primaryMongoProperties")private MongoConfigProperties primaryProperties;@Primary@Bean(name = "primaryTemplate")public MongoTemplate primaryTemplate() {//1.获取primaryTemplateSimpleMongoClientDatabaseFactory primaryFactory = getFactory(this.primaryProperties);MongoTemplate primaryTemplate = new MongoTemplate(primaryFactory);//2.默认数据源监听处理String type = "_class";MongoConverter converter = primaryTemplate.getConverter();if (converter.getTypeMapper().isTypeKey(type)) {((MappingMongoConverter) converter).setTypeMapper(new DefaultMongoTypeMapper(null));}//3.返回return primaryTemplate;}@Bean(name = "primaryMongoTransactionManager")public MongoTransactionManager primaryTransactionManager() {SimpleMongoClientDatabaseFactory factory = getFactory(this.primaryProperties);return new MongoTransactionManager(factory);}@Primary@Bean(name = "primaryGridFsTemplate")public GridFsTemplate primaryGridFsTemplate() {SimpleMongoClientDatabaseFactory factory = getFactory(this.primaryProperties);MappingMongoConverter converter = new MappingMongoConverter(factory, new MongoMappingContext());return new GridFsTemplate(factory, converter);}@Primary@Bean("primaryFactory")public SimpleMongoClientDatabaseFactory getFactory(MongoConfigProperties properties) {//1.设置链接地址List<ServerAddress> hosts = new ArrayList<>();properties.getAddress().forEach(address -> {List<String> addressInfos = StrUtil.split(address, StrUtil.COLON);hosts.add(new ServerAddress(addressInfos.get(0), Integer.parseInt(addressInfos.get(1))));});//2.初始化连接池参数ConnectionPoolSettings poolSetting = ConnectionPoolSettings.builder().maxWaitTime(10000, TimeUnit.MILLISECONDS).build();//3.构造基础链接参数MongoClientSettings.Builder settingBuilder = MongoClientSettings.builder().applyToConnectionPoolSettings(builder -> builder.applySettings(poolSetting)).applyToClusterSettings(builder -> builder.hosts(hosts)).readPreference(ReadPreference.secondaryPreferred());//4.初始链接参数以及连接池参数MongoClientSettings settings;//5.根据用户名是否为空判定是否鉴权if (StrUtil.isNotBlank(properties.getUsername())) {//6.添加授权参数MongoCredential credential = MongoCredential.createScramSha1Credential(properties.getUsername(), properties.getDatabase(), properties.getPassword().toCharArray());//7.添加链接参数settings = settingBuilder.credential(credential).build();} else {//7.添加链接参数settings = settingBuilder.build();}//8.创建工厂返回return new SimpleMongoClientDatabaseFactory(MongoClients.create(settings), properties.getDatabase());}}
备数据源添加事务管理器
与主数据源关注一致即可
import cn.hutool.core.util.StrUtil;import com.mongodb.MongoClientSettings;import com.mongodb.MongoCredential;import com.mongodb.ReadPreference;import com.mongodb.ServerAddress;import com.mongodb.client.MongoClients;import com.mongodb.connection.ConnectionPoolSettings;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.mongodb.MongoTransactionManager;import org.springframework.data.mongodb.core.MongoTemplate;import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;import org.springframework.data.mongodb.core.convert.MappingMongoConverter;import org.springframework.data.mongodb.core.convert.MongoConverter;import org.springframework.data.mongodb.core.mapping.MongoMappingContext;import org.springframework.data.mongodb.gridfs.GridFsTemplate;import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;import javax.annotation.Resource;import java.util.ArrayList;import java.util.List;import java.util.concurrent.TimeUnit;/*** @author: 冯铁城 [17615007230@163.com]* @date: 2022-07-29 15:44:02* @describe: mongo主数据源各种配置类*/@Configuration@EnableMongoRepositories(basePackages = "com.ftc.mongotest", mongoTemplateRef = "secondaryTemplate")public class SecondaryMongoTemplate {@Resource@Qualifier("secondaryMongoProperties")private MongoConfigProperties secondaryProperties;@Bean(name = "secondaryTemplate")public MongoTemplate secondaryTemplate() {//1.获取secondaryTemplateSimpleMongoClientDatabaseFactory secondaryFactory = getFactory(this.secondaryProperties);MongoTemplate secondaryTemplate = new MongoTemplate(secondaryFactory);//2.默认数据源监听处理String type = "_class";MongoConverter converter = secondaryTemplate.getConverter();if (converter.getTypeMapper().isTypeKey(type)) {((MappingMongoConverter) converter).setTypeMapper(new DefaultMongoTypeMapper(null));}//3.返回return secondaryTemplate;}@Bean(name = "secondaryMongoTransactionManager")public MongoTransactionManager secondaryTransactionManager() {SimpleMongoClientDatabaseFactory factory = getFactory(this.secondaryProperties);return new MongoTransactionManager(factory);}@Bean(name = "secondaryGridFsTemplate")public GridFsTemplate secondaryGridFsTemplate() {SimpleMongoClientDatabaseFactory factory = getFactory(this.secondaryProperties);MappingMongoConverter converter = new MappingMongoConverter(factory, new MongoMappingContext());return new GridFsTemplate(factory, converter);}@Bean("secondaryFactory")public SimpleMongoClientDatabaseFactory getFactory(MongoConfigProperties properties) {//1.设置链接地址List<ServerAddress> hosts = new ArrayList<>();properties.getAddress().forEach(address -> {List<String> addressInfos = StrUtil.split(address, StrUtil.COLON);hosts.add(new ServerAddress(addressInfos.get(0), Integer.parseInt(addressInfos.get(1))));});//2.初始化连接池参数ConnectionPoolSettings poolSetting = ConnectionPoolSettings.builder().maxWaitTime(10000, TimeUnit.MILLISECONDS).build();//3.构造基础链接参数MongoClientSettings.Builder settingBuilder = MongoClientSettings.builder().applyToConnectionPoolSettings(builder -> builder.applySettings(poolSetting)).applyToClusterSettings(builder -> builder.hosts(hosts)).readPreference(ReadPreference.secondaryPreferred());//4.初始链接参数以及连接池参数MongoClientSettings settings;//5.根据用户名是否为空判定是否鉴权if (StrUtil.isNotBlank(properties.getUsername())) {//6.添加授权参数MongoCredential credential = MongoCredential.createScramSha1Credential(properties.getUsername(), properties.getDatabase(), properties.getPassword().toCharArray());//7.添加链接参数settings = settingBuilder.credential(credential).build();} else {//7.添加链接参数settings = settingBuilder.build();}//8.创建工厂返回return new SimpleMongoClientDatabaseFactory(MongoClients.create(settings), properties.getDatabase());}}
添加全局事务管理器
当一个方法中涉及到两个数据源的写操作,就需要指定事务管理器为全局事务管理器
需要注意的是,ChainedTransactionManager这个类现在过时了,但是我还没找到它的替代方法,所以目前先用它吧。
并且@Bean(name = “transactionManagerConfig”)中的”transactionManagerConfig”一定不能改名字!!!!!!!!
import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.transaction.ChainedTransactionManager;import org.springframework.transaction.PlatformTransactionManager;/*** @author: 冯铁城 [17615007230@163.com]* @date: 2022-07-29 16:53:06* @describe:*/@Configurationpublic class GlobalTransactionManager {@Bean(name = "transactionManagerConfig")public ChainedTransactionManager transactionManagerConfig(@Qualifier("primaryMongoTransactionManager") PlatformTransactionManager ptm1,@Qualifier("secondaryMongoTransactionManager") PlatformTransactionManager ptm2) {return new ChainedTransactionManager(ptm1, ptm2);}}
方法添加对应的事务管理器
用到了那个数据源声明对应数据源的事务管理器,如果用到了多数据源,那就声明全局事务管理器
import com.ftc.mongotest.entity.Student;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.data.mongodb.core.MongoTemplate;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;/*** @author: 冯铁城 [17615007230@163.com]* @date: 2022-07-29 14:15:54* @describe: Student业务实现类*/@Servicepublic class StudentService {@Resource@Qualifier(value = "primaryTemplate")private MongoTemplate primaryTemplate;@Resource@Qualifier(value = "secondaryTemplate")private MongoTemplate secondaryTemplate;/*** 主数据源保存*/@Transactional(rollbackFor = Exception.class, transactionManager = "primaryMongoTransactionManager")public void savePrimaryStudent() {//1.创建对象Student student = new Student();student.setId(1);student.setName("主数据源数据");//2.保存primaryTemplate.insert(student);//3.执行异常int error = 1 / 0;}/*** 备数据源保存*/@Transactional(rollbackFor = Exception.class, transactionManager = "secondaryMongoTransactionManager")public void saveSecondaryStudent() {//1.创建对象Student student = new Student();student.setId(1);student.setName("从数据源数据");//2.保存secondaryTemplate.insert(student);//3.执行异常int error = 1 / 0;}@Transactional(rollbackFor = Exception.class, transactionManager = "transactionManagerConfig")public void saveStudentPrimaryAndSecondary(){//1.创建主数据源对象Student student = new Student();student.setId(1);student.setName("主数据源数据");//2.主数据源保存primaryTemplate.insert(student);//3.创建从数据源对象student = new Student();student.setId(1);student.setName("从数据源数据");//4.从数据源保存secondaryTemplate.insert(student);//5.执行异常int error = 1 / 0;}}
验证
- 当前两个数据源都没有数据

- 测试主数据源事务

如图,没有数据存入,事务回滚成功
- 测试被数据源事务

如图,没有数据存入,事务回滚成功
- 测试混合数据源事务
3.正则查询
使用Criteria.where().regex()即可
@Testvoid testRegex() {//1.定义存入集合List<Student> students = CollUtil.newArrayList();//2.循环封装数据for (int i = 0; i < 10; i++) {Student student = new Student();student.setId(i);student.setName("ftc" + i);students.add(student);}//3.存入数据primaryTemplate.insert(students, Student.class);//4.正则查询校验Student result = primaryTemplate.findOne(new Query(Criteria.where("name").regex("1")), Student.class);Assert.isTrue("ftc1".equals(result.getName()));//5.正则查询携带首选项校验result = primaryTemplate.findOne(new Query(Criteria.where("name").regex("FTC2", "i")), Student.class);Assert.isTrue("ftc2".equals(result.getName()));}
4.MapReduce
与命令行一致,在javaApi中也需要声明map函数,reduce函数,以及对应的options,包括out,query,limit,sort等
查询年龄大于2的同学中,不同性别的人数
@Testvoid mapReduce() {//1.定义存入集合List<Student> students = CollUtil.newArrayList();//2.循环封装数据for (int i = 0; i < 10; i++) {Student student = new Student();student.setId(i);student.setName("ftc" + i);student.setSex(i % 2 == 0 ? "男" : "女");student.setAge(i);students.add(student);}//3.测试数据存入集合primaryTemplate.insert(students, Student.class);//4.定义Map以及Reduce方法String mapFunction = "function() { emit(this.sex,1); }";String reduceFunction = "function(key, values) { return Array.sum(values)}";//5.定义mapReduce并获取结果List<JSONObject> mapReduceResult = primaryTemplate.mapReduce(JSONObject.class).map(mapFunction).reduce(reduceFunction).inCollection("student").matching(new Query(Criteria.where("age").gt(2))).all();//6.校验结果String result = "[{\"_id\":\"女\",\"value\":4},{\"_id\":\"男\",\"value\":3}]";Assert.isTrue(result.equals(JSONUtil.toJsonStr(mapReduceResult)));}
查询年龄大于3且成绩排名前三的同学中,不同性别同学的名字集合
使用Query.limit()未生效,只有使用MapReduceOption.limit()生效,具体原因还未知
@Testvoid mapReduce() {//1.定义存入集合List<Student> students = CollUtil.newArrayList();//2.循环封装数据for (int i = 0; i < 10; i++) {Student student = new Student();student.setId(i);student.setName("ftc" + i);student.setSex(i % 2 == 0 ? "男" : "女");student.setAge(i);student.setGrade((double) (i + 10));students.add(student);}//3.测试数据存入集合primaryTemplate.insert(students, Student.class);//4.定义Map以及Reduce方法String mapFunction = "function() { emit(this.sex,this.name); }";String reduceFunction = "function(key, values) { return values.join('; ')}";//5.定义集合过滤条件Query query = new Query(Criteria.where("age").gt(3)).with(Sort.by(Sort.Direction.DESC, "grade"));//6.定义mapReduce并获取结果List<JSONObject> mapReduceResult = primaryTemplate.mapReduce(Student.class).map(mapFunction).reduce(reduceFunction).with(MapReduceOptions.options().limit(3)).as(JSONObject.class).matching(query).all();//7.校验结果String result = "[{\"_id\":\"男\",\"value\":\"ftc8\"},{\"_id\":\"女\",\"value\":\"ftc7; ftc9\"}]";Assert.isTrue(result.equals(JSONUtil.toJsonStr(mapReduceResult)));}
5.GridFS
单数据源
操作模板引入
无需进行额外配置,直接引入即可
@Autowiredprivate GridFsTemplate gridFsTemplate;
put数据
其中metadata可以自定义配置,可以理解为对文件的备注,方便在后续进行查询,非必须步骤
@Testvoid testPut() {//1.获取文件输入流BufferedInputStream inputStream = FileUtil.getInputStream("C:\\Users\\86176\\Desktop\\OIP-C.jpg");//2.设置文件备注HashMap<String, Object> metadata = MapUtil.newHashMap(2);metadata.put("作者", "ftc");metadata.put("作用", "学习使用");//3.存入文件ObjectId store = gridFsTemplate.store(inputStream, "test.jpg", metadata);Assert.isTrue(ObjectUtil.isNotNull(store));}
Get数据
其中IOUtil与FileUtil都使用了Hutool来操作
@Testvoid testGet() throws IOException {//1.获取文件GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("metadata.作用").regex("学")));//2.获取文件流GridFsResource resource = gridFsTemplate.getResource(gridFSFile);//3.文件写入InputStream inputStream = resource.getInputStream();byte[] bytes = IoUtil.readBytes(inputStream);File file = FileUtil.writeBytes(bytes, "C:\\Users\\86176\\Desktop\\copy.jpg");Assert.isTrue(file.exists());}
List数据
@Testvoid testList() {//1.获取文件GridFSFindIterable gridFSFiles = gridFsTemplate.find(new Query());//2.循环遍历for (GridFSFile gridFSFile : gridFSFiles) {System.out.println(gridFSFile.getFilename());}}
delete数据
@Testvoid testDelete() {//1.删除文件gridFsTemplate.delete(new Query());//2.验证GridFSFindIterable gridFSFiles = gridFsTemplate.find(new Query());Assert.isTrue(CollUtil.isEmpty(gridFSFiles));}
多数据源
操作模板引入
import cn.hutool.core.util.StrUtil;import com.mongodb.MongoClientSettings;import com.mongodb.MongoCredential;import com.mongodb.ReadPreference;import com.mongodb.ServerAddress;import com.mongodb.client.MongoClients;import com.mongodb.connection.ConnectionPoolSettings;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import org.springframework.data.mongodb.MongoTransactionManager;import org.springframework.data.mongodb.core.MongoTemplate;import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;import org.springframework.data.mongodb.core.convert.MappingMongoConverter;import org.springframework.data.mongodb.core.convert.MongoConverter;import org.springframework.data.mongodb.core.mapping.MongoMappingContext;import org.springframework.data.mongodb.gridfs.GridFsTemplate;import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;import javax.annotation.Resource;import java.util.ArrayList;import java.util.List;import java.util.concurrent.TimeUnit;/*** @author: 冯铁城 [17615007230@163.com]* @date: 2022-07-29 15:44:02* @describe: mongo主数据源各种配置类*/@Configuration@EnableMongoRepositories(basePackages = "com.ftc.mongotest", mongoTemplateRef = "primaryTemplate")public class PrimaryMongoTemplate {@Resource@Qualifier("primaryMongoProperties")private MongoConfigProperties primaryProperties;@Primary@Bean(name = "primaryTemplate")public MongoTemplate primaryTemplate() {//1.获取primaryTemplateSimpleMongoClientDatabaseFactory primaryFactory = getFactory(this.primaryProperties);MongoTemplate primaryTemplate = new MongoTemplate(primaryFactory);//2.默认数据源监听处理String type = "_class";MongoConverter converter = primaryTemplate.getConverter();if (converter.getTypeMapper().isTypeKey(type)) {((MappingMongoConverter) converter).setTypeMapper(new DefaultMongoTypeMapper(null));}//3.返回return primaryTemplate;}@Bean(name = "primaryMongoTransactionManager")public MongoTransactionManager primaryTransactionManager() {SimpleMongoClientDatabaseFactory factory = getFactory(this.primaryProperties);return new MongoTransactionManager(factory);}@Primary@Bean(name = "primaryGridFsTemplate")public GridFsTemplate primaryGridFsTemplate() {SimpleMongoClientDatabaseFactory factory = getFactory(this.primaryProperties);MappingMongoConverter converter = new MappingMongoConverter(factory, new MongoMappingContext());return new GridFsTemplate(factory, converter);}@Primary@Bean("primaryFactory")public SimpleMongoClientDatabaseFactory getFactory(MongoConfigProperties properties) {//1.设置链接地址List<ServerAddress> hosts = new ArrayList<>();properties.getAddress().forEach(address -> {List<String> addressInfos = StrUtil.split(address, StrUtil.COLON);hosts.add(new ServerAddress(addressInfos.get(0), Integer.parseInt(addressInfos.get(1))));});//2.初始化连接池参数ConnectionPoolSettings poolSetting = ConnectionPoolSettings.builder().maxWaitTime(10000, TimeUnit.MILLISECONDS).build();//3.构造基础链接参数MongoClientSettings.Builder settingBuilder = MongoClientSettings.builder().applyToConnectionPoolSettings(builder -> builder.applySettings(poolSetting)).applyToClusterSettings(builder -> builder.hosts(hosts)).readPreference(ReadPreference.secondaryPreferred());//4.初始链接参数以及连接池参数MongoClientSettings settings;//5.根据用户名是否为空判定是否鉴权if (StrUtil.isNotBlank(properties.getUsername())) {//6.添加授权参数MongoCredential credential = MongoCredential.createScramSha1Credential(properties.getUsername(), properties.getDatabase(), properties.getPassword().toCharArray());//7.添加链接参数settings = settingBuilder.credential(credential).build();} else {//7.添加链接参数settings = settingBuilder.build();}//8.创建工厂返回return new SimpleMongoClientDatabaseFactory(MongoClients.create(settings), properties.getDatabase());}}
import cn.hutool.core.util.StrUtil;import com.mongodb.MongoClientSettings;import com.mongodb.MongoCredential;import com.mongodb.ReadPreference;import com.mongodb.ServerAddress;import com.mongodb.client.MongoClients;import com.mongodb.connection.ConnectionPoolSettings;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.mongodb.MongoTransactionManager;import org.springframework.data.mongodb.core.MongoTemplate;import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;import org.springframework.data.mongodb.core.convert.MappingMongoConverter;import org.springframework.data.mongodb.core.convert.MongoConverter;import org.springframework.data.mongodb.core.mapping.MongoMappingContext;import org.springframework.data.mongodb.gridfs.GridFsTemplate;import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;import javax.annotation.Resource;import java.util.ArrayList;import java.util.List;import java.util.concurrent.TimeUnit;/*** @author: 冯铁城 [17615007230@163.com]* @date: 2022-07-29 15:44:02* @describe: mongo主数据源各种配置类*/@Configuration@EnableMongoRepositories(basePackages = "com.ftc.mongotest", mongoTemplateRef = "secondaryTemplate")public class SecondaryMongoTemplate {@Resource@Qualifier("secondaryMongoProperties")private MongoConfigProperties secondaryProperties;@Bean(name = "secondaryTemplate")public MongoTemplate secondaryTemplate() {//1.获取secondaryTemplateSimpleMongoClientDatabaseFactory secondaryFactory = getFactory(this.secondaryProperties);MongoTemplate secondaryTemplate = new MongoTemplate(secondaryFactory);//2.默认数据源监听处理String type = "_class";MongoConverter converter = secondaryTemplate.getConverter();if (converter.getTypeMapper().isTypeKey(type)) {((MappingMongoConverter) converter).setTypeMapper(new DefaultMongoTypeMapper(null));}//3.返回return secondaryTemplate;}@Bean(name = "secondaryMongoTransactionManager")public MongoTransactionManager secondaryTransactionManager() {SimpleMongoClientDatabaseFactory factory = getFactory(this.secondaryProperties);return new MongoTransactionManager(factory);}@Bean(name = "secondaryGridFsTemplate")public GridFsTemplate secondaryGridFsTemplate() {SimpleMongoClientDatabaseFactory factory = getFactory(this.secondaryProperties);MappingMongoConverter converter = new MappingMongoConverter(factory, new MongoMappingContext());return new GridFsTemplate(factory, converter);}@Bean("secondaryFactory")public SimpleMongoClientDatabaseFactory getFactory(MongoConfigProperties properties) {//1.设置链接地址List<ServerAddress> hosts = new ArrayList<>();properties.getAddress().forEach(address -> {List<String> addressInfos = StrUtil.split(address, StrUtil.COLON);hosts.add(new ServerAddress(addressInfos.get(0), Integer.parseInt(addressInfos.get(1))));});//2.初始化连接池参数ConnectionPoolSettings poolSetting = ConnectionPoolSettings.builder().maxWaitTime(10000, TimeUnit.MILLISECONDS).build();//3.构造基础链接参数MongoClientSettings.Builder settingBuilder = MongoClientSettings.builder().applyToConnectionPoolSettings(builder -> builder.applySettings(poolSetting)).applyToClusterSettings(builder -> builder.hosts(hosts)).readPreference(ReadPreference.secondaryPreferred());//4.初始链接参数以及连接池参数MongoClientSettings settings;//5.根据用户名是否为空判定是否鉴权if (StrUtil.isNotBlank(properties.getUsername())) {//6.添加授权参数MongoCredential credential = MongoCredential.createScramSha1Credential(properties.getUsername(), properties.getDatabase(), properties.getPassword().toCharArray());//7.添加链接参数settings = settingBuilder.credential(credential).build();} else {//7.添加链接参数settings = settingBuilder.build();}//8.创建工厂返回return new SimpleMongoClientDatabaseFactory(MongoClients.create(settings), properties.getDatabase());}}
Put数据
@Resource@Qualifier("primaryGridFsTemplate")private GridFsTemplate primaryGridFsTemplate;@Resource@Qualifier("secondaryGridFsTemplate")private GridFsTemplate secondaryGridFsTemplate;@Testvoid testPut() {//1.获取文件输入流BufferedInputStream inputStream = FileUtil.getInputStream("C:\\Users\\86176\\Desktop\\OIP-C.jpg");//2.设置文件备注HashMap<String, Object> metadata = MapUtil.newHashMap(2);metadata.put("作者", "ftc");metadata.put("作用", "学习使用");//3.主数据源存入文件ObjectId store = primaryGridFsTemplate.store(inputStream, "testPrimary.jpg", metadata);Assert.isTrue(ObjectUtil.isNotNull(store));//4.获取文件输入流inputStream = FileUtil.getInputStream("C:\\Users\\86176\\Desktop\\OIP-C.jpg");//5.设置文件备注metadata = MapUtil.newHashMap(2);metadata.put("作者", "ftc");metadata.put("作用", "学习使用");//4.备数据源存入文件store = secondaryGridFsTemplate.store(inputStream, "testSecondary.jpg", metadata);Assert.isTrue(ObjectUtil.isNotNull(store));}
Get数据
void testGet() throws IOException {//1.主数据源获取文件GridFSFile gridFSFile = primaryGridFsTemplate.findOne(new Query(Criteria.where("metadata.作用").regex("学")));//2.主数据源获取文件流GridFsResource resource = primaryGridFsTemplate.getResource(gridFSFile);//3.主数据源文件写入InputStream inputStream = resource.getInputStream();byte[] bytes = IoUtil.readBytes(inputStream);File file = FileUtil.writeBytes(bytes, "C:\\Users\\86176\\Desktop\\copyPrimary.jpg");Assert.isTrue(file.exists());//4.从数据源获取文件gridFSFile = secondaryGridFsTemplate.findOne(new Query(Criteria.where("metadata.作用").regex("学")));//5.从数据源获取文件流resource = secondaryGridFsTemplate.getResource(gridFSFile);//6.从数据源文件写入inputStream = resource.getInputStream();bytes = IoUtil.readBytes(inputStream);file = FileUtil.writeBytes(bytes, "C:\\Users\\86176\\Desktop\\copySecondary.jpg");Assert.isTrue(file.exists());}
List数据
@Testvoid testList() {//1.主数据源获取文件GridFSFindIterable gridFSFiles = primaryGridFsTemplate.find(new Query());//2.循环遍历for (GridFSFile gridFSFile : gridFSFiles) {System.out.println(gridFSFile.getFilename());}//3.备数据源获取文件gridFSFiles = secondaryGridFsTemplate.find(new Query());//4.循环遍历for (GridFSFile gridFSFile : gridFSFiles) {System.out.println(gridFSFile.getFilename());}}
Delete数据
@Testvoid testDelete() {//1.主数据源删除文件primaryGridFsTemplate.delete(new Query());//2.验证GridFSFindIterable gridFSFiles = primaryGridFsTemplate.find(new Query());Assert.isTrue(CollUtil.isEmpty(gridFSFiles));//3.备数据源删除文件secondaryGridFsTemplate.delete(new Query());//4.验证gridFSFiles = secondaryGridFsTemplate.find(new Query());Assert.isTrue(CollUtil.isEmpty(gridFSFiles));}

