Facelets介绍,第一部分

            
原文:http://www.jsfcentral.com/articles/facelets_1.html
近来用到Facelets,看到一篇很好的文章,与大家分享!

                 这是关于Facelets文章系列的第一部分
    Facelets是用来建立JSF应用程序时的一个可供选择的表现层技术。Facelets提供了一个强有力的模板化系统,让你使用HTML样式的模板来定义JSF的表现层,减少了组件整合进表现层时候冗余的代码,而不需要一个web容器。在这篇文中,Jacob将会介绍Facelets,解释一些Facelets的特性,还有他创建这个project的缘由。这个系列文章的第二部分将会指导你如何使用Facelets。


--------------------------------------------------------------------------------

自从JavaServer Faces成为工业标准以后,web社区一直热切地寻找一个类似Tapestry的框架。当JavaServer Faces 和JSP开始对齐,Facelets迈向了JSP specification地外部并且它提供了一个高性能以JSF为中心的表现层技术。任何写了一个JSP页面的人将可以用Facelets和类似的XML标签库来做同样的事。不同点在于任何隐藏在JSP供应商API下面的负荷被移除了,进而增强了JSF使之更像一个平台,并且提供了简单的插入式开发而不用进行任何的JSP标签库的开发工作。

JavaServer Faces的UIComponents是Facelets中最基本的类;没有必要去开发额外的对象去整合。也没有任何必要去学习另外一个XML schema来定义你的表现层。

这里是一个示例告诉了你在Facelets中定义一个页面是如何容易:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:c="http://java.sun.com/jstl/core">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Hello</title>
</head>
<body>
<form id="helloForm" jsfc="h:form">
<h2>
Hi. My name is Duke.  I'm thinking of a number from
#{UserNumberBean.minimum} to #{UserNumberBean.maximum}.
Can you guess it?
</h2>
<img id="waveImage" src="wave.med.gif" />

<input type="text" jsfc="h:inputText" id="userNo"
       value="#{UserNumberBean.userNumber}"
   validator="#{UserNumberBean.validate}"/>
  
<input type="submit" jsfc="h:commandButton" id="submit"
       action="success" value="Submit" />
<p />
<h:message showSummary="true" id="errors1" for="userNo"/>
<p />
<c:forEach begin="1" end="4" varStatus="v">
#{view.viewId} #{v.index}<br/>
</c:forEach>
</form>

</body>
</html>你可能会感觉到这些标签看起来特别熟悉。这就是要点。使用Facelets将不需要学习额外的模板语言或schema。

为什么使用Facelets?

最先和最重要的,Facelets不依赖于一个JSP容器。 这就意味着你可以使用新的JSF1.2的特性而不需要等待JSP2.1容器。当JSF1.1出来的时候,结合使用JSF 1.1和JSP有一些严重的问题。大部分问题都在Hans Bergsten的"Improving JSF by Dumping JSP."文章中提到了。强烈建议阅读这篇文章在你推进倒JSF1.2和Facelets之前。
Secondly, Facelets is designer friendly. Taking from Tapestry's jwcid attribute, Facelets uses jsfc and proper namespaces to convert HTML elements to their associated JSF component. In the example above, jsfc (JSF Compilation) is used to tell the compiler to instead build a h:inputText component into the view.

第二,Facelets是设计者友好的。取自Tapestry的jwcid属性,Facelets使用jsfc和合适的命名空间将HTML元素转换倒他们对应的JSF组件。在上面的例子中,jsfc(JSF Compilation)告诉了编译器在view中添加一个h:inputText组件。

最后要提出的就是,Facelets是非常轻量级的。你们中的一些人可能很熟悉Velocity的作为模板引擎的性能。Facelet也拥有相同的性能,你可以定义测试你的JSF表现层而不需要一个Servlet容器。Facelets的消耗很少且有在实际的成品中使用的经验。它也为servlet以外的JSF应用开发打开了一道门,包括Portlets。

这里就是你如何创建一个Facelet:

