h:commandButton 不能与 JSF bean 一起工作,而页面正在加载

Posted

技术标签:

【中文标题】h:commandButton 不能与 JSF bean 一起工作,而页面正在加载【英文标题】:h:commandButton not working with JSF bean, while page is loading 【发布时间】:2016-04-25 22:06:48 【问题描述】:

问题:h:commandButton ajax 在页面加载时无法使用 JSF bean。

一个 JSF 页面的列表很长(加载需要几秒钟):

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:co="http://java.sun.com/jsf/composite/standart/components"> 

    <h:form id="myForm"> 
        <div><h:outputLabel value="My name is #myViewBean.name" /></div>
        <h:commandButton
            action="#myViewBean.actRedirectToAnotherView()" 
            value="Redirect"/>                
        <h:dataTable value="#myViewBean.bigList" var="entity">
            <h:column>
                #entity
            </h:column>
        </h:dataTable>
    </h:form>
</html>

和托管视图范围 bean “MyViewBean”:

package mypackage;

import java.util.ArrayList;
import java.util.List;
import javax.inject.Named;
import org.springframework.context.annotation.Scope;

@Named
@Scope(value = "view")
public class MyViewBean 

    private static int beanNrCounter = 0;
    private static final List<String> bigList = new ArrayList();
    static 
        for (int i = 0; i < 100000; i++) 
            bigList.add("Item in big list " + i);
        
    

    private final String name;

    public MyViewBean() 
        beanNrCounter++;
        name = "BEAN NR " + beanNrCounter;
        System.out.println("Created MyViewBean with name " + name);  
    

    public String actRedirectToAnotherView() 
        String viewName = "anotherView.jsf";//actually some complex operation which decides where to redirect user 
        System.out.println("Redirecting to another view " + viewName );
        return viewName + "&faces-redirect=true";
    

    public String getName() 
        return name;
    

    public List<String> getBigList() 
        return bigList;
    


如果我在页面加载过程中单击“重定向”按钮方法“actRedirectToAnotherView”不执行,而是创建了另一个“MyViewBean”bean。如果我点击按钮然后页面已经加载,一切都按预期工作。

我已经检查过,然后单击“重定向”按钮,如果页面已加载表单参数 javax.faces.ViewState 通过 ajax 帖子传递,但如果页面正在加载 - javax.faces.ViewState 丢失(所以当然新视图已创建)。

如果我将托管 bean 的范围更改为“请求”问题仍然存在(“重定向”按钮仍然不起作用,actRedirectToAnotherView 不会执行)。

如何在页面加载时修复 ajax 行为? 在我看来,只要访问 MyViewBean,客户端就知道 javax.faces.ViewState,所以无论页面是否已经加载,都应该传递 javax.faces.ViewState。

我正在使用:

JSF 莫哈拉 (2.2.6) Spring:“视图范围”是通过示例完成的 https://github.com/michail-nikolaev/primefaces-spring-scopes/blob/master/primefaces-scopes-test/src/main/java/org/nkey/primefaces/scopes/test/spring/scope/ViewScope.java Primefaces (5.1)

【问题讨论】:

最安全的做法是在延迟加载或加载页面的部分内容时阻止页面(= 不同于例如延迟数据表) 可能 Kukeltje 提出的两种解决方案都可行。只是阻塞不是最用户友好的解决方案,延迟加载只会让问题不那么明显(对于非常慢的互联网连接,它仍然存在)。对我来说看起来很奇怪,几乎所有基于 jsf ajax 的功能在页面加载时都无法按预期工作(在互联网连接缓慢时很容易注意到) 除了具体的问题,你为什么要使用 POST 进行导航?使用&lt;h:button&gt; 这只是用最少的代码展示问题的原型。 actRedirectToAnotherView 方法执行一些“业务逻辑”,并“决定”将用户重定向到哪里。我将更新代码示例以使其“合乎逻辑”。 好的。它真的必须与表格的形式相同吗?表中似乎没有与请求相关的任何输入。否则,只需将按钮放在自己的形式中。你知道,每个表单一个
【参考方案1】:

看看这个例子,希望对你有用

小脸:

<h:form>
    <h:commandLink value="show" action="#showProducts.toggleShow">
        <f:ajax render="products"/>
    </h:commandLink>
    <h:panelGroup id="products">
        <h:dataTable var="product" value="#showProducts.products" rendered="#!showProducts.show">
            <h:column>#product.name</h:column>
        </h:dataTable>
    </h:panelGroup>
</h:form>

对于托管 Bean

private List<Product> products;

@PostConstruct
public void init() 
    products = this.getProductManager().getProducts();


public List<Product> getProducts() 
    return products;

Or if it actually needs to be lazily loaded, then rather do so:

private List<Product> products;

public List<Product> getProducts() 
    if (products == null) 
        products = this.getProductManager().getProducts();
    
    return products;

【讨论】:

我不确定它对我的情况有何帮助(我没有在 getter 中进行任何昂贵的操作,我的列表是静态的,并且在应用程序启动期间加载一次)。问题在于 javax.faces.ViewState 在页面加载时未传递(页面约为 7Mb,因此自然需要几秒钟)

以上是关于h:commandButton 不能与 JSF bean 一起工作,而页面正在加载的主要内容,如果未能解决你的问题,请参考以下文章

h:commandbutton,如何重定向到外部站点?(JSF 2)[重复]

Java EE 7 JSF Facelet h:commandButton 操作重定向到页面 [重复]

h:commandbutton 与 ajax 调用错误的操作方法

h:button 和 h:commandButton 之间的区别

需要将 jQuery 验证插件与 jsf 集成

h:button和h:commandButton之间的区别