Web的开发就是组件的开发 ,JSF的组件开发实例(上)

JSF 组件模型

JSF 组件模型与 AWT GUI 组件模型类似。它有事件和属性,就像 Swing 组件模型一样。它也有包含组件的容器,容器也是组件,也可以由其他容器包含。从理论上说,JSF 组件模型分离自 HTML 和 JSP。JSF 自带的标准组件集里面有 JSP 绑定,可以生成 HTML 渲染。

JSF 组件的示例包括日历输入组件和 HTML 富文本输入组件。您可能从来没时间去编写这样的组件,但是如果它们已经存在,那会如何呢?通过把常用功能变成商品,组件模型降低了向 Web 应用程序添加更多功能的门槛。

组件的功能通常围绕着两个动作:解码和编码数据。解码 是把进入的请求参数转换成组件的值的过程。编码 是把组件的当前值转换成对应的标记(也就是 HTML)的过程。

JSF 框架提供了两个选项用于编码和解码数据。使用直接实现 方式,组件自己实现解码和编码。使用委托实现 方式,组件委托渲染器进行编码和解码。如果选择委托实现,可以把组件与不同的渲染器关联,会在页面上以不同的方式渲染组件;例如多选列表框和一列复选框。

因此,JSF 组件由两部分构成:组件和渲染器。JSF 组件 类定义 UI 组件的状态和行为;渲染器 定义如何从请求读取组件、如何显示组件 —— 通常通过 HTML 渲染。渲染器把组件的值转换成适当的标记。事件排队和性能验证发生在组件内部。

在图 1 中可以看到数据编码和解码出现在 JSF 生命周期中的什么阶段(到现在,我希望您已经熟悉 JSF 生命周期了)。

图 1. JSF 生命周期和 JSF 组件
1

提示!

在许多情况下,可以在保持组件本身不变的情况下,通过改变渲染而简化开发过程。在这些情况下,可以编写定制渲染器而不是定制组件。

更多组件概念

所有 JSF 组件的基类是 UIComponent。在开发自己的组件时,需要继承 UIComponentBase,它扩展了 UIComponent 并提供了 UIComponent 中所有抽象方法的默认实现。

组件拥有双亲和标识符。每个组件都关联着一个组件类型,组件类型用于在 face 的上下文配置文件(faces-config.xml)中登记组件。可以用 JSF-EL (表达式语言)把 JSF 组件绑定到受管理的 bean 属性。可以把表达式关联到组件上的任何属性,这样就允许用 JSF-EL 设置组件的属性值。在创建使用 JSF-EL 绑定的组件属性时,需要创建值绑定表达式。在调用绑定属性的 getter 方法时,除非 setter 方法已经设置了值,否则 getter 方法必须用值绑定获得值。

组件可以作为 ValueHolderEditableValueHolderValueHolder 与一个或多个 ValidatorConverter 相关联;所以 JSF UI 组件也与 ValidatorConverter 关联(请参阅 参考资料 获得更多关于 JSF 验证和转换的内容。)

像表单字段组件这样的组件拥有一个 ValueBinding,它必须绑定到 JavaBean 的读写属性。组件可以调用 getParent 方法访问它们的双亲,也可以调用 getChildren 方法访问它们的子女。组件也可以有 facet 组件,facet 组件是当前组件的子组件,可以调用 getFacets 方法访问它,这个方法返回一个映射。Facets 是著名的子组件。

这里描述的许多组件的概念将会是接下来展示的示例的一部分,所以请记住它们!

 

JSF 样式的 Hello World!

我们用一个又好又容易的示例来开始 JSF 组件的开发:我将展示如何渲染 Label 标记(示例:<label>Form Test</label>)。

下面是我要采取的步骤:

  1. 扩展 UIComponent
    • 创建一个类,扩展 UIComponent
    • 保存组件状态
    • 用 faces-config.xml 登记组件
  2. 定义渲染器或者内联地实现它
    • 覆盖 encode
    • 覆盖 decode
    • 用 faces-config.xml 登记渲染器
  3. 创建定制标记,继承 UIComponentTag
    • 返回渲染器类型
    • 返回组件类型
    • 设置可能使用 JSF 表达式的属性

Label 示例将演示 JSF 组件开发的以下方面:

  • 创建组件
  • 直接实现渲染器
  • 编码输出
  • 把定制标记与组件关联

返回 图 1,可以看到在这个示例中会有两个生命周期属性在活动。它们是 Apply Request ValueRender Response

在图 2 中,可以看到在 JSP 中如何使用 Label 标记的(<label>Form Test</label>)。

图 2. 在 JSP 中使用 JSF 标记
2

第 1 步:扩展 UIComponent

第一步是创建一个组件,继承 UIOutput,后者是 UIComponent 的子类。 除了继承这个类之外,我还添加了组件将会显示的 label 属性,如清单 1 所示:

清单 1. 继承 UIComponent 并添加 label