// grab our FaceletFactory and create a Facelet
FaceletFactory factory = FaceletFactory.getInstance();
Facelet f = factory.getFacelet(viewToRender.getViewId());

// populate UIViewRoot
f.apply(context, viewToRender);Facelets的一些特性
可以和JSF 1.1或1.2工作,包括 Sun's RI和Apache MyFaces.
0时间的UIComponents 标签开发
对JSF组件和页面的快速模板化/装饰支持
可以在不同的文件中声明UIComponent树(UICompositions)
支持到行/标签/属性的精确的错误报告
可以在不同的文件中声明标签, 甚至可以包含在Jar包中
全面的 EL 支持, 包含 Functions
编译期间的 EL 验证
XML 配置文件不是必要的, 但是是可用的
使用了 'jsfc' 属性, 和Tapestry的jwcid起相同作用 (例如: <input id="bar" type="text" jsfc="h:inputText" value="#{foo.bar}"/>)
插入式的装饰设计使设计者的工作更加简单 (例: 在编译期转换<input type="text"/>到<h:inputText/>)
不需要任何额外的呈现工具
Facelets不依赖于web容器
--------------------------------------------------------------------------------
Jacob Hookom is a developer with Sun's JavaServer Faces RI and Glassfish projects and is an active member of the JavaServer Faces Expert Group. He started consulting at 16 and has since held titles from Information Architect to Product Manager. More recently, Jacob started the 'Facelets' project as an ideal foundation for JavaServer Faces development. He has an accredited BS in Comprehensive Computer Science from the University of Wisconsin, Eau Claire. 
为什么Facelets会成功
任何人都希望更加设计者友好,而Tapestry看起来仿佛是开发者追求的唯一选择。另外一方面,JSF是一个任何人都希望使用的标准,但是JSF需要一个更加“可插入性”的ViewHandler框架来使开发者和设计者觉得友好。

开发者们做了足够的工作,在faces-config.xml中定义UIComponents/Converters/Validators,Facelets仅仅需要他们提供一个别名来将他们定义的对象插入到页面中去(不需要任何XML)。重点是简单的整合性和开发性。

最后,Facelets是整洁的面向JSF方面纠正。模板化,重用,易开发性拥有最高优先权,用来帮助开发者使用JSF平台开发大项目。

                        Facelets介绍,第二部分
    这是关于Facelets文章系列的第二篇,Facelets是用来建立JSF应用程序时的一个可供选择的表现层技术。第一篇文章提供了Facelets的介绍。在这篇文章中,Jacob将会告诉你如何在JSF应用中开始使用Facelets。



--------------------------------------------------------------------------------

准备开始
Facelets是作为JSF的一个ViewHandler实现的,可以被简便的配置到你的应用程序中。使用Facelets很简单,确保Facelets Jar(jsf-facelets.jar)在你项目的classpath中,并且对你的faces-config.xml文件做一个简单的修改就可以了。
<faces-config>
  <application>
    <!-- tell JSF to use Facelets -->
    <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
  </application>
</faces-config>JavaServer Faces默认使用JSP文件定义视图(*.jsp)。你需要在你的WEB-INF/web.xml中修改该类型。

<context-param>
  <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
  <param-value>.xhtml</param-value>
</context-param>依照上面定义的context-param,你就可以开始写Facelets并且将他们保存为以.xhtml类型的文档。你现在可以开始使用Facelets了。

内建类库
Facelets使用JavaServer Faces API 中所有UIComponents的方法和你在JSP中使用的方法一样。这就意味着你可以在线的JSF的tag类库文档。

也有一个简单的JSTL的核心库提供给你<c:forEach/> 和 <c:if/>。

最后,Facelets内建了一个UI标签库提供了模板化和重用性。关于这方面更多的资料在本文的第三篇文章中。

建立一个Facelet
Facelets仅仅需要严格的XML格式。他们不依赖于XHTML语法,可以被使用到VML,SVG,甚至SOAP中。使用JSP,你通常反复的引用标签库,而Facelets只需要在编译期间找到命名空间即可,和JSPX类似。这里是一个XHTML文档的开始部分:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
<head>
<meta http-equiv="Content-Type"
        content="text/html; charset=iso-8859-1" />
