在基于Model2的應用中,控制層的類總會包含對業務層諸類的調用,業務層諸類不可避免的要產生各種異常,如果統一到控制層進行處理的話會導致代碼變得龐大臃腫還有不少重復,這種的例子在Web應用中的Servlet和Action諸類中并不少見。
如果我們使用模板方法模式(Template Method Pattern)將業務處理和異常處理分開,能有效簡化控制層諸類的代碼,借用這種模式,我們可以把固定的異常處理代碼放在基類中,而讓子類來實現具體的業務,如果執行業務過程中出現異常如數據庫無法連接,用戶找不到等異常后,直接將異常拋出讓基類來處理,這樣做成功的把業務處理和異常處理分開到了子類和基類兩種類中,涉及具體業務處理的子類代碼得到了很大的簡化,更方便閱讀,修改和管理。
具體請參考以下代碼:
諸Action的基類,包含了所有的異常處理,它是一個抽象類,規定子類必需實現process函數:
package com.heyang.action.base;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.TypeMismatchDataAccessException;

import com.heyang.domain.User;
import com.heyang.exception.database.CannotFindRecordByIdException;
import com.heyang.exception.database.OneIdMultiRecordException;
import com.heyang.exception.user.CannotFindUserInSessionException;
import com.heyang.exception.user.ErrorPswdException;


/** *//**
* 各個Action的基類
* @author 何楊(heyang78@gmail.com)
*
* @since 2008-8-29 上午09:00:48
* @version 1.00
*/

public abstract class BizBaseAction extends Action
{
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)

throws Exception
{
request.setCharacterEncoding("UTF-8");

try
{
return process(mapping,form,request,response);
}

catch(CannotFindUserInSessionException ex)
{
// 用戶名不存在
request.setAttribute("msg", "在session中找不到用戶,要執行操作請先登錄");
return new ActionForward("/web/page/login.jsp");
}

catch(CannotFindRecordByIdException ex)
{
// 用戶名不存在
request.setAttribute("msg", "用戶名不存在,請重新輸入");
return new ActionForward("/web/page/login.jsp");
}

catch(ErrorPswdException ex)
{
// 用戶登錄密碼錯誤
request.setAttribute("msg", "密碼錯誤,請重新輸入");
return new ActionForward("/web/page/login.jsp");
}

catch(OneIdMultiRecordException ex)
{
// 系統發生重大問題,一個用戶名對應著多條記錄
request.setAttribute("feedbackTitle", "系統發生重大問題");
request.setAttribute("feedbackConcept", "系統發生重大問題,成員用戶名對應著多條記錄,報告此錯誤的郵件已經發給系統管理員,請耐心等候處理。");
return new ActionForward("/web/page/result.jsp");
}

catch(TypeMismatchDataAccessException ex)
{
request.setAttribute("feedbackTitle", "Java類型和數據類型不匹配.");
request.setAttribute("feedbackConcept", "錯誤信息為"+ex.getMessage());
return new ActionForward("/web/page/result.jsp");
}

catch(DataAccessResourceFailureException ex)
{
request.setAttribute("feedbackTitle", "無法連接到數據庫,請檢查數據庫連接是否正確.");
request.setAttribute("feedbackConcept", "錯誤信息為"+ex.getMessage());
return new ActionForward("/web/page/result.jsp");
}

catch(DataIntegrityViolationException ex)
{
request.setAttribute("feedbackTitle", "Insert或Update數據時違反了完整性.");
request.setAttribute("feedbackConcept", "錯誤信息為"+ex.getMessage());
return new ActionForward("/web/page/result.jsp");
}

catch(InvalidDataAccessResourceUsageException ex)
{
request.setAttribute("feedbackTitle", "使用錯誤的SQL語句或數據訪問關系型數據庫.");
request.setAttribute("feedbackConcept", "錯誤信息為"+ex.getMessage());
return new ActionForward("/web/page/result.jsp");
}

catch(Exception ex)
{
request.setAttribute("feedbackTitle", "未知的錯誤");
request.setAttribute("feedbackConcept", "錯誤信息為"+ex.getMessage());
return new ActionForward("/web/page/result.jsp");
}
}

/** *//**
* 留待子類實現業務
* @param mapping
* @param form
* @param request
* @param response
* @return
* @throws Exception
*/
protected abstract ActionForward process(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception ;


/** *//**
* 從Session中找出登錄用戶
* @param request
* @return
* @throws CannotFindUserInSessionException
*/

protected User getUser(HttpServletRequest request) throws CannotFindUserInSessionException
{
// 從Session中取得用戶
User user = (User) request.getSession().getAttribute("user");

if (user == null)
{
throw new CannotFindUserInSessionException("在session中找不到用戶");
}
return user;
}
}

子類之一loginAction,只需實現簡短的process函數即可,所有異常拋出由基類處理:
package com.heyang.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.heyang.action.base.BizBaseAction;
import com.heyang.domain.User;
import com.heyang.service.UserService;
import com.heyang.util.ReqUtil;
import com.heyang.util.SpringUtil;


/** *//**
* 用于用戶登錄的Action
* @author 何楊(heyang78@gmail.com)
*
* @since 2008-8-29 上午09:00:48
* @version 1.00
*/

public final class LoginAction extends BizBaseAction
{
public ActionForward process(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)

throws Exception
{
request.setCharacterEncoding("UTF-8");
// 取得參數
String name = ReqUtil.getFormProperty("name",form);
String pswd = ReqUtil.getFormProperty("pswd",form);
// 取得Service
UserService service=SpringUtil.getUserService();
// 取得用戶
User user=service.getUser(name, pswd);
request.getSession().setAttribute("user", user);
return new ActionForward("/ShowBlocks.do");
}
}
這樣完成以后,對子類來說,只需要關心業務代碼即可,出現異常后的處理和轉向都由基類規定的模板方法完成,這正是模板方法模式給我們帶來的好處。有點疑惑的是,現在還不確定這樣做會有什么消極印象,如安全性或結構方面的,大家要是覺得有問題請不吝賜教。