问题
PF 3.5.10, Mojarra 2.1.21, omnifaces 1.5
I have a JSF library (with css files only). This library is in a .jar file. The css will be included in xhtml with
<h:outputStylesheet library="mylib" name="css/mycss.css">
.
In html it is rendered to the following: localhost:8080/cms/javax.faces.resource/css/mycss.css.jsf?ln=mylib
CSS file of primefaces is rendered to:
localhost:8080/cms/javax.faces.resource/primefaces.js.jsf?ln=primefaces&v=3.5.10
Notice the library version (&3.5.10) at the end. How can I do the same thing ? Should I write version in Manifest.mf. Or how can I use jsf-versioning in jar file?
回答1:
That's unfortunately not possible. Library versioning is not supported for resources in JAR.
You've basically 2 options:
Do it the easy and ugly way, include server's startup time as query string. Given that you're using OmniFaces, you could use its builtin
#{startup}
managed bean referring ajava.util.Date
instance in application scope:<h:outputStylesheet ... name="some.css?#{startup.time}" /> <h:outputScript ... name="some.js?#{startup.time}" />
Or perhaps you've the version already as some application variable.
<h:outputStylesheet ... name="some.css?v=#{app.version}" /> <h:outputScript ... name="some.js?v=#{app.version}" />
Update: Notwithstanding, this doesn't work for
<h:outputStylesheet>
. See also: https://github.com/javaserverfaces/mojarra/issues/3945 or https://github.com/javaee/javaserverfaces-spec/issues/1395It works for
<h:outputScript>
though, which had a very simliar bug report which was implemented pretty soon https://github.com/javaserverfaces/mojarra/issues/1216Do the same as PrimeFaces, create a custom
ResourceHandler
.public class MyVersionResourceHandler extends ResourceHandlerWrapper { private ResourceHandler wrapped; public MyVersionResourceHandler(ResourceHandler wrapped) { this.wrapped = wrapped; } @Override public Resource createResource(String resourceName) { return createResource(resourceName, null, null); } @Override public Resource createResource(String resourceName, String libraryName) { return createResource(resourceName, libraryName, null); } @Override public Resource createResource(String resourceName, String libraryName, String contentType) { final Resource resource = super.createResource(resourceName, libraryName, contentType); if (resource == null) { return null; } return new ResourceWrapper() { @Override public String getRequestPath() { return super.getRequestPath() + "&v=1.0"; } @Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2). public String getResourceName() { return resource.getResourceName(); } @Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2). public String getLibraryName() { return resource.getLibraryName(); } @Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2). public String getContentType() { return resource.getContentType(); } @Override public Resource getWrapped() { return resource; } }; } @Override public ResourceHandler getWrapped() { return wrapped; } }
Or if you happen to already use OmniFaces, it could be done simpler:
public class YourVersionResourceHandler extends DefaultResourceHandler { public YourVersionResourceHandler(ResourceHandler wrapped) { super(wrapped); } @Override public Resource decorateResource(Resource resource) { if (resource == null || !"mylib".equals(resource.getLibraryName())) { return resource; } return new RemappedResource(resource, resource.getRequestPath() + "&v=1.0"); } }
Either way, to get it to run, register it as
<resource-handler>
in/META-INF/faces-config.xml
of the JAR.<application> <resource-handler>com.example.MyVersionResourceHandler</resource-handler> </application>
回答2:
You can also use your project version and append it as a version number for your resource files. This can be done using the maven-war-plugin
. The maven-war-plugin
will look at your pages during the build time and replace the defined properties.
The following example shows you how to configure the maven-war-plugin
to filter your webapp resources in order to inject the custom property asset.version
:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
...
<properties>
<asset.version>${project.version}</asset.version>
</properties>
...
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>gif</nonFilteredFileExtension>
<nonFilteredFileExtension>ico</nonFilteredFileExtension>
<nonFilteredFileExtension>jpg</nonFilteredFileExtension>
<nonFilteredFileExtension>png</nonFilteredFileExtension>
<nonFilteredFileExtension>pdf</nonFilteredFileExtension>
</nonFilteredFileExtensions>
<failOnMissingWebXml>false</failOnMissingWebXml>
<webResources>
<webResource>
<directory>${basedir}/src/main/webapp</directory>
<filtering>true</filtering>
</webResource>
</webResources>
</configuration>
</plugin>
...
</plugins>
</build>
</project>
The asset.version
property can then be used in your JSF file.
Here is an example tested with JSF 2.2:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html ...
xmlns:jsf="http://xmlns.jcp.org/jsf">
...
<script jsf:name="js/libs/pure/pure-min.css?v=${project.version}" />
The result (in my case) will be the following:
<script type="text/javascript" src="/context-path/javax.faces.resource/js/libs/pure/pure-min.css.xhtml?v=1.0.15-SNAPSHOT"></script>
回答3:
@Balusc response said "well, not a bug, but oversight and spec fail". It seems like css resources deployed in libraries cannot be versioned with mojarra 2.2.14. Is it right? I tried to implement your solution with a custom ResourceHandler, but resource returned by getWrapped().createResource(resourceName, libraryName) always returns null. It seems like createResource() try to find the library's resources (like css/layout.css) with path /META-INF/resources/ but it lacks the version.
To workaround the problem i have overrided createResource method on a custom ResourceHandler which extends Omnifaces DefaultResourceHandler to add version prefix to the resourceName
@Override
public Resource createResource(String resourceName, String libraryName) {
if (libraryName != null && libraryName.equals(LIBRARY_NAME)) {
if (!resourceName.startsWith(version)) {
resourceName = version + "/"+resourceName;
}
}
return super.createResource(resourceName, libraryName);
}
With this workaround the generated link looks like
<link type="text/css" rel="stylesheet" href="/javax.faces.resource/1_0_3/css/layout.css?ln=common&v=1_0_3"/>
for the outputStylesheet declaration
<h:outputStylesheet library="common" name="css/layout.css" />
I'm not sure this is the best workaround.
来源:https://stackoverflow.com/questions/18143383/how-to-use-jsf-versioning-for-resources-in-jar