jsf viewparam 验证错误后丢失
我面临以下问题:在一页中,我列出了应用程序的所有用户,并为每个用户提供了一个“编辑”按钮,这是一个带有 ?id=
编辑页面在元数据中有一个
。
如果我犯了一些输入错误并提交(我使用 CDI Weld Bean 验证),页面会再次显示,但我丢失了 URL 中的 ?id=...
,因此失去了用户我正在编辑的用户的 id。
我看过 JSF 验证错误,丢失值中描述的类似问题,但是使用 inputhidden 的解决方案(或更糟的是,使用战斧(看起来有点大材小用)需要大量丑陋的代码。
我尝试过使用 CDI 添加“对话”,它正在工作,但对我来说,它看起来又太过分了。
JSF 中是否存在一个简单的解决方案来在验证错误时保留视图参数?
[我的环境:Tomcat7 + MyFaces 2.1.0 + Hibernate Validator 4.2.0 + CDI(Weld) 1.1.2]
I'm facing the following issue: in one page, I list all users of my application and have an "edit" button for each one, which is a "GET" link with ?id=<userid>
.
The edit page has a <f:viewParam name="id" value="#{editUserBean.id}"/>
in metadata.
If I made some input mistakes and submit (I use CDI Weld Bean validation), the page is displayed again, but I've lost the ?id=...
in the URL and so lose the user id of the user I'm editing.
I've looked at a similar problem described in JSF validation error, lost value, but the solution with inputhidden (or worse, with tomahawk, which looks overkill) requires lot of uggly code.
I've tried adding a "Conversation" with CDI, and it is working, but it looks like too much overkill to me again.
Does there exists a simple solution in JSF to preserve view parameters in case of validation errors?
[My environment: Tomcat7 + MyFaces 2.1.0 + Hibernate Validator 4.2.0 + CDI(Weld) 1.1.2]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
有趣的案例。对于每个人来说,以下最小代码都会重现这一点:
Facelet:
Bean:
如果您使用
viewparam.xhtml?id=12
调用 Facelet,它将在屏幕上显示12
。如果您随后输入有效的内容,例如aaaaa
,则 id 将从 URL 中消失,但会继续显示在屏幕上(由于 ui 组件的有状态特性)。然而...正如OP提到的,一旦发生任何验证器错误(例如输入
a
),id将永久丢失。之后输入有效的内容不会将其恢复。这几乎看起来像是一个错误,但我尝试了 Mojarra 2.1 和 Myfaces 2.1,两者都有相同的行为。更新:
经过一番检查,问题似乎出在“UIViewParameter”(Mojarra)的这个方法中:
然后更具体地说,这个方法:
因为
hasValueExpression()
为 true,它将尝试从模型(支持 bean)获取值。但由于该 bean 是请求范围的,因此该请求不会有任何值,因为验证刚刚失败,因此尚未设置任何值。实际上,UIViewParameter
的有状态值会被支持 bean 返回的默认值(通常为 null,但这当然取决于您的 bean)覆盖。一种解决方法是使您的 bean
@ViewScoped
,无论如何,这通常是一个更好的范围(我假设您使用该参数从服务获取用户,并且可能没有必要一遍又一遍地这样做在每次回发时)。另一种替代方法是创建您自己的
UIViewParameter
版本,如果验证失败,它不会尝试从模型中获取值(基本上所有其他UIInput
组件都会这样做)。Interesting case. For everyone, the following minimal code reproduces this:
Facelet:
Bean:
If you call the Facelet with
viewparam.xhtml?id=12
it will display the12
onscreen. If you then input something valid, e.g.aaaaa
, the id will disappear from the URL, but keeps being displayed on screen (owning to the stateful nature of ui components).However... as OP mentioned, as soon as any validator error occurs (e.g. entering
a
), the id will be permanently lost. Entering valid input afterwards will not bring it back. It almost seems like a bug, but I tried both Mojarra 2.1 and Myfaces 2.1 and both have the same behavior.Update:
After some inspection, the problem seems to be in this method of `UIViewParameter' (Mojarra):
And then more specifically this method:
Because
hasValueExpression()
is true, it will try to get the value from the model (the backing bean). But since this bean was request scoped it will not have any value for this request, since validation has just failed and thus no value has ever been set. In effect, the stateful value ofUIViewParameter
is overwritten by whatever the backing bean returns as a default (typically null, but it depends on your bean of course).One workaround is to make your bean
@ViewScoped
, which is often a better scope anyway (I assume you use the parameter to get a user from a Service, and it's perhaps unnecessary to do that over and over again at every postback).Another alternative is to create your own version of
UIViewParameter
that doesn't try to get the value from the model if validation has failed (as basically all otherUIInput
components do).您实际上并没有丢失视图参数。 f:viewParam 是有状态的,因此即使它不在 URL 中,它仍然存在。只需在绑定到查看参数的 setter 中放置一个断点或 system.out 即可。
(如果你在 viewParam stateless stateful 上搜索,你会找到更多信息)
You don't actually loose the view parameter. f:viewParam is stateful, so even if it's not in the URL, it's still there. Just put a break point or system.out in the setter bound to view param.
(if you google on viewParam stateless stateful you'll find some more info)
我的应用程序中也有同样的内容。我切换到@ViewAccessScoped,它允许更优雅的实现。
I've the same in my Application. I switched to @ViewAccessScoped which allows way more elegant implementations.
或者,当您第一次从 url 获取参数时,将其保存在会话映射中并继续从该映射中使用,并在保存/或更新表单后清除映射。
Or when you the first time get parameter from url, save it in session map and continue use from that map, and after save/or update the form clean map.
这很棘手,但您可以尝试使用 History API 恢复视图参数:
This is tricky, but you can try to restore view parameters with History API: