如何在 JSF 中导航?如何使 URL 反映当前页面(而不是上一个页面)

Posted

技术标签:

【中文标题】如何在 JSF 中导航?如何使 URL 反映当前页面(而不是上一个页面)【英文标题】:How to navigate in JSF? How to make URL reflect current page (and not previous one) 【发布时间】:2022-01-24 04:32:29 【问题描述】:

我目前正在学习 JSF,当我意识到每当我们使用 <h:form> 时,JSF 的标准行为是总是向我显示 previous 页面的 URL。浏览器,而不是 当前 页面的 URL。

我知道这与 JSF 总是将表单发布到同一页面然后只是将控制器返回给不知道页面位置已更改的浏览器的任何页面呈现给浏览器的方式有关。

似乎 JSF 已经存在了很长时间,必须有一个干净、可靠的方法来处理这个问题。如果是这样,你介意分享一下吗?

我找到了各种解决方法,但遗憾的是没有一个看起来像真正可靠的解决方案。

请接受 URL 具有误导性。 将"?faces-redirect=true" 附加到每个 bean 的操作的返回值,然后 弄清楚如何将@RequestScoped 替换为其他东西(Flash Scopes、CDI 对话、@SessionScoped...)。 接受为每个用户操作进行两次 HTTP 往返。 使用某种方法(例如,第 3 方库或自定义代码)隐藏 URL 中的页面名称,始终为每个页面使用相同的通用 URL。

如果"?faces-redirect=true" 足够好,有没有办法配置整个应用程序以这种方式处理所有请求?

【问题讨论】:

在这里解决了一个非常相似的问题,以防万一有人需要它***.com/questions/15635338/… 【参考方案1】:

确实,JSF 作为一个基于表单的应用程序目标 MVC 框架将 POST 表单提交到与请求带有 <h:form> 的页面的表单相同的 URL。您可以通过查看生成的 html 输出的<form action> URL 来确认它。这是在以 postback 为特征的 Web 开发术语中。默认情况下,回发上的导航不会导致对新 URL 的新请求,而是将目标页面加载为响应的内容。当您只需要逐页导航时,这确实令人困惑。

通常,导航/重定向的正确方法取决于业务需求和请求的idempotence(阅读:“书签性”)(注意:有关具体代码示例,请参阅下面的“另请参阅”链接) .

如果请求是幂等的,只需使用 GET 表单/链接而不是 POST 表单(即使用 <a><form><h:link><h:button> 而不是 <h:form><h:commandXxx>)。 例如,逐页导航、类似 Google 的搜索表单等。

如果请求是非幂等的,只需在同一视图中有条件地显示结果(即从操作方法返回nullvoid 并使用例如<h:message(s)> 和/或rendered)。 例如,页内数据输入/编辑、多步向导、模态对话框、确认表单等。

如果请求是非幂等的,但目标页面是幂等的,只需在POST之后发送一个重定向(即从action方法返回结果?faces-redirect=true,或者手动调用ExternalContext#redirect(),或者把<redirect/>放在legacy XML 导航案例)。 例如编辑成功后显示所有数据列表、登录后重定向等。

请注意,纯页面到页面导航通常是幂等的,这就是许多 JSF 初学者因滥用命令链接/按钮而失败的地方,然后抱怨 URL 没有改变。另请注意,导航案例很少用于针对 SEO/UX 开发的实际应用程序中,这是许多 JSF 教程失败的地方,让读者不相信。

另外请注意,使用 POST 绝对不会比 GET“更安全”,因为请求参数不会立即在 URL 中可见。它们在 HTTP 请求正文中仍然可见并且仍然可以操作。因此,为了“安全”,绝对没有理由将 POST 用于幂等请求。真正的安全性在于使用 HTTPS 而不是 HTTP,并在当前登录的用户被允许查询实体 X 或操作实体 X 等情况下检查业务服务方法。一个体面的安全框架为此提供了注释。

另见:

What is the difference between redirect and navigation/forward and when to use what? JSF implicit vs. explicit navigation What URL to use to link / navigate to other JSF pages Bookmarkability via View Parameters feature What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for? When should I use h:outputLink instead of h:commandLink? Creating master-detail pages for entities, how to link them and which bean scope to choose Retaining GET request query string parameters on JSF form submit Pass an object between @ViewScoped beans without using GET params

【讨论】:

感谢您提供非常系统的答案。你提到了很多我不知道的选择。我会看看他们。多步骤向导确实是我的想法。您是否碰巧知道一个页面上有一个很好的示例,说明如何在不使用 3rd 方工具的情况下在单个页面上做到这一点? 例如***.com/questions/9741778/… 这很酷。用户仍然无法访问各个页面/步骤?我特别喜欢你可以使用@ViewScoped。谢谢! 请原谅我的无知 BalusC(再次)。为什么 JSF 的设计者不使用为浏览器的后退按钮存储的 URL 来知道将 POST 发回的位置,而不是弄乱浏览器的 URL。毫无疑问,这是有技术原因的,但这是唯一让我对 JSF 感到恼火的事情。它搞砸了:从子文件夹出来时的 CSS 文件位置;书签;还有容器安全性,因为它会很高兴地显示一个安全页面,因为容器安全性正在查看当前 URL,并查看前一页,而不是当前所谓的实际安全页面。 作为回答,只是不要使用 POST 进行页面到页面导航。

以上是关于如何在 JSF 中导航?如何使 URL 反映当前页面(而不是上一个页面)的主要内容,如果未能解决你的问题,请参考以下文章

用于链接/导航到其他 JSF 页面的 URL

如何在页面呈现期间测试是不是存在 JSF 导航案例

如何使用 FacesContext 在 JSF 中获取以前的 URL?

jsf 2.2 中的 URL 更新 [重复]

JSF:向操作方法添加参数后导航规则停止工作

如何在 JSF ajax 监听器方法中导航/重定向