Struts的动态表单的应用 
原文连接:http://www.developer.com/java/web/article.php/2214681 
By James M. Turner 
  
这篇文章以实例代码来阐述Dynaforms在struts1.1种的引用——译者注 
  
如果你使用过struts先前的版本,你就会注意到你需要花费大量的时候来写ActionForm类文件,而这些类文件对于struts都是非常关键的(它充当“View”的一部分),通常它的结构就是bean properties在加上一个validate方法(有时还有reset方法)。 
随着struts1.1版本的推出,开发员有了另外一种方法来完成前面的任务:使用DynaBeans。DynaBeans动态生成Java Beans。这就意味着我们可以通过配置(通常利用xml) 
来生成formbean而不是在formbean中硬编码。 
为了了解DynaBeans(struts中为Dynaforms)是如何工做的,让我们看一个简单的表单,字段有:name,address,telephone等,下面的代码为通常的写法(没有使用Dynaforms)。 
  
article1.CustomerForm 
  package article1;   import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionError; import javax.servlet.http.HttpServletRequest;   public class CustomerForm extends ActionForm {      protected boolean nullOrBlank (String str) {        return ((str == null) || (str.length() == 0));     }     public  ActionErrors validate(ActionMapping mapping,             HttpServletRequest request) {        ActionErrors errors = new ActionErrors();         if (nullOrBlank(lastName)) {            errors.add("lastName",                   new ActionError("article1.lastName.missing"));        }         if (nullOrBlank(firstName)) {            errors.add("firstName",                   new ActionError("article1.firstName.missing"));        }         if (nullOrBlank(street)) {            errors.add("street",                   new ActionError("article1.street.missing"));        }         if (nullOrBlank(city)) {            errors.add("city",                   new ActionError("article1.city.missing"));        }         if (nullOrBlank(state)) {            errors.add("state",                   new ActionError("article1.state.missing"));        }         if (nullOrBlank(postalCode)) {            errors.add("postalCode",                   new ActionError("article1.postalCode.missing"));        }         if (nullOrBlank(phone)) {            errors.add("phone",                   new ActionError("article1.phone.missing"));        }         return errors;     }       private String lastName;     private String firstName;     private String street;     private String city;     private String state;     private String postalCode;     private String phone;       public String getLastName() {        return lastName;     }       public void setLastName(String lastName) {        this.lastName = lastName;     }       public String getFirstName() {        return firstName;     }       public void setFirstName(String firstName) {        this.firstName = firstName;     }       public String getStreet() {        return street;     }       public void setStreet(String street) {        this.street = street;     }       public String getCity() {        return city;     }       public void setCity(String city) {        this.city = city;     }       public String getState() {        return state;     }       public void setState(String state) {        this.state = state;     }       public String getPostalCode() {        return postalCode;     }       public void setPostalCode(String postalCode) {        this.postalCode = postalCode;     }       public String getPhone() {        return phone;     }       public void setPhone(String phone) {        this.phone = phone;     } } 
  
看到上边的写法(这么长一段代码[虽然大多的工具都可以自动生成set和get方法]感想如何?如果要为每一个表单配备一个formbean,那么将是一件多了令人痛苦的事情——译者注),你知道了它是一个标准的JavaBean,只是多了一个validate方法,validate方法确保client断的输入都是合法的。 
  
相应的jsp页面同样也是很简单的,如下: 
  
customer.jsp 
  <%@ taglib uri="/WEB-INF/c.tld" prefix="c" %> <%@ taglib prefix="fmt" uri="/WEB-INF/fmt.tld" %> <%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>   <head> <title>Example of a standard Customer form</title> </head> <h1>Example of a standard Customer form</h1> <html:form action="/addCustomer"> Last Name: <html:text property="lastName"/> <html:errors property="lastName" /><br> First Name: <html:text property="firstName"/> <html:errors property="firstName" /><br> Street Addr: <html:text property="street"/> <html:errors property="street" /><br> City: <html:text property="city"/> <html:errors property="city" /><br> State: <html:text property="state" maxlength="2" size="2" /> <html:errors property="state" /><br> Postal Code: <html:text property="postalCode" maxlength="5"                                               size="5" /> <html:errors property="postalCode" /><br> Telephone: <html:text property="phone" maxlength="11" size="11" /> <html:errors property="phone" /><br> <html:submit/> </html:form> 
  
