JSF2自定义组件编程系列 第三部分

本节将实现一个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。

 

你可能感兴趣的:(jsf2)