该帖已经被评为隐藏帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-09-20
二、Dao层 Dao层是数据化持久层,以前我们习惯使用JDBC做链接,现在我们使用JPA,结合Spring的优势,使用连接池来配置、以及与数据库的同步!我们使用JAP+Spring,只需要建立数据库即可以,使用所谓的“逆向工程”——老程序员们都这样称呼它,我觉得这样才是真正的面向对象的设计。 1、基础抽象接口DAO,以后让所对象的Dao都来实现这个借口。 对于一个dao层来说,是处理Service传递进来的数据与数据库同步的,所以一般的方法就是CRUD的方法,对于每一种对象来说,都是需要进行增删改查,然而在Model层中,不同的对象经过JPA的映射之后会生成不同的表,所以我们dao层就需要针对不同的对象都有增删改查,所以使用反射式比较适合的选择(这个抽象类中包含了通用的CRUD的方法)。 该类是其他所有Dao的接口,应该具备以下几个通用的操作:
1.//增加一个实体对象 public abstract void add(T paramT); 2.//删除一个实体 public abstract void delete(Integer paramInteger); 3.//修改一个对象 public abstract void modify(T paramT); 4.//查询单个对象(通过Model.id) public abstract T query(Integer paramInteger); 5.//分页查询 public abstract ModelSet<T> queryAll(int firstindex, int maxresult, String wherejpql, Object[] queryParams, LinkedHashMap<String, String> orderby); 6.//Compass全文检索 public abstract List<T> search(String paramString); 7.//反射获取Class public abstract Class<T> getModelClass();
//参见如下的代码。 package com.jxs.sys.core.base.dao; import java.util.LinkedHashMap; import java.util.List; import com.jxs.sys.core.base.model.Model; import com.jxs.sys.core.base.model.ModelSet; /** * * @目的 数据持久层接口 * @时间 Apr 24, 2010 * @作者 BestUpon * @邮箱 bestupon@foxmail.com * * @param <T> */ public abstract interface Dao<T extends Model> { public abstract void add(T paramT); public abstract void delete(Integer paramInteger); public abstract void modify(T paramT); public abstract T query(Integer paramInteger); public abstract ModelSet<T> queryAll(int firstindex, int maxresult, String wherejpql, Object[] queryParams, LinkedHashMap<String, String> orderby); public abstract List<T> search(String paramString); public abstract Class<T> getModelClass(); } 2、写一个真正的处理数据的Dao层类-DaoOperation DaoOperation 这个类是真正的处理和数据库同步的类,由于们使用的JPA的Hibernate实现,所以我们要构建一个实体管理器,EnteryManager 例如:
//持久化上下文 @PersistenceContext protected EntityManager em; 使用这个实体管理器去操作所有的实体对象。
我们针对public abstract interface Dao<T extends Model>{}这个类中的所有方法,要在DaoOperation 这个类中去真正的操作数据,所以我们要对外公开一下几个方法:
1.//删除实体对象 public <T> void delete(Class<T> entityClass, Object entityid); 2.//查询试题对象 public <T> T find(Class<T> entityClass, Object entityId); 3.//持久化实体对象 public void save(Object object); 4.//统计实体对象个数 public <T> int getCount(Class<T> entityClass); 5.//修改更新实体对象 public void update(Object object) 6.//分页+排序查询 public <T> ModelSet<T> getScrollData(Class<T> entityClass, int firstindex, int maxresult, LinkedHashMap<String, String> orderby); 7.//分页+JPQL 查询 public <T> ModelSet<T> getScrollData(Class<T> entityClass, int firstindex, int maxresult, String wherejpql, Object[] queryParams); 8.//单纯分页整体查询 public <T> ModelSet<T> getScrollData(Class<T> entityClass, int firstindex, int maxresult); 9.//无分页,整体查询 public <T> ModelSet<T> getScrollData(Class<T> entityClass); 10.//分页+JPQL+排序查询 public <T> ModelSet<T> getScrollData(Class<T> entityClass, int firstindex, int maxresult, String wherejpql, Object[] queryParams, LinkedHashMap<String, String> orderby); 这样一个底层持久化操作类,实现了所有的同步操作。 11.//清缓存方法 clear();
还有两个属性:
//ehCache缓存管理器 @Resource(name = "ehCache") private Cache cache; //Compass搜索索引管理器 @Resource(name = "indexManager") private IndexManager indexManager; 说明:上面有有个ModelSet,这个对象是是查询到的数据的集合,大家想想应该这么设计呢?
我是这样设计的:
1.//将查询到的结果转换成一个这个对象的List集合,方便前台,操作(例如Struts2标签中的操作,DisplayTag显示数据的需要数据等) private List<T> resultlist = new ArrayList<T>(); 2.//返回一个总体记录数,分页等需要 private long totalrecord = 0L; 3.//查询判断一些不需要的对象在里面,或者需要的对象在里面,这样过滤一些对象的时候需要 private List<String> includeids = new ArrayList<String>(); 上面的方法都给出了,接下来就需要对其实现了,怎么个实现法呢?——很简单,就是拼JPQL查询字符串。 实现代码,参见如下:
package com.jxs.sys.core.base.dao; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.util.LinkedHashMap; import javax.annotation.Resource; import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import net.sf.ehcache.Cache; import org.hibernate.ejb.QueryImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.jxs.sys.core.base.model.ModelSet; import com.jxs.sys.core.global.cache.ClearCache; import com.jxs.sys.core.global.config.utils.ConfigHolder; import com.jxs.sys.core.search.compass.IndexManager; /** * *@TO 数据同步基础类 *@des *@author BestUpon *@date Sep 20, 2010 4:31:20 PM *@version since 1.0 */ @Transactional public abstract class DaoOperation { protected final Logger log = LoggerFactory.getLogger(super.getClass()); @PersistenceContext protected EntityManager em; @Resource(name = "ehCache") private Cache cache; @Resource(name = "indexManager") private IndexManager indexManager; public void clear() { this.em.clear(); } private <T> void del(Class<T> entityClass, Object entityid) { this.em.remove(this.em.getReference(entityClass, entityid)); } @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED) public <T> void delete(Class<T> entityClass, Object entityid) { del(entityClass, entityid); if (isIndexable()) { this.indexManager.deleteIndex(entityClass, entityid); } if (isOperationSearchResult()) { this.log.info("删除对象,删除搜索缓存"); ClearCache.clear(this.cache, "search" + entityClass.getName()); } } @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED) public <T> T find(Class<T> entityClass, Object entityId) { return this.em.find(entityClass, entityId); } public void save(Object object) { this.em.persist(object); if (isIndexable()) this.indexManager.createIndex(object); } @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED) public <T> int getCount(Class<T> entityClass) { javax.persistence.Query query = this.em.createQuery("select count(" + getCountField(entityClass) + ") from " + getEntityName(entityClass) + " o"); setQueryCache(query); return ((Integer) query.getSingleResult()).intValue(); } public void update(Object object) { this.em.merge(object); if (isOperationSearchResult()) { this.log.info("更新对象,删除搜索缓存"); ClearCache.clear(this.cache, "search" + object.getClass().getName()); } if (isIndexable()) this.indexManager.updateIndex(object); } @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED) public <T> ModelSet<T> getScrollData(Class<T> entityClass, int firstindex, int maxresult, LinkedHashMap<String, String> orderby) { return getScrollData(entityClass, firstindex, maxresult, null, null, orderby); } @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED) public <T> ModelSet<T> getScrollData(Class<T> entityClass, int firstindex, int maxresult, String wherejpql, Object[] queryParams) { return getScrollData(entityClass, firstindex, maxresult, wherejpql, queryParams, null); } @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED) public <T> ModelSet<T> getScrollData(Class<T> entityClass, int firstindex, int maxresult) { return getScrollData(entityClass, firstindex, maxresult, null, null, null); } @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED) public <T> ModelSet<T> getScrollData(Class<T> entityClass) { return getScrollData(entityClass, -1, -1); } @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED) public <T> ModelSet<T> getScrollData(Class<T> entityClass, int firstindex, int maxresult, String wherejpql, Object[] queryParams, LinkedHashMap<String, String> orderby) { return queryData(entityClass, firstindex, maxresult, wherejpql, queryParams, orderby); } private void setQueryCache(javax.persistence.Query query) { if ((!(isCacheable())) || (!(query instanceof QueryImpl))) return; ((QueryImpl) query).getHibernateQuery().setCacheable(true); } private <T> ModelSet<T> queryData(Class<T> entityClass, int firstindex, int maxresult, String wherejpql, Object[] queryParams, LinkedHashMap<String, String> orderby) { ModelSet<T> qr = new ModelSet<T>(); String entityname = getEntityName(entityClass); javax.persistence.Query query = this.em.createQuery("select o from " + entityname + " o " + ((wherejpql == null) ? "" : new StringBuilder("where ").append(wherejpql).toString()) + buildOrderby(orderby)); setQueryParams(query, queryParams); if ((firstindex != -1) && (maxresult != -1)) { query.setFirstResult(firstindex).setMaxResults(maxresult); } setQueryCache(query); qr.setResultlist(query.getResultList()); query = this.em.createQuery("select count(" + getCountField(entityClass) + ") from " + entityname + " o " + ((wherejpql == null) ? "" : new StringBuilder("where ").append(wherejpql).toString())); setQueryParams(query, queryParams); setQueryCache(query); qr.setTotalrecord(((Long) query.getSingleResult()).longValue()); return qr; } protected void setQueryParams(javax.persistence.Query query, Object[] queryParams) { if ((queryParams != null) && (queryParams.length > 0)) for (int i = 0; i < queryParams.length; ++i) query.setParameter(i + 1, queryParams[i]); } protected String buildOrderby(LinkedHashMap<String, String> orderby) { StringBuffer orderbyql = new StringBuffer(""); if ((orderby != null) && (orderby.size() > 0)) { orderbyql.append(" order by "); for (String key : orderby.keySet()) { orderbyql.append("o.").append(key).append(" ").append((String) orderby.get(key)).append(","); } orderbyql.deleteCharAt(orderbyql.length() - 1); } return orderbyql.toString(); } protected <T> String getEntityName(Class<T> entityClass) { String entityname = entityClass.getSimpleName(); Entity entity = (Entity) entityClass.getAnnotation(Entity.class); if ((entity.name() != null) && (!("".equals(entity.name())))) { entityname = entity.name(); } return entityname; } protected <T> String getCountField(Class<T> clazz) { String out = "o"; try { PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors(); for (PropertyDescriptor propertydesc : propertyDescriptors) { Method method = propertydesc.getReadMethod(); if ((method != null) && (method.isAnnotationPresent(EmbeddedId.class))) { PropertyDescriptor[] ps = Introspector.getBeanInfo(propertydesc.getPropertyType()).getPropertyDescriptors(); out = "o." + propertydesc.getName() + "." + ((!(ps[1].getName().equals("class"))) ? ps[1].getName() : ps[0].getName()); break; } } } catch (Exception e) { e.printStackTrace(); } return out; } public static boolean isCacheable() { return ConfigHolder.getConfig().isUseCache(); } public static boolean isIndexable() { return ConfigHolder.getConfig().isUseIndex(); } public static boolean isOperationSearchResult() { return ConfigHolder.getConfig().isOperationSearchResult(); } } 大家也学觉得很莫名其妙,为什么只给出两个抽象类呢?接下来我们将这两个类“串起来”,看看会有什么效果呢?我先给出类来,大家看看,要怎么实现呢?public abstract class DaoSupport<T extends Model> extends DaoOperation implements Dao<T> {}
也学大家会很奇怪,怎么又一个抽象类呢?能不能弄点新鲜玩意,就会写抽象类呢?嘿嘿。。。慢慢向下看。 看到了没有,上面有个:implements Dao<T>,这就意味着,在这个类中就Dao 这几个方法,如果让你实现反射的话,或许有更好的方法,个人是这样实现的,利用一下构造方法。
public DaoSupport() { this.modelClass = ReflectionUtils.getSuperClassGenricType(super.getClass()); }这样做的有什么好处呢?巧妙的运用的Spring的注入的时候,利用空构造函数实例化一个对象,巧借给这个对象的modelClass 赋值。 这里主要是讲解一种思路,具体的反射,如有需要,以后在讨论。 由于前面的DaoOperation这个类已经要将做的所有事情都做完了,这里直接使用super.xxx(xxx);这样的方式很轻松的就做好了。参见如下代码: package com.jxs.sys.core.base.dao; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import javax.annotation.Resource; import net.sf.ehcache.Cache; import net.sf.ehcache.Element; import org.apache.commons.beanutils.BeanComparator; import org.apache.commons.lang.StringUtils; import org.compass.core.Compass; import org.compass.core.CompassHits; import org.compass.core.CompassSession; import org.compass.core.CompassTemplate; import org.perf4j.aop.Profiled; import com.jxs.sys.core.base.event.AddEvent; import com.jxs.sys.core.base.event.ModifyEvent; import com.jxs.sys.core.base.listeners.AuditListener; import com.jxs.sys.core.base.model.Model; import com.jxs.sys.core.base.model.ModelSet; import com.jxs.sys.core.base.utils.ReflectionUtils; import com.jxs.sys.core.base.utils.WebUtil; import com.jxs.sys.core.global.cache.ClearCache; import com.jxs.sys.core.security.model.User; import com.jxs.sys.core.security.userholder.UserHolder; /** * * @TO 数据操作支持类 * @des * @author BestUpon * @date Sep 20, 2010 4:33:28 PM * @version since 1.0 * @param <T> */ public abstract class DaoSupport<T extends Model> extends DaoOperation implements Dao<T> { @Resource(name = "compassTemplate") private CompassTemplate compassTemplate; @Resource(name = "ehCache") private Cache cache; /** * 这个属性是权限管理用的,这里不需要管他 */ @Resource(name = "auditListener") private AuditListener auditListener; private Class<T> modelClass; @Profiled(tag = "DaoSupport") public DaoSupport() { this.modelClass = ReflectionUtils.getSuperClassGenricType(super.getClass()); } public Class<T> getModelClass() { return this.modelClass; } @Profiled(tag = "addInDao", message = "model = {$0}") public void add(T model) { AddEvent addEvent = new AddEvent(model); this.auditListener.onEvent(addEvent, this); super.save(model); } @Profiled(tag = "deleteInDao", message = "modelId = {$0}") public void delete(Integer modelId) { super.delete(getModelClass(), modelId); } @Profiled(tag = "modifyInDao", message = "model = {$0}") public void modify(T model) { ModifyEvent modifyEvent = new ModifyEvent(model); this.auditListener.onEvent(modifyEvent, this); super.update(model); } @Profiled(tag = "queryInDao", message = "modelId = {$0}") public T query(Integer modelId) { return (T) ((Model) super.find(getModelClass(), modelId)); } @Profiled(tag = "queryAllInDao", message = "firstindex = {$0}, maxresult = {$1}, wherejpql = {$1}, queryParams = {$1}, orderby = {$1}") public ModelSet<T> queryAll(int firstindex, int maxresult, String wherejpql, Object[] queryParams, LinkedHashMap<String, String> orderby) { return super.getScrollData(getModelClass(), firstindex, maxresult, wherejpql, queryParams, orderby); } @Profiled(tag = "searchInDao", message = "queryString = {$0}") public List<T> search(String queryString) { User user = UserHolder.getCurrentLoginUser(); ModelSet<T> qr = null; Element element = null; Compass compass = this.compassTemplate.getCompass(); CompassSession session = compass.openSession(); List models = null; CompassHits hits = session.find(queryString); this.log.info("命中:" + hits.getLength()); this.log.info("查询字符串:" + queryString); models = hightlight(hits); session.close(); Comparator comparter = new BeanComparator("id"); Collections.sort(models, comparter); Collections.reverse(models); qr = new ModelSet(); qr.setResultlist(models); qr.setTotalrecord(models.size()); ClearCache.clear(this.cache, user.getCacheName() + "search" + getModelClass().getName()); element = new Element(user.getCacheName() + "search" + getModelClass().getName(), qr); this.cache.put(element); return models; } @Profiled(tag = "hightlightInDao", message = "hits = {$0}") private List<T> hightlight(CompassHits hits) { List models = new ArrayList(); for (int i = 0; i < hits.length(); ++i) { Model model = null; if (hits.data(i).getClass() == getModelClass()) { model = (Model) hits.data(i); for (String searchProperty : model.getSearchProperties()) { try { String[] multiLevelProperties = searchProperty.split(":"); String value = hits.highlighter(i).fragment(multiLevelProperties[0]); if (!(StringUtils.isEmpty(value))) { String[] searchExpressions = multiLevelProperties[0].split("_"); String realProperty = searchExpressions[(searchExpressions.length - 1)]; String[] properties = (String[]) null; if (multiLevelProperties.length > 1) { properties = multiLevelProperties[1].split("_"); } List<Model> objs = new ArrayList<Model>(); objs.add(model); if (properties != null) { for (String props : properties) { List now = new ArrayList(); for (Model temp : objs) { if (props.endsWith("$")) { List temps = (List) ReflectionUtils.getFieldValue(temp, props.substring(0, props.length() - 1)); now.addAll(temps); } else { Model next = (Model) ReflectionUtils.getFieldValue(temp, props); now.add(next); } } objs = now; } } for (Model obj : objs) try { Object o = ReflectionUtils.getFieldValue(obj, realProperty); if (o != null) { String oldValue = o.toString(); String newValue = WebUtil.removeHightlight(value); if ((StringUtils.isNotEmpty(oldValue)) && (StringUtils.isNotEmpty(newValue)) && (newValue.equals(oldValue))) ReflectionUtils.setFieldValue(obj, realProperty, value); } } catch (Exception e) { this.log.info("添加高亮,给对象【" + obj.getMetaData() + "】设置属性【" + realProperty + "】失败,值为:【" + value + "】"); } } } catch (Exception e) { this.log.info("处理" + searchProperty + "高亮抛出异常,忽略,原因:" + e.getCause()); } } models.add(model); } else { this.log.info("搜索出不是" + getModelClass() + "的实例" + hits.data(i)); } } return models; } } 那么其他的对象的Dao需要怎么做呢?
UserDao package com.jxs.sys.core.security.dao; import com.jxs.sys.core.base.dao.Dao; import com.jxs.sys.core.security.model.User; public abstract interface UserDao extends Dao<User> { public abstract User queryUserByName(String paramString); } 那么他的实现呢? package com.jxs.sys.core.security.dao.jpa; import java.util.List; import org.springframework.stereotype.Repository; import com.jxs.sys.core.base.dao.DaoSupport; import com.jxs.sys.core.security.dao.UserDao; import com.jxs.sys.core.security.model.User; @Repository("userDao") public class UserDaoJpa extends DaoSupport<User> implements UserDao { public User queryUserByName(String userName) { String wherejpql = " o.username=?1"; String[] par = new String[]{userName}; this.log.info("查找username为 " + userName + " 的用户"); List<User> users = super.getScrollData(User.class, -1, -1, wherejpql, par).getResultlist(); if ((users == null) || (users.size() != 1)) { this.log.info("不存在用户名为 【" + userName + "】的用户"); return null; } return ((User) users.get(0)); } }
是不是很简单呢?几乎 不需要你写什么代码,所有的CURD的方法都有了! 为什么要举这个例子呢? 1、前面的所有例子都是使用CRUD的简单例子,现在多了一个业务逻辑——按UserName查询?怎么做呢? 很简单,看见没有,UserDao. queryUserByName(String username);就是例子,在UserDaoJpa. queryUserByName(String username);将其实现了,就好了。一般的业务逻辑都是查询,增加一般都是逐条记录的增加。这样是不是很省事呢? 期待:Service层整理中。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-09-20
HI,看了model和dao层。觉得从思想上面并没有太大的突破。跟springside的差不多。还是泛型dao的思路
|
|
返回顶楼 | |
发表时间:2010-09-20
最后修改:2010-09-20
nothink 写道
HI,看了model和dao层。觉得从思想上面并没有太大的突破。跟springside的差不多。还是泛型dao的思路
|
|
返回顶楼 | |
发表时间:2010-09-20
dao层和service层设计差不多,不过使用的ibatis
|
|
返回顶楼 | |
发表时间:2010-09-20
看看巴巴运动网视频一切都那么的easy。
|
|
返回顶楼 | |
发表时间:2010-09-21
差不多,平时都是这样设计的,没新意。
|
|
返回顶楼 | |
浏览 4858 次