浏览器返回+ viewscope bean

ber*_*tie 12 back-button jsf-2

问题是:点击浏览器后退按钮会发生什么 - >打开一个已经销毁了viewscoped-managedbean的页面 - >从该页面的commandButton提交一个带有网格记录选择的请求?

我的期望:重新创建关联的viewscope-managebean,接收网格记录选择,并处理它们,就像从不涉及浏览器后退按钮一样.

我的经验:相关的viewscope-managebean不会重新创建,也不会接收网格记录选择.必须重新输入URL,或者在点击浏览器后退按钮后重新输入F5才能再次正常工作.

所以这是成功的场景,所有的bean都是视图编组的bean:

  1. 在@PostConstruct中创建了page1.xhtml - > page1Bean,查询数据等
  2. 检查/选择数据表中的多条记录,单击"处理"按钮
  3. page1Bean的进程方法将选定的记录存储在flash对象中,并重定向到page2.xhtml
  4. page1Bean被破坏,page2Bean被创建,并且在preRenderView监听器方法中,从flash对象中获取所选记录,并处理它们
  5. 单击"转到主页面"commandButton重定向到page1.xhtml,并且page2Bean被销毁,page1Bean再次创建
  6. 从2号到5号的循环仍然可行

现在,这是涉及浏览器后退按钮的错误情况(从#6开始发生的不同事情):

  1. 在@PostConstruct中创建了page1.xhtml - > page1Bean,查询数据等
  2. 检查/选择数据表中的多条记录,单击"处理"按钮
  3. page1Bean的进程方法将选定的记录存储在flash对象中,并重定向到page2.xhtml
  4. page1Bean被破坏,page2Bean被创建,并且在preRenderView监听器方法中,从flash对象中获取所选记录,并处理它们
  5. 单击浏览器后退按钮page2Bean未销毁,未创建page1Bean
  6. 检查/选择数据表中的多条记录,单击"处理"按钮
  7. page1Bean方法执行(奇怪,因为page1Bean应该被销毁),但无法看到所做的记录选择,并重定向到page2.xhtml
  8. page1Bean没有被销毁(没有日志记录输出),没有创建page2Bean(因为它没有被销毁),像往常一样执行preRenderView监听器,但这一次,flash对象中没有选定的记录

是否可以使用带有浏览器后退按钮的viewscope-beans获得正常体验(就像没有浏览器后退按钮一样)?

这是我的依赖:

<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.faces</artifactId>
    <version>2.1.3</version>
    <scope>compile</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)

请分享您的想法!

Bal*_*usC 16

浏览器似乎已从其缓存提供页面,而不是向服务器发送完整的HTTP GET请求,而您将JSF状态保存方法设置为server(这是默认值).

有两种方法可以解决这个问题:

  1. 告诉浏览器不要缓存动态JSF页面.您可以借助过滤器来完成此操作.

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
    
        if (!req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
            res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
            res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
            res.setDateHeader("Expires", 0); // Proxies.
        }
    
        chain.doFilter(request, response);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    将过滤器映射到FacesServlet相同的URL模式.

  2. 将JSF状态保存方法设置为client,以便将整个视图状态存储在表单的隐藏字段中,而不是存储在服务器端的会话中.

    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>
    
    Run Code Online (Sandbox Code Playgroud)

过滤方式是优选的.