JSF组件开发指南

JSF 组件模型

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



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



组件的功能通常围绕着两个动作:解码和编码数据。

解码(decoding) 是把进入的请求参数转换成组件的值的过程。

编码 (encode) 是把组件的当前值转换成对应的标记(也就是 HTML)的过程。



JSF 框架提供了两个选项用于编码和解码数据

使用直接实现 方式,组件自己实现解码和编码

使用委托实现 方式,组件委托渲染器进行编码和解码。

如果选择委托实现,可以把组件与不同的渲染器关联,会在页面上以不同的方式渲染组件;例如多选列表框和一列复选框。因此,JSF 组件由两部分构成:组件和渲染器。JSF 组件 类定义 UI 组件的状态和行为;渲染器 定义如何从请求读取组件、如何显示组件 —— 通常通过 HTML 渲染。渲染器把组件的值转换成适当的标记。事件排队和性能验证发生在组件内部。

在图 1 中可以看到数据编码和解码出现在 JSF 生命周期中的什么阶段




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



所有 JSF 组件的基类是 UIComponent。在开发自己的组件时,需要继承 UIComponentBase,它扩展了 UIComponent 并提供了 UIComponent 中所有抽象方法认实现。组件拥有双亲和标识符。每个组件都关联着一个组件类型,组件类型用于在 face 的上下文配置文件(faces-config.xml)中登记组件。可以用 JSF-EL (表达式语言)把 JSF 组件绑定到受管理的 bean 属性。可以把表达式关联到组件上的任何属性,这样就允许用 JSF-EL 设置组件的属性值。在创建使用 JSF-EL 绑定的组件属性时,需要创建值绑定表达式。在调用绑定属性的 getter 方法时,除非 setter 方法已经设置了值,否则 getter 方法必须用值绑定获得值。组件可以作为 ValueHolder 或 EditableValueHolder。ValueHolder 与一个或多个 Validator 和 Converter 相关联;所以 JSF UI 组件也与 Validator 和 Converter 关联



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

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





提示

在许多情况下,可以在保持组件本身不变的情况下,通过改变渲染而简化开发过

程。在这些情况下,可以编写定制渲染器而不是定制组件。



JSF 组件的LoginComponent



我们用一个又好又容易的示例来开始 JSF 组件的开发:

下面是我要采取的步骤:



1. 扩展 UIComponent

创建一个类,扩展 UIComponent

保存组件状态

用 faces-config.xml 登记组件

2. 创建定制标记,继承 UIComponentTag

覆盖 encode

覆盖 decode

用 faces-config.xml 登记渲染器

3. 定义渲染器或者内联地实现它

返回渲染器类型

返回组件类型

设置可能使用 JSF 表达式的属性





详细结构:由component 、model 、renderer 、taglib 、utils(可选) 组成。




Step 1 扩展Components

具体代码请参考Sample,这里只叙述一些重要的方法

一个类是LoginComponent.java LoginComponent是整个组件开发的核心类。

它必须继承一个UIComponent,这里它继承的是UIInput

每个组件都关联着一个组件类型,组件类型用于在 face 的上下文配置文件(faces-config.xml)中登记组件






<component>

<component-type>sonic.Loginr</component-type>

<component-class>mycomponents.component.LoginComponent</component-class>

</component>



JSF提供了数值绑定机制,使得在Faces标记中访问bean property 很容易,其原理是用 JSF-EL (表达式语言)把 JSF 组件绑定到受管理的 bean 属性。可以把表达式关联到组件上的任何属性

这样就允许用 JSF-EL 设置组件的属性值,比如:

<h:inputText id=”user” value=”#{ userBean .username}” />

Valuebinding 在解析userBean.username这个keypath的时候,会使用反射(reflection)访问UserBean中的username property、如果没有就为null.。





在创建使用 JSF-EL 绑定的组件属性时,需要创建值绑定表达式。在调用绑定属性的 getter 方法时,除非 setter 方法已经设置了值,否则 getter 方法必须用值绑定获得值。




//get The UserName value

public String getUserText() ...{

if(this.userText!=null)

return this.userText;

else...{

ValueBinding vb = this.getValueBinding("userText");

if(vb==null)

return "";

else

return (String)vb.getValue(getFacesContext());

}

}





//Get the Password value

public String getPswText() ...{

if(this.pswText!=null)

return this.pswText;

else...{

ValueBinding vb = this.getValueBinding("pswText");

if(vb == null)

return "";

else

return (String)vb.getValue(getFacesContext());

}

}




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



它的主要作用就是保存和恢复组件的状态。由saveStore(),restoreState() 两个方法来执行。

getFamily()方法主要是返回在faces-config.xml中定义了相关联的渲染器






<render-kit>

<renderer>

<component-family>sonic.Loginr</component-family>

<renderer-type>sonic.Loginr</renderer-type>

<renderer-class>mycomponents.renderer.LoginRenderer</renderer-class>

</renderer>

</render-kit>



