要回答这个问题,我们需要了解重定向的工作原理。
重定向
收到客户端 HTTP 请求。对此请求的响应已创建。它看起来总是一样的。返回代码 302,并设置标题 Location。例如:
HTTP/1.1 302 Moved Temporarily
Server: Apache-Coyote/1.1
Location: http://stackoverflow.com
...
当客户端收到此响应时,它会执行另一个请求。这次从 Location 标头获取对 URI 的请求。
问题示例说明
h:commandLink 触发 POST 请求。创建响应。此响应包含来自操作的 URI:
HTTP/1.1 302 Moved Temporarily
Server: Apache-Coyote/1.1
Location: http://localhost:8080/myapp/pages/hello.xhtml
...
包含参数名称,但它在消息正文中。
当客户端收到代码 302 和 Location 时,它会像往常一样执行相同的操作。创建 GET 请求:
GET /myapp/pages/hello.xhtml HTTP/1.1
简单的 POST 响应正文被忽略。没有理由从正文中获取内容并将其附加到 GET 请求。这就是问题示例无法正常工作的原因。
解决方案 1: (基于 LaurentG 的建议)
可以使用includeViewParams。但它仅包含来自元素 f:viewParam 的值。因此,在与 commandButton 相同的页面上,我们必须添加这样的元素:
<h:head></h:head>
<f:metadata>
<f:viewParam name="name"></f:viewParam>
</f:metadata>
<h:body>
<h:form>
<h:commandLink value="Go to hello page" action="/pages/hello.xhtml?faces-redirect=true&includeViewParams=true" >
<f:param name="name" value="Hubert" />
</h:commandLink>
</h:form>
</h:body>
所以我们在页面 hello.xhtml 上有 f:viewParam 元素,并且这个页面重定向到页面 hello.xhtml。
解决方案 2:
如果参数值来自控制器,那么我们可以使用 h:commandButton 从页面中删除元素 f:viewParam。技巧可以在动作方法中完成:
<h:form>
<h:commandLink value="Go to hello page" action="#{controller.action}" />
</h:form>
和动作():
public String action() {
String outcome = "/pages/hello?faces-redirect=true";
try {
outcome += String.format("&name=%s", URLEncoder.encode(name, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return outcome;
}
解决方案 1 和 2 克里特斯响应:
HTTP/1.1 302 Moved Temporarily
Server: Apache-Coyote/1.1
Location: http://localhost:8080/myapp/pages/hello.xhtml?name=Hubert
...
这就是我们需要的。