刷新时如何防止重复条目?
Posted
技术标签:
【中文标题】刷新时如何防止重复条目?【英文标题】:How to prevent duplicate entries while refreshing? 【发布时间】:2012-09-25 07:51:30 【问题描述】:我有一个 index.jsp
页面,我有一个表单,用户可以在其中输入一些数据,这些数据使用 Controller servlet 存储在数据库中。
在数据库中输入数据后,我想显示与该表单相同的页面 (index.jsp
)。另外,我想显示用户在数据库中输入的所有条目。
我尝试使用RequestDispatcher
的forward()
方法。它工作正常(这意味着我能够再次显示相同的表单,并且还可以显示该用户使用 JSTL 在表单下方输入的所有数据)。
但问题是每当用户按下Refresh or F5
按钮时,所有以前的数据也会输入到数据库中,当我显示所有数据时,也会出现重复的条目。
我曾想过使用 POST-REDIRECT-GET 模式,但问题是当我重定向时,我无法使用 JSTL 显示这些数据。
我该怎么做?
【问题讨论】:
【参考方案1】:我会在页面中添加一个不可见的 ID。如果数据是数据库中的新数据(ID = 未知),则插入并创建一个 ID 并使用该 ID 更新页面。这样您就知道它是否是 ID != 未知,并且您不必进行插入。如果数据没有改变,你甚至不必进行更新......
【讨论】:
恐怕我对 servlet 没有经验。我写的是一个典型的场景,我使用普通的旧 Java 和数据库。我想你可以采用这种方法。我无法确定的是 servlet 技术是否有一些内置功能可以为您执行此操作。 Fildor 的建议就是这样做的方法。在隐藏字段中包含页面中记录的数据库 ID。如果用户还没有提交数据,这应该是 -1 或 0。当您处理插入数据的请求时,获取新插入行的数据库 ID,并将其包含在下次页面中。如果用户再次提交表单,则使用 ID 更新详细信息,这是他们所期望的。顺便说一句,在您的表单中使用 POST 而不是 GET - 然后会提醒用户,如果他们刷新数据将被重新提交。【参考方案2】:我认为 PRGP(Post Redirect Get Pattern)是解决这个问题的方法。如果您使用的是 Spring Web Flow,它有一个 FlashScope,您可以在其中放置要在 Post-get-redirection 之后保留的数据。使用这种方法,您可以保留的不仅仅是编辑 ID。
【讨论】:
【参考方案3】:我曾想过使用 POST-REDIRECT-GET 模式,但问题是当我重定向时,我无法使用 JSTL 显示这些数据。
只需发送一个请求参数即可识别您希望在新 GET 请求中显示的信息。
// ...
Long id = dataService.save(data);
// ...
response.sendRedirect(request.getContextPath() + "/index?editId=" + id);
然后在servlet 中映射到/index
的URL 模式
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
Long editId = Long.valueOf(request.getParameter("editId")); // Handle nullcheck yourself.
Data editData = dataService.find(editId);
request.setAttribute("editData", editData); // For the edit form.
List<Data> allData = dataService.list();
request.setAttribute("allData", allData); // For the table/list of all data.
request.getRequestDispatcher("/index.jsp").forward(request, response);
【讨论】:
谢谢 Balus,我认为这是一个很好的解决方案,我一定会尝试并让您知道。【参考方案4】:这是最简单的解决方案
<%@page import="java.util.*"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%!
//This List is just for demonstration purposes
List<String> names = new ArrayList<String>();
%>
<%
if(request.getParameter("name")!=null )
names.add(request.getParameter("name"));
session.setAttribute("nameList", names);
//Here you put your database insert code
//Whenever the code execution reaches this line ,
//then it means that you have a new page submission
//and not a refresh or f5 case
response.sendRedirect("index.jsp");
%>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form action="index.jsp" method="post">
<input type="text" id="name" name="name"/>
</form>
<p>
<table>
<c:forEach items="$nameList" var="element">
<tr>
<td>Name: <c:out value="$element"/> </td>
</tr>
</c:forEach>
</table>
</p>
</body>
</html>
诀窍在于response.sendRedirect("index.jsp");
。这使得null
成为所有请求参数。如果f5
或refresh
被命中,则if
永远不会被执行。如果是正常提交,则执行if
,然后调用response.sendRedirect("index.jsp");
。
总之,您真正需要做的就是:
1) 检查if(request.getParameter("name")!=null )
2) 如果以上为真,则进行数据库插入
3) 如果以上为真则response.sendRedirect("index.jsp");
更新
if(request.getParameter("name")!=null )
DbUtility.addNameToDb(request.getParameter("name"));
ArrayList<String> currentList = DbUtility.getAllNamesFromDb();
session.setAttribute("nameList", currentList);
response.sendRedirect("index.jsp");
您只需要实现这两种方法。 addNameToDb(String)
将使insert
在您的数据库中。 getAllNamesFromDb()
将返回一个 ArrayList<String>
对象,该对象将代表您数据库中的条目。 (并且您不再需要我之前在第一个答案中介绍的names
列表)
【讨论】:
您好,感谢您的回复,但我也想在数据库中添加条目。我想要做的是假设我使用数据库中的表单创建了 1 个条目,然后我的所有条目(假设名称是主键)应该显示在我使用的相同表单下方。它现在显示正常,但是当我点击刷新时,我也发现了重复的条目。 我会尝试,但我不想使用session
范围来存储我需要在request
范围内的数据。以上是关于刷新时如何防止重复条目?的主要内容,如果未能解决你的问题,请参考以下文章