Retaining GET request query string parameters on JSF form submit
http-request-parameters, jsf, jsf-2, navigation
Solution
Your concrete problem is caused because a JSF `<h:form>` submits by default to the current request URL without any query string. Look closer at the generated HTML output, you'll see
<form action="/app/agreement.xhtml" ...>
You'd thus explicitly need to include those request parameters yourself. There are several ways to solve this. If you weren't sending a redirect, then you could just add them as hidden inputs to the JSF form.
<h:form>
<input type="hidden" name="site" value="#{param.site}" />
<input type="hidden" name="serviceId" value="#{param.serviceId}" />
...
</h:form>
Only, those parameters won't reappear in URL in browser's address bar. This isn't a problem if you're only using using ajax on the same page. The `<h:inputHidden>` is by the way not suitable as it will confusingly lose its value when a conversion or validation error occurs on the form.
In order to get them to reappear in URL, you need `<f:viewParam>` and `includeViewParams`. In order to get `includeViewParams` to work, you need to declare the following in both the source page `agreement.xhtml` ...
<f:metadata>
<f:viewParam name="site" value="#{agreement.site}" />
<f:viewParam name="serviceId" value="#{agreement.serviceId}" />
</f:metadata>
... and the target page `generated.xhtml`:
<f:metadata>
<f:viewParam name="site" value="#{generated.site}" />
<f:viewParam name="serviceId" value="#{generated.serviceId}" />
</f:metadata>
Now you can send a redirect including the view parameters as follows:
public String generateMethod() {
// ...
return "generated?faces-redirect=true&includeViewParams=true";
}
Do note that the bean should be `@ViewScoped` in order to keep those parameters alive between opening the page with the form and submitting the form, also on validation errors. Otherwise, when sticking to a `@RequestScoped` bean, you should be retaining them as `<f:param>` in the command components:
<h:commandButton ...>
<f:param name="site" value="#{generated.site}" />
<f:param name="serviceId" value="#{generated.serviceId}" />
</h:commandButton>
There's no way to set them for `<f:ajax>` inside input components, your bean should then really be `@ViewScoped`.
Alternatively, if you happen to use JSF utility library OmniFaces already, then you could also just replace the `<h:form>` by `<o:form>` as follows (see also showcase example):
<o:form>
That's basically all. This will generate a `<form action>` with current query string included.
<form action="/app/agreement.xhtml?site=US&serviceId=AABBCC" ...>
Those request parameters are then just available in the request parameter map of the form submit. You don't need additional metadata/viewparams and you also don't need to send a redirect and your bean can be kept `@RequestScoped`, if necessary.
public String generateMethod() {
// ...
return "generated";
}
See also:
- What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
- How to navigate in JSF? How to make URL reflect current page (and not previous one)
Problem
I have 3 pages: - `main.xhtml` - `agreement.xhtml` - `generated.xhtml` The `agreement.xhtml` needs two parameters to load correctly: `serviceId` and `site`. So, a normal url looks like this: `/app/agreement.xhtml?site=US&serviceId=AABBCC`. I have this button on `agreement.xhtml` ``` <h:form> <h:commandButton value="Generate License File" action="#{agreement.generateMethod}" /> </h:form> ``` The `@RequestScoped` bean `#{agreement}` has this method: ``` public String generateMethod(){ ....... return "generated"; } ``` I need that, on click, the `generateMethod()` method is executed, and after it's done, the user is redirected to the `generated.xhtml` page. What's happening is that, on click, the page browser sends the user to `/app/agreement.xhtml` and, since it's not sending the parameters `site` and `serviceId`, it crashes. I tried making the `generateMethod()` return a `"generated?faces-redirect=true"`, but still nothing. Any ideas?