我有一个JSF页面,它将数据发布到外部页面。数据是从JSF托管bean加载的,该bean在post数据中生成唯一的ID。
我有一个问题,用户单击结帐按钮,然后导航回同一页面,并再次按下结帐按钮。帖子数据没有更新。而且,根本不调用bean。是否有办法强制JSF重新加载页面和表单数据?
<form action="#{checkoutBean.externalUrl}" method="post"
id="payForm" name="payForm">
<input type="hidden" value="#{checkoutBean.uniqueID}" />
<input type="submit" value="Proceed to Checkout" />
</form>
该页面可能正在从浏览器缓存中加载。这基本上是无害的,但确实会使最终用户感到困惑,因为他/她错误地认为它实际上来自服务器。您可以通过查看浏览器的web开发人员工具集中的HTTP流量监视器来轻松确认这一点(在Chrome/FireFox23+/IE9+中按F12并勾选"网络"部分)。
基本上需要告诉浏览器不要缓存(动态)JSF页面。这样,浏览器将实际向服务器请求页面(从而触发托管bean的适当创建/初始化等等),而不是从缓存中显示先前请求的页面。
一般来说,这是通过一个简单的servlet过滤器来完成的,如下所示:@WebFilter("/app/*")
public class NoCacheFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (!request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(req, res);
}
// ...
}
其中/app/*
是您希望关闭浏览器缓存的示例URL模式。如有必要,您可以将其映射到/*
, *.xhtml
甚至servletNames={"Faces Servlet"}
上。
如果您碰巧使用JSF实用程序库OmniFaces,那么您可以通过向web.xml
添加以下条目来使用其内置的CacheControlFilter
(它演示了FacesServlet
上的直接映射,这意味着每个动态JSF页面都不会被缓存):
<filter>
<filter-name>noCache</filter-name>
<filter-class>org.omnifaces.filter.CacheControlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>noCache</filter-name>
<servlet-name>facesServlet</servlet-name>
</filter-mapping>
我找到了一个适用于JSF而无需创建servlet过滤器的解决方案。把下面这行放到你的。xhtml页面中。
<f:event type="preRenderView" listener="#{facesContext.externalContext.response.setHeader('Cache-Control', 'no-cache, no-store')}" />
您可以通过在单击按钮时调用的方法的末尾添加这行代码轻松刷新页面:Faces.refresh();