springboot整合MongoDB以及对mongoTemplate进一步的封装
前言
业务需要使用到MongoDB,因此将整合过程一一记录。由于原生template操作并不直观,以及操作方式与传统sql数据库有差别。这里将template做进一步封装,使其操作风格尽可能与传统数据DAO一致,对上层屏蔽数据库操作的差异。
springboot整合MongoDB
pom版本依赖信息
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/>
</parent>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
properties文件配置
spring.data.mongo.uri=mongodb://localhost:27017/test
若有密码认证则配置如下
spring.data.mongo.uri=mongodb://username:password@localhost:27017/datasource
mongodb与springboot整合config配置
@Configuration
public class MongoDBConfig {
@Value("${spring.data.mongo.uri}")
private String uri;
@Bean
public MappingMongoConverter mappingMongoConverter(MongoMappingContext mongoMappingContext) {
DefaultDbRefResolver dbRefResolver = new DefaultDbRefResolver(dbFactory());
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
converter.setTypeMapper(new DefaultMongoTypeMapper(null));
// 去除写入mongodb时的_class字段
return converter;
}
@Bean
public MongoDbFactory dbFactory() {
return new SimpleMongoClientDbFactory(uri);
}
}
对mongoTemplate做进一步封装
目的对上层使用者屏蔽不同的数据的操作差异。
创建模板接口
package com.onecloud.wm.core.db;
import com.onecloud.wm.core.db.mongo.MongoFilter;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import java.util.List;
import java.util.Map;
/**
* db操作模板
*
* @author wm
* @date 2021/09/17
*/
public interface IDbTemplate {
/**
* 批量增加
*
* @param list 集合
* @param collectionName 表名
* @return 结果
*/
boolean batchSave(List list, String collectionName);
/**
* 增加
*
* @param obj 对象
* @return 结果
*/
boolean save(Object obj);
/**
* 删除
*
* @param obj 对象
* @return 结果
*/
boolean remove(Object obj);
/**
* 更新
*
* @param objClazz 对象类
* @param valueMap 条件map
* @param updateMap 更新map
* @return 结果
*/
boolean update(Class objClazz, Map<String, Object> valueMap, Map<String, Object> updateMap);
/**
* 按属性过滤条件列表查找对象列表.
*
* @param objClazz 表对象类
* @param valueMap 条件map
*/
Object findUniqueBy(Class objClazz, Map<String, Object> valueMap);
/**
* 条件统计数量
*
* @param objClazz 表对象类
* @param valueMap 条件map
* @return 数据量
*/
long count(Class objClazz, Map<String, Object> valueMap);
/**
* 按属性过滤条件列表查找对象列表.
*
* @param objClazz 表对象类
* @param valueMap 条件map
*/
List find(Class objClazz, Map<String, Object> valueMap);
/**
* 按属性过滤条件列表分页查找对象.
*
* @param objClazz 表对象类
* @param pageRequest 分页条件
* @param valueMap 条件map
*/
PageImpl findPage(Class objClazz, PageRequest pageRequest, Map<String, Object> valueMap);
/**
* 按属性过滤条件列表查找对象列表.
*
* @param objClazz 表对象类
* @param filters 条件过滤器
*/
List find(Class objClazz, List<MongoFilter> filters);
}
增加MongoDbTemplate对IDbTemplate实现类
@Primary注解用于如果有多个实现类,告知spring优先使用此实现
@Component将该实现类交给sping容器管理
以obj对象形式保存数据。将对象的属性为key,以需要属性数据位value组装成map,对数据进行改查操作。
将map以及将自定义MongoFilter转成MongoDB规范查询语言。具体核心代码如下文 查询转换核心
package com.onecloud.wm.core.db.mongo;
import com.onecloud.wm.core.db.IDbTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
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.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.util.List;
import java.util.Map;
/**
* mongo 操作模板
*
* @author wm
* @date 2021/09/17
*/
@Component
@Primary
public class MongoDbTemplate implements IDbTemplate {
@Autowired
private MongoTemplate mongoTemplate;
@Override
public boolean batchSave(List list, String collectionName) {
mongoTemplate.insert(list, collectionName);
return true;
}
@Override
public boolean save(Object obj) {
mongoTemplate.save(obj);
return true;
}
@Override
public boolean remove(Object obj) {
return mongoTemplate.remove(obj).getDeletedCount() > 0;
}
@Override
public boolean update(Class objClazz, Map<String, Object> valueMap, Map<String, Object> updateMap) {
Criteria criteria = MongoQueryTool.buildCriteria(valueMap);
Assert.notNull(criteria, "Criteria must not be null!");
Query query = Query.query(criteria);
Update update = MongoQueryTool.buildUpdate(updateMap);
return mongoTemplate.updateFirst(query, update, objClazz).getModifiedCount() > 0;
}
@Override
@SuppressWarnings("unchecked")
public Object findUniqueBy(Class objClazz, Map<String, Object> valueMap) {
Criteria criteria = MongoQueryTool.buildCriteria(valueMap);
Assert.notNull(criteria, "Criteria must not be null!");
Query query = Query.query(criteria);
return mongoTemplate.findOne(query, objClazz);
}
@Override
public long count(Class objClazz, Map<String, Object> valueMap) {
Criteria criteria = MongoQueryTool.buildCriteria(valueMap);
Assert.notNull(criteria, "Criteria must not be null!");
Query query = Query.query(criteria);
return mongoTemplate.count(query, objClazz);
}
@Override
@SuppressWarnings("unchecked")
public List find(Class objClazz, Map<String, Object> valueMap) {
Criteria criteria = MongoQueryTool.buildCriteria(valueMap);
Assert.notNull(criteria, "Criteria must not be null!");
Query query = Query.query(criteria);
return mongoTemplate.find(query, objClazz);
}
@Override
@SuppressWarnings("unchecked")
public PageImpl findPage(Class objClazz, PageRequest pageRequest, Map<String, Object> valueMap) {
Criteria criteria = MongoQueryTool.buildCriteria(valueMap);
Assert.notNull(criteria, "Criteria must not be null!");
long count = count(objClazz, valueMap);
Query query = Query.query(criteria);
query.with(pageRequest);
List list = mongoTemplate.find(query, objClazz);
return new PageImpl(list, pageRequest, count);
}
@Override
@SuppressWarnings("unchecked")
public List find(Class objClazz, List<MongoFilter> filters) {
Criteria criteria = MongoQueryTool.buildCriteria(filters);
Assert.notNull(criteria, "Criteria must not be null!");
Query query = Query.query(criteria);
return mongoTemplate.find(query, objClazz);
}
}
查询转换核心
MongoFilter具体类
package com.onecloud.wm.core.db.mongo;
/**
* mongo 过滤条件封装
*
* @author wm
* @date 2021/09/17
*/
public class MongoFilter {
private Object matchValue = null;
private MatchType matchType = null;
private String propertyName = null;
public MongoFilter() {}
public MongoFilter(String propName, MatchType matchType, Object value) {
this.matchType = matchType;
this.propertyName = propName;
this.matchValue = value;
}
/**
* 获取比较方式.
*/
public MatchType getMatchType() {
return matchType;
}
/**
* 获取比较值.
*/
public Object getMatchValue() {
return matchValue;
}
/**
* 获取比较属性名称.
*/
public String getPropertyName() {
return propertyName;
}
/** 属性比较类型. */
public enum MatchType {
EQ, LIKE, LT, GT, LE, GE, IN, NE
}
}
查询转换工具类
package com.onecloud.scada.school.core.db.mongo;
import com.onecloud.scada.model.util.CommonTool;
import com.onecloud.scada.school.core.db.mongo.MongoFilter.MatchType;
import com.onecloud.scada.utils.AssertUtils;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Update;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* mongo查询规则转换工具
*
* @author wm
* @date 2021/09/17
*/
public class MongoQueryTool {
/**
* map转MongoDB查询语句规则
*
* @param paramMap map
*/
public static Criteria buildCriteria(Map<String, Object> paramMap) {
if (paramMap == null) {
return null;
}
Criteria criteria = null;
int i = 0;
for (String key : paramMap.keySet()) {
Object value = paramMap.get(key);
if (i == 0) {
if (value instanceof Collection) {
criteria = Criteria.where(key).in((List)value);
} else {
criteria = Criteria.where(key).is(value);
}
} else {
if (value instanceof Collection) {
criteria.and(key).in((List)value);
} else {
criteria.and(key).is(value);
}
}
i++;
}
return criteria;
}
/**
* map转MongoDB查询语句规则
*
* @param filters filters
*/
public static Criteria buildCriteria(List<MongoFilter> filters) {
if (CommonTool.isNullOrEmpty(filters)) {
return null;
}
Criteria criteria = new Criteria();
int i = 0;
List<Criteria> criteriaList = new ArrayList<>();
for (MongoFilter filter : filters) {
if (i == 0) {
criteria = buildCriterion(filter.getPropertyName(), filter.getMatchValue(), filter.getMatchType());
} else {
criteriaList
.add(buildCriterion(filter.getPropertyName(), filter.getMatchValue(), filter.getMatchType()));
}
i++;
}
if (CommonTool.isNonEmpty(criteriaList)) {
criteria = criteria.andOperator(criteriaList.toArray(new Criteria[] {}));
}
return criteria;
}
/**
* map转MongoDB更新语句规则
*
* @param paramMap map
*/
public static Update buildUpdate(Map<String, Object> paramMap) {
if (paramMap == null) {
return null;
}
Update update = new Update();
for (String key : paramMap.keySet()) {
Object value = paramMap.get(key);
update.set(key, value);
}
return update;
}
/**
* 按属性条件参数创建Criterion,辅助函数.
*/
public static Criteria buildCriterion(String propertyName, Object propertyValue, MatchType matchType) {
AssertUtils.hasText(propertyName, "propertyName不能为空");
Criteria criteria = new Criteria(propertyName);
// 根据MatchType构造criterion
switch (matchType) {
case EQ:
criteria = criteria.is(propertyValue);
break;
case NE:
criteria = criteria.ne(propertyValue);
break;
case LIKE:
String pattern = ".*" + propertyValue + ".*";
criteria = criteria.regex(pattern);
break;
case LE:
criteria = criteria.lte(propertyValue);
break;
case LT:
criteria = criteria.lt(propertyValue);
break;
case GE:
criteria = criteria.gte(propertyValue);
break;
case GT:
criteria = criteria.gt(propertyValue);
break;
case IN:
criteria = criteria.in((List)propertyValue);
break;
default:
break;
}
return criteria;
}
}
后续
可进一步封装MongoDBDao层,以及MongoDBService,完成基础的实现。后续扩展新的表,可直接实继承MongoDBService实现类,使用默认操作
见:像传统数据库DAO一样操作MongoDB