struts2数据类型转换详解
Web应用程序的交互都是建立在HTTP之上的,互相传递的都是字符串。也就是说服务器接收到的来自用户的数据只能是字符串或者是字符数组,而在Web应用的对象中,往往使用了多种不同的类型,如整数(int)、浮点数(float)、日期(Date)或者是自定义数据类型等。因此在服务器端必须将字符串转换成合适的数据类型。
Struts2框架中为我们提供了一些简单类型的转换器,比如转换为int、float等简单数据类型是不需要我们自己定义转换器去转换的,struts2内部本身就为我们提供了转换的方法,但像一些复杂的类型和我们自定义的数据类型还是需要我们自己去写转换器去转换的。在转换工程中,如果在类型转换中出现异常,类型转换器开发者无需关心异常处理逻辑,Struts2的conversionError拦截器会自动处理该异常,并且提示在页面上生成提示信息。
下面我们就一步步的实现和注册一个我们自己的转换器,也就是自定义类型转换器的几个步骤:
一:自定义类型转换器
实现自定义类型转换器我们一般有两种方式:
1.实现OGNL提供的TypeConvert接口以及实现了TypeConvert接口的DefaultTypeConvert类来实现自定义的类型转换器。我们来看一下DefaultTypeConvert类的源码:
- publicclass DefaultTypeConverter implements TypeConverter{
- public DefaultTypeConverter(){
- super();
- }
- /**
- * @param context:类型转换的上下文
- * @param value:需要转换的参数
- * @param toType:转换后的目的类型
- */
- public Object convertValue(Map context,
- Object value,
- Class toType)
- {
- return OgnlOps.convertValue(value, toType);
- }
- public Object convertValue(Map context, Object target,
- Member member, String propertyName,
- Object value, Class toType)
- {
- return convertValue(context, value, toType);
- }
- }
convertValue方法的作用:
该方法负责完成类型的双向转换,为了实现双向转换,我们通过判断toType的类型即可判断转换的方向。toType类型是需要转换的目标类型,如:当toType类型是User类型时,表明需要将字符串转换成User实例;当toType类型是String类型时,表明需要把User实例转换成字符串类型。通过toType类型判断了类型转换的方向后,我们就可以分别实现两个方向的转换逻辑了。实现类型转换器的关键就是实现conertValue方法,该方法有三个参数:
第一个参数 context:类型转换的上下文
第二个参数 value:需要转换的参数
第三个参数 toType:转换后的目的类型
2. 基于Struts2的类型转换器
Struts 2提供了一个StrutsTypeConverter的抽象类,这个抽象类是DefaultTypeConverter类的子类。开发时可以直接继承这个类来进行转换器的构建。通过继承该类来构建类型转换器,可以不用对转换的类型进行判断(和第一种方式的区别),下面我们来看一下StrutsTypeConverter类的源码:
- publicabstractclass StrutsTypeConverter extends DefaultTypeConverter {
- //重写DefaultTypeConverter类的convertValue方法
- public Object convertValue(Map context, Object o, Class toClass) {
- //如果需要把复合类型转换成字符串类型
- if (toClass.equals(String.class)) {
- return convertToString(context, o);
- }
- //如果需要把字符串转换成符合类型
- elseif (o instanceof String[]) {
- return convertFromString(context, (String[]) o, toClass);
- }
- //如果需要把字符串转换成符合类型
- elseif (o instanceof String) {
- return convertFromString(
- context, new String[]{(String) o}, toClass);
- } else {
- return performFallbackConversion(context, o, toClass);
- }
- }
- protected Object performFallbackConversion(Map context,
- Object o, Class toClass) {
- returnsuper.convertValue(context, o, toClass);
- }
- publicabstract Object convertFromString(Map context,
- String[] values, Class toClass);
- publicabstract String convertToString(Map context, Object o);
- }
该类已经实现了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;
比如,此处没有使用泛型,而是使用了局部类型转换文件:
- Conversion02Action.java
- public class Conversion02Action extends ActionSupport {
- private List lists;
- private Map maps;
- public String execute()throws Exception{
- System.out.println(((Person)lists.get(0)).getGender());
- System.out.println(((Person)lists.get(0)).getSalary());
- System.out.println(((Person)maps.get("one")).getGender());
- System.out.println(((Person)maps.get("one")).getSalary());
- return SUCCESS;
- }
- public List getLists() {
- return lists;
- }
- public void setLists(List lists) {
- this.lists = lists;
- }
- public Map getMaps() {
- return maps;
- }
- public void setMaps(Map maps) {
- this.maps = maps;
- }
- }
Conversion02Action-conversion.properties
- Element_lists=org.person.Person
- Key_maps=java.lang.String
- Element_maps=org.person.Person
页面表单:
- <s:fielderror></s:fielderror>
- <s:form action="conversion02" >
- <s:textfield label="list1.salary" name="lists[0].salary"></s:textfield>
- <s:textfield label="list1.gender" name="lists[0].gender"></s:textfield>
- <s:textfield label="map1.gender" name="maps['one'].gender"></s:textfield>
- <s:textfield label="map1.salary" name="maps['one'].salary"></s:textfield>
- <s:submit value="提交"></s:submit>
- </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中的配置信息:
- <interceptor-stack name="defaultStack">
- .. .. ..
- <!—- 处理类型转换错误的拦截器 -->
- <interceptor-ref name="conversionError"/>
- <!—- 处理数据校验的拦截器 -->
- <interceptor-ref name="validation">
- <param name="excludeMethods">input,back,cancel,browse</param>
- </interceptor-ref>
- <interceptor-ref name="workflow">
- <param name="excludeMethods">input,back,cancel,browse</param>
- </interceptor-ref>
- </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数据类型转换详解的更多相关文章
- 关于Struts2的类型转换详解
详细出处参考:http://www.jb51.net/article/35465.htm 一.类型转换的意义 对于一个智能的MVC框架而言,不可避免的需要实现类型转换.因为B/S(浏览器/服务器)结构 ...
- ContentProvider数据访问详解
ContentProvider数据访问详解 Android官方指出的数据存储方式总共有五种:Shared Preferences.网络存储.文件存储.外储存储.SQLite,这些存储方式一般都只是在一 ...
- 【HANA系列】SAP HANA XS使用JavaScript数据交互详解
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA XS使用Jav ...
- struts2常用标签详解(申明:来源于网络)
struts2常用标签详解(申明:来源于网络) 地址:http://blessht.iteye.com/blog/1184960
- JVM 运行时数据区详解
一.运行时数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同数据区域. 1.有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,所有的线程共享这些数据区. 2.第二种则 ...
- struts2基本配置详解2
接上篇struts2基本配置详解,还有一些配置没有讲到,下面将继续. struts.xml <package name="com.amos.web.action" names ...
- 学习《深度学习与计算机视觉算法原理框架应用》《大数据架构详解从数据获取到深度学习》PDF代码
<深度学习与计算机视觉 算法原理.框架应用>全书共13章,分为2篇,第1篇基础知识,第2篇实例精讲.用通俗易懂的文字表达公式背后的原理,实例部分提供了一些工具,很实用. <大数据架构 ...
- 【HANA系列】【第一篇】SAP HANA XS使用JavaScript数据交互详解
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列][第一篇]SAP HANA XS ...
- 3dTiles 数据规范详解[1] 介绍
版权:转载请带原地址.https://www.cnblogs.com/onsummer/p/12799366.html @秋意正寒 Web中的三维 html5和webgl技术使得浏览器三维变成了可能. ...
随机推荐
- JavaScript HTML DOM增删改查
首先 js 可以修改HTML中的所有元素和属性,它还可以改变CSS样式,并且可以监听到所有事件并作出响应,这篇笔记呢 主要记录如何对HTML元素进行增删改查. 1 查找DOM 第一种方式是我们最常用的 ...
- SQL Server 2008中如何为XML字段建立索引
from:http://blog.csdn.net/tjvictor/article/details/4370771 SQL Server中的XML索引分为两类:主XML 索引和辅助XML索引.其中辅 ...
- http://www.haolizi.net/example/view_2380.html
null
- Android开发:《Gradle Recipes for Android》阅读笔记(翻译)3.2——设置Flavors和Variants
问题: 需要构建大体上一样,但是使用不同资源或者类的应用. 解决方案: 产品的flavors可以帮助你对同一个app创建不同的版本. 讨论: build types是开发过程的一部分,一般用来将app ...
- 【BZOJ3124】[Sdoi2013]直径 树形DP(不用结论)
[BZOJ3124][Sdoi2013]直径 Description 小Q最近学习了一些图论知识.根据课本,有如下定义.树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度.如果一棵树有N个节 ...
- 《从零开始学Swift》学习笔记(Day 24)——枚举
原创文章,欢迎转载.转载请注明:关东升的博客 Swift中的枚举可以定义一组常量.提高程序的可读性:还具有面向对象特性. 使用enum关键词声明枚举类型,具体定义放在一对大括号内,枚举的语法格式如下 ...
- 内网网络摄像机(RTSP/IPC/NVR)如何能在公网进行RTMP/HLS/HTTP-FLV直播
一.背景需求 传统监控行业里不管是设备端.服务器端亦或是客户端都在一个内网里面.而且现在的大部分监控方案都是这样的格局,小到一个公司范围内的监控,再到一个园区.一个仓库监控.一个农业园林监控.一个养殖 ...
- 检测当前的语言环境是否使用了 UTF-8 编码(三篇文章:先用setlocale()设置编码,再用nl_langinfo()进行检测。locale对象可以使用langLocale.name() == "zh_CN"判断)
C/C++程序中,locale(即系统区域设置,即国家或地区设置)将决定程序所使用的当前语言编码.日期格式.数字格式及其它与区域有关的设置,locale设置的正确与否将影响到程序中字符串处理(wcha ...
- 【题解】Journeys(线段树优化连边)
[#3073. Pa2011]Journeys (线段树优化连边) 这张图太直观了,直接讲透了线段树优化连边的原理和正确性. 考虑建立两颗线段树,一颗是外向树,一颗是内向树,相当于网络流建模一样,我们 ...
- Java栈和堆的区别
一.栈空间 1.栈空间存储数据效率高 2.栈中的数据是按“先进后出”的方式管理 3.栈空间存储空间比较小,不能存放大量的数据 4.JVM将基本类型的数据存放在栈空间 帮助理解 1.“客栈” 能提供很多 ...