@ManagedProperty(value = "#param.id") 在非请求范围 Bean

Posted

技术标签:

【中文标题】@ManagedProperty(value = "#param.id") 在非请求范围 Bean【英文标题】:@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>

【问题讨论】:

【参考方案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 可能会在没有参数的情况下回发到同一个视图时丢失。

    或者,在 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 程序员和编程语言一样优秀。

以上是关于@ManagedProperty(value = "#param.id") 在非请求范围 Bean的主要内容,如果未能解决你的问题,请参考以下文章

可以将@ManagedBean 作为@ManagedProperty 注入@WebServlet?

无法将 JSF ViewScoped bean 作为 ManagedProperty 注入 Validator

注入 vs ManagedProperty [重复]

ViewScoped Bean 中 SessionScope 的 ManagedProperty - 瞬态?

CDI @Named bean 中的 @javax.faces.bean.ManagedProperty 返回 null

JSF 2.3 与 Spring 4.3 @Inject @ManagedProperty 问题