java 防止在页面加载时向资源添加后缀
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14963756/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Prevent suffix from being added to resources when page loads
提问by blo0p3r
I have a JSF2 application running and working no problem. The issue I am having with JSF is with the resource bundle. All resources have the .xhtml
suffix appended to it. So main.css
becomes main.css.xhtml
when loaded in the browser. I would like to have it so the .xhtml
isn't apended to the resources (don't mind about the pages themselves).
我有一个 JSF2 应用程序正在运行并且没有问题。我在 JSF 中遇到的问题是资源包。所有资源都.xhtml
附加了后缀。所以在浏览器中加载时main.css
就变成main.css.xhtml
了。我想要它,所以.xhtml
它不会附加到资源中(不要介意页面本身)。
Is there a way where we can NOThave .xhtml
appended to resources?
是否有一个地方,我们可以一个方式不具有.xhtml
附加的资源呢?
I would ideally not have to change the internal workings of the site. I have listed ideas below, but I have to say I don't really like these. Hoping for a solution somewhere?
理想情况下,我不必更改网站的内部运作。我在下面列出了一些想法,但我不得不说我真的不喜欢这些。希望在某处找到解决方案?
I am using Majorra v.2.1.17 on Glassfish 3.1.2.2.
我在 Glassfish 3.1.2.2 上使用 Majorra v.2.1.17。
Current Faces Servlet loading as in web.xml (updated)
在 web.xml 中加载 Current Faces Servlet(更新)
<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>
Why this questions is different from others
为什么这个问题与其他问题不同
- JSF 2 resources with CDN?. I am not looking to place my resources on a CDN, but to have my resources stay on my server but are pushed towards a CDN.
- Change /javax.faces.resource prefix of resource URLs. I don't want to change the prefix. I want only to change the suffix. I would want
<link type="text/css" rel="stylesheet" href="/javax.faces.resource/main03.css.xhtml?ln=styles">
to become :<link type="text/css" rel="stylesheet" href="/javax.faces.resource/main03.css?ln=styles">
WITHOUTthe.xhtml
extension. - Changing JSF prefix to suffix mapping forces me to reapply the mapping on CSS background images. Since I have no issue with loading the resources. The site works, we are simply having a hard time differrentiating a webpage from a resource (Since we are looking at the extention alone).
- 带 CDN 的 JSF 2 资源?. 我不打算将我的资源放在 CDN 上,而是让我的资源留在我的服务器上,但被推向 CDN。
- 更改资源 URL 的 /javax.faces.resource 前缀。我不想更改前缀。我只想更改后缀。我想
<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">
WITHOUT的.xhtml
扩展。 - 将 JSF 前缀更改为后缀映射迫使我在 CSS 背景图像上重新应用映射。因为我对加载资源没有问题。该网站有效,我们只是很难将网页与资源区分开来(因为我们只查看扩展名)。
Reasoning
推理
Sure you might be asking me why I need this. Well, we are moving our application to be served by the Akamai CDN.
当然你可能会问我为什么需要这个。好吧,我们正在将我们的应用程序转移到 Akamai CDN 提供服务。
The issue we are having with the integration of the site is that we are trying to cache static content on the edge servers. This is done by matching file extensions (ie: .js, .doc, .png, css, etc). We cannot match xhtml
because this would be caching all pages as well as static content. Which by that would cause problems with sessions and such.
我们在站点集成中遇到的问题是我们正在尝试在边缘服务器上缓存静态内容。这是通过匹配文件扩展名(即:.js、.doc、.png、css 等)来完成的。我们无法匹配,xhtml
因为这会缓存所有页面以及静态内容。这会导致会话等问题。
Attempted Solution
尝试的解决方案
In line with the answer by BalusC, I have implemented the resource handler as suggested. I will not rewrite code here, since it is in answer below.
根据 BalusC 的回答,我已经按照建议实现了资源处理程序。我不会在这里重写代码,因为它在下面的答案中。
However, I am getting an error when loading composite components. I am getting an error as such :
但是,加载复合组件时出现错误。我收到这样的错误:
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)
...
Composite component is loaded correctly because if I "unregister" the new ResourceHandler
we just created it will load. The stack trace leads me to believe that it is trying to find this component in a java class, instead of finding it in the resources. According to grepcode
this would be at this last line (975) where the error happens :
复合组件已正确加载,因为如果我“取消注册”ResourceHandler
我们刚刚创建的新组件,它将加载。堆栈跟踪让我相信它正在尝试在 java 类中找到这个组件,而不是在资源中找到它。根据grepcode
这将在最后一行(975)发生错误:
String packageName = componentResource.getLibraryName();
String className = componentResource.getResourceName();
className = packageName + '.' + className.substring(0, className.lastIndexOf('.'));
Meaning that the resourceName
, aka className
is null
since the error I am getting is java.lang.NullPointerException
. I can't seem to figure out how/where the ResourceHandler
is called vis-a-vis a composite component. Any help figuring out this last issue?
这意味着resourceName
,又名className
是null
因为我得到的错误是java.lang.NullPointerException
. 我似乎无法弄清楚ResourceHandler
相对于复合组件如何/在哪里调用它。对解决最后一个问题有帮助吗?
回答by BalusC
This is doable with a custom ResourceHandler
which returns in createResource()
a Resource
which in turn returns an "unmapped" URL on Resource#getRequestPath()
. You only need to add the default JSF resource prefix /javax.faces.resource/*
to the <url-pattern>
list of the FacesServlet
mapping in order to get it to be triggered anyway.
这是可行的具有自定义ResourceHandler
它返回createResource()
一个Resource
这反过来又返回上一个“未映射”的URL Resource#getRequestPath()
。您只需要将默认的 JSF 资源前缀添加/javax.faces.resource/*
到映射<url-pattern>
列表中FacesServlet
,以便无论如何都能触发它。
Further, you need to override isResourceRequest()
to check if the URL starts with the JSF resource prefix and also the handleResourceRequest()
to locate and stream the proper resource.
此外,您需要覆盖isResourceRequest()
以检查 URL 是否以 JSF 资源前缀开头,以及handleResourceRequest()
定位和传输正确的资源。
All with all, this should do:
总之,这应该做:
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;
}
}
Register it as follows in faces-config.xml
:
注册如下faces-config.xml
:
<application>
<resource-handler>com.example.UnmappedResourceHandler</resource-handler>
</application>
Extend the FacesServlet
URL pattern with ResourceHandler.RESOURCE_IDENTIFIER
:
使用以下命令扩展FacesServlet
URL 模式ResourceHandler.RESOURCE_IDENTIFIER
:
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
<url-pattern>/javax.faces.resource/*</url-pattern>
</servlet-mapping>
回答by chkal
You could have a look at Rewrite. Rewrite allows to modify URLs that are rendered to the page and modify them in any way you want. You could do something like this to add a CDN To your site:
你可以看看Rewrite。重写允许修改呈现到页面的 URL,并以您想要的任何方式修改它们。您可以执行以下操作将 CDN 添加到您的站点:
.addRule(CDN.relocate("{p}foo-{version}.css")
.where("p").matches(".*")
.where("version").matches(".*")
.to("http://mycdn.com/foo-{version}.css"));
I think it should be easy to implement your requirement using Rewrite.
我认为使用 Rewrite 实现您的要求应该很容易。
Have a look at the example configurationsto learn about the features of rewrite.
查看示例配置以了解重写的功能。