`
langshao
  • 浏览: 7134 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

让SpringSide的DAO针对接口编程

阅读更多
考虑到项目将在全省各市部署,预想到在条件允许的市需要调其他市的档案,因此希望DAO能针对接口编程,方便以后扩展以及适应不同的市。
于是在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.
分享到:
评论
3 楼 langshao 2010-03-24  
chirs 写道
难道一个DAO的基本封装还有多种实现吗?今天使用hibernat明天就使用jdbc或者ibatis了吗?

是今天访问本地数据库,明天可能还需要查其他市的数据库,可能通过WebService的方式。
项目有点特殊,在各地区部署,而数据又要共用。再者,数据量太大,每个市都几千万,还要集中到省就更加了,字段也上百个,估计将来要切分之类优化的,希望这些数据层的变化不影响到业务层。
2 楼 chirs 2010-03-24  
难道一个DAO的基本封装还有多种实现吗?今天使用hibernat明天就使用jdbc或者ibatis了吗?
1 楼 chirs 2010-03-24  
我怎么觉得接口到底用啊.

相关推荐

    SpringSide的Hibernate封装

    SpringSide的Hibernate封装是针对Spring和Hibernate整合时的一种优化实践,旨在提高开发效率和代码的可维护性。它通过三层封装来实现对Hibernate操作的便捷和类型安全。 第一层是HibernateGenericDao,它是基于...

    Springside-core-4.1.0/Springside-core-4.1.0

    3. **数据访问层**:支持多种ORM框架,如Hibernate和MyBatis,提供统一的DAO接口,降低了数据访问层的复杂性。 4. **RESTful API**:通过Spring MVC实现RESTful服务,方便前后端分离的开发模式。 四、使用场景与...

    springside-3.2.2源码

    源码中可以看到 Spring 的依赖注入(DI)和面向切面编程(AOP)的广泛应用,以及对 SpringMVC、Spring Data、Spring Security 等子框架的集成。 1. SpringMVC:负责 Web 层的处理,通过 HandlerMapping 和 ...

    springside的jar包

    4. **最佳实践**:Springside遵循了许多Java开发的最佳实践,如约定优于配置、面向接口编程、依赖注入等,有助于提升代码质量和可维护性。 5. **持续集成**:项目支持Maven构建,并提供了持续集成的配置模板,方便...

    SpringSide4 参考手册

    SpringSide4参考手册是一份详尽的文档,涵盖了使用SpringSide4.0版本开发应用时可能会用到的各种技术组件和模块。SpringSide是一个开源的Java开发平台,它集成了Spring框架和大量实用的组件,以方便开发人员构建复杂...

    springside3.0.zip

    7. **国际化支持**:SpringSide 3.0 支持多语言环境,通过ResourceBundle和Spring的MessageSource接口,可以方便地实现应用的国际化。 8. **安全控制**:Spring Security(前身Acegi Security)被集成到SpringSide ...

    springside开发全面讲解

    本资料将由浅入深,逐步解析springside的核心概念和技术,以期让初学者也能顺利上手。 springside的核心特性包括: 1. **模块化设计**:springside采用模块化设计,将项目划分为多个独立的模块,如核心模块、安全...

    SpringSide4

    SpringSide4框架简单使用 sprindside4只写一个简单的DAO接口,日后再根据需要添加方法定义。不需要Dao implements

    springside

    在深入理解SpringSide之前,我们首先需要了解Spring Framework,这是一个广泛使用的Java企业级应用开发框架,它为开发者提供了诸如依赖注入、面向切面编程、数据访问、事务管理等核心功能。 SpringSide项目的核心...

    springside4-4.1.0.GA

    例如,它强调面向接口编程、依赖注入、单元测试等原则,使得代码更加松耦合,易于维护。 四、开发效率提升 SpringSide 4.1.0.GA包含了一套代码生成工具,可以自动生成常见的CRUD操作,减少了重复劳动,提高了开发...

    springside-4.0.0.GA.zip

    SpringSide项目始于对Spring Framework的深度理解和实践,它的核心在于简化Spring的使用,让开发者能够更快速、更高效地构建企业级应用程序。4.0.0.GA版本是该项目的一个稳定发布,代表着经过充分测试和验证的成熟...

    springside-core-4.1.0.GA.jar

    5. **AOP(面向切面编程)支持**: Springside提供了对Spring AOP的集成,允许开发者定义切面,实现如日志记录、事务管理等功能,增强了代码的可复用性。 6. **单元测试**:Springside鼓励并简化了单元测试的编写,...

    springside示例quickstart的eclipse工程

    它集合了最佳实践,包括Maven构建系统、JUnit测试框架、AspectJ切面编程、Hibernate ORM工具等,以帮助开发者快速上手Spring应用。在本文中,我们将深入探讨SpringSide示例Quickstart的Eclipse工程,了解其结构和...

    springside-core-4.2.2.GA(含关联的test.jar)

    pom.xml配置 ...mvn install:install-file -DgroupId=org.springside -DartifactId=springside-core -Dversion=4.2.2.GA -Dfile=./springside-core-4.2.2.GA.jar -Dpackaging=jar -DgeneratePom=true

    springside.jar

    springside-extension模块是针对Spring框架的扩展,包含了一些实用的工具类和配置,如日志管理、缓存支持、安全控制等。这些扩展使得开发者能够更便捷地实现常见的业务需求,降低了开发难度。 五、springside-...

    有springside4.2.3-GA.jar 包

    《深入解析springside4.2.3-GA.jar:Java开发者的宝藏库》 在Java开发领域,SpringSide框架以其高效、灵活和强大的特性深受开发者喜爱。本文将围绕springside4.2.3-GA.jar这个核心组件,探讨其在Java应用中的重要...

    springside4(showcase)

    SpringSide 4的showcase还会展示如何整合其他Spring模块,比如Spring Security进行权限管理,Spring Data进行数据访问,Spring AOP实现切面编程,以及Spring Test进行单元测试和集成测试。所有这些都将帮助开发者...

    springside3.3.4 使用方法

    ### springside3.3.4使用方法与SSH整合详解 #### 一、Springside简介 Springside项目是基于Spring框架的一个应用架构示例,它提供了一套完整的开发模式来构建企业级Java Web应用程序。Springside 3.3.4版本作为一...

    springside3文档资料收录

    SpringSide3则围绕这些核心特性,通过实例解析,让开发者能够快速上手Spring。 二、依赖注入 依赖注入是Spring框架的核心,它解决了对象之间的耦合问题,降低了代码的复杂度。在SpringSide3中,你会了解到如何通过...

    SpringSide3.3.4安装部署

    SpringSide3.3.4 安装部署详解 SpringSide3.3.4 安装部署是指在计算机上安装和部署 SpringSide3.3.4 软件的过程。在这个过程中,我们需要使用 Maven 工具来生成项目模板,安装 mini-web 应用程序,并配置相应的...

Global site tag (gtag.js) - Google Analytics