好久没有更新博客了,最近一段时间工作比较忙,所以请见谅,无论你是爱看呢还是爱看呢还是爱看呢,总之或许对你有些帮助。
DAO(Data Access Object)是一个数据访问(顾名思义就是与数据库打交道)接口,DAO一般在业务逻辑与数据库资源之间,是我们访问数据库的桥梁。
在核心J2EE模式中是这样介绍DAO模式的:为了建立一个健壮的J2EE应用,应该将所有对数据源的访问操作抽象封装在一个公共API中。用程序设计的语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口在逻辑上对应这个特定的数据存储。
今天就说一下在项目代码开发过程中经常会遇到的DAO方面问题:
1.项目中模块众多,传统做法是每个模块编写一个独立的DAO接口及实现。这种情况下模块之间功能往往相似(传统增删改查),所以给程序员开发工作量上带来了不小的负担,而且维护起来也非常困难。
2.采用1方式编写众多DAO接口,这些编写好的代码只能在本系统中使用,移植到其他系统中相当于重写,所以利用率非常低。
3.一旦某个业务逻辑变更,带来的会是灾难性的代码修改问题,程序员需要逐个类的去修改每一个方法,难免会有遗漏和错误。
4.每个程序员编写习惯及规范性的差异导致每个接口中定义的类名,方法名,参数名等等不一致,甚至千奇百怪。
..........
等等。
为了避免以上一些问题并且发挥出高级编程语言的高度复用性的优点,我们可以将具有相同特征、特性的DAO接口封装为一个公用或基础DAO,我们给这个DAO接口起名为CommonDAO。
在CommonDAO中将共用方法(增删改查)提取,然后其他方法调用此DAO即可完成相同作用的工作,这样就节省了共用方法的这部分开发时间,而且维护起来也非常方便,下面就开始代码部分的讲解。
1.定义CommonDAO接口,代码如下:
/** * * @description 公共DAO * @author ming.li * @modify ming.li * @modifyDate 2014-1-6 下午12:29:21 * @notes 未填写备注 * @version 1.0.0 * */ public interface CommonDAO{ /** * * @description 添加 * @param o * @return * @returnType Integer * @exception * @since 1.0.0 */ Integer add(Object o); /** * * @description 删除 * @param id * @param clazz * @returnType void * @exception * @since 1.0.0 */ boolean delete(Integer id,Class clazz); /** * * @description 修改 * @param id * @param o * @returnType void * @exception * @since 1.0.0 */ boolean modify(Integer id,Object o); /** * * @description 详情 * @param id * @param clazz * @return * @returnType Object * @exception * @since 1.0.0 */ Object detail(Integer id,Class clazz); /** * * @description 根据QuerySet查询列表 * @param qs * @param startIndex * @param pageSize * @return * @returnType ResultSet * @exception * @since 1.0.0 */ ResultSet queryByList(QuerySet qs, int startIndex, int pageSize); }
接口比较简单,含有增删改查几种基本方法。这里需要重点说下ResultSet queryByList(QuerySet qs, int startIndex, int pageSize);这个方法,我将查询参数与返回结果进行了封装,代码如下:
2.QuerySet类:
/** * * @description 查询参数集 * @author ming.li * @modify ming.li * @modifyDate 2014-1-3 下午03:59:27 * @notes 未填写备注 * @version 1.0.0 * */ public class QuerySet implements java.io.Serializable { /** * 模糊查询对象 */ private Object fuzzyObject; /** * 相等查询对象 */ private Object exactObject; /** * 自定义查询参数 */ private String param; /** * 排序 */ private String order; public String getParam() { if (StringUtils.hasText(param)) { return param; } return ""; } public String getOrder() { if (StringUtils.hasText(order)) return order; else return ""; } /** 省略部分get/set方法 **/ }
3.ResultSet类:
import java.util.List; /** * * @description 查询结果集 * @author ming.li * @modify ming.li * @modifyDate 2014-1-3 下午03:15:56 * @notes 未填写备注 * @version 1.0.0 * */ public class ResultSet implements java.io.Serializable{ /** * 查询结果列表 */ private List resultList; /** * 记录总数 */ private int count; private ResultSet(List resultList, int count) { this.resultList = resultList; this.count = count; } /** * * @description 获取结果集 * @param resultList * @param count * @return * @returnType ResultSet * @exception * @since 1.0.0 */ public static ResultSet getResultSet(List resultList, int count) { return new ResultSet(resultList, count); } /** 省略部分get/set方法 **/ }
4.然后我们实现CommonDAO接口,实现类为CommonDAOImpl,代码如下:
import java.sql.SQLException; import java.util.List; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.Session; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import com.epro.uams.common.util.CollectionUtils; import com.epro.uams.common.util.DAOUtils; import com.epro.uams.common.vo.query.QuerySet; import com.epro.uams.common.vo.query.ResultSet; import com.epro.uams.dao.CommonDAO; /** * * @description 公共DAO * @author ming.li * @modify ming.li * @modifyDate 2014-1-6 下午12:32:56 * @notes 未填写备注 * @version 1.0.0 * */ public class CommonDAOImpl extends HibernateDaoSupport implements CommonDAO{ public Integer add(Object o) { return (Integer) this.getHibernateTemplate().save(o); } public boolean modify(Integer id, Object o) { Object target = getHibernateTemplate().get(o.getClass(), id); if (target != null) { DAOUtils.setParam(o, target); getHibernateTemplate().update(target); return true; } return false; } public boolean delete(Integer id, Class clazz) { Object target = getHibernateTemplate().get(clazz, id); if (target != null) { getHibernateTemplate().delete(target); return true; } return false; } public Object detail(Integer id, Class clazz) { return getHibernateTemplate().get(clazz, id); } public ResultSet queryByList(QuerySet qs, final int startIndex, final int pageSize) { final String hql = DAOUtils.getHql(qs); List result =this.getHibernateTemplate().executeFind(new HibernateCallback<Object>() { public Object doInHibernate(Session session) throws HibernateException, SQLException { Query query = session.createQuery(hql); query.setFirstResult(startIndex); query.setMaxResults(pageSize); return query.list(); } }); final String countHql="select count(*) "+hql; int count = (int) this.getHibernateTemplate().execute(new HibernateCallback<Integer>() { public Integer doInHibernate(Session session) throws HibernateException, SQLException { Query query = session.createQuery(countHql); List result = query.list(); if (!CollectionUtils.isEmpty(result)) return Integer.parseInt(result.get(0).toString()); else return 0; } }); return ResultSet.getResultSet(result, count); } }
代码看不懂不要紧,接下来我慢慢讲解。
1)定义一个公共接口CommonDAO,里面含有共用方法,这点大家应该都应该理解。
2)CommonDAO里的参数及返回值都是Object类型,这样可以为所有对象使用。
3)我将查询参数与查询返回结果进行了封装,在查询参数对象QuerySet中放入了一个模糊查询对象,一个精确查询对象以及其他参数属性和排序。
下面解释下模糊查询对象与精确查询对象,其实他们的作用就是作为动态传参来用的,以往的查询方法例如:User queryUserInfo(Integer usrId,String name,int age.......等等参数),然后我们在queryUserInfo方法实现中会判断不同的参数是否存在,最后利用StringBuffer动态拼接一个HQL或者SQL进行查询。
我想这样做过的朋友非常多吧,一旦参数很多或逻辑比较复杂程序员就崩溃了,采用了上面的两种对象后,我们只需要把想要查询的属性赋值后放置在QuerySet中即可,然后利用工具方法(后面讲解)进行动态拼装查询语句。
示例:
User(用户信息)类,含有以下属性:
private Integer userId; private Integer type; private String name; private String tel; private String mobile; private String description; private String email; private Date createDate;
如果我想根据name和emal查询该用户只需要:
User user=new User(); user.SetName("g21121"); user.SetEmail("g21121"); QuerySet qs=new QuerySet(); //根据对象的属性模糊查询 qs.setFuzzyObject(user); //根据对象的属性精确查询 qs.setExactObject(user);
最后调用查询方法queryByList(QuerySet qs, int startIndex, int pageSize)即可,返回结果会放置在ResultSet中。
下面是DAOUtils的代码,其中基本为利用反射进行不同对象间赋值,根据对象属性动态组装查询语句等:
import java.lang.reflect.Field; /** * * @description DAO工具类 * @author ming.li * @modify ming.li * @modifyDate 2014-1-7 下午02:56:14 * @notes 未填写备注 * @version 1.0.0 * */ public class DAOUtils { /** * * @description 动态生成HQL * @param o * @return * @throws IllegalArgumentException * @throws IllegalAccessException * @returnType String * @exception * @since 1.0.0 */ public static String getHql(QuerySet qs) { String tableName = ""; if (qs.getExactObject() != null) { tableName = qs.getExactObject().getClass().getSimpleName(); } else if (qs.getFuzzyObject() != null) { tableName = qs.getFuzzyObject().getClass().getSimpleName(); } else { return ""; } // 初始hql语句 String hql = "from " + tableName + " "; // 精确查询条件 String eql = getExactHql(qs.getExactObject()); // 模糊查询条件 String fql = getFuzzyHql(qs.getFuzzyObject()); // 自定义参数 String param = qs.getParam(); // 排序 String order = qs.getOrder(); if (StringUtils.hasText(eql) && StringUtils.hasText(fql)) { // 两种条件均存在 return hql + " where " + eql + " and (" + fql + ") " + getParam(param) + " " + order; } else if (StringUtils.hasText(eql) && !StringUtils.hasText(fql)) { // 只有精确查询条件 return hql + " where " + eql + getParam(param) + " " + order; } else if (!StringUtils.hasText(eql) && StringUtils.hasText(fql)) { // 只有模糊查询条件 return hql + " where " + "(" + fql + ") " + getParam(param) + " " + order; } else { return hql; } } /** * * @description 获取额外参数 * @param param * @return * @returnType String * @exception * @since 1.0.0 */ private static String getParam(String param) { if (StringUtils.hasText(param)) { int hasAnd = param.trim().toUpperCase().indexOf("AND"); if (hasAnd == 0) { return " " + param; } else { return " and " + param; } } return ""; } /** * * @description 获取模糊查询条件 * @param fuzzyObject * @return * @returnType String * @exception * @since 1.0.0 */ private static String getFuzzyHql(Object fuzzyObject) { if (fuzzyObject != null) { // 模糊查询对象 Class fuzzyClass = fuzzyObject.getClass(); // 获取模糊查询的属性 try { StringBuffer sb = new StringBuffer(""); // 是否含有查询条件 // 获取属性列表 Field[] fs = fuzzyClass.getDeclaredFields(); // 循环添加属性查询条件 for (Field f : fs) { f.setAccessible(true); Object value = f.get(fuzzyObject); String name = f.getName(); if (value != null) { sb.append(" or " + name + " like '%" + value + "%'"); } } // 判断是否含有查询条件 String fql = sb.toString(); if (StringUtils.hasText(fql) && fql.length() > 3) return fql.substring(3); } catch (Exception e) { e.printStackTrace(); } } return ""; } /** * * @description 获取精确查询条件 * @param exactObject * @return * @returnType String * @exception * @since 1.0.0 */ private static String getExactHql(Object exactObject) { if (exactObject != null) { // 精确查询对象 Class exactClass = exactObject.getClass(); // 取出需要准确查询的属性 try { StringBuffer sb = new StringBuffer(""); // 获取属性列表 Field[] fs = exactClass.getDeclaredFields(); // 循环添加属性查询条件 for (Field f : fs) { f.setAccessible(true); Object value = f.get(exactObject); String name = f.getName(); if (value != null) { if (f.getType().getName().equals("java.lang.String")) { sb.append(" and " + name + "='" + value + "'"); } else { sb.append(" and " + name + "=" + value); } } } // 判断是否含有查询条件 String eql = sb.toString(); if (StringUtils.hasText(eql) && eql.length() > 3) return eql.substring(4); } catch (Exception e) { e.printStackTrace(); } } return ""; } /** * * @description 设置要修改内容 * @param source * @param target * @return * @returnType Object * @exception * @since 1.0.0 */ public static Object setParam(Object source, Object target) { Class sClazz = source.getClass(); Class tClazz = target.getClass(); try { // 获取属性列表 Field[] fs = sClazz.getDeclaredFields(); for (Field f : fs) { f.setAccessible(true); Object value = f.get(source); String name = f.getName(); if (value != null) { Field tf = tClazz.getDeclaredField(name); tf.setAccessible(true); tf.set(target, value); } } } catch (Exception e) { e.printStackTrace(); } return target; } /** * * @description 查询Set VO转换成PO * @param qs * @param clazz * @returnType void * @exception * @since 1.0.0 */ public static void convertQuerySet(QuerySet qs, Class clazz) { if (qs != null) { try { // 精确查询对象 if (qs.getExactObject() != null) { Object exact = clazz.newInstance(); setParam(qs.getExactObject(), exact); qs.setExactObject(exact); } // 模糊查询对象 if (qs.getFuzzyObject() != null) { Object fuzzy = clazz.newInstance(); setParam(qs.getFuzzyObject(), fuzzy); qs.setFuzzyObject(fuzzy); } } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } /** * * @description 去除动态拼接hql的最后几位 * @param hql * @return * @returnType String * @exception * @since 1.0.0 */ public static String trimLastChar(String hql, int size) { return hql.substring(0, hql.length() - size); } }
以上就是所有核心代码,有不明白或错误的地方可以直接回帖。