今天谈谈自定义JSF的component,renderer,用到官方例子Image Map Example,这个可以在Oracle官方网站下载。
这个步骤是(来自官方网站):
创建一个自定义的component class, 所有的component必须要继承UIComponentBase,但是如果我们只需要一个特定的功能,没有必要直接继承UIComponentBase,我们可以继承比如UICommand,所有的都在javax.faces.component里面,UI开头的。
@FacesComponent("DemoMap")
public class MapComponent extends UICommand {...}
@FacesComponent("DemoArea")
public class AreaComponent extends UIOutput {...}
上面这两行代码就是说创建一个自定义的按钮component 和Output的component,FaceComponent的意思就是告诉JSF,我现在报名了,我有个新的component叫做DemoMap和DemoArea。
DemoMap有一个或者多个DemoArea当作子component,所以这个时候这个父DemoMap要做的就是:
1. 接收子component 当前被选中的值
2. 用这些值赋给对应的父component的properties
3. 当用户点击map的时候生成一个event
4. 保存这个event的状态
5.渲染html,比如html 的html的map tag,input tag 。 MapComponent会把渲染交给Render去做
现在谈谈AreaComponent, 这个是和一个bean绑定的,这个component可以从bean里面得到形状的值,把这个值放在hidden的id里面,Rendering the area
tag, including the JavaScript for the onmouseover
, onmouseout
, and onclick
functions。,需要delegate给render去做render的task。
Delegate给render,component class需要重写 这个方法
public String getFamily() {
return ("Map");
}
然后再render的class里就可以这样写
@FacesRenderer(componentFamily = "Map", rendererType = "DemoMap")
public class MapRenderer extends Renderer {}
下面谈一下怎么写render,这个比较复杂一点。
@Override
public void encodeBegin(FacesContext context, UIComponent component)
throws IOException {
if ((context == null)|| (component == null)) {
throw new NullPointerException();
}
MapComponent map = (MapComponent) component;
ResponseWriter writer = context.getResponseWriter();
writer.startElement("map", map);
writer.writeAttribute("name", map.getId(), "id");
}
@Override
public void encodeEnd(FacesContext context, UIComponent component)
throws IOException {
if ((context == null) || (component == null)){
throw new NullPointerException();
}
MapComponent map = (MapComponent) component;
ResponseWriter writer = context.getResponseWriter();
writer.startElement("input", map);
writer.writeAttribute("type", "hidden", null);
writer.writeAttribute("name", getName(context,map), "clientId");
writer.endElement("input");
writer.endElement("map");
}
上面这部分代码就是要渲染
<map name="bookMap">
<input type="hidden" name="bookMap_current">
</map>
最后就是要decode,把那个隐藏html的值拿到后传回给map的component的attribute “current”注意
@Override
public void decode(FacesContext context, UIComponent component) {
if ((context == null) || (component == null)) {
throw new NullPointerException();
}
MapComponent map = (MapComponent) component;
String key = getName(context, map);
String value = (String) context.getExternalContext().
getRequestParameterMap().get(key);
if (value != null)
map.setCurrent(value);
}
}
注意这一句
If the component has child components, you might need to use more than one of these methods to render the component; otherwise, all rendering should be done in encodeEnd
. Alternatively, you can use the encodeALL
method, which encompasses all the methods.
所以,因为AreaRender没有子render,只需要一个encodeEnd就好了
@Override
public void encodeEnd(FacesContext context, UIComponent component)
throws IOException {
if ((context == null) || (component == null)) {
throw new NullPointerException();
}
AreaComponent area = (AreaComponent) component;
String targetImageId = area.findComponent(
area.getTargetImage()).getClientId(context);
ImageArea iarea = (ImageArea) area.getValue();
ResponseWriter writer = context.getResponseWriter();
StringBuilder sb;
writer.startElement("area", area);
writer.writeAttribute("alt", iarea.getAlt(), "alt");
writer.writeAttribute("coords", iarea.getCoords(), "coords");
writer.writeAttribute("shape", iarea.getShape(), "shape");
sb = new StringBuilder("document.forms[0]['").append(targetImageId).
append("'].src='");
sb.append(
getURI(context,
(String) area.getAttributes().get("onmouseout")));
sb.append("'");
writer.writeAttribute("onmouseout", sb.toString(), "onmouseout");
sb = new StringBuilder("document.forms[0]['").append(targetImageId).
append("'].src='");
sb.append(
getURI(context,
(String) area.getAttributes().get("onmouseover")));
sb.append("'");
writer.writeAttribute("onmouseover", sb.toString(), "onmouseover");
sb = new StringBuilder("document.forms[0]['");
sb.append(getName(context, area));
sb.append("'].value='");
sb.append(iarea.getAlt());
sb.append("'; document.forms[0].submit()");
writer.writeAttribute("onclick", sb.toString(), "value");
writer.endElement("area");
}