How do you use JSF implicit redirection with POST parameters
Solution 1
You can't redirect using POST.
When you use faces-redirect=true
you are using an HTTP redirect, and what happens is: the server sends a HTTP 302 response to the browser with an URL for redirection, then the browser does a GET request on that URL.
What you can do instead is to redirect to an URL sending the id
parameter via GET, going something like this:
public void goToDetails(){
// some code
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext()
String id = object.getPk().toString();
ec.redirect(ec.getRequestContextPath() + "/details.jsf?id=" + id);
}
You may want to create an util method for this sort of thing, like Faces#redirect()
of OmniFaces library.
UPDATE: As noted in the comments, it's also possible to just add the id in the return string:
public String goToDetails(){
// some code
String id = object.getPk().toString();
return "details?faces-redirect=true&id=" + id;
}
Solution 2
If the backing bean behind list.jsf
doesn't need to do any processing (from the example it doesn't look like it), you should link to details.jsf
directly via a GET request.
You can use the <h:link>
tag for this as follows:
<h:link value="details" outcome="details.jsf" >
<f:param name="id" value="#{listBean.object.pk}"/>
</h:link>
On your details view, you can declare that the view uses a GET parameter and bind it directly to the backing bean of that view:
<f:metadata>
<f:viewParam name="id" value="#{detailsBean.id}" />
</f:metadata>
Additionally, you can directly validate and or convert that parameter, so your detailsBean
will get an Object of the right type instead of the string-based id. If you need to do any post-processing in the detailsBean
after the GET parameter is injected, you can use the preRenderView
event:
<f:metadata>
<f:viewParam name="id" value="#{detailsBean.id}" />
<f:event type="preRenderView" listener="#{detailsBean.preRenderView()}" />
</f:metadata>
Working examples:
- http://code.google.com/p/javaee6-crud-example/source/browse/WebContent/index.xhtml
- http://code.google.com/p/javaee6-crud-example/source/browse/WebContent/user_edit.xhtml
Also see:
Achraf
A beginner software engineer specially in JAVA enterprise edition and some frameworks like hibernate, JSF, Spring...
Updated on June 05, 2022Comments
-
Achraf almost 2 years
In my JSF application I have two pages,
list.jsf
anddetails.jsf
, and each page has its own controller with view scope. Inlist.jsf
I have a<h:commandLink>
that calls an action and pass a parameter:<h:commandLink value="details" action="#{listBean.goToDetails}" > <f:param name="id" value="#{listBean.object.pk}"/></h:commandLink>
This is the bean method:
@ManagedBean @ViewScoped public class ListBean { public String goToDetails() { // some code return "details?faces-redirect=true"; } }
I read the parameter in the second bean like this:
Map<String, String> params = FacesContext.getCurrentInstance() .getExternalContext().getRequestParameterMap(); this.setIdParam(params.get("id"));
When I run this code, the parameter is not passed to the second bean instance. However when I change navigation to
forward
(withoutfaces-redirect=true
), the parameter is passed and I can see the details indetails.jsf
but the URL doesn't match with the current page.So what I want to do is to use a "jsf implicit redirection" (not a forward) with POST parameters (f:param).
-
Mike Braun over 11 yearsI'm really sorry for the down vote. The first part of your answer is really good, but I felt the second part is not optimal. You're now advising to do a PRG, while all that is needed here is a get. Even iff PRG was needed, then you could just return an outcome with the redirect directive and a parameter. Eg return "details.jsf?faces-redirect=true&id=" + id; But if you don't need PRG, just link directly. This is better for performance and direct links can be bookmarked, inspected upfront, etc.
-
Alfian Nahar over 11 yearsthis approach is better indeed, though OP's code does have a comment implying that there is more code in the action method.
-
Alfian Nahar over 11 years@MikeBraun I agree that a simple link is much better, it's just that OP's code has a comment saying
// some code
in there which implied there were more stuff. Otherwise, I fully agree that a link would be best. -
Mike Braun over 11 yearsYes, you're right. Depending on what "some code" does, the PRG pattern would be needed indeed, but then you could use the outcome string with parameter instead of programmatically setting the redirect. I'm curious what "some code" is btw. For linking from a list to details view I've a feeling this isn't needed either, but of course only OP knows this ;)
-
Alfian Nahar over 11 yearsYeah, I didn't know you could add URL parameters in the return string. Just finished testing now, and learned something new! :) Thanks
-
Achraf over 11 yearsThank you for your response it is very usefull, but in my case i have to use a commandButton with action.
-
Mike Braun over 11 years@Achraf do you also know why you need a commandButton? If you just want a button rendered then you can also use h:button. This will fire a get request just like h:link. What special things does your action do apart from the redirect? (just curious and for helping other people which method to choose). Thanks!
-
Achraf over 11 yearsThank you @MikeBraun for your interventions. In my case the action execute some code before redirecting. Explaining: I have multiple details views (details1.jsf, details2.jsf...) and each object instance must be associated with the appropriate view so in goToDetails method I have to do some logic to specify the redirection destination