背景:
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);
}