在 JSF 表单提交上保留 GET 请求查询字符串参数

Posted

技术标签:

【中文标题】在 JSF 表单提交上保留 GET 请求查询字符串参数【英文标题】:Retaining GET request query string parameters on JSF form submit 【发布时间】:2013-07-18 00:56:21 【问题描述】:

我有 3 页:

main.xhtml agreement.xhtml generated.xhtml

agreement.xhtml 需要两个参数才能正确加载:serviceIdsite。所以,一个普通的 url 看起来像这样:/app/agreement.xhtml?site=US&serviceId=AABBCC

我在agreement.xhtml 上有这个按钮

<h:form>
   <h:commandButton value="Generate License File" action="#agreement.generateMethod" />   
</h:form>

@RequestScoped bean #agreement 有这个方法:

public String generateMethod()
    .......
    return "generated";

我需要在点击时执行generateMethod() 方法,并在完成后将用户重定向到generated.xhtml 页面。发生的情况是,在点击时,页面浏览器将用户发送到/app/agreement.xhtml,并且由于它没有发送参数siteserviceId,所以它崩溃了。

我尝试让generateMethod() 返回"generated?faces-redirect=true",但仍然没有。有什么想法吗?

【问题讨论】:

使用人脸重定向 = true。看到这个[问题][1][1]:***.com/questions/11242240/… 【参考方案1】:

您的具体问题是因为 JSF &lt;h:form&gt; 默认情况下提交到当前请求 URL 而没有任何查询字符串。仔细查看生成的 HTML 输出,您会看到

<form action="/app/agreement.xhtml" ...>

因此,您需要自己明确包含这些请求参数。有几种方法可以解决这个问题。如果您没有发送重定向,那么您可以将它们作为隐藏输入添加到 JSF 表单中。

<h:form>
    <input type="hidden" name="site" value="#param.site" />
    <input type="hidden" name="site" value="#param.serviceId" />
    ...
</h:form>

只是,这些参数不会重新出现在浏览器地址栏中的 URL 中。如果您只在同一页面上使用 ajax,这不是问题。 &lt;h:inputHidden&gt; 顺便说一句不合适,因为当表单上发生转换或验证错误时,它会混淆地失去其价值。

为了让它们重新出现在 URL 中,您需要 &lt;f:viewParam&gt;includeViewParams。为了让includeViewParams 工作,您需要在both 源页面agreement.xhtml 中声明以下内容...

<f:metadata>
    <f:viewParam name="site" value="#agreement.site" />
    <f:viewParam name="serviceId" value="#agreement.serviceId" />
</f:metadata>

...目标页面generated.xhtml

<f:metadata>
    <f:viewParam name="site" value="#generated.site" />
    <f:viewParam name="serviceId" value="#generated.serviceId" />
</f:metadata>

现在您可以发送包含视图参数的重定向,如下所示:

public String generateMethod() 
    // ...

    return "generated?faces-redirect=true&includeViewParams=true";

请注意,bean 应该是@ViewScoped,以便在打开带有表单的页面和提交表单之间保持这些参数有效,包括验证错误。否则,当坚持使用 @RequestScoped bean 时,您应该在命令组件中将它们保留为 &lt;f:param&gt;

<h:commandButton ...>
    <f:param name="site" value="#generated.site" />
    <f:param name="serviceId" value="#generated.serviceId" />
</h:commandButton>

没有办法在输入组件中为&lt;f:ajax&gt; 设置它们,那么你的bean 应该真的是@ViewScoped


或者,如果您碰巧已经使用 JSF 实用程序库 OmniFaces,那么您也可以将 &lt;h:form&gt; 替换为 &lt;o:form&gt;,如下所示(另请参阅 showcase example):

<o:form>

基本上就是这样。这将生成一个包含当前查询字符串的&lt;form action&gt;

<form action="/app/agreement.xhtml?site=US&serviceId=AABBCC" ...>

然后,这些请求参数仅在表单提交的请求参数映射中可用。您不需要额外的元数据/视图参数,也不需要发送重定向,如有必要,您的 bean 可以保留@RequestScoped

public String generateMethod() 
    // ...

    return "generated";

另见:

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)

【讨论】:

h:form中的h:inputs、h:message和其他元素在切换到o:form后是否仍然有效?或者是否需要做任何额外的工作?原来的commandButton(类型submit,使用POST)仍然可以返回void/null吗?【参考方案2】:

您的generateMethod 必须返回

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

您甚至可以将&amp;amp; 替换为&amp;,但在您的xhtml 中将其转义。

在您的generated.xhtml 中,您可以像这样捕获&lt;f:viewParam&gt; 传递的参数

<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>

【讨论】:

以上是关于在 JSF 表单提交上保留 GET 请求查询字符串参数的主要内容,如果未能解决你的问题,请参考以下文章

(gin框架拓展)两种 HTTP 请求方法:GET 和 POST

使用 GET 提交 JSF 表单

表单提交中get 和post方式的区别

表单提交中get和post方式的区别

表单提交中get 和post方式的区别

JSF 2.0;我的脸;仅使用 POST 提交表单