Facelets介绍,第二部分

来源:互联网 发布:广西广电网络招聘信息 编辑:程序博客网 时间:2024/04/26 21:49

这是关于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组件,可在此查阅)

  1. 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的配置文件一样。
  2. 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的详细文章。