UIComponent 类的一个职责是为其绑定的model property 提供UI表示(UIComponent&Render其实对应MVC中的View)。 UIComponent定义有value property,用了缓冲在请求相应中inbound(接受请求值),outbound(处理后的请求值)这个property 还在

Apply Request Values 阶段暂时保存了对提交的值转换之后的结果,最终,组件value字段的内容会在

Update Model Value 阶段 被转换到对应的bean property .



由于,我的组件是一个复合组件,有2个textBox , 他不能在updateModel()这个方法自动绑定与bean相关联的属性,所以在这个里面就要重载updateModel(),手动绑定属性到bean中。


public void updateModel(FacesContext context) ...{

// Todo Auto-generated method stub

ValueBinding vb = this.getValueBinding("userText");

if (vb != null)...{

vb.setValue(context,this.getUsername());

this.setUsername(null);

}


ValueBinding vb2 = this.getValueBinding("pswText");

if (vb2 != null)...{

vb2.setValue(context,this.getpassword());

this.setPassword(null);

}

super.updateModel(context);

}








Step 2 创建一个LoginTag为 LoginComponent创建定制标记


l LoginTag 必须 extends UIComponentTag

l 在web.xml中的 <jsp-config></jsp-config>中添加标记定位


<jsp-config>

<taglib>

<taglib-uri>http://www.ygsoft.com</taglib-uri>

<taglib-location>/WEB-INF/login.tld</taglib-location>

</taglib>

</jsp-config>






l 添加login.tld


setproperty()这个方法允许这个代码允许 LoginComponent的 value 属性绑定到后台 bean


protected void setProperties(UIComponent component) ...{

/**//* have to call the super class */

super.setProperties(component);

Computils.setAttribute(component,"userLabel",userLabel);

Computils.setAttribute(component,"pswLabel",pswLabel);

Computils.setAttribute(component,"userText",userText);

Computils.setAttribute(component,"pswText",pswText);

Computils.setAttribute(component,"loginSuccess",loginSuccess);

Computils.setAttribute(component,"loginFailure",loginFailure);

Computils.setAttribute(component,"errorStyleClass",errorStyleClass);

((LoginComponent)component).setrequired(true);

}



public final static void setAttribute(UIComponent component,

String attrName,String value) ...{

if (value != null) ...{

if (Util.isVBExpression(value)) ...{

ValueBinding vb = Util.getValueBinding(value);

component.setValueBinding(attrName,vb);

} else ...{

component.getAttributes().put(attrName,value);

}

}

}




errorStyleClass属性不是setValueBinding的,它们被添加到 JSF 组件的属性映射 中。Renderer类会使用属性映射去渲染类和样式属性。这个设置允许特定于 HTML 的代码从组件脱离所以是用getAttributes().put(attrName,value);来设定的



最后是把渲染器映射到组件


public String getComponentType() {

return "sonic.Loginr";

}

<component>

<component-type>sonic.Loginr</component-type>

<component-class>mycomponents.component.LoginComponent</component-class>

</component>

============================================================================

public String getRendererType() {

return "sonic.Loginr";

}

<render-kit>

<renderer>

<component-family>sonic.Loginr</component-family>

<renderer-type>sonic.Loginr</renderer-type>

<renderer-class>mycomponents.renderer.LoginRenderer</renderer-class>

</renderer>

</render-kit>








Step 3 定义一个独立渲染器LoginRender


其实渲染器可以在UIComponent里面的,这里使用的是使用委托实现方式,组件委托渲染器进行编码和解码。

渲染器的作用其实主要是html的输出,其中的重点是encodeBegin, decode



LoginComponent组件是一个 UIInput 组件,这意味着它接受输入(UIoUtPut组件不用decode),所以 必须 进行解码。decode方法可以从会话、cookie、头、请求等处读取值。在大多数请问下,decode方法只是像上面那样从请求参数读取值。Decode 方法负责从请求取得输入,并解码成适合组件的数据



Encode 编码,编成HTML码,Rander类里面就是encodeBegin,encodeEnd这里就是写在encodeBeanin里面,其实对应自定义标签里面的doStartTag(),doEndTag();

encodeBegin()里面主要是用 ResponseWriter

响应写入器(javax.faces.context.ResponseWriter)可以容易地处理 HTML 这样的标记语言






ResponseWriter writer = context.getResponseWriter();

比如:

writer.startElement("table",component);

writer.writeAttribute("width","60%",null);

writer.writeAttribute("align","center",null);

writer.writeAttribute("border","0",null);

writer.writeAttribute("cellpadding",null);

writer.endElement("table");



生成HTML代码就是


<table width=”60%” align=”center” border=”0” cellspacing=”1”></table>

