zoukankan      html  css  js  c++  java
  • Hibernate DetachedCriteria实现

     前段时间在做模糊查询,并利用数据库分页,DAO用hibernate实现,刚开始的时候
    根据业务层的数据,拼hql语句进行查询,且不说要进行一些if判断,单从结构上来说,
    底层的数据访问层依赖于业务层或者表现层了.
      比如说,我想查询姓王的员工,年龄大于30岁的,在DAO显然要name like '%王' and age >30,如果业务发生变化,查询与王**姓名相同,年龄等于30的,那就改hql语句吧,
    name ='王**' and age =30,数据访问层依赖于业务层,觉得不合理.
     Hibernate3提供一个新的东西,DetachedCriteria可以脱离session分离查询条件,也就是把查询条件通过业务层或表现层传入,数据访问层进行数据操作,解决了数据访问层依赖于业务层的问题.
    实现细节:
    结合泛型设计DAO

    public interface DAO<PO,ID extends java.io.Serializable> {


     public List<Workparam> findRowsByCriteria( DetachedCriteria detachedCriteria, int first, int max);
     
     
     public int findCountByCriteria( DetachedCriteria detachedCriteria);

    }

    DAO的实现:

    public class DAOHibernate<PO,ID extends java.io.Serializable> extends HibernateDaoSupport implements DAO<PO,ID> {

     
     @SuppressWarnings("unchecked")
     public List<PO> findRowsByCriteria(DetachedCriteria detachedCriteria, int first, int max) {
      // TODO 自动生成方法存根
      return getHibernateTemplate().findByCriteria(detachedCriteria, first, max);

     
     public int findCountByCriteria(DetachedCriteria detachedCriteria) {
      // TODO 自动生成方法存根
      detachedCriteria.setProjection(Projections.rowCount());
      System.out.println(getHibernateTemplate().findByCriteria(detachedCriteria));
      return (Integer) getHibernateTemplate().findByCriteria(detachedCriteria).get(0);
     }


     }

    }

    具体实现的DAO:

    public interface WorkparamDAO extends DAO<Workparam,Integer>{

    }

    implements:

    public class WorkparamDAOHibernate extends DAOHibernate<Workparam,Integer> implements WorkparamDAO {

    }

     
    在利用spring管理DAOHibernate的时候,最好设置其abstract="true",即为抽象的,
    实际上DAOHibernate在没有由子类参数化PO,ID类型之前,也是不能使用的.它也不知道PO,ID是什么类型,编译时不会报错,但运行的时候就会出错.
     
    接下来做一个分页工具类,封装分页信息:

    public class PageSplitUtil<E> {
     
     //存放记录集合
     private List<E> items;
     
     //每页记录数
     private int pageSize = Constants.PAGE_SIZE;
     
     //总记录数
     //初始化其值,为了判断缓存
     private int totalCount=-1;
     
     //分页索引数组
     private int indexs[];
     
     //开始索引值
     private int firstIndex = Constants.FIRST_INDEX;
     
     //当前页索引
     private int currentIndex;
     
     //是否有上一个索引
     private boolean hasPreIndex;
     
     //是否有下一个索引
     private boolean hasNextIndex;
     
     //上一页索引
     private int preIndex;
     
     //上一页索引
     private int nextIndex;
     
     //最后一页
     private int lastIndex;
     
     //小分页数
     private int splitCount=Constants.SPLIT_COUNT;
     
     //存放url
     private String action;

     //constructor
     public PageSplitUtil(List<E> items,int current,int totalCount){
      this.items = items;
      this.totalCount = totalCount ;
      this.currentIndex = current;
      calculateTotalPage();
     }
     
     
     public PageSplitUtil(List<E> items,int current,int pageSize,int totalCount){
      this.items = items;
      this.pageSize = pageSize;
      this.totalCount = totalCount;
      this.currentIndex = current;
      calculateTotalPage();
     }
     
     public int getCurrentIndex() {
      return currentIndex;
     }

     
     public void setCurrentIndex(int currentIndex) {
      this.currentIndex = currentIndex<1?1:currentIndex;
     }

     
     public boolean isHasNextIndex() {
      return currentIndex>=lastIndex || lastIndex ==1 ?false:true;
     }

     
     public boolean isHasPreIndex() {
      return currentIndex<=firstIndex ?false:true;
     }

     
     public int[] getIndexs() {
      indexs = new int[lastIndex];
      for (int i = 0; i < lastIndex; i++) {
       indexs[i]=i+1;
      }
      return indexs;
     }

     
     public List<E> getItems() {
      return items;
     }

     
     public void setItems(List<E> items) {
      this.items = items;
     }

     
     public int getPageSize() {
      return pageSize;
     }


     
     public int getFirstIndex() {
      return firstIndex;
     }


     
     public int getTotalCount() {
      return totalCount;
     }


     
     public int getLastIndex() {

      return lastIndex;
     }

     
     public int getSplitCount() {
      return splitCount;
     }
     
     public int getNextIndex() {
      return currentIndex>=lastIndex ? lastIndex : currentIndex+1;
     }

     
     public int getPreIndex() {
      return currentIndex<=firstIndex ? firstIndex : currentIndex-1;
     } 
     
     
     public String getAction() {
      return action;
     }

     public void setAction(String action) {
      this.action = action;
     }


     //计算总页数
     private void calculateTotalPage(){
      if(totalCount>0){
       lastIndex=(int) Math.ceil((double)totalCount/pageSize);

      }else{
       lastIndex =0;
      }
     }

    }

     
    把detachedCriteria查询条件在业务层实现

    public PageSplitUtil findRowsByCriteria(Workparam param,int current,int pageSize) {
      // TODO 自动生成方法存根
      DetachedCriteria dc = DetachedCriteria.forClass(param.getClass());
      dc.add(Restrictions.like("workName", param.getWorkName(), MatchMode.ANYWHERE));
       dc.add(Restrictions.eq("workState", param.getWorkState())).addOrder(Order.desc("workId"));

      int totalCount=workparamDAO.findCountByCriteria(dc);
      
      PageSplitUtil ps=new PageSplitUtil<Workparam>(list,current,pageSize,totalCount);
      return ps;
     }

    由于detachedCriteria是根据Criteria的扩展实现,Critetia利用Express来封装了判断的条件以及sql函数(count(),avg()等).在hibernate3中,利用Restrictions封装逻辑判断条件,如like,eq,between等,用Projections封装了sql函数,如count(),avg()等.
    MatchMode为匹配方式:START,前边匹配,END,后边匹配,ANYWHERE前后匹配,EXACT完全匹配四种方式.
    detachedCriteria支持数据库查询时的排序,addOrder(Order.asc("按属性排序"));
    detachedCriteria的多表关联查询,dc.createAlias("workType", "t").add(Restrictions.like("t.typeName", "早班类"));workType作为Workparam的关联属性,在映射文件中会根据其关系对相关联的表进行模糊查询.
     
    为了方便在每个页面使用,用自定义标签显示分页信息:

    public class PageSplitTag extends BodyTagSupport {
     private static final long serialVersionUID = -1411548776656848362L;

     private String action="";

     private PageSplitUtil pageUtil;
     
     public PageSplitTag() {
      // TODO 自动生成构造函数存根
     }
     
     public int doStartTag() throws JspException{
      try {
       String txt=getText().toString();
       pageContext.getOut().write(txt);
       return this.SKIP_BODY;
      } catch (IOException e) {
       // TODO 自动生成 catch 块
       throw new JspException("输出错误"+e.getMessage());
      }
     }
     
     
     private StringBuffer getText() {
      // TODO 自动生成方法存根
      if(pageUtil==null) return new StringBuffer("初始化分页失败");
      
      //判断action是否设置
      if(action==null||"".equals(action)){
       action=pageUtil.getAction();
      }
      
      StringBuffer txt=new StringBuffer("<form action="+action+" method="get" name="splitfrm">");
      txt.append("<td height="27" align="center">共有<font color="red">"
         +pageUtil.getTotalCount()+"</font>条记录&nbsp;&nbsp;");
      txt.append("<font color="red">"+pageUtil.getPageSize()+"</font>条/页&nbsp;&nbsp;");
      //判断是否有上一页
      if(pageUtil.isHasPreIndex()){
       txt.append("<a href="+action+"?page="+pageUtil.getFirstIndex()+">首页</a>&nbsp;");
       txt.append("<a href="+action+"?page="+pageUtil.getPreIndex()+">&lt;&lt;&lt;</a>&nbsp;&nbsp;");
      }
      else{
       txt.append("<font color="#999966">首页</font>&nbsp;");
       txt.append("<font color="#999966">&lt;&lt;&lt;</font>&nbsp;");
      }
      //小的分页
      int indexs[]=pageUtil.getIndexs();
      int currentIndex=pageUtil.getCurrentIndex();
      int splitCount=pageUtil.getSplitCount();
      int count=0;
      //每次显示从当前页开始的后splitCount页
      if(pageUtil.getLastIndex()-(currentIndex+splitCount)>=0){
       count=currentIndex+splitCount;
      }else{
       count=indexs.length;
      }
       for (int i = currentIndex-1; i < count; i++) {
         if(currentIndex == indexs[i] ){
          txt.append("<font color="red">"+currentIndex+"</font>&nbsp;");
         }else{
          txt.append("<a href="+action+"?page="+indexs[i]+">"+indexs[i]+"</a>&nbsp;");
        }
       }
      txt.append("&nbsp");
      
      //判断是否还有下一页
      if(pageUtil.isHasNextIndex()){
       txt.append("<a href="+action+"?page="+pageUtil.getNextIndex()+">&gt;&gt;&gt;</a>&nbsp;");
       txt.append("<a href="+action+"?page="+pageUtil.getLastIndex()+">尾页</a>&nbsp;");
      }
      else{
       txt.append("<font color="#999966">&gt;&gt;&gt;</font>&nbsp;");
       txt.append("<font color="#999966">尾页</font>&nbsp;");
      }
      //页数选择
      txt.append("GO<select name="page" onchange="javascript:document.splitfrm.submit();">");
      for (int i = 0; i < indexs.length; i++) {
       if(currentIndex == indexs[i]){
        txt.append("<option value="+indexs[i]+" selected="selected">"+indexs[i]+"</option>");
       }else{
        txt.append("<option value="+indexs[i]+">"+indexs[i]+"</option>");
       }
      }
      txt.append("</select>页</form></td>");
      return txt;
     }

    setter..

    }

    然后在每个页面用自定义标签就可以了:

    <%@ taglib uri="http://www.oamanager.com/mytag" prefix="tag"%>

    <tag:splitPage action="${splitList.action}" pageUtil="${splitList}"></tag:splitPage>

     设置action请求的路径和分页信息就可以了.
     
    缺点:
    1:在DAO接口的设计中依赖于hibernate的实现.如果改用ibatis或ojb,需更改接口,不符合接口的设计原则.
    2:分页的自定义Tag显示形式固定,如果利用DIV+CSS,或者XML+CSS的话,表现形式更加灵活.
  • 相关阅读:
    js实现冒泡排序
    AngularJS控制器
    AngularJS指令
    AngularJS表达式
    AngularJS基础
    Python小例子(判断质数)
    Python小例子(求和)
    Python笔记
    js小例子(简单模糊匹配输入信息)
    word学习笔记
  • 原文地址:https://www.cnblogs.com/zengda/p/4451793.html
Copyright © 2011-2022 走看看