<title>My First Facelet</title>
</head>
<body>
  <!-- body content goes here -->
  Hello #{param.name}!
</body>
</html>你可以把这段代码保存为test.xhtml然后即刻请求test.jsf?name=Jacob(如果你的FacesServlet被map到*.jsf)。这是一个很好的用来确保你已经正确设置Facelets的测试。

使用EL
Facelets使用JSF中新的EL-API规范。这就意味着你可以交替使用${ } 或者 #{ },而不像是JSP。如上例所示,表达式可以内嵌正则文本。

如果你使用JSF1.2,你可以添加你自己定义的ELResolvers来整合诸如Spring,EJB,JNDI等等。--全部都可以如果你需要的话。你甚至可以拥有适合你应用程序对象的ELResolvers。

EL-API是JSP2.1规范的一部分,但是不依赖于JSP或者JSF。这就意味着它可以和Facelets一起被应用到任何部署中。

使用组件
在上面的test.xhtml实例中,你发现了额外的命名空间被申明。这些和JavaServer Faces API中内建的JSP标签库的命名空间相同。再次,Facelets期望建立在常见的领域和文档之外。

当你使用Facelets中内建的JSF组件,有一个标签库文档是一件很好的事。

既然我们已经有了test.xhtml作为开始,让我们来创建一个简单的表单。将下面的代码加入你页面的body中:

<h:form>
    <h:inputText value="#{person.name}"/>
    <h:commandButton action="#{person.action}"/>
</h:form>下面的步骤将是创建你自己的backingbean(BB)并修改faces-config.xml。

别名组件(jsfc)
前面的方法使用了特殊的标签,而使得他们在一个HTML编辑器工具(比如Dreamweaver)中不是特别好看。Facelets提供了一种不同的方法,使用标准HTML元素的jsfc属性来指定你页面中的组件(非常类似于Tapestry 和 Struts Shale 的 Clay plugin)

Facelets编译器寻找文档中所有组件的jsfc属性。jsfc属性的值是页面设计者用来在该页面中取代此元素值的别名。

<input type="text" jsfc="h:inputText" value="#{foo.bar}"/>Facelets在编译的时候将会生成一个h:inputText组件,同时将会自动配置所有合适的属性。

别名组件允许设计工具看到正常的HTML input标签,而编程人员可以将之看成是一个在jsfc属性中定义的JSF组件。

Facelet 编译
如第一篇文中提到的,Facelets只编译规范的XML。这些文件可以只有一行或者三行,唯一的要求就是它必须是合法的XML文档。

Facelets使用SAX来将文档编译成拥有TagHandlers的无状态树包含在一个Facelet对象中。Facelets是线程安全的并且可以被简单的应用在一次多请求的大规模部署中。Facelets在编译期间提供在JSF中使用到类库及视图操作的警告消息和报告。

执行Facelets编译是简单的,如下所示:

// grab our FaceletFactory and create a Facelet 
FaceletFactory factory = FaceletFactory.getInstance(); 
Facelet f = factory.getFacelet(viewToRender.getViewId());   
// populate UIViewRoot 
f.apply(context, viewToRender);更多关于Facelet的体系架构将会在稍后的文章中提供。

Exceptions & Debugging
Facelets注重了错误操作的解决。举个例子,有次你不小心的打错了一个属性的表达式,Facelets将会在编译期间自动生成一条如下的错误信息:

greeting.xhtml @18,97 <input action="#{success[}"> Error Parsing: #{success[}正如你所看到的,Facelets为你提供了错误消息来告诉你什么文件哪一行哪一列发生了错误。它甚至提供了发生错误的元素及属性。

Facelets也使用java.util.logging包来打印出排错消息。你可以阅读这里来了解如何在你的JRE中设置日值。

自定义组件
Facelets允许你使用一个XML文件或者Java代码来自定义你自己的组件库,但是在此篇文中我将只会涉及使用XML配置,因为XML配置是更好的选择。

