| 应用的数据一方面显示给用户看,另一方面需要保存到数据库中。而这两个用途数据的表现形式可能不同。
举例来说:
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>
代码有点乱,请多多包涵。  |