---使用HttpSession防止表单重复提交
来源:互联网 发布:淘宝10元包邮怎么赚钱 编辑:程序博客网 时间:2024/06/07 00:29
可能出现表单重复提交的情况
- 表单数据中的数据提交到一个servlet,servlet通过转发的方式相应了一个jsp页面(地址栏中任然是servlet的url),然后刷新当前页面。
- 在提交表单的时候,相应过程中重复点击。
- 到达相应页面后,点击浏览器返回按钮再重新点击提交。
解决办法
思想案例
思想:
在相应表单页面的时候,添加一个标记,当表单数据提交过去的时候,验证标记,并且删除标记,如果出现表单数据提交,那么就相应提示信息。
例子:
index.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%><% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><base href="<%=basePath%>"><title>My JSP 'index.jsp' starting page</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"><meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><!-- <link rel="stylesheet" type="text/css" href="styles.css"> --></head><body> <% String tokenValue = new Date().getTime() + ""; session.setAttribute("token", tokenValue); %> This is my JSP page. <br> <form action="<%=request.getContextPath()%>/tokenServlet" method="post"> <input type="hidden" name="token" value="<%=tokenValue%>"> <input type="text" name="username" /> <input type="submit" value="submit" /> </form></body></html>
TokenServlet.java
package com.aaa.servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;public class TokenServlet extends HttpServlet { private static final long serialVersionUID = 1L; public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); String tokenValue = request.getParameter("token"); Object token = session.getAttribute("token"); System.out.println(token); System.out.println(tokenValue); if (token != null && token.equals(tokenValue)) { session.removeAttribute("token"); } else { response.sendRedirect(request.getContextPath() + "/token/token.jsp"); return; } String username = request.getParameter("username"); System.out.println("username---" + username); request.setAttribute("username", username); request.getRequestDispatcher("/token/success.jsp").forward(request, response); }}
success.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%><% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><base href="<%=basePath%>"><title>My JSP 'success.jsp' starting page</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"><meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><!-- <link rel="stylesheet" type="text/css" href="styles.css"> --></head><body> <h1> Hello <%=request.getAttribute("username")%></h1></body></html>
token.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><base href="<%=basePath%>"><title>My JSP 'token.jsp' starting page</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"><meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><!-- <link rel="stylesheet" type="text/css" href="styles.css"> --></head><body>表单重复提交</body></html>
分析:在这个案例中,在相应index.jsp页面的时候,生成一个值tokenValue放在session(token-tokenValue)中,并且在表单中添加一个隐藏域token(token-tokenvalue),然后在表单数据提交到servlet的时候,将从隐藏域中的token和session中的token验证是否一致,一致则相应success.jsp,不一致则响应token.jsp提示表单重复提交。
使用TokenProcessor类来防止表单重复提交
使用这个的目的是为了提高代码的重用,总不可能在每次需要防止表单重复提交的地方都重写一遍这些吧,应该把他抽出来,我的理解是这个也是一种思想,将从重复的工作解放出来。
原理大都和前面类似
1. 在访问包含表单的页面的时候,产生一个token,存放在session中。
2. 在表单中提交的时候,将token放在隐藏域中提交到servlet,如果一致 则清楚session的令牌值 然后执行处理操作, 如果不相等 则提示用户已经提交过表单 同时产生一个新的token保存到session中 当用户再次到提交数据页面的时候 将新产生的令牌值最为隐藏输入域的值
TokenProcessor.java:
package com.aaa.tokenprocess;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;/** * TokenProcessor类是一个单例类。 */public class TokenProcessor { static final String TOKEN_KEY = "org.tuxianchao.token"; private static TokenProcessor instance = new TokenProcessor(); /** * 得到单例的实例。 */ public static TokenProcessor getInstance() { return instance; } /** * 最近一次生成令牌值的时间戳。 */ private long previous; /** * 判断请求参数中的令牌值是否有效。 */ public synchronized boolean isTokenValid(HttpServletRequest request) { // 得到请求的当前Session对象。 HttpSession session = request.getSession(false); if (session == null) { return false; } // 从Session中取出保存的令牌值。 String saved = (String) session.getAttribute(TOKEN_KEY); if (saved == null) { return false; } // 清除Session中的令牌值。 resetToken(request); // 得到请求参数中的令牌值。 String token = request.getParameter(TOKEN_KEY); if (token == null) { return false; } return saved.equals(token); } /** * 清除Session中的令牌值。 */ public synchronized void resetToken(HttpServletRequest request) { HttpSession session = request.getSession(false); if (session == null) { return; } session.removeAttribute(TOKEN_KEY); } /** * 产生一个新的令牌值,保存到Session中, 如果当前Session不存在,则创建一个新的Session。 */ public synchronized void saveToken(HttpServletRequest request) { HttpSession session = request.getSession(); String token = generateToken(request); if (token != null) { session.setAttribute(TOKEN_KEY, token); } } /** * 根据session ID和当前的系统时间生成一个唯一的令牌。 */ public synchronized String generateToken(HttpServletRequest request) { HttpSession session = request.getSession(); try { byte id[] = session.getId().getBytes(); long current = System.currentTimeMillis(); if (current == previous) { current++; } previous = current; byte now[] = new Long(current).toString().getBytes(); MessageDigest md = MessageDigest.getInstance("MD5"); md.update(id); md.update(now); return toHex(md.digest()); } catch (NoSuchAlgorithmException e) { return null; } } /** * 将一个字节数组转换为一个十六进制数字的字符串。 */ private String toHex(byte buffer[]) { StringBuffer sb = new StringBuffer(buffer.length * 2); for (int i = 0; i < buffer.length; i++) { sb.append(Character.forDigit((buffer[i] & 0xf0) >> 4, 16)); sb.append(Character.forDigit(buffer[i] & 0x0f, 16)); } return sb.toString(); } /** * 从Session中得到令牌值,如果Session中没有保存令牌值,则生成一个新的令牌值。 */ public synchronized String getToken(HttpServletRequest request) { HttpSession session = request.getSession(false); if (null == session) return null; String token = (String) session.getAttribute(TOKEN_KEY); if (null == token) { token = generateToken(request); if (token != null) { session.setAttribute(TOKEN_KEY, token); return token; } else return null; } else return token; }}
修改后的index.jsp:
<%@page import="com.aaa.tokenprocess.TokenProcessor"%><%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%><% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><base href="<%=basePath%>"><title>My JSP 'index.jsp' starting page</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"><meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><!-- <link rel="stylesheet" type="text/css" href="styles.css"> --></head><body> <% //取得TokenProcess的实例对象 TokenProcessor tokenProcessor = TokenProcessor.getInstance(); //获取token String token = tokenProcessor.getToken(request); %> This is my JSP page. <br> <form action="<%=request.getContextPath()%>/tokenServlet1" method="post"> <!-- 添加隐藏域,其值为token--> <input type="hidden" name="org.tuxianchao.token" value="<%=token%>"> <input type="text" name="username" /> <input type="submit" value="submit" /> </form></body></html>
修改后的TokenServlet.java:
package com.aaa.servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import com.aaa.tokenprocess.TokenProcessor;public class TokenServlet1 extends HttpServlet { private static final long serialVersionUID = 1L; public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { TokenProcessor tokenProcessor = TokenProcessor.getInstance(); if (tokenProcessor.isTokenValid(request)) { // 合法 request.getRequestDispatcher("/token/success.jsp").forward(request, response); } else { // 不合法 tokenProcessor.saveToken(request); response.sendRedirect(request.getContextPath() + "/token/token.jsp"); } }}
0 0
- ---使用HttpSession防止表单重复提交
- 使用JavaScript防止表单重复提交
- 使用Javascript防止重复提交表单
- 使用拦截器防止表单重复提交
- strsuts2使用标签防止表单重复提交
- struts2 使用标签防止表单重复提交
- 使用Session防止表单重复提交
- PHP使用session防止表单重复提交
- session的使用:防止表单重复提交
- 使用Struts 2防止表单重复提交
- 使用Session防止表单重复提交
- 使用Session防止表单重复提交
- 使用Session防止表单重复提交
- 使用Session防止表单重复提交
- 使用Session防止表单重复提交
- 使用Session防止表单重复提交
- 使用Session防止表单重复提交
- 使用Session防止表单重复提交
- Wireshark过滤器使用规则介绍
- HDU 4126 Genghis Khan the Conqueror(树形dp,MST,破坏原有最小生成树边后的最小生成树代价)
- UVA 116 Unidirectional TSP 动态规划+类似数塔
- 338. Counting Bits
- About Core Animation
- ---使用HttpSession防止表单重复提交
- DMA
- Codeforces Round #344 (Div. 2)D. Messenger【kmp】
- Android自定义控件之日历控件
- sql create table index
- SpringMVC 上传文件出现 Provisional headers are shown 和 response 数据 无法输出问题
- node之hello world
- 工厂,模式
- 总结下这周的get点w4day3