Struts 页面流(Page flow)表单验证

来源:互联网 发布:嘉盛外汇 知乎 编辑:程序博客网 时间:2024/06/03 20:33

创建Web应用的过程中,验证用户在HTML表单中的输入是最常见的一个问题。用户输入数据必须被验证从而保证进行业务处理之前数据是正确的。输入的表单数据可能用于创建或更新数据库条目、调用Web服务、或作为业务过程的输入。基于目前由Struts提供的表单验证框架,页面流提供了一种简单易用的服务端验证方式。
页面流验证提供以下功能:
· 用户表单输入的服务端验证
· 用待验证的表单bean封装验证逻辑
· 验证失败时自动导航到输入页面
· 内置消息包支持,方便进行国际化
本文假定读者熟悉页面流及JSP。本文将介绍创建表单bean和验证页面的基本步骤。如果发生验证错误用户将会得到通知,从而可以修正它们;动作方法被调用时可以认为数据是正确的。

Request生命周期及验证
表单验证针对的是已提交表单bean中的内容。通过JSP页面的<netui:form> 标签的动作属性,该bean被间接选中;表单bean与指定动作相关联。表单bean继承自com.bea.wlw.netui.pageflow.FormData。为了验证表单bean,开发人员需要重载validate() 方法并提供验证逻辑。
图1演示了request的生命周期以及验证是如何发生的。当Strut的控制器接收到请求时,它将请求传递给页面流RequestProcessor。请求处理器的processPopulate 方法首先构造一个新的表单bean,其中含有来自请求的所有数据条目。此步骤将会创建FormData。然后请求处理器检查是否为动作激活了表单验证。如果验证被激活,将会针对该表单bean调用validate()方法。如果出现验证错误,控制权将交给一个输入页面,同时转交的还有用户输入的数据以及错误信息。如果没有发现错误,控制权将被传递给目标动作从而继续处理请求。
通过简单的五个步骤就可以在页面流中进行验证。下面详细解释每个步骤。
步骤1——验证方法
验证用户输入的第一个步骤是在表单bean上创建validate()方法。该方法将会检查表单bean的属性,察看有没有用户输入错误。下面这个非常简单的表单bean定义了两个属性:name 和type。validate() 方法提供了对这些属性的验证。
public static class NameBean extends FormData                       
  {
      private String name; 
      private String type;            
      public void setType(String type)            
      {
          this.type = type;        
 }
      public String getType()
      {        
          return this.type;
      }          
      public void setName(String name)       
      {
          this.name = name;     
 }
      public String getName()
      {            
          return this.name;
      }          
      public ActionErrors validate(ActionMapping mapping,            HttpServletRequest request)
      {            
          ActionErrorserrors = new ActionErrors();
          if (name == null || name.equals("")) {   
              errors.add("nameError",
              new ActionError("NullNameError"));            
          } else {          
              if (!Character.isUpperCase(name.charAt(0))) {
                  errors.add("nameError",      
                   new ActionError("UpperCaseNameError",name));
              }            
          }
          if (type == null || (!type.equals("bar") && !type.equals("foo"))) {
              errors.add("typeError",        
              new ActionError("TypeError",type));
          }            
          if (!errors.empty()) {
              request.setAttribute("errorNotSet",new Boolean(false));  
          }
          return errors;            
      }
validate() 方法返回Struts的ActionErrors 对象,其中包含任何可能发生的错误信息。当该方法被调用时,它接收Struts ActionMapping 结构和HttpServletRequest。如果方法内部发生错误,Struts ActionError 类将会捕获错误信息。

validate() 方法所做的第一件事就是创建用来返回验证错误的ActionErrors 对象。
ActionErrors errors = new ActionErrors();
如果返回一个非空ActionErrors 对象,该方法会将错误通知给请求处理器。如果没有ActionError添加进来,ActionErrors将是空的。该方法可能返回空ActionErrors ,也可能返回null来表示没有错误发生。
在本例中,如果发生错误将会创建一个新的ActionError 对象并将其添加到ActionErrors 中:
errors.add("typeError", new ActionError("TypeError",type));
我们将在例子中创建一个含有名为"typeError"的属性的新错误。<netui:error> 标签使用名称来判断应该报告哪个错误。新创建的ActionError 含有一个主键 "TypeError"。主键是在消息包中查找错误显示信息要用到的ID。除此之外,我们还会传递变量type以便在信息创建时进行文本替换。
步骤2——在动作中打开验证
只有为动作开启了验证功能,validate() 方法才能被调用。通过添加一个validation-error-page 属性到@jfp:action 注解即可开启验证功能:
/**
   * @jpf:action validation-error-page="index.jsp" 
   * @jpf:forward name="success" path="results.jsp"
   */       
  protected Forward processNameBean(NameBean form)
  {         
      HttpServletRequest req = getRequest();
      req.setAttribute("Form",form);          
      return new Forward("success"); }            
既可以手工也可以通过动作源码视图的属性编辑窗口来定义注解。

步骤3——创建错误消息文本
错误消息文本是从消息包中查找出来的。消息包被放置在WEB-INF/classes子目录下。在本例中,我们创建Validation.properties 文件并将其放在 WEB-INF/classes/message 目录
Validation.properties 中包含那些将会显示在<netui:error> 或 <netui:errors> 标签中的文本。该属性文件包含以下条目:
rrors.header=<ul>
  errors.footer=</u>
  errors.prefix=<li>
  errors.suffix</li>
  NullNameError=The name field must not be null.  
  UpperCaseNameError=The name <b>'{0}'</b> must begin
  with an upper case letter.         
  TypeError=The type <b>'{0}'</b> must be the value 'foo' or 'bar'

在例子中,我们通过以下语句创建一个 ActionError :
  ActionError("TypeError",type));
