编写JSF用户自定义UI组件(之四)

【续前。。。。。。】

八、步骤二:编写标签处理器类

UI组件类不同于普通Java类的地方是,它不是在Java代码中被引用,而是在JSP文件中。在JSP文件中,我们不能通过new操作符实例化UI组件类,只能通过JSP标签引用和实例化UI组件类。

前文介绍过如何引用一号组件,即在JSP文件中写入类似这样的标签即可:

<x:repeatText text="Hello world!" number="3">


当 JSP引擎读到这个标签时,它会把x:repeatText翻译为对某个类的调用,这个类就是所谓的标签处理器类tag handler。JSP引擎会将组件类的一个实例传递给标签处理器类,标签处理器类的功能是给这个组件类实例的各个属性赋值,值的来源就是标签中的 text="Hello world!" number="3"。

可见,JSP引擎和标签处理器类配合工作,可以实现类似于Java代码 中实例化一个类并给类的属性赋值的功能。我们在JSP文件中写下<x:repeatText text="Hello world!" number="3">,实际上就相当于实例化一号组件类并给其text和number分别赋值“Hello world!”和“3”。图 7示出了JSP标签和普通Java代码的类比。


 
图 7 JSP标签和普通Java代码的类比

 

也许你已经留意到图 7中标签名repeatText和组件类名StrRepeat之间的不同,它们是如何对应的,我们将在后文解释。

理解了标签处理器类的作用后,我们就很容易编写它的代码了。如同组件类StrRepeat可以继承UIComponentBase类一样,标签处理器类也可 以继承JSF框架提供的几个标签处理父类,以减少代码量。例如,一号组件的标签处理类可以继承UIComponentELTag类,如果我们将一号组件的 标签处理器类命名为StrRepeatTag,则其声明为:

public class StrRepeatTag extends UIComponentELTag{
    ...
}
 

标签处理器类的属性决定了我们允许用户在JSP文件中为自定义UI组件的哪些属性赋值。对于一号组件,我们允许用户在JSP标签中对一号组件的text和 number属性赋值,因此,StrRepeatTag类也必须有text和number这两个属性,用来接收用户在JSP标签中写入的值,然后转赋给一 号组件。这很容易,只需为StrRepeatTag类定义两个标准的JavaBeans属性即可,如程序清单 4所示。

程序清单 4 StrRepeatTag类的text和number属性

    private String text;
    public String getText() { return text; }
    public void setText(String text) { this.text = text; }

    private int number;
    public int getNumber() { return number; }
    public void setNumber(int number) { this.number = number; }
 

读者不难发现,这部分代码和一号组件类StrRepeat的(见程序清单 1)完全一样,甚至连属性名称都相同。当然,这不是强制要求,标签处理器类和相应的组件类的属性可以不同名,个数也可以不同,如果你无需允许用户在JSP标签中给组件类的所有属性赋值。

标签处理器类有几个方法,我们逐一说明:

1.    返回组件类型的方法getComponentType()(参见程序清单 5)

程序清单 5 标签处理器类StrRepeatTag的getComponentType()方法代码

    @Override
    public String getComponentType() {
        return "MyComponentType";
    }

 
这个方法返回一个称被为“组件类型”的字符串。组件类型决定了标签处理器类和组件类之间的对应关系,例如,当JSP引擎碰 到<x:repeatText.../>这样的标签时,之所以能够正确地判断出这是与StrRepeat组件类相对应的一个标签,正是由于“ 组件类型”字符串起着牵线搭桥的作用。具体的对应方法,后文有更详细的说明。

父类UIComponentELTag中的getComponentType()方法是抽象的,因此必须在子类中实现它。本例中,我们返回的组件类型为MyComponentType,如程序清单 5所示。

2.    返回呈现器类型的方法getRendererType()(参见程序清单 6)

程序清单 6标签处理器类StrRepeatTag的getRendererType()方法代码

    @Override
    public String getRendererType() {
        return null;
        //throw new UnsupportedOperationException("Not supported yet.");
    }
 

呈现器是一种专门负责向http响应输出组件内容的类。JSF允许组件类自己输出自己的内容,也允许它假手于人,即交给与之对应的呈现器类来输出。这个方法 返回的呈现器类型,正是用来供JSF框架选择合适的呈现器类的。由于一号组件是自己负责输出,不需要呈现器类,因此,我们让这个方法简单地返回一个 null,即告诉JSF框架,一号组件没有对应的呈现器类。

父类UIComponentELTag中的getRendererType()方法是抽象的,因此必须在子类中实现它。

3.    给组件类实例赋值的方法setProperties()

程序清单 7标签处理器类StrRepeatTag的setProperties()方法代码

    @Override
    protected void setProperties(UIComponent component) {
        super.setProperties(component);
        component.getAttributes().put("text", this.getText());
        component.getAttributes().put("number", this.getNumber());
    }
 

我们已在前面提到,用户可以通过JSP标签给组件类实例的属性赋值,setProperties()方法实现的正是这个功能。其入口参数component 是对应的组件类的实例,给实例赋值的方法有点特殊,不是直接调用相应属性的setter方法(如我们通常所做的那样),而是通过给一个Map中添加名值对 来实现的。这个Map的内容是由JSF的UI组件自己负责维护的,其中包含了一些名值对,“名”即为其各个属性的名称,“值”则是该属性的取值。调用组件 的getAttributes()方法可以获得这个Map,往其中put一个名值对,就相当于给一个指定名称的属性赋值。例如,代码 put("text", this.getText())给一号组件实例的text属性赋值,值是通过this.getText()方法获得的(这里的this代表标签处理器类的 实例本身),也就是用户在标签中输入的“Hello world!”。

父类UIComponentELTag中已经实现setProperties()方法,子类StrRepeatTag覆盖这个方法,因此必须在方法的最前面调用父类的实现,即super.setProperties(component)。

StrRepeatTag类的完整代码(省略了package和import语句)如所示。

程序清单 8 一号组件的标签处理器类StrRepeatTag的完整代码

public class StrRepeatTag extends UIComponentELTag{

    @Override
    public String getComponentType() {
        return "MyComponentType";
    }

    @Override
    public String getRendererType() {
        return null;
        //throw new UnsupportedOperationException("Not supported yet.");
    }
   
    @Override
    protected void setProperties(UIComponent component) {
        super.setProperties(component);
        component.getAttributes().put("text", this.getText());
        component.getAttributes().put("number", this.getNumber());
    }
   
    private String text;
    public String getText() { return text; }
    public void setText(String text) { this.text = text; }

    private int number;
    public int getNumber() { return number; }
    public void setNumber(int number) { this.number = number; }
}
 

在NetBeans中,为一号组件编写标签处理器类StrRepeatTag的步骤如下:

1.    创建一个Java类,命名为StrRepeatTag,放在customcomponent1包中,修改其声明,使继承UIComponentELTag类;
2.    创建text属性和number属性,以及它们的getter和setter方法;
3.    实现getComponentType()方法;
4.    实现getRendererType()方法;
5.    覆盖setProperties()方法。

图 8是NetBeans中的StrRepeatTag类代码。
 



 
图 8 NetBeans中一号组的标签处理器类StrRepeatTag的代码

 

【待续。。。。。。】

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值