JSF 2 basic @RequestScoped CRUD



>我有这些简单的页面:

列表.xhtml

<h:form id="form">  
    <h:dataTable value="#{testBean.model}" var="elem">
        <h:column>
            <f:facet name="header">code</f:facet>
            #{elem.code}
        </h:column>
        <h:column>
            <f:facet name="header">description</f:facet>
            #{elem.description}
        </h:column>
        <h:column>
            <f:facet name="header">action</f:facet>
            <h:commandButton action="#{testBean.edit(elem)}" value="edit"/>
        </h:column>
    </h:dataTable>
</h:form>

编辑.xhtml

<h:form id="form">
    <h:panelGrid columns="2">
        <h:outputLabel value="code"/>
        <h:inputText value="#{testBean.selection.code}"/>
        <h:outputLabel value="description"/>
        <h:inputText value="#{testBean.selection.description}"/>
    </h:panelGrid>
    <h:commandButton action="#{testBean.update}" value="update"/>
</h:form>

而这个豆子:

@ManagedBean
public class TestBean implements Serializable
{
    private static final long serialVersionUID = 1L;
    @EJB
    private PersistenceService service;
    private Object selection;
    private List<UnitType> model;
    @PostConstruct
    public void init()
    {
        model = service.findAll(UnitType.class);
    }
    public String edit(Object object)
    {
        System.out.println(Tracer.current(object));
        setSelection(object);
        return "edit";
    }
    public String update()
    {
        System.out.println(Tracer.current(selection));
        return "list";
    }
    // getters and setters
}

所以表格被渲染,当我单击其中一个"编辑"按钮时,它会导航到显示填充输入的"edit.jsf",但是当我单击"更新"按钮时,它给了我此错误:

javax.el.PropertyNotFoundException: /test2/edit.xhtml @27,54 value="#{testBean.selection.code}": Target Unreachable, 'null' returned null

请注意,我知道如何实现一个@ViewScoped接口来管理 CRUD 操作,但这是一个简单的概念证明,我需要更好地理解 JSF 生命周期。

所以我希望"testBean"是@RequestScoped


更新尝试f:viewParam,仍然不明白...

列表.xhtml

<?xml version="1.0" encoding="ISO-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
    <h:head>
        <title>test list</title>
    </h:head>
    <h:body>
        <h:messages/>
        <h:form id="form">
            <h:dataTable value="#{testBean2.model}" rows="10" var="elem">
                <h:column>
                    <f:facet name="header">converterString</f:facet>
                    #{elem.converterString}
                </h:column>
                <h:column>
                    <f:facet name="header">first name</f:facet>
                    #{elem.firstName}
                </h:column>
                <h:column>
                    <f:facet name="header">last name</f:facet>
                    #{elem.lastName}
                </h:column>
                <h:column>
                    <f:facet name="header">action</f:facet>
                    <h:commandButton action="#{testBean2.edit}" value="edit">
                        <f:param name="entity" value="#{elem.converterString}"/>
                    </h:commandButton>
                    <h:commandButton action="#{testBean2.edit2}" value="edit2">
                        <f:param name="entity" value="#{elem.converterString}"/>
                    </h:commandButton>
                </h:column>
            </h:dataTable>
        </h:form>
    </h:body>
</html>

编辑.xhtml

<?xml version="1.0" encoding="ISO-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
    <f:metadata>
        <f:viewParam id="entityParam" name="entity" value="#{testBean2.selection}" converter="entityConverter" required="true"/>
    </f:metadata>
    <h:head>
        <title>test edit</title>
    </h:head>
    <h:body>
        <h:messages/>
        <h:form id="form">
            <h:panelGrid columns="2">
                <h:outputLabel value="selection"/>
                <h:outputText value="#{testBean2.selection.converterString}"/>
                <h:outputLabel value="firstName"/>
                <h:inputText value="#{testBean2.selection.firstName}"/>
                <h:outputLabel value="lastName"/>
                <h:inputText value="#{testBean2.selection.lastName}"/>
            </h:panelGrid>
            <h:commandButton action="#{testBean2.update}" value="update" ajax="false">
                <f:param name="entity" value="#{testBean2.selection.converterString}"/>
            </h:commandButton>
        </h:form>
    </h:body>
</html>

测试豆2.java

@ManagedBean
public class TestBean2 implements Serializable
{
    private static final long serialVersionUID = 1L;
    @EJB
    private PersistenceService service;
    private Object selection;
    private List<Person> model;
    @PostConstruct
    public void init()
    {
        Tracer.out();
        model = service.queryAll(Person.class);
    }
    public String edit()
    {
        JsfUtils.addSuccessMessage("edited");
        return "edit";
    }
    public String edit2()
    {
        JsfUtils.addSuccessMessage("edited");
        return "edit?faces-redirect=true&amp;includeViewParams=true";
    }
    public void update()
    {
        Tracer.out(selection);
        JsfUtils.addSuccessMessage("updated");
    }
    // getters and setters
}