import java.io.IOException;
import javax.faces.component.UIOutput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
public class LabelComponent extends UIOutput{
 private String label;
 public String getLabel() {
  return label;
 }
 public void setLabel(String label) {
  this.label = label;
 }
...

接下来要做的是保存组件状态。JSF 通常通过会话、隐藏表单字段、cookies 等进行实际的存储和状态管理。(这通常是用户配置的设置)。要保存组件状态,需要覆盖组件的 saveStaterestoreState 方法,如清单 2 所示:

清单 2. 保存组件状态

@Override
    public Object saveState(FacesContext context) {
        Object values[] = new Object[2];
        values[0] = super.saveState(context);
        values[1] = label;
        return ((Object) (values));
    }
    @Override
    public void restoreState(FacesContext context, Object state) {
        Object values[] = (Object[])state;
        super.restoreState(context, values[0]);
        label = (String)values[1];
    }

可以注意到,我使用的是 JDK 1.5。我对编译器进行了设置,所以我必须指定 override 注释,以便指明哪些方法要覆盖基类的方法。这样做可以更容易地标识出 JSF 的钩子在哪。

创建组件的最后一步是用 faces-config.xml 登记它,如下所示:

<faces-config>
   <component>
      <component-type>simple.Label</component-type>
      <component-class>
         arcmind.simple.LabelComponent
      </component-class>
   </component>
...

第 2 步:定义渲染器

下面要做的是内联地定义渲染器的功能。稍后我会介绍如何创建独立的渲染器。现在,先从编码 Label 组件的输出、显示 label 开始,如清单 3 所示:

清单 3. 编码组件的输出

public class LabelComponent extends UIOutput{
 ...
 public void encodeBegin(FacesContext context) 
     throws IOException {
  ResponseWriter writer = 
   context.getResponseWriter();
  writer.startElement("label", this);
                     writer.write(label);
                     writer.endElement("label");
                     writer.flush();
 }
 ...
}

注意,响应写入器(javax.faces.context.ResponseWriter)可以容易地处理 HTML 这样的标记语言。清单 3 的代码输出 <label> 元素体内的 label 的值。

下面显示的 family 属性用来把 Label 组件与渲染器关联。虽然目前 Label 组件还不需要这个属性(因为还没有独立的渲染器),但是在这篇文章后面,在介绍如何创建独立渲染器的时候,会需要它。

public class LabelComponent extends UIOutput{
 ...
 public String getFamily(){
  return "simple.Label";
 }
 ...
}

插曲:研究 JSF-RI

如果正在使用来自 Sun Microsystems 的 JSF 参考实现(不是 MyFaces 实现),那么就不得不在组件创建代码中添加下面一段:

public void encodeEnd(FacesContext context) 
   throws IOException {
 return;
}
public void decode(FacesContext context) {
 return;
}

Sun 的 JSF RI 期望,在组件没有渲染器的时候,渲染器会发送一个空指针异常。MyFaces 实现不要求处理这个需求,但是在代码中包含以上方法依然是个好主意,这样组件既可以在 MyFaces 环境中工作也可以在 JSF RI 环境中工作了。

MyFaces 更好!

如果正在使用 Sun JSF RI 或其他替代品,那么请帮自己一个忙,转到 MyFaces。虽然 MyFaces 不总是 更好的实现,但是目前它是。它的错误消息要比 Sun JSF RI 的好,而这个框架相比之下更严格。

第 3 步:创建定制标记

JSF 组件不是天生绑定到 JSP 上的。要连接起 JSP 世界和 JSF 世界,需要能够返回组件类型的定制标记(然后在 faces-context 文件中登记)和渲染器,如图 3 所示。

图 3. 连接 JSF 和 JSP
3

注意,由于没有独立的渲染器,所以可以给 getRendererType() 返回 null 值。还请注意,必须已经把 label 属性的值从定制标记设置到组件上,如下所示:

[LabelTag.java]
public class LabelTag extends UIComponentTag {
…
protected void setProperties(UIComponent component) {
 /* you have to call the super class */
 super.setProperties(component);
 ((LabelComponent)component).setLabel(label);
}

记住,Tag 设置从 JSP 到 Label 组件的绑定,如图 4 所示。

图 4. 绑定 JSF 和 JSP
4

现在要做的全部工作就是创建一个 TLD(标记库描述符)文件,以登记定制标记,如清单 4 所示:

清单 4. 登记定制标记

[arcmind.tld]
<taglib>
   <tlib-version>0.03</tlib-version>
   <jsp-version>1.2</jsp-version>
   <short-name>arcmind</short-name>
   <uri>http://arcmind.com/jsf/component/tags</uri>
   <description>ArcMind tags</description>
   
   <tag>
      <name>slabel</name>
      <tag-class>arcmind.simple.LabelTag</tag-class>
      <attribute> 
         <name>label</name> 
         <description>The value of the label</description>
      </attribute> 
   </tag>
...

一旦定义了 TLD 文件,就可以开始在 JSP 中使用标记了,如下面示例所示:

[test.jsp]
<%@ taglib prefix="arcmind" 
         uri="http://arcmind.com/jsf/component/tags" %>
            ...
 <arcmind:slabel label="Form Test"/>

现在就可以了 —— 开发一个简单的 JSP 组件不需要更多了。但是如果想创建稍微复杂一些的组件,针对更复杂的使用场景时该怎么办?请继续往下看(Web的开发就是组件的开发 ,JSF的组件开发实例(下))。

 

 

http://hi.baidu.com/rover828/blog/item/9ea6ab4ba48d5ef483025ce3.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,kaggle教程,方案分析,竞赛资料,竞赛方案参考,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值