SpriingBoot整合MongoDB多数据源

news2025/4/13 15:51:44

背景:

MongoDB多数据源:springboot为3以上版本,spring-boot-starter-data-mongodb低版本MongoDBFactory已过时,
改为MongoDatabaseFactory。

1、pom引入:

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
 </dependency>

在这里插入图片描述
2、结构:

在这里插入图片描述
3、连接配置

spring:
  data:
    mongodb:
      primary:
        uri: mongodb://admin:admin!8@192.168.10.112:27017/kuname?authSource=admin&readPreference=primary&appname=MongoDB Compass Community&ssl=false

4、具体内容

package com.hh.framework.config;

import com.hh.framework.page.MongoPageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoConverter;

/**
 * @Description:mongo监听 新增时消除默认添加的 _class 字段保存实体类类型
 **/
@Configuration
public class ApplicationReadyListener implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    @Qualifier("primaryMongo")
    MongoTemplate primaryMongoTemplate;

    /*@Autowired
    @Qualifier("secondaryMongo")
    MongoTemplate secondaryMongoTemplate;
*/
    private static final String TYPEKEY = "_class";

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        MongoConverter converter = primaryMongoTemplate.getConverter();
        if (converter.getTypeMapper().isTypeKey(TYPEKEY)) {
            ((MappingMongoConverter) converter).setTypeMapper(new DefaultMongoTypeMapper(null));
        }
       /* MongoConverter converter2 = secondaryMongoTemplate.getConverter();
        if (converter2.getTypeMapper().isTypeKey(TYPEKEY)) {
            ((MappingMongoConverter) converter2).setTypeMapper(new DefaultMongoTypeMapper(null));
        }*/
    }

    @Bean
    public MongoPageHelper mongoPageHelper() {
        return new MongoPageHelper(primaryMongoTemplate);
    }

}

package com.hh.framework.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

@Configuration
public class MongoDbConfig {
    @Autowired
    MongoDatabaseFactory mongoDatabaseFactory;
    public @Bean MongoTemplate mongoTemplate() throws Exception {
        //remove _class(insert数据时,mongodb默认生成_class字段)
        MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDatabaseFactory), new MongoMappingContext());
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));
        return new MongoTemplate(mongoDatabaseFactory, converter);
    }

}

package com.hh.framework.config;

import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * @Description:mongo连接配置类
 **/
@Configuration
public class MongoInit {
    @Bean(name = "primaryMongoProperties")
    @Primary
    @ConfigurationProperties(prefix = "spring.data.mongodb.primary")
    public MongoProperties statisMongoProperties() {
        System.out.println("-------------------- primaryMongoProperties init ---------------------");
        return new MongoProperties();
    }

   /* @Bean(name = "secondaryMongoProperties")
    @ConfigurationProperties(prefix = "spring.data.mongodb.secondary")
    public MongoProperties twoMongoProperties() {
        System.out.println("-------------------- secondaryMongoProperties init ---------------------");
        return new MongoProperties();
    }*/

}

package com.hh.framework.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

/**
 * @Description:monngo第一个数据源:primary
 **/
@Slf4j
@Configuration
//jar中含有此类,但此处引入冒红,不影响使用
@EnableMongoRepositories( basePackages = "com.hh.framework.entity.primary",mongoTemplateRef = "primary")
public class PrimaryMongoTemplate {



    @Autowired
    @Qualifier("primaryMongoProperties")
    private MongoProperties primaryMongoProperties;

