【问题标题】:@ManagedProperty(value = "#{param.id}") in a non-request Scope Bean@ManagedProperty(value = "#{param.id}") 在非请求范围 Bean
【发布时间】:2011-06-02 13:22:14
【问题描述】:

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

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

而Bean的作用域是ViewScope

我最终得到了这个错误:

无法创建托管 bean 收据。发现以下问题: - 表达式#{param.id},request所引用的对象的范围比引用的托管bean视图范围短

我能做什么?

arjan 看看:

我的页面: 小面标题

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

【问题讨论】:

    标签: java jsf jsf-2 managed javabeans


    【解决方案1】:

    两种方式:

    1. 使 bean 请求限定范围并将视图范围作为另一个 @ManagedProperty 注入。

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

      view scoped bean 在@PostConstruct 和 request scoped bean 的 action 方法中可用。你只需要记住id 可能会在没有参数的情况下回发到同一个视图时丢失。

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

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

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

    【讨论】:

    • 谢谢,第一个解决方案(在 requestScoped 中注入 viewScoped bean)是一种好的和流行的做法吗???
    • 我的应用程序由 GlassFish 提供服务,我也可以使用 CDI bean,但我决定使用 JSF bean 做一些项目,因为我是 JSF 的新手,这是个好主意吗?
    • 取决于id 的用途。您想在每次请求时“刷新”它吗?选择方式 1。或者您想在整个视图范围内使用初始值?走2路。
    • 谢谢,非常完整的描述。
    • @Tarik:我总是从代码 sn-ps 中省略明显性,以使答案更加集中。考虑到问题的表述方式,OP 非常清楚对 getter/setter 的需求。如果 OP 不知道,我宁愿添加像 // +getter+setter 这样的评论,而不是添加一大堆显而易见的东西。只需让您的 IDE 自动生成 getter/setter 并将它们全部隐藏在类的底部即可。
    【解决方案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 参数提供的请求值调用 backing bean 的 setter。这适用于GET 和(非人脸)POST 请求。

    优点是您可以在此处使用标准的 JSF 转换器和验证器。当然,如果您的托管 bean 没有绑定到特定视图,那么这个解决方案就不太理想了。

    需要注意的一个小特殊的事情是,在提供视图参数的初始请求之后执行普通人脸回发时,将再次调用 bean 中的设置器,即使 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 参数也可以。

    【讨论】:

    • 据我在书籍和教程中发现,它们仅适用于 Get 参数,您确定它们可以与 Post 参数一起使用吗????...
    • 嗯,虽然我不是这方面的权威来源,但我很确定我以前用过 POST 参数。我会再次检查并更新我的答案。
    • 我再次测试并更新了我的答案。这只是两个文件,所以应该很容易复制。
    • 我还查看了 Mojarra 源代码,看看这些参数最终是如何解决的。在 Mojarra 2.03 中,它位于 UIViewParameter 第 217 行: String paramValue = context.getExternalContext().getRequestParameterMap().get(getName());由于请求参数映射始终包含来自 POST 和 GET 请求的参数,因此这会自动解释它应该可以工作。然而,在 JSF 规范中没有明确声明应该支持 POST 和 GET。规范似乎并没有明确说明这一点。
    • 感谢您为我花费的时间。祝你好运 :)。 Java 程序员和编程语言一样优秀。
    猜你喜欢
    • 2011-06-20
    • 1970-01-01
    • 2013-01-21
    • 2011-08-15
    • 2011-11-11
    • 2011-04-19
    • 1970-01-01
    • 2012-05-26
    • 2011-08-19
    相关资源
    最近更新 更多