您的位置:首页 > 编程语言 > Java开发

Struts 2学习及问题记录(3)——类型转换及输入校验

2016-05-16 09:27 537 查看
  所有的MVC框架都需要负责解析HTTP请求参数,并将请求参数传递给控制器组件。但是,HTTP请求参数都是字符串类型,而Java是强类型语言,所以MVC框架必须提供字符串参数和相应数据类型互相转换的功能。

  输入校验也是所有Web应用必须处理的问题。因为所有的浏览者都可以自由使用应用,所以收集到的数据非常复杂。可能包括用户的误输入,也可能包含恶意用户的恶意输入,这些都可能导致系统的异常,轻则非正常中断,重者甚至会导致系统崩溃。所以必须将这些异常输入过滤掉,这就是输入校验,也叫数据校验。

  系统的类型转换与输入校验的总体流程如下图:



  下面将分别对类型转换和输入校验进行总结。

一、类型转换

  Struts 2中有以下集中类型转换:

Struts 2内建的类型转换器
基于OGNL的类型转换
通过类型转换文件指定
自定义类型转换器
基于Struts 2的自定义类型转换器

  (1)Struts 2内建的类型转换器
  这种类型转换器主要用于对常用类型进行转换,例如整型(int和Integer)、日期类型(Date)、数组、集合等。这些类型在实际开发中无需进行任何特殊处理。
  (2)基于OGNL的类型转换
  这种类型转换方法主要用于复合类型。通过OGNL表达式,开发者无需任何特殊处理,就可以对符合类型进行类型转换。不过在使用OGNL表达式方法时,需要注意以下几点:
  》需要转换的符合类必须有无参数的构造器,因为Struts 2通过反射来创建一个符合类实例;
  》符合类内需要转换类型的属性,需要有相应的setter和getter方法。
  (3)通过类型转换文件指定
  类型转换文件是一个普通的Properties(.properties)文件。局部类型转换文件的文件名应该为ActionName-conversion.properties形式。这个文件需要放在与Action类文件的相同目录下。文件中通过指定key-value对来指定元素的类型,格式如下:
<span style="font-size:18px;">Element_<ListPropName>=<ElementType></span>
  上面是配置列表元素类型的方法。与此类似,Map内的key和value类型也是这样配置。

  (4)自定义类型转换器
  自定义的类型转换器必须实现TypeConverter接口。不过OGNL项目为该接口提供了一个实现类:DefaultTypeConverter,通常可以扩展这个类来实现自定义类型转换器,同时需要重写其中的convertValue()方法。这个方法根据自身的toType参数来判断转换方向,并根据转换方向分别实现。
  仅仅提供类型转换器还不够,必须还得在Web应用中注册转换器。注册方式分为局部类型转换器、全局类型转换器和通过注解方式来注册类型转换器。
  局部类型转换器只对特定的Action内的指定属性起作用。使用局部类型转换文件指定。其文件配置格式如下:
<span style="font-size:18px;"><propName>=<ConverterClass></span>
  <propName>是需要转换的属性名,<ConverterClass>是类型转换器的实现类。

  而全局类型转换器则是对指定类型起作用。全局类型转换器注册应该提供一个xwork-conversion.properties文件,并直接放在WEB-INF/classes路径下即可。文件中有多个如下项:

<propName>=<ConvertClass>
  其中个参数含义与上相同。

  (5)基于Struts 2的自定义类型转换器

  与上一种方法类似,不过这种类型转换器是继承自StrutsTypeConverter抽象类。该抽象类已经实现了convertValue()方法,并将两个转换方向替换成了不同的方法,当把字符串转换成符合类型时,调用convertFromString()方法,把符合类型转换成字符串时,调用convertToString()方法。

二、输入校验

  输入校验分为客户端校验和服务器端校验。客户端校验主要用于过滤正常用户的误操作,主要通过JavaScript代码完成;服务器端校验是组织非法数据的最后防线,主要通过在应用中编程实现。
  Struts 2提供了基于验证框架的输入校验,在这种校验方式下,所有的输入校验只需要编写简单的配置文件,Struts 2的验证框架将会负责进行服务器校验和客户端校验。使用Struts 2的校验框架进行校验,无需对程序代码进行任何改变。
  Struts 2中每个Action都有一个校验文件,文件名应该遵循如下规则:
