Component可以将解码、编码的动作交给Renderer,这让您的表现层技术可以轻易的抽换,我们可以将之前的自订组件的解码、编码动作移出至
Renderer,不过由于我们之前设计的Component是个很简单的组件,事实上,如果只是要新增一个Command在输入栏位旁边,我们并不需要
大费周章的自订一个新的组件,我们可以直接为输入栏位更换一个自订的Renderer。
要自订一个Renderer,您要继承javax.faces.render.Renderer,我们的自订Renderer如下:
package onlyfun.caterpillar;
import java.io.IOException; import java.util.Map; import javax.faces.component.EditableValueHolder; import javax.faces.component.UIComponent; import javax.faces.component.UIInput; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.render.Renderer;
public class TextCmdRenderer extends Renderer { private static final String TEXT = ".text"; private static final String CMD = ".cmd"; public void encodeBegin(FacesContext context, UIComponent component) throws IOException { ResponseWriter writer = context.getResponseWriter(); String clientId = component.getClientId(context); encodeTextField(component, writer, clientId); encodeCommand(component, writer, clientId); } public void decode(FacesContext context, UIComponent component) { Map reqParaMap = context.getExternalContext(). getRequestParameterMap(); String clientId = component.getClientId(context); String submittedValue = (String) reqParaMap.get(clientId + TEXT); ((EditableValueHolder) component).setSubmittedValue( submittedValue); ((EditableValueHolder) component).setValid(true); } private void encodeTextField(UIComponent component, ResponseWriter writer, String clientId) throws IOException { writer.startElement("input", component); writer.writeAttribute("name", clientId + TEXT, null); Object value = ((UIInput) component).getValue(); if(value != null) { writer.writeAttribute("value", alue.toString(), null); } String size = (String) component.getAttributes().get("size"); if(size != null) { writer.writeAttribute("size", size, null); } writer.endElement("input"); } private void encodeCommand(UIComponent component, ResponseWriter writer, String clientId) throws IOException { writer.startElement("input", component); writer.writeAttribute("type", "submit", null); writer.writeAttribute("name", clientId + CMD, null); writer.writeAttribute("value", "submit", null); writer.endElement("input"); } }
这个自订的Renderer其解码、编码过程,与之前直接在Component中进行解码或编码过程是类似的,所不同的是在解码与编码的方法上,多了 UIComponent参数,代表所代理绘制的Component。
接下来在自订Tag上,我们的TextWithCmdTag与之前主题所介绍的没什么差别,只不过在getComponentType()与 getRendererType()方法上要修改一下:
package onlyfun.caterpillar;
import javax.faces.application.Application; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.el.ValueBinding; import javax.faces.webapp.UIComponentTag;
public class TextWithCmdTag extends UIComponentTag { private String size; private String value; public String getComponentType() { return "javax.faces.Input"; }
public String getRendererType() { return "onlyfun.caterpillar.TextCmd"; } ..... }
getComponentType()取得的是"javax.faces.Input",它实际上对应至UIInput类,而
getRendererType()取回的是"onlyfun.caterpillar.TextCmd",这会在faces-config.xml中定
义,以对应至实际的Renderer类:
.... <faces-config> <render-kit> <renderer> <component-family> javax.faces.Input </component-family> <renderer-type> onlyfun.caterpillar.TextCmd </renderer-type> <renderer-class> onlyfun.caterpillar.TextCmdRenderer </renderer-class> </renderer> </render-kit> .... </faces-config>
为Component定义一个Renderer,必须由component family与renderer
type共同定义,这并不难理解,因为一个Component可以搭配不同的Renderer,但它是属于同一个component
family,例如UIInput就是属于javax.faces.Input这个组件家族,而我们为它定义一个新的Renderer。
接下未完成的范例可以取之前主题介绍过的,我们虽然没有自订组件,但我们为UIInput置换了一个新的Renderer,这个Renderer会在输入栏位上加入一个按钮。
如果您坚持使用之前自订的UITextWithCmd,则可以如下修改:
package onlyfun.caterpillar;
import javax.faces.component.UIInput;
public class UITextWithCmd extends UIInput { public UITextWithCmd() { setRendererType("onlyfun.caterpillar.TextCmd"); } }
我们只是单纯的继承UIInput,然后使用setRendererType()设定"onlyfun.caterpillar.TextCmd",但并没有为组件加入什么行为,看来什么事都没有作,但事实上这是因为继承了UIInput,它为我们处理了大多数的细节。
接下来同样的,设定自订Tag:
package onlyfun.caterpillar;
import javax.faces.application.Application; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.el.ValueBinding; import javax.faces.webapp.UIComponentTag;
public class TextWithCmdTag extends UIComponentTag { private String size; private String value; public String getComponentType() { return "onlyfun.caterpillar.TextWithCmd"; }
public String getRendererType() { return "onlyfun.caterpillar.TextCmd"; } ..... }
要使用自订的Component,记得要在faces-config.xml中再加入:
....
<component>
<component-type>
onlyfun.caterpillar.TextWithCmd
</component-type>
<component-class>
onlyfun.caterpillar.UITextWithCmd
</component-class>
</component>
...
|