1.hint指定强制使用索引

使用Query.withHint方法来指定使用索引

  1. @Test
  2. void testHint(){
  3. //1.设置年龄索引
  4. Index ageIndex = new Index().on("age", Sort.Direction.ASC);
  5. //2.创建索引
  6. String indexName = mongoTemplate.indexOps(Student.class).ensureIndex(ageIndex);
  7. //3.创建查询条件
  8. Query query = new Query(Criteria.where("age").is(1)).withHint(indexName);
  9. //4.指定使用年龄索引查询
  10. List<Student> students = mongoTemplate.find(query, Student.class);
  11. }

image.png

2.事务操作

前置条件

  1. mongo服务器版本>=4.0
  2. mongo服务器必须部署为副本集模式/副本集的分片模式
  3. 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) {

    1. 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. //1.创建对象
    2. Student student = new Student();
    3. student.setId("1");
    4. //2.保存
    5. mongoTemplate.insert(student);
    6. //3.执行异常
    7. int error = 1 / 0;

    } } ```

    验证

  1. 查询集合中并无数据

image.png

  1. 触发保存 ```java import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest class StudentServiceTest {

  1. @Autowired
  2. private StudentService studentService;
  3. @Test
  4. void saveStudent() {
  5. studentService.saveStudent();
  6. }

}

  1. 3. 数据并未存入,事务回滚成功
  2. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/28218714/1659075046697-ac86c57d-994b-4fb8-8149-39c549bc99f3.png#clientId=u0e47fd13-e2a0-4&crop=0&crop=0&crop=1&crop=1&errorMessage=unknown%20error&from=paste&height=54&id=uab41ad1f&margin=%5Bobject%20Object%5D&name=image.png&originHeight=81&originWidth=518&originalType=binary&ratio=1&rotation=0&showTitle=false&size=10684&status=error&style=none&taskId=ufbe86f1b-238a-434e-969e-f76a9d5161e&title=&width=345.3333333333333)<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/28218714/1659075017571-30f0fc4b-28ec-4e1f-9887-17a9bfc489e7.png#clientId=u0e47fd13-e2a0-4&crop=0&crop=0&crop=1&crop=1&errorMessage=unknown%20error&from=paste&height=308&id=u99d4a734&margin=%5Bobject%20Object%5D&name=image.png&originHeight=462&originWidth=1669&originalType=binary&ratio=1&rotation=0&showTitle=false&size=102376&status=error&style=none&taskId=uc0a7da77-6035-4d78-b709-fc32ff07dc3&title=&width=1112.6666666666667)
  3. <a name="tobdW"></a>
  4. ### 多数据源
  5. <a name="TTbL1"></a>
  6. #### 主数据源添加事务管理器
  7. 重点关注两点:
  8. 1. primaryMongoTransactionManager的创建
  9. 2. @Bean("primaryFactory")注解一定不能少!!!少了之后事务管理器直接失效!!!!!具体为啥目前还没测试出来,但是一定不能没有!!!!
  10. ```java
  11. import cn.hutool.core.util.StrUtil;
  12. import com.mongodb.MongoClientSettings;
  13. import com.mongodb.MongoCredential;
  14. import com.mongodb.ReadPreference;
  15. import com.mongodb.ServerAddress;
  16. import com.mongodb.client.MongoClients;
  17. import com.mongodb.connection.ConnectionPoolSettings;
  18. import org.springframework.beans.factory.annotation.Qualifier;
  19. import org.springframework.context.annotation.Bean;
  20. import org.springframework.context.annotation.Configuration;
  21. import org.springframework.context.annotation.Primary;
  22. import org.springframework.data.mongodb.MongoTransactionManager;
  23. import org.springframework.data.mongodb.core.MongoTemplate;
  24. import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
  25. import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
  26. import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
  27. import org.springframework.data.mongodb.core.convert.MongoConverter;
  28. import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
  29. import org.springframework.data.mongodb.gridfs.GridFsTemplate;
  30. import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
  31. import javax.annotation.Resource;
  32. import java.util.ArrayList;
  33. import java.util.List;
  34. import java.util.concurrent.TimeUnit;
  35. /**
  36. * @author: 冯铁城 [17615007230@163.com]
  37. * @date: 2022-07-29 15:44:02
  38. * @describe: mongo主数据源各种配置类
  39. */
  40. @Configuration
  41. @EnableMongoRepositories(basePackages = "com.ftc.mongotest", mongoTemplateRef = "primaryTemplate")
  42. public class PrimaryMongoTemplate {
  43. @Resource
  44. @Qualifier("primaryMongoProperties")
  45. private MongoConfigProperties primaryProperties;
  46. @Primary
  47. @Bean(name = "primaryTemplate")
  48. public MongoTemplate primaryTemplate() {
  49. //1.获取primaryTemplate
  50. SimpleMongoClientDatabaseFactory primaryFactory = getFactory(this.primaryProperties);
  51. MongoTemplate primaryTemplate = new MongoTemplate(primaryFactory);
  52. //2.默认数据源监听处理
  53. String type = "_class";
  54. MongoConverter converter = primaryTemplate.getConverter();
  55. if (converter.getTypeMapper().isTypeKey(type)) {
  56. ((MappingMongoConverter) converter).setTypeMapper(new DefaultMongoTypeMapper(null));
  57. }
  58. //3.返回
  59. return primaryTemplate;
  60. }
  61. @Bean(name = "primaryMongoTransactionManager")
  62. public MongoTransactionManager primaryTransactionManager() {
  63. SimpleMongoClientDatabaseFactory factory = getFactory(this.primaryProperties);
  64. return new MongoTransactionManager(factory);
  65. }
  66. @Primary
  67. @Bean(name = "primaryGridFsTemplate")
  68. public GridFsTemplate primaryGridFsTemplate() {
  69. SimpleMongoClientDatabaseFactory factory = getFactory(this.primaryProperties);
  70. MappingMongoConverter converter = new MappingMongoConverter(factory, new MongoMappingContext());
  71. return new GridFsTemplate(factory, converter);
  72. }
  73. @Primary
  74. @Bean("primaryFactory")
  75. public SimpleMongoClientDatabaseFactory getFactory(MongoConfigProperties properties) {
  76. //1.设置链接地址
  77. List<ServerAddress> hosts = new ArrayList<>();
  78. properties.getAddress().forEach(address -> {
  79. List<String> addressInfos = StrUtil.split(address, StrUtil.COLON);
  80. hosts.add(new ServerAddress(addressInfos.get(0), Integer.parseInt(addressInfos.get(1))));
  81. });
  82. //2.初始化连接池参数
  83. ConnectionPoolSettings poolSetting = ConnectionPoolSettings
  84. .builder()
  85. .maxWaitTime(10000, TimeUnit.MILLISECONDS)
  86. .build();
  87. //3.构造基础链接参数
  88. MongoClientSettings.Builder settingBuilder = MongoClientSettings
  89. .builder()
  90. .applyToConnectionPoolSettings(builder -> builder.applySettings(poolSetting))
  91. .applyToClusterSettings(builder -> builder.hosts(hosts))
  92. .readPreference(ReadPreference.secondaryPreferred());
  93. //4.初始链接参数以及连接池参数
  94. MongoClientSettings settings;
  95. //5.根据用户名是否为空判定是否鉴权
  96. if (StrUtil.isNotBlank(properties.getUsername())) {
  97. //6.添加授权参数
  98. MongoCredential credential = MongoCredential.createScramSha1Credential(
  99. properties.getUsername(), properties.getDatabase(), properties.getPassword().toCharArray()
  100. );
  101. //7.添加链接参数
  102. settings = settingBuilder.credential(credential).build();
  103. } else {
  104. //7.添加链接参数
  105. settings = settingBuilder.build();
  106. }
  107. //8.创建工厂返回
  108. return new SimpleMongoClientDatabaseFactory(MongoClients.create(settings), properties.getDatabase());
  109. }
  110. }

备数据源添加事务管理器

与主数据源关注一致即可

  1. import cn.hutool.core.util.StrUtil;
  2. import com.mongodb.MongoClientSettings;
  3. import com.mongodb.MongoCredential;
  4. import com.mongodb.ReadPreference;
  5. import com.mongodb.ServerAddress;
  6. import com.mongodb.client.MongoClients;
  7. import com.mongodb.connection.ConnectionPoolSettings;
  8. import org.springframework.beans.factory.annotation.Qualifier;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import org.springframework.data.mongodb.MongoTransactionManager;
  12. import org.springframework.data.mongodb.core.MongoTemplate;
  13. import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
  14. import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
  15. import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
  16. import org.springframework.data.mongodb.core.convert.MongoConverter;
  17. import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
  18. import org.springframework.data.mongodb.gridfs.GridFsTemplate;
  19. import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
  20. import javax.annotation.Resource;
  21. import java.util.ArrayList;
  22. import java.util.List;
  23. import java.util.concurrent.TimeUnit;
  24. /**
  25. * @author: 冯铁城 [17615007230@163.com]
  26. * @date: 2022-07-29 15:44:02
  27. * @describe: mongo主数据源各种配置类
  28. */
  29. @Configuration
  30. @EnableMongoRepositories(basePackages = "com.ftc.mongotest", mongoTemplateRef = "secondaryTemplate")
  31. public class SecondaryMongoTemplate {
  32. @Resource
  33. @Qualifier("secondaryMongoProperties")
  34. private MongoConfigProperties secondaryProperties;
  35. @Bean(name = "secondaryTemplate")
  36. public MongoTemplate secondaryTemplate() {
  37. //1.获取secondaryTemplate
  38. SimpleMongoClientDatabaseFactory secondaryFactory = getFactory(this.secondaryProperties);
  39. MongoTemplate secondaryTemplate = new MongoTemplate(secondaryFactory);
  40. //2.默认数据源监听处理
  41. String type = "_class";
  42. MongoConverter converter = secondaryTemplate.getConverter();
  43. if (converter.getTypeMapper().isTypeKey(type)) {
  44. ((MappingMongoConverter) converter).setTypeMapper(new DefaultMongoTypeMapper(null));
  45. }
  46. //3.返回
  47. return secondaryTemplate;
  48. }
  49. @Bean(name = "secondaryMongoTransactionManager")
  50. public MongoTransactionManager secondaryTransactionManager() {
  51. SimpleMongoClientDatabaseFactory factory = getFactory(this.secondaryProperties);
  52. return new MongoTransactionManager(factory);
  53. }
  54. @Bean(name = "secondaryGridFsTemplate")
  55. public GridFsTemplate secondaryGridFsTemplate() {
  56. SimpleMongoClientDatabaseFactory factory = getFactory(this.secondaryProperties);
  57. MappingMongoConverter converter = new MappingMongoConverter(factory, new MongoMappingContext());
  58. return new GridFsTemplate(factory, converter);
  59. }
  60. @Bean("secondaryFactory")
  61. public SimpleMongoClientDatabaseFactory getFactory(MongoConfigProperties properties) {
  62. //1.设置链接地址
  63. List<ServerAddress> hosts = new ArrayList<>();
  64. properties.getAddress().forEach(address -> {
  65. List<String> addressInfos = StrUtil.split(address, StrUtil.COLON);
  66. hosts.add(new ServerAddress(addressInfos.get(0), Integer.parseInt(addressInfos.get(1))));
  67. });
  68. //2.初始化连接池参数
  69. ConnectionPoolSettings poolSetting = ConnectionPoolSettings
  70. .builder()
  71. .maxWaitTime(10000, TimeUnit.MILLISECONDS)
  72. .build();
  73. //3.构造基础链接参数
  74. MongoClientSettings.Builder settingBuilder = MongoClientSettings
  75. .builder()
  76. .applyToConnectionPoolSettings(builder -> builder.applySettings(poolSetting))
  77. .applyToClusterSettings(builder -> builder.hosts(hosts))
  78. .readPreference(ReadPreference.secondaryPreferred());
  79. //4.初始链接参数以及连接池参数
  80. MongoClientSettings settings;
  81. //5.根据用户名是否为空判定是否鉴权
  82. if (StrUtil.isNotBlank(properties.getUsername())) {
  83. //6.添加授权参数
  84. MongoCredential credential = MongoCredential.createScramSha1Credential(
  85. properties.getUsername(), properties.getDatabase(), properties.getPassword().toCharArray()
  86. );
  87. //7.添加链接参数
  88. settings = settingBuilder.credential(credential).build();
  89. } else {
  90. //7.添加链接参数
  91. settings = settingBuilder.build();
  92. }
  93. //8.创建工厂返回
  94. return new SimpleMongoClientDatabaseFactory(MongoClients.create(settings), properties.getDatabase());
  95. }
  96. }

添加全局事务管理器

当一个方法中涉及到两个数据源的写操作,就需要指定事务管理器为全局事务管理器
需要注意的是,ChainedTransactionManager这个类现在过时了,但是我还没找到它的替代方法,所以目前先用它吧。
并且@Bean(name = “transactionManagerConfig”)中的”transactionManagerConfig”一定不能改名字!!!!!!!!

  1. import org.springframework.beans.factory.annotation.Qualifier;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.data.transaction.ChainedTransactionManager;
  5. import org.springframework.transaction.PlatformTransactionManager;
  6. /**
  7. * @author: 冯铁城 [17615007230@163.com]
  8. * @date: 2022-07-29 16:53:06
  9. * @describe:
  10. */
  11. @Configuration
  12. public class GlobalTransactionManager {
  13. @Bean(name = "transactionManagerConfig")
  14. public ChainedTransactionManager transactionManagerConfig(
  15. @Qualifier("primaryMongoTransactionManager") PlatformTransactionManager ptm1,
  16. @Qualifier("secondaryMongoTransactionManager") PlatformTransactionManager ptm2) {
  17. return new ChainedTransactionManager(ptm1, ptm2);
  18. }
  19. }

方法添加对应的事务管理器

用到了那个数据源声明对应数据源的事务管理器,如果用到了多数据源,那就声明全局事务管理器

  1. import com.ftc.mongotest.entity.Student;
  2. import org.springframework.beans.factory.annotation.Qualifier;
  3. import org.springframework.data.mongodb.core.MongoTemplate;
  4. import org.springframework.stereotype.Service;
  5. import org.springframework.transaction.annotation.Transactional;
  6. import javax.annotation.Resource;
  7. /**
  8. * @author: 冯铁城 [17615007230@163.com]
  9. * @date: 2022-07-29 14:15:54
  10. * @describe: Student业务实现类
  11. */
  12. @Service
  13. public class StudentService {
  14. @Resource
  15. @Qualifier(value = "primaryTemplate")
  16. private MongoTemplate primaryTemplate;
  17. @Resource
  18. @Qualifier(value = "secondaryTemplate")
  19. private MongoTemplate secondaryTemplate;
  20. /**
  21. * 主数据源保存
  22. */
  23. @Transactional(rollbackFor = Exception.class, transactionManager = "primaryMongoTransactionManager")
  24. public void savePrimaryStudent() {
  25. //1.创建对象
  26. Student student = new Student();
  27. student.setId(1);
  28. student.setName("主数据源数据");
  29. //2.保存
  30. primaryTemplate.insert(student);
  31. //3.执行异常
  32. int error = 1 / 0;
  33. }
  34. /**
  35. * 备数据源保存
  36. */
  37. @Transactional(rollbackFor = Exception.class, transactionManager = "secondaryMongoTransactionManager")
  38. public void saveSecondaryStudent() {
  39. //1.创建对象
  40. Student student = new Student();
  41. student.setId(1);
  42. student.setName("从数据源数据");
  43. //2.保存
  44. secondaryTemplate.insert(student);
  45. //3.执行异常
  46. int error = 1 / 0;
  47. }
  48. @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManagerConfig")
  49. public void saveStudentPrimaryAndSecondary(){
  50. //1.创建主数据源对象
  51. Student student = new Student();
  52. student.setId(1);
  53. student.setName("主数据源数据");
  54. //2.主数据源保存
  55. primaryTemplate.insert(student);
  56. //3.创建从数据源对象
  57. student = new Student();
  58. student.setId(1);
  59. student.setName("从数据源数据");
  60. //4.从数据源保存
  61. secondaryTemplate.insert(student);
  62. //5.执行异常
  63. int error = 1 / 0;
  64. }
  65. }

验证

  1. 当前两个数据源都没有数据

image.png

  1. 测试主数据源事务

image.png
如图,没有数据存入,事务回滚成功
image.png

  1. 测试被数据源事务

image.png
如图,没有数据存入,事务回滚成功
image.png

  1. 测试混合数据源事务

image.png
如图,没有数据存入,事务回滚成功
image.png

3.正则查询

使用Criteria.where().regex()即可

  1. @Test
  2. void testRegex() {
  3. //1.定义存入集合
  4. List<Student> students = CollUtil.newArrayList();
  5. //2.循环封装数据
  6. for (int i = 0; i < 10; i++) {
  7. Student student = new Student();
  8. student.setId(i);
  9. student.setName("ftc" + i);
  10. students.add(student);
  11. }
  12. //3.存入数据
  13. primaryTemplate.insert(students, Student.class);
  14. //4.正则查询校验
  15. Student result = primaryTemplate.findOne(new Query(Criteria.where("name").regex("1")), Student.class);
  16. Assert.isTrue("ftc1".equals(result.getName()));
  17. //5.正则查询携带首选项校验
  18. result = primaryTemplate.findOne(new Query(Criteria.where("name").regex("FTC2", "i")), Student.class);
  19. Assert.isTrue("ftc2".equals(result.getName()));
  20. }

4.MapReduce

与命令行一致,在javaApi中也需要声明map函数,reduce函数,以及对应的options,包括out,query,limit,sort等

查询年龄大于2的同学中,不同性别的人数

  1. @Test
  2. void mapReduce() {
  3. //1.定义存入集合
  4. List<Student> students = CollUtil.newArrayList();
  5. //2.循环封装数据
  6. for (int i = 0; i < 10; i++) {
  7. Student student = new Student();
  8. student.setId(i);
  9. student.setName("ftc" + i);
  10. student.setSex(i % 2 == 0 ? "男" : "女");
  11. student.setAge(i);
  12. students.add(student);
  13. }
  14. //3.测试数据存入集合
  15. primaryTemplate.insert(students, Student.class);
  16. //4.定义Map以及Reduce方法
  17. String mapFunction = "function() { emit(this.sex,1); }";
  18. String reduceFunction = "function(key, values) { return Array.sum(values)}";
  19. //5.定义mapReduce并获取结果
  20. List<JSONObject> mapReduceResult = primaryTemplate
  21. .mapReduce(JSONObject.class)
  22. .map(mapFunction)
  23. .reduce(reduceFunction)
  24. .inCollection("student")
  25. .matching(new Query(Criteria.where("age").gt(2)))
  26. .all();
  27. //6.校验结果
  28. String result = "[{\"_id\":\"女\",\"value\":4},{\"_id\":\"男\",\"value\":3}]";
  29. Assert.isTrue(result.equals(JSONUtil.toJsonStr(mapReduceResult)));
  30. }

查询年龄大于3且成绩排名前三的同学中,不同性别同学的名字集合

使用Query.limit()未生效,只有使用MapReduceOption.limit()生效,具体原因还未知

  1. @Test
  2. void mapReduce() {
  3. //1.定义存入集合
  4. List<Student> students = CollUtil.newArrayList();
  5. //2.循环封装数据
  6. for (int i = 0; i < 10; i++) {
  7. Student student = new Student();
  8. student.setId(i);
  9. student.setName("ftc" + i);
  10. student.setSex(i % 2 == 0 ? "男" : "女");
  11. student.setAge(i);
  12. student.setGrade((double) (i + 10));
  13. students.add(student);
  14. }
  15. //3.测试数据存入集合
  16. primaryTemplate.insert(students, Student.class);
  17. //4.定义Map以及Reduce方法
  18. String mapFunction = "function() { emit(this.sex,this.name); }";
  19. String reduceFunction = "function(key, values) { return values.join('; ')}";
  20. //5.定义集合过滤条件
  21. Query query = new Query(Criteria.where("age").gt(3))
  22. .with(Sort.by(Sort.Direction.DESC, "grade"));
  23. //6.定义mapReduce并获取结果
  24. List<JSONObject> mapReduceResult = primaryTemplate
  25. .mapReduce(Student.class)
  26. .map(mapFunction)
  27. .reduce(reduceFunction)
  28. .with(MapReduceOptions.options().limit(3))
  29. .as(JSONObject.class)
  30. .matching(query)
  31. .all();
  32. //7.校验结果
  33. String result = "[{\"_id\":\"男\",\"value\":\"ftc8\"},{\"_id\":\"女\",\"value\":\"ftc7; ftc9\"}]";
  34. Assert.isTrue(result.equals(JSONUtil.toJsonStr(mapReduceResult)));
  35. }

5.GridFS

单数据源

操作模板引入

无需进行额外配置,直接引入即可

  1. @Autowired
  2. private GridFsTemplate gridFsTemplate;

put数据

其中metadata可以自定义配置,可以理解为对文件的备注,方便在后续进行查询,非必须步骤

  1. @Test
  2. void testPut() {
  3. //1.获取文件输入流
  4. BufferedInputStream inputStream = FileUtil.getInputStream("C:\\Users\\86176\\Desktop\\OIP-C.jpg");
  5. //2.设置文件备注
  6. HashMap<String, Object> metadata = MapUtil.newHashMap(2);
  7. metadata.put("作者", "ftc");
  8. metadata.put("作用", "学习使用");
  9. //3.存入文件
  10. ObjectId store = gridFsTemplate.store(inputStream, "test.jpg", metadata);
  11. Assert.isTrue(ObjectUtil.isNotNull(store));
  12. }

如图,文件存储成功
image.png

Get数据

其中IOUtil与FileUtil都使用了Hutool来操作

  1. @Test
  2. void testGet() throws IOException {
  3. //1.获取文件
  4. GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("metadata.作用").regex("学")));
  5. //2.获取文件流
  6. GridFsResource resource = gridFsTemplate.getResource(gridFSFile);
  7. //3.文件写入
  8. InputStream inputStream = resource.getInputStream();
  9. byte[] bytes = IoUtil.readBytes(inputStream);
  10. File file = FileUtil.writeBytes(bytes, "C:\\Users\\86176\\Desktop\\copy.jpg");
  11. Assert.isTrue(file.exists());
  12. }

如图,文件获取成功
image.png

List数据

  1. @Test
  2. void testList() {
  3. //1.获取文件
  4. GridFSFindIterable gridFSFiles = gridFsTemplate.find(new Query());
  5. //2.循环遍历
  6. for (GridFSFile gridFSFile : gridFSFiles) {
  7. System.out.println(gridFSFile.getFilename());
  8. }
  9. }

delete数据

  1. @Test
  2. void testDelete() {
  3. //1.删除文件
  4. gridFsTemplate.delete(new Query());
  5. //2.验证
  6. GridFSFindIterable gridFSFiles = gridFsTemplate.find(new Query());
  7. Assert.isTrue(CollUtil.isEmpty(gridFSFiles));
  8. }

文件删除成功
image.png

多数据源

操作模板引入

  1. import cn.hutool.core.util.StrUtil;
  2. import com.mongodb.MongoClientSettings;
  3. import com.mongodb.MongoCredential;
  4. import com.mongodb.ReadPreference;
  5. import com.mongodb.ServerAddress;
  6. import com.mongodb.client.MongoClients;
  7. import com.mongodb.connection.ConnectionPoolSettings;
  8. import org.springframework.beans.factory.annotation.Qualifier;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import org.springframework.context.annotation.Primary;
  12. import org.springframework.data.mongodb.MongoTransactionManager;
  13. import org.springframework.data.mongodb.core.MongoTemplate;
  14. import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
  15. import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
  16. import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
  17. import org.springframework.data.mongodb.core.convert.MongoConverter;
  18. import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
  19. import org.springframework.data.mongodb.gridfs.GridFsTemplate;
  20. import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
  21. import javax.annotation.Resource;
  22. import java.util.ArrayList;
  23. import java.util.List;
  24. import java.util.concurrent.TimeUnit;
  25. /**
  26. * @author: 冯铁城 [17615007230@163.com]
  27. * @date: 2022-07-29 15:44:02
  28. * @describe: mongo主数据源各种配置类
  29. */
  30. @Configuration
  31. @EnableMongoRepositories(basePackages = "com.ftc.mongotest", mongoTemplateRef = "primaryTemplate")
  32. public class PrimaryMongoTemplate {
  33. @Resource
  34. @Qualifier("primaryMongoProperties")
  35. private MongoConfigProperties primaryProperties;
  36. @Primary
  37. @Bean(name = "primaryTemplate")
  38. public MongoTemplate primaryTemplate() {
  39. //1.获取primaryTemplate
  40. SimpleMongoClientDatabaseFactory primaryFactory = getFactory(this.primaryProperties);
  41. MongoTemplate primaryTemplate = new MongoTemplate(primaryFactory);
  42. //2.默认数据源监听处理
  43. String type = "_class";
  44. MongoConverter converter = primaryTemplate.getConverter();
  45. if (converter.getTypeMapper().isTypeKey(type)) {
  46. ((MappingMongoConverter) converter).setTypeMapper(new DefaultMongoTypeMapper(null));
  47. }
  48. //3.返回
  49. return primaryTemplate;
  50. }
  51. @Bean(name = "primaryMongoTransactionManager")
  52. public MongoTransactionManager primaryTransactionManager() {
  53. SimpleMongoClientDatabaseFactory factory = getFactory(this.primaryProperties);
  54. return new MongoTransactionManager(factory);
  55. }
  56. @Primary
  57. @Bean(name = "primaryGridFsTemplate")
  58. public GridFsTemplate primaryGridFsTemplate() {
  59. SimpleMongoClientDatabaseFactory factory = getFactory(this.primaryProperties);
  60. MappingMongoConverter converter = new MappingMongoConverter(factory, new MongoMappingContext());
  61. return new GridFsTemplate(factory, converter);
  62. }
  63. @Primary
  64. @Bean("primaryFactory")
  65. public SimpleMongoClientDatabaseFactory getFactory(MongoConfigProperties properties) {
  66. //1.设置链接地址
  67. List<ServerAddress> hosts = new ArrayList<>();
  68. properties.getAddress().forEach(address -> {
  69. List<String> addressInfos = StrUtil.split(address, StrUtil.COLON);
  70. hosts.add(new ServerAddress(addressInfos.get(0), Integer.parseInt(addressInfos.get(1))));
  71. });
  72. //2.初始化连接池参数
  73. ConnectionPoolSettings poolSetting = ConnectionPoolSettings
  74. .builder()
  75. .maxWaitTime(10000, TimeUnit.MILLISECONDS)
  76. .build();
  77. //3.构造基础链接参数
  78. MongoClientSettings.Builder settingBuilder = MongoClientSettings
  79. .builder()
  80. .applyToConnectionPoolSettings(builder -> builder.applySettings(poolSetting))
  81. .applyToClusterSettings(builder -> builder.hosts(hosts))
  82. .readPreference(ReadPreference.secondaryPreferred());
  83. //4.初始链接参数以及连接池参数
  84. MongoClientSettings settings;
  85. //5.根据用户名是否为空判定是否鉴权
  86. if (StrUtil.isNotBlank(properties.getUsername())) {
  87. //6.添加授权参数
  88. MongoCredential credential = MongoCredential.createScramSha1Credential(
  89. properties.getUsername(), properties.getDatabase(), properties.getPassword().toCharArray()
  90. );
  91. //7.添加链接参数
  92. settings = settingBuilder.credential(credential).build();
  93. } else {
  94. //7.添加链接参数
  95. settings = settingBuilder.build();
  96. }
  97. //8.创建工厂返回
  98. return new SimpleMongoClientDatabaseFactory(MongoClients.create(settings), properties.getDatabase());
  99. }
  100. }
  1. import cn.hutool.core.util.StrUtil;
  2. import com.mongodb.MongoClientSettings;
  3. import com.mongodb.MongoCredential;
  4. import com.mongodb.ReadPreference;
  5. import com.mongodb.ServerAddress;
  6. import com.mongodb.client.MongoClients;
  7. import com.mongodb.connection.ConnectionPoolSettings;
  8. import org.springframework.beans.factory.annotation.Qualifier;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import org.springframework.data.mongodb.MongoTransactionManager;
  12. import org.springframework.data.mongodb.core.MongoTemplate;
  13. import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
  14. import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
  15. import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
  16. import org.springframework.data.mongodb.core.convert.MongoConverter;
  17. import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
  18. import org.springframework.data.mongodb.gridfs.GridFsTemplate;
  19. import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
  20. import javax.annotation.Resource;
  21. import java.util.ArrayList;
  22. import java.util.List;
  23. import java.util.concurrent.TimeUnit;
  24. /**
  25. * @author: 冯铁城 [17615007230@163.com]
  26. * @date: 2022-07-29 15:44:02
  27. * @describe: mongo主数据源各种配置类
  28. */
  29. @Configuration
  30. @EnableMongoRepositories(basePackages = "com.ftc.mongotest", mongoTemplateRef = "secondaryTemplate")
  31. public class SecondaryMongoTemplate {
  32. @Resource
  33. @Qualifier("secondaryMongoProperties")
  34. private MongoConfigProperties secondaryProperties;
  35. @Bean(name = "secondaryTemplate")
  36. public MongoTemplate secondaryTemplate() {
  37. //1.获取secondaryTemplate
  38. SimpleMongoClientDatabaseFactory secondaryFactory = getFactory(this.secondaryProperties);
  39. MongoTemplate secondaryTemplate = new MongoTemplate(secondaryFactory);
  40. //2.默认数据源监听处理
  41. String type = "_class";
  42. MongoConverter converter = secondaryTemplate.getConverter();
  43. if (converter.getTypeMapper().isTypeKey(type)) {
  44. ((MappingMongoConverter) converter).setTypeMapper(new DefaultMongoTypeMapper(null));
  45. }
  46. //3.返回
  47. return secondaryTemplate;
  48. }
  49. @Bean(name = "secondaryMongoTransactionManager")
  50. public MongoTransactionManager secondaryTransactionManager() {
  51. SimpleMongoClientDatabaseFactory factory = getFactory(this.secondaryProperties);
  52. return new MongoTransactionManager(factory);
  53. }
  54. @Bean(name = "secondaryGridFsTemplate")
  55. public GridFsTemplate secondaryGridFsTemplate() {
  56. SimpleMongoClientDatabaseFactory factory = getFactory(this.secondaryProperties);
  57. MappingMongoConverter converter = new MappingMongoConverter(factory, new MongoMappingContext());
  58. return new GridFsTemplate(factory, converter);
  59. }
  60. @Bean("secondaryFactory")
  61. public SimpleMongoClientDatabaseFactory getFactory(MongoConfigProperties properties) {
  62. //1.设置链接地址
  63. List<ServerAddress> hosts = new ArrayList<>();
  64. properties.getAddress().forEach(address -> {
  65. List<String> addressInfos = StrUtil.split(address, StrUtil.COLON);
  66. hosts.add(new ServerAddress(addressInfos.get(0), Integer.parseInt(addressInfos.get(1))));
  67. });
  68. //2.初始化连接池参数
  69. ConnectionPoolSettings poolSetting = ConnectionPoolSettings
  70. .builder()
  71. .maxWaitTime(10000, TimeUnit.MILLISECONDS)
  72. .build();
  73. //3.构造基础链接参数
  74. MongoClientSettings.Builder settingBuilder = MongoClientSettings
  75. .builder()
  76. .applyToConnectionPoolSettings(builder -> builder.applySettings(poolSetting))
  77. .applyToClusterSettings(builder -> builder.hosts(hosts))
  78. .readPreference(ReadPreference.secondaryPreferred());
  79. //4.初始链接参数以及连接池参数
  80. MongoClientSettings settings;
  81. //5.根据用户名是否为空判定是否鉴权
  82. if (StrUtil.isNotBlank(properties.getUsername())) {
  83. //6.添加授权参数
  84. MongoCredential credential = MongoCredential.createScramSha1Credential(
  85. properties.getUsername(), properties.getDatabase(), properties.getPassword().toCharArray()
  86. );
  87. //7.添加链接参数
  88. settings = settingBuilder.credential(credential).build();
  89. } else {
  90. //7.添加链接参数
  91. settings = settingBuilder.build();
  92. }
  93. //8.创建工厂返回
  94. return new SimpleMongoClientDatabaseFactory(MongoClients.create(settings), properties.getDatabase());
  95. }
  96. }

Put数据

  1. @Resource
  2. @Qualifier("primaryGridFsTemplate")
  3. private GridFsTemplate primaryGridFsTemplate;
  4. @Resource
  5. @Qualifier("secondaryGridFsTemplate")
  6. private GridFsTemplate secondaryGridFsTemplate;
  7. @Test
  8. void testPut() {
  9. //1.获取文件输入流
  10. BufferedInputStream inputStream = FileUtil.getInputStream("C:\\Users\\86176\\Desktop\\OIP-C.jpg");
  11. //2.设置文件备注
  12. HashMap<String, Object> metadata = MapUtil.newHashMap(2);
  13. metadata.put("作者", "ftc");
  14. metadata.put("作用", "学习使用");
  15. //3.主数据源存入文件
  16. ObjectId store = primaryGridFsTemplate.store(inputStream, "testPrimary.jpg", metadata);
  17. Assert.isTrue(ObjectUtil.isNotNull(store));
  18. //4.获取文件输入流
  19. inputStream = FileUtil.getInputStream("C:\\Users\\86176\\Desktop\\OIP-C.jpg");
  20. //5.设置文件备注
  21. metadata = MapUtil.newHashMap(2);
  22. metadata.put("作者", "ftc");
  23. metadata.put("作用", "学习使用");
  24. //4.备数据源存入文件
  25. store = secondaryGridFsTemplate.store(inputStream, "testSecondary.jpg", metadata);
  26. Assert.isTrue(ObjectUtil.isNotNull(store));
  27. }

Get数据

  1. void testGet() throws IOException {
  2. //1.主数据源获取文件
  3. GridFSFile gridFSFile = primaryGridFsTemplate.findOne(new Query(Criteria.where("metadata.作用").regex("学")));
  4. //2.主数据源获取文件流
  5. GridFsResource resource = primaryGridFsTemplate.getResource(gridFSFile);
  6. //3.主数据源文件写入
  7. InputStream inputStream = resource.getInputStream();
  8. byte[] bytes = IoUtil.readBytes(inputStream);
  9. File file = FileUtil.writeBytes(bytes, "C:\\Users\\86176\\Desktop\\copyPrimary.jpg");
  10. Assert.isTrue(file.exists());
  11. //4.从数据源获取文件
  12. gridFSFile = secondaryGridFsTemplate.findOne(new Query(Criteria.where("metadata.作用").regex("学")));
  13. //5.从数据源获取文件流
  14. resource = secondaryGridFsTemplate.getResource(gridFSFile);
  15. //6.从数据源文件写入
  16. inputStream = resource.getInputStream();
  17. bytes = IoUtil.readBytes(inputStream);
  18. file = FileUtil.writeBytes(bytes, "C:\\Users\\86176\\Desktop\\copySecondary.jpg");
  19. Assert.isTrue(file.exists());
  20. }

List数据

  1. @Test
  2. void testList() {
  3. //1.主数据源获取文件
  4. GridFSFindIterable gridFSFiles = primaryGridFsTemplate.find(new Query());
  5. //2.循环遍历
  6. for (GridFSFile gridFSFile : gridFSFiles) {
  7. System.out.println(gridFSFile.getFilename());
  8. }
  9. //3.备数据源获取文件
  10. gridFSFiles = secondaryGridFsTemplate.find(new Query());
  11. //4.循环遍历
  12. for (GridFSFile gridFSFile : gridFSFiles) {
  13. System.out.println(gridFSFile.getFilename());
  14. }
  15. }

Delete数据

  1. @Test
  2. void testDelete() {
  3. //1.主数据源删除文件
  4. primaryGridFsTemplate.delete(new Query());
  5. //2.验证
  6. GridFSFindIterable gridFSFiles = primaryGridFsTemplate.find(new Query());
  7. Assert.isTrue(CollUtil.isEmpty(gridFSFiles));
  8. //3.备数据源删除文件
  9. secondaryGridFsTemplate.delete(new Query());
  10. //4.验证
  11. gridFSFiles = secondaryGridFsTemplate.find(new Query());
  12. Assert.isTrue(CollUtil.isEmpty(gridFSFiles));
  13. }