<facelet-taglib>   
<namespace>http://www.mycompany.com/jsf</namespace>
<tag>    
<tag-name>bar</tag-name>
  <component>       
<component-type>javax.faces.Data</component-type>    
          <renderer-type>com.mycompany.Bar</renderer-type>
</component>   
</tag>
</facelet-taglib>这就是你整合你的组件到Facelets中所要做的全部工作。这些XML文档可以使用下面两种方法参考。
(译注:关于在Facelets中如何使用Tomahawk组件,可在此查阅)

Reference them in a ";" delimitted list within your web.xml under the init-param "facelets.LIBRARIES". These files are relative to your application, just like referencing Struts configuration files.
在你的web.xml的init-param?facelets.LIBRARIES?中引用,使用?;?分隔不同XML配置文件。这些文档和你的应用程序有关,就如同引用Struts的配置文件一样。
Package them in your JAR's META-INF folder with a file extension of ".taglib.xml". Facelets will automatically pick these up for compilation just as with JSP tld files.
将它们打包到你的JAR文件中的META-INF文件夹中,使用一个以?.taglib.xml?结尾的文件。Facelets将会自动将这些读入编译,就好像JSP的tld文件。
在facelet-taglib文件中,你也可以指定转换器,验证器,和自定义的TagHandler来获取文件处理的的最终控制。

自定义验证器和转换器
验证器和转换器可以在Facelet中通过同一个facelet-taglib文档描述。

<facelet-taglib>   
<namespace>http://www.jsfcentral.com/public</namespace>   
<tag>     
<tag-name>validateRegExp</tag-name> 
    <validator>
<validator-id>foo.bar.RegExp</validator-id>    
        </validator>   
</tag>   
<tag>    
<tag-name>convertUtilDate</tag-name>
           <converter>       
              <converter-id>foo.bar.UtilDate</converter-id>
           </converter>   
     </tag> 
</facelet-taglib>再次,由于Facelets和JavaServer Faces的API整合的很紧密,这些就是你所要定义的全部。Facelets将会自动装配这些属性到你的Converter或者是Validator对象中。

自定义组件
好的,我还没有想到但是你想在Facelets中添加你的自定义组件。这就包含了你想要为UIComponents,Validators,Converters装配各自的属性。

Facelets提供了许多基本类来使得你的工作更简单。让我们来看看<c:if>的源码,或许能给你一些好主意:

public final class IfHandler extends TagHandler
{       
protected final TagAttribute test;     
protected final TagAttribute var;
      
     public IfHandler(TagConfig config)
     {         
        super(config);         
        this.test = this.getRequiredAttribute("test");         
        this.var = this.getAttribute("var");    
      }      

     public void apply(FaceletContext ctx, UIComponent parent)             
           throws IOException, FacesException, ELException
      {         
         boolean b = this.test.getBoolean(ctx);         
         if (this.var != null)
         {            
              ctx.setAttribute(var.getValue(ctx), new Boolean(b));       
          }         
         if (b)
         {             
              this.nextHandler.apply(ctx, parent);        
         }     
       } 
}这就是了!你将发现当文档被编译的时候Facelets使用了?好居民?法则和构造函数注入的方法。Facelets和全部标签都是无状态的,而不像JSP(添加入了tag handler对象)。更多技术方面的细节将会在一篇不同的文档中提供,所以现在酒描述tag里面是如何进行的。

TagHandler,<c:if> 继承的,是一个很好的让你可以使用开发自定义标签的基本类示例。将TagHandler想象成JSP的TagSupport或者BodyTagSupport。

在构造函数中,该Tag的表现被传递,转达了该文档的结构包含的:位置,子标签,和属性。

TagAttributes是XML文档中属性的表现。他们有众多方法来处理EL表达式和高压方法到你需要的类型中。他们也是无状态的,他们的方法必须要传递到FaceletContext中以提供当前的状态。

最后一点比较有趣的就是子元素被部分变量nextHandler表现。你可以在<c:if>的情况下添加任意多的子元素或者根本不添加。

