|
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>
...
|