该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2005-01-26
我们知道由于HTTP协议只能传递String,如果后台的Java模型使用了其他类型的属性,必须得做一些转化工作,而这些转化代码通常却是繁琐而又无聊,WebWork提供了Type Conversion功能,能够让我们从这些代码中解脱出来。 看一个例子, 一个Person对象,有一个出生日期的属性: public class Person { private Date dateOfBirth; } 一个Action对Person做操作: public class CreatePerson implements Action { private Person person; public String execute(); throws Exception { //Do some work //... return SUCCESS; } } 我们通常在页面上会限制这个日期的格式(比如yyyy-MM-dd),通过写一个WebWork的转化器,我们就可以把在页面上:<input type="text" name="person.dateOfBirth" value="1949-10-01"/> 这样的值直接变成了相应的Date对象。 转换器需要扩展ognl.DefaultTypeConverter (在webwork2.1.6以后,我们可以扩展WebWorkTypeConverter这个对象,更新的代码可以参考这个: http://cvs.iteye.com:8008/quake/getfile/jert/src/java/com/javaeye/core/webwork/converter/DateConverter.java?v=1.2 ) public class DateConverter extends DefaultTypeConverter { private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");; public Object convertValue(Map ognlContext, Object value, Class toType); { Object result = null; if (toType == Date.class); { result = doConvertToDate(value);; } else if (toType == String.class); { result = doConvertToString(value);; } return result; } private Date doConvertToDate(Object value); { Date result = null; if (value instanceof String); { try { result = sdf.parse((String); value);; } catch (ParseException e); { throw new XworkException("Could not parse date", e);; } } else if (value instanceof Object[]); { // let's try to convert the first element only Object[] array = (Object[]); value; if ((array != null); && (array.length >= 1);); { value = array[0]; result = doConvertToDate(value);; } } else if (Date.class.isAssignableFrom(value.getClass(););); { result = (Date); value; } return result; } private String doConvertToString(Object value); { String result = null; if (value instanceof Date); { result = sdf.format(value);; } return result; } } 那么WebWork是如何知道要使用这个转化器对Person的dateOfBirth做转化呢?我们有2种方法: 1. Class-specific conversion rules 写一个className-conversion.properties,这上面的例子里,我们就在Person.java所在的package下面,写一个Person-conversion.properties 在这个文件里面指定: dateOfBirth=com.javaeye.core.webwork.converter.DateConverter 2. Application-wide conversion rules 在classpath root下面写一个xwork-conversion.properties: java.util.Date=com.javaeye.core.webwork.converter.DateConverter 这样一旦写好了一个转换器以后,就能够很方便地被重用了,在这篇wiki里面,有更加详细的介绍: http://wiki.opensymphony.com/display/XW/Type+Conversion 再举一个实际的例子: 在jert里面,我们希望可以给用户选择多语言,那么我们在页面上提供了一个下拉列表,选项有zh_CN和en_US,通过一个LocaleConverter,我们就可以直接把String转化成Locale对象: http://cvs.iteye.com:8008/quake/getfile/jert/src/java/com/javaeye/core/webwork/converter/LocaleConverter.java?v=1.1 结论:灵活使用转换器可以减少我们那些繁琐无聊的类型转化代码。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2005-02-28
这个DateConverter没有默认的实现? 好像简单问题复杂化了
|
|
返回顶楼 | |
发表时间:2005-03-01
如果你不自己设置DateConvert,你的date格式为new SimpleDateFormat()
|
|
返回顶楼 | |
发表时间:2005-03-03
moxie 写道 如果你不自己设置DateConvert,你的date格式为new SimpleDateFormat()
好,我试试 |
|
返回顶楼 | |
发表时间:2005-03-05
如果有一个类,有很多子类,我可以在参数里指定Action的自动使用某个子类型吗?
如 class Child {} class Son extends Child class Daughter extends Child class SomeAction { Child child; } 我可以在form里通过某个filed指定child的实例应该用Son或者Daughter类创建吗?特别是当Child为abstract的时候,我们肯定必须使用某个子类的。 |
|
返回顶楼 | |
发表时间:2005-03-05
指定类型的问题解决了,通过写了一个扩展自WebWorkTypeConverter的自定义转换器,然后结合form里把指定的属性设置为需要转型的子类型而完成的。
我在xwork-default-conversions.properties里配置了一个全局的类型转换器。(不知道为什么,Action级别的根据field的配置始终行不通,是不是这个文件里不能配置成someField.someObject=xxx.converter?) 转换器的核心代码如下: /* (non-Javadoc); * @see com.opensymphony.webwork.util.WebWorkTypeConverter#convertFromString(java.util.Map, java.lang.String[], java.lang.Class); */ public Object convertFromString(Map context, String[] values, Class toClass); { try { return Class.forName(values[0]);.newInstance();; } catch (Exception e); { return values; } } /* (non-Javadoc); * @see com.opensymphony.webwork.util.WebWorkTypeConverter#convertToString(java.util.Map, java.lang.Object); */ public String convertToString(Map context, Object o); { return o.getClass();.getName();; } 部分标单如下: <ww:select label="'Select One Discount Type'" name="'coupon.discount'" list="#{'com.alpaq.icoupon.core.entity.discount.AmountDiscount':'Amount Discount', 'com.alpaq.icoupon.core.entity.discount.PercentageDiscount':'Percent Discount'}" onchange="'switchDiscountType(this);;'"/> <ww:textfield label="'Amount Discount Value'" name="'coupon.discount.amount'" /> <ww:textfield label="'Percent Discount Value(without %);'" id="typePDInput" name="'coupon.discount.percent'" disabled="'true'"/> 不过,我发现这么一来虽然能把类型转换成期望的子类型,但是,该类型的field还是不能被设置。如以上标单中的coupon.discount.amount,并不能设置action里coupon属性的discount属性的amount属性。。。 另外,我还单独模仿Jert里的PrametersInterceptor写了一个Interceptor来吧coupon.discount放到coupon.discount.amount的前头,不然会出现异常。 |
|
返回顶楼 | |
发表时间:2005-03-06
问问Quake Wang:
如果我在界面上有两种格式的日期怎么办? 例如一种短格式: SimpleDateFormat("yyyy-mm-dd"),一种长格式SimpleDateFormat("yyyy-mm-dd hh:MM:ss") |
|
返回顶楼 | |
发表时间:2005-03-06
To yufan_shi
我把回复你的email贴这里了,不知道其他人是否有其他方法: 首先如果你有多种Coupon的话,那么应该有一个CouponFactory,能够根据不同的 值,创建出不同的Coupon实例,比如: DefaultCoupon,ElectricCoupon等等, 那 么可以按照jert里的例子,用一个Intercetpor来首先绑定couponType(当然也可以 是couponTypeId这样的属性名,这样就可以重用jert里的那个Interceptor了): Action.setCouponType(String couponType); { this.coupon = CouponFactory.getCoupon(couponType);; } 对于discount的多态,我们可以在action里面添加helper method: setDiscountAmount(Double amout); { ((AmountDiscount); coupon.getDiscount(););.setAmout(amout);; } 这样可以去掉if else的判断,但是需要在action多写helper method, 我觉得这个 问题,你也可以去webwork的mailist问问看,看看其他人是否有好的解决方法。 |
|
返回顶楼 | |
发表时间:2005-03-06
To wolfsquare
你说的这个问题,可以根据你的应用情况,看哪种方式是比较常见的转换规则,那么把这个规则定成 引用 2. Application-wide conversion rules 在classpath root下面写一个xwork-conversion.properties: java.util.Date=com.javaeye.core.webwork.converter.DateConverter 另外的一个转换,可以写成Class-specific conversion rules : otherDate=com.javaeye.core.webwork.converter.OtherDateConverter |
|
返回顶楼 | |
发表时间:2005-03-06
Quake Wang 写道 To yufan_shi
我把回复你的email贴这里了,不知道其他人是否有其他方法: 首先如果你有多种Coupon的话,那么应该有一个CouponFactory,能够根据不同的 值,创建出不同的Coupon实例,比如: DefaultCoupon,ElectricCoupon等等, 那 么可以按照jert里的例子,用一个Intercetpor来首先绑定couponType(当然也可以 是couponTypeId这样的属性名,这样就可以重用jert里的那个Interceptor了): Action.setCouponType(String couponType); { this.coupon = CouponFactory.getCoupon(couponType);; } 对于discount的多态,我们可以在action里面添加helper method: setDiscountAmount(Double amout); { ((AmountDiscount); coupon.getDiscount(););.setAmout(amout);; } 这样可以去掉if else的判断,但是需要在action多写helper method, 我觉得这个 问题,你也可以去webwork的mailist问问看,看看其他人是否有好的解决方法。 想了一下,也许可以通过spring注入一个discountFactory,并且在spring里配置好TypeID和ClassName的对应关系,然后,就能通过discountFactory动态的创建子类型了,以后要增加什么新的子类型,也不需要修改任何Java代码,只要改一下spring的配置文件。 对于这些属性对象的属性的动态绑定,可能只能采用你说的这种方法;现在我的本本不再我手上,还没有试过在改成用factory在setTypeId()里绑定子类型的方法后,用coupon.discount.amount能否成功绑定. |
|
返回顶楼 | |