背景:
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";@Overridepublic 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));}*/}@Beanpublic 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 {@AutowiredMongoDatabaseFactory 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") //第一个数据源名字oneMongopublic MongoTemplate primaryMongoTemplate() {try {log.info("primaryMongoProperties:" + primaryMongoProperties.getUri());return new MongoTemplate(mongoDatabaseFactory(primaryMongoProperties));} catch (Exception e) {e.printStackTrace();}return null;}@Bean@Primarypublic 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@Primarypublic 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;@Autowiredpublic 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;@Overridepublic 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);}