如果我按"编辑"按钮,它会转到edit页面,但选择为空并且不显示任何消息。

如果我按"edit2"按钮,它会转到edit页面,但选择为空,显示所需的消息并且 URL edit.jsf?entity=

我做错了什么?

据我了解,当您的第二个请求来测试Bean时,选择对象为空。如果使用会话 Bean 运行此命令,则可能不会收到此错误。

在我看来

,没有干净的方法可以实现你想要的。

我建议您简单地在请求之间传递 Id attr 作为简单的请求参数。因此,在 post 构造函数中,检查参数值是否已设置,并在此基础上在持久性层中执行查看。

或者,使用已有的设置,绑定:

<h:inputText value="#{testBean.selection.code}"/>

组件到您的后备 Bean 中,并在必要时调用getValue()。无论哪种方式,仍然不整洁。

如果您发现任何其他方式,请告诉我们。

最后我找到了一种方法:数据将处于较长的范围,简而言之

请注意,这只是一个概念证明,而不是一个真实的用例。并且要注意,在处理@RequestScope豆时,PrimeFaces lazy DataTable 模型范围

@ManagedBean
public class TestBean
{
    @EJB
    private PersistenceService service;
    @ManagedProperty("#{viewScope.item}")
    private Item item;
    @ManagedProperty("#{sessionScope.model}")
    private EntityDataModel<Item> model;
    @PostConstruct
    public void init()
    {
        if(model == null)
        {
            model = new EntityDataModel<Item>(Item.class);
            Faces.setSessionAttribute("model", model);
        }
    }
    public String update()
    {
        Faces.getFlash().setKeepMessages(true);
        try
        {
            item = service.update(item);
            Faces.setViewAttribute("item", item);
            JsfUtils.addSuccessMessage("updated");
            return "view?faces-redirect=true&includeViewParams=true";
        }
        catch(Exception e)
        {
            e.printStackTrace();
            JsfUtils.addErrorMessage(e);
        }
        return null;
    }
    // getters and setters, other actions, ...
}

列表.xhtml

<p:dataTable value="#{testBean.model}" var="elem" ...>
    ...
    <p:column exportable="false" toggleable="false" headerText="#{bundle.actions}">
        <!-- two techniques available for navigation -->
        <p:button outcome="view?id=#{elem.converterString}" icon="#{icons.view}" />
        <p:commandButton rendered="#{user.isEditAllowed(elem)}"
            action="edit?faces-redirect=true&amp;includeViewParams=true" process="@form"
            icon="#{icons.edit}">
            <f:param name="id" value="#{elem.converterString}" />
        </p:commandButton>
    </p:column>
</p:dataTable>

查看.xhtml

<f:metadata>
    <o:viewParam id="itemId" name="id" value="#{viewScope.item}" required="true"
        converter="entityConverter" />
</f:metadata>
<ui:composition template="/WEB-INF/templates/template.xhtml">
    <ui:define name="content">
        <p:panelGrid columns="2">
            <h:outputLabel value="#{bundle.name}" />
            <h:outputText value="#{item.name}" />
            ...
        </p:panelGrid>
        <p:button outcome="list" value="#{bundle.list}" icon="#{icons.list}" />
        <p:button rendered="#{user.isEditAllowed(item)}" 
            outcome="edit?id=#{item.converterString}" value="#{bundle.edit}"
            icon="#{icons.edit}" />
    </ui:define>
</ui:composition>

编辑.xhtml

<f:metadata>
    <o:viewParam id="itemId" name="id" value="#{viewScope.item}" required="true"
        converter="entityConverter" />
</f:metadata>
<ui:composition template="/WEB-INF/templates/template.xhtml">
    <ui:define name="content">
        <p:panelGrid columns="2">
            <h:outputLabel value="#{bundle.name}" />
            <h:panelGroup>
                <p:inputText id="name" value="#{item.name}" />
                <p:message for="name" />
            </h:panelGroup>
            ...
        </p:panelGrid>
        <p:commandButton process="@form" update="@form" action="#{testBean.update}" 
            value="#{bundle.update}" icon="#{icons.update}" />
        <p:button outcome="view?id=#{item.converterString}" value="#{bundle.cancel}" 
            icon="#{icons.cancel}" />
    </ui:define>
</ui:composition>

最新更新