JSF2.0引入的一个特性就是客户化的组合用户界面组件,通常叫做复合组件。用户界面组件是为了特定功能创建的可以重用的用户界面,包括预先定义的一组验证器、转换器和监听器。复合组件在视图中可以向单独的组件同样的使用。在JSF1.x中,创建客户化的用户界面组件是一项比较复杂的工作,要求开发人员编写Java代码和XML配置文件。JSF2.0引入了复合组件的观念,目的是使得开发人员能够创建简单的、可重用的JSF用户界面组件而不需要编写Java代码或XML配置文件。复合组件JSF2.0通过两个特写简化了创建复合组件的过程Facelets和Resources。一个复合组件就是一个在资源库中的Facelets。为了更好的理解,让我们回顾一下在JSF1.x中是怎样创建复合组件的:1.创建扩展了UIInput或UIOutput的组件类,或创建UIComponent的子类。具体使用哪一个要看哪一个更复合要求。2.创建一个Renderer类来创建合适的标记。3.在faces-config.xml文件中注册该组件。4.创建一个JSP的tag实现来在JSP中使用该组件5.创建一个标签库描述文件(.tld)来使用该JSP。现在让我们来看看在JSF2.0中是怎样创建复合组件的:1.创建resource库2.在资源库中创建一个Facelets标记文件3.在facelets页面中使用复合组件 使用以下的命名空间: http://java.sun.com/jsf/composite/resLib,这里resLib是资源库的名字在Facelets页面中以pre:comp的格式引用该复合组件。这里pre是命名空间的前缀,comp是资源库中Facelets文件的名字。资源在web的术语中,资源就是包含或能够展示给用户的信息的任何东西。和通常的web页面不同的是,资源可以是图片、样式表甚至是JavaScript文件。JSF2.0提供了新的特性来处理资源,该特性极大的简化了开发人员创建用户组件的过程。新的资源特性是通过打包机制来得到的。资源通常被打包放置在web应用程序的根目录下或classpath下。在不同的地方查找资源的默认的实现方式是:1.在web应用程序的根目录中查找资源resources/<resourceIdentifier>在根目录下应该有一个名为resources的文件夹,该文件夹中包含了所有的资源。2.在classpath中META-INF/resources/<resourceIdentifier>被打包的resource必须被放在Jar文件的META-INF文件夹中的resources目录下。在上面的例子中,<resourceIdentifiere>的格式是[localePrefix/] [libraryName/][libraryVersion/] resourceName [/resourceVersion]其中方括号[]内的内容是可选的,如:1.loginHand.gif – 只有resourceName2.login/loginHand.gif – libraryName/resourceName 3.login/1_2/loginHand.gif – libraryName/libraryVersion/resourceName 在JSF2.0中创建复合组件下面让我们使用一个简单的例子来演示如何在JSF2.0中创建复合组件。假设我们有一个web应用程序,该程序会问用户5个问题来测试用户的基本知识。在5个问题问完后,会显示用户的得分。用户必须先注册才能够使用该应用程序。下面就是注册页面必须要拥有的特点:1.输入的email必须符合标准的格式2.输入的password和Confirm password必须一样3.输入的日期必须是mm/dd/yy格式4.当用户点击注册按钮的时候,业务方法会被调用来完成注册的过程。大家可以看到,这些要求都是很普通的,基本上很多注册页面都有同样的要求。这样我们就可以创建一个复合组件来完成这些要求,并且这个复合组件可以被重用。首先,我们需要创建一个叫做regForm的资源库。在这个资源库中,我们创建一个Facelets文件叫做register.xhtml,这个文件会包含必要的代码。我们会把这文件放在resources/regForm/register.xhml。该文件代码如下: <!-- XHTML DOCTYPE Declaration --><html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:composite="http://java.sun.com/jsf/composite"> <!—Interface that defines the user contract of the component--> <composite:interface>... </composite:interface> <!-- Implementation that specifies the actual markup--> <composite:implementation>... </composite:implementation></html></p> 复制代码 用来定义一个复合组件的标签在http://java.sun.com/jsf/composite 中被定义。每个复合组件都必须提供一个可用的合约,这样使用者才知道该组件提供了什么。这个合约在<interface>标签中指定, 而实际实现组件功能的标记在<implementation>中指定。下面我们来看看怎样定义合约: <!-- Interface that defines the user contract of the component --> <composite:interface> <composite:attribute name="regButtonText" required="true"/> <composite:attribute name="regPrompt" default="Please fill registration details" /> <composite:attribute name="emailPrompt" default="Email" /> <composite:attribute name="userNamePrompt" default="Username"/> <composite:attribute name="passwordPrompt" default="Password"/> <composite:attribute name="confirmPasswordPrompt" default="Confirm Password"/> <composite:attribute name="dobPrompt" default="Date of Birth in mm/dd/yy format"/> <composite:attribute name="regAction" method-signature="java.lang.String register()" required="true"/> <composite:attribute name="managedBean" required="true"/></composite:interface> 复制代码 这个组件的约定允许使用者为输入框提供客户化的标记,该标记的值可以通过预先定义好的属性传入,该属性通过<attribute>标签来声明。例如在上面的例子中,我们定义了一个名叫regButtonText的属性,该属性是将会作为register按钮的标记。required=“true”表明使用者必须提供该属性的值。其他的属性如regPrompt、emailPrompt等是可选的,有缺省值。当用户点击register按钮时,一个被管理bean的方法会被调用。这个bean和方法通过名为managedBean和regAction的属性来指定。注意regAction方法的声明定义了要调用的方法签名。定义好了合约之后,下一步要做的事情就是实现这个复合组件。我们使用<implementation>标签来实现组件。在这个例子中,我们只需要实现一个包含不同的输入元素的表单来接受用户的邮件地址、用户名、密码和生日。要访问组件的属性,我们需要使用如下的语法:#{cc.attrs.attr_name}这里attr_name是属性的名称。下面我们来看看实现的代码: <composite:implementation> <h:form id="form" prependId="false"> <div class="prompt"> #{cc.attrs.regPrompt} </div> <h:panelGrid columns="2"> <h:outputText value="#{cc.attrs.emailPrompt}"/> <h:inputText id="email" value="#{cc.attrs.managedBean.email}" required="true"> <f:validateRegex pattern="[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+" /> </h:inputText> <h:outputText value="#{cc.attrs.userNamePrompt}"/> <h:inputText id="name" value="#{cc.attrs.managedBean.userName}" required="true"/> <h:outputText value="#{cc.attrs.passwordPrompt}"/> <h:inputSecret id="password" value="#{cc.attrs.managedBean.password}" required="true"/> <h:outputText value="#{cc.attrs.confirmPasswordPrompt}"/> <h:inputSecret id="confirmPassword" value="#{cc.attrs.managedBean.confirmPassword}" required="true"/> <h:outputText value="#{cc.attrs.dobPrompt}"/> <h:inputText id="dob" value="#{cc.attrs.managedBean.dob}" required="true"> <f:convertDateTime dateStyle="short"/> </h:inputText> </h:panelGrid> <p> <h:commandButton id="regButton" value="#{cc.attrs.regButtonText}" action="#{cc.attrs.regAction}" οnclick="return checkPwd(this.form)"/> </p> </h:form> <script type="text/javascript"> <!—Javascript code to validate that values in password and confirmPasssword field are same --> </script> <div> <h3>Please note that all fields are mandatory</h3> </div> <div class="error" style="padding-top:10px;"> <h:messages layout="list" /> </div></composite:implementation> 复制代码 请注意在上面的代码中,我们使用了<f:validateRegex>标签来验证输入的email地址的值。这个标签是JSF2.0的标签,允许使用正则表达式来验证用户输入的值。同样的,用户输入的日期被<f:converDateTime>标签转换成日期对象。要验证输入的密码和验证密码是一样的,我们需要使用JavaScript来完成,具体的代码我们就不介绍了,这个超出了本文的范围。要注意的是组成复合组件的每个单独的组件的ID在运行时会被加上一个前缀,这个前缀就是复合组件的ID(复合组件的ID只有在运行时才能够确定)。因此password组件的实际的ID会是"#{cc.clientId}"+":"+"password",这里冒号':'是ID的分隔符。另外要注意的是表单的prepend属性被设置为了false,这个保证表单的ID(form)不会被加入到组件的ID中。到目前为止,register组件就被创建成功了,下面我们来看看在Facelets页面中怎样使用这个组件。假设我们的注册页面是registForm.xhtml,我们要在该页面中使用register组件,我们就需要为该组件的资源库声明命名空间。声明命名空间的方法如下:xmlns:prefix="http://java.sun.com/jsf/composite/reg_lib"这里prefix是我们声明的命名空间,reg_lib是包含组件的资源库的名称。在我们的例子中,我们使用如下的声明:xmlns:regForm="http://java.sun.com/jsf/composite/regForm"声明了命名空间之后,我们就可以使用复合组件了。使用复合组件的方法很简单,和使用普通的标签没有什么区别。<regForm:register regButtonText="Register" managedBean="#{regBean}" regAction="#{regBean.register}"/> 本主题由 afrag 于 2011-3-16 18:28 分类