转自: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);
}