JSF里自定义Renderer

Component可以将译码、编码的动作交给Renderer,这让您的表现层技术可以轻易的抽换,我们可以将之前的自定义组件的译码、编码动作移出至 Renderer,不过由于我们之前设计的Component是个很简单的组件,事实上,如果只是要新增一个Command在输入字段旁边,我们并不需要大费周章的自定义一个新的组件,我们可以直接为输入字段更换一个自定义的Renderer。
要自定义一个Renderer,您要继承javax.faces.render.Renderer,我们的自定义Renderer如下:

TextCmdRenderer.java
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()方法上要修改一下:

TextWithCmdTag.java
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.xml
....
<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,则可以如下修改:

UITextWithCmd.java
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:

TextWithCmdTag.java
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>
...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值