Retaining GET request query string parameters on JSF form submit

随声附和 提交于 2019-11-26 00:25:49

问题


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?


回答1:


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="site" 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 includeRequestParams="true">

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";
}

Or, if you're using an "pretty URL" library such as PrettyFaces or FacesViews or perhaps something homegrown and intend to submit to exactly the same URL as appears in the browser's address bar, then you could use useRequestURI instead.

<o:form useRequestURI="true">

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)



回答2:


Your generateMethod would have to return

return "generated?site=US&amp;serviceId=AABBCC&amp;faces-redirect=true";

You can even replace &amp; with & but escape it in your xhtml.

In your generated.xhtml you can catch the parameters that are being passed with <f:viewParam> like this

<f:metadata>
    <f:viewParam name="site" value="#{yourBean.site}"/><!--Make sure you have a setter-->
    <f:viewParam name="serviceId" value="#{yourBean.serviceId}"/><!--Make sure you have a setter-
</f:metadata>
<h:head>


来源:https://stackoverflow.com/questions/17734230/retaining-get-request-query-string-parameters-on-jsf-form-submit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!