PrimeFaces4,5的AutoComplete、SelectOneMenu等在下拉菜单中除了显示单纯的文字列表外,还可以分多列显示图片等内容,效果上比OS自带的控件更绚了,但使用上并不复杂,将String的List数据更换成POJO的List,再自定义一个Converter就行了。
Converter并不是PrimeFaces定义的,属于JSF规范。在JavaEE的文档[3]中,对Converter的介绍是“Converters are used to convert data that is received from the input components.” ,需要这个东西的原因是JSF等Web层和普通GUI一样,用户输入的内容都是作为字符串来接收和显示的,但是在程序内部存储的变量则可能是Integer,Float,Date等等类型,需要进行类型转换。以往这些转换是由应用设计人员自己编码进行的,但新的GUI框架中,这部分转换基本都交给专门的功能类来处理了。
JSF2.0中,这个转换工作是由Converter类来完成的,JavaEE6.0已经实现了一部分数据类型的Converter,位于javax.faces.convert 包内:
- BigDecimalConverter
- BigIntegerConverter
- BooleanConverter
- ByteConverter
- CharacterConverter
- DateTimeConverter
- DoubleConverter
- FloatConverter
- IntegerConverter
- LongConverter
- NumberConverter
- ShortConverter
在JSF页面代码中,选中的对象是需要转换为一个字符串形式来传递给后台的(可以看一下JSF运行生成的HTML源代码),所以每个对象要有一个字符串表示形式,同样该字符串表示形式也要能转换会对象。
JSF中的Faces转换器都必须实现接口javax.faces.convert.Converter ,该接口定义了两个方法:
public Object getAsObject(FacesContext context, UIComponent component, String value)
public String getAsString(FacesContext context, UIComponent component, Object value)
这两个方法所作的工作正好相反,一个是把String类型的value转换为Object类型,一个是把Object类型转换为String形式,分别用于处理输入和生成显示用的HTML代码。
Converter的使用和实现
Converter的使用很简单,只要像上面的例子一样,在AutoComplete、SelectOneMenu等控件的converter属性里指定一下就行了,但其编写要稍微费点周折。和文档中的例子不同的是,实际项目中数据来源通常不是固定的,而是来自数据库等可变的数据。比如AutoComplete控件,下拉列表里的数据往往是根据输入内容从数据库里查询出来的,因此Converter要实现Object和String的转换,还需要获得数据库中的数据。
比如以ID号作为员工对象转换为String的表示内容,则Object to String很简单,return ""+((Employee)obj).getId() 就行了,但String to Object就不那么简单了,员工姓名、性别等属性从何而来? 最直接的方法是也从数据库获取,还有一个方法是把刚才的下拉列表里的Employee List缓存在Session里,直接到里面查找。
具体方式,从数据库获取的方法可以把Converter定义为JSF的托管Bean,给其配置到业务层或者持久层的访问接口。
缓存在Session里的方式需要把AutoComplete对应的托管Bean在获取下拉列表的数据时,同时保存一份到Session里,比如把一个托管Bean生命周期定义为SessionScope,在里面存放数据,但同一个页面同时在多个窗口打开可能会有数据冲突。或者放在ViewScope的托管Bean里以避免?这种方式还没有经过验证,不确定会有什么问题。Converter从数据库获取Object的方式,为简单起见,可以把AutoComplete等控件对应的托管Bean实现为Converter,这样可以避免再配置一遍,不过结构上不太优雅,正式设计中还是不要这么做为好。