@ManagedProperty(value = "#{param.id}") in a non-request Scope Bean
I need to pass a parameter (POST) to a @managedBean, I used managed properties like this:
@ManagedProperty(value = "#{param.id}")
private int id;
And the scope of the Bean is ViewScope
I end up with this error:
Unable to create managed bean receipt. The following problems were found: - The scope of the object referenced by expression #{param.id}, request, is shorter than the referring managed beans scope of view
What can I do?
arjan take a look:
My page: Facelet Title
<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>
Two ways:
Make the bean request scoped and inject the view scoped one as another
@ManagedProperty
.@ManagedBean @RequestScoped public class RequestBean { @ManagedProperty(value="#{param.id}") private Integer id; @ManagedProperty(value="#{viewBean}") private ViewBean viewBean; }
The view scoped bean is available during
@PostConstruct
and action methods of request scoped bean. You only need to keep in mind that theid
can get lost when you do a postback to the same view without the parameter.Or, grab it manually from the request parameter map during bean's initialization.
@ManagedBean @ViewScoped public class ViewBean { private Integer id; @PostConstruct public void init() { id = Integer.valueOf(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id")); } }
This way the initial
id
is available during the entire view scope.
As an alternative to grabbing the parameters directly from the request in your bean, you can use view parameters
.
These need to be declared on the Facelet where you use your managed bean as follows:
<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>
If you now request this page, the setter of the backing bean will be called with the request value provided for the id parameter. This works for both GET
and (non-faces) POST
requests.
The advantage is that you can use the standard JSF converters and validators here. Of course if your managed bean is not tied to a particular view then this solution is less ideal.
A small peculiar thing to watch out for is that when doing a normal faces postback after the initial request that provided the view parameter, the setter in your bean will be called again, even if the bean is in view scope and no new value is explicitly provided.
To test that this works, I've used the following managed 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;
}
}
And the following 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>
Enter a number in the input field and click the submit button. If the number is printed back on the screen the test has succeeded. Note that the second form is a regular form and does not post any JSF state along. I tested this on JBoss AS 6 and it works. Proving the id parameter as a GET parameter also works.
精彩评论