首先声明,本文所述只是鉴于本人在开发一些应用时的心得,仅供参考。
1、现在的绝大多数web应用,通常都以action、service、dao三层去组织代码,这样划分结构很清晰,分工明确
2、一般情况下,我们会把事务控制在service层。
3、action和dao层,会使用一些框架技术。比如action层可能选择有springmvc、struts等,dao层有hibernate、mybatis等选择,所以action的dao有可能遂根据情况变化,而service层关注业务逻辑,业务代码都是自己完成的,代码对自己是透明的。
基于1,我们的每个业务,可能都需要这三层代码,也就是因为一个很简单的业务,我们会写dao层及实现,service层及实现,action层,这样会造成很多的类。所以最好做到dao层必须通用,service层绝大部分通用,这样就会减少大量的类。
基于2,我们应把业务逻辑写在service层,这样才能控制住事务。例如我们的一个业务:删除A记录,插入B记录(需要在一个事务里进行),如果我们把这个业务逻辑写在了action层,我们再action层调用删除A的service,然后再调用插入B的service,如果说插入B失败了,那我们删除A这个操作将不能回滚,因为事务控制在了service层,这样写已不是一个事务。删除A操作的service已经完成,事务已经提交了,插入B的操作在另外的事务里运行。根据需要,业务逻辑尽量放在service层。通过配置spring事务控制的传播行为,在service层可以达到大部分的业务事务要求,而不需另加一层。
基于3,我们更应该把与业务相关的代码移至service层,如果service层的事务不容易控制了,可以增加额外的support层(个人理解,其实还是业务逻辑层)协助控制事务。这主要发生在我们把整个业务逻辑放在了service的一个方法,而这个方法以及调用的方法的事务配置为required(或其他),但业务的部分操作需要在不同的事务中进行,我们不想写另外的方法,也不想去更改事务配置,所以引入support层(或许你说可以把这种逻辑向action层移动,在action层处理,但记住我们的前提,action的框架是会变的,我们想尽量做到更改action层时,更简单。而且从分工来说,action层应该只关注视图逻辑,个人自扫门前雪,休管他人瓦上霜)。support层当然不是只为处理这种事务问题的,我把它定义为业务处理时需要的一些辅助层,可以协助处理业务,比如刚才说的事务问题,还有可以提供工具类支持等。
对于dao层,应该只关注数据库连接执行结果封装这些事。
我们的通用,是基于以上的分析结论进行,下面贴上代码:
通用dao层:
package com.wls.websvn.dao;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import com.wls.websvn.support.Page;
public interface CommonDao {
/**
*
* 增加一个实体
* @param pojo
* @return 影响的行数 0失败,1成功
*/
public int save(T pojo);
/**
*
* 通过id删除实体
*
* @param clazz
* @param id
* @return
*/
public int deleteById(Class clazz,
Serializable id);
/**
*
* 通过主键获取实体
*
* @param clazz
* @param id
* @return
*/
public T getById(Class clazz, Serializable id);
/**
*
* 查询所有实体
*
* @param clazz
* @return
*/
public List listAll(Class clazz);
/**
*
* 分页查询
*
* @param clazz
* @param p
* @return
*/
public Page pageSelect(Class clazz,Page p,String[]attrs,Object[]values);
/**
*
* 分页查询时,用来统计总条数
*
* @param clazz
* @param attrs
* @param values
* @return
*/
public int pageCount(Class clazz,String[]attrs,Object[]values);
/**
*
* 统计总条数
*
* @param clazz
* @return
*/
public int countAll(Class clazz);
/**
*
* 指定查询使用的命名sql,查询结果封装成map
*
* @param statment
* @param paraMap
* @return
*/
List
dao层实现:
package com.wls.websvn.dao.mybatis;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Repository;
import com.wls.websvn.dao.CommonDao;
import com.wls.websvn.support.Page;
@Repository("commonDao")
public class CommonDaoImpl implements CommonDao {
@Resource(name = "sqlSessionFactory")
protected SqlSessionFactory sqlSessionFactory;
protected String getStatement(Class clazz, String prefix) {
String entityName = clazz.getSimpleName();
if (entityName.endsWith("Model")) {
entityName = entityName.substring(0, entityName.length() - 5);
}
entityName = prefix + entityName;
return entityName;
}
@Override
public int save(T pojo) {
String statement = getStatement(pojo.getClass(), "insert");
return sqlSessionFactory.openSession().insert(statement, pojo);
}
@Override
public int deleteById(Class clazz,
Serializable id) {
String statement = getStatement(clazz, "idDelete");
return sqlSessionFactory.openSession().update(statement, id);
}
@Override
public T getById(Class clazz, Serializable id) {
String statement = getStatement(clazz, "idGet");
return sqlSessionFactory.openSession().selectOne(statement, id);
}
@Override
public List listAll(Class clazz) {
String statement = getStatement(clazz, "list");
return sqlSessionFactory.openSession().selectList(statement);
}
/**
*
* 组装排序串
*
* @param sort
* @param order 最好将order定义成枚举类型,传递一个枚举数组
* @return
*/
private String genOrderStr(String sort, String order) {
String orderBy = "";
if (StringUtils.isNotBlank(sort)) {
if (StringUtils.isNotBlank(order)) {
StringBuilder sb = new StringBuilder(" ");
String[] aSort = sort.split(",");
String[] aOrder = order.split(",");
for (int i = 0; i < aSort.length; i++) {
sb.append(aSort[i]).append(" ");
if (i < aOrder.length) {
sb.append(aOrder[i]).append(",");
} else {
sb.append("ASC").append(",");
}
}
// 删除最后一个,
sb.deleteCharAt(sb.length() - 1);
orderBy = sb.toString();
} else {
orderBy = " order by " + sort;
}
}
return orderBy;
}
@Override
public int pageCount(Class clazz,
String[] attrs, Object[] values) {
Map paraMap = new HashMap();
if (values != null && attrs != null) {
for (int i = 0; i < values.length; i++) {
if (i < attrs.length) {
paraMap.put(attrs[i], values[i]);
}
}
}
String statement = getStatement(clazz, "pageCount");
Object o = sqlSessionFactory.openSession().selectOne(statement,paraMap);
return Integer.parseInt(o.toString());
}
@Override
public Page pageSelect(Class clazz,
Page p, String[] attrs, Object[] values) {
int startNum = p.getStartIndex();
int pageSize = p.getPageSize();
String orderBy = genOrderStr(p.getSort(), p.getOrder());
Map paraMap = new HashMap();
if (values != null && attrs != null) {
for (int i = 0; i < values.length; i++) {
if (i < attrs.length) {
paraMap.put(attrs[i], values[i]);
}
}
}
String statement = getStatement(clazz, "page");
p.setTotal(pageCount(clazz, attrs, values));
paraMap.put("startNum", startNum);
paraMap.put("pageSize", pageSize);
paraMap.put("endNum", startNum + pageSize);
paraMap.put("orderBy", orderBy);
List list = sqlSessionFactory.openSession().selectList(statement,
paraMap);
p.setData(list);
return p;
}
@Override
public int countAll(Class clazz) {
String statement = getStatement(clazz, "count");
Object o = sqlSessionFactory.openSession().selectOne(statement);
return Integer.parseInt(o.toString());
}
@Override
public List
package com.wls.websvn.support;
import java.util.List;
public class Page {
/**
* 页码
*/
private int page = 1;
/**
* 每页条数
*/
private int pageSize = 10;
/**
* 总记录数
*/
private long total;
/**
* 排序列
*/
private String sort;
/**
* 升降序
*/
private String order;
/**
* 单页数据
*/
private List data;
public Page() {
this.page = 1;
this.pageSize = 10;
}
public Page(int page, int pageSize) {
this.page = page;
this.pageSize = pageSize;
}
/**
* 获取page值
* @return int page.
*/
public int getPage() {
return page;
}
/**
* 设置page值
* @param page The page to set.
*/
public void setPage(int page) {
this.page = page;
}
/**
* 获取pageSize值
* @return int pageSize.
*/
public int getPageSize() {
return pageSize;
}
/**
* 设置pageSize值
* @param pageSize The pageSize to set.
*/
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
/**
* 获取data值
* @return List data.
*/
public List getData() {
return data;
}
/**
* 设置data值
* @param data The data to set.
*/
public void setData(List data) {
this.data = data;
}
/**
* 获取total值
* @return long total.
*/
public long getTotal() {
return total;
}
/**
* 设置total值
* @param total The total to set.
*/
public void setTotal(long total) {
this.total = total;
}
public String getSort() {
return sort;
}
public void setSort(String sort) {
this.sort = sort;
}
/**
* @return the order
*/
public String getOrder() {
return order;
}
/**
* @param order the order to set
*/
public void setOrder(String order) {
this.order = order;
}
/**
*
* 获取分页开始的位置
*
* @return
*/
public int getStartIndex() {
if(page<1){
return 0;
}
return (page - 1) * pageSize;
}
}
package com.wls.websvn.service;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import com.wls.websvn.support.Page;
public interface CommonService {
/**
*
* 增加一个实体
* @param pojo
* @return 影响的行数 0失败,1成功
*/
public int save(T pojo);
/**
*
* 通过id删除实体
*
* @param clazz
* @param id
* @return
*/
public int deleteById(Class clazz,
Serializable id);
/**
*
* 通过主键获取实体
*
* @param clazz
* @param id
* @return
*/
public T getById(Class clazz, Serializable id);
/**
*
* 查询所有实体
*
* @param clazz
* @return
*/
public List listAll(Class clazz);
/**
*
* 分页查询
*
* @param clazz
* @param p
* @return
*/
public Page pageSelect(Class clazz,Page p,String[]attrs,Object[]values);
/**
*
* 分页查询时,用来统计总条数
*
* @param clazz
* @param attrs
* @param values
* @return
*/
public int pageCount(Class clazz,String[]attrs,Object[]values);
/**
*
* 统计总条数
*
* @param clazz
* @return
*/
public int countAll(Class clazz);
/**
*
* 指定查询使用的命名sql,查询结果封装成map
*
* @param statment
* @param paraMap
* @return
*/
List
package com.wls.websvn.service.impl;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.wls.websvn.dao.CommonDao;
import com.wls.websvn.service.CommonService;
import com.wls.websvn.support.Page;
/**
*
* @author weilisky
* 考虑将来可能切换到hibernate或其他框架的情况,尽量的将切换时不用变的代码移到service层。
* 将切换时可能会变更的代码放在了dao层
*
*/
@Service("commonService")
public class CommonServiceImpl implements CommonService {
@Resource(name = "commonDao")
protected CommonDao commonDao;
@Override
public int save(T pojo) {
return commonDao.save(pojo);
}
@Override
public int deleteById(Class clazz,
Serializable id) {
return commonDao.deleteById(clazz, id);
}
@Override
public T getById(Class clazz, Serializable id) {
return commonDao.getById(clazz, id);
}
@Override
public List listAll(Class clazz) {
return commonDao.listAll(clazz);
}
@Override
public int pageCount(Class clazz,
String[] attrs, Object[] values) {
return commonDao.pageCount(clazz, attrs, values);
}
@Override
public Page pageSelect(Class clazz,
Page p, String[] attrs, Object[] values) {
return commonDao.pageSelect(clazz, p, attrs, values);
}
@Override
public int countAll(Class clazz) {
return commonDao.countAll(clazz);
}
@Override
public List
如果CommonService不够用了,你的接口应该继承CommonService接口,你的实现应该继承CommonServiceImpl实现,然后根据需要override其中的一些方法。
需要说明一下,我们把protected
最后附上例子model和mapping:
package com.wls.websvn.model;
import java.io.Serializable;
import java.util.Date;
public class BaseModel implements Serializable{
/**
*
*/
private static final long serialVersionUID = -459530011111182045L;
protected Long id;
protected Date createDate;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
}
package com.wls.websvn.model;
public class UserModel extends BaseModel {
/**
*
*/
private static final long serialVersionUID = 5715947400419117755L;
//登录名
private String userName;
//真实姓名
private String realName;
//密码
private String userPwd;
private String phoneNum;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
}
insert into
SVN_USER(ID_,
NAME_, REALNAME_, PASSWORD_, MOBILEPHONE_,CREATE_TIME_)
values
(#{id,
jdbcType=BIGINT},
#{userName, jdbcType=VARCHAR},
#{realName,
jdbcType=VARCHAR},
#{userPwd, jdbcType=VARCHAR},
#{phoneNum,
jdbcType=VARCHAR},
#{createDate,
jdbcType=TIMESTAMP})
DELETE FROM
SVN_USER WHERE ID_=#{id,jdbcType=BIGINT}
applicationContext-dao.xml
applicationContext-service.xml