相应的action也没有复杂的业务代码,只是将从client端传过来的值打印到控制台。 
article1.AddCustomerActionpackage article1;   import org.apache.struts.action.Action; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionForm;   import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.ServletException; import java.io.IOException;   public class AddCustomerAction extends Action {    public ActionForward execute(ActionMapping mapping,                                  ActionForm form,                                  HttpServletRequest request,                                  HttpServletResponse response)     throws ServletException, IOException{        CustomerForm custForm = (CustomerForm) form;         System.out.println("lastName   = "                            + custForm.getLastName());         System.out.println("firstName  = "                            + custForm.getFirstName());         System.out.println("street     = " + custForm.getStreet());        System.out.println("city       = " + custForm.getCity());        System.out.println("state      = " + custForm.getState());        System.out.println("postalCode = "                            + custForm.getPostalCode());         System.out.println("phone      = " + custForm.getPhone());          return mapping.findForward("success");    } } 
  
  
下面看看struts-config.xml的配置,struts利用该配置文件将上述文件联系到一起来协同完成任务。 
  <struts-config> <form-beans> <form-bean name="customerForm" type="jdj.article1.Customer" />       </form-beans> <action-mappings> <action path="/addCustomer" type="article1.AddCustomerAction"                             name="customerForm" scope="request"                             input="/addCustomer.jsp"> <forward name="success" path="/addCustomerSucceeded.jsp"                         redirect="false" /> </action> </action-mappings> <message-resources parameter="ApplicationResources" /> <plug-in className="org.apache.struts.validator.ValidatorPlugIn"> <set-property value="/WEB-INF/validator-rules.xml"               property="pathnames" /> struts-config.xml</plug-in></struts-config> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts-config PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"   "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"> <struts-config>  <form-beans>   <form-bean name="customerForm" type="article1.CustomerForm" />  </form-beans>  <action-mappings>   <action path="/addCustomer" type="article1.AddCustomerAction"           name="customerForm" scope="request" input="/customer.jsp">       <forward name="success" path="/addCustomerSucceeded.jsp"                redirect="false" />   </action>  </action-mappings>  <message-resources parameter="ApplicationResources" />  <plug-in className="org.apache.struts.validator.ValidatorPlugIn">    <set-property value="/WEB-INF/validator-rules.xml"         property="pathnames" />  </plug-in> </struts-config> 
  
上边通过配置,customerForm来引用CustemerForm类, “/addCustomer”action使用customerForm并且触发article1.AddCustomerAction来处理请求。 
  
下图添加customer空表单图片 
  
  
如果什么也没有填就提交了,将会出现下图的反馈信息: 
  
  
如果你所有输入的信息都合法,那么在控制台你可以看到如下类似的信息: 
  lastName = Bush firstName = George street = 1600 Pennsylvania Avenue NW city = Washington state = DC postalCode = 20500 phone = 2024561414 
  
  
到现在为止,上边代码熟悉struts得都应该很熟悉但是,如果应用struts1.1的新特性,你将会用更少的代码来完成上述同样的功能。使用Dynaforms,我们应该更改customerForm在struts-config.xml中信息来使用org.apache.struts.action.DynaActionForm (为了便于读者比较使用前后的差别,我们将使用新的类新的jsp页面来完成同样的功能) 
  
