避免在JSF中刷新时两次创建同一对象

避免在JSF中刷新时两次创建同一对象,jsf,Jsf,假设我们在AddObject.jspx中有一个“addnewobject”表单,还有一个Confirm.jsp页面(比如说数据库中添加了id为NN的object…) 在faces-config.xml中: <navigation-rule> <from-view-id>/AddObject.jsp</from-view-id> <navigation-case> <from-outcome>add<

假设我们在AddObject.jspx中有一个“addnewobject”表单,还有一个Confirm.jsp页面(比如说数据库中添加了id为NN的object…)

在faces-config.xml中:

<navigation-rule>
    <from-view-id>/AddObject.jsp</from-view-id>
    <navigation-case>
        <from-outcome>add</from-outcome>
        <to-view-id>/Confirm.jsp</to-view-id>
    </navigation-case>
</navigation-rule>

/AddObject.jsp
添加
/Confirm.jsp
因此,用户打开AddObject.jsp,填写表单,然后单击“添加”按钮,该按钮在AddObject的支持bean中触发事件处理程序。支持bean将新对象插入数据库并返回“add”结果。因此,我们最终进入确认屏幕

现在,如果我点击F5(刷新浏览器),将创建一个新对象,并使用新对象的新ID重新显示确认屏幕。我可以继续按F5键,得到我想要的任何新对象

我不要这个。我想检测这种情况。避免多次添加同一对象(在数据库中生成许多只因ID不同的行)


我可以用JSF做这个吗?如果它似乎没有很好地利用这些信息,为什么它会要求我提供从视图id/结果/到视图id?

这个问题有两个部分

首先,您需要避免broswer刷新确认页面重新提交请求。因此,如果浏览器的历史不说

 POST this request
而是说

 GET this confirmation page
我们可以通过使用

 <redirect/>

JSF导航中的语句。现在,这意味着将向浏览器发送重定向响应。浏览器然后向JSF请求确认页面。注意:从JSF的角度来看,这是一个新的请求,所以您想要显示的任何数据都需要在会话范围而不是请求范围内

这种“对进行更改的操作使用重定向”的方法是一种非常常见的习惯用法。但是,它并没有解决“QuickFire用户”问题。如果用户快速点击“提交”两次,会发生什么?您可能会遇到浏览器已发送两个请求的情况。还有其他可能发生这种情况的场景——第一个请求出现网络故障,用户变得不耐烦,再次发送请求

因此,我们需要设法处理这种双重提交。这不是JSF特有的问题。典型的解决方案是,后端在填充原始请求页面时发送令牌。这是在一个隐藏的领域举行。当请求被提交时,令牌(某个唯一的数字)被发送回记录其已被使用的应用程序,因此检测到双重提交


您还可以在浏览器中使用JavaScript来防止重复提交。这将提供更友好的用户体验,但我不建议只依赖浏览器端控件。服务器应该具有最终的响应能力。

感谢您的回复。但是“存储确认屏幕所需的一切,然后重定向到确认屏幕”的解决方法有点像黑客。即便如此,我想我还是会使用它,因为我想不出更好的替代方案。(顺便说一句,我想让会话尽可能精简…)令人失望的是,JSF提供了优雅地解决问题所需的所有信息,但却愚蠢得无法使用这些信息:-(我不同意这是一种黑客行为。你会让它把东西存储在哪里?重要的是,你需要告诉浏览器调整它的历史视图-因此我们必须告诉浏览器重定向。因此提交屏幕数据必须存储在会话id键入的某个地方,这就是会话的用途。这不是JSF特有的解决方案。