日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

利用session防止表单重复提交

發(fā)布時(shí)間:2023/12/3 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 利用session防止表单重复提交 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1、是什么?一個(gè)表單不能多次提交;

2、為什么? 在網(wǎng)絡(luò)不好或者并發(fā)請(qǐng)求時(shí)會(huì)導(dǎo)致多次重復(fù)提交數(shù)據(jù)的問(wèn)題。防止重復(fù)提交,可以維護(hù)數(shù)據(jù)一致性;

3、怎么做? 把 session的編號(hào)和當(dāng)前時(shí)間戳經(jīng)過(guò) MD5 加密得到token并存入 session;更多token 介紹參見(jiàn)?https://blog.csdn.net/PacosonSWJTU/article/details/109958455??

更多加密算法介紹(MD5, SHA, AES, DES ),參見(jiàn)??https://blog.csdn.net/PacosonSWJTU/article/details/109954811

?

【荔枝】轉(zhuǎn)自 張孝祥??

token 生成方式如下:??(更加通用的方法是,把 用戶名,密碼當(dāng)做加密源進(jìn)行加密,得到摘要作為token)?

/*** 產(chǎn)生表單標(biāo)識(shí)號(hào)并將之保存在當(dāng)前用戶Session中。**@param request 封裝當(dāng)前請(qǐng)求消息的HttpServletRequest對(duì)象*/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,該表單會(huì)帶上token; (有token,可以理解為已經(jīng)登錄了,登錄信息加密為token令牌)?

// 填寫(xiě)表單 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 會(huì)把 token 從 會(huì)話移除, 防止二次提交;?

// 表單處理邏輯 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("這是重復(fù)或非法提交!");return;}String p1 = request.getParameter("p1");if(p1==null || p1.trim().equals("")){out.println("請(qǐng)輸入內(nèi)容!");}else{out.println("提交內(nèi)容已被處理!");tokenProcessor.resetToken(request); // 一旦處理成功, 移除掉token ,防止2次重復(fù)提交 }} }

=========== TokenProcessor全部代碼如下:

// token標(biāo)識(shí)處理器 public class TokenProcessor {private long previous; //上次生成表單標(biāo)識(shí)號(hào)的時(shí)間值private static TokenProcessor instance = new TokenProcessor();public static String FORM_TOKEN_KEY = "FORM_TOKEN_KEY";private TokenProcessor(){}public static TokenProcessor getInstance(){return instance;}/***驗(yàn)證請(qǐng)求消息中的標(biāo)識(shí)號(hào)是否有效,如果請(qǐng)求消息中的表單標(biāo)識(shí)號(hào)與當(dāng)前*用戶的Session域中的表單標(biāo)識(shí)號(hào)相同,返回結(jié)果為true,否則返回false。**@param request 封裝當(dāng)前請(qǐng)求消息的HttpServletRequest對(duì)象*/public synchronized boolean isTokenValid(HttpServletRequest request){/*為避免Session對(duì)象不存在時(shí)創(chuàng)建Session對(duì)象,下面的語(yǔ)句不用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);}/*** 清除存儲(chǔ)在當(dāng)前用戶Session中的表單標(biāo)識(shí)號(hào)。**@param request 封裝當(dāng)前請(qǐng)求消息的HttpServletRequest對(duì)象*/public synchronized void resetToken(HttpServletRequest request){HttpSession session = request.getSession(false);if (session == null){return;}session.removeAttribute(FORM_TOKEN_KEY);}/*** 產(chǎn)生表單標(biāo)識(shí)號(hào)并將之保存在當(dāng)前用戶Session中。**@param request 封裝當(dāng)前請(qǐng)求消息的HttpServletRequest對(duì)象*/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){;}}/*** 將一個(gè)字節(jié)數(shù)組轉(zhuǎn)換成十六進(jìn)制的字符串形式返回。* @param buffer 要被轉(zhuǎn)換的字節(jié)數(shù)組*/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、訪問(wèn)記錄?

步驟1,?

步驟2,輸入值,提交;?

步驟3,刷新, (系統(tǒng)判定為重復(fù)提交,因?yàn)榈?步,提交成功后, 系統(tǒng)移除了token )?

?

?

總結(jié)

以上是生活随笔為你收集整理的利用session防止表单重复提交的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。