DWR和HttpSessionBindingListeners
DWR1.x中存贮已经创造的Bean的方法需要注意,它在每次请求时都会调用相同的 setAttribute() 方法。就是说,如果一个Bean在dwr.xml中的声明周期设置为session,再每次调用bean中的方法时,DWR都会执行一次 session.setAttribute(yourBean) 。这看上去没有什么危害,但是如果你要使用servlet的事件机制的,就是说用了HttpSessionBindingListener接口,你就会发现valueBound和valueUnbound事件在每次调用时都会发生,而不是你想像的在bean被创建时以及session过期时。 DWR2 只在第一次创建对象时调用 setAttribute() 。
Converters
我们必须保证所有的参数都可以被转换。JDK中的多数类型已经有转换器了,但是你需要给DWR转换你的代码的权利。一般来说JavaBean的参数需要一个
? ? ? ? ? ? ?
所有的原生类型 boolean,int,double, 等等
原生类型的对象类型 Boolean,Integer,等等
java.lang.String
java.util.Date 和SQL中的Date 以上类型组成的数组
以上类型的集合类型 (Lists, Sets, Maps, Iterators, 等)
从DOM, XOM, JDOM 和 DOM4J中的DOM对象 (类似 Element 和 Document)
基础的转换器
原生类型,String,像BigDecimal这样的简单对象的转换器已经有了。你不需要在dwr.xml中部分的
默认支持的类型包括: 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的字符串 (例如\,你想把它转换成Java的Date类型有两个办法:在javascript中用Date.parse()把它解析成Date类型,然后用DWR的DateConverter传递给服务器;或者把它作为字符串传递给Server,再用Java中的SimpleDateFormat(或者类似的)来解析。
同样,如果你有个Java的Date类型并且希望在HTML使用它。你可以先用
SimpleDateFormat把它转换成字符串再使用。也可以直接传Date给Javascript,然后用Javascript格式化。第一种方式简单一些,尽管浪费了你的转换器,而且这样做也会是浏览器上的显示逻辑受到限制。其实后面的方法更好,也有一些工具可以帮你,例如:
? ?
The Javascript Toolbox Date formatter Web Developers Notes on Date formatting
其他对象
其实创建自己的转换器也很简单。Converter接口的Javadoc包含了信息。其实这种需要很少出现。在你写自己的Converter之前先看看BeanConverter,它有可能就是你要的。
数组转换器(Array Converter)
数组实体不太容易理解。默认情况下DWR能转换所有原生类型的数组,还有所有
marshallable对象的数组。这些marshallable对象包括前面介绍的String和Date类型。
高级Java程序员应该能够理解为什么match属性看上去很怪。
上面没有解释*的作用 - 它是通配符,表示匹配接下来的所有字符串。这也是DWR可以转换任意类型的数组的原因。
Bean 和 Object 转换器(Bean and Object Converters )
两个没有默认打开的转换器是Bean 和 Object 转换器。Bean转换器可以把POJO转换成Javascript的接合数组(类似与Java中的Map),或者反向转换。这个转换器默认情况下是没打开的,因为DWR要获得你的允许才能动你的代码。
Object转换器很相似,不同的是它直接应用于对象的成员,而不是通过getter和setter方法。下面的例子都是可以用object来替换bean的来直接访问对象成员。 如果你有一个在
你可以为某一个单独的类打开转换器:
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:\Remoted.setPerson(p);
限制属性转换
就像你可以在creator的定义中剔出一些方法一样,converter也有类似的定义。 限制属性转换仅仅对于Bean有意义,很明显原生类型是不要需要这个功能的,所以只有BeanConverter及其子类型(HibernateBeanConverter))有这个功能。 语法是这样的:
这就保证了DWR不会调用 fred.getProperty1() 和fred.getProperty2两个方法。另外如果你喜欢\白名单\而不是\黑名单\的话:
安全上比较好的设计是使用\白名单\而不是\黑名单\。
对象的私有成员
通过'object'转换器的参数的一个名为force的参数,可以让DWR通过反射来访问对象私有成员。
语法是这样的:
直到DWR1.1.3,这里有一个bug,public的field反而不能被发现,所以你需要在public成员上设置force=true
集合类型转换器(Collection Converter )
有个两个默认的转换器,针对Map和Collection:
? ?
仅仅用反射机制是没有方法明确集合里面是什么类型的。所以这两个转换器不能把集合里面的东西转换成有意义的Javascript对象。 不能明确是那种类型的集合。
虽然我们不能让他们自动的起作用,我们可以在dwr.xml中用signatures语法声明它们类型,使之正确转换。
枚举类型转换器(Enum Converter)
枚举类型转换器默认是没有打开的。它在Java5中的Enum和Javascript的String之间进行转换。这个转换器默认关闭是因为DWR要在转换你的代码之前得到你的同意。 枚举类型转换器是DWR 1.1版以后才支持的。 你可以这样设置来打开这个转换器:
一个简单的例子。假设你有下面的Java代码: