转自:Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1320284
作者:海星 猪的克星
最近参与一个项目,使用Struts作为web层框架。在开发过程中,有大量比如CRUD之类的业务,使用相同的ActionForm,因此在处理这些业务时使用DispatchAction是非常方便的,而且代码也集中在一个类中被多个方法分割。因此,比较容易进行修改和维护。
但是当同时结合Apache的Validation框架使用时,就会出现问题。如果在配置Action时没有关闭Validation那么所有的form在构造或重新利用时都将进行验证,比如:在显示增加界面是不需要进行Form验证,在提交增加时不需要进行Form验证。另外,增加时和编辑时的Input是不同,但是Action配置时只能提供一个Input元素。
针对以上问题我的处理方法是扩展Struts,首先我想做的是让Struts根据配置来进行验证,也就是说对需要进行Form验证的方法使用验证,在验证不成功时根据每个方法的配置返回不同的Input。对不需要进行Form的方法不使用验证。打开Struts(1.2.9)的代码,在RequestProcessor类中有这样一个方法:
protected boolean processValidate(HttpServletRequest request, HttpServletResponse response, ActionForm form, ActionMapping mapping)
这个方法是在创建(或者从新利用)Form之后进行Form验证的方法,我们可以复写这个方法,对于需要进行验证的DispatchAction中的方法我们不进行处理,由RequestProcessor进行处理,对于不需要进行Form验证的方法我们默认返回验证成功。以下是我继承RequestProcessor后的新类:
package mahaixing.struts; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.InvalidCancelException; import org.apache.struts.action.RequestProcessor; /** *//** * @author 马海星 2006-9-25 * * 您可以任意使用和修改这些代码. */ public class DispatchRequestProcessor extends RequestProcessor ...{ protected boolean processValidate(HttpServletRequest request, HttpServletResponse response, ActionForm form, ActionMapping mapping) throws IOException, ServletException, InvalidCancelException ...{ DispatchActionMapping bam = null; if (mapping instanceof DispatchActionMapping) ...{ bam = (DispatchActionMapping)mapping; } else ...{ return super.processValidate(request, response, form, mapping); } if (mapping.getParameter() == null) ...{ return super.processValidate(request, response, form, mapping); } String parameter = request.getParameter(mapping.getParameter()); if (parameter == null) ...{ return super.processValidate(request, response, form, bam); } parameter = parameter.trim().toLowerCase(); if (bam.containsIgnore(parameter)) ...{ return true; } else ...{ bam.setNoIgnore(parameter); } return super.processValidate(request, response, form, bam); } }这里使用到了一个DispatchActionMapping类,这个类是作为配置支持的,大家知道ActionMapping(也就是后续版本中的ActionConfig)是用来配置Action的,因此,为了达到我的目的需要扩展ActionMapping:
package mahaixing.struts; import java.util.ArrayList; import java.util.HashMap; import java.util.StringTokenizer; import org.apache.struts.action.ActionMapping; /** *//** * @author 马海星 2006-9-25 * * 您可以任意使用和修改这些代码. * * Struts的ActionMapping的扩展,主要是为BaseAction服务(BaseAction继承了org.apache.struts.actions.DispatchAction) * 所以这个类也可以用在DispathAction上。 * * 作用: * 1. 可以指定不需要进行Form验证的Action方法 (通过DispatchAction的paratement指定的参数) * 2. 可以指定需要进行Form验证的Action方法以及对应的Input * * 配置方法(struts-config.xml): * 1. <action-mappings type="mahaixing.BaseActionMapping"> * 2. <action classname="mahaixing.BaseActionMapping"> * * 这个类需要配合使用BaseRequestProcessor,那么就需要在配置文件(struts-config.xml)中进行如下配置: * <controller processorClass="mahaixing.BaseRequestProcessor"/> * * Action的写法: * <action path="/news" * name="newsForm" * type="mahaixing.NewsAction" * input="/default_input" * scope="request"> * <set-property property="ignores" value="addShow,delete,modifyShow"/> * <set-property property="inputs" value="add=/news/addNews.jsp, modify=/news/modifyNews.jsp"/> * <forward name="list" path="/news/listNewsForManagement.do"/> * <forward name="addShow" path="/news/addNews.jsp"/> * <forward name="modifyShow" path="/news/modifyNews.jsp"/> * <forward name="list" path="/news/listNewsForManagement.do"/> * </action> * * <set-property property="ignores" value="addShow,delete,modifyShow"/> * 这个配置指定:addShow, delete, modifyShow时不需要进行Form验证,那么其他的所有方法都将进新Form验证。 * * <set-property property="inputs" value="add=/news/addNews.jsp, modify=/news/modifyNews.jsp"/> * 指定add方法的input是/news/addNews.jsp,modify方法的Input是/news/modifyNews.jsp。如果在Action中的其他方法没有在这里指 * 定,那么都将默认返回action中的input。 * * action标签中的input为默认的input,不知道为什么ActionMapping是默认保存在Session中 * */ public class DispatchActionMapping extends ActionMapping ...{ private static final long serialVersionUID = -4695833433866065225L; /** *//** * 不需要进行Form验证的方法名称列表 */ private ArrayList ignores = new ArrayList(); /** *//** * 需要进行Form验证的方法名称以及Input的map */ private HashMap inputs = new HashMap(); /** *//** * 当前需要验证的方法名 */ private String currentNoIgnore = null; /** *//** * 设置当前需要验证的方法名 * * @param parameter */ public void setNoIgnore(String parameter) ...{ currentNoIgnore = parameter; } /** *//** * 设置需要验证的方法名以及Input * 各个名称之间以","分割,名称与input之间以"="分割 * * @param inputs */ public void setInputs(String inputs) ...{ StringTokenizer st = new StringTokenizer(inputs, ","); while (st.hasMoreTokens()) ...{ String input = st.nextToken().trim(); //如果去掉空格后字符串长度为0,那么跳过 if (input.length() > 0) parseInput(input); } } /** *//** * 解析方法名及input,以"="分割 * @param input */ protected void parseInput(String input) ...{ StringTokenizer st = new StringTokenizer(input, "="); //方法名,默认为null String key = null; //名称默认为null String forward = null; //因为传递过来的字符窜长度大于0,所以这个方法不会失效 key = st.nextToken().toLowerCase(); //如果没有写input,那么input为null if (st.hasMoreElements()) forward = st.nextToken().trim(); inputs.put(key, forward); }