SpringMVC整合Mongodb开发,高级操作

开发环境:

操作系统:windows xp
Mongodb2.0.6
依 赖 包:Spring3.2.2 + spring-data-mongodb-1.3.0 + Spring-data-1.5 + mongodb2.7.3
说    明:Springmvc整合Mongodb的时候建议选择稳定版的Spring-data-mongdbMongodb1.0.1中存在数据映射bug.所以使用1.3.0.

项目结构图:

说明:
持久层操作使用MongoTemplate类操作.实现将对象与Mongodb库中的数据交互操作.


这里需要说明的是我的实体对象中的id属性对应的是库中记录中的_id属性.

MongodbSpringMVC整合参见文档http://www.cnblogs.com/dennisit/p/3372568.html

Mongodb的高级操作:
添加对象到数据库

/**
     * 保存一个对象
     *
     * @author <a href='mailto:dennisit@163.com'>Cn. 苏若年 (En.dennisit)</a> Copy Right since 2013-10-13 下午 03:37:28
     *                
     * @param t
     * @return
     */
    public void save(T t){
        log.info("[Mongo Dao]save:" + t);
        this.mongoTemplate.save(t);
    }

根据Id从库中查询对象

    
    /**
     * 根据 Id 从 Collection 中查询对象
     *
     * @author <a href='mailto:dennisit@163.com'>Cn. 苏若年 (En.dennisit)</a> Copy Right since 2013-10-17 下午 01:59:55
     *                
     * @param id
     *                 实体对象的 Id, 对应 Collection 中记录的 _id 字段. 
     *                 <p>
     *                     需要说明的是,Mongdo 自身没有主键自增机制. 解决方法
     *                     <ol>
     *                         <li> 实体入库的时候, 程序中为实体赋主键值.
     *                         <li> 实体入库的时候, 在 mongodb 中自定义函数实现主键自增机制. 定义方法同 js 代码类似
     *                     </ol>
     *                 </p>
     * @return
     */
    public T queryById(String id) {
        Query query = new Query();
        Criteria criteria = Criteria.where("_id").is(id);
        query.addCriteria(criteria);
        log.info("[Mongo Dao]queryById:" + query);
        return this.mongoTemplate.findOne(query, this.getEntityClass());}

根据条件从库中查询

    /**
     * 根据条件查询集合
     *
     * @author <a href='mailto:dennisit@163.com'>Cn. 苏若年 (En.dennisit)</a> Copy Right since 2013-10-13 下午 03:32:54
     *                
     * @param query        
     *                     查询条件
     * @return
     *                     满足条件的集合
     */
    public List<T> queryList(Query query){
        log.info("[Mongo Dao]queryList:" + query);
        return this.mongoTemplate.find(query, this.getEntityClass());}

根据条件查询单个记录

/**
     * 通过条件查询单个实体
     *
     * @author <a href='mailto:dennisit@163.com'>Cn. 苏若年 (En.dennisit)</a> Copy Right since 2013-10-13 下午 03:33:12
     *                
     * @param query
     * @return
     */
    public T queryOne(Query query){
        log.info("[Mongo Dao]queryOne:" + query);
        return this.mongoTemplate.findOne(query, this.getEntityClass());}

说明:查询单个用的是mongoTemplate.findOne方法,查询多条的用的是mongoTemplate.find.
分页查询操作

    /**
     * 通过条件进行分页查询
     *
     * @author <a href='mailto:dennisit@163.com'>Cn. 苏若年 (En.dennisit)</a> Copy Right since 2013-10-13 下午 03:33:30
     *                
     * @param query
     *                     查询条件
     * @param start
     *                     查询起始值 
     *                     <strong> 类似 mysql 查询中的 limit start, size 中的 start</strong>
     * @param size
     *                     查询大小
     *                     <strong> 类似 mysql 查询中的 limit start, size 中的 size</strong>
     * @return
     *                     满足条件的集合
     */
    public List<T> getPage(Query query, int start, int size){query.skip(start);
        query.limit(size);
        log.info("[Mongo Dao]queryPage:" + query + "(" + start +"," + size +")");
        List<T> lists = this.mongoTemplate.find(query, this.getEntityClass());
        return lists;
    }
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 根据条件查询库中符合记录的总数,为分页查询服务
 *
 * </span><span style="color: rgba(128, 128, 128, 1)">@author</span><span style="color: rgba(0, 128, 0, 1)"> &lt;a href='mailto:dennisit@163.com'&gt;Cn.苏若年(En.dennisit)&lt;/a&gt; Copy Right since 2013-10-13 下午03:35:44
 *                
 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> query
 *                     查询条件
 * </span><span style="color: rgba(128, 128, 128, 1)">@return</span><span style="color: rgba(0, 128, 0, 1)">
 *                     满足条件的记录总数
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Long getPageCount(Query query){
    log.info(</span>"[Mongo Dao ]queryPageCount:" +<span style="color: rgba(0, 0, 0, 1)"> query);
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.mongoTemplate.count(query, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.getEntityClass());
}
</span></span></pre>

根据Id删除操作

    /**
     * 根据 Id 删除用户
     *
     * @author <a href='mailto:dennisit@163.com'>Cn. 苏若年 (En.dennisit)</a> Copy Right since 2013-10-13 下午 04:09:20
     *                
     * @param id
     */
    public void deleteById(String id) {
        Criteria criteria = Criteria.where("_id").in(id);
        if(null!=criteria){
            Query query = new Query(criteria);
            log.info("[Mongo Dao]deleteById:" + query);
            if(null!=query && this.queryOne(query)!=null){
                this.delete(query);
            }
        }
    }

删除对象操作

    
    /**
     * 删除对象
     *
     * @author <a href='mailto:dennisit@163.com'>Cn. 苏若年 (En.dennisit)</a> Copy Right since 2013-10-13 下午 03:45:33
     *                
     * @param t
     */
    public void delete(T t){
        log.info("[Mongo Dao]delete:" + t);
        this.mongoTemplate.remove(t);
    }

修改操作:

说明:Mongodb的修改操作大致有3.

mongoTemplate.updateFirst操作、mongoTemplate.updateMulti操作、this.mongoTemplate.upsert操作.

分别表示修改第一条、修改符合条件的所有、修改时如果不存在则添加.

修改满足条件的第一条记录

    /**
     * 更新满足条件的第一个记录
     *
     * @author <a href='mailto:dennisit@163.com'>Cn. 苏若年 (En.dennisit)</a> Copy Right since 2013-10-13 下午 03:47:10
     *                
     * @param query
     * @param update
     */
    public void updateFirst(Query query,Update update){
        log.info("[Mongo Dao]updateFirst:query(" + query + "),update(" + update + ")");
        this.mongoTemplate.updateFirst(query, update, this.getEntityClass());}

修改满足条件的多条记录

    /**
     * 更新满足条件的所有记录
     *
     * @author <a href='mailto:dennisit@163.com'>Cn. 苏若年 (En.dennisit)</a> Copy Right since 2013-10-13 下午 03:48:02
     *                
     * @param query
     * @param update
     */
    public void updateMulti(Query query, Update update){
        log.info("[Mongo Dao]updateMulti:query(" + query + "),update(" + update + ")");
        this.mongoTemplate.updateMulti(query, update, this.getEntityClass());}

修改,如果要修改的对象不存在则添加

    /**
     * 查找更新, 如果没有找到符合的记录, 则将更新的记录插入库中
     *
     * @author <a href='mailto:dennisit@163.com'>Cn. 苏若年 (En.dennisit)</a> Copy Right since 2013-10-13 下午 03:48:58
     *                
     * @param query
     * @param update
     */
    public void updateInser(Query query, Update update){
        log.info("[Mongo Dao]updateInser:query(" + query + "),update(" + update + ")");
        this.mongoTemplate.upsert(query, update, this.getEntityClass());}

上面的操作是Mongodb的基础操作封装,利用泛型实现的抽象类MongoGenDao.java,泛型中定义钩子方法,然后Dao类继承抽象类,实现该钩子方法,返回反射的类型.钩子方法的定义如下:

    /**
     * 钩子方法, 由子类实现返回反射对象的类型
     *
     * @author <a href='mailto:dennisit@163.com'>Cn.pudp(En.dennisit)</a> Copy Right since 2013-10-13 下午 03:21:48
     *                
     * @return
     */
    protected abstract Class<T> getEntityClass();