我们自定义的组件已经写了出来,你可以继续将它添加到facelet-taglib文档中:

<facelet-taglib>   
      <namespace>http://www.jsfcentral.com/public</namespace>   
           <tag>     
              <tag-name>if</tag-name>     
              <handler-class>com.jsfcentral.IfHandler</handler-class>   
           </tag> 
</facelet-taglib>总结
这仅仅是使用Facelets框架的一个简短介绍。接下来将会有更多关于模板化,特色和定制Facelets的详细文章。

Facelets介绍,第三部分 收藏
原文:http://www.jsfcentral.com/articles/facelets_3.html

译:JSF-OPENDOC team的巨土无比

                       这是Facelets系列文章中的第三部分
  是用另外一种视图技术来创建JSF应用。Facelets是一个强大的模板化系统,它能让你用HTML风格的模板来定义JSF视图,并能够减少那些适合于集成在视图中的组件的代码数量,而且不需要web容器。这篇文章解释了你如何能够用Facelets在你的JSF工程里面创建模板。


--------------------------------------------------------------------------------

对任何一种想要成功的视图技术来说,它必须拥有一些创建模板和重用的功能,而且必须好用又易懂。对于JSF来说,Facelets技术完美的解决了这个问题,并且延续了传统的、基于标签的UI风格。这篇文章包括了一些增加重用和简化维护JSF工程的方法。

当人们第一次开始创建网页的时候,他们经常发现自己在多个文件中重复相同的内容。作为一个开发人员来说,当你开始用面向对象的思想来开发的时候,这样的重复劳动会让人很灰心丧气。难道把这些内容简单地维护在一个地方不是更漂亮吗?

开始
模板化和重用的第一步是创建一个模板。一个网页通常由一些基本的部分组成:header, body,和footer。用Facelets,你能把这些通用的元素放在一个单独的页面里,并创建一个带有可编辑区的模板,如下面的模板所示:

<!-- template.xhtml -->    
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"    
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">    
<html xmlns="http://www.w3.org/1999/xhtml"     
                         xmlns:ui="http://java.sun.com/jsf/facelets"> 
<head>    
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />    
<title>Sample Template</title> 
</head> 
<body>    
<h1>#{title}</h1>    
<div><ui:insert name="menu"/></div>    
<p><ui:insert name="body"/></p>   
</body> 
</html>对于menu和body来说,<ui:insert/> 标签用来标记这块地方的内容会根据每一页变化。你可以用这个模板来创建其他的页面,并给menu和body区域提供不同的内容。

<!-- template-client.xhtml -->    
<!-- content above will be trimmed -->    
<ui:composition template="template.xhtml">      
<ui:param name="title" value="Here's my Title"/>      
<ui:define name="menu">Here's My Menu</ui:define>      
<ui:define name="body">Here's My Body</ui:define>      
</ui:composition>    
<!-- content below will be trimmed -->这个例子介绍了另外一个标签<ui:composition/>。该标签提供了一对特征。它删掉了它外面的任何内容,就是说,你可以写一些普通的HTML页面,而Facelets将只是用或者 显示出现在<ui:composition/>标签里面的内容。使用这个标签,你同样可以选择提供一个模板的属性,该属性将定义内容如何或在哪里显示。

为了把内容和模板配对,<ui:define/>标签的name属性和模板中的<ui:insert/>标签的name属性一致的就可以替换。为了简便地传递变量或者文字,你可以使用<ui:param/>标签,该标签把其value属性作为模板中的一个变量来替代。

当Facelets使用指定的模板呈现该页面时候,你将会得到以下的输出:

<!-- template.xhtml -->    
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"     
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">    
<html xmlns="http://www.w3.org/1999/xhtml"    
                                    xmlns:ui="http://java.sun.com/jsf/facelets"> 
<head>   
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />   
<title>Sample Template</title> 
</head>
<body>    
<h1>Here's my Title</h1>    
<div>Here's My Menu</div> 
   <p>Here's My Body</p>   
</body> 
</html>前面的这个例子能够被更加简化,如果在模板中只有一个地方是可变的:

