dwr-converters

转换器

转换器在客户端和服务器之间转换数据.

下面这些转换器有单独章节介绍

基础的转换器

原生类型,String,像BigDecimal这样的简单对象的转换器已经有了。你不需要在dwr.xml中<allow>部分的<convert>中定义。它们默认支持。

默认支持的类型包括: boolean, byte, short, int, long, float, double, char, java.lang.Boolean, java.lang.Byte, java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Float, java.lang.Double, java.lang.Character, java.math.BigInteger, java.math.BigDecimal 和 java.lang.String

Date转换器

Date转换器负责在Javascript的Date类型与Java中的Date类型(java.util.Date, java.sql.Date, java.sql.Times or java.sql.Timestamp)之间进行转换。同基础的转换器一样,DateConverter默认是支持的。

如果你有一个Javascript的字符串 (例如"01 Jan 2010") ,你想把它转换成Java的Date类型有两个办法:在javascript中用Date.parse()把它解析成Date类型,然后用DWR的DateConverter传递给服务器;或者把它作为字符串传递给Server,再用Java中的SimpleDateFormat(或者类似的)来解析。

同样,如果你有个Java的Date类型并且希望在HTML使用它。你可以先用SimpleDateFormat把它转换成字符串再使用。也可以直接传Date给Javascript,然后用Javascript格式化。第一种方式简单一些,尽管浪费了你的转换器,而且这样做也会是浏览器上的显示逻辑受到限制。其实后面的方法更好,也有一些工具可以帮你,例如:

其他对象

其实创建自己的转换器也很简单。Converter接口的Javadoc包含了信息。其实这种需要很少出现。在你写自己的Converter之前先看看BeanConverter,它有可能就是你要的。 

数组转换器

数组实体不太容易理解。默认情况下DWR能转换所有原生类型的数组,还有所有marshallable对象的数组。这些marshallable对象包括前面介绍的String和Date类型。
高级Java程序员应该能够理解为什么match属性看上去很怪。

<convert converter="array" match="[Z"/>
<convert converter="array" match="[B"/>
<convert converter="array" match="[S"/>
<convert converter="array" match="[I"/>
<convert converter="array" match="[J"/>
<convert converter="array" match="[F"/>
<convert converter="array" match="[D"/>
<convert converter="array" match="[C"/>
<convert converter="array" match="[L*"/>

上面没有解释*的作用 - 它是通配符,表示匹配接下来的所有字符串。这也是DWR可以转换任意类型的数组的原因。

Bean 和 Object 转换器

两个没有默认打开的转换器是Bean 和 Object 转换器。Bean转换器可以把POJO转换成Javascript的接合数组(类似与Java中的Map),或者反向转换。这个转换器默认情况下是没打开的,因为DWR要获得你的允许才能动你的代码。

Object转换器很相似,不同的是它直接应用于对象的成员,而不是通过getter和setter方法。下面的例子都是可以用object来替换bean的来直接访问对象成员。

如果你有一个在 <create ...> 中声明的远程调用Bean。它有个一参数也是一个bean,并且这个bean有一个setter存在一些安全隐患,那么攻击者就可能利用这一点。

你可以为某一个单独的类打开转换器:

<convert converter="bean" match="your.full.package.BeanName"/>

如果要允许转换一个包或者子包下面的所有类,可以这样写:

<convert converter="bean" match="your.full.package.*"/>

显而易见,这样写是允许转换所有的JavaBean:

<convert converter="bean" match="*"/>

BeanConverter 和 JavaBeans 规范

用于被BeanConverter转换的Bean必须符合JavaBeans的规范,因为转换器用的是Introspection,而不是Reflection。这就是说属性要符合一下条件:有getter和setter,setter有一个参数,并且这个参数的类型是getter的返回类型。setter应该返回void,getter应该没有任何参数。setter没有重载。以上这些属于常识。如果你用的不是JavaBean,那么你应该用ObjectConverter.

设置Javascript变量

DWR可以把Javascript对象(又名maps,或联合数组)转换成JavaBean或者Java对象。

一个简单的例子可以帮助你。假设你有下面的Java代码:

public class Remoted {
  public void setPerson(Person p) {
    // ...
  }
}

public class Person {
  public void setName(String name) { ... }
  public void setAge(int age) { ... }
  // ...
}

如果这个Remoted已经被配置成Creator了,Persion类也定义了BeanConverter,那么你可以通过下面的方式调用Java代码:

var p = { name:"Fred", age:21 };
Remoted.setPerson(p);

限制属性转换

就像你可以在creator的定义中剔出一些方法一样,converter也有类似的定义。

限制属性转换仅仅对于Bean有意义,很明显原生类型是不要需要这个功能的,所以只有BeanConverter及其子类型(HibernateBeanConverter))有这个功能。

语法是这样的:

<convert converter="bean" match="com.example.Fred">
  <param name="exclude" value="property1, property2"/>
</convert>

