类型转换中的错误处理

 

表现层数据是由用户输入的,用户输入则是非常复杂的,正常用户的偶然错误,还有Cracker(破坏者)的恶意输入,都可能导致系统出现非正常情况。例如,在如图4.2所示的输入页面中,我们希望用户输入crazyit.org,leegang模式的字符串,希望用户输入的字符串包含一个英文逗号(,)作为用户名和密码的分隔符,如果用户输入多于一个的英文逗号,或者没有输入英文逗号,都将引起系统异常——因为上面的类型转换器将无法正常分解出用户名和密码。

实际上,表现层数据涉及的两个处理:数据校验和类型转换是紧密相关的,只有当输入数据是有效数据时,系统才可以进行有效的类型转换——当然,有时候即使用户输入的数据能进行有效转换,但依然是非法数据(假设需要输入一个人的年龄,输入200则肯定是非法数据)。因此,可以进行有效的类型转换是基础,只有当数据完成了有效的类型转换后,下一步才去做数据校验。

Struts 2提供了一个名为conversionError的拦截器,这个拦截器被注册在默认的拦截器栈中。我们查看Struts 2框架的默认配置文件struts-default.xml,该文件中有如下配置片段:

<interceptor-stack name="defaultStack">

     <!-- 省略其他拦截器引用 -->

     ...

     <!-- 处理类型转换错误的拦截器 -->

     <interceptor-ref name="conversionError"/>

     <!-- 处理数据校验的拦截器 -->

     <interceptor-ref name="validation">

          <param name="excludeMethods">input,back,cancel,browse</param>

     </interceptor-ref>

     <!-- 省略其他拦截器 -->

     ...

</interceptor-stack>

在上面的默认拦截器栈中包含了conversionError拦截器的引用,如果Struts 2的类型转换器执行类型转换时出现错误,该拦截器将负责将对应错误封装成表单域错误(FieldError),并将这些错误信息放入ActionContext中。

显然,conversionError拦截器实际上是AOP中的Throws处理(关于各种处理类型的定义和深入介绍,请参阅本书关于Spring的介绍)。Throws处理当系统抛出异常时启动,负责处理异常。通过这种方式,Struts 2的类型转换器中只完成类型转换逻辑,而无须关心异常处理逻辑。因此,我们看到上面的类型转换器无须进行任何异常处理逻辑。

4.6显示了Struts 2类型转换中的错误处理流程。

4.6只显示了类型转换器、conversionError拦截器和控制器之间的顺序图,并未完全刻画出系统中的其他成员。当conversionError拦截器对转换异常进行处理后,系统会跳转到名为input的逻辑视图。

 

4.6  Struts 2类型转换中的错误处理流程

为了让Struts 2框架处理类型转换的错误,以及使用后面的数据校验机制,系统的Action类都应该通过继承ActionSupport类来实现。ActionSupport类为完成类型转换错误处理,数据校验实现了许多基础工作。

1.处理类型转换错误

下面将以最简单的局部类型转换器为例,介绍如何处理类型转换错误。

我们重新改写系统的Action类,让系统的Action类继承Struts 2ActionSupport类。修改后的Action类代码片段如下。

程序清单:codes\04\4.1\errorHandler\WEB-INF\src\org\crazyit\app\action\LoginAction.java

//为了正常使用系统的类型转换错误处理机制,让Action类继承ActionSupport

public class LoginAction

extends ActionSupport

{

     //该类包含一个User类型属性,该属性用于封装名为user的请求参数

     private User user;

     private String tip;

     //省略该类的其他成分

     ...

}

了让Struts 2类型转换的错误处理机制生效,包括下一节的输入校验生效,都必须让Action继承Struts 2ActionSupport基类,因为Struts 2ActionSupport负责收集类型转换错误、输入校验错误,并将它们封装成FieldError对象,添加到ActionContext中。

前面已经提到,当类型转换出现异常时,conversionError拦截器会处理该异常,然后转入名为input的逻辑视图,因此应该为该Action增加名为input的逻辑视图定义。修改后的struts.xml文件代码如下。

程序清单:codes\04\4.1\errorHandler\WEB-INF\src\struts.xml

<?xml version="1.0" encoding="GBK"?>

<!DOCTYPE struts PUBLIC

     "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"

     "http://struts.apache.org/dtds/struts-2.1.7.dtd">

<struts>

     <!-- 配置国际化资源文件 -->

     <constant name="struts.custom.i18n.resources" value="mess"/>

     <package name="lee" extends="struts-default">

          <action name="login" class="org.crazyit.app.action.LoginAction">

               <!-- 配置名为input的逻辑视图,

                    当转换失败后转入该逻辑视图 -->

               <result name="input">/input.jsp</result>

               <result name="success">/welcome.jsp</result>

               <result name="error">/welcome.jsp</result>

          </action>

          <action name="">

               <result>.</result>      

          </action>

     </package>

</struts>

上面的粗体字代码为input逻辑视图指定了物理视图资源:input.jsp。经过上面配置,如果用户输入不能成功转换成User对象,系统将转入input.jsp页面,等待用户再次输入。

前面已经讲述过,Struts 2会负责将转换错误封装成FieldError,并将其放在ActionContext中,这样就可以在对应视图中输出转换错误,在页面中使用<s:fielderror/>标签即可输出类型转换错误信息。

在默认情况下,使用<s:fielderror/>标签会输出形如Invalid field value for field xxx的错误提示信息,其中xxxAction中属性名,也是该属性对应的请求参数的名。

对于中文环境而言,用户通常希望看到中文的提示信息,因此应该改变默认的提示信息。只需在应用的国际化资源文件中增加如下一行代码,即可改变默认的类型转换错误的提示信息。

#改变默认的类型转换失败后的提示信息

