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

Posted

技术标签:

【中文标题】当通过链接或后退按钮打开时,强制 JSF 刷新页面/视图/表单【英文标题】:Force JSF to refresh page / view / form when opened via link or back button 【发布时间】:2016-07-26 17:36:23 【问题描述】:

我有一个将数据发布到外部页面的 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>

【问题讨论】:

【参考方案1】:

该页面可能是从浏览器缓存中加载的。这本质上是无害的,但确实让最终用户感到困惑,因为他/她错误地认为它确实来自服务器。您可以通过查看浏览器的 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/* 是您要关闭浏览器缓存的示例 URL 模式。如有必要,您可以将其映射到 /**.xhtml 甚至 servletNames="Faces Servlet"

如果你碰巧使用了 JSF 实用程序库 OmniFaces,那么你可以使用它的内置 CacheControlFilter,只需将以下条目添加到 web.xml(它演示了在 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>

另请参阅showcase。

【讨论】:

假设我不想缓存我的第三页。当我的第一页呈现时,我的 bean 将被创建/初始化。如果取决于我的第一页或第二页,数据将填充到第三页并从这里发布。如果我们指示浏览器正确创建/初始化 bean此时,那么我在渲染第一页和第二页期间的数据集将丢失。如何克服这个 BalusC? @OscarSmith:另一种“解决方案”可能有效,但不是正确的方法。 为什么不呢?它允许对不同的页面进行特定的控制,并且没有明显的缺点。 我不确定,但不应该是chain.doFilter(request, response);而不是chain.doFilter(req, res);吗? @Hendrik:不,它们的值完全相同。只是一个不同的参考。你知道,Java 是面向对象的。当引用不同时,它不会复制值。另见例如***.com/a/3330884【参考方案2】:

我找到了一个适用于 JSF 的解决方案,而无需创建 servlet 过滤器。只需将下面的行添加到您的 .xhtml 页面即可。

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

【讨论】:

这个答案更干净。有没有办法用更新的 JSF 特性来清理它?

以上是关于当通过链接或后退按钮打开时,强制 JSF 刷新页面/视图/表单的主要内容,如果未能解决你的问题,请参考以下文章

当用户在 JSF 中注销后单击后退按钮时重定向到登录页面 [重复]

如何处理后退按钮android以退出应用程序并在首页中打开时关闭本机导航侧菜单

按下后退按钮时强制重新加载/刷新

当用户再次导航返回和前进时强制刷新/重新加载

如何在 jQuery 中强制页面刷新或重新加载?

Chrome 后退按钮页面刷新 - ASP.net