通过链接或后退按钮打开时,强制JSF刷新页面/视图/表单

时间:2012-12-31 12:05:22

标签: jsf back-button browser-refresh html-post

我有一个JSF页面,它将数据发布到外部页面。 数据从JSF托管bean加载,该bean在后期数据中生成唯一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>

2 个答案:

答案 0 :(得分:9)

该页面很可能是从浏览器缓存中加载的。这基本上是无害的,但确实让最终用户感到困惑,因为他/她错误地认为它确实来自服务器。您可以通过查看浏览器Web开发人员工具集中的HTTP流量监视器轻松确认这一点(按Chrome / FireFox23 + / IE9 +中的F12并选中“网络”部分)。

你基本上需要告诉浏览器不要缓存(动态)JSF页面。这样浏览器实际上会向服务器请求页面(并因此触发托管bean的正确创建/初始化等),而不是从其缓存中显示先前请求的那个。

一般来说,这是通过简单的servlet filter完成的,如下所示:

@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/*是您要关闭浏览器缓存的示例网址格式。如有必要,您可以在/**.xhtml甚至servletNames={"Faces Servlet"}上进行映射。

如果您碰巧使用JSF实用程序库OmniFaces,那么只需将以下条目添加到web.xml(它演示{{1}上的直接映射)即可使用其内置CacheControlFilter意味着每个动态JSF页面都不会被缓存):

FacesServlet

另请参阅showcase

答案 1 :(得分:4)

我找到了一个适用于JSF的解决方案,而无需创建servlet-filter。只需将下面的行放在.xhtml页面上即可。

<f:event type="preRenderView" listener="#{facesContext.externalContext.response.setHeader('Cache-Control', 'no-cache, no-store')}" />