<span style="font-size:18px;"><ActionName>-validation.xml</span>
  该文件应该保存在Action的class文件相同的路径之中。

  校验规则文件的跟元素是<validators.../>元素,根据不同的配置风格,其子元素也不同。配置风格有两种,一个是字段校验器配置风格,另一个是非字段校验器配置风格。
  字段校验器配置风格遵守如下形式:
<span style="font-size:18px;"><validators>
<field name="被校验字段">
<field-validator type="校验器名">
<param name="参数名">参数值</param>
......
<message key="I18Nkey">校验失败后的提示信息</message>
</field-validator>
......
</field>
......
</validators></span>
  非字段校验器配置风格遵守如下形式:
<validators>
<validator type="校验器名">
<prama name="fieldName">需要被校验的字段</param>
<param name="参数名">参数值</param>
......
<message key="I18Nkey">校验失败后的提示信息</message>
</validator>
......
</validators>
  与类型转换失败相似的是,当输入校验失败后,Struts 2也是自动返回名为“input”的Result。

  当一个Action类中包含多个类似execute()方法时,每个方法都是一个处理逻辑。不同的处理逻辑可能需要不同的校验规则。如果需要让Action处理多个请求时,应该在配置时,指定method属性,这样就可以将一个Action处理类配置成多个逻辑Action。这时的校验文件名采用如下形式:
<span style="font-size:18px;"><ActionClassName>-<ActionAliasName>-validation.xml</span>
  该文件也需要放在Action的class文件的同一路径下。

  在同时存在<ActionClassName>-validation.xml和<ActionName>-<ActionAliasName>-validation.xml的时候,名为<ActionAliasName>的Action中包含的校验规则是这两个文件的总和。
  更进一步,如果存在两个Action:BaseAction和ChildAction,其中ChildAction继承了BaseAction,那么系统对校验文件的搜索顺序如下:

BaseAction-validation.xml
BaseAction-别名-validation.xml
ChildAction-validation.xml
ChildAction-别名-validation.xml

  Struts 2搜索规则文件是从上而下的,实际用的校验规则是所有校验规则的总和。如果两个校验文件中有冲突,则后面文件的校验规则会覆盖前面的。

  校验器的执行顺序有如下规则:

所有非字段风格的校验器优先于字段风格的校验器
所有非字段风格的校验器中,排在前面的会先执行
所有的字段风格的校验器中,排在前面的会先执行

  校验器短路的原则如下:

所有非字段校验器最优先执行,如果某个非字段校验器校验失败了,则该字段上所有的字段校验器都不会获得校验的机会
非字段校验器的校验失败,不会阻止其他非字段校验的执行
如果一个字段校验器校验失败后,则该字段下且排在该校验失败的校验器之后的其他字段校验器不会获得校验机会
字段校验其不会阻止非字段校验器的执行

  使用注解来指定验证规则,只要使用验证器注解修饰Action里各成员变量对应的setter方法即可,同时将该Action相同路径下的校验规则我呢见删除。

  Sturts 2也允许通过手动方式完成自定义校验,来满足一些特殊的校验需求。

  手动完成输入校验有两种方法,一个是重写validate()方法,一个是重写validateXxx()方法。

  总的来看,Struts 2的输入校验需要经过以下几个步骤:

类型转换器负责对字符串的请求参数执行类型转换,并将这些值设置成Action的属性值
在执行类型转换过程中如果出现异常,将异常信息保存到ActionContext中,conversionError拦截器负责将其封装到FieldError里,然后执行第3步;如果没有异常信息,则直接进入第3步
使用Struts 2应用中配置的校验器进行输入校验
通过反射调用validateXxx()方法
调用Action类里的validate()方法
如果以上步骤都没有产生FieldError,调用Action里的处理用户请求的处理方法;否则转入input逻辑视图所指定的视图资源

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: