`
langshao
  • 浏览: 7211 次
  • 性别: 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  
我怎么觉得接口到底用啊.

相关推荐

    springside4-master

    SpringSide4-Master是一个针对企业级Java开发的开源项目,旨在提供一个现代化、模块化、高质量的Java EE(Enterprise Edition)应用骨架,帮助开发者快速搭建起符合最佳实践的基础框架。这个项目的核心是基于Spring ...

    li_3ck_02a_1118.pdf

    li_3ck_02a_1118

    基于MATLAB的牛顿迭代法实现

    基于MATLAB的牛顿迭代法实现

    mellitz_3ck_01_0319.pdf

    mellitz_3ck_01_0319

    2025探索银行业人工智能驱动技术转型的投资回报率

    内容概要:文章阐述了银行采用人工智能(AI)技术替代传统系统的紧迫性和收益,讨论了通过构建现代化的数据和技术平台实现效率提升的方法,同时强调实施过程中确保数据质量和建立信任的重要性。文中提及,在金融行业中,若想优化业绩则必须拥抱AI带来的机遇,并为此进行经营模式的革新。根据Workday主办的研讨会内容,PwC金融服务风险与监管领导和Workday金融服务高层指出了大部分银行对AI认知不足的问题,强调AI在金融、人力资源以及IT等领域的广泛应用潜力及具体应用场景,如欺诈检测、技能映射和财务管理方面的作用。并且提到了AI部署过程中可能出现的技术与非技术难题及相应解决办法,鼓励金融机构及时投资建设新型基础设施,以保持竞争力。 适用人群:银行及其他金融机构管理人员;金融科技领域的专业研究人员;对企业数字化和智能化转型感兴趣的商业分析师、投资者;从事信息技术咨询工作的顾问。 使用场景及目标:本文可以帮助金融机构制定合理的技术发展战略规划,评估是否有必要推进AI技术转型,同时也为希望涉足银行科技项目的开发者提供了宝贵的市场洞察,帮助理解行业内普遍存在的困难与潜在的市场需求。此外,对于想要了解银行

    matlab程序代码项目案例论文+程序 基于在线优化的快速模型预测控制Fast model predicitive control with matlab interface.zip

    matlab程序代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    [AB PLC例程源码][MMS_043071]Phase Manager and a Scalable Batching Solution.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    [AB PLC例程源码][MMS_044386]1769-SM2 Compact I-O to DSI Module - Multi Drive Mode Operation - with.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    [AB PLC例程源码][MMS_041232]Monitor I-O Connections in Logix.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    chromedriver-linux64-136.0.7058.0.zip

    chromedriver-linux64-136.0.7058.0.zip

    [AB PLC例程源码][MMS_042504]Logix5000 interface to Atlas-Copco Tool Controller over EtherNet-IP.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    [AB PLC例程源码][MMS_042349]How to read-write data to-from a PLC using OPC in Visual Basic 6.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    电力工程领域中背压热电联产电厂的设计与参数计算

    内容概要:本文档介绍了背压热电联产(CHP)发电厂的详细设计步骤,涵盖确定各状态点的压力、温度、比焓以及质量流率的具体方法。主要内容围绕计算净电功率、燃料消耗及其效率展开,并提供了T-s图绘制的指南。针对每个组件(如蒸汽轮机、冷凝器、除氧器等),都列出了详细的效率假设和压力损失表,为实际工程应用提供了宝贵的参考资料和操作指导。同时,该作业任务要求学生从给定初始值中选择合适的操作条件进行系统模拟,并利用课程讲义和Moodle平台资料完成计算流程。 适用人群:对能源转换和动力设备设计感兴趣的学生或者初涉该领域的工程师。 使用场景及目标:旨在帮助学员深入了解并掌握背压热电联产装置的工作原理和技术指标计算的方法论,通过实践练习提高他们的问题解决能力。 其他说明:文档强调了稳态运行假设的重要性,即物质平衡等于能量输入等于输出的原则,并鼓励参与者借助附录提供的典型操作参数图表来寻找解决问题的方向。此外,它还特别指出对于一些变量值求解可能需要迭代法来进行调整,直至获得稳定结果。提交的报告必须含有一份详细的T-s图和其他必要附件。

    机器学习-市财政收入分析(含数据集)

    机器学习_市财政收入分析(含数据集)

    [AB PLC例程源码][MMS_046989]KAT with Code Sequencer.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    tracy_3cd_01_0318.pdf

    tracy_3cd_01_0318

    lusted_3cd_01_0918.pdf

    lusted_3cd_01_0918

    基于51的自动分拣系统设计20250307

    题目:基于51的自动分拣系统设计 主控:AT89C52 测距模块:超声波测距模块 甲醛传感器(ADC0832+滑动变阻器模拟) 粉尘传感器(PCF8591+滑动变阻器模拟) 净化模块(继电器驱动蓝灯) 排风模块(继电器驱动绿灯) 电源电路(5V降压为3.3V供电) 显示模块(LCD1602) 声光报警 按键(3个,切换阈值选择,阈值加减) 检测物体:开关模拟 电机驱动模块(继电器驱动直流电机转动) 功能: 1.显示屏显示甲醛,粉尘浓度可以切换设置阈值。 2.通过甲醛传感器检测车间环境,大于阈值时声光报警并启动净化模块。 3.通过粉尘传感器检测车间环境,大于阈值时声光报警并启动排风模块。 4.采用超声波传感器进行物体超高监测异常(大于XX距离)时触发声光报警 5.检测到物体(开关闭合)直流电机转动(模拟传送带)

    network-server

    network_server

    [AB PLC例程源码][MMS_046691]Integrated Architecture Foundations of Modular Programming.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

Global site tag (gtag.js) - Google Analytics