    @Primary
    @Bean(name = "primaryMongo") //第一个数据源名字oneMongo
    public MongoTemplate primaryMongoTemplate() {

        try {
            log.info("primaryMongoProperties:" + primaryMongoProperties.getUri());
            return new MongoTemplate(mongoDatabaseFactory(primaryMongoProperties));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Bean
    @Primary
    public MongoDatabaseFactory mongoDatabaseFactory(MongoProperties mongoProperties) {
        return new SimpleMongoClientDatabaseFactory(mongoProperties.getUri());
    }

}

package com.hh.framework.config;

/*import com.mongodb.MongoClientURI;*/
/*import org.springframework.data.mongodb.core.SimpleMongoDbFactory;*/
/*
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
*/

/**
 * @Description: mongo第二个数据源:secondary
 **/
/*
@Configuration
@EnableMongoRepositories(
        basePackages = "com.hh.framework.entity.secondary",
        mongoTemplateRef = "secondary")
 */
public class SecondaryMongoTemplate {

/*
    @Autowired
    @Qualifier("secondaryMongoProperties")
    private MongoProperties secondaryMongoProperties;

    @Primary
    @Bean(name = "secondaryMongo") //第二个数据源名字
    public MongoTemplate primaryMongoTemplate() {

        try {
            log.info("secondaryMongoProperties:" + secondaryMongoProperties.getUri());
            return new MongoTemplate(mongoDatabaseFactory(secondaryMongoProperties));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Bean
    @Primary
    public MongoDatabaseFactory mongoDatabaseFactory(MongoProperties mongoProperties) {
        return new SimpleMongoClientDatabaseFactory(mongoProperties.getUri());
    }*/
}


package com.hh.framework.entity.primary;

import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.Date;


@Document(collection = "t_city")
@Data
public class CityEntity {

    private String id;

    private String code;

    private String name;
}

5、以下为工具类:

package com.hh.framework.page;


import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
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.stereotype.Component;

import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * MongoDB分页查询工具类.
 **/
@Component
public class MongoPageHelper {

    public static final int FIRST_PAGE_NUM = 1;
    public static final String ID = "_id";
    private final MongoTemplate mongoTemplate;

    @Autowired
    public MongoPageHelper(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    /**
     * 分页查询,直接返回集合类型的结果.
     *
     * @see MongoPageHelper#pageQuery(Query,
     * Class, Function, Integer, Integer,
     * String)
     */
    public <T> MongoPageResult<T> pageQuery(Query query, Class<T> entityClass, Integer pageSize,
                                       Integer pageNum) {
        return pageQuery(query, entityClass, Function.identity(), pageSize, pageNum, null);
    }

    /**
     * 分页查询,不考虑条件分页,直接使用skip-limit来分页.
     *
     * @see MongoPageHelper#pageQuery(Query,
     * Class, Function, Integer, Integer,
     * String)
     */
    public <T, R> MongoPageResult<R> pageQuery(Query query, Class<T> entityClass, Function<T, R> mapper,
                                          Integer pageSize, Integer pageNum) {
        return pageQuery(query, entityClass, mapper, pageSize, pageNum, null);
    }

    /**
     * 分页查询.
     *
     * @param query Mongo Query对象,构造你自己的查询条件.
     * @param entityClass Mongo collection定义的entity class,用来确定查询哪个集合.
     * @param mapper 映射器,你从db查出来的list的元素类型是entityClass, 如果你想要转换成另一个对象,比如去掉敏感字段等,可以使用mapper来决定如何转换.
     * @param pageSize 分页的大小.
     * @param pageNum 当前页.
     * @param lastId 条件分页参数, 区别于skip-limit,采用find(_id>lastId).limit分页.
     * 如果不跳页,像朋友圈,微博这样下拉刷新的分页需求,需要传递上一页的最后一条记录的ObjectId。 如果是null,则返回pageNum那一页.
     * @param <T> collection定义的class类型.
     * @param <R> 最终返回时,展现给页面时的一条记录的类型。
     * @return PageResult,一个封装page信息的对象.
     */
    public <T, R> MongoPageResult<R> pageQuery(Query query, Class<T> entityClass, Function<T, R> mapper,
                                          Integer pageSize, Integer pageNum, String lastId) {
        //分页逻辑
        long total = mongoTemplate.count(query, entityClass);
        final Integer pages = (int) Math.ceil(total / (double) pageSize);
        if (pageNum <= 0 || pageNum > pages) {
            pageNum = FIRST_PAGE_NUM;
        }
        final Criteria criteria = new Criteria();
        if (StringUtils.isNotBlank(lastId)) {
            if (pageNum != FIRST_PAGE_NUM) {
                criteria.and(ID).gt(new ObjectId(lastId));
            }
            query.limit(pageSize);
        } else {
            int skip = pageSize * (pageNum - 1);
            query.skip(skip).limit(pageSize);
        }

        final List<T> entityList = mongoTemplate
                .find(query.addCriteria(criteria)
                                .with(Sort.by(Lists.newArrayList(new Order(Direction.ASC, ID)))),
                        entityClass);

        final MongoPageResult<R> pageResult = new MongoPageResult<>();
        pageResult.setTotal(total);
        pageResult.setPages(pages);
        pageResult.setPageSize(pageSize);
        pageResult.setPageNum(pageNum);
        pageResult.setList(entityList.stream().map(mapper).collect(Collectors.toList()));
        return pageResult;
    }

}


package com.hh.framework.page;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * 分页结果.
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(Include.NON_NULL)
public class MongoPageResult<T> {

    @Schema(description = "页码,从1开始")
    private Integer pageNum;

    @Schema(description = "页面大小")
    private Integer pageSize;

    @Schema(description = "总数")
    private Long total;

    @Schema(description = "总页数")
    private Integer pages;

    @Schema(description = "数据")
    private List<T> list;

}


package com.hh.framework.page;


import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * 分页结果.
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(Include.NON_NULL)
public class MongoPageResult<T> {

    @Schema(description = "页码,从1开始")
    private Integer pageNum;

    @Schema(description = "页面大小")
    private Integer pageSize;

    @Schema(description = "总数")
    private Long total;

    @Schema(description = "总页数")
    private Integer pages;

    @Schema(description = "数据")
    private List<T> list;

}

6、业务模块使用:service层


    @Autowired
    @Qualifier("primaryMongo")
    private MongoTemplate primaryMongoTemplate;


    @Override
    public List getList() {

        Criteria criteria = Criteria.where("id").in().and("code").gte("").lte("");
        Query query = Query.query(criteria).with(Sort.by(Sort.Direction.DESC,"code"));
        return primaryMongoTemplate.find(query, CityEntity.class);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1575706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端入门(认识HTML,CSS,JavaScript三件套)

目录 前言 HTML&#xff08;构建&#xff09; CSS&#xff08;设计&#xff09; JavaScript&#xff08;互动&#xff09; 总结 相关书籍推荐 前言 前端&#xff08;Frontend&#xff09;指的是与用户直接交互的部分&#xff0c;也称为客户端。在网站或者应用程序中&…

奥威BI零售方案,一套解决80%通用需求的数据分析方案

这意味着什么&#xff0c;意味着只需要点击应用奥威BI零售数据分析方案&#xff0c;就可以解决80%的通用分析需求&#xff0c;日常经营决策所需的分析指标再也不用花费大量时间去整理计算&#xff0c;事关运营决策的人、货、场分析都能立即获取&#xff0c;立即掌握数据情况。 …

Hive3.0.0建库表命令测试

Hive创建表格格式如下&#xff1a; create [external] table [if not exists] table_name [(col_name data_type [comment col_comment],)] [comment table_comment] [partitioned by(col_name data_type [comment col_comment],)] [clustered by (col_name,col_name,...)…

1、java语法入门(找工作版)

文章目录 一、Java简介二、Java常量与变量1、标识符2、关键字3、变量4、类的命名规则5、数据类型6、基本数据类型字面值7、变量的定义与初始化8、ASCII码和Unicode编码9、转义字符10、类型转换11、常量 三、Java运算符1、算术运算符2、赋值运算符3、关系运算符4、逻辑运算符5、…

Flutter应用发布前的关键iOS设备测试策略

大家好&#xff0c;我是咕噜铁蛋&#xff01;今天我想和大家分享一下关于Flutter应用在发布前&#xff0c;如何进行关键iOS设备测试的策略。随着移动应用的普及&#xff0c;Flutter作为一种跨平台的开发框架&#xff0c;越来越受到开发者的青睐。但是&#xff0c;跨平台也意味着…

文件上传【1】

1.文件上传更改上传类型 上传文件时存在上传类型固定&#xff08;jpg、png、gif&#xff09;如果是前端确定&#xff08;弹窗&#xff0c;后端未出现请求确定是前端&#xff09;只需要在设置中禁用js代码或抓包更改文件后缀名就可以上传其他类型的文件&#xff08;亦可用于复制…

element-ui-树状表格

需求&#xff1a; 要做出如下图所示的 树形表格&#xff0c;也就是数据之间有父子类关系的这种&#xff0c;可以点击展开、收缩 原数据示例 [{"id": 1,"name": "组织架构","description": "组织架构","type": …

C#/.NET/.NET Core推荐学习书籍(24年4月更新,已分类)

前言 古人云&#xff1a;“书中自有黄金屋&#xff0c;书中自有颜如玉”&#xff0c;说明了书籍的重要性。作为程序员&#xff0c;我们需要不断学习以提升自己的核心竞争力。以下是一些优秀的C#/.NET/.NET Core相关学习书籍&#xff08;包含了C#、.NET、.NET Core、Linq、EF/E…

【QT+QGIS跨平台编译】076:【libdxfrw跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、libdxfrw介绍二、QGIS下载三、文件分析四、pro文件五、编译实践一、libdxfrw介绍 libdxfrw是一个用于读取和写入DXF(Drawing Exchange Format)文件的开源C++库。DXF是一种由AutoCAD开发的文件格式,用于存储CAD(计算机辅助设计)图形数据,它…

机器学习和深度学习

一、定义 机器学习是一种人工智能领域的分支&#xff0c;旨在使计算机系统能够自动从数据中学习和提高性能&#xff0c;而不需要明确的编程。简而言之&#xff0c;机器学习是利用经验来训练计算机系统&#xff0c;使其能够从输入数据中提取规律&#xff0c;并对新数据进行预测…

stm32 IIC协议

该文章为大家介绍了 IIC协议 的基础知识。 文章目录 前言一、IIC 概念二、IIC 信号三、IIC 数据传输格式3.1 写操作3.2 读操作 四、UART/IIC总线区别总结 前言 一、IIC 概念 IIC协议是由数据线SDA和时钟SCL构成的串行总线&#xff0c;可发送和接收数据,是一个多主机的半双工通…

服务器主机安全受到危害的严重性

为了让小伙伴们了解到服务器主机安全受到危害的严重性&#xff0c;以下详细说明一下&#xff1a;1. 数据泄露&#xff1a;如果服务器主机遭受攻击&#xff0c;攻击者可能会窃取敏感数据&#xff0c;如用户数据、商业秘密、机密文件等&#xff0c;导致数据泄露和商业机密的泄漏。…

C++的List类(一):List类的基本概念

目录 前言 List类的基本概念 List的构造函数 List类迭代器的使用 List的功能 List的元素访问 List与vector比较 前言 vector的insert和erase都会导致迭代器失效list的insert不会导致迭代器失效&#xff0c;erase会导致迭代器失效 insert导致失效的原因是开辟了新空间后…

Collection与数据结构 Stack与Queue(二):队列与Queue

1. 队列 1.1 概念 只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出FIFO(First In First Out) 入队列&#xff1a;进行插入操作的一端称为队尾&#xff08;Tail/Rear&#xff09; 出队列&#xff1a;进行删除操作…

css实现扫码循环扫描特效

摘要&#xff1a; 需求中需要模拟扫描的效果来实现户型的生成&#xff01;由于接口ai生成的图片户型时间比较长&#xff0c;所以需要模拟特效&#xff01; <!DOCTYPE html> <html><head><mate charset"UTF-8" /><title>扫描</title…

【全套源码教程】基于SpringBoot+MyBatis+Vue的流浪动物救助网站的设计与实现

目录 前言 需求分析 可行性分析 技术实现 后端框架&#xff1a;Spring Boot 持久层框架&#xff1a;MyBatis 前端框架&#xff1a;Vue.js 数据库&#xff1a;MySQL 功能介绍 前台界面功能介绍 动物领养及捐赠 宠物论坛 公告信息 商品页面 寻宠服务 个人中心 购…

Word一打开背景色全黑了,如何解决~

三天假期&#xff0c;大家应该没学习的吧&#xff01;哈哈哈&#xff0c;可是 office Word 趁大家玩的时候&#xff0c;偷偷加了个夜间模式&#xff0c;而且还是默认模式。一打开就是乌漆嘛黑一片黑底白字的 Word&#xff0c;这丑的样子让我无能为力&#xff0c;看的我头大。 …

深入浅出 -- 系统架构之负载均衡Nginx实现高可用

一、Nginx的高可用 线上如果采用单个节点的方式部署Nginx&#xff0c;难免会出现天灾人祸&#xff0c;比如系统异常、程序宕机、服务器断电、机房爆炸、地球毁灭....哈哈哈&#xff0c;夸张了。但实际生产环境中确实存在隐患问题&#xff0c;由于Nginx作为整个系统的网关层接入…

基于R语言BIOMOD2模型的物种分布模拟

随着生物多样性全球大会的举办&#xff0c;不论是管理机构及科研单位、高校都在积极准备&#xff0c;根据国家林草局最新工作指示&#xff0c;我国将积极整合、优化自然保护地&#xff0c;加快推进国家公园体制试点&#xff0c;构建以国家公园为主体的自然保护地体系。针对我国…

Visual Studio 配置代码风格审查工具cpplint

文章目录 一、Visual Studio 配置代码风格审查工具cpplint1、安装2、运行3、集成到Visual Studio4、集成到Git 前言 cpplint是一个用于检查C代码风格的工具&#xff0c;它可以帮助我们发现潜在的编码问题&#xff0c;提高代码质量。cpplint遵循Google的C编码规范&#xff0c;通…