大部分时候,我们使用Struts 2提供的类型转换器,以及基于OGNL的类型转换机制,就能满足大部分类型转换需求。但在有些特殊的情形下,例如需要把一个字符串转换成一个复合对象(例如User对象)时,这就需要使用自定义类型转换器。例如,用户输入一个abc,xyz字符串,我们需要将其转换成一个User类型实例,其中abc作为User实例的name属性值,而xyz作为User实例的pass属性值。

假设本系统有一个如图4.2所示的表单输入页面。

图4.2输入字符串的页面

如图4.2所示的页面包含一个名为user的表单域,这将产生一个名为user的请求参数,该请求对应的Action类代码如下。

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

public class LoginAction implements Action

{

private User user;

private String tip;

//user属性的setter和getter方法

public void setUser(User user)

{

this.user = user;

}

public User getUser()

{

return this.user;

}

//省略tip属性的setter和getter方法

...

public String execute() throws Exception

{

if (getUser().getName().equals("crazyit.org")

&& getUser().getPass().equals("leegang") )

{

setTip("登录成功!");

return SUCCESS;

}

else

{

setTip("登录失败!!");

return ERROR;

}

}

}

从上面的代码中可以看出,该Action的user属性是User类型,而对应表单页发送的user请求参数则只能是字符串类型。Struts 2功能虽然强大,但它依然不知道如何完成字符串和User对象之间的转换,这种转换需要程序员来完成。

User类就是一个普通的JavaBean类,关于此类代码读者请参考光盘中的程序清单:codes\04\4.1\LocalConverter\WEB-INF\src\org\crazyit\app\domain\User.java。

Struts 2的类型转换器实际上依然是基于OGNL框架的,在OGNL项目中有一个TypeConverter接口,这个接口就是自定义类型转换器必须实现的接口。该接口的定义代码如下:

//OGNL提供的类型转换器接口

public interface TypeConverter

{

public Object convertValue(Map context, Object target,

Member member, String propertyName, Object value, Class toType);

}

实现类型转换器必须实现上面的TypeConverter,不过上面接口里的方法太过复杂,所以OGNL项目还为该接口提供了一个实现类:DefaultTypeConverter,通常都采用扩展该类来实现自定义类型转换器。实现自定义类型转换器需要重写DefaultTypeConverter类的convertValue方法。

下面是本应用所使用的类型转换器的代码。

程序清单:codes\04\4.1\LocalConverter\WEB-INF\src\org\crazyit\app\converter\UserConverter.java

public class UserConverter extends DefaultTypeConverter

{

//类型转换器必须重写convertValue方法,该方法需要完成双向转换

public Object convertValue(Map context

, Object value, Class toType)

{

//当需要将字符串向User类型转换时

if (toType == User.class )

{

//系统的请求参数是一个字符串数组

String[] params = (String[])value;

//创建一个User实例

User user = new User();

//只处理请求参数数组第一个数组元素,

//并将该字符串以英文逗号分割成两个字符串

String[] userValues = params[0].split(",");

//为User实例赋值

user.setName(userValues[0]);

user.setPass(userValues[1]);

//返回转换来的User实例

return user;

}

else if (toType == String.class )

{

//将需要转换的值强制类型转换为User实例

User user = (User) value;

return "

+ user.getPass() + ">";

}

return null;

}

}

上面的程序的粗体字代码是实现类型转换的关键,第一段粗体字代码实现将字符串转换成User对象,第二段粗体字代码实现将User对象转换成字符串。读者可能对上面实现的类型转换器感到有一些迷惑,下面是关于上面的类型转换器的几点说明。

1.convertValue方法的作用

convertValue方法的作用最简单,该方法负责完成类型的转换,不过这种转换是双向的:当需要把字符串转换成User实例时,是通过该方法实现的;当需要把User实例转换成字符串时,也是通过该方法实现的。

为了让该方法实现双向转换,我们通过判断toType的类型即可判断转换的方向。toType类型是需要转换的目标类型,当toType类型是User类型时,表明需要将字符串转换成User实例;当toType类型是String类型时,表明需要把User实例转换成字符串类型。图4.3显示了这种toType参数和转换方向之间的关系。

图4.3 toType参数和转换

方向之间的关系

一旦通过toType类型判断了类型转换的方向后,我们就可以分别实现两个方向的转换逻辑了。

2.convertValue方法参数和返回值的意义

通过上面的介绍可以看出,实现类型转换器的关键就是实现convertValue方法,该方法有如下三个参数。

Ø第一个参数:context是类型转换环境的上下文。

Ø第二个参数:value是需要转换的参数。随着转换方向的不同,value参数的值也是不一样的,当把字符串类型向User类型转换时,value是原始字符串数组;当需要把User类型向字符串类型转换时,value是User实例。

Ø第三个参数:toType是转换后的目标类型,这个参数前面已经介绍了。

该方法的返回值就是类型转换后的值,该值的类型也会随转换方向的不同而不同,当把字符串向User类型转换时,返回值类型就是User类型;当需要把User类型向字符串类型转换时,返回值类型就是字符串类型。

由此可见,转换器的convertValue方法,接收需要转换的值,需要转换的目标类型为参数,然后返回转换后的目标值。

3.当把字符串向User类型转换时,为什么value是一个字符串数组,而不是一个字符串

很多读者会感到疑惑:当我们需要把字符串转换成User类型时,为什么value的值是字符串数组,而不是一个字符串。因为在前面的介绍中,我们总是说浏览器发送的请求参数类型是字符串,而不是字符串数组。

