Java集成mongodb有很多方式,可以直接用mongodb的java驱动程序来发送语句到mongodb服务器,也可以用第三方的工具包来做。
(1) 选择版本
今天我选择的就是springdata集成的mongodb(spring-data-mongodb)
1.1 spring-data-mongodb版本
gradle坐标:
org.springframework.data:spring-data-mongodb:1.7.2.RELEASE
maven 坐标
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.7.2.RELEASE</version>
</dependency>
1.2 java驱动器版本
gradle坐标:
org.mongodb:mongo-java-driver:3.2.0
maven 坐标
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.2.0</version>
</dependency>
(2) 集成
2.1 spring 配置文件
新建文件 mongodb-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- mongodb 的基本配置 -->
<mongo:mongo id="mongo" host="192.168.1.202" port="27017" />
<!-- 权限配置 -->
<bean id="userCredentials" class="org.springframework.data.authentication.UserCredentials">
<constructor-arg name="username" value="root"/>
<constructor-arg name="password" value="root"/>
</bean>
<!-- template 配置 -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo" />
<!-- 数据库名称 -->
<constructor-arg value="demodb" />
<!-- 权限 -->
<constructor-arg ref="userCredentials" />
</bean>
</beans>
集成到spring的基础配置文件中即可
spring的主配置文件插入如下代码
<!-- 导入mongodb的配置文件 -->
<import resource="mongodb-context.xml"/>
(3) 编写基础类
3.1 Dao 基础操作类 MongodbDao
其他的dao类都可以继承改类
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
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.Repository;
import com.github.pagehelper.PageInfo;
/**
* mongodb 基础操作类
* @author chenpengye 2015年12月21日 下午11:33:06
* @param <T>
*/
@Repository
public class MongodbDao<T extends IdEntity> {
private static final Logger logger = LoggerFactory.getLogger(MongodbDao.class);
private static final int DEFAULT_SKIP = 0;
private static final int DEFAULT_LIMIT = 200;
@Autowired
protected MongoTemplate mongoTemplate;
// ======= 增 ============
public void save(T t) {
mongoTemplate.save(t);
logger.debug("save entity: {}", t);
}
public void insertAll(List<T> list) {
mongoTemplate.insertAll(list);
}
// ======= 删 ============
/**
* 删除对象
*
* @param t
*/
public void delete(T t) {
mongoTemplate.remove(t);
}
/**
* 根据id 删除对象
*
* @param id
*/
public void deleteById(String id) {
Criteria criteria = Criteria.where("id").is(id);
Query query = new Query(criteria);
mongoTemplate.remove(query, this.getEntityClass());
}
/**
* 根据条件删除
*/
public void delete(Query query) {
mongoTemplate.remove(query, this.getEntityClass());
}
/**
* 删除该collection 的所有的数据
*/
public void deleteAll() {
mongoTemplate.dropCollection(this.getEntityClass());
}
// ======= 改 ============
public void update(Query query, Update update) {
mongoTemplate.findAndModify(query, update, this.getEntityClass());
}
// ======= 查 ============
public List<T> findAll(){
return mongoTemplate.findAll(this.getEntityClass());
}
/**
* 根据查询query 查找list
*
* @param query
* @return
*/
public List<T> find(Query query) {
return mongoTemplate.find(query, this.getEntityClass());
}
/**
* 按照字段排序 - 顺序 <br/>
* @param query 查询条件 <br/>
* @param properties 排序字段 <br/>
* @return
*/
public List<T> findWithOrderAsc(Query query, String... properties){
Sort sort = new Sort(Direction.ASC, properties);
query.with(sort);
return mongoTemplate.find(query, this.getEntityClass());
}
/**
* 按照字段排序 - 逆序 <br/>
* @param query 查询条件 <br/>
* @param properties 排序字段 <br/>
* @return
*/
public List<T> findWithOrderDesc(Query query, String... properties){
Sort sort = new Sort(Direction.DESC, properties);
query.with(sort);
return mongoTemplate.find(query, this.getEntityClass());
}
/**
* 根据查询query 查找一个对象
*
* @param query
* @return
*/
public T findOne(Query query) {
return mongoTemplate.findOne(query, this.getEntityClass());
}
/**
* 根据 id 查询对象
*
* @param id
* @return
*/
public T findById(String id) {
return mongoTemplate.findById(id, this.getEntityClass());
}
/**
* 根据id 和 集合名字查询对象
*
* @param id
* @param collectionName
* @return
*/
public T findById(String id, String collectionName) {
return mongoTemplate.findById(id, this.getEntityClass(), collectionName);
}
/**
* 查询分页 tips:[不要skip 太多的页数,如果跳过太多会严重影响效率。最大不要skip 20000页]
* @param page
* @param query
* @return
*/
public PageInfo<T> findPage(PageInfo<T> page, Query query) {
long count = this.count(query);
page.setTotal(count);
int pageNumber = page.getPageNum();
int pageSize = page.getPageSize();
query.skip((pageNumber - 1) * pageSize).limit(pageSize);
List<T> list = this.find(query);
page.setList(list);
return page;
}
public long count(Query query) {
return mongoTemplate.count(query, this.getEntityClass());
}
/**
* 获取需要操作的实体类class <br/>
* 例如: StudentScoreDao extends MongodbDao <b><StudentScore></b> <br/>
* 返回的是 <b>StudentScore</b> 的Class
*
* @return
*/
private Class<T> getEntityClass() {
return ReflectionUtils.getSuperClassGenricType(getClass());
}
/**
* 获取collection的名字,默认是dao范型T的名字 <br/>
* 例如: StudentScoreDao extends MongodbDao <b><StudentScore></b> <br/>
* 则返回的名字是:<b>StudentScore</b>
*
* @return
*/
private String getCollectionName() {
return getEntityClass().getSimpleName();
}
}
由于现行项目使用mybatis,并且分页采用了pagehelper:pagehelper:4.0.3,因此这里的分页类也采用里pagehelper里面的分页类。如果要分页,请也引入pagehelper的jar包
gradle坐标
compile 'com.github.jsqlparser:jsqlparser:0.9.4'
compile 'com.github.pagehelper:pagehelper:4.0.3'
maven坐标
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>0.9.4</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.0.3</version>
</dependency>
3.2 工具类 ReflectionUtils
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
/**
* 反射工具类.
*
* 提供访问私有变量,获取泛型类型Class, 提取集合中元素的属性, 转换字符串到对象等Util函数.
*
*/
public class ReflectionUtils {
private static Logger logger = LoggerFactory.getLogger(ReflectionUtils.class);
/**
* 调用Getter方法.
*/
public static Object invokeGetterMethod(Object obj, String propertyName) {
String getterMethodName = "get" + StringUtils.capitalize(propertyName);
return invokeMethod(obj, getterMethodName, new Class[] {}, new Object[] {});
}
/**
* 调用Setter方法.使用value的Class来查找Setter方法.
*/
public static void invokeSetterMethod(Object obj, String propertyName, Object value) {
invokeSetterMethod(obj, propertyName, value, null);
}
/**
* 调用Setter方法.
*
* @param propertyType 用于查找Setter方法,为空时使用value的Class替代.
*/
public static void invokeSetterMethod(Object obj, String propertyName, Object value, Class<?> propertyType) {
Class<?> type = propertyType != null ? propertyType : value.getClass();
String setterMethodName = "set" + StringUtils.capitalize(propertyName);
invokeMethod(obj, setterMethodName, new Class[] { type }, new Object[] { value });
}
/**
* 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
*/
public static Object getFieldValue(final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
}
Object result = null;
try {
result = field.get(obj);
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常{}", e.getMessage());
}
return result;
}
/**
* 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
*/
public static void setFieldValue(final Object obj, final String fieldName, final Object value) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
}
try {
field.set(obj, value);
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常:{}", e.getMessage());
}
}
/**
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
*
* 如向上转型到Object仍无法找到, 返回null.
*/
public static Field getAccessibleField(final Object obj, final String fieldName) {
Assert.notNull(obj, "object不能为空");
Assert.hasText(fieldName, "fieldName");
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Field field = superClass.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {//NOSONAR
// Field不在当前类定义,继续向上转型
}
}
return null;
}
/**
* 直接调用对象方法, 无视private/protected修饰符.
* 用于一次性调用的情况.
*/
public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args) {
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
}
try {
return method.invoke(obj, args);
} catch (Exception e) {
throw convertReflectionExceptionToUnchecked(e);
}
}
/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
*
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes) {
Assert.notNull(obj, "object不能为空");
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Method method = superClass.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
return method;
} catch (NoSuchMethodException e) {//NOSONAR
// Method不在当前类定义,继续向上转型
}
}
return null;
}
/**
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
* 如无法找到, 返回Object.class.
* eg.
* public UserDao extends HibernateDao<User>
*
* @param clazz The class to introspect
* @return the first generic declaration, or Object.class if cannot be determined
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <T> Class<T> getSuperClassGenricType(final Class clazz) {
return getSuperClassGenricType(clazz, 0);
}
/**
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
* 如无法找到, 返回Object.class.
*
* 如public UserDao extends HibernateDao<User,Long>
*
* @param clazz clazz The class to introspect
* @param index the Index of the generic ddeclaration,start from 0.
* @return the index generic declaration, or Object.class if cannot be determined
*/
@SuppressWarnings("rawtypes")
public static Class getSuperClassGenricType(final Class clazz, final int index) {
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0) {
logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+ params.length);
return Object.class;
}
if (!(params[index] instanceof Class)) {
logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}
return (Class) params[index];
}
/**
* 将反射时的checked exception转换为unchecked exception.
*/
public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|| e instanceof NoSuchMethodException) {
return new IllegalArgumentException("Reflection Exception.", e);
} else if (e instanceof InvocationTargetException) {
return new RuntimeException("Reflection Exception.", ((InvocationTargetException) e).getTargetException());
} else if (e instanceof RuntimeException) {
return (RuntimeException) e;
}
return new RuntimeException("Unexpected Checked Exception.", e);
}
}
3.3 基础实体类 IdEntity
import java.io.Serializable;
/**
* mongodb 基础id类,id都是字符串型的
* @author chenpengye
* 2015年12月21日 下午4:53:45
*/
public class IdEntity implements Serializable {
private static final long serialVersionUID = 33633625616087044L;
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
3.4 实体类 StudentScore
import java.io.Serializable;
import java.util.List;
/**
* 测试实体类
* @author chenpengye
* 2015年12月21日 下午11:59:02
*/
public class StudentScore extends IdEntity implements Serializable {
private static final long serialVersionUID = 8743196073520676022L;
/**
* 学生姓名
*/
private String username;
/**
* 学生成绩
*/
private List<Double> scoreList;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public List<Double> getScoreList() {
return scoreList;
}
public void setScoreList(List<Double> scoreList) {
this.scoreList = scoreList;
}
}
3.5 实体类的dao操作类 StudentScoreDao
import org.springframework.stereotype.Repository;
/**
* 继承MongodbDao<br/>
* 此类对StudentScore对增删改查和分页方法都已经有了<br/>
* @author chenpengye
* 2016年1月4日 下午10:04:25
*/
@Repository
public class StudentScoreDao extends MongodbDao<StudentScore> {
}
有需要的同学可以参考我的上一篇博客,关于mongodb的安装
---(1)在ubuntu上安装mongodb ------
欢迎探讨,如有疑问请发邮件到chenpengye1861@163.com