为了提供正确的浏览器缓存,我想摆脱Apache MyFaces Orchestra为每个请求添加conversationContext
参数,以获取对css文件的请求。
正如Bozho建议的那样,我已经实现了一个过滤器来设置Orchestra正在寻找的属性。
public class ResourceFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse theResponse, FilterChain theChain) throws IOException, ServletException {
if(shouldNotAppendConversation(request)) {
request.setAttribute(RequestParameterServletFilter.REQUEST_PARAM_FILTER_CALLED, Boolean.TRUE);
}
theChain.doFilter(request, theResponse);
}
private boolean shouldNotAppendConversation(ServletRequest theRequest) {
HttpServletRequest aRequest = (HttpServletRequest) theRequest;
String aPath = aRequest.getRequestURI();
if(aPath.endsWith(".css.jsf")) {
return true;
}
return false;
}
@Override
public void init(FilterConfig theFilterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
这不起作用参数仍附加到每个请求。在调试时,我发现过滤器首先受到对jsf站点的请求的影响。我确实希望在该请求中包含conversation context
,因此过滤器会将请求直接转发到链中的下一个过滤器。命中过滤器的下一个请求(通常是对css文件的请求)已经包含在请求中的conversation context
。
奇怪的是,如果我将过滤器修改为始终设置属性,则所有请求都不会具有conversation context
属性。但这意味着,conversation context
也不包含在jsf网站的请求中(但应该)。
我注意到jsf网站生成的html中的css文件链接也包含conversation context
属性,具体取决于过滤器实现。我想因为这个原因,第二个请求已经包含了conversation context
参数?
我不明白为什么Orchestra会将conversation context
参数附加到每个请求,而不仅仅是未设置属性的请求。
如何实现过滤器才能正常工作?
答案 0 :(得分:3)
下一个请求(例如对于CSS文件)在请求到您的页面之后点击您的过滤器已经包含conversationContext
参数只是因为这是该资源的URL已被页面呈现的方式先前的请求。
因此,应在渲染时对conversationContext
进行控制。以下解决方案适用于JSF 2(我使用的是Mojarra 2.1.11,myfaces-orchestra-core20 1.5,RichFaces 4.1.0.Final)。一个特殊的servlet过滤器什么都不做,只用我们自己的包装器包装HttpServletResponse
:
public class RfOrchestraParamControlFilter implements Filter {
...
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
response = new RfOrchestraParamControlResponseWrapper((HttpServletResponse)response);
chain.doFilter(request, response);
}
...
}
响应包装器测试要为being a richfaces resource编码的url,并在当前线程中打开Orchestra的ConversationRequestParameterProvider
分离模式进行编码:
package ...
import javax.faces.application.ResourceHandler;
import org.richfaces.resource.ResourceHandlerImpl;
import org.apache.myfaces.orchestra.conversation.ConversationRequestParameterProvider;
public class RfOrchestraParamControlResponseWrapper extends HttpServletResponseWrapper {
public RfOrchestraParamControlResponseWrapper(HttpServletResponse httpServletResponse) {
super(httpServletResponse);
}
@Override
public String encodeURL(String url) {
if (url.contains(ResourceHandler.RESOURCE_IDENTIFIER) || url.contains(ResourceHandlerImpl.RICHFACES_RESOURCE_IDENTIFIER)) {
boolean current = ConversationRequestParameterProvider.isInSeparationMode();
/* Disable conversationContext parameter in current thread for the time of rendering link to a resource */
ConversationRequestParameterProvider.setInSeparationMode(true);
String result = super.encodeURL(url);
/* Restore */
ConversationRequestParameterProvider.setInSeparationMode(current);
return result;
}
else return super.encodeURL(url);
}
}
(在测试作为资源的url作为上下文路径时,我不得不使用String.contains()
而不是String.startsWith()
,并且servlet路径恰好在传递的url前面添加。)
然而,到目前为止,这无济于事。原因是Orchestra在其RequestParameterFacesContextFactory
中使用自己的响应包装,并且在我们的过滤器被击中后发生。通过这种方式,Orchestra的包装结果证明是我们的包装器外部导致我们的包装器接收url
为时已晚,当网址已被拦截且conversationContext
附加。
为了避免这种情况,我们可以通过将RequestParameterFacesContextFactory
拦截器的效果替换为实际does the same work的RequestParameterServletFilter
来使我们的响应包装器在Orchestra的外部。不幸的是,使用另一个过滤器并不是很精致我们可能没有,但到目前为止我还没有看到另一种方法。
所以,在web.xml
中将过滤器放在 Orchestra之后:
<filter>
<filter-name>requestParameterFilter</filter-name>
<filter-class>org.apache.myfaces.orchestra.requestParameterProvider.RequestParameterServletFilter</filter-class>
</filter>
<filter>
<filter-name>myOrchestraFilter</filter-name>
<filter-class>mypkg.RfOrchestraParamControlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestParameterFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>myOrchestraFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
答案 1 :(得分:0)
无法使先前的解决方案起作用。我是这样做的:
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.stream.Collectors;
import javax.faces.application.ResourceHandler;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URIBuilder;
/**
* @author Felipe Riccetto
*/
public class RemoveConversationParamFilter implements Filter {
public static String removeQueryParameter(final String url,
final String parameterName) throws URISyntaxException {
URIBuilder uriBuilder = new URIBuilder(url);
List<NameValuePair> queryParameters = uriBuilder.getQueryParams()
.stream().filter(p -> !p.getName().equals(parameterName))
.collect(Collectors.toList());
if (queryParameters.isEmpty()) {
uriBuilder.removeQuery();
} else {
uriBuilder.setParameters(queryParameters);
}
return uriBuilder.build().toString();
}
@Override
public void destroy() {
// nothing
}
@Override
public void doFilter(final ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp2 = new HttpServletResponseWrapper(
(HttpServletResponse) resp) {
@Override
public String encodeURL(String url) {
String s = super.encodeURL(url);
try {
String urlPath = new URL(
((url.toLowerCase().startsWith("http://")
|| url.toLowerCase().startsWith("https://"))
? ""
: "http://fake")
+ url).getPath().toString().toLowerCase();
if (urlPath.endsWith(".js") || urlPath.endsWith(".css")
|| urlPath.endsWith(".png")
|| urlPath.endsWith(".jpeg")
|| urlPath.endsWith(".jpg")
|| urlPath.endsWith(".gif") || urlPath.contains(
ResourceHandler.RESOURCE_IDENTIFIER)) {
s = removeQueryParameter(s, "conversationContext");
}
} catch (MalformedURLException | URISyntaxException e) {
// ignore
}
return s;
}
};
chain.doFilter(req, resp2);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// nothing
}
}
web.xml:
<filter>
<filter-name>RemoveConversationParamFilter</filter-name>
<filter-class>RemoveConversationParamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RemoveConversationParamFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
此最后一个映射必须是您的web.xml中的最后一个