JavaEE 8学习之Custom Component , Renderer

本文介绍了如何在JavaEE 8中创建自定义JSF组件和渲染器,以官方的Image Map Example为例。首先,创建自定义组件类,它们继承自UIComponentBase或其特定子类。接着,实现组件之间的交互,包括接收子组件值、处理事件、保存状态以及渲染HTML。然后,详细讨论了渲染器的实现,包括重写关键方法如encodeEnd,并展示了如何将渲染任务委托给Renderer类。最后,文章提到了decode过程,将隐藏HTML的值传递回组件属性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天谈谈自定义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 onmouseoveronmouseout, 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");
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值