阻止在页面加载时将后缀添加到资源

我有一个JSF2应用程序运行和工作没有问题。 我与JSF的问题在于资源包。 所有资源都附加了.xhtml后缀。 所以main.css在浏览器中加载后变为main.css.xhtml 。 我想拥有它所以.xhtml不会依赖于资源(不要介意页面本身)。

有没有办法让我们不能.xhtml附加到资源上?

理想情况下,我不需要改变网站的内部工作方式。 我在下面列出了一些想法,但我不得不说我不喜欢这些。 希望在某处找到解决方案?

我在Glassfish 3.1.2.2上使用Majorra v.2.1.17。

当前Faces Servlet加载为web.xml(已更新)

  Faces Servlet javax.faces.webapp.FacesServlet 1   Faces Servlet *.xhtml   Faces Servlet /javax.faces.resource/*  

为什么这个问题与其他问题不同

  • 带有CDN的JSF 2资源? 。 我不是要将我的资源放在CDN上,而是让我的资源留在我的服务器上但是被推向了CDN。
  • 更改资源URL的/javax.faces.resource前缀 。 我不想改变前缀。 我只想更改后缀。 我希望成为: 没有 .xhtml扩展名。
  • 将JSF前缀更改为后缀映射会强制我重新应用CSS背景图像上的映射 。 因为我没有加载资源的问题。 该网站有效,我们只是很难将网页与资源区分开来(因为我们只关注扩展)。

推理

当然你可能会问我为什么需要这个。 好吧,我们正在将我们的应用程序移至Akamai CDN。

我们在整合网站时遇到的问题是我们正在尝试在边缘服务器上缓存静态内容。 这是通过匹配文件扩展名来完成的(即:.js,.doc,.png,css等)。 我们无法匹配xhtml因为这将缓存所有页面以及静态内容。 这会导致会话等问题。

试图解决方案

根据BalusC的回答,我按照建议实现了资源处理程序。 我不会在这里重写代码,因为它在下面回答。

但是,我在加载复合组件时遇到错误。 我这样得到一个错误:

 WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception java.lang.NullPointerException at com.sun.faces.application.ApplicationImpl.createComponent(ApplicationImpl.java:975) at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.createComponent(CompositeComponentTagHandler.java:162) at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.createComponent(ComponentTagHandlerDelegateImpl.java:494) at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:169) ... 

正确加载复合组件,因为如果我“取消注册”我们刚刚创建的新ResourceHandler ,它将加载。 堆栈跟踪让我相信它正试图在java类中找到这个组件,而不是在资源中找到它。 根据grepcode这将发生错误发生的最后一行(975):

 String packageName = componentResource.getLibraryName(); String className = componentResource.getResourceName(); className = packageName + '.' + className.substring(0, className.lastIndexOf('.')); 

这意味着resourceName ,aka classNamenull因为我得到的错误是java.lang.NullPointerException 。 我似乎无法弄清楚ResourceHandler相对于复合组件的调用方式/位置。 有没有帮助搞清楚这最后一期?

这对于自定义ResourceHandler是可行的,该自定义ResourceHandlercreateResource()中返回一个Resource ,而Resource又在Resource#getRequestPath()上返回一个“未映射”的URL。 您只需要将默认的JSF资源前缀/javax.faces.resource/*添加到FacesServlet映射的列表中,以便无论如何都可以触发它。

此外,您需要覆盖isResourceRequest()以检查URL是否以JSF资源前缀开头,还是handleResourceRequest()来查找和流式传输适当的资源。

总而言之,这应该做到:

 public class UnmappedResourceHandler extends ResourceHandlerWrapper { private ResourceHandler wrapped; public UnmappedResourceHandler(ResourceHandler wrapped) { this.wrapped = wrapped; } @Override public Resource createResource(final String resourceName, final String libraryName) { final Resource resource = super.createResource(resourceName, libraryName); if (resource == null) { return null; } return new ResourceWrapper() { @Override public String getRequestPath() { ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); String mapping = externalContext.getRequestServletPath(); if (externalContext.getRequestPathInfo() == null) { mapping = mapping.substring(mapping.lastIndexOf('.')); } String path = super.getRequestPath(); if (mapping.charAt(0) == '/') { return path.replaceFirst(mapping, ""); } else if (path.contains("?")) { return path.replace(mapping + "?", "?"); } else { return path.substring(0, path.length() - mapping.length()); } } @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 boolean isResourceRequest(FacesContext context) { return ResourceHandler.RESOURCE_IDENTIFIER.equals(context.getExternalContext().getRequestServletPath()); } @Override public void handleResourceRequest(FacesContext context) throws IOException { ExternalContext externalContext = context.getExternalContext(); String resourceName = externalContext.getRequestPathInfo(); String libraryName = externalContext.getRequestParameterMap().get("ln"); Resource resource = context.getApplication().getResourceHandler().createResource(resourceName, libraryName); if (resource == null) { super.handleResourceRequest(context); return; } if (!resource.userAgentNeedsUpdate(context)) { externalContext.setResponseStatus(HttpServletResponse.SC_NOT_MODIFIED); return; } externalContext.setResponseContentType(resource.getContentType()); for (Entry header : resource.getResponseHeaders().entrySet()) { externalContext.setResponseHeader(header.getKey(), header.getValue()); } ReadableByteChannel input = null; WritableByteChannel output = null; try { input = Channels.newChannel(resource.getInputStream()); output = Channels.newChannel(externalContext.getResponseOutputStream()); for (ByteBuffer buffer = ByteBuffer.allocateDirect(10240); input.read(buffer) != -1; buffer.clear()) { output.write((ByteBuffer) buffer.flip()); } } finally { if (output != null) try { output.close(); } catch (IOException ignore) {} if (input != null) try { input.close(); } catch (IOException ignore) {} } } @Override public ResourceHandler getWrapped() { return wrapped; } } 

faces-config.xml中将其注册如下:

  com.example.UnmappedResourceHandler  

使用ResourceHandler.RESOURCE_IDENTIFIER扩展FacesServlet URL模式:

  facesServlet *.xhtml /javax.faces.resource/*  

你可以看看Rewrite 。 重写允许修改呈现给页面的URL并以您想要的任何方式修改它们。 您可以执行以下操作将CDN添加到您的站点:

 .addRule(CDN.relocate("{p}foo-{version}.css") .where("p").matches(".*") .where("version").matches(".*") .to("http://mycdn.com/foo-{version}.css")); 

我认为使用Rewrite实现您的需求应该很容易。

查看示例配置以了解重写的function。

Interesting Posts