研究一下springside的核心部分源代码

 这两天,有一些时间,研究一下springside的源代码,结果感觉不错,于是对自己做过一些代码做了一些优化与重构.
分页的代码如下:
(说明:这里的代码是我参考了springside的源代码后作了一些比较小的改动,这里没有给出完整的例子,只是讨论一下核心的代码)
这里想说的代码主要是泛型DAO层的应用与分页的写法.

分页,采用了hibernate的一些API来分页,这里同时采用了两种分页方式,CriteriaPage分页方式,适用于多表单时查询后分页用的,而第二种方式是采用Hql语句查询后分页的.代码如下:

CriteriaPage.java文件:
package org.mmc.commons;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.impl.CriteriaImpl;
import org.hibernate.impl.CriteriaImpl.OrderEntry;
import org.mmc.utils.BeanUtils;

/**
 * 使用Hql查询的的分页查询类.
 * 支持执行Count查询取得总记录条数
 * 本类参考了springside项目的分页设计
 */
public class CriteriaPage {

    /**
     * 得到一个PageInstance实例,.
     */
    public static Page getPageInstance(Criteria criteria, int pageNo, int pageSize) {
      
            return CriteriaPage.getPageInstanceByCount(criteria, pageNo, pageSize);
    }

    /**
     * 以查询Count的形式获取totalCount的函数
     */
    protected static Page getPageInstanceByCount(Criteria criteria, int pageNo, int pageSize) {
        CriteriaImpl impl = (CriteriaImpl) criteria;

        //先把Projection和OrderBy条件取出来,清空两者来执行Count操作
        Projection projection = impl.getProjection();
        List<OrderEntry> orderEntries;
        try {
            orderEntries = (List) BeanUtils.getPrivateProperty(impl, "orderEntries");
            BeanUtils.setPrivateProperty(impl, "orderEntries", new ArrayList());
        }
        catch (Exception e) {
            throw new InternalError(" Runtime Exception impossibility throw ");
        }

        //执行查询
        int totalCount = (Integer) criteria.setProjection(Projections.rowCount()).uniqueResult();

        //将之前的Projection和OrderBy条件重新设回去
        criteria.setProjection(projection);
        if (projection == null) {
            criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
        }

        try {
            BeanUtils.setPrivateProperty(impl, "orderEntries", orderEntries);
        } catch (Exception e) {
            throw new InternalError(" Runtime Exception impossibility throw ");
        }

        return getPageResult(criteria, totalCount, pageNo, pageSize);
    }
   
    /**
     * 取得totalCount后,根据pageNo和PageSize, 执行criteria的分页查询,取得Page变量
     */
    private static Page getPageResult(Criteria criteria, int totalCount, int pageNo, int pageSize) {
        if (totalCount < 1) return new Page();

        int startIndex = Page.getStartOfPage(pageNo, pageSize);
        List list = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();

        return new Page(startIndex, totalCount, pageSize, list);
    }

}


HqlPage.java文件的代码
package org.mmc.commons;

import java.util.List;

import org.hibernate.Query;

/**
 * 使用Hql查询的的分页查询类.
 * 支持执行getCount查询取得总记录条数
 * 本类参考了springside项目的分页设计
 *
 * @author lighter
 * @see org.mmc.commons.Page
 */
public class HqlPage {


    public static Page getPageInstanceByCount(Query query, int pageNo, int pageSize, int totalCount) {
        return getPageResult(query, totalCount, pageNo, pageSize);
    }

    private static Page getPageResult(Query q, int totalCount, int pageNo, int pageSize) {
        if (totalCount < 1) return new Page();
        int startIndex = Page.getStartOfPage(pageNo, pageSize);
        List list = q.setFirstResult(startIndex).setMaxResults(pageSize).list();

        return new Page(startIndex, totalCount, pageSize, list);
    }
}

Page.java文件的源代码如下:
package org.mmc.commons;

import java.util.ArrayList;

/**
 * 分页对象. 包含数据及分页信息.
 *
 * @author lighter 天马行空
 */
public class Page implements java.io.Serializable {
 /**
  * 当前页第一条数据的位置,从0开始
  */
 private int start;

 /**
  * 每页的记录数
  */
 private int pageSize = Constants.DEFAULT_PAGE_SIZE;

 /**
  * 当前页中存放的记录
  */
 private Object data;

 /**
  * 总记录数
  */
 private int totalCount;

