什么是JSF资源库,以及如何使用它?

JSF <h:outputStylesheet><h:outputScript><h:graphicImage>组件具有library属性。 这是什么,应该如何使用? 在networking上有很多的例子,它使用如下的常见的内容/文件types的cssjsimg (或image )作为库名取决于使用的标签:

 <h:outputStylesheet library="css" name="style.css" /> <h:outputScript library="js" name="script.js" /> <h:graphicImage library="img" name="logo.png" /> 

它有什么用处? 这些示例中的library值似乎只是重复了标记名称所代表的内容。 对于<h:outputStylesheet>它基于标记名已经很明显,它代表一个“CSS库”。 下面哪个区别也是一样的?

 <h:outputStylesheet name="css/style.css" /> <h:outputScript name="js/script.js" /> <h:graphicImage name="img/logo.png" /> 

而且,生成的HTML输出有点不同。 给定*.xhtml URL模式上的/contextnameFacesServlet映射的上下文path,前者将生成以下HTML名称作为请求参数的库名称:

 <link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/style.css.xhtml?ln=css" /> <script type="text/javascript" src="/contextname/javax.faces.resource/script.js.xhtml?ln=js"></script> <img src="/contextname/javax.faces.resource/logo.png.xhtml?ln=img" alt="" /> 

后者在URI的path中使用库名称生成以下HTML:

 <link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/css/style.css.xhtml" /> <script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml"></script> <img src="/contextname/javax.faces.resource/img/logo.png.xhtml" alt="" /> 

后一种方法在事后看来比前一种方法更有意义。 那么library属性到底有多有用呢?

实际上,所有这些使用常见的内容/文件types(例如“js”,“css”,“img”等)作为库名的例子都是误导性的

真实世界的例子

