应用的数据一方面显示给用户看,另一方面需要保存到数据库中。而这两个用途数据的表现形式可能不同。
举例来说:
1,用户看到的性别是“男”,而数据库中存储的是“0”--这种类型的数据属于代码数据;
2,用户看到的数量是“1,214,235.30”,而数据库中存储的是“1214235.3”--这种类型的数据属于格式上的控制,可能与本地化有关。
对于以上关于数据显示和存储的差异Tapestry是如何设计与解决的呢?请接着往下看...
一、数据显示的格式化
1,输入域
用户可以输入数据的组件,如:TextField。
需要设置translator属性,如果是代码数据的转换则继承于AbstractTranslator,如果是数据格式的转换则继承于FormatTranslator。
如果是继承于AbstractTranslator,则需要实现formatObject方法和parseText方法.
其中formatObject方法是为了显示而进行的转换,它是将对象转换为字符串,因为客户端显示的都是字符串;
parseText方法是为了存储以及后台处理而进行的转换,它是将字符串转换为对象,因为后台处理的都是对象。
2,输出域
用户不可以输入数据的组件,如:Insert
设置Insert的format属性为java.text.Format子类的实例。
二、数据存储的格式化
这种情况发生在输入型组件上。请参考第一条有关parseText的说明。
所以,Tapestry对数据的格式化处理是通过translator和format两种方式来进行处理的。一,转换器(translator)
实现了一个数字转换器NumberTranslator,它继承于
org.apache.tapestry.form.translator.NumberTranslator,实现的功能是字符串与数字的相互转换,可
以设置如果数字为0或NaN时显示给用户的可以是其它字符串,也可以设置小数位数等。
由于涉及到客户端javascript的对数字类型的校验(使用函数isNaN),所以后端数字的模式(如###,###%)这种复杂的形式暂时不予支持。支持的数据形式如:00123.450
public class NumberTranslator extends
org.apache.tapestry.form.translator.NumberTranslator {
public NumberTranslator() {
}
protected String formatObject(IFormComponent field, Locale locale,Object object) {
Number number = (Number) object;
if (number.doubleValue() == 0) {
if (!HiveMind.isBlank(this._zero))
return this._zero;
}
if (number.equals(new Double(Double.NaN))) {
if (!HiveMind.isBlank(this._nan))
return this._nan;
}
return super.formatObject(field, locale, object);
}
public NumberTranslator(String initializer) {
PropertyUtils.configureProperties(this, initializer);
}
protected Object parseText(IFormComponent field,
ValidationMessages messages, String text) throws ValidatorException {
if (text.equals(this._zero)) {
return new Long(0);
}
if (text.equals(this._nan)) {
return new Double(Double.NaN);
}
return super.parseText(field, messages, text);
}
protected String defaultScript() {
return null;
}
public void renderContribution(IMarkupWriter writer, IRequestCycle cycle,
FormComponentContributorContext context, IFormComponent field) {
context
.includeClasspathScript("/mycom/web/tapestry/translator/NumberValidator.js");
String message = TapestryUtils.enquote(buildMessage(context, field,getMessageKey()));
if (this.getSubmit() ==
null)
{
context.addSubmitHandler(Script.getFormNumberScript(field,
this._zero, this._nan, message));
} else {
TapestryUtils.getPageRenderSupport(cycle, field)
.addInitializationScript(
Script.getSubmitNumberScript(this.getSubmit(),field, this._zero,
this._nan, TapestryUtils.enquote(message)));
}
}
private String _zero = "0";
private String _nan = "NaN";
private String _submit = null;
public void setZero(String zero) {
this._zero = zero;
}
public String getZero() {
return this._zero;
}
public void setNan(String nan) {
this._nan = nan;
}
public String getNan() {
return this._nan;
}
public String getSubmit() {
return this._submit;
}
public void setSubmit(String submit) {
this._submit = submit;
}
}
使用方法:
设置输入域(如:TextField)的translator属性:
<binding name="translator" value="translator:number2,zero=--,submit=login,pattern=###.00"/>
注意:与校验器类似,转换器也需要支持表单级和提交按钮级两种级别的转换。
格式化器(format)
1,数字格式化器
增加一个绑定numberformat,请参考另一篇文章tapestry绑定的研究与应用。
public class NumberFormatBinding extends AbstractBinding {
private final IComponent _component;
private final String _format;
protected NumberFormatBinding(String description,
ValueConverter valueConverter, Location location,
IComponent component, String format) {
super(description, valueConverter, location);
this._component = component;
this._format = format;
}
public Object getObject() {
if (_format == null)
throw new BindingException(BindingMessages.missingAsset(_component,
_format), _component, getLocation(), this, null);
return new DecimalFormat(_format);
}
}
public class NumberFormatBindingFactory extends AbstractBindingFactory {
public IBinding createBinding(IComponent root, String bindingDescription,
String expression, Location location) {
return new NumberFormatBinding(bindingDescription, getValueConverter(),
location, root, expression);
}
}
使用方法:
设置Insert组件的format属性:
<binding name="format" value="numberformat:###,###"/>
2,日期格式器
public class DateFormatBinding extends AbstractBinding {
private final IComponent _component;
private final String _format;
protected DateFormatBinding(String description,
ValueConverter valueConverter, Location location,
IComponent component, String format) {
super(description, valueConverter, location);
this._component = component;
this._format = format;
}
public Object getObject() {
if (_format == null)
throw new BindingException(BindingMessages.missingAsset(_component,_format), _component, getLocation(), this, null);
return new SimpleDateFormat(_format);
}
}
public class DateFormatBindingFactory extends AbstractBindingFactory {
public IBinding createBinding(IComponent root,
String bindingDescription,String expression, Location location) {
return new
DateFormatBinding(bindingDescription, getValueConverter(),location,
root, expression);
}
}
使用方法:
设置Insert组件的format属性:
<binding name="format" value="dateformat:yyyy-MM-dd"/>
3,注册这两个绑定。
<!-- add a binding named "numberformat" to format a number
usage: <binding name="format" value="numberformat:###,###.00"/>
-->
<service-point
id="NumberFormatBindingFactory"
interface="org.apache.tapestry.binding.BindingFactory">
<invoke-factory>
<construct
class="mycom.web.tapestry.binding.NumberFormatBindingFactory">
<set-object property="valueConverter"
value="infrastructure:valueConverter"/>
</construct>
</invoke-factory>
</service-point>
<contribution configuration-id="tapestry.bindings.BindingFactories">
<binding prefix="numberformat" service-id="NumberFormatBindingFactory"/>
</contribution>
<!-- add a binding named "dateformat" to format a date
usage: <binding name="format" value="dateformat:yyyy-MM-dd"/>
-->
<service-point
id="DateFormatBindingFactory"
interface="org.apache.tapestry.binding.BindingFactory">
<invoke-factory>
<construct
class="mycom.web.tapestry.binding.DateFormatBindingFactory">
<set-object property="valueConverter"
value="infrastructure:valueConverter"/>
</construct>
</invoke-factory>
</service-point>
<contribution configuration-id="tapestry.bindings.BindingFactories">
<binding prefix="dateformat" service-id="DateFormatBindingFactory"/>
</contribution>
代码有点乱,请多多包涵。 |