2

In my JSF application I have two pages, list.jsf and details.jsf, and each page has its own controller with view scope. In list.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 (without faces-redirect=true), the parameter is passed and I can see the details in details.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).

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Achraf
  • 658
  • 6
  • 14
  • 34
  • Related: [Response.Redirect with POST instead of Get?](http://stackoverflow.com/questions/46582) – McDowell Dec 28 '12 at 09:42
  • Very curious; what does "some code" in goToDetails consist of? From the name of the method and the use case you described it's hard to imagine what it could possibly do. If it's indeed doing something useful the answer by eljunior is the best (but replace the statements with a simple outcome), otherwise the answer by arjan tijms is better. – Mike Braun Dec 28 '12 at 12:45

2 Answers2

6

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;
}
user1364684
  • 800
  • 2
  • 8
  • 28
Elias Dorneles
  • 22,556
  • 11
  • 85
  • 107
  • I'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. – Mike Braun Dec 28 '12 at 12:20
  • @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. – Elias Dorneles Dec 28 '12 at 12:26
  • Yes, 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 ;) – Mike Braun Dec 28 '12 at 12:36
  • Yeah, I didn't know you could add URL parameters in the return string. Just finished testing now, and learned something new! :) Thanks – Elias Dorneles Dec 28 '12 at 12:41
5

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:

Also see:

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
  • this approach is better indeed, though OP's code does have a comment implying that there is more code in the action method. – Elias Dorneles Dec 28 '12 at 12:22
  • Thank you for your response it is very usefull, but in my case i have to use a commandButton with action. – Achraf Dec 28 '12 at 13:30
  • @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! – Mike Braun Dec 28 '12 at 14:28
  • Thank 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 – Achraf Dec 28 '12 at 20:31