有没有一种我们不能将.xhtml附加到资源的方式?
我最好不用改变网站的内部工作.我已经列出了下面的想法,但我不得不说我不太喜欢这些.希望解决某个地方?
我在Glassfish 3.1.2.2上使用了Majorra v.2.1.17.
当前Faces Servlet加载在web.xml(更新)
<servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.xhtml</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/javax.faces.resource/*</url-pattern> </servlet-mapping>
为什么这个问题与别人不同
> JSF 2 resources with CDN?.我不想将资源放在CDN上,而是将资源留在我的服务器上,但是被推向CDN.
> Change /javax.faces.resource prefix of resource URLs.我不想改变前缀.我只想改变后缀.我想要< link type =“text / css”rel =“stylesheet”href =“/ javax.faces.resource / main03.css.xhtml?ln = styles”>成为:< link type =“text / css”rel =“stylesheet”href =“/ javax.faces.resource / main03.css?ln = styles”>没有.xhtml扩展名.
> Changing JSF prefix to suffix mapping forces me to reapply the mapping on CSS background images.由于我没有加载资源的问题.该网站的作品,我们只是很难区分一个网页从一个资源(因为我们仅仅看扩展).
推理
当然你可能会问我为什么需要这个.那我们正在把我们的应用程序转移给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 className为null,因为我得到的错误是java.lang.NullPointerException.我似乎无法确定ResourceHandler与复合组件的对应关系.任何帮助弄清楚这最后一个问题?
解决方法
createResource()
中返回一个
Resource
,然后在
Resource#getRequestPath()
返回一个“未映射的”URL的自定义
ResourceHandler
.您只需要将默认的JSF资源前缀/javax.faces.resource/*添加到< url-pattern> ; 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<String,String> 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中注册如下:
<application> <resource-handler>com.example.UnmappedResourceHandler</resource-handler> </application>
使用ResourceHandler.RESOURCE_IDENTIFIER扩展FacesServlet URL模式:
<servlet-mapping> <servlet-name>facesServlet</servlet-name> <url-pattern>*.xhtml</url-pattern> <url-pattern>/javax.faces.resource/*</url-pattern> </servlet-mapping>