本节将实现一个HtmlInput tag,仍然是Noncomposite Component。接受用户的输入,点击按钮后,会显示用户输入的信息。有朋友要看效果图,我也想show一下,可是图片上传失败。在这个系列文章结束的时候,我会上传我的代码。
基本流程是,用户在初始页面上输入数据,点击按钮后,一般采用PostBack的方法将数据传递到JSF的 Serverlet,在后台的Renderer的decode方法内部通过 FacesContext.getExternalContext().getRequestParameterMap()获取Map对象,然后通过 key去查找用户的输入数据。key是什么?这里采用clientIdValue:InputField的格式。
需要解释一下ClientId,JSF定义了一个规则,为了知道是哪一个Tag,程序员可以通过下面的方法在页面初始化的时候输出ClientId到客户端:(实际上一般都是赋给了HTML tag的 name属性)
writer.writeAttribute("name", clientIdValue, "clientId");//第三个参数必须是"clientId",是JSF内部使用的。
然后当客户端提交数据后,UIComponent可以通过调用成员函数getClientId(context)获得这个clientIdValue。在我这个例子里面,我在页面初始化的时候将从调用component.getClientId()或得clientIdValue并输出到客户端,用来标志我的HtmlInput tag,然后在下次客户提交的时候拿回来。但是由于我的HtmlInput tag内部有三个子tag,一个输入,一个按钮,一个输出,对于前两个,也需要ClientId标志它们,我使用了父ClientIdValue+区分字符+子tag名称的做法。默认区分字符是:。因此,当获取到HtmlInput tag的ClientId后,拼接出输入子tag的ClientId:"ClientIdValue:InputField",将其作为key从map中检索用户填入的数据。所以ClientId对于检索输入数据非常重要,要想能检索到,你必须按照JSF的规则先在初始化的时候给需要的tag设置ClientId,以后才能拿回来作为key从Map中使用。
区分字符是可以修改的,通过在web.xml文件中配置 context-param下的javax.faces.SEPARATOR_CHAR.这个以后用到CSS的时候再说。
现在秀一下代码,Renderer的代码:
package com.freebird.renderer;
import com.freebird.component.HtmlInput;
import javax.faces.render.Renderer;
import javax.faces.context.ResponseWriter;
import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.component.UINamingContainer;
import java.util.Map;
/**
* Describe class HtmlInputRenderer here.
*
*
* Created: Wed Dec 29 12:14:24 2010
*
* @author <a href="mailto:chenshu@csdesktop">chenshu</a>
* @version 1.0
/
public class HtmlInputRenderer extends Renderer {
public void decode(FacesContext context, UIComponent component) {
Map requestMap = context.getExternalContext().getRequestParameterMap();
String clientId = component.getClientId(context);
char sep = UINamingContainer.getSeparatorChar(context);
String symbol = ((String) requestMap.get(clientId + sep + "inputfield"));
HtmlInput myComponent = (HtmlInput)component;
myComponent.setSubmittedValue(symbol);
}
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
String clientId = component.getClientId(context);
char sep = UINamingContainer.getSeparatorChar(context);
encodeInputField(context, clientId + sep + "inputfield",component);
encodeSubmitButton(context, clientId + sep + "submit",component);
encodeOutputField(context,component);
}
private void encodeInputField(FacesContext context, String clientId, UIComponent component) throws IOException {
// Render a standard HTML input field
ResponseWriter writer = context.getResponseWriter();
writer.startElement("input", component);
writer.writeAttribute("type", "text", null);
writer.writeAttribute("name", clientId, "clientId");
HtmlInput myComponent = (HtmlInput)component;
String value = (String)myComponent.getSubmittedValue();
if (value != null) {
writer.writeAttribute("value", value, "value");
}
writer.writeAttribute("size", "6", null);
writer.endElement("input");
}
private void encodeSubmitButton(FacesContext context, String clientId , UIComponent component) throws IOException {
// render a submit button
ResponseWriter writer = context.getResponseWriter();
writer.startElement("input", component);
writer.writeAttribute("type", "Submit", null);
writer.writeAttribute("name", clientId, "clientId");
writer.writeAttribute("value", "Click Me!", null);
writer.endElement("input");
}
private void encodeOutputField(FacesContext context,UIComponent component) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String hellomsg = (String) component.getAttributes().get("value");
writer.startElement("p", component);
writer.writeText("You entered: " + hellomsg, null);
writer.endElement("p");
}
}
UIComponent的代码,HtmlInput类仅仅继承了UIInput类,所以自然拥有了getFamily,get/setSubmittedValue方法的实现。
package com.freebird.component;
import javax.faces.component.UIInput;
/*
* Describe class HtmlInput here.
*
*
* Created: Wed Dec 29 11:43:18 2010
*
* @author <a href="mailto:chenshu@csdesktop">chenshu</a>
* @version 1.0
/
public class HtmlInput extends UIInput {
}
现在看一下两个配置文件:
faces-config.xml中添加
<component>
<component-type>HtmlInput</component-type>
<component-class>com.freebird.component.HtmlInput</component-class>
</component>
<render-kit>
<renderer>
<component-family>javax.faces.Input</component-family>
<renderer-type>HtmlInputRenderer</renderer-type>
<renderer-class>com.freebird.renderer.HtmlInputRenderer</renderer-class>
</renderer>
</render-kit>
helloworld.taglib.xml中添加
<tag>
<tag-name>htmlinput</tag-name>
<component>
<component-type>HtmlInput</component-type>
<renderer-type>HtmlInputRenderer</renderer-type>
</component>
</tag>
在web应用程序中使用该tag很简单,仅仅是一行:
<cs:htmlinput/>
下一部分将转入开发Composite Component。