在基于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");
}
}
这样完成以后,对子类来说,只需要关心业务代码即可,出现异常后的处理和转向都由基类规定的模板方法完成,这正是模板方法模式给我们带来的好处。有点疑惑的是,现在还不确定这样做会有什么消极印象,如安全性或结构方面的,大家要是觉得有问题请不吝赐教。