利用session防止表单重复提交
1、是什么?一個表單不能多次提交;
2、為什么? 在網絡不好或者并發請求時會導致多次重復提交數據的問題。防止重復提交,可以維護數據一致性;
3、怎么做? 把 session的編號和當前時間戳經過 MD5 加密得到token并存入 session;更多token 介紹參見?https://blog.csdn.net/PacosonSWJTU/article/details/109958455??
更多加密算法介紹(MD5, SHA, AES, DES ),參見??https://blog.csdn.net/PacosonSWJTU/article/details/109954811
?
【荔枝】轉自 張孝祥??
token 生成方式如下:??(更加通用的方法是,把 用戶名,密碼當做加密源進行加密,得到摘要作為token)?
/*** 產生表單標識號并將之保存在當前用戶Session中。**@param request 封裝當前請求消息的HttpServletRequest對象*/public synchronized void saveToken(HttpServletRequest request){HttpSession session = request.getSession();try {byte id[] = session.getId().getBytes();long current = System.currentTimeMillis();if (current == previous){current++;}previous = current;byte now[] = String.valueOf(current).getBytes();// 基于MD5加密 MessageDigest md = MessageDigest.getInstance("MD5");md.update(id);md.update(now);String token = toHex(md.digest());session.setAttribute(FORM_TOKEN_KEY, token);}catch (NoSuchAlgorithmException e){;}}生成表單的servlet,該表單會帶上token; (有token,可以理解為已經登錄了,登錄信息加密為token令牌)?
// 填寫表單 public class FormGenerateServlet extends HttpServlet {public void service(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{response.setContentType("text/html;charset=GB2312");PrintWriter out = response.getWriter();TokenProcessor.getInstance().saveToken(request);String token = (String)request.getSession().getAttribute(TokenProcessor.FORM_TOKEN_KEY);out.println("<form action='FormDealServlet'" + "method='POST'>" +"<input type='hidden' name='" + TokenProcessor.FORM_TOKEN_KEY + "' value='" + token + "'>" +"字段1:<input type='text' name='p1'><br>" +"<input type='submit' value='提交'> " +"</form>");} }處理邏輯servlet DealServlet, 可以看到, 一旦提交成功, 該servlet 會把 token 從 會話移除, 防止二次提交;?
// 表單處理邏輯 servlet public class FormDealServlet extends HttpServlet {public void service(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{response.setContentType("text/html;charset=GB2312");PrintWriter out = response.getWriter(); TokenProcessor tokenProcessor = TokenProcessor.getInstance();if(!tokenProcessor.isTokenValid(request)){out.println("這是重復或非法提交!");return;}String p1 = request.getParameter("p1");if(p1==null || p1.trim().equals("")){out.println("請輸入內容!");}else{out.println("提交內容已被處理!");tokenProcessor.resetToken(request); // 一旦處理成功, 移除掉token ,防止2次重復提交 }} }=========== TokenProcessor全部代碼如下:
// token標識處理器 public class TokenProcessor {private long previous; //上次生成表單標識號的時間值private static TokenProcessor instance = new TokenProcessor();public static String FORM_TOKEN_KEY = "FORM_TOKEN_KEY";private TokenProcessor(){}public static TokenProcessor getInstance(){return instance;}/***驗證請求消息中的標識號是否有效,如果請求消息中的表單標識號與當前*用戶的Session域中的表單標識號相同,返回結果為true,否則返回false。**@param request 封裝當前請求消息的HttpServletRequest對象*/public synchronized boolean isTokenValid(HttpServletRequest request){/*為避免Session對象不存在時創建Session對象,下面的語句不用request.getSession()*/HttpSession session = request.getSession(false);if (session == null){return false;}String saved = (String) session.getAttribute(FORM_TOKEN_KEY);if (saved == null){return false;}String token = request.getParameter(FORM_TOKEN_KEY);if (token == null){return false;}return saved.equals(token);}/*** 清除存儲在當前用戶Session中的表單標識號。**@param request 封裝當前請求消息的HttpServletRequest對象*/public synchronized void resetToken(HttpServletRequest request){HttpSession session = request.getSession(false);if (session == null){return;}session.removeAttribute(FORM_TOKEN_KEY);}/*** 產生表單標識號并將之保存在當前用戶Session中。**@param request 封裝當前請求消息的HttpServletRequest對象*/public synchronized void saveToken(HttpServletRequest request){HttpSession session = request.getSession();try {byte id[] = session.getId().getBytes();long current = System.currentTimeMillis();if (current == previous){current++;}previous = current;byte now[] = String.valueOf(current).getBytes();// 基于MD5加密 MessageDigest md = MessageDigest.getInstance("MD5");md.update(id);md.update(now);String token = toHex(md.digest());session.setAttribute(FORM_TOKEN_KEY, token);}catch (NoSuchAlgorithmException e){;}}/*** 將一個字節數組轉換成十六進制的字符串形式返回。* @param buffer 要被轉換的字節數組*/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();} }
4、訪問記錄?
步驟1,?
步驟2,輸入值,提交;?
步驟3,刷新, (系統判定為重復提交,因為第2步,提交成功后, 系統移除了token )?
?
?
總結
以上是生活随笔為你收集整理的利用session防止表单重复提交的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: servlet session 跟踪用户
- 下一篇: repo-关于URL编码