在非请求作用域Bean中,@ManagedProperty(value = "#{param.id}")是什么意思?

17

我需要将参数(POST)传递给一个@managedBean,我使用了如下的managed properties:

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

这个Bean的作用域是ViewScope。

我遇到了这个错误:

无法创建托管bean receipt。发现以下问题:-表达式#{param.id}引用的对象作用域为request,但其作用域比引用它的托管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>

2个回答

39
  1. 有两种方法:

    第一种方法是将bean设置为请求作用域,并将视图作用域的bean作为另一个@ManagedProperty注入。

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

    在请求作用域Bean的@PostConstruct和动作方法期间,视图作用域Bean可用。您只需要记住,在不带参数的情况下向同一视图进行回传时,id可能会丢失。

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

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

    这种方式使得初始 id 在整个视图范围内都可用。


1
谢谢,第一种解决方案(在请求范围内的bean中注入视图范围内的bean)是一个好的和流行的做法吗? - ehsun7b
2
取决于“id”的目的。您想在每个请求上“刷新”它吗?选择第一种方式。还是您想在整个视图范围内使用初始值?选择第二种方式。 - BalusC
谢谢,非常完整的描述。 - ehsun7b
@BalusC 感谢您的回答,您没有为托管属性添加setter是正常的吗?还是因为这不是OP问题的目的? - Tarik
1
@Tarik:我总是从代码片段中省略显而易见的部分,以使答案更加专注。鉴于问题的表述方式,OP非常清楚需要使用getter/setter。如果OP不知道,我宁愿添加一个注释,如// +getter+setter,而不是添加一堆显而易见的内容。只需让您的IDE自动生成getter/setter并将它们隐藏在类的底部即可。 - BalusC
显示剩余8条评论

6
作为在Bean中直接从请求中获取参数的替代方法,您可以使用“视图参数”。 这些参数需要在使用托管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。这适用于GET和(非面向对象)POST请求。
优点是您可以在此处使用标准JSF转换器和验证程序。当然,如果您的托管bean未绑定到特定视图,则此解决方案不太理想。
需要注意的一个小问题是,在提供视图参数的初始请求之后进行正常的面向对象回发时,即使bean位于视图范围内并且没有明确提供新值,也将再次调用bean中的setter。
为了测试这个功能,我使用了以下托管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参数证明也可行。

就我在书籍和教程中的了解,它们只适用于获取参数,你确定它们可以与Post参数一起使用吗? - ehsun7b
1
嗯,虽然我不是权威来源,但我相当确定我以前使用过POST参数。我会再次检查并更新我的答案。 - Arjan Tijms
我再次测试并更新了我的答案。只有两个文件,所以你复制起来应该很容易。 - Arjan Tijms
我还查看了Mojarra源代码,以了解这些参数是如何最终解决的。在Mojarra 2.03中,它在UIViewParameter第217行:String paramValue = context.getExternalContext().getRequestParameterMap().get(getName());由于请求参数映射始终包含来自POST和GET请求的参数,因此这自动解释了它应该起作用。然而,在JSF规范中,并没有明确说明BOTH POST和GET都应该被支持。规范似乎并没有明确说明这一点。 - Arjan Tijms
@ArjanTijms arjam 我使用ManagedProperty来获取param.id。现在我在一个方法中使用它来检索与此Id相关联的请求,但下一次我尝试使用它时,它为null,即private String id。你有什么想法为什么它清除了值? - sys_debug
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接