完成Component的自訂,接下來要設定一個自訂Tag與之對應,自訂Tag的目的,在於設定 Component屬性,取得Componenty型態,取得Renderer型態值等;屬性的設定包括了設定靜態值、設定綁定值、設定驗證器等等。
要自訂與Component對應的Tag,您可以繼承UIComponentTag,例如:
- 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 null;
}
public void setProperties(UIComponent component) {
super.setProperties(component);
setStringProperty(component, "size", size);
setStringProperty(component, "value", value);
}
private void setStringProperty(UIComponent component,
String attrName, String attrValue) {
if(attrValue == null)
return;
if(isValueReference(attrValue)) {
FacesContext context =
FacesContext.getCurrentInstance();
Application application =
context.getApplication();
ValueBinding binding =
application.createValueBinding(attrValue);
component.setValueBinding(attrName, binding);
}
else {
component.getAttributes().
put(attrName, attrValue);
}
}
public void release() {
super.release();
size = null;
value = null;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
首先看到這兩個方法:
public String getComponentType() {
return "onlyfun.caterpillar.TextWithCmd";
}
public String getRendererType() {
return null;
}
return "onlyfun.caterpillar.TextWithCmd";
}
public String getRendererType() {
return null;
}
由於我們的Component目前不使用Renderer,所以getRendererType()傳回null值,而 getComponentType()在於讓JSF取得這個Tag所對應的Component,所傳回的值在faces-config.xml中要有定 義,例如:
....
<component>
<component-type>
onlyfun.caterpillar.TextWithCmd
</component-type>
<component-class>
onlyfun.caterpillar.UITextWithCmd
</component-class>
</component>
....
<component>
<component-type>
onlyfun.caterpillar.TextWithCmd
</component-type>
<component-class>
onlyfun.caterpillar.UITextWithCmd
</component-class>
</component>
....
藉由faces-config.xml中的定義,JSF可以得知 onlyfun.caterpillar.TextWithCmd的真正類別,而這樣的定義方式很顯然的,您可以隨時換掉<component- class>所對應的類別,也就是說,Tag所對應的Component是可以隨時替換的。
在設定Component屬性值時,可以由component.getAttributes()取得Map物件,並將標籤屬性值存入Map 中,這個Map物件可以在對應的Component中使用getAttributes()取得,例如在上一個主題中的UITextWithCmd中可以如 下取得存入Map的size屬性:
package onlyfun.caterpillar;
import java.io.IOException;
import java.util.Map;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
public class UITextWithCmd extends UIInput {
....
private void encodeTextField(ResponseWriter writer,
String clientId) throws IOException {
....
String size = (String) getAttributes().get("size");
if(size != null) {
writer.writeAttribute("size", size, null);
}
.....
}
....
}
import java.io.IOException;
import java.util.Map;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
public class UITextWithCmd extends UIInput {
....
private void encodeTextField(ResponseWriter writer,
String clientId) throws IOException {
....
String size = (String) getAttributes().get("size");
if(size != null) {
writer.writeAttribute("size", size, null);
}
.....
}
....
}
可以使用isValueReference()來測試是否為JSF Expression Language的綁定語法,如果是的話,則我們必須建立ValueBinding物件,並設定值綁定:
....
private void setStringProperty(UIComponent component,
String attrName, String attrValue) {
if(attrValue == null)
return;
if(isValueReference(attrValue)) {
FacesContext context =
FacesContext.getCurrentInstance();
Application application =
context.getApplication();
ValueBinding binding =
application.createValueBinding(attrValue);
component.setValueBinding(attrName, binding);
}
else {
component.getAttributes().
put(attrName, attrValue);
}
}
....
private void setStringProperty(UIComponent component,
String attrName, String attrValue) {
if(attrValue == null)
return;
if(isValueReference(attrValue)) {
FacesContext context =
FacesContext.getCurrentInstance();
Application application =
context.getApplication();
ValueBinding binding =
application.createValueBinding(attrValue);
component.setValueBinding(attrName, binding);
}
else {
component.getAttributes().
put(attrName, attrValue);
}
}
....
如果是value屬性,記得在上一個主題中我們提過,從UIOutput繼承下來的getValue()方法可以取得 Component的value設定值,這個值可能是靜態的屬性設定值,也可能是JSF Expression的綁定值,預設會先從元件的屬性設定值開始找尋,如果找不到,再從綁定值(ValueBinding物件)中找尋。
最後,我們必須提供自訂Tag的tld檔:
- textcmd.tld
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>textcmd</short-name>
<uri>https://openhome.cc/textcmd</uri>
<tag>
<name>textcmd</name>
<tag-class>onlyfun.caterpillar.TextWithCmdTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>size</name>
</attribute>
<attribute>
<name>value</name>
<required>true</required>
</attribute>
</tag>
</taglib>