`
掌心童话
  • 浏览: 15187 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Java Web Application 自架构 三 通用DAO类实现

阅读更多

        准备好了单元测试模块,就写个底层的数据访问的控制Handle类来试试吧。也就是通常我们所说的DAO类。一般而言,每个模型/实体类需要建立一个DAO类。 不过经验告诉我们,一些通用的CRUD方法几乎在每个DAO类中都是一样的,那么也就是说我们通常所写的DAO会有些代码冗余的问题,而且根据业务需要,日后的维护工作有可能添加一些新的实体类,写地越多,DAO类就越多,写的代码就越多余还浪费时间。如何将写好的一个DAO类进行代码重用成为了问题。其实笔者见过一个的系统里有做过将Hibernate框架人应用做成静态类,用到时直接HibernateUtil.save()的。今天,咱也做一个通用的DAO放一些通用的CRUD方法进去,用来做通用的CRUD操作。这样做既省去了不少代码量,加强了代码可读性,而且还方便快捷地架构起这个WebModel,可以重用到很多的系统中。当然,遇到特殊的Entity 需要建个别的DAO时再当别论。

       

      首先是接口的编写,我在接口的编写时加了很多的JavaDoc,就不贴出代码了,上传为附件方便读者下载吧。此处列出几个方法做简单说明

package com.xxxxx.webmodel.pin;

import java.util.List;
import java.util.Map;
      public interface IPersistencePin {
	public void createPersistingEntity(Object persistingObj) throws Exception;
	public <PerE> PerE retrievePersistedEntity(Class<PerE> persistedClass,
			long id) throws Exception;
	public <PerE> PerE retrievePersistedEntity(Class<PerE> persistedClass,
			String identifier) throws Exception;
	public <PerE> List<PerE> retrievePersistedEntityAllInList(
			Class<PerE> persistedClass) throws Exception;
	public void updatePersistedEntity(Object persistingObj) throws Exception;
	public void deletePersistedEntity(Object persistingObj) throws Exception;
}
 

接口的实现:

package com.xxxxx.webmodel.pin.impl;

/*省略多个import 语句*/
import com.gxino.webmodel.pin.IPersistencePin;
@Repository
public class HibernatePersistencePin implements Serializable,IPersistencePin {
	private static final long serialVersionUID = -295800418896667101L;
	private SessionFactory sessionFactory;
	public static long getSerialversionuid() {
		return serialVersionUID;
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	@Resource
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
}

       其中,第一个方法 createPersistingEntity(Object persistingObj) MapHibernate 中的任意Pojo的对象持久化,即将某实体类的一个对象的各项属性值存入数据库。

@Override
  public void createPersistingEntity(Object persistingObj) throws Exception {
	Session session = null;
	boolean needCloseSession = false;
	try{
		session = sessionFactory.getCurrentSession();
		if(session==null)throw new HibernateException("No current Session");
	}catch(HibernateException he){
		session = sessionFactory.openSession();
		needCloseSession = true;
	}
	try{
		session.save(persistingObj);
		if(needCloseSession)session.close();
	}catch(HibernateException he){
		throw new Exception("Save Pojo failed, because of "+he.getMessage());
	}
}
 

      笔者在该方法中做了currentSessionopenSession双处理,也就是说该方法既可以是业务逻辑进行事务中的某一句,也可以无事务信赖地被单独调用。后面的update 方法与delete方法以及通过id从数据库中查出该对象的方法是如出一辙,只是session.save(persistingOjb)换成其他语句,就不贴代码了。贴一下另两个方法的第二个Try块中的代码吧:

 

      1<PerE> PerE retrievePersistedEntity(Class<PerE> persistedClass,

String uniquePropertyName, Object propertyValue)

传入一个唯一键值的名值对找出类对象:

Criteria criteria = session.createCriteria(persistedClass);
criteria.add(Restrictions.eq(uniquePropertyName, propertyValue));
@SuppressWarnings("unchecked")
PerE result = (PerE)criteria.uniqueResult();
if(needCloseSession)session.close();
return result;
 

 

       这里用到了HibernateCriteriaRestrictions,其实还有个Example类。 关于这一点,网络上有好多高手有解盲它的专题用法的帖子,笔者就不作大篇文章说它了。感觉这个比起写hql更 『面向对象』 一点儿,好用且易理解,所以特意贴在这里一个,以提醒自己与读者们可以这样去写。其实用了它的代码都是白话文,简单提一下: 从Session中创建一个某pojo人“基准”,用一些 “条件”,或是举例的方式,限定这个查询基准,之后按这个限定的标准查出具体对象。

查找所有对象到一个List中也不多说了,criteriaadd任何限制,直接criteria.list();就好.

 

       2<PerE> PerE retrievePersistedEntity(Class<PerE> persistedClass,

String identifier) throws Exception;

        无需给出唯一键的名,只需要唯一键的值,即去查询到该实体类对象。不过由于一个表中,可能有多个唯一键,这样就会产生冲突。例如,用户名和Email两个唯一性字段,用户Aaaa@aaa.com作用户名,用户Baaa@aaa.comemail,这种情况下查询到用户的结果就不仅是A而且还有B了。所以笔者将它在接口里就标了@deprecated

同样,只贴第二个try块中应放的代码。

String propertyName=null;
Method[] methodArray =persistedClass.getMethods();
if(methodArray!=null)for(Method method:methodArray){
	if(method.getName().startsWith("get")){
		Criteria criteria = session.createCriteria(persistedClass);
		Annotation anno = method.getAnnotation(Column.class);
		if(anno.toString().contains("unique=true")){
			propertyName = Character.toString(method.getName().charAt(3)).toLowerCase()+method.getName().substring(4);
			criteria.add(Restrictions.eq(propertyName, identifier));
		}
		@SuppressWarnings("unchecked")
		PerE result = (PerE)criteria.uniqueResult();
		if(needCloseSession)session.close();
		return result;
	}
}
if(needCloseSession)session.close();
return null;
 

        这方法的实现需要javax.persistence.Column这一注解到实体类中的每一个属性做配合。换句话说,HibernateMapping是注解方式的。 Column注解在JPA的规范中, hibernate框架有JPA的实现,在hibernate-jpa-2.0-api-x.x.x-Final.jar包中。 上面代码用到了反射,主要意思是:找到该Pojo类中所有属性的getter,通过查看该getter上是否注解有@Column并且注解的一个属性unique值为true,来找到相应的属性名,然后用名值对限定查询标准去查出实体类对象。

 

        至于怎么用JPA注解配置Pojo,也可以作为专题发表一篇文章了,笔者就不多叙述,直接在附件夹带一些实体类了,实体类如何mapsessionFactory中也在第一篇《xxx 注解化配置》的ApplicationContext.java中出现,代码在配置sessionFactory @Bean的方法中:

@SuppressWarnings("rawtypes")
Class[] entities = new Class[2];
entities[0] = AccountEntity.class;
entities[1] = ActionLogEntity.class;
asfBean.setAnnotatedClasses(entities);
 

 

       另外,有些读者可能已经发现,上述通用DAO中的实现中,每个方法也几乎重用了好多地方,只是改变了中间的核心部分,可不可以用一个固定的方法将每个方法的核心语句包住,就像是让Spring代管Transactional一样,很明显,我们会想到AOP,顺便将log也做到AOP中,不过这一篇就不多讨论了。先就这样用着。

最后,别忘了写单元测试类。

package com.xxxxx.webmodel.test.pin;

import static org.junit.Assert.fail;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;

import com.xxxxx.webmodel.entity.AccountEntity;
import com.xxxxx.webmodel.entity.ActionLogEntity;
import com.xxxxx.webmodel.pin.IPersistencePin;
import com.xxxxx.webmodel.util.ApplicationContext;
import com.xxxxx.webmodel.util.WebConfiguration;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={ApplicationContext.class})
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class })
@TransactionConfiguration(defaultRollback=true,transactionManager="hibernateTransactionManager")
@Transactional
public class PersistencePinTest {
	private IPersistencePin persistPin;
	private Map<String,Object> usedStuff;
	
	public IPersistencePin getPersistPin() {
		return persistPin;
	}
	@Resource
	public void setPersistPin(IPersistencePin persistPin) {
		this.persistPin = persistPin;
	}
	
	@BeforeClass
	public static void init() throws Exception{
			new WebConfiguration().onStartup(null);
	}
	
	@Before
	public void setUp() throws Exception{
		if(usedStuff==null)
			usedStuff = new HashMap<String,Object>();
		AccountEntity account = new AccountEntity();
		account.setUserName("junittest");
		account.setPassword("junittest");
		account.setEmail("junittest@junit.com");
		account.setAlias("unitTest");
		account.setAge((short)18);
		account.setGender("Male");
		account.setCreatedAt(new Date());
		persistPin.createPersistingEntity(account);
		usedStuff.put("userId", new Long(account.getId()));
		usedStuff.put("userName", account.getUserName());
		usedStuff.put("userEmail", account.getEmail());
        
		ActionLogEntity actionLog = new ActionLogEntity();
		actionLog.setAction("Junit Test");
		actionLog.setActor(account);
		actionLog.setHappenTime(new Date());
		try{persistPin.createPersistingEntity(actionLog);}
		catch(Exception e){
			e.printStackTrace();
			}
		usedStuff.put("actionId", new Long(actionLog.getId()));
		usedStuff.put("actionTime", actionLog.getHappenTime());
	}

	@Test
	@Ignore
	public final void testHibernateSession() throws Exception{
		/*Please not execute @Before setUp() method, for test this, and NO 				@TransactionConfiguration NO @Transactional*/
		/*Also make other test methods @Ignore*/
		AccountEntity account = new AccountEntity();
		account.setUserName("junittest");
		account.setPassword("junittest");
		account.setEmail("junittest@junit.com");
		account.setAlias("unitTest");
		account.setAge((short)18);
		account.setGender("Male");
		account.setCreatedAt(new Date());
		persistPin.createPersistingEntity(account);
		persistPin.deletePersistedEntity(account);
	}
}
 

具体的其他测试方法在附件的文件中,或是读者们自行去写会比笔者的要好很多。

附件中有源码,在很下面哦,请您仔细找一下

分享到:
评论

相关推荐

    数据库三层架构通用代码 访问层 数据库接口

    在"数据库三层架构通用代码 访问层 数据库接口"的场景中,通用类库源码可能包含以下内容: - 数据库连接池:如C3P0、Druid或HikariCP,用于高效管理和复用数据库连接。 - DAO(Data Access Object)接口和实现:...

    JAVA Web常见的面试题

    ### JAVA Web 常见面试题详解 #### 1. CSS与DIV的使用场景 - **CSS (Cascading Style Sheets)**:层叠样式表,用于定义HTML文档中元素的外观,包括颜色、布局和字体等。 - **DIV**:HTML中的一个通用容器元素,...

    JAVA企业快速通用开发平台框架源码(基于Bootstrap的Java企业通用开发平台框架)+部署文档及视频[请勿商用]

    1. **源码结构**:包括src/main/java目录下的服务层、DAO层、实体类、配置文件等,以及src/main/resources下的配置文件如application.properties或yml。 2. **前端资源**:Bootstrap的HTML模板、CSS样式文件、...

    java毕设项目之基于java+springboot科研工作量管理系统的设计与实现.zip

    项目中还包含了一些通用的服务和控制器,比如`CommonService.java`和`GongzuoliangController.java`,这些类通常用于实现业务逻辑,处理来自前端的请求,并调用DAO层操作数据库。`CommonUtil.java`可能是包含了一些...

    jsp数据库通用模块开发与系统移植

    《jsp数据库通用模块开发与系统移植》这一主题涵盖了在Java Web开发中使用JSP(JavaServer Pages)技术与数据库交互的通用模块设计和系统移植的关键知识点。这些源代码提供了实践中的示例,对于学习和理解相关技术至...

    网购网站实例(JAVA+SQLServer)

    这个项目对于学习JAVA Web开发、了解电商系统架构以及实践SQLServer数据库操作具有很高的参考价值。通过分析和运行这个实例,开发者可以深入理解前后端交互、数据库设计、事务处理等核心概念,为构建自己的电子商务...

    JAVA面试题(中).pdf

    Java规范中与WebService相关的规范包括JAX-WS(Java API for XML Web Services)用于构建Web服务,JAX-RS(Java API for RESTful Web Services)用于开发RESTful Web服务,以及JAXP(Java API for XML Processing)...

    oldx-admin是一款后台通用脚手架

    在这个项目中,你将看到如何使用Java类、接口、继承、多态等概念来组织代码结构,并实现模块化设计。 在后台管理系统的实现中,"oldx-admin"可能包括了权限管理、用户认证、角色分配、数据展示、CRUD操作等功能。这...

    JSP数据库通用模块开发与系统移植.rar

    9. **MVC(Model-View-Controller)架构**:虽然JSP最初的设计并没有明确遵循MVC模式,但在实际开发中,开发者通常会结合Servlet和JSP来实现MVC,提高代码结构的清晰度和可维护性。 这个压缩包可能包含的文件可能...

    maxmall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现。.zip

    - **maxmall-common**:公共模块,包含通用工具类、常量、枚举等,供其他模块复用。 - **maxmall-provider**:服务提供者模块,实现了接口中的业务逻辑,处理来自客户端的请求。 - **maxmall-dalgen**:数据访问层...

    JSP数据库通用模块开发与系统移植

    6. **数据库通用模块开发**:书中将详细阐述如何设计和实现可重用的数据库操作模块,例如数据访问对象(DAO)模式,以及事务管理策略,以提高代码复用性和可维护性。 7. **系统移植**:在不同环境中部署和运行JSP...

    构建maven+Spring Boot+Mybatis+redis多模块层级项目

    通过这样的架构,我们可以构建一个高效、可扩展且易于维护的Java Web应用。这种项目结构使得各部分职责明确,便于团队协作和代码复用。同时,利用Spring Boot的自动化配置和Mybatis的简洁映射,可以快速地开发出功能...

    java专业术语.pdf

    ***mon Object Request Broker Architecture(CORBA):通用对象请求代理架构,是一种网络通信协议,允许不同机器上的对象进行通信。 14. Data Access Object(DAO):数据访问对象,是一种设计模式,用于将数据...

    自己动手写Struts.pdf

    - **实现具体的Action类**:继承自`Action`接口,实现具体的功能。 - **使用数据访问对象DAO**:实现对数据库的操作,封装增删改查等功能。 - **异常处理机制**:处理可能出现的异常情况,确保程序的健壮性。 - ...

    Struts文章系统_strutsarticle_release毕业设计—(包含完整源码可运行).rar

    Struts文章系统是一个基于Java和Struts框架的后端应用,用于实现文章的发布、管理、检索等功能。这个毕业设计项目提供了完整的源代码,并且是可运行的状态,这对于学习Struts框架以及Java后端开发的学生来说,是一个...

    基于springboot框架的福聚苑社区团购毕业设计(源码+开发说明+演示视频).zip

    Spring Boot项目的源码通常包含配置文件(如application.properties或yaml)、控制器(Controller)、服务(Service)、模型(Model)和DAO(Data Access Object)等组件。通过阅读源码,我们可以了解如何在Spring ...

    基于ssm+mysql的协同过滤的在线通用旅游平台网站源码数据库.zip

    6. **网站源码**:项目包含的源码可能包括Controller、Service、DAO、Model等各个层次的Java类,以及配置文件如XML配置、application.properties等,它们共同构成了整个系统的逻辑。 7. **数据库设计**:在MySQL...

    后台管理系统通用框架,基于springboot,可进行二次开发,供毕设二次开发.zip

    1. **源代码**:包括主程序入口、配置文件(application.properties或.yml)、MVC控制器、服务接口与实现、模型类、数据库访问对象(DAO)等。 2. **模板引擎**:如Thymeleaf或Freemarker,用于生成动态HTML页面。 3...

    基于SpringBoot搭建的一个通用的OA管理系统,以车辆管理为例.zip

    4. **编写实体类**:定义车辆、驾驶员等对象的Java类,并使用注解进行ORM映射。 5. **创建数据访问层**:使用JPA或MyBatis编写DAO,处理数据的增删改查操作。 6. **实现业务逻辑**:在Service层编写业务逻辑,调用...

Global site tag (gtag.js) - Google Analytics