在@RequestScoped bean 的回发中保留 GET 参数

Retain GET parameter on postback on @RequestScoped bean

我想在数据库中仅更新表单中指定的那些字段。在实体 "account" 中,我使用注释 @DynamicUpdate.

AccountMB (@RequestScoped) 方法:

public String update() {
    getDao().update(getInstance());
    return SUCCESS;
}

public Account getInstance() {

    //setId(new Long("1"));

    if (instance == null) {
        if (id != null) {
            instance = loadInstance();
        } else {
            instance = createInstance();
        }
    }

    return instance;
}

并形成 form.xhtml:

<f:metadata>
    <f:viewParam name="accountId" value="#{accountMB.id}" />
</f:metadata>

<h:form prependId="false">

    <h:inputHidden id="accountId" value="#{accountMB.id}"/>

    <h:inputHidden id="id" value="#{accountMB.instance.id}"/>

    <h:inputText id="firstName" value="#{accountMB.instance.firstName}"/>

    <h:commandButton type="submit" action="#{accountMB.update}" value="Save">
        <f:setPropertyActionListener target="#{accountMB.id}" value="1" />
    </h:commandButton> 
</h:form>

我打开页面form.xhtml?accountId=1,以加载数据的形式,点击"Save"。它写入一个错误:

java.sql.SQLException: ORA-01407: cannot update ("MYBD"."ACCOUNTS"."EMAIL") to NULL

如果在getInstance()方法中取消注释setId(new Long("1"));,数据将被保存。

如果我在 AccountMB 中使用注释 @ViewScoped,数据将被保存。

但是我想使用注解@RequestScoped

我明白,我触发了 createInstance(); 并且电子邮件字段未填写。

告诉我如何将 id 传递给加载方法 loadInstance();

我使用 <f:setPropertyActionListener target="#{accountMB.id}" value="1" /><h:inputHidden id="accountId" value="#{accountMB.id}"/>。但这是行不通的。请帮助我。

您的错误是您(懒惰地)在 getter 方法而不是 @PostConstruct 中加载实体。在 JSF 能够调用 setId() 之前,实体正在 loaded/created。无论如何,在 getter 方法中执行业务逻辑是令人担忧的。 You'd better not do that and keep the getter methods untouched.

因为您想使用 @RequestScoped bean,所以 <f:viewParam> 对您来说不是很有用。准备 @PostConstruct 中的实体为时已晚,因此可以用提交的值填充它。它可以很好地与 @ViewScoped bean 一起工作,因为它在回发时被重用。

@RequestScopedbean中需要自己抓取HTTP请求参数:

@Named
@RequestScoped
public class AccountBacking {

    private Account account;

    @EJB
    private AccountService service;

    @PostConstruct
    public void init() {
        String id = FacesContext.getCurrentInstance().getRequestParameterMap().get("accountId");
        account = (id != null) ? service.find(Long.valueOf(id)) : new Account();
    }

    public void save() {
        service.save(account);
    }

    public Account getAccount() {
        return account;
    }

}

那么您可以使用这种形式,其中仅 <f:param> 用于在回传中保留 GET 参数:

<h:form>
    <h:inputText id="firstName" value="#{accountBacking.account.firstName}"/>

    <h:commandButton action="#{accountBacking.save}" value="Save">
        <f:param name="accountId" value="#{param.accountId}" />
    </h:commandButton>
</h:form>