<!-- simple-template.xhtml -->    
...
<body>    
<h1>Title</h1>    
<!-- editable body -->    
<p><ui:insert/></p> 
</body>    
... 想要用上面模板的页面就可以简化成下面:

<!-- simple-template-client.xhtml -->    
<ui:composition template="simple-template.xhtml">    
Here's My Simple Body   
</ui:composition>使用Includes
页面中的位置这个概念在页面中定义可重用的内容是相当强大的。上面几个例子展示了如何使用模板中的位置来显示内容。但是如果你想从另一个页面中包含进来一些东西该如何做呢?可能这里有一系列的表单控件或者一个复杂的菜单,以至于你宁愿把它们分离到一个不同的文件中,以便重用或者单独管理而不用散乱在页面布局的各个角落。

总的来说,Facelets提供了两种包含位置或者其他页面的方法。第一种是用<ui:include/>标签,对于web开发人员来说,该标签应该是相当熟悉的:

<!-- include.xhtml -->    
...    
<span id="leftNav">    
<ui:include src="/WEB-INF/siteNav.xhtml"/>   
</span>    
...<!-- siteNav.xhtml -->    
..    
<ui:composition>   
<!-- myfaces tomahawk components -->    
<t:tree2 value="#{backingBean.options}" var="opt">   
...    
</t:tree2>   
</ui:composition>   
...当Facelets处理include.xhtml时,siteNav.xhtml的所有<ui:composition/>中的内容将被包含进include.xhtml:

<!-- include.xhtml -->    
...  
<span id="leftNav">   
<!-- myfaces tomahawk components --> 
   <t:tree2 value="#{backingBean.options}" var="opt">    
...    
</t:tree2>  
</span>  
...如果你愿意给siteNav.xhtml传递变量,这些变量供tree组件使用,那么你可以使用<ui:param/>标签:

<!-- include.xhtml -->   
...  
<span id="leftNav">    
<ui:include src="/WEB-INF/siteNav.xhtml">   
<ui:param name="menuBean" value="#{backingBean.options}"/>    
</ui:include>  
</span>
  ...<!-- siteNav.xhtml -->    
...   
<ui:composition>   
<!-- myfaces tomahawk components -->   
<t:tree2 value="#{menuBean}" var="opt">   
...    
</t:tree2>    
</ui:composition>    
...你能够看到现在siteNav.xhtml可以使用变量menuBean并且menuBean是通过<ui:include/>标签来传递的。这样使一些灵活的可重用的通用组件和内容成为了可能。

对于<ui:include/>和<ui:param/>,Facelets提供了一个更加简洁的解决方案,通过支持自定义标签。别急,你不需要自己写任何一点java代码。为了给siteNav.xhtml定制一个可重用的标签,你必须创建一个简单的XML标签库文件。

<facelet-taglib>    
<namespace>">http://www.mycompany.com/jsf</namespace>   
<tag>    
<tag-name>siteNav.xhtml</tag-name>    
<source>/WEB-INF/tags/siteNav.xhtml</source>   
</tag> 
</facelet-taglib>除了在你的新标签库XML文件中制定Facelets外,你可能需要添加尽可能多的标签到新的标签库中。通过指定http://www.mycompany.com/jsf作为命名空间,你可以这样写:

<!-- include-tag.xhtml --> 
...   
<span id="leftNav">    
<my:siteNav menuBean="#{backingBean.options}"/>
</span> 
...这个include-tag.xhtml例子和前面的include.xhtml例子效果一样。MenuBean的属性作为siteNav.xhtml的一个属性将生效,就像<ui:param/>传递的那样。

你的工程可能包括了一个jar文件,其中包括了所有的自定义标签库,或者只是简单的把自定义标签库放到了一个文件加里。更多的标签在Facelets Developer Documentation中详细描述.



本文来自CSDN博客http://blog.csdn.net/leeshaoqun/archive/2006/08/27/1126490.aspx

你可能感兴趣的:(xml,jsp,XHTML,JSF,tapestry)