基于Spring+Hibernate的通用增删改查的实现方法
王保政
QQ:29803446
一、设计方案
1.1 名词解释:
业务服务层:业务服务层引用了数据访问层接口DAO,业务服务层的类名一般是按Service作为后缀,业务服务层具体实现类可以按ServiceImpl命名。业务服务层类都可以在Spring配置文件中进行配置。
服务定位器:ServiceLocator是一个服务定位器,也可以说是业务服务层的门面类,此服务定位器提供了静态的方法,通过静态的方法可调用所有的业务服务层接口,ServiceLocator封装了读取Spring配置文件的方法,在JSP或控制层及业务服务层都可以通过ServiceLocator.getXXXService().业务方法()的格式来引用业务服务层提供的方法,例如在JSP中调用一个插入的方法,格式:
ServiceLocator.getDBSupportService().insert(entity,null);//entity为一个继承了AbstractEntity实体变量。
使用ServiceLocator,不需要自己书写读取Spring配置文件的方法来调用spring bean,而且通过ServiceLocator调用的业务逻辑类在spring配置文件中都是按单例配置的,不用的request引用的是同一个内存实例对象,这样可以大大提高系统的性能。
1.2 设计说明
名词解释中简单谈了ServiceLocator和Service层,Service层的bean是要调用Dao层的,Service Bean有一个Dao的属性,这个属性是通过构造注入的方式配置的,所以在Service的构造方法中应该有对dao的赋值语句,建议Service类的Dao属性字段不要按照设值注入的方式,因为我们不希望通过service.getXXXDao()的方式直接引用到Dao层。
在上面的设计图中IDBSupportService是业务服务层接口,DBSupportServiceImpl是业务服务层接口的实现类。IDBSupportService中定义了与数据库操作相关的通用的增删改查等方法。
DAO层的设计是这样的,IBaseDao声明了增删改查方法,BaseHibernateDao抽象类实现了增删改查的通用方法,这个类继承了org.springframework.orm.hibernate3.support.HibernateDaoSupport,这个类提供了很多Spring框架自带的数据库操作相关的模板方法。
AbstractEntity是一个抽象实体类,所有数据库表对应的实体类都要继承这个抽象实体类。
二、Spring配置文件
(1)acegisecurityContext.xml :这个文件与acegi权限相关,本文暂不介绍。
(2)datasource.xml定义了数据源及hibernate参数和映射文件:
<?xml version="1.0" encoding="GB2312"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<!-- 本文件配置应用所使用的各种数据源 -->
<bean id="mysqlds"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/mysql</value>
</property>
</bean>
<bean id="sessionMysqlFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="mysqlds" />
</property>
<property name="mappingResources">
<list>
<!—为节省篇幅,只列出一个hbm.xml文件-->
<value>
org/apache/easframework/core/entity/OlapReportChart.hbm.xml
</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.c3p0.max_size">230</prop>
<prop key="hibernate.c3p0.min_size">2</prop>
<prop key="hibernate.c3p0.timeout">10000</prop>
<prop key="hibernate.c3p0.max_statements">100</prop>
<prop key="hibernate.c3p0.maxIdleTime">20</prop>
<prop key="hibernate.c3p0.acquire_increment">3</prop>
<prop key="hibernate.c3p0.validate">false</prop>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.query.factory_class">
org.hibernate.hql.ast.ASTQueryTranslatorFactory
</prop>
</props>
</property>
</bean>
<bean id="hibernateMysqlTemplate"
class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionMysqlFactory" />
</property>
</bean>
</beans>
(3) core-service.xml,此文件配置业务逻辑类,其中<ref bean="hibernateMysqlTemplate"/>引用的是datasource.xml中配置的bean。
<?xml version="1.0" encoding="GB2312"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="IDBSupportService" class="org.apache.easframework.core.service.impl.DBSupportServiceImpl">
<constructor-arg><ref local="IBaseDao"/></constructor-arg>
</bean>
<bean id="INodeService" class="org.apache.easframework.core.service.impl.NodeServiceImpl">
<constructor-arg><ref local="IBaseDao"/></constructor-arg>
</bean>
<bean id="IBaseDao" class="org.apache.easframework.core.dao.impl.DBSupportDaoImpl">
<property name="hibernateTemplate">
<ref bean="hibernateMysqlTemplate"/>
</property>
</bean>
</beans>
三、ServiceLocator的代码:
package org.apache.easframework.core.service;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.apache.easframework.core.service.ISysConfig;
public class ServiceLocator {
private static final Logger log = Logger.getLogger(ServiceLocator.class);
private static ApplicationContext context;
public static final ServiceLocator thisService = new ServiceLocator(); //单例类
private static final String[] xmlFiles = new String[] {
"/core-service.xml", "/datasource.xml" ,"/system-config.xml"};
//public static ServiceLocator getInstance()
//{
// return thisService;
//}
/**
* 系统配置组件
*
* @return
*/
public static ISysConfig getSysConfigService() {
String beanName = "ISysConfig";
ISysConfig service = (ISysConfig) getBeanService(beanName);
return service;
}
public static INodeService getNodeService()
{
String beanName ="INodeService";
INodeService service = (INodeService)getBeanService(beanName);
return service;
}
public static IDBSupportService getDBSupportService() {
String beanName = "IDBSupportService";
IDBSupportService service = (IDBSupportService) getBeanService(beanName);
return service;
}
private static IService getBeanService(String serviceName) {
IService bean = null;
try {
if (context == null) {
context = new ClassPathXmlApplicationContext(xmlFiles);
}
bean = (IService) context.getBean(serviceName);
} catch (Exception e) {
log.error("获取Service Bean对象失败!");
log.error(e.getMessage());
e.printStackTrace();
}
return bean;
}
}
四、DBSupportServiceImpl增删改查业务逻辑实现类代码:
package org.apache.easframework.core.service.impl;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.easframework.core.dao.IBaseDao;
import org.apache.easframework.core.entity.AbstractEntity;
import org.apache.easframework.core.pageloader.IPageLoader;
import org.apache.easframework.core.pageloader.PageLoaderHibernateImpl;
import org.apache.easframework.core.pageloader.PageLoaderInfo;
import org.apache.easframework.core.service.IDBSupportService;
import org.apache.log4j.Logger;
import org.hibernate.criterion.DetachedCriteria;
public class DBSupportServiceImpl implements IDBSupportService
{
private static final Logger logger = Logger .getLogger(DBSupportServiceImpl.class);
private IBaseDao defaultDao;
/**
* 使用这种方式为了在Spring配置文件中按构造注入的方式实例化Dao,因为不希望外部调用通过getDao方法来间接引用Dao的方法
* 如果使用setter注入,则需要提供defaultDao的set和get方法
* @param dao
*/
public DBSupportServiceImpl(IBaseDao dao)
{
logger.info("Dao构造注入!!!");
this.defaultDao = dao;
}
public void delete(AbstractEntity entity, HttpServletRequest request) throws Exception {
this.defaultDao.delete(entity);
}
public void deleteById(String entityClassName, String keyFieldName, Object keyFieldValue, HttpServletRequest request) throws Exception {
this.defaultDao.deleteById(entityClassName, keyFieldName, keyFieldValue);
}
public void deleteByIds(String entityClassName, String fieldName, Object[] pkIds, HttpServletRequest request) throws Exception {
this.defaultDao.deleteByIds(entityClassName, fieldName, pkIds);
}
public List findAll(String entityClassName, HttpServletRequest request) throws Exception {
List list = this.defaultDao.findAll(entityClassName);
return list;
}
public List findByDetachedCriteria(DetachedCriteria criteria, HttpServletRequest request) throws Exception {
List list = this.defaultDao.findByDetachedCriteria(criteria);
return list;
}
public List findByHqlQuery(String hql, HttpServletRequest request) throws Exception
{
List list = this.defaultDao.findByHqlQuery(hql);
return list;
}
public AbstractEntity findById(String entityClassName, String keyFieldName, Object keyFieldValue, HttpServletRequest request) throws Exception {
AbstractEntity entity = this.defaultDao.findById(entityClassName, keyFieldName, keyFieldValue);
return entity;
}
public List findLabelValueBean(String sql, HttpServletRequest request) throws Exception {
List list = this.defaultDao.findLabelValueBean(sql);
return list;
}
public List findListByFieldValue(String entityClassName, String fieldName, Object fieldValue, boolean isSortAsc, String sortFieldName, HttpServletRequest request) throws Exception {
List list = this.defaultDao.findListByFieldValue(entityClassName, fieldName, fieldValue, isSortAsc, sortFieldName);
return list;
}
public List findPage(String entityClassName, String hqlWhere, int currentPage, int linePerPage, HttpServletRequest request) throws Exception {
List list = this.defaultDao.findPage(entityClassName, hqlWhere, currentPage, linePerPage);
return list;
}
public List findSimilarEntities(AbstractEntity conditionEntity, HttpServletRequest request) throws Exception {
List list = this.defaultDao.findSimilarEntities(conditionEntity);
return list;
}
public Object findSingleValueByHql(String hql, HttpServletRequest request) throws Exception {
Object obj = this.defaultDao.findSingleValueByHql(hql);
return obj;
}
public Object findSingleValueBySql(String sql, HttpServletRequest request) throws Exception {
Object obj = this.defaultDao.findSingleValueBySql(sql);
return obj;
}
public void insert(AbstractEntity entity, HttpServletRequest request) throws Exception {
this.defaultDao.insert(entity);
}
public void saveOrUpdate(AbstractEntity entity, HttpServletRequest request) throws Exception {
this.defaultDao.saveOrUpdate(entity);
}
public void update(AbstractEntity entity, HttpServletRequest request) throws Exception {
this.defaultDao.update(entity);
}
public void updateHql(String hql, HttpServletRequest request) throws Exception {
this.defaultDao.updateHql(hql);
}
public void updateSql(String sql, HttpServletRequest request) throws Exception {
this.defaultDao.updateSql(sql);
}
}
五、BaseHibernateDao.java
package org.apache.easframework.core.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.easframework.core.entity.AbstractEntity;
import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public abstract class BaseHibernateDao extends HibernateDaoSupport implements IBaseDao {
private static final Logger logger = Logger
.getLogger(BaseHibernateDao.class);
public void insert(AbstractEntity entity) {
getHibernateTemplate().save(entity);
}
public void delete(AbstractEntity entity) {
getHibernateTemplate().delete(entity);
}
public AbstractEntity findById(String entityClassName, String keyFieldName,
Object keyFieldValue) throws Exception {
AbstractEntity entity = null;
String sql = "";
if (keyFieldValue instanceof java.lang.String) {
// String型测试通过
sql = "from " + entityClassName + " as vo where vo." + keyFieldName
+ " = '" + keyFieldValue + "'";
} else {
// 数值型的未测试
sql = "from " + entityClassName + " as vo where vo." + keyFieldName
+ " = " + String.valueOf(keyFieldValue) + " ";
}
List list = getHibernateTemplate().find(sql);
if (list.size() > 0)
entity = ((AbstractEntity) list.get(0));
return entity;
}
public List findListByFieldValue(String entityClassName,
String keyFieldName, Object keyFieldValue, boolean isSortAsc,
String sortFieldName) throws Exception {
String sSort = "asc";
if (isSortAsc == false)
sSort = "desc";
String sql = "";
if (keyFieldValue instanceof java.lang.String) {
// String型测试通过
sql = "from " + entityClassName + " as vo where vo." + keyFieldName
+ " = '" + keyFieldValue + "' order by " + sortFieldName
+ " " + sSort;
} else {
// 数值型的未测试
sql = "from " + entityClassName + " as vo where vo." + keyFieldName
+ " = " + String.valueOf(keyFieldValue) + " order by "
+ sortFieldName + " " + sSort;
}
List list = getHibernateTemplate().find(sql);
return list;
}
public void deleteById(String entityClassName, String keyFieldName,
Object keyFieldValue) throws Exception {
AbstractEntity entity = findById(entityClassName, keyFieldName,
keyFieldValue);
if (entity != null) {
delete(entity);
}
}
public void deleteByIds(String entityClassName, String fieldName,
Object[] pkIds) throws Exception {
if (pkIds != null && pkIds.length > 0) {
for (int i = 0; i < pkIds.length; i++) {
deleteById(entityClassName, fieldName, pkIds[i]);
}
}
}
public void update(AbstractEntity entity) throws Exception {
getHibernateTemplate().update(entity);
}
public void saveOrUpdate(AbstractEntity entity) throws Exception {
getHibernateTemplate().saveOrUpdate(entity);
}
// entityClassName需要类的全路径名
public List findAll(String entityClassName) throws Exception {
List list = getHibernateTemplate().loadAll(
Class.forName(entityClassName));
return list;
}
public List findByHqlQuery(String hql) throws Exception {
List list = getHibernateTemplate().find(hql);
return list;
}
public List findByDetachedCriteria(DetachedCriteria criteria)
throws Exception {
List list = getHibernateTemplate().findByCriteria(criteria);
return list;
}
public List findSimilarEntities(AbstractEntity conditionEntity)
throws Exception {
List list = getHibernateTemplate().findByExample(conditionEntity);
return list;
}
public Object findSingleValueByHql(String hql) throws Exception {
Object obj = findByHqlQuery(hql).get(0);
return obj;
}
public void updateHql(String hql) throws Exception {
Session session = super.getSession();
session.createQuery(hql).executeUpdate();
session.flush();
super.releaseSession(session);
}
public Object findSingleValueBySql(String sql) throws Exception {
Connection con = null;
Object obj = null;
Session session = null;
session = super.getSession();
con = session.connection();
PreparedStatement stmt = null;
stmt = con.prepareStatement(sql);
try {
ResultSet rst = stmt.executeQuery();
while (rst.next()) {
obj = rst.getObject(1);
break;
}
rst.close();
stmt.close();
} catch (SQLException ex) {
ex.printStackTrace();
logger.error("出现异常:" + ex.getMessage());
throw ex;
} finally {
con.close();
super.releaseSession(session);
}
if(obj==null)
{
obj = new String("");//进行一下处理以免外部调用还要执行异常处理
}
else
{
}
return obj;
}
public void updateSql(String sql) throws Exception {
Connection con = null;
Session session = null;
session = super.getSession();
con = session.connection();
PreparedStatement stmt = null;
stmt = con.prepareStatement(sql);
try {
stmt.executeUpdate();
stmt.close();
} catch (SQLException ex) {
ex.printStackTrace();
logger.error("出现异常:" + ex.getMessage());
throw ex;
} finally {
con.close();
super.releaseSession(session);
}
}
public List findLabelValueBean(String sql) throws Exception {
List list = new ArrayList();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rst = null;
Session session = null;
session = super.getSession();
con = session.connection();
try {
pstmt = con.prepareStatement(sql);
rst = pstmt.executeQuery();
String sName = "";
String sCode = "";
while (rst.next()) {
sName = rst.getString(2);
sCode = rst.getString(1);
//System.out.println(sCode + sName);
list
.add(new org.apache.struts.util.LabelValueBean(sName,
sCode));
}
rst.close();
pstmt.close();
} finally {
con.close();
super.releaseSession(session);
}
return list;
}
public List findPage(String entityClassName, String hqlWhere,
int currentPage, int linePerPage) throws Exception {
List list = null;
Session session = null;
if (!(currentPage >= 0))
currentPage = 1;
if (!(linePerPage >= 0))
linePerPage = 10;
try {
session = super.getSession();
Query query = session.createQuery("from " + entityClassName + " "
+ hqlWhere);
query.setFirstResult((currentPage - 1) * linePerPage);
query.setMaxResults(linePerPage);
list = query.list();
} finally {
super.releaseSession(session);
}
return list;
}
}
六、IDBSupportService.java:
package org.apache.easframework.core.service;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.easframework.core.entity.AbstractEntity;
import org.apache.easframework.core.pageloader.IPageLoader;
import org.hibernate.criterion.DetachedCriteria;
/**
* 数据库操作相关的接口,声明了增删改查等接口方法
* 业务逻辑接口方法中声明了request参数,(在Spring配置文件中使用单例模式配置service bean
* 接口方法中的request参数主要用于在拦截器中拦截request中的参数值并存入日志,这样不需要在JSP页面中编写日志写入的代码
* 每个业务接口的方法都要抛出异常,以便在Service层或控制层根据异常截获来控制事务是否回滚。
* 此接口是数据库操作的基本Service接口,其他业务逻辑类可以在自己的方法中调用此接口中的方法
* @author bzwang
*
*/
public interface IDBSupportService extends IService
{
/**
* 插入实体
* @param entity
* @param request
* @throws Exception
*/
public void insert(AbstractEntity entity,HttpServletRequest request) throws Exception;
/**
* 删除实体
* @param entity
* @param request
* @throws Exception
*/
public void delete(AbstractEntity entity,HttpServletRequest request) throws Exception;
/**
* 根据某列的值查询实体,只返回单一实体
* @param entityClassName 实体类的名字,可以不带package
* @param keyFieldName 类字段名
* @param keyFieldValue 类字段值
* @param request
* @return AbstractEntity
* @throws Exception
*/
public AbstractEntity findById(String entityClassName,String keyFieldName,Object keyFieldValue,HttpServletRequest request) throws Exception;
/**
* 根据某列的值查询实体列表
* @param entityClassName 实体类名,可以不带包路径
* @param fieldName 类字段名
* @param fieldValue 类字段值
* @param isSortAsc 是否升序排列,升序true,降序false
* @param sortFieldName 排序的类字段名
* @param request
* @return 返回实体的List
* @throws Exception
*/
public List findListByFieldValue(String entityClassName,String fieldName,Object fieldValue,boolean isSortAsc,String sortFieldName,HttpServletRequest request) throws Exception;
/**
* 根据某列的值删除实体(此列应为唯一值列)
* @param entityClassName 实体类名
* @param keyFieldName 类字段名
* @param keyFieldValue 类字段值
* @param request
* @throws Exception
*/
public void deleteById(String entityClassName, String keyFieldName, Object keyFieldValue,HttpServletRequest request) throws Exception ;
/**
* 删除某列的值在ID数组中的实体
* @param entityClassName 实体类名
* @param fieldName 类字段名
* @param pkIds ID数组,可以整型数组或字符串数组
* @param request
* @throws Exception
*/
public void deleteByIds(String entityClassName,String fieldName,Object[] pkIds,HttpServletRequest request) throws Exception; //删除一组实体
/**
* 保存修改后的实体
* @param entity 实体对象
* @param request
* @throws Exception
*/
public void update(AbstractEntity entity,HttpServletRequest request) throws Exception;
/**
* 保存修改或新增的实体,具有新增和修改两种作用
* @param entity 新增或修改的实体
* @param request
* @throws Exception
*/
public void saveOrUpdate(AbstractEntity entity,HttpServletRequest request) throws Exception;
/**
* 给定实体类名查询所有实体
* @param entityClassName 实体类名,此参数需要类的全路径名(实现方法中使用了Class.forName())
* @param request
* @return List
* @throws Exception
*/
public List findAll(String entityClassName ,HttpServletRequest request) throws Exception;
/**
* 给定一个hql语句来查询某列值,如select max(),select count(*),select (colunmname)...
* @param hql Hiberate的hql语句
* @param request
* @return Object返回一个单一对象,可能为字符串类,也可能返回各种数字类,所以取得返回值后,要对返回的Object进行类型转换。
* @throws Exception
*/
public List findByHqlQuery(String hql ,HttpServletRequest request) throws Exception;
/**
* 设定criteria查询条件进行查询
* @param criteria 查询条件类
* @param request
* @return
* @throws Exception
*/
public List findByDetachedCriteria(DetachedCriteria criteria ,HttpServletRequest request) throws Exception;
/**
* 根据查询条件类中的字段值作为查询条件进行查询,查询条件类的字段在查询时是进行相等性匹配的,不支持like模糊查询。
* @param conditionEntity 条件类,此类中各列的值作为查询条件。
* @param request
* @return
* @throws Exception
*/
public List findSimilarEntities(AbstractEntity conditionEntity ,HttpServletRequest request) throws Exception;
/**
*
* @param hql
* @param request
* @return
* @throws Exception
*/
public Object findSingleValueByHql(String hql,HttpServletRequest request) throws Exception;
/**
* 给定一个sql语句来查询某列值,如select max(),select count(*),select (colunmname)...
* @param sql sql语句
* @param request
* @return Object返回一个单一对象,可能为字符串类,也可能返回各种数字类,所以取得返回值后,要对返回的Object进行类型转换。
* @throws Exception
*/
public Object findSingleValueBySql(String sql,HttpServletRequest request) throws Exception;
/**
* 执行delete或update的Hibernate HQL语句
* @param hql hql语句
* @param request
* @throws Exception
*/
public void updateHql(String hql,HttpServletRequest request) throws Exception;
/**
* 执行delete或update 的SQL语句
* @param sql SQL语句
* @param request
* @throws Exception
*/
public void updateSql(String sql,HttpServletRequest request) throws Exception;
/**
* 返回一个org.apache.struts.util.LabelValueBean的List
* @param sql 此sql的格式为select code,name from ... where...,返回由代码名称两字段构成的org.apache.struts.util.LabelValueBean
* @param request
* @return List org.apache.struts.util.LabelValueBean
* @throws Exception
*/
public List findLabelValueBean(String sql,HttpServletRequest request ) throws Exception;
/**
* 给定Hibernate where条件进行分页查询,e.g List list = ServiceLocator.getDBSupportService().findPage("CmsApp"," order by appSenname asc",1,2,null);
* @param entityClassName 要查询的实体类名
* @param hqlWhere Hibernate的HQL Where语句
* @param currentPage 当前页面
* @param linePerPage 每页行数
* @param request
* @return List 实体类的列表
* @throws Exception
*/
public List findPage(String entityClassName,String hqlWhere,int currentPage,int linePerPage,HttpServletRequest request ) throws Exception;
}