Mongodb基础操作封装大致就这么多

 

接下来介绍如何在数据Dao中根据需要复写我们的持久层基础操作.实例是会员管理的基础实现.

package com.pudp.dao;

import java.util.List;

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.pudp.base.MongoGenDao;
import com.pudp.model.Member;
import com.pudp.util.StringUtil;

/**

  • description:
  • @author <a href='mailto:dennisit@163.com'> Cn. 苏若年 (En.dennisit)</a> Copy Right since 2013-10-13
  • com.pudp.dao.MemberDao.java

*/
@Repository
public class MemberDao extends MongoGenDao<Member>{

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 分页查询   对应mongodb操作中的  db.member.find().skip(10).limit(10);
 *
 * </span><span style="color: rgba(128, 128, 128, 1)">@author</span><span style="color: rgba(0, 128, 0, 1)"> &lt;a href='mailto:dennisit@163.com'&gt;Cn.苏若年(En.dennisit)&lt;/a&gt; Copy Right since 2013-10-13 下午04:09:58
 *                
 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> member
 *                     查询的条件
 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> start    
 *                     用户分页查询的起始值
 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> size
 *                     查询的数据数目
 * 
 * </span><span style="color: rgba(128, 128, 128, 1)">@return</span><span style="color: rgba(0, 128, 0, 1)">
 *                     返回查询到的数据集合
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;Member&gt;<span style="color: rgba(0, 0, 0, 1)"> queryPage(Member member, Integer start, Integer size) {
    Query query </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Query();
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">此处可以增加分页查询条件Criteria.然后query.addCriteria(criteria);</span>
    <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.getPage(query,(start-1)*<span style="color: rgba(0, 0, 0, 1)">size,size);
}

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 查询满足分页的记录总数
 *
 * </span><span style="color: rgba(128, 128, 128, 1)">@author</span><span style="color: rgba(0, 128, 0, 1)"> &lt;a href='mailto:dennisit@163.com'&gt;Cn.苏若年(En.dennisit)&lt;/a&gt; Copy Right since 2013-10-16 上午10:20:12
 *                
 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> member
 *                     查询的条件
 * </span><span style="color: rgba(128, 128, 128, 1)">@return</span><span style="color: rgba(0, 128, 0, 1)">
 *                     返回满足条件的记录总数
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Long queryPageCount(Member member){
    Query query </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Query();
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">此处可以增加分页查询条件Criteria.然后query.addCriteria(criteria);</span>
    <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.getPageCount(query);
}

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 更新操作
 *
 * </span><span style="color: rgba(128, 128, 128, 1)">@author</span><span style="color: rgba(0, 128, 0, 1)"> &lt;a href='mailto:dennisit@163.com'&gt;Cn.苏若年(En.dennisit)&lt;/a&gt; Copy Right since 2013-10-17 下午02:21:26
 *                
 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> member
 *                         要更新的数据
 * </span><span style="color: rgba(128, 128, 128, 1)">@throws</span><span style="color: rgba(0, 128, 0, 1)"> Exception
 *                         更新异常
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> updateFirst(Member member) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> Exception {
    Update update </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Update();
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(<span style="color: rgba(0, 0, 255, 1)">null</span>==member.getId()||""<span style="color: rgba(0, 0, 0, 1)">.equals(member.getId().trim())){
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果主键为空,则不进行修改</span>
        <span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception("Update data Id is Null"<span style="color: rgba(0, 0, 0, 1)">);
    }
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(StringUtil.isNotNullValue(member.getUsername())){
        update.set(</span>"username"<span style="color: rgba(0, 0, 0, 1)">, member.getUsername());
    }
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(StringUtil.isNotNullValue(member.getPassword())){
        update.set(</span>"password"<span style="color: rgba(0, 0, 0, 1)">, member.getPassword());
    }
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(StringUtil.isNotNullValue(member.getSex())){
        update.set(</span>"sex"<span style="color: rgba(0, 0, 0, 1)">, member.getSex());
    }
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(StringUtil.isNotNullValue(member.getEmail())){
        update.set(</span>"email"<span style="color: rgba(0, 0, 0, 1)">, member.getEmail());
    }
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.updateFirst(Query.query(Criteria.where("_id"<span style="color: rgba(0, 0, 0, 1)">).is(member.getId())),update);
}

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 更新库中所有数据
 *
 * </span><span style="color: rgba(128, 128, 128, 1)">@author</span><span style="color: rgba(0, 128, 0, 1)"> &lt;a href='mailto:dennisit@163.com'&gt;Cn.苏若年(En.dennisit)&lt;/a&gt; Copy Right since 2013-10-17 下午02:22:07
 *                
 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> member
 *                         更新的数据
 * </span><span style="color: rgba(128, 128, 128, 1)">@throws</span><span style="color: rgba(0, 128, 0, 1)"> Exception
 *                         更新异常
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> updateMulti(Member member) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> Exception {
    Update update </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Update();
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(<span style="color: rgba(0, 0, 255, 1)">null</span>==member.getId()||""<span style="color: rgba(0, 0, 0, 1)">.equals(member.getId().trim())){
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果主键为空,则不进行修改</span>
        <span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception("Update data Id is Null"<span style="color: rgba(0, 0, 0, 1)">);
    }
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(StringUtil.isNotNullValue(member.getUsername())){
        update.set(</span>"username"<span style="color: rgba(0, 0, 0, 1)">, member.getUsername());
    }
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(StringUtil.isNotNullValue(member.getPassword())){
        update.set(</span>"password"<span style="color: rgba(0, 0, 0, 1)">, member.getPassword());
    }
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(StringUtil.isNotNullValue(member.getSex())){
        update.set(</span>"sex"<span style="color: rgba(0, 0, 0, 1)">, member.getSex());
    }
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(StringUtil.isNotNullValue(member.getEmail())){
        update.set(</span>"email"<span style="color: rgba(0, 0, 0, 1)">, member.getEmail());
    }
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.updateMulti(Query.query(Criteria.where("_id"<span style="color: rgba(0, 0, 0, 1)">).is(member.getId())),update);
}


</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 实现钩子方法,返回反射的类型
 * </span><span style="color: rgba(128, 128, 128, 1)">@author</span><span style="color: rgba(0, 128, 0, 1)"> &lt;a href='mailto:dennisit@163.com'&gt;Cn.苏若年(En.dennisit)&lt;/a&gt; Copy Right since 2013-10-17 
 *                
 * </span><span style="color: rgba(128, 128, 128, 1)">@return</span><span style="color: rgba(0, 128, 0, 1)">        
 *                 反射类型
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@Override
</span><span style="color: rgba(0, 0, 255, 1)">protected</span> Class&lt;Member&gt;<span style="color: rgba(0, 0, 0, 1)"> getEntityClass() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> Member.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">;
}

}

业务层调用Dao进行业务数据的交互.这里列出实例中的Service层中对持久层分页操作的实现

    /**
     * 分页查询
     * @author <a href='mailto:dennisit@163.com'>Cn. 苏若年 (En.dennisit)</a> Copy Right since 2013-10-17 
     *                
     * @param member
     *                     查询的条件
     * @param start
     *                      对应 <code>Page</code> 工具类的属性当前页:pageNum 
     * @param size
     *                      对应 <code>Page</code> 工具类的属性每页显示多少条记录:pageSize
     * @return
     */
    public Page<Member> queryPage(Member member, int start, int size) {
        Page<Member> page = new Page<Member>();
        try {
            List<Member> list = this.memberDao.queryPage(member, start, size);
            Long recordTotal = this.memberDao.queryPageCount(member);
            page= new Page<Member>(list, recordTotal, (long)start, size);
            log.info(page);
        } catch (Exception e) {e.printStackTrace();
        }
        return page;
    }

至此,SpringMVC整合mongodb的高级操作实例完毕,实例中使用jquery.Pager插件分页这个属于分页插件的应用,就不介绍了.

运行效果图:


转载请注明出处:[http://www.cnblogs.com/dennisit/p/3374297.html]

ÔÚÏß½»Ì¸