 /**
  * 构造方法,只构造空页
  */
 public Page() {
  this(0, 0, Constants.DEFAULT_PAGE_SIZE, new ArrayList());
 }

 /**
  * 默认构造方法
  *
  * @param start
  *            本页数据在数据库中的起始位置
  * @param totalSize
  *            数据库中总记录条数
  * @param pageSize
  *            本页容量
  * @param data
  *            本页包含的数据
  */
 public Page(int start, int totalSize, int pageSize, Object data) {
  this.pageSize = pageSize;
  this.start = start;
  this.totalCount = totalSize;
  this.data = data;
 }

 /**
  * 取数据库中包含的总记录数
  */
 public int getTotalCount() {
  return this.totalCount;
 }

 /**
  * 取总页数
  */
 public int getTotalPageCount() {
  if (totalCount % pageSize == 0)
   return totalCount / pageSize;
  else
   return totalCount / pageSize + 1;
 }

 /**
  * 取每页数据容量
  */
 public int getPageSize() {
  return pageSize;
 }

 /**
  * 当前页中的记录
  */
 public Object getResult() {
  return data;
 }

 /**
  * 取当前页码,页码从1开始
  */
 public int getCurrentPageNo() {
  return (start / pageSize) + 1;
 }

 /**
  * 是否有下一页
  */
 public boolean hasNextPage() {
  return (this.getCurrentPageNo() < this.getTotalPageCount() - 1);
 }

 /**
  * 是否有上一页
  */
 public boolean hasPreviousPage() {
  return (this.getCurrentPageNo() > 1);
 }

 /**
  * 获取任一页第一条数据的位置,每页条数使用默认值
  * 关键字设为pretected
  */
 protected static int getStartOfPage(int pageNo) {
  return getStartOfPage(pageNo, Constants.DEFAULT_PAGE_SIZE);
 }

 /**
  * 获取任一页第一条数据的位置,startIndex从0开始
  * 关键字设为pretected
  */
 protected static int getStartOfPage(int pageNo, int pageSize) {
  return (pageNo - 1) * pageSize;
 }
}


    分页的改造已经完成,现在重构一下DAO层的写法,利用了spring对hibernate支持的一些的API.
DAO层:
AbstractHibernateDao.java的源代码
package org.mmc.dao;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.mmc.utils.GenericsUtils;

import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 纯Hibernate Entity DAO基类.
 * 通过泛型,子类无需扩展任何函数即拥有完整的CRUD操作.
 *
 */
abstract public class AbstractHibernateDao<T> extends HibernateDaoSupport {

    protected Log logger = LogFactory.getLog(getClass());

    /**
     * Dao所管理的Entity类型.
     */
    protected Class<T> entityClass;

    /**
     * 取得entityClass的函数.
     * JDK1.4不支持泛型的子类可以抛开Class<T> entityClass,重新实现此函数达到相同效果。
     */
    protected Class getEntityClass() {
        return entityClass;
    }

    /**
     * 在构造函数中将泛型T.class赋给entityClass
     */
    public AbstractHibernateDao() {
        entityClass = GenericsUtils.getGenericClass(getClass());
    }

    public T get(Serializable id) {
        T o = (T) getHibernateTemplate().get(getEntityClass(), id);
        if (o == null)
            throw new ObjectRetrievalFailureException(getEntityClass(), id);
        return o;
    }

    public List<T> getAll() {
        return getHibernateTemplate().loadAll(getEntityClass());
    }

    public void save(Object o) {
        getHibernateTemplate().saveOrUpdate(o);
    }

    public void removeById(Serializable id) {
        remove(get(id));
    }

    public void remove(Object o) {
        getHibernateTemplate().delete(o);
    }

    public List<T> find(String hsql, Object... values) {
        if (values.length == 0)
            return getHibernateTemplate().find(hsql);
        else
            return getHibernateTemplate().find(hsql, values);
    }

    /**
     * 根据属性名和属性值查询对象.
     *
     * @return 符合条件的唯一对象
     */
    public T findUniqueBy(String name, Object value) {
        Criteria criteria = getSession().createCriteria(getEntityClass());
        criteria.add(Restrictions.eq(name, value));
        return (T) criteria.uniqueResult();
    }

    /**
     * 根据属性名和属性值查询对象.
     *
     * @return 符合条件的对象列表
     */
    public List<T> findBy(String name, Object value) {
        Assert.hasText(name);
        Criteria criteria = getSession().createCriteria(getEntityClass());
        criteria.add(Restrictions.eq(name, value));
        return criteria.list();
    }

