我有一个 JSF2 应用程序正在运行并且工作正常。我在使用 JSF 时遇到的问题是资源包。所有资源都有 .xhtml
后缀附加到它。所以main.css
变成 main.css.xhtml
在浏览器中加载时。我想要它所以 .xhtml
不附加到资源(不要介意页面本身)。
有没有办法让我们不拥有.xhtml
附加到资源?
理想情况下,我不必更改网站的内部运作方式。我在下面列出了想法,但我不得不说我不太喜欢这些。希望在某个地方找到解决方案?
我在 Glassfish 3.1.2.2 上使用 Majorra v.2.1.17。
Current 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
因为这将缓存所有页面以及静态内容。这会导致 session 等问题。
尝试的解决方案
根据 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
, 又名 className
是null
因为我得到的错误是 java.lang.NullPointerException
.我似乎无法弄清楚 ResourceHandler
如何/在哪里被称为相对于复合组件。对解决最后一个问题有帮助吗?
最佳答案
这可以通过自定义 ResourceHandler
实现在 createResource()
中返回一个 Resource
这又会在 Resource#getRequestPath()
上返回一个“未映射”的 URL .您只需要添加默认的 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>
扩展FacesServlet
带有 ResourceHandler.RESOURCE_IDENTIFIER
的 URL 模式:
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
<url-pattern>/javax.faces.resource/*</url-pattern>
</servlet-mapping>
关于java - 防止在页面加载时将后缀添加到资源中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14963756/