xwork.default.invalid.fieldvalue={0}字段类型转换失败!

因为上面的资源文件中包含了非西欧字符,因此必须使用native2ascii命令来处理该文件。

也就是说,Struts 2使用keyxwork.default.invalid.fieldvalue的消息作为标准的提示信息,并在input.jsp页面中增加如下代码:

<!-- 输出类型转换错误、输入校验提示 -->

<s:fielderror/>

变了默认提示信息后,如果再次提交包含不能合理转换的请求参数,将看到如图4.7所示的页面。

 

 

4.7  类型转换错误的提示信息

提示:

 

 

 

当我们使用 Struts 2 提供的表单标签来生成表单时,这些表单标签不仅可以为我们增加额外的布局功能,还可以自动输出类型转换失败的提示信息和输入校验失败的提示信息。

 

在某些时候,可能还需要对特定字段指定特别的提示信息,此时可通过Action的局部资源文件来实现,在文件中增加如下一项:

invalid.fieldvalue.<propName>=<tipMsg>

将其中<propName>替换成需要进行类型转换的属性名(此处的propName可以支持OGNL表达式,例如user.birth代表Actionuser属性的birth属性),<tipMsg>替换成转换失败后的提示信息,上面的转换错误提示就会发挥作用了。

对于如图4.8所示的请求页面,其中包含了用户姓名、用户年龄和用户生日三个表单域,它们代表三个请求参数,这三个请求参数由Struts 2采用字符串、整数型和日期类型属性封装,因此必须涉及到类型转换!本应用的类型转换是基于OGNL表达式的类型转换。

 

 

4.8  输入用户信息的输入页面

处理上面请求的Action类代码如下。

程序清单:codes\04\4.1\errorHandler2\WEB-INF\src\org\crazyit\app\action\LoginAction.java

public class LoginAction extends ActionSupport

{

     private User user;  

     //user属性的settergetter方法

     public void setUser(User user)

     {

          this.user = user;

     }   

     public User getUser()

     {

          return user;

     }

     //没有execute方法,直接使用ActionSupportexecute方法

}

因为要改变birth属性的类型转换失败的提示信息,所以我们为该Action提供一个局部资源文件,该文件内只包含如下一行代码。

程序清单:codes\04\4.1\errorHandler2\WEB-INF\src\org\crazyit\app\action\LoginAction.properties

#改变上面的Actionuser属性的birth属性类型转换后的提示信息

invalid.fieldvalue.user.birth=生日信息必须满足yyyy-MM-dd格式

该文件的文件名为LoginAction.properties(用native2ascii处理后新文件名为LoginAction_zh_CN. properties),将该文件放在与LoginAction.class相同的位置(例如WEB-INF\classes\org\crazyit\app\action路径下)。如果我们在如图4.8所示的输入页面中输入了不能成功进行类型转换的字符串,将看到如图4.9所示的页面。

4.9中可以看到,输入的年龄参数无法正常转换,生日参数也无法正常转换,其中“age字段无效”是全局的转换错误提示,由xwork.default.invalid.fieldvalue消息提供,后面的生日字段的转换错误提示则是单独指定的。

 

 

 

上面的转换错误信息是红色的,而不是黑色的,

仅仅是因为笔者增加了一个<s:head/>标签,该标签可以导入xhtml主题所需要的一些CSS样式。

 

 

 

4.9  输出类型转换的错误提示

2.处理集合属性的转换错误

如果Action里包含一个集合属性,只要Struts 2能检测到集合里元素的类型(可以通过局部类型转换文件指定,也可通过泛型方式指定),类型转换器就可以正常起作用。当类型转换器在执行类型转换过程中出现异常时,系统的conversionError拦截器就会处理该异常,处理结束后返回名为input的逻辑视图。

假设有如下Action处理类,该处理类里包含一个List集合属性。

程序清单:codes\04\4.1\ListErrorHandler\WEB-INF\src\org\crazyit\app\action\LoginAction.java

//使用Struts 2的类型转换的错误机制,应该继承ActionSupport

public class LoginAction extends ActionSupport

{

     private List<User> users;

    

     //users属性的settergetter方法

     public void setUsers(List<User> users)

     {

          this.users = users;

     }

     public List<User> getUsers()

     {

          return users;

     }

}

于上面的Action,该Action需要的users属性是一个List集合,我们有两种方式来传入请求参数:

Ø  只传入一个users请求参数,该请求参数的值是字符串数组的形式;

Ø  分别传入多个users[0]users[1]…形式的请求参数,这种形式将会充分利用OGNL表达式类型转换机制。

对于第一种形式,因为只有一个请求参数,请求参数名为users,只要任何一个users请求参数不能成功转换成User对象,Struts 2都会提示users字段无效,如图4.10所示。

如果将三个请求参数的名字设为users[0]users[1]…的形式,Struts 2将可以区分每个请求参数,从而显示更友好的转换错误提示。例如,我们将表单页的代码改为如下。

程序清单:codes\04\4.1\ListErrorHandler\ognlInput.jsp

<s:form action="login">

     <s:iterator value="{0, 1, 2}" status="stat">

          <!-- 将会依次生成多个请求参数 -->

          <s:textfield name="users[%{#stat.index}]"

 

 

    

4.10  集合属性类型转换失败

               label="%{#stat.index}个用户信息"/>

     </s:iterator>

     <tr>

          <td colspan="2"><s:submit value="转换" theme="simple"/>

          <s:reset value="重填" theme="simple"/></td>

     </tr>

</s:form>

上面的页面代码我们使用了迭代器标签来指定三个表单域的name,三个表单域的name将分别是users[0]users[1]users[2],在这种情况下如果任一个表单域类型转换失败,将看到如图4.11所示的页面。

 

                      

4.11  集合属性类型转换失败

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值