    /**
     * 根据属性名和属性值以Like AnyWhere方式查询对象.
     */
    public List<T> findByLike(String name, String value) {
        Assert.hasText(name);
        Criteria criteria = getSession().createCriteria(getEntityClass());
        criteria.add(Restrictions.like(name, value, MatchMode.ANYWHERE));
        return criteria.list();
    }

    /**
     * 根据Map中过滤条件进行查询.
     *
     * @param filter        过滤条件.
     * @param criteriaSetup 将Map中条件转换为criteria的call back类
     */
    public List<T> findBy(Map filter, CriteriaSetup criteriaSetup) {
        Criteria criteria = getEntityCriteria();
        if (!CollectionUtils.isEmpty(filter)) {
            criteriaSetup.setup(criteria, filter);
        }
        return criteria.list();
    }

    /**
     * 函数作用同
{@link #findBy(Map,CriteriaSetup)}
     * 如果不需要分页,子类可直接重载此函数.
     */
    public List<T> findBy(Map filter) {
        return findBy(filter, getDefaultCriteriaSetup());
    }

    protected CriteriaSetup getDefaultCriteriaSetup() {
        return new CriteriaSetup() {
            public void setup(Criteria criteria, Map filter) {
                if (filter != null && !filter.isEmpty()) {
                    Set keys = filter.keySet();
                    for (Object key : keys) {
                        String value = (String) filter.get(key);
                        if (StringUtils.isNotBlank(value))
                            criteria.add(Restrictions.eq((String) key, value));
                    }
                }
            }
        };
    }

    /**
     * 取得Entity的Criteria.
     */
    protected Criteria getEntityCriteria() {
        return getSession().createCriteria(getEntityClass());
    }

    /**
     * 构造Criteria的排序条件默认函数.可供其他查询函数调用
     *
     * @param criteria Criteria实例.
     * @param sortMap  排序条件.
     * @param entity   entity对象,用于使用反射来获取某些属性信息
     */
    protected void sortCriteria(Criteria criteria, Map sortMap, Object entity) {
        if (!sortMap.isEmpty()) {
            for (Object o : sortMap.keySet()) {
                String fieldName = o.toString();
                String orderType = sortMap.get(fieldName).toString();

                //处理嵌套属性如category.name,modify_user.id,暂时只处理一级嵌套
                if (fieldName.indexOf('.') != -1) {
                    String alias = StringUtils.substringBefore(fieldName, ".");
                    String aliasType = alias;
                    try {
                        aliasType = PropertyUtils.getProperty(entity, alias).getClass().getSimpleName();
                    } catch (Exception e) {
                        logger.error("Get property" + alias + " error");
                    }
                    criteria.createAlias(aliasType, alias);
                }

                if ("asc".equalsIgnoreCase(orderType)) {
                    criteria.addOrder(Order.asc(fieldName));
                } else {
                    criteria.addOrder(Order.desc(fieldName));
                }
            }
        }
    }

    /**
     * 判断对象某列的值在数据库中不存在重复
     *
     * @param names 在POJO里相对应的属性名,列组合时以逗号分割<br>
     *              如"name,loginid,password"
     */
    public boolean isNotUnique(Object entity, String names) {
        Assert.hasText(names);
        Criteria criteria = getSession().createCriteria(entity.getClass()).setProjection(Projections.rowCount());
        String[] nameList = names.split(",");
        try {
            for (String name : nameList) {
                criteria.add(Restrictions.eq(name, PropertyUtils.getProperty(entity, name)));
            }

            String keyName = getSessionFactory().getClassMetadata(entity.getClass()).getIdentifierPropertyName();
            if (keyName != null) {
                Object id = PropertyUtils.getProperty(entity, keyName);
                //如果是update,排除自身
                if (id != null)
                    criteria.add(Restrictions.not(Restrictions.eq(keyName, id)));
            }
        }
        catch (Exception e) {
            logger.error(e.getMessage());
            return false;
        }
        return ((Integer) criteria.uniqueResult()) > 0;
    }
}

再建一个文件:
BaseHibernateDao.java
package org.mmc.dao;

import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.CriteriaSpecification;
import org.mmc.commons.CriteriaPage;
import org.mmc.commons.HqlPage;
import org.mmc.commons.Page;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

/**
 * Hibernate Entity Dao基类.
 * 扩展的分页函数,具体的分页代码在Page类中.
 *
 * @see AbstractHibernateDao
 * @see HqlPage
 * @see CriteriaPage
 */
abstract public class BaseHibernateDao<T> extends AbstractHibernateDao<T> {
    /**
     * 根据Map中过滤条件和分页参数进行分页查询.
     *
     * @param filterMap 过滤条件.
     * @param pageNo    当前页码
     * @param pageSize  每页显示记录数.
     */
    public Page findBy(Map filterMap, int pageNo, int pageSize) {
        return findBy(filterMap, null, pageNo, pageSize);
    }

    /**
     * 根据Map中过滤条件,排序条件和分页参数进行分页查询.
     *
     * @param filterMap 过滤条件.
     * @param orderMap  排序条件.
     * @param pageNo    当前页码
     * @param pageSize  每页显示记录数.
     */
    public Page findBy(Map filterMap, Map orderMap, int pageNo, int pageSize, CriteriaSetup criteriaSetup) {
        Criteria criteria = getSession().createCriteria(getEntityClass());

        if (!CollectionUtils.isEmpty(filterMap)) {
            try {
                criteriaSetup.setup(criteria, filterMap);
            } catch (Exception e) {
            }
        }

        if (!CollectionUtils.isEmpty(orderMap))
            sortCriteria(criteria, orderMap, null);

        criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);

        return pagedQuery(criteria, pageNo, pageSize);
    }

    public Page findBy(Map filterMap, Map orderMap, int pageNo, int pageSize) {
        return findBy(filterMap, orderMap, pageNo, pageSize, getDefaultCriteriaSetup());
    }

    /**
     * Criteria分页查询,采用了getCount模式
     */
    public Page pagedQuery(Criteria criteria, int pageNo, int pageSize) {
        return CriteriaPage.getPageInstance(criteria, pageNo, pageSize);
    }

    /**
     * HQL分页查询,可以指定具体的模式,
     * 采用getCount方式,须在此层完成hsql的转换与查询。
     * 注意参数Object...args的应用,可以在查询的设置查询条件用的(JDK5.0语法)
     */
    public Page pagedQuery(String hql, int pageNo, int pageSize, Object... args) {
        Assert.hasText(hql);
        Query query = getSession().createQuery(hql);
        for (int i = 0; i < args.length; i++) {
            query.setParameter(i, args[i]);
        }
            String countQueryString = " select count (*) " + removeSelect(removeOrders(hql));
            List countlist = getHibernateTemplate().find(countQueryString, args);
            int totalCount = (Integer) countlist.get(0);
            return HqlPage.getPageInstanceByCount(query, pageNo, pageSize, totalCount);
    }

    /**
     * 去除select 子句,未考虑union的情况
     */
    private static String removeSelect(String hql) {
        Assert.hasText(hql);
        int beginPos = hql.toLowerCase().indexOf("from");
        Assert.isTrue(beginPos != -1, " hql : " + hql + " must has a keyword 'from'");
        return hql.substring(beginPos);
    }

    /**
     * 去除orderby 子句
     */
    private static String removeOrders(String hql) {
        Assert.hasText(hql);
        Pattern p = Pattern.compile("order//s*by[//w|//W|//s|//S]*", Pattern.CASE_INSENSITIVE);
        Matcher m = p.matcher(hql);
        StringBuffer sb = new StringBuffer();
        while (m.find()) {
            m.appendReplacement(sb, "");
        }
        m.appendTail(sb);
        return sb.toString();
    }
}
 

 BaseHibernateDAO负责抽象一个Entity 的CRUD函数。

  所有子类只要声明如下,即拥有如下函数:

public class UserDAO extends BaseHibernateDao<User>
  • protected final Log logger
  • public Object get(Serializable id)
  • public List getAll()
  • public void save(Object o)
  • public void remove(Serializable id)
  • public void remove(Object o)
  • public List find(String hql)
  • public List find(String hql,Object value)
  • public List find(String hql,object[])
  • public Object findBy(String name,Object value)
  • public List findAllBy(String name,Object value)
  • public List findAllByLike(String name,Object value)
  • public List findAllBy(Map filter)

    上面只是简单的说了一下的springside项目源代码的一些优雅的地方,如果有需要的要求的话,我会贴出完整的一个简单例子的demo的,包括分页的与泛型DAO的应用.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值