在如图4.4所示的页面中,姓名输入框的值只能是一个普通字符串。但选择课程的列表框的值则可以同时选择多个值。因此,浏览者向服务器发送请求时,该下拉列表框对应的请求参数则是字符串数组。

图4.4包含字符串数组请求参数的表单页

对于DefaultTypeConverter转换器而言,它必须考虑到最通用的情形,因此它把所有的请求参数都视为字符串数组,而不是字符串。对字符串请求参数而言(例如姓名请求参数),转换器把该请求参数值当成长度为1的数组。

提示:

可以认为DefaultTypeConverter是通过HttpServletRequest的getParameter Values(name)方法来获取请求参数值的。因此它获取的请求参数总是字符串数组,如果请求参数只包含一个单个的值,则该请求参数的值是一个长度为1的字符串数组。

java 自定义 转换器_自定义类型转换器相关推荐

  1. springmvc自定义参数解析器/类型转换器

    概述 有些时候我们需要对GET请求的入参做自定义的处理,比较常见的就是字符串反序列化时间类型了,常用的像@DateTimeFormat注解,但是这需要在每个入参的属性上都加上这个注解,比较费手,那么我 ...

  2. java import自定义类_自定义类加载器-从.class和.jar中读取

    一. 类加载器 JVM中的类加载器:在jvm中,存在两种类加载器, a) Boostrap ClassLoader:这个是由c++实现的,所以在方法区并没有Class对象的实例存在.用于加载JAVA_ ...

  3. java自定义字段_自定义字段的设计与实现(Java实用版)

    前言 自定义字段又叫做"开放模型",用户可以根据自已的需求,添加需要的字段,实现个性化定制. 使用自定义字段的目的,使用自定义字段解决哪些问题 如现有一套CRM系统,客户模块中客户 ...

  4. java validate校验_自定义工具类实现validate参数校验

    前言 相信项目中做一些htttp接口,避免不了要对参数进行校验,大多数情况下,其实我们只是校验是否为NULL就可以了 1.通过注解实现各种状态的字段 1.1.引入依赖 默认的版本是6.0.9.Fina ...

  5. java 日志切面_自定义注解+面向切面整合的日志记录模块(一)

    java中的常见注解 jdk的自带注解 @Override:告诉编译器我重写了接口方法 @Deprecated:告诉编译器这个方法过时了,不建议使用,Ide会在方法上划横线 @SuppressWarn ...

  6. java自定义配置文件_自定义配置文件如何配置

    @Component public class RoleDirectiveModel implements TemplateDirectiveModel { /** * * @param enviro ...

  7. java授权失败_自定义Spring Security的身份验证失败处理方法

    1.概述 在本快速教程中,我们将演示如何在Spring Boot应用程序中自定义Spring Security的身份验证失败处理.目标是使用表单登录方法对用户进行身份验证. 2.认证和授权(Authe ...

  8. java 自定义表达式_自定义 Java Lambda

    用了这么久的 Java,也体验了 Java 8 的 lambda 带来的便捷,但是我一直都是直接用,而从未想过他是如何实现的.比如:为什么在小括号里面可以放一个函数作为参数,自己造一个lambda 应 ...

  9. java session 持久化_自定义实现session持久化

    自定义实现session持久化 使用场景 对于有登录校验的网站,tomcat 重启之后,刷新页面又得重新登录,影响用户体验. 原因: tomcat 的session 在内存中,tomcat重启之后,内 ...

  10. java 地图报表_自定义地图功能介绍

    自定义动态地图利用动态的和互动式的falsh地图帮助您按类别,地区或实体显示地理数据.用户可以用它有效地按以下因素绘制业务数据,如地区产品销售额,地区税收,户口普查资料,如国家人口数,选举结果和统计调 ...

最新文章

  1. Linux学习(五)---开机、重启和用户登录注销
  2. 模型参数优化(三):模拟退火
  3. spring框架mvc框架_Spring MVC测试框架入门–第2部分
  4. 解析ajax数据显示到from表单中,jQuery Ajax从另一页上的Form请求中提取数据?
  5. 设计秒杀系统架构,这4个关键点要注意
  6. bzoj1597 [Usaco2008 Mar]土地购买
  7. 101.接收上游响应的缓存处理流程
  8. 我发起了一个 .Net Core 平台上的 分布式缓存 开源项目 ShareMemory 用于 取代 Redis...
  9. 使用TF卡烧录Jetson NX开发板
  10. 单元测试报告软件测试,软件单元测试报告-模板
  11. 用python实现爬取百度贴吧的小项目
  12. Android TextToSpeech简单使用
  13. Android Startup实现分析
  14. elementUI表格合并行
  15. 中学语文教学参考杂志社中学语文教学参考编辑部2022年第27期目录
  16. python 数据分析 |3. Pandas 学习
  17. 音视频处理工具ffmpeg基本使用
  18. rfc959 FTP传输协议
  19. 集成机器学习服务上架华为应用市场指南
  20. nginx 配置优化的几个参数

热门文章

  1. 组态王bitset用法_组态王使用问题解答
  2. 计算机考研专业课408什么意思,考研408是什么意思
  3. 最小二乘法(least squares)的曲线拟合(curve fitting)
  4. 决策树ID3算法实现与讨论(完整代码与数据)
  5. lamp一键安装包不安装mysql_LAMP一键安装包-CentOS 5/6下自动编译安装Apache、MySQL、PHP...
  6. 数字化转型建设的基本模型与能力构建
  7. ArcGIS_一种简单的三维城市建模方法
  8. linux基础教程-黑马程序员汇总PDF
  9. JESD204B 使用说明
  10. 微信小程序下拉刷新功能