浏览 3993 次
锁定老帖子 主题:让SpringSide的DAO针对接口编程
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-03-23
于是在SpringSide的examples.miniweb上作了些修改,希望能够抛砖引玉,更希望各位批评指正。 将IdEntity改为EntityObject,希望以后所有实体都继承它。Id不一定放在这,但要重写equals和hashCode等。 package org.springside.examples.miniweb.entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.MappedSuperclass; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; /** * 统一定义id的entity基类. * * 基类统一定义id的属性名称、数据类型、列名映射及生成策略. * 子类可重载getId()函数重定义id的列名映射和生成策略. * * @author calvin */ //JPA 基类的标识 @MappedSuperclass public abstract class EntityObject { protected Long id; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) //@GeneratedValue(strategy = GenerationType.SEQUENCE) public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Override public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); } @Override public boolean equals(Object o) { return o != null && o.getClass().equals(this.getClass()) && EqualsBuilder.reflectionEquals(this, o); } @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } } 定义DAO的通用接口,如下,还有很多常用通用的没有写出来。 package org.springside.examples.miniweb.dao; import java.io.Serializable; import java.util.Collection; import java.util.List; import org.springside.examples.miniweb.entity.EntityObject; /** * 通用DAO接口<br> * 在能用此接口完成功能时,不必再派生出子接口<br> * 在此接口不能满足要求时,派生出相应的子接口<br> * * @see org.springside.examples.miniweb.dao.security.RoleDao * @see org.springside.examples.miniweb.dao.security.ResourceDao * * @author langshao * */ public interface GenericDao { /** * 根据实体的class及id获取相应的实体 * * @param <T> * @param entityClass 实体的class, 如 <code>User.class</code> * @param id 当为 <code>null</code> 时返回 <code>null</code> * @return 找到则返回相应的实体, 找不到时返回 <code>null</code> */ <T extends EntityObject> T get(Class<T> entityClass, Serializable id); /** * 根据实体的class获取所有的实体 * * @param <T> * @param entityClass 实体的class, 如 <code>User.class</code> * @return 没有数据时返回空的 List */ <T extends EntityObject> List<T> getAll(Class<T> entityClass); /** * 新增或更新实体<br> * 当entity的id为 <code>null</code> 时新增, 否则更新 * * @param entity 当为 <code>null</code> 时不保存 */ void saveOrUpdate(EntityObject entity); /** * 批量新增或更新实体<br> * 当entity的id为 <code>null</code> 时新增, 否则更新 * * @param entities 当entities为 <code>null</code> 时不保存 * @exception IllegalArgumentException entities的成员含有 <code>null</code> * 时会抛出异常 */ void saveOrUpdateAll(Collection<? extends EntityObject> entities) throws IllegalArgumentException; /** * 删除实体 * * @param entity 当为 <code>null</code> 时不删除 */ void delete(EntityObject entity); /** * 批量删除实体 * * @param entities 当entities为 <code>null</code> 时不删除 * @exception IllegalArgumentException entities的成员含有 <code>null</code> * 时会抛出异常 */ void deleteAll(Collection<? extends EntityObject> entities) throws IllegalArgumentException; } 一个简单的实现类如下,我是比较喜欢用HibernateTemplate。 package org.springside.examples.miniweb.dao.impl; import java.io.Serializable; import java.util.Collection; import java.util.List; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.stereotype.Repository; import org.springside.examples.miniweb.dao.GenericDao; import org.springside.examples.miniweb.entity.EntityObject; /** * 通用DAO实现 * * @author langshao * */ @Repository public class GenericDaoImpl extends HibernateDaoSupport implements GenericDao { /** * 为了使sessionFactory能自动注入而写了这个方法 * * @param sessionFactory */ @Autowired public void setSessionFactory4Autowired(SessionFactory sessionFactory) { this.setSessionFactory(sessionFactory); } @SuppressWarnings("unchecked") public <T extends EntityObject> T get(Class<T> entityClass, Serializable id) { if (id != null) return (T) getHibernateTemplate().get(entityClass, id); return null; } @SuppressWarnings("unchecked") public <T extends EntityObject> List<T> getAll(Class<T> entityClass) { return getHibernateTemplate().loadAll(entityClass); } public void saveOrUpdate(EntityObject entity) { if (entity != null) { getHibernateTemplate().saveOrUpdate(entity); } } public void saveOrUpdateAll(Collection<? extends EntityObject> entities) throws IllegalArgumentException { if (entities != null && !entities.isEmpty()) { getHibernateTemplate().saveOrUpdateAll(entities); } } public void delete(EntityObject entity) { if (entity != null) { getHibernateTemplate().delete(entity); } } public void deleteAll(Collection<? extends EntityObject> entities) throws IllegalArgumentException { if (entities != null) { getHibernateTemplate().deleteAll(entities); } } } 在删除角色时,需要将相应的关联表也删除,因此角色需要重写delete的实现,为了方便自动注入,建立一个新的接口: package org.springside.examples.miniweb.dao.security; import org.springside.examples.miniweb.dao.GenericDao; /** * 角色DAO接口 * * @author langshao */ public interface RoleDao extends GenericDao { } 实现如下: package org.springside.examples.miniweb.dao.security.impl; import java.util.List; import org.springframework.stereotype.Repository; import org.springside.examples.miniweb.dao.impl.GenericDaoImpl; import org.springside.examples.miniweb.dao.security.RoleDao; import org.springside.examples.miniweb.entity.EntityObject; import org.springside.examples.miniweb.entity.security.User; /** * 角色DAO实现 * * @author langshao * */ @Repository public class RoleDaoImpl extends GenericDaoImpl implements RoleDao { private static final String QUERY_USER_BY_ROLEID = "select u from User u left join u.roleList r where r.id = ?"; /** * 重载函数,因为Role中没有建立与User的关联,因此需要以较低效率的方式进行删除User与Role的多对多中间表. */ @Override @SuppressWarnings("unchecked") public void delete(EntityObject role) { // 查询出拥有该角色的用户,并删除该用户的角色. List<User> users = getHibernateTemplate().find(QUERY_USER_BY_ROLEID, role.getId()); for (User u : users) { u.getRoleList().remove(role); } super.delete(role); } } 这样做之后,GenericDao 的 @Autowired 便会报错,以 RoleDaoTest 来说明如何解决之。 在applicationContext-test.xml中加入一个bean: <bean id="genericDao" class="org.springside.examples.miniweb.dao.impl.GenericDaoImpl" /> 然后RoleDaoTest如下写: package org.springside.examples.miniweb.integration.dao.security; import javax.annotation.Resource; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springside.modules.test.DataUtils; import org.springside.modules.test.spring.SpringTxTestCase; import org.springside.examples.miniweb.dao.GenericDao; import org.springside.examples.miniweb.dao.security.RoleDao; import org.springside.examples.miniweb.entity.security.Role; import org.springside.examples.miniweb.entity.security.User; /** * UserDao的集成测试用例,测试ORM映射及特殊的DAO操作. * * @author calvin */ public class RoleDaoTest extends SpringTxTestCase { @Autowired private RoleDao roleDao; @Resource(name = "genericDao") private GenericDao userDao; /** * 测试删除角色时删除用户-角色的中间表. */ @Test public void deleteRole() { //新增测试角色并与admin用户绑定. Role role = new Role(); role.setName(DataUtils.randomName("Role")); roleDao.saveOrUpdate(role); User user = userDao.get(User.class, 1L); user.getRoleList().add(role); userDao.saveOrUpdate(user); flush(); int oldJoinTableCount = countRowsInTable("SS_USER_ROLE"); int oldUserTableCount = countRowsInTable("SS_USER"); //删除用户角色, 中间表将减少1条记录,而用户表应该不受影响. roleDao.delete(role); flush(); int newJoinTableCount = countRowsInTable("SS_USER_ROLE"); int newUserTableCount = countRowsInTable("SS_USER"); assertEquals(1, oldJoinTableCount - newJoinTableCount); assertEquals(0, oldUserTableCount - newUserTableCount); } } 再举个扩充通用接口的例子: package org.springside.examples.miniweb.dao.security; import java.util.List; import org.springside.examples.miniweb.dao.GenericDao; import org.springside.examples.miniweb.entity.security.Resource; /** * 受保护资源对象的DAO接口 * * @author langshao */ public interface ResourceDao extends GenericDao { /** * 查询URL类型的资源并预加载可访问该资源的授权信息. */ List<Resource> getUrlResourceWithAuthorities(); } 实现如下: package org.springside.examples.miniweb.dao.security.impl; import java.util.List; import org.springframework.stereotype.Repository; import org.springside.examples.miniweb.dao.impl.GenericDaoImpl; import org.springside.examples.miniweb.dao.security.ResourceDao; import org.springside.examples.miniweb.entity.security.Resource; /** * 受保护资源对象的DAO实现 * * @author langshao */ @Repository public class ResourceDaoImpl extends GenericDaoImpl implements ResourceDao { public static final String QUERY_BY_RESOURCETYPE_WITH_AUTHORITY = "select distinct r from Resource r " + "left join fetch r.authorityList WHERE r.resourceType=? ORDER BY r.position ASC"; @SuppressWarnings("unchecked") public List<Resource> getUrlResourceWithAuthorities() { return getHibernateTemplate().find( QUERY_BY_RESOURCETYPE_WITH_AUTHORITY, Resource.URL_TYPE); } } 这样做主要是想针对接口编程,还有就是不想每新增一个Entity就要增加一个DAO,只要通用的够用就不用再写了。 Write less, do more. 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-03-24
我怎么觉得接口到底用啊.
|
|
返回顶楼 | |
发表时间:2010-03-24
难道一个DAO的基本封装还有多种实现吗?今天使用hibernat明天就使用jdbc或者ibatis了吗?
|
|
返回顶楼 | |
发表时间:2010-03-24
chirs 写道 难道一个DAO的基本封装还有多种实现吗?今天使用hibernat明天就使用jdbc或者ibatis了吗?
是今天访问本地数据库,明天可能还需要查其他市的数据库,可能通过WebService的方式。 项目有点特殊,在各地区部署,而数据又要共用。再者,数据量太大,每个市都几千万,还要集中到省就更加了,字段也上百个,估计将来要切分之类优化的,希望这些数据层的变化不影响到业务层。 |
|
返回顶楼 | |