http://zenggongli.javaeye.com/blog/162762

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强制返回为文本 -------------------------------- 数字类型的格式化 --------------------------------     固定格式参数:     General Number 普通数字,如可以用来去掉千位分隔号     format$("100,1
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办法, Format 或者FormatDateTime 竟然结果和系统设置的区域语言的日期和时间格式相关。意思是尽管你用诸如 Format(Now, "MM/dd/yyyy"),如果系统的设置格式区域语言的日期和时间格式分隔符是"-",那他还会显示为 MM-dd-yyyy     只有拼凑: <%response.write
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace My ‘全局错误处理,新的解决方案直接添加本ApplicationEvents.vb 到工程即可 ‘添加后还需要一个From用来显示错误。如果到这步还不会则需要先打好基础啦 ‘======================================================== ‘以下事件
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用的爽呀,这篇文章写与2011年,看来我以前没有认真去找这个方法呀。 https://blog.csdn.net/chzjxgd/article/details/6176325 金蝶K3 BOS的插件官方是用VB6编写的,如果  能用.Net下的语言工具开发BOS插件是一件很愉快的事情,其中缘由不言而喻,而本文则是个人首创,实现在了用V
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选中的单元格进行处理 Dim m As Range, tmpStr As String, s As String Dim x As Integer, y As Integer, subStr As String If MsgBox("确定要分列处理吗?请确定分列的数据会覆盖它后面的单元格!", _
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single) 2 Dim path As String, hash As String 3 For Each fil
  Imports MySql.Data.MySqlClient Public Class Form1 ‘ GLOBAL DECLARATIONS Dim conString As String = "Server=localhost;Database=net2;Uid=root;Pwd=123456;" Dim con As New MySqlConnection
‘導入命名空間 Imports ADODB Imports Microsoft.Office.Interop   Private Sub A1() Dim Sql As String Dim Cnn As New ADODB.Connection Dim Rs As New ADODB.Recordset Dim S As String   S = "Provider=OraOLEDB.Oracl
Imports System.IO Imports System.Threading Imports System.Diagnostics Public Class Form1 Dim A(254) As String    Function ping(ByVal IP As Integer) As String Dim IPAddress As String IPAddress = "10.0.
VB运行EXE程序,并等待其运行结束 参考:https://blog.csdn.net/useway/article/details/5494084 Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Pr
今天碰到一个问题,登陆的时候,如果不需要验证手机号为空,则不去验证手机号 因为登陆的时候所有的验证信息都存放在一个数组里 Dim CheckUserInfo() As String ={UserBirthday, SecEmail, UserMob, UserSex, RealNameFirst, RealName, CheckCardID, CheckCardType, Contactemail
在VB6.0中,数据访问接口有三种: 1、ActiveX数据对象(ADO) 2、远程数据对象(RDO) 3、数据访问对象(DAO) 1.使用ADO(ActiveX Data Objec,ActiveX数据对象)连接SQL Server 1)使用ADO控件连接 使用ADO控件的ConnectionString属性就可以连接SQL Server,该属性包含一个由分号分隔的argument=value语
注:大家如果没有VB6.0的安装文件,可自行百度一下下载,一般文件大小在200M左右的均为完整版的软件,可以使用。   特别提示:安装此软件的时候最好退出360杀毒软件(包括360安全卫士,电脑管家等,如果电脑上有这些软件的话),因为现如今的360杀毒软件直接会对VB6.0软件误报,这样的话就可能会在安装过程中被误报阻止而导致安装失败,或者是安装后缺乏很多必须的组件(其它的杀毒软件或安全卫士之类的
Private Sub Form_Load() Call conndb End Sub Private Function conndb() Dim cn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim strCn, sql As String Dim db_host As String Dim db_user As String
  PPSM06S70:  Add  moddate  EDITSPRINTJOB:  MAX(TO_CHAR(ETRN.MODDATE, ‘yyyy/mm/dd/HH24:MI AM‘)) ACTUAL_SHIPDATE   4.Test Scenario (1) :Query SQL Test DN:8016578337 SELECT CTRN.TKCTID TRUCK_ID,        
  沒有出現CrystalReportViewer時,須安裝CRforVS_13_0. 新增1個數據集,新增1個數據表,添加二列,列名要和資料庫名一樣. 修改目標Framework 修改app.config, <startup >改成<startup useLegacyV2RuntimeActivationPolicy ="true">  CrystalReport1.rpt增加數據庫專家 在表單
Imports System.Threading Imports System Public Class Form1 Dim th1, th2 As Thread Public Sub Method1() Dim i As Integer For i = 1 To 100 If Me.Label1.BackColor =
Friend Const PROCESS_ALL_ACCESS = &H1F0FFF = 2035711 Friend Const PROCESS_VM_READ = &H10 Friend Const PROCESS_VM_WRITE = &H20 Friend Const PAGE_READONLY = &H2 Friend Const PAGE_READWRITE = &H4 Friend
以下代码随手写的 并没有大量测试 效率也有待提升 如果需要C#的请自行转换 Function SplitBytes(Data As Byte(), Delimiter As Byte()) As List(Of Byte()) Dim i = 0 Dim List As New List(Of Byte()) Dim bytes As New
Imports System.Data.SqlClient Public Class Form1 REM Public conn1 As SqlConnection = New SqlConnection("server=.; Integrated Security=False;Initial Catalog= mydatabase1; User ID= sa;password")