@ManagedProperty(value = “#{param.id}”) 在非请求作用域 Bean 中

2022-09-02 23:24:16

我需要将参数(POST)传递给@managedBean,我使用了如下托管属性:

@ManagedProperty(value = "#{param.id}")
private int id;

Bean 的范围是 ViewScope

我最终得到这个错误:

无法创建受管理的 Bean 收据。发现以下问题: - 表达式 #{param.id}请求引用的对象的作用域比引用的受管 Bean 视图的作用域短

我该怎么办?

arjan 来看看:

我的页面:Facelet 标题

<form method="post" action="faces/index.xhtml">
  <input name="id" value="4" />
  <input type="submit" value="submit" />
</form>

<h:form>
  <h:commandLink value="click" action="index">
    <f:param id="id" name="id" value="20"/>
  </h:commandLink>
</h:form>


答案 1

两种方式:

  1. 将 Bean 请求限定为作用域,并将视图作为另一个视图注入作用域。@ManagedProperty

    @ManagedBean
    @RequestScoped
    public class RequestBean {
    
        @ManagedProperty(value="#{param.id}")
        private Integer id;
    
        @ManagedProperty(value="#{viewBean}")
        private ViewBean viewBean;
    }
    

    视图作用域 Bean 在请求作用域 Bean 期间可用,并且操作方法可用。您只需记住,在没有参数的情况下回发到同一视图时,可能会丢失。@PostConstructid

  2. 或者,在 Bean 初始化期间从请求参数映射中手动获取它。

    @ManagedBean
    @ViewScoped
    public class ViewBean {
    
        private Integer id;
    
        @PostConstruct
        public void init() {
            id = Integer.valueOf(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id"));       
        }
    }
    

    这样,初始值在整个视图范围内都可用。id


答案 2

作为直接从 Bean 中的请求中获取参数的替代方法,您可以使用 。view parameters

这些需要在使用受管 Bean 的 Facelet 上声明,如下所示:

<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:body>

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

    <!-- Rest of Facelet here -->   

    </h:body>
</html>

如果现在请求此页,则将使用为 id 参数提供的请求值调用支持 Bean 的 setter。这适用于和(非人脸)请求。GETPOST

优点是您可以在此处使用标准的 JSF 转换器和验证器。当然,如果您的受管 Bean 未绑定到特定视图,则此解决方案就不那么理想。

需要注意的一个小奇特事情是,在提供视图参数的初始请求之后执行普通面回发时,将再次调用 Bean 中的 setter,即使 Bean 在视图范围内并且没有显式提供新值也是如此。

为了测试这是否有效,我使用了以下受管 Bean:

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;

@ManagedBean
@ViewScoped
public class MyBean {

    Long id;

    @PostConstruct
    public void test() {
        System.out.println("post construct called");
    }

    public void actionMethod(ActionEvent event) {       
        System.out.println("action called");        
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

}

以及以下 Facelet:

<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:body>

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

        <h:outputText value="#{myBean.id}"/>

        <h:form>
            <h:commandButton value="test" actionListener="#{myBean.actionMethod}"/>
        </h:form>

        <form method="post">
            <input name="id" value="4" />
            <input type="submit" value="submit" />
        </form>

    </h:body>
</html>

在输入字段中输入一个数字,然后单击提交按钮。如果该数字打印回屏幕上,则测试成功。请注意,第二个窗体是常规窗体,不会发布任何 JSF 状态。我在JBoss AS 6上测试了这个,它的工作原理。将 id 参数证明为 GET 参数也有效。


推荐