【问题标题】:How to reuse Primefaces datatable with different data in different browser tabs?如何在不同的浏览器选项卡中重用具有不同数据的 Primefaces 数据表?
【发布时间】:2019-05-31 06:46:17
【问题描述】:

我的应用程序在 url 中有一个查询参数,用于在数据表中使用相同的 xhtml(所有动态内容)呈现不同的数据。

bean的作用域是会话作用域,数据表渲染所有数据,并且有很多输入元素可以打开不同的对话框。

如果我打开另一个发送不同查询参数的浏览器选项卡,数据表将完美呈现,但是如果我返回第一个选项卡,所有命令链接都不会调用操作,整个应用程序将开始非常不稳定。

根据我的研究,这是因为我更改了数据表中的数据,我尝试使用动态 ID、动态小部件名称对其进行命名,但似乎没有任何效果。

<f:metadata>
  <f:viewParam name="param" value="#{moduleBean.param}"/>
  <f:viewAction action="#{moduleBean.setup}" />
</f:metadata>

<c:set var="module" value="#{moduleBean.param}" />

<p:dataTable id="#{module}-dataTable" value="#{moduleBean.model[module]}" var="data">

  <p:commandLink action="#{moduleBean.openModuleDetails}" update=":#{module}-searchDialog" oncomplete="PF('#{module}-searchWidget').show();">
    <f:param name="module" value="#{module}" />
    <f:param name="dataRow" value="#{data.dbKey}" />
  </p:commandLink>
</p:dataTable>


@Named
@javax.faces.view.ViewScoped
public class ModuleBean implements Serializable {

   private String param;

   public void setup() throws IOException {
      this.model.put(this.param, new LazyDataModel(this.param));
   }

    public Map<String, LazyDataModel> getModel() {
        return model;
    }
}

这会在每个选项卡中使用所有正确的 id 构建所有预期的 html,但是 JSF 仍然没有处理 commandlink 中的操作。不用说,如果我只使用一个浏览器标签,一切都会完美运行。

有时它会在链接中单击两次后开始工作,但在浏览器选项卡之间来回切换最终总是会崩溃。

向命令链接添加动作侦听器也没有解决问题。

关于如何使 JSF 将相同的数据表视为同一页面上的不同实体但具有不同参数的任何建议?

【问题讨论】:

    标签: jsf primefaces datatable cdi


    【解决方案1】:

    在不了解底层 bean 的情况下 - 如果您将 moduleBean 放在 @SessionScoped 中,这将是预期的行为。会话(和会话范围的 bean)在浏览器选项卡之间共享。因此,您不能依赖来自两个不同选项卡的基础值。

    尝试将表数据的支持值更改为@RequestScoped/@ViewScoped

    这是一个完整的解决方案,请注意,它使用 PrimeFaces 6.2、Apache Commons 和 Lombok;

    @Data
    @Named
    @ViewScoped
    public class TableTestBackingBean implements Serializable {
        private int param;
    
        @Inject
        private PersonsBean personsBean;
    
        public void onClicked() {
            System.out.println("Clicked fine!");
        }
    
        public List<Person> getPersons() {
            return personsBean.getPersons()[param];
        }
    }
    
    @Data
    @ApplicationScoped
    public class PersonsBean {
        @Data
        @AllArgsConstructor
        public class Person {
            private String firstName;
            private String lastName;
            private int age;
        }
    
        private List<Person> persons[];
    
        @PostConstruct void init() {
            persons = new List[4];
    
            for (int j = 0; j < 4; j++) {
                persons[j] = new ArrayList<>();
    
                for (int i = 0; i < 30; i++) {
                    final String firstName =
                        RandomStringUtils.randomAlphanumeric(10);
                    final String lastName = 
                        RandomStringUtils.randomAlphanumeric(10);
                    final int age = RandomUtils.nextInt(0, 120);
    
                    persons[j].add(new Person(firstName, lastName, age));
                }
            }
        }   
     }
    
    <?xml version="1.0" encoding="UTF-8"?>
    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
          xmlns:p="http://primefaces.org/ui" xmlns:f="http://java.sun.com/jsf/core">
        <f:metadata>
            <f:viewParam name="param" value="#{tableTestBackingBean.param}"/>
        </f:metadata>
        <h:head>
                <title>Test</title>
        </h:head>
        <h:body>
            <p:dataTable value="#{tableTestBackingBean.persons}" var="t">
                <p:column headerText="First Name"><h:outputText value="#{t.firstName}" /></p:column>
                <p:column headerText="Last Name"><h:outputText value="#{t.lastName}" /></p:column>
                <p:column headerText="Age"><h:outputText value="#{t.age}" /></p:column>
            </p:dataTable>
            <h:form>
                <p:commandButton action="#{tableTestBackingBean.onClicked}" value="Click Me!" />
            </h:form>
        </h:body>
    </html>
    

    这对表数据使用应用程序范围的 bean,使其完全保持静态。这可以顺利工作,并且表格会根据 param 中传递的参数以不同的方式呈现数据。

    【讨论】:

    • 最好使用@ViewScoped bean 进行ajax 分页、过滤和选择
    • 我知道它们是共享的,这就是为什么将分页结果返回到数据表的模型是一个地图,它可以由视图发送的参数访问。我将所有分页结果和数据保存在支持 bean 中,所以它仍然应该采用正确的。不幸的是,它还不足以让它发挥作用
    • ViewScoped 由于某种原因根本无法工作。这就是我使用会话的原因
    • 但是#{moduleBean.param} 的共享对于所有页面来说都非常有效。然后第一页的初始模型与您打开 page2 时使用的模型不同。如果您不使用 c:set 但始终直接使用参数,它也可能会起作用。你有效地创建了一个windowscoped,我打算建议使用它。见 deltaspike!
    • 我实际上检查了所有页面的#{moduleBean.param} 并不相同。它实际上解析为发送的正确查询参数,并使用它来命名所有表和组件,在视图中工作,并在支持 bean 中工作。只是数据表有点混乱
    猜你喜欢
    • 1970-01-01
    • 2013-12-28
    • 2014-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多