首先,我们来看看现有的像Mojarra和MyFaces这样的JSF实现以及像PrimeFaces和OmniFaces这样的JSF组件库如何使用它。 其中没有一个人以这种方式使用资源库。 他们使用它(在下面,通过@ResourceDependencyUIViewRoot#addComponentResource() )以下面的方式:

 <h:outputScript library="javax.faces" name="jsf.js" /> <h:outputScript library="primefaces" name="jquery/jquery.js" /> <h:outputScript library="omnifaces" name="omnifaces.js" /> <h:outputScript library="omnifaces" name="fixviewstate.js" /> <h:outputScript library="omnifaces.combined" name="[dynamicname].js" /> <h:outputStylesheet library="primefaces" name="primefaces.css" /> <h:outputStylesheet library="primefaces-aristo" name="theme.css" /> <h:outputStylesheet library="primefaces-vader" name="theme.css" /> 

应该清楚的是,它基本上代表了所有这些资源通常属于的共同的库/模块/主题名称

更容易识别

这样一来,指定和区分这些资源所属的和/或来自哪里将变得更加容易。 想象一下,你碰巧在你自己的webapp中有一个primefaces.css资源,其中你正在重写/微调一些默认的PrimeFaces CSS; 如果PrimeFaces没有为自己的primefaces.css使用一个库名,那么PrimeFaces自己的不会被加载,而是由webapp提供的,这会破坏look'n'feel。

另外,当你使用一个自定义的ResourceHandler ,当正确使用库时,你也可以对来自特定库的资源进行更精细的控制。 如果所有组件库都将使用所有JS文件的“js”,那么ResourceHandler如何区分它是否来自特定的组件库? 例子是OmniFaces CombinedResourceHandlerGraphicResourceHandler ; 检查在委托给链中的下一个资源处理器之前检查库的createResource()方法。 这样他们知道什么时候创buildCombinedResourceGraphicResource的目的。

值得注意的是RichFaces做错了。 它根本没有使用任何library ,并且在它上面自带了另一个资源处理层,因此不可能通过编程来识别RichFaces资源。 这就是为什么OmniFaces CombinedResourceHander必须引入基于reflection的黑客才能使其与RichFaces资源一起工作的原因。

你自己的web应用程序

您自己的web应用程序不一定需要资源库。 你最好只是省略它。

 <h:outputStylesheet name="css/style.css" /> <h:outputScript name="js/script.js" /> <h:graphicImage name="img/logo.png" /> 

或者,如果你真的需要有一个,你可以给它一个更明智的通用名称,如“默认”或一些公司名称。

 <h:outputStylesheet library="default" name="css/style.css" /> <h:outputScript library="default" name="js/script.js" /> <h:graphicImage library="default" name="img/logo.png" /> 

或者,当资源特定于某个主要的Facelets模板时,您也可以为其指定模板的名称,以便更容易相互关联。 换句话说,这更多是为了自我纪录的目的。 例如,在/WEB-INF/templates/layout.xhtml模板文件中:

 <h:outputStylesheet library="layout" name="css/style.css" /> <h:outputScript library="layout" name="js/script.js" /> 

/WEB-INF/templates/admin.xhtml模板文件:

 <h:outputStylesheet library="admin" name="css/style.css" /> <h:outputScript library="admin" name="js/script.js" /> 

对于真实世界的例子,请查看OmniFaces展示源代码 。

或者,如果您想通过多个webapps共享相同的资源,并且基于与此答案相同的示例创build了一个“common”项目,该项目又被embedded为webapp的/WEB-INF/lib JAR,那么也可以将它作为库引用(名称可以自由select;像OmniFaces和PrimeFaces这样的组件库也可以这样工作):

 <h:outputStylesheet library="common" name="css/style.css" /> <h:outputScript library="common" name="js/script.js" /> <h:graphicImage library="common" name="img/logo.png" /> 

库版本控制

另一个主要优点是可以将资源库版本控制应用于由您自己的Web应用程序提供的资源(这对于embedded到JAR中的资源不起作用)。 您可以使用\d+(_\d+)*模式中的名称在库文件夹中创build直接的子子文件夹,以表示资源库版本。

 WebContent |-- resources | `-- default | `-- 1_0 | |-- css | | `-- style.css | |-- img | | `-- logo.png | `-- js | `-- script.js : 

使用此标记时:

 <h:outputStylesheet library="default" name="css/style.css" /> <h:outputScript library="default" name="js/script.js" /> <h:graphicImage library="default" name="img/logo.png" /> 

这将生成下面的HTML版本库作为v参数:

 <link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/css/style.css.xhtml?ln=default&amp;v=1_0" /> <script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml?ln=default&amp;v=1_0"></script> <img src="/contextname/javax.faces.resource/img/logo.png.xhtml?ln=default&amp;v=1_0" alt="" /> 

所以,如果你已经编辑/更新了一些资源,那么你所要做的就是将版本文件夹复制或重命名为一个新的值。 如果您有多个版本文件夹,则根据数字sorting规则,JSF ResourceHandler将自动从最高版本号提供资源。

所以,在将resources/default/1_0/*文件夹复制/重命名为resources/default/1_1/* ,如下所示:

 WebContent |-- resources | `-- default | |-- 1_0 | | : | | | `-- 1_1 | |-- css | | `-- style.css | |-- img | | `-- logo.png | `-- js | `-- script.js : 

然后最后的标记示例将生成以下HTML:

 <link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/css/style.css.xhtml?ln=default&amp;v=1_1" /> <script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml?ln=default&amp;v=1_1"></script> <img src="/contextname/javax.faces.resource/img/logo.png.xhtml?ln=default&amp;v=1_1" alt="" /> 

这将迫使网页浏览器直接从服务器请求资源,而不是在第一次请求带有已更改参数的URL时,从caching中显示同名的资源。 这样,当用户需要检索更新的CSS / JS资源时,不需要进行硬刷新(Ctrl + F5等)。

请注意,对于JAR文件中包含的资源,库版本控制是不可能的。 你需要一个自定义的ResourceHandler 。 另请参见如何在jar中使用JSF版本控制资源 。

也可以看看:

  • JSF资源版本控制
  • JSF2静态资源caching
  • 具有共享代码的多个JSF项目的结构
  • JSF 2.0规范 – 第2.6章资源处理