1、自动类型转换

Struts2内部提供大量类型转换器,用来完成数据类型转换问题:

  • String和boolean、Boolean:完成字符串与布尔值之间的转换
  • String和char、Character:往常字符串与字符之间的转换
  • String和int、Integer:完成字符串与整型之间的转换
  • String和long、Long:完成字符串与长整型值之间的转换
  • String和double、Double:完成字符串与双精度浮点值的转换
  • String和float、Float:完成字符串和单精度浮点之间的转换
  • String和Date:完成字符串和日期类型之间的转换,可以接收yyyy-MM-dd格式字符串
  • String和数组:可以将多个同名参数,转换到数组中
  • String和Map、List:支持将数据保存到List或者Map集合

自动类型转换例子:

表单信息:

 <form action="${pageContext.servletContext.contextPath}/converterAction.action">
name:<input type="text" name="name"><br>
password:<input type="password" name="password"><br>
age:<input type="text" name="age"><br>
birthday:<input type="text" name="birthday"><br>
hobby:<input name="hobby" type="checkbox" value="music">music
<input name="hobby" type="checkbox" value="movie">movie<br>
<input type="submit" value="提交">
</form>

Action类:

 public class ConverterAction extends ActionSupport {
private String name;
private String password;
private int age;
private Date birthday;
private String[] hobby; public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String[] getHobby() {
return hobby;
}
public void setHobby(String[] hobby) {
this.hobby = hobby;
} @Override
public String execute() throws Exception {
System.out.println("name: " + name);
System.out.println("password: " + password);
System.out.println("age: " + age);
System.out.println("birthday: " + birthday);
System.out.print("hobby: ");
for (int i = 0; i < hobby.length; i++) {
System.out.print(hobby[i]);
if (i != hobby.length - 1) {
System.out.print(", ");
}
}
return SUCCESS;
}
}

前台输入信息:

后台显示信息:

2、自定义类型转换

1)基于OGNL的类型转换器

  Struts2的类型转换器实际上是基于OGNL实现的,都需要实现一个TypeConverter接口,该接口位于ognl.jar包内。该接口定义了一个convertValue()方法,实现该接口的类型转换器实现类都需要重写该方法来进行类型转换。

 public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType);

  由于TypeConverter接口的convertValue()方法过于复杂,OGNL还提供了一个实现TypeConverter接口的类DefaultTypeConverter,开发者只要继承该类,就可以开发类型转换器的实现类。DefaultTypeConverter类的子类需要重写convertValue()方法,来实现字符串类型与复合类型之间的双向转换,convertValue()方法有三个参数:Map context:该参数为类型转换环境的上下文内容;Object value:该参数为需要转换的参数,是一个字符串数组;Class toType:该参数指的是转换目标的类型。

  在Struts2中并没有直接使用ognl.DefaultTypeConverter实现类,甚至都没有使用ognl.TypeConverter接口,而是自己定义了一个与ognl.TypeConverter接口一样的TypeConverter接口,该接口位于com.opensymphony.xwork2.conversion包下,其名称和接口函数定义完全相同。Struts2自行定义TypeConverter接口的目的在于对外屏蔽类型转换的实现细节,从而能够将Struts2对TypeConverter的扩展实现纳入到Struts2的容器中进行管理,从而方便对OGNL原始的TypeConverter接口进行扩展并支持更加广泛的类型转换逻辑。

  在Struts2的com.opensymphony.xwork2.conversion包下DefaultTypeConverter实现类有3个convertValue方法:

所以我们在继承com.opensymphony.xwork2.conversion包下DefaultTypeConverter实现类的时候可以直接重写convertValue(Object value, Class toType)方法即可。

无论是继承ongl包下的DefaultTypeConverter还是继承com.opensymphony.xwork2.conversion包下DefaultTypeConverter,在自定义类型转换的时候,实现方式都一样。

2)基于Struts2的类型转换器

  Struts2框架提供了一个类型转换器的StrutsTypeConverter抽象类,可以继承该类来开发自定义的类型转换器实现类。 该抽象类实际上继承了DefaultTypeConverter类,在该类的基础上进行了简化。StrutsTypeConverter类中提供了两个抽象方法,分别实现"form字符串参数-Struts复合类型"之间的双向转换。