使用DynaActionForm,你可以利用form-property xml标签,它允许你在struts-config.xml中定义formbean的属性元素。以我们的例子来说,struts-config.xml中将是如下这个样子: 
  <form-bean name="dynaCustomerForm"            type="org.apache.struts.action.DynaActionForm">   <form-property name="lastName" type="java.lang.String"/>   <form-property name="firstName" type="java.lang.String"/>   <form-property type="java.lang.String" name="street"/>   <form-property name="city" type="java.lang.String"/>   <form-property name="state" type="java.lang.String"/>   <form-property name="postalCode" type="java.lang.String"/> </form-bean>   
     上边的改动对于jsp页面没有任何的影响。不过你要对于原来的action进行稍微的改动应为:你现在已经不在向execute()中传递formbean(没有get set方法),所以 你应该把form转型到DynaActionForm,然后利用方法get(filename)来取得client端数据新的action代码如下: 
  
article1.AddDynaCustomerActionpackage article1;   import org.apache.struts.action.*;   import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.ServletException; import java.io.IOException;   public class AddDynaCustomerAction extends Action {  public ActionForward execute(ActionMapping mapping,                                ActionForm form,                                HttpServletRequest request,                                HttpServletResponse response)                        throws ServletException, IOException{  DynaActionForm custForm = (DynaActionForm) form;   System.out.println("lastName   = " + custForm.get("lastName"));  System.out.println("firstName  = " + custForm.get("firstName"));  System.out.println("street     = " + custForm.get("street"));  System.out.println("city       = " + custForm.get("city"));  System.out.println("state      = " + custForm.get("state"));  System.out.println("postalCode = "                      + custForm.get("postalCode"));  System.out.println("phone      = " + custForm.get("phone"));        return mapping.findForward("success");     } } 
  
从上边的代码可以看出,似乎”屏蔽“了actionform,然而我们也“丢失”了一些其他的,譬如:严整输入合法性的问题。有两种方法可以恢复校验功能:一是创建一个DynaActionForm的子类,然后在子类中实现validate()方法。如下代码: 
  
article1.DynaCustomerFormpackage article1;   import org.apache.struts.action.*;   import javax.servlet.http.HttpServletRequest;   public class DynaCustomerForm extends DynaActionForm {  protected boolean nullOrBlank (String str) {  return ((str == null) || (str.length() == 0));  }   public ActionErrors validate(ActionMapping mapping,                     HttpServletRequest request) {  ActionErrors errors = new ActionErrors();   if (nullOrBlank((String)this.get("lastName"))) {    errors.add("lastName",           new ActionError("article1.lastName.missing"));  }   if (nullOrBlank((String)this.get("firstName"))) {    errors.add("firstName",           new ActionError("article1.firstName.missing"));  }   if (nullOrBlank((String)this.get("street"))) {    errors.add("street",           new ActionError("article1.street.missing"));  }   if (nullOrBlank((String)this.get("city"))) {    errors.add("city", new ActionError("article1.city.missing"));  }   if (nullOrBlank((String)this.get("state"))) {    errors.add("state",           new ActionError("article1.state.missing"));  }   if (nullOrBlank((String)this.get("postalCode"))) {    errors.add("postalCode",           new ActionError("article1.postalCode.missing"));  }   if (nullOrBlank((String)this.get("phone"))) {    errors.add("phone", new ActionError("article1.phone.missing"));  }   return errors;  }   } 
如果是这样,我们就要更改struts-config.xml来使用DynaActionForm的子类,这样的效果似乎是又回到了先前的样子(为每一个表单写DynaActionForm),呵呵。。。 
所以推荐的做法是使用struts1.1种的Validator Framework,这方面的内容在以后的文章中在说明。 
  
关于作者: 
  
James Turner is the owner and manager of Black Bear Software, LLC, which specializes in custom Java-based e-Commerce and CRM solutions delivery. He is also the author of "MySQL and JSP Web Applications: Data-Driven Programming Using Tomcat and MySQL" (ISBN: 0672323095) and is the co-author of "Struts: Kick Start" (ISBN: 0672324725), which will be published in November. He can be reached at [email protected]. 
   
 
  |