这就保证了DWR不会调用 fred.getProperty1() 和fred.getProperty2两个方法。另外如果你喜欢"白名单"而不是"黑名单"的话:

<convert converter="bean" match="com.example.Fred">
  <param name="include" value="property1, property2"/>
</convert>

安全上比较好的设计是使用"白名单"而不是"黑名单"。

对象的私有成员

通过'object'转换器的参数的一个名为force的参数,可以让DWR通过反射来访问对象私有成员。

语法是这样的:

<convert converter="object" match="com.example.Fred">
  <param name="force" value="true"/>
</convert>

直到DWR1.1.3,这里有一个bug,public的field反而不能被发现,所以你需要在public成员上设置force=true。

集合类型转换器

有个两个默认的转换器,针对Map和Collection:

<convert converter="collection" match="java.util.Collection"/>

<convert converter="map" match="java.util.Map"/>

一般来说这些转换器可以递归转换它们的内容。

但是也有两点不足之处:

  • 仅仅用反射机制是没有方法明确集合里面是什么类型的。所以这两个转换器不能把集合里面的东西转换成有意义的Javascript对象。
  • 不能明确是那种类型的集合。

虽然我们不能让他们自动的起作用,我们可以在dwr.xml中用signatures语法声明它们类型,使之正确转换。

枚举类型转换器

枚举类型转换器默认是没有打开的。它在Java5中的Enum和Javascript的String之间进行转换。这个转换器默认关闭是因为DWR要在转换你的代码之前得到你的同意。

枚举类型转换器是DWR 1.1版以后才支持的。

你可以这样设置来打开这个转换器:

<convert converter="enum" match="your.full.package.EnumName"/>

设置Javascript变量

一个简单的例子。假设你有下面的Java代码:

public class Remoted {
  public void setStatus(Status p) {
    // ...
  }
}

enum Status {
  PASS,
  FAIL,
}

如果Remoted类已经配置好Creator,并且Status枚举类型已经设置了EnumConverter。那么你就可以在javascript中这样调用:

Remoted.setStatus("PASS");

如果没有匹配的类型,就会抛出异常。

DOM 对象

DWR可以自动转换来之DOM,DOM4J,JDOM和XOM的DOM树。你可以简单得用上面这些类库返回一个Document、Element或者Node,DWR会把他们自动转换成浏览器的DOM对象。

在程序启动的时候会有一个常见的关于JDOM转换器的警告,你可以放心的忽略它,除非你要用JDOM:

INFO: Missing classdef for converter 'jdom'. Failed to load uk.ltd.getahead.dwr.convert.JDOMConverter. Cause: org/jdom/Document

因为DWR没有办法知道你是否想用JDOM,所以这个信息设在INFO级别的。

如果你曾经尝试过使用JDOM,你会意识到在这种情况下这个转换器不可用的 - 这也是我们显示这个信息的原因。

exist-db.org

我相信DWR能同exist-db很好的工作,因为它是建立在W3C DOM之上的,而DWR也支持这个。

DWR 和 Hibernate

让DWR和Hibernate正常工作的检查列表

  1. 确保你使用的是最新的DWR。Hibernate转换器是新东西,所以你需要下载最新的
  2. 确保你已经明白开始指南上所写的内容。
  3. 确保你的Hiberante在没有DWR的时候工作正常。
  4. 如果是Spring和Hibernate一起使用,那么你最好先了解一下如何将整合Spring
  5. 配置DWR,使之与Hibernate一起工作。 (看下面)。
  6. 查看演示页面:http://localhost:8080/YOUR-WEBAPP/dwr,确定Spring的Bean可以出现。

HibernateBeanConverter

这个转换器同标准的BeanConverter非常相似,不同之处在于我们可以决定如何处理延迟加载。

使用HibernateBeanConverter可能会带来如下风险:

  • 架构: HibernateBeanConverter不符合MVC模式,所以不能把对象在数据曾和表现曾之间进行隔离。这个风险可以通过在上面加上独立的bean来减轻。
  • 性能: DWR试图通过相同的序列化方式来转换所有可以得到的属性(除了DWR仅仅读JavaBean属性的时候)。所以可能会出现通过HTTP序列化了你的整个数据的情况。通常这并不是你想要的。要减少这一风险可以使用BeanConverter(HibernateBeanConverter衍生于它)的排除某些属性的功能:
    <param name="exclude" value="propertyToExclude1, propertyToExclude2"/>

HibernateBeanConverter会尝试不去读取没有初始化的属性。如果你只是想读取所有的东西那么应该使用BeanConverter。

建议使用Hibernate3,实际上Hibernate2一下的情况,你会发现你得到的都是空的Bean。

Session管理

如果你使用Hibernate对象,你需要知道每一个DWR请求都是一个新的Servlet请求,所以你需要保证为每个请求打开一个Hiberante的Session。

如果你用Spring,那么可以很方便的使用Spring里面的OpenSessionInViewFilter,它可以保证为每个请求打开一个Hiberante的Session。类似的解决方案在其它Framework中也存在。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值