字符串“TypeError”用于消息的查找:
   TypeError=The type <b>'{0}'</b> must be the value 'foo' or 'bar'
在运行时刻,变量type 替换'{0}'处从而生成报告给用户的完整文本。
 
步骤4—— 将消息文件绑定到页面流
消息文件Validation.properties 需要绑定到页面流,这样才能在报告消息给用户之前进行消息的查找。可以通过页面流的一个注解来进行绑定。
  /* @jpf:controller       
  * @jpf:message-resources resources="messages.Validation"
  */       
  public class Controller extends PageFlowController 
  {
@jpf:message-resources注解声明页面流使用messages.Validation 属性文件。既可以在源代码中直接设置该注解,也可以在源码视图页面流属性编辑窗口下面的消息资源列表区域中设置。
消息资源名称是查找消息包需要用到的classpath条目。本例中,因为WEB-INF/classes 在classpath中,所以messages.Validation能够被找到。它的实际文件名是WEB-INF/classes/message/Validation.properties。

注意:Java将会缓存那些访问过的消息包。如果在开发过程中修改了.properties 文件,可以通过修改页面流文件并重启测试浏览器、或停止并重启服务来清空缓存。
 
步骤5——在JSP页面中报告错误

有两个页面流标签用于报告验证过程中发生的错误。<netui:error> 标签根据value 属性进行错误报告。它通常被用在输入字段后面直接报告该字段的错误。<netui:errors> 标签将会报告页面中的所有错误。下面的JSP代码片断演示了一个<netui:form>例子,它负责提交NameBean表单bean。它使用<netui:error> 标签在用户输入字段之后报告错误。除此之外,通过<netui:errors> 标签,其它错误被报告在文档的底部。
 <h4>Name Input Form</h4>
  <netui:form action="processNameBean" focus="">
      <table>
          <tr>
              <td><netui:label value="Name:">
              </netui:label></td>
              <td><netui:textbox dataSource="{actionForm.name}">
                     </netui:textBox></td>
              <td><span style="color:#cc0000;">
                  <netui:error value="nameError"/></span></td>
          </tr>
          <tr>
              <td><netui:label value="Type:"/></td>
              <td><netui:textBox dataSource="{actionForm.type}"/></td>
              <td><span style="color:#cc0000;">
                  <netui:error value="typeError"/></span></td>
          </tr>
      </table>
      <netui:button value="Submit Form"></netui:button>
  </netui:form>
  <netui-template:visible visibility="{request.errorNotSet}"      
  negate="true" >
      <hr />
      <span style="color:#cc0000;">
      <netui:errors><br /></netui:errors>
      </span>
  </netui-template:visible>
<netui:errors> 标签有四个可以定义在消息包中的特殊属性:errors.header, errors.footer, errors.prefix, errors.suffi,利用这些属性可以在显示的消息周围进行格式设定。在本例中,错误被显示在一个未排序的列表中。而且,<netui:error> 标签允许error.prefix 和error.suffix 定义标记性的标签。本例中没有演示这一功能。

结果
用户在表单中输入非法数据后验证错误被返回,然后请求处理器定向到index.jsp页面,错误信息被显示在字段之后以及表单下面。错误表单的内容全部被返回,这样用户可以只修改那些出错的字段。

结论
 
服务端的用户输入验证需要经历五个步骤。首先在表单bean中创建一个validate() 方法,该方法将会验证用户输入并报告错误。第二步,必须在接收表单的动作上设置validation-error-page 符号才能激活表单验证。第三步,添加错误文本到消息包中。第四步,借助消息资源注解,消息包被绑定到页面流上。最后,在JSP中添加<netui:error> 或 <netui:errors> 标签,它们将会显示错误文本。页面流框架会管理所有的验证调用,并在错误发生后将控制权路由到输入页面,否则路由到目标动作。