重用标准渲染器类型
接着,我们开始创建 Value Scroller 的子组件,并且实现渲染器的功能。按照传统方式,必须覆盖 UIComponent 的 encodeBegin() 和 decode() 方法,但是,如果我们开发的复合组件只是由多个标准组件构成,我们完全可以将不依赖于特定标记语言的标准组件基类加入到自定义组件中,并且为每个标准组件设定一个标准的渲染器类型,就可以完成复合组件要实现的渲染器功能。重用标准组件渲染器类型好处在于两方面:减少开发的工作量和可能出错的机会,对于 JSF 初学者尤为重要;不用实现与特定标记语言相关的 encode/decode 逻辑,使组件类更易于重用。
“JavaServer Faces 实战” 这本书列出了 JSF 规范提供的标准渲染器类型。
表 1. JSF 标准渲染器
从 表 1 可以看出,一个组件基类通常对应于多个渲染器类型(如果使用 HTML 作为标记语言,即对应于多个 HTML 元素),因为组件基类只定义了通用的数据和行为。比如说,UICommand 有两个 HTML 子类 HtmlCommandButton 和 HtmlCommandLink,分别对应于渲染器类型 javax.faces.Link 和 javax.faces.Button 。当我们想在一个复合组件内部包含一个链接时,只需要创建一个 UICommand 实例,并将其渲染器类型设置为 javax.faces.Link,而不用从头覆盖实现 encodeBegin() 和 decode() 方法。清单 2 列出了 Value Scroller 中的子组件如何在组件类 ValueScroller 中被创建,以及渲染器等属性如何被设定。
清单 2. 重用标准渲染器创建自定义复合组件
private static final String INPUT_TEXT_RENDERER = "javax.faces.Text";
private static final String COMMAND_LINK_RENDERER = "javax.faces.Link";
private static final String GRAPHIC_IMAGE_RENDERER = "javax.faces.Image";
/**
* Add children to the base container
*
*/
private void addChildrenAndFaces() {
// Set attributes of the base container
this.setRendererType(PANEL_GRID_RENDERER);
this.getAttributes().put(COLUMNS_ATTRIBUTE, new Integer(2));
// Add the input component
input = new UIInput();
input.setId(INPUT_ID);
input.setRendererType(INPUT_TEXT_RENDERER);
this.getChildren().add(input);
// Add the container of the up and down links
UIPanel linkContainer = new UIPanel();
linkContainer.setId(LINKPANEL_ID);
linkContainer.setRendererType(PANEL_GRID_RENDERER);
linkContainer.getAttributes().put(COLUMNS_ATTRIBUTE, new Integer(1));
ScrollerActionListener listener = new ScrollerActionListener();
// Add the up link
UICommand upLink = new UICommand();
upLink.setId(UPLINK_ID);
upLink.setRendererType(COMMAND_LINK_RENDERER);
upLink.addActionListener(listener);
UIGraphic upImage = new UIGraphic();
upImage.setId(UPIMAGE_ID);
upImage.setRendererType(GRAPHIC_IMAGE_RENDERER);
upImage.setUrl(UPIMAGE_URL);
upLink.getChildren().add(upImage);
linkContainer.getChildren().add(upLink);
// Add the down link
UICommand downLink = new UICommand();
downLink.setId(DOWNLINK_ID);
downLink.setRendererType(COMMAND_LINK_RENDERER);
downLink.addActionListener(listener);
UIGraphic downImage = new UIGraphic();
downImage.setId(DOWNIMAGE_ID);
downImage.setRendererType(GRAPHIC_IMAGE_RENDERER);
downImage.setUrl(DOWNIMAGE_URL);
downLink.getChildren().add(downImage);
linkContainer.getChildren().add(downLink);
this.getChildren().add(linkContainer);
}