3、注册类型转换器

在Struts2框架中使用自定义类型转换器需要注册,这样Struts2框架在处理用户请求的时候才知道使用哪个类型转换器进行转换。Struts2有两种方式注册类型转换器:

1)注册局部类型转换器

  局部类型转换器仅仅对某个Action的属性其作用,注册局部类型转换器需要建立一个命名规则为ActionName-conversion.properties的属性文件,该属性文件保存在与Action类文件相同的目录下。ActionName就是使用类型转换器的Action类的类名,而-conversion.properties是固定的格式。该文件是一个标准的属性文件,内容为标准的Key-Value格式,该键值对定义如下:

 <!--propertyName为要进行转换的属性名-->
propertyName=类型转换器

如果在model中有两个类User和Product,它们都有Date类型属性,都需要在页面上输入,但是它们格式不一样,例如:

  User birthday 格式:yyyy/MM/dd

  Product producttime 格式:yyyy-MM-dd

如果遇到这种情况,可以在model所在的包下创建注册的properties文件,名称的命名规则为modelname-conversion.properties,该属性文件的内容和上面的一样:

 <!--propertyName为要进行转换的属性名-->
propertyName=类型转换器

2)注册全局类型转换器

  全局类型转换器对所有Action的特定属性都会生效,注册一个全局类型转换器,需要建立一个xwork-conversion.properties属性文件,该文件需要保存在class路径的根目录下,如WEB-INF/classes。该文件的内容为"复合类型-对应的类型转换器",其中复合类型就是Action中需要进行类型转换的属性所属于的类型,对应的类型转换器就是转换该复合类型的对应转换器,比如要对Date类型的属性进行转换:

java.util.Date=com.sunny.converter.DateConverter

4、类型转换器的实现

在类型转换器的实现例子中自定义类型转换器继承的是DefaultTypeConverter,注册局部类型转换器。

表单信息:

 <form action="${pageContext.servletContext.contextPath}/converterAction.action">
name:<input type="text" name="name"><br>
password:<input type="password" name="password"><br>
age:<input type="text" name="age"><br>
birthday:<input type="text" name="birthday"><br>
hobby:<input name="hobby" type="checkbox" value="music">music
<input name="hobby" type="checkbox" value="movie">movie<br>
<input type="submit" value="提交">
</form>

自定义类型转换器类:

 public class DateConverter extends DefaultTypeConverter {
@Override
public Object convertValue(Object value, Class toType) {
if (value == null || toType == null) {
return false;
} if (toType != Date.class) {
return false;
} /*
* 对于DefaultTypeConverter转换器而言,它必须考虑到最通用的情形,
* 因此他把所有请求参数都视为字符串数组而不是字符串。
*/
if (value instanceof String[]) {
String str[] = (String[])value;
if (str[0] != null && str[0].length() > 0) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
try {
//把请求参数转换成特定格式的date类
return sdf.parse(str[0]);
} catch (ParseException e) {
/*
* 在struts2框架里,自定义的类型转换器,
* 如果我们不手动抛出异常,struts2框架只捕获异常,但是并不抛出。
* 所以框架就会认为类型转换器转换成功,转向成功页面。
*/
throw new RuntimeException(e);
}
}
}
return new Date();
}
}

注册局部类型转换器,对Date类型的birthday进行转换,接收yyyy/MM/dd类型字符串:

 birthday=com.sunny.converter.DateConverter

Action类:

 public class ConverterAction extends ActionSupport {
private String name;
private String password;
private int age;
private Date birthday;
private String[] hobby; public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String[] getHobby() {
return hobby;
}
public void setHobby(String[] hobby) {
this.hobby = hobby;
} @Override
public String execute() throws Exception {
System.out.println("name: " + name);
System.out.println("password: " + password);
System.out.println("age: " + age);
System.out.println("birthday: " + birthday);
System.out.print("hobby: ");
for (int i = 0; i < hobby.length; i++) {
System.out.print(hobby[i]);
if (i != hobby.length - 1) {
System.out.print(", ");
}
}
return SUCCESS;
}
}

前台输入信息:

后台显示信息:

注意事项:

  • 在进行自定义类型转换时,如果转换错误,我们不手动抛出异常,struts2框架只捕获异常,并不抛出,框架就会认为转换成功,转向成功页面,所以一定要手动抛出异常。
  • 不管是自动类型转换还是自定义类型转换,如果类型转换错误,会跳转到input视图,如果在struts.xml文件中没有name值为"input"的<result>,会跳转到错误页面。

5、错误处理机制

Struts2的错误处理是由conversionError拦截器自动完成的,当发生类型转换错误时,conversionError拦截器拦截此错误并封装成fieldError,将此错误信息放入ActionContext中,并返回input逻辑视图,我们前面提到过此时必须在struts.xml文件中有name值为"input"的<result>,在jsp页面中可以使用<s:fielderror/>即可显示错误信息,默认显示的错误信息是在属性文件xwork-messages.properties中定义的:

 xwork.error.action.execution=Error during Action invocation
xwork.exception.missing-action=There is no Action mapped for action name {0}.
xwork.exception.missing-package-action=There is no Action mapped for namespace {0} and action name {1}.
xwork.default.invalid.fieldvalue=Invalid field value for field "{0}".

当birthday输入格式错误时,根据action中的<result name="input">/error.jsp</result>会跳转到error.jsp页面,

jsp页面信息:

 <body>
<s:fielderror fieldName="birthday"/>
</body>

jsp页面显示信息:

如果我们需要配置显示的错误信息,有方式有两种:
1)在国际化资源文件中配置
xwork.default.invalid.fieldvalue={0},错误;
在项目中建立一个国际化资源文件converter.properties,文件名可以随便,在文件中输入下面内容:
xwork.default.invalid.fieldvalue={0},错误;
然后,在struts.xml文件中配置<constant name="struts.custom.i18n.resources" value="com.sunny.action.converter" />
 <struts>
<constant name="struts.devMode" value="true" />
<constant name="struts.custom.i18n.resources" value="com.sunny.action.converter" />
<package name="default" namespace="/" extends="struts-default">
<action name="converterAction" class="com.sunny.action.ConverterAction">
<result>/success.jsp</result>
<result name="input">/error.jsp</result>
</action>
</package> </struts>

说明:资源文件的定义有好几种方式,会在国际化中讲到

如果birthday输入格式错误,显示如下:

2)配置Action特定属性错误信息
在Action所在包中,创建ActionName.properties,在文件中配置提示信息: invalid.fieldvalue.属性名= 错误信息,其中invalid.fieldvalue为固定格式
invalid.fieldvalue.birthday=日期类型转换错误,要求格式必须是yyyy/MM/dd;
显示效果:
这种配置方式的内容:invalid.fieldvalue.birthday=日期类型转换错误,要求格式必须是yyyy/MM/dd;也可以配置在国际化资源文件中,同样可以起作用。
注意:类型转换的Action在struts.xml中配置所在包需要extends="struts-default",因此在此文件中包含conversionError拦截器

Struts2学习笔记(七)——类型转换的更多相关文章

  1. (C/C++学习笔记) 七. 类型转换

    七. 类型转换 ● 隐式类型转换 隐式类型转换 implicit type conversions #include<iostream> using namespace std; void ...

  2. [Struts2学习笔记] -- 自定义类型转换

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...

  3. Struts2 学习笔记19 类型转换 Part1

    现在来说一说类型转换,提到类型转换其实我们之前早已经用过了,在url传递参数的时候,我们传递过来的参数其实都是String类型的,在显示的时候都自动转换了,像这种简单的转换很好理解,我们要说的是,转换 ...

  4. Struts2 学习笔记20 类型转换part2 写自己的转换器

    之前说的是调用Struts2的默认转换器,现在我们来说以下写自己的转换器,这个一般不常用,在访问不是自己写的类中可能用到.我们一点点来,因为写自己的转换器需要注意的东西还是很多的. 我们还是用之前的项 ...

  5. (转)Qt Model/View 学习笔记 (七)——Delegate类

    Qt Model/View 学习笔记 (七) Delegate  类 概念 与MVC模式不同,model/view结构没有用于与用户交互的完全独立的组件.一般来讲, view负责把数据展示 给用户,也 ...

  6. Struts2学习笔记⑧

    今天是Struts2学习笔记的最后一篇文章了.用什么做结尾呢,这两天其实还学了很多东西,没有记录下,今天就查漏补缺一下. 文件上传与下载.FreeMarker以及昨天没做完的例子 文件上传与下载 文件 ...

  7. Struts2学习笔记①

    Struts2 学习笔记① 所有的程序学习都从Hello World开始,今天先跟着书做一个HW的示例. Struts2是一套MVC框架,使用起来非常方便,接触到现在觉得最麻烦的地方是配置文件.我的一 ...

  8. Struts2学习笔记NO.1------结合Hibernate完成查询商品类别简单案例(工具IDEA)

    Struts2学习笔记一结合Hibernate完成查询商品类别简单案例(工具IDEA) 1.jar包准备 Hibernate+Struts2 jar包 struts的jar比较多,可以从Struts官 ...

  9. Learning ROS for Robotics Programming Second Edition学习笔记(七) indigo PCL xtion pro live

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS forRobotics Pro ...

随机推荐

  1. Oracle数据迁移笔记-Rownum与序列的自增长的组合用法技巧

    Rownum与序列的自增长的组合用法技巧 根据序列自增长的步长规律,结合表行记录Rownum值的规则批量生成表的行记录主键的用法技巧 案例如下: CREATE OR REPLACE PROCEDURE ...

  2. JavaScript实现淡入淡出

    <!DOCTYPE html> <html> <head> <title>css动画</title> </head> <b ...

  3. 智联招聘 卓聘IM演进过程

    1.  卓聘IM开发背景 智联卓聘是智联旗下高端人才招聘平台,成立快4年了,业务增涨每年以100%速度增涨,业务增涨快在开发和上线速度要求也比较高. 2016年6月提出IM开发需求,7月初上线,开发人 ...

  4. firefox插件开发及源码下载

    在个别情况下,由于数据量巨大,造成显示性能的明显下降,此时使用c++开发firefox插件,可以提高用户使用体验. test.html: 在插件中,我们导出3个函数给js:AddStr, Pause, ...

  5. android 7.0 多渠道打包 - 美团开源工具Walle 命令行打包

    在Android 7.0(Nougat)推出了新的应用签名方案APK Signature Scheme v2后,之前快速生成渠道包的方式(美团Android自动化之旅-生成渠道包)已经行不通了,对此美 ...

  6. Spring阅读方法

    转自:http://www.cnblogs.com/xing901022/p/4178963.html 最近没什么实质性的工作,正好有点时间,就想学学别人的代码.也看过一点源码,算是有了点阅读的经验, ...

  7. AmazeUI(妹子UI)中CSS组件、JS插件、Web组件的区别

    AmazeUI(妹子UI)是非常优秀的国产前端UI,现在来介绍一下AmazeUI中CSS组件.JS插件与Web组件的区别. CSS组件顾名思义就是仅使用CSS渲染而成的组件,而JS插件也很容易理解,就 ...

  8. jqthumb.js缩略图插件-让缩略图正常显示而不变形

    插件介绍 项目中有图片的时候,有的宽大于高,有的宽小于高,尤其在做图片列表的时候,经常发现缩略图会有变形的.我们怎样来解决这一问题呢. 方法一:用photoshop来处理缩略图.小的项目还可以,大的项 ...

  9. Android studio导出AAR包问题整理。

    最近因为项目需求开始整理一个SDK 以AAR的方式提供出去.在整理的过程中遇到了很多坑. 以下是一些总结希望能帮助遇到同样问题的人. 1.怎么导出AAR,这种文章太多了,我贴一个大家可以做参考. ht ...

  10. Pandas: 如何将一列中的文本拆分为多行? | Python

    Pandas: 如何将一列中的文本拆分为多行? 在数据处理过程中,经常会遇到以下类型的数据: 在同一列中,本该分别填入多行中的数据,被填在一行里了,然而在分析的时候,需要拆分成为多行. 在上图中,列名 ...