Web应用程序的交互都是建立在HTTP之上的,互相传递的都是字符串。也就是说服务器接收到的来自用户的数据只能是字符串或者是字符数组,而在Web应用的对象中,往往使用了多种不同的类型,如整数(int)、浮点数(float)、日期(Date)或者是自定义数据类型等。因此在服务器端必须将字符串转换成合适的数据类型。

Struts2框架中为我们提供了一些简单类型的转换器,比如转换为int、float等简单数据类型是不需要我们自己定义转换器去转换的,struts2内部本身就为我们提供了转换的方法,但像一些复杂的类型和我们自定义的数据类型还是需要我们自己去写转换器去转换的。在转换工程中,如果在类型转换中出现异常,类型转换器开发者无需关心异常处理逻辑,Struts2的conversionError拦截器会自动处理该异常,并且提示在页面上生成提示信息。

下面我们就一步步的实现和注册一个我们自己的转换器,也就是自定义类型转换器的几个步骤:

一:自定义类型转换器

实现自定义类型转换器我们一般有两种方式:

1.实现OGNL提供的TypeConvert接口以及实现了TypeConvert接口的DefaultTypeConvert类来实现自定义的类型转换器。我们来看一下DefaultTypeConvert类的源码:

  1. publicclass DefaultTypeConverter implements TypeConverter{
  2. public DefaultTypeConverter(){
  3. super();
  4. }
  5. /**
  6. * @param context:类型转换的上下文
  7. * @param value:需要转换的参数
  8. * @param toType:转换后的目的类型
  9. */
  10. public Object convertValue(Map context,
  11. Object value,
  12. Class toType)
  13. {
  14. return OgnlOps.convertValue(value, toType);
  15. }
  16. public Object convertValue(Map context, Object target,
  17. Member member, String propertyName,
  18. Object value, Class toType)
  19. {
  20. return convertValue(context, value, toType);
  21. }
  22. }

convertValue方法的作用:

该方法负责完成类型的双向转换,为了实现双向转换,我们通过判断toType的类型即可判断转换的方向。toType类型是需要转换的目标类型,如:当toType类型是User类型时,表明需要将字符串转换成User实例;当toType类型是String类型时,表明需要把User实例转换成字符串类型。通过toType类型判断了类型转换的方向后,我们就可以分别实现两个方向的转换逻辑了。实现类型转换器的关键就是实现conertValue方法,该方法有三个参数:

第一个参数 context:类型转换的上下文

第二个参数 value:需要转换的参数

第三个参数 toType:转换后的目的类型

2. 基于Struts2的类型转换器

Struts 2提供了一个StrutsTypeConverter的抽象类,这个抽象类是DefaultTypeConverter类的子类。开发时可以直接继承这个类来进行转换器的构建。通过继承该类来构建类型转换器,可以不用对转换的类型进行判断(和第一种方式的区别),下面我们来看一下StrutsTypeConverter类的源码:

  1. publicabstractclass StrutsTypeConverter extends DefaultTypeConverter {
  2. //重写DefaultTypeConverter类的convertValue方法
  3. public Object convertValue(Map context, Object o, Class toClass) {
  4. //如果需要把复合类型转换成字符串类型
  5. if (toClass.equals(String.class)) {
  6. return convertToString(context, o);
  7. }
  8. //如果需要把字符串转换成符合类型
  9. elseif (o instanceof String[]) {
  10. return convertFromString(context, (String[]) o, toClass);
  11. }
  12. //如果需要把字符串转换成符合类型
  13. elseif (o instanceof String) {
  14. return convertFromString(
  15. context, new String[]{(String) o}, toClass);
  16. } else {
  17. return performFallbackConversion(context, o, toClass);
  18. }
  19. }
  20. protected Object performFallbackConversion(Map context,
  21. Object o, Class toClass) {
  22. returnsuper.convertValue(context, o, toClass);
  23. }
  24. publicabstract Object convertFromString(Map context,
  25. String[] values, Class toClass);
  26. publicabstract String convertToString(Map context, Object o);
  27. }

该类已经实现了DefaultTypeConverter的convertValue方法。实现该方法时,它将两个不同转换方向替换成不同方法——当需要把字符串转换成复合类型时,调用convertFromString抽象方法;当需要把复合类型转换成字符串时,调用convertToString抽象方法,下图展示了其对应关系:

二.注册自定义类型转换器:

实现了自定义的类型转换器之后,将该类型转换器注册在Web应用中,Struts2框架才可以正常使用该类型转换器,类型转换器的注册分为两种

1.注册局部类型转换器。

局部类型转换器仅仅对某个Action起作用。局部类型转换器非常简单,只需要在相应的Action目录下新建一个资源文件。该资源文件名格式如下。ActionName-conversion.properties。其中ActionName表示需要进行转换的Action的类名,“-conversion.properties”字符串则是固定格式的。该文件也是一个典型Properties文件,文件由键值对组成:propertyName = 类型转换器类

如:name=util.NameConvert

name:表示要进行转换的属性

util.NameConvert:表示要进行转换的自定义类型转换器。

注意:该属性文件应该与ActionName.class放在相同位置。

2.注册全局类型转换器。对所有Action的特定类型的属性都会生效。

全局类型转换器,必须提供一个xwork-conversion.properties文件。文件必须保存在classes目录下。该资源文件名格式如下:

复合类型=对应的类型转换器

复合类型:指定需要完成类型转换的复合类

对应的类型转换器:指定所指定类型转换的转换器。

如:注册User类的全局类型转换器为:UserConverter

cn.wjz.bean.User = cn.wjz.util.UserConverter

注意:如果局部类型转换和全局类型转换同时存在的话,局部类型转换具有较高的优先级,也就是以局部类型转换器为主。

三.集合类型的类型转换
对于List元素来说,内容如: Element_attributeName=typeName;

对于Map元素来说,

(1)如果表示key的类型,则:Key_attributeName=typeName;

(2)如果表示value的类型,则为:Element_attributeName=typeName;

比如,此处没有使用泛型,而是使用了局部类型转换文件:

  1. Conversion02Action.java
  2. public class Conversion02Action extends ActionSupport {
  3. private List lists;
  4. private Map maps;
  5. public String execute()throws Exception{
  6. System.out.println(((Person)lists.get(0)).getGender());
  7. System.out.println(((Person)lists.get(0)).getSalary());
  8. System.out.println(((Person)maps.get("one")).getGender());
  9. System.out.println(((Person)maps.get("one")).getSalary());
  10. return SUCCESS;
  11. }
  12. public List getLists() {
  13. return lists;
  14. }
  15. public void setLists(List lists) {
  16. this.lists = lists;
  17. }
  18. public Map getMaps() {
  19. return maps;
  20. }
  21. public void setMaps(Map maps) {
  22. this.maps = maps;
  23. }
  24. }

Conversion02Action-conversion.properties

  1. Element_lists=org.person.Person
  2. Key_maps=java.lang.String
  3. Element_maps=org.person.Person

页面表单:

  1. <s:fielderror></s:fielderror>
  2. <s:form action="conversion02" >
  3. <s:textfield label="list1.salary" name="lists[0].salary"></s:textfield>
  4. <s:textfield label="list1.gender" name="lists[0].gender"></s:textfield>
  5. <s:textfield label="map1.gender" name="maps['one'].gender"></s:textfield>
  6. <s:textfield label="map1.salary" name="maps['one'].salary"></s:textfield>
  7. <s:submit value="提交"></s:submit>
  8. </s:form>

四.Struts 2内建的类型转换器 :

Sturts 2为常用的数据类型提供了内建的类型转换器,所以根本不用自定义转换器。对于内建的转换器,Struts在遇到这些类型时,会自动去调用相应的转换器进行类型转换。

Struts 2全部的内建转换器:

·基本数据类型以及其封装类。包括:boolean和Boolean、char和Character、int和Integer、long和Integer、float和Float、double和Double。完成字符串和基本数据类型或其封装类之间的转换。

·日期类型。使用当前区域的短格式转换,即DateFormat.getInstance(DateFormat.SHORT)完成字符串和日期类型之间的转换。

·集合(Collection)类型。将request.getParameterValues(String arg)返回的字符串数据与Java.util.Collection转换。集合元素为String类型。

·集合(Set)类型。与Collection的转换相似,只是去掉了相同的值。集合元素为String类型。

·数组类型。将request.getParameterValues(String arg)返回的字符串数组中的每个字符串值取出组成一个数组。数组元素为String类型。

注意:Struts 2提供的全部内建转换器都是双向的,也就是说从用户输入页到服务器端时会将字符串类型转换成相应的数据类型。在显示输出时,又会将相应的数据类型转换成字符串类型来显

数组类型的转换器。这个转换器非常有用,比如多个表单元素的name属性相同,那么提交的参数就不再是字符串而是一个字符串数组。通过Sturts 2提供的数组类型的转换器就能很方便的将多个相同name属性的表单元素的值封装到Action中的一个数组中。

五.类型转换中错误处理:

1.类型转换的错误处理流程:

Struts2提供了一个名为conversionError的拦截器,这个拦截器被注册在默认的拦截器栈中,在Struts-default.xml中的配置信息:

  1. <interceptor-stack name="defaultStack">
  2. .. .. ..
  3. <!—- 处理类型转换错误的拦截器 -->
  4. <interceptor-ref name="conversionError"/>
  5. <!—- 处理数据校验的拦截器 -->
  6. <interceptor-ref name="validation">
  7. <param name="excludeMethods">input,back,cancel,browse</param>
  8. </interceptor-ref>
  9. <interceptor-ref name="workflow">
  10. <param name="excludeMethods">input,back,cancel,browse</param>
  11. </interceptor-ref>
  12. </interceptor-stack>

如果Struts2的类型转换器执行类型转换时出现错误,该拦截器将负责将对应的错误封装成表单域错误(fieldError),并将这些错误信息放入ActionContext中。

Struts2的错误处理流程:

2、错误信息的友好显示

在进行类型转换中,如果出现错误将会提示错误信息。Struts 2默认提供了错误信息提示,但是这些错误信息提示不够友好,下面将介绍如何自定义错误信息来取代Struts 2的默认错误信息。

·定义全局类型转换错误处理信息:

在应用的国际化资源文件中增加如下的信息:

xwork.default.invalid.fieldvalue = key

key的值就是用户希望在页面中显示的提示信息。  例如:

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

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

因为包含非西欧字符,因此使用 native2ascii 命令处理

xwork.default.invalid.fieldvalue =

{0}\u5b57\u6bb5\u7c7b\u578b\u8f6c\u6362\u5931\u8d25\uff01\uff01

·定义局部类型转换错误处理信息:

在某些时候可能还需要对特定的字段指定特别的提示信息,此时可以提供该Action的局部资源文件,文件名:ActionName.properties , 在文件中增加如下一项:

invalid.fieldvalue.属性名 =提示信息

例如:

#改变Action中birth属性类型转换错误后的提示信息

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

使用 native2ascii 命令处理

invalid.fieldvalue.birth =

\u751f\u65e5\u4fe1\u606f\u5fc5\u987b\u6ee1

\u8db3yyyy-MM-DD\u683c\u5f0f

 

六.类型转换的流程

1、用户进行请求,根据请求名在struts.xml中寻找Action

2、在Action中,根据请求域中的名字去寻找对应的set方法。找到后在赋值之前会检查这个属性有没有自定义的类型转换。没有的话,按照默认进行转换;如果某个属性已经定义好了类型转换,则会去检查在Action同一目录下的action文件名-conversion.properties文件。

3、从文件中找到要转换的属性及其转换类。

4、然后进入转换类中,在此类中判断转换的方向。我们是先从用户请求开始的,所以这时先进入从字符串到类的转换。返回转换后的对象。流程返回Action。

5、将返回的对象赋值给Action中的属性,执行Action中的execute()

6、执行完execute()方法,根据struts.xml的配置转向页面

7、在jsp中显示内容时,根据页面中的属性名去调用相应的get方法,以便输出

8、在调用get方法之前,会检查有没有此属性的自定义类型转换。如果有,再次跳转到转换类当中。

9、在转换类中再次判断转换方向,进入由类到字符串的转换,完成转换后返回字符串。

10、将返回的值直接带出到要展示的页面当中去展示。

struts2数据类型转换详解的更多相关文章

  1. 关于Struts2的类型转换详解

    详细出处参考:http://www.jb51.net/article/35465.htm 一.类型转换的意义 对于一个智能的MVC框架而言,不可避免的需要实现类型转换.因为B/S(浏览器/服务器)结构 ...

  2. ContentProvider数据访问详解

    ContentProvider数据访问详解 Android官方指出的数据存储方式总共有五种:Shared Preferences.网络存储.文件存储.外储存储.SQLite,这些存储方式一般都只是在一 ...

  3. 【HANA系列】SAP HANA XS使用JavaScript数据交互详解

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA XS使用Jav ...

  4. struts2常用标签详解(申明:来源于网络)

    struts2常用标签详解(申明:来源于网络) 地址:http://blessht.iteye.com/blog/1184960

  5. JVM 运行时数据区详解

    一.运行时数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同数据区域. 1.有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,所有的线程共享这些数据区. 2.第二种则 ...

  6. struts2基本配置详解2

    接上篇struts2基本配置详解,还有一些配置没有讲到,下面将继续. struts.xml <package name="com.amos.web.action" names ...

  7. 学习《深度学习与计算机视觉算法原理框架应用》《大数据架构详解从数据获取到深度学习》PDF代码

    <深度学习与计算机视觉 算法原理.框架应用>全书共13章,分为2篇,第1篇基础知识,第2篇实例精讲.用通俗易懂的文字表达公式背后的原理,实例部分提供了一些工具,很实用. <大数据架构 ...

  8. 【HANA系列】【第一篇】SAP HANA XS使用JavaScript数据交互详解

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列][第一篇]SAP HANA XS ...

  9. 3dTiles 数据规范详解[1] 介绍

    版权:转载请带原地址.https://www.cnblogs.com/onsummer/p/12799366.html @秋意正寒 Web中的三维 html5和webgl技术使得浏览器三维变成了可能. ...

随机推荐

  1. Nginx系列之负载均衡和反响代理

    NGINX介绍 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行 其特点是占有内存少,并发能力强,事实上nginx ...

  2. Git安装部署

    1.1 最新git源码下载地址 https://github.com/git/git/releases https://www.kernel.org/pub/software/scm/git/ 1.2 ...

  3. SQL.Cookbook 读书笔记2 查询结果排序

    第二章 查询结果排序 2.1 按查询字段排序 order by sal asc; desc;-- 3表示sal 2.2 按子串查询 );--按job的最后两个字符排序 2.3 对字符数字混合排序 cr ...

  4. 7、easyui 表单

    这是最后一个小节了,后面将会使用一个小项目来进一步实用讲解: 在之前的什么相关只是点都以及讲过了或者说涉及到过,如datagrid表格,树形菜单,布局面板panel,页签,拖放功能,只是在表格的属性细 ...

  5. lucene中的IndexWriter.setMaxFieldLength()

    lucene中的IndexWriter.setMaxFieldLength() 老版本的Lucene中,IndexWriter的maxFieldLength是指一个索引中的最大的Field个数. 这个 ...

  6. 部署网站时的错误“one of its dependencies.试图加载格式不正确的程序。”解决方案。

    Sever Error in '/' Application.Could not load file or assembly 'SresBase' or one of its dependencies ...

  7. 如何自己实现一套EasyNVR这样的无插件流媒体服务器

    EasyNVR流媒体解决方案 EasyNVR能够通过简单的网络摄像机通道配置,将传统监控行业里面的高清网络摄像机IP Camera.NVR等具有RTSP协议输出的设备接入到EasyNVR,EasyNV ...

  8. Centos中查询目录中内容命名ls(六)

    首先解释下这块, root代表当前登录用户,localhost代表主机名, ~代表当前主机目录,#代表用户权限 #表示超级用户,$表示普通用户: 查询目录中内容命令 ls  (list缩写) 格式 l ...

  9. TreeMap详细介绍(源码解析)和使用示例

    本文转自 http://www.cnblogs.com/skywang12345/p/3310928.html 概要 这一章,我们对TreeMap进行学习.我们先对TreeMap有个整体认识,然后再学 ...

  10. MySQL中InnoDB全文检索

    InnoDB存储引擎从1.2.x开始支持全文索引技术,其采用full inverted index的方式.在InnoDB存储引擎中,将(DocumentID,Postition)视为一个ilist.因 ...