spring+mybatis通用dao層、service層的一些個人理解與實現
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層:
[java] view plain copy print?- package com.wls.websvn.dao;
- import java.io.Serializable;
- import java.util.List;
- import java.util.Map;
- import com.wls.websvn.support.Page;
- publicinterface CommonDao {
- /**
- *
- * 增加一個實體
- * @param pojo
- * @return 影響的行數 0失敗,1成功
- */
- public <T extends Serializable> int save(T pojo);
- /**
- *
- * 通過id刪除實體
- *
- * @param clazz
- * @param id
- * @return
- */
- public <T extends Serializable> int deleteById(Class<T> clazz,
- Serializable id);
- /**
- *
- * 通過主鍵獲取實體
- *
- * @param clazz
- * @param id
- * @return
- */
- public <T extends Serializable> T getById(Class<T> clazz, Serializable id);
- /**
- *
- * 查詢所有實體
- *
- * @param clazz
- * @return
- */
- public <T extends Serializable> List<T> listAll(Class<T> clazz);
- /**
- *
- * 分頁查詢
- *
- * @param clazz
- * @param p
- * @return
- */
- public <T extends Serializable> Page<T> pageSelect(Class<T> clazz,Page<T> p,String[]attrs,Object[]values);
- /**
- *
- * 分頁查詢時,用來統計總條數
- *
- * @param clazz
- * @param attrs
- * @param values
- * @return
- */
- public <T extends Serializable> int pageCount(Class<T> clazz,String[]attrs,Object[]values);
- /**
- *
- * 統計總條數
- *
- * @param clazz
- * @return
- */
- public <T extends Serializable> int countAll(Class<T> clazz);
- /**
- *
- * 指定查詢使用的命名sql,查詢結果封裝成map
- *
- * @param statment
- * @param paraMap
- * @return
- */
- List<Map<String,Object>> selectMap(String statment, Map<String, Object> paraMap);
- }
dao層實現:
[java] view plain copy print?- 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")
- publicclass CommonDaoImpl implements CommonDao {
- @Resource(name = "sqlSessionFactory")
- protected SqlSessionFactory sqlSessionFactory;
- protected <T> String getStatement(Class<T> 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 <T extends Serializable> int save(T pojo) {
- String statement = getStatement(pojo.getClass(), "insert");
- return sqlSessionFactory.openSession().insert(statement, pojo);
- }
- @Override
- public <T extends Serializable> int deleteById(Class<T> clazz,
- Serializable id) {
- String statement = getStatement(clazz, "idDelete");
- return sqlSessionFactory.openSession().update(statement, id);
- }
- @Override
- public <T extends Serializable> T getById(Class<T> clazz, Serializable id) {
- String statement = getStatement(clazz, "idGet");
- return sqlSessionFactory.openSession().selectOne(statement, id);
- }
- @Override
- public <T extends Serializable> List<T> listAll(Class<T> 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 <T extends Serializable> int pageCount(Class<T> clazz,
- String[] attrs, Object[] values) {
- Map<String, Object> paraMap = new HashMap<String, Object>();
- 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 <T extends Serializable> Page<T> pageSelect(Class<T> clazz,
- Page<T> p, String[] attrs, Object[] values) {
- int startNum = p.getStartIndex();
- int pageSize = p.getPageSize();
- String orderBy = genOrderStr(p.getSort(), p.getOrder());
- Map<String, Object> paraMap = new HashMap<String, Object>();
- 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<T> list = sqlSessionFactory.openSession().selectList(statement,
- paraMap);
- p.setData(list);
- return p;
- }
- @Override
- public <T extends Serializable> int countAll(Class<T> clazz) {
- String statement = getStatement(clazz, "count");
- Object o = sqlSessionFactory.openSession().selectOne(statement);
- return Integer.parseInt(o.toString());
- }
- @Override
- public List<Map<String, Object>> selectMap(String statement,
- Map<String, Object> paraMap) {
- return sqlSessionFactory.openSession().selectList(statement, paraMap);
- }
- }
- package com.wls.websvn.support;
- import java.util.List;
- publicclass Page<T> {
- /**
- * 頁碼
- */
- privateint page = 1;
- /**
- * 每頁條數
- */
- privateint pageSize = 10;
- /**
- * 總記錄數
- */
- privatelong total;
- /**
- * 排序列
- */
- private String sort;
- /**
- * 升降序
- */
- private String order;
- /**
- * 單頁資料
- */
- private List<T> 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.
- */
- publicint getPage() {
- return page;
- }
- /**
- * 設定page值
- * @param page The page to set.
- */
- publicvoid setPage(int page) {
- this.page = page;
- }
- /**
- * 獲取pageSize值
- * @return int pageSize.
- */
- publicint getPageSize() {
- return pageSize;
- }
- /**
- * 設定pageSize值
- * @param pageSize The pageSize to set.
- */
- publicvoid setPageSize(int pageSize) {
- this.pageSize = pageSize;
- }
- /**
- * 獲取data值
- * @return List<T> data.
- */
- public List<T> getData() {
- return data;
- }
- /**
- * 設定data值
- * @param data The data to set.
- */
- publicvoid setData(List<T> data) {
- this.data = data;
- }
- /**
- * 獲取total值
- * @return long total.
- */
- publiclong getTotal() {
- return total;
- }
- /**
- * 設定total值
- * @param total The total to set.
- */
- publicvoid setTotal(long total) {
- this.total = total;
- }
- public String getSort() {
- return sort;
- }
- publicvoid setSort(String sort) {
- this.sort = sort;
- }
- /**
- * @return the order
- */
- public String getOrder() {
- return order;
- }
- /**
- * @param order the order to set
- */
- publicvoid setOrder(String order) {
- this.order = order;
- }
- /**
- *
- * 獲取分頁開始的位置
- *
- * @return
- */
- publicint getStartIndex() {
- if(page<1){
- return0;
- }
- 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;
- publicinterface CommonService {
- /**
- *
- * 增加一個實體
- * @param pojo
- * @return 影響的行數 0失敗,1成功
- */
- public <T extends Serializable> int save(T pojo);
- /**
- *
- * 通過id刪除實體
- *
- * @param clazz
- * @param id
- * @return
- */
- public <T extends Serializable> int deleteById(Class<T> clazz,
- Serializable id);
- /**
- *
- * 通過主鍵獲取實體
- *
- * @param clazz
- * @param id
- * @return
- */
- public <T extends Serializable> T getById(Class<T> clazz, Serializable id);
- /**
- *
- * 查詢所有實體
- *
- * @param clazz
- * @return
- */
- public <T extends Serializable> List<T> listAll(Class<T> clazz);
- /**
- *
- * 分頁查詢
- *
- * @param clazz
- * @param p
- * @return
- */
- public <T extends Serializable> Page<T> pageSelect(Class<T> clazz,Page<T> p,String[]attrs,Object[]values);
- /**
- *
- * 分頁查詢時,用來統計總條數
- *
- * @param clazz
- * @param attrs
- * @param values
- * @return
- */
- public <T extends Serializable> int pageCount(Class<T> clazz,String[]attrs,Object[]values);
- /**
- *
- * 統計總條數
- *
- * @param clazz
- * @return
- */
- public <T extends Serializable> int countAll(Class<T> clazz);
- /**
- *
- * 指定查詢使用的命名sql,查詢結果封裝成map
- *
- * @param statment
- * @param paraMap
- * @return
- */
- List<Map<String,Object>> selectMap(String statment, Map<String, Object> paraMap);
- }
- 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")
- publicclass CommonServiceImpl implements CommonService {
- @Resource(name = "commonDao")
- protected CommonDao commonDao;
- @Override
- public <T extends Serializable> int save(T pojo) {
- return commonDao.save(pojo);
- }
- @Override
- public <T extends Serializable> int deleteById(Class<T> clazz,
- Serializable id) {
- return commonDao.deleteById(clazz, id);
- }
- @Override
- public <T extends Serializable> T getById(Class<T> clazz, Serializable id) {
- return commonDao.getById(clazz, id);
- }
- @Override
- public <T extends Serializable> List<T> listAll(Class<T> clazz) {
- return commonDao.listAll(clazz);
- }
- @Override
- public <T extends Serializable> int pageCount(Class<T> clazz,
- String[] attrs, Object[] values) {
- return commonDao.pageCount(clazz, attrs, values);
- }
- @Override
- public <T extends Serializable> Page<T> pageSelect(Class<T> clazz,
- Page<T> p, String[] attrs, Object[] values) {
- return commonDao.pageSelect(clazz, p, attrs, values);
- }
- @Override
- public <T extends Serializable> int countAll(Class<T> clazz) {
- return commonDao.countAll(clazz);
- }
- @Override
- public List<Map<String, Object>> selectMap(String statement,
- Map<String, Object> paraMap) {
- return commonDao.selectMap(statement, paraMap);
- }
- }
如果CommonService不夠用了,你的介面應該繼承CommonService介面,你的實現應該繼承CommonServiceImpl實現,然後根據需要override其中的一些方法。
需要說明一下,我們把protected <T> String getStatement(Class<T> clazz, String prefix)放置在dao層,因為它並不是業務邏輯的一部分,而且對於mybaits框架,你需要這個方法,而對應hibenate你可能根本不需要(或則可以把這個方法重構到另外的一個介面)。
最後附上例子model和mapping:
[java] view plain copy print?- package com.wls.websvn.model;
- import java.io.Serializable;
- import java.util.Date;
- publicclass BaseModel implements Serializable{
- /**
- *
- */
- privatestaticfinallong serialVersionUID = -459530011111182045L;
- protected Long id;
- protected Date createDate;
- public Long getId() {
- return id;
- }
- publicvoid setId(Long id) {
- this.id = id;
- }
- public Date getCreateDate() {
- return createDate;
- }
- publicvoid setCreateDate(Date createDate) {
- this.createDate = createDate;
- }
- }
- package com.wls.websvn.model;
- publicclass UserModel extends BaseModel {
- /**
- *
- */
- privatestaticfinallong serialVersionUID = 5715947400419117755L;
- //登入名
- private String userName;
- //真實姓名
- private String realName;
- //密碼
- private String userPwd;
- private String phoneNum;
- public String getUserName() {
- return userName;
- }
- publicvoid setUserName(String userName) {
- this.userName = userName;
- }