最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
JavaWeb中HttpSession中表单的重复提交示例
时间:2022-06-29 01:34:06 编辑:袖梨 来源:一聚教程网
表单的重复提交
重复提交的情况:
①. 在表单提交到一个 Servlet,而 Servlet 又通过请求转发的方式响应了一个 JSP(HTML)页面,此时地址栏还保留着 Servlet 的那个路径,在响应页面点击 “刷新”。
②. 在响应页面没有到达时,重复点击 “提交按钮”
③. 点击返回,再点击提交
不是重复提交的情况:点击 “返回”,“刷新” 原表单页面,再点击提交。
如何避免表单的重复提交:在表单中做一个标记,提交到 Servlet 时,检查标记是否存在且和预定义的标记一样,若一致,则受理请求,并销毁标记,若不一致或没有标记,则直接响应提示信息:“重复提交”
①仅提供一个隐藏域不行:
②把标记放在 Request 中 , 行不通,表单页面刷新后,request 已经被销毁,再提交表单是一个新的 request 的。
③把标记放在 Session 中,可以
1. 在原表单页面,生成一个随机值 token
2. 在原表单页面,把 token 值放入 session 属性中
3. 在原表单页面,把 token 值放入到隐藏域
4. 在目标的 Servlet 中:获取 session 和隐藏域中的 token 值
比较两个值是否一致,受理请求,且把 session 域中的 token 属性清除,若不一致,则直接响应提示页面:“重复提交”
我们可以通过 Struts1 中写好的类 TokenProcessor 来重构代码, 面向组件编程
代码如下 | 复制代码 |
packagecom.lsy.javaweb; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpSession; importjava.security.MessageDigest; importjava.security.NoSuchAlgorithmException; publicclassTokenProcessor { privatestaticfinalString TOKEN_KEY ="TOKEN_KEY"; privatestaticfinalString TRANSACTION_TOKEN_KEY ="TRANSACTION_TOKEN_KEY"; /** * The singleton instance of this class. */ privatestaticTokenProcessor instance =newTokenProcessor(); /** * The timestamp used most recently to generate a token value. */ privatelongprevious; /** * Protected constructor for TokenProcessor. Use * TokenProcessor.getInstance() to obtain a reference to the processor. */ protectedTokenProcessor() { super(); } /** * Retrieves the singleton instance of this class. */ publicstaticTokenProcessor getInstance() { returninstance; } /** * * Return * user's current session, and the value submitted as a request parameter * with this action matches it. Returns * following circumstances: * * * * *
* *
* *
* *
* token in the user's session * * * * @param request * The servlet request we are processing */ publicsynchronizedbooleanisTokenValid(HttpServletRequest request) { returnthis.isTokenValid(request,false); } /** * Return * user's current session, and the value submitted as a request parameter * with this action matches it. Returns * * * *
*
* *
* *
* token in the user's session * * * * @param request * The servlet request we are processing * @param reset * Should we reset the token after checking it? */ publicsynchronizedbooleanisTokenValid(HttpServletRequest request,booleanreset) { // Retrieve the current session for this request HttpSession session = request.getSession(false); if(session ==null) { returnfalse; } // Retrieve the transaction token from this session, and // reset it if requested String saved = (String) session.getAttribute(TRANSACTION_TOKEN_KEY); if(saved ==null) { returnfalse; } if(reset) { this.resetToken(request); } // Retrieve the transaction token included in this request String token = request.getParameter(TOKEN_KEY); if(token ==null) { returnfalse; } returnsaved.equals(token); } /** * Reset the saved transaction token in the user's session. This indicates * that transactional token checking will not be needed on the next request * that is submitted. * * @param request * The servlet request we are processing */ publicsynchronizedvoidresetToken(HttpServletRequest request) { HttpSession session = request.getSession(false); if(session ==null) { return; } session.removeAttribute(TRANSACTION_TOKEN_KEY); } /** * Save a new transaction token in the user's current session, creating a * new session if necessary. * * @param request * The servlet request we are processing */ publicsynchronizedString saveToken(HttpServletRequest request) { HttpSession session = request.getSession(); String token = generateToken(request); if(token !=null) { session.setAttribute(TRANSACTION_TOKEN_KEY, token); } returntoken; } /** * Generate a new transaction token, to be used for enforcing a single * request for a particular transaction. * * @param request * The request we are processing */ publicsynchronizedString generateToken(HttpServletRequest request) { HttpSession session = request.getSession(); returngenerateToken(session.getId()); } /** * Generate a new transaction token, to be used for enforcing a single * request for a particular transaction. * * @param id * a unique Identifier for the session or other context in which * this token is to be used. */ publicsynchronizedString generateToken(String id) { try{ longcurrent = System.currentTimeMillis(); if(current == previous) { current++; } previous = current; byte[] now =newLong(current).toString().getBytes(); MessageDigest md = MessageDigest.getInstance("MD5"); md.update(id.getBytes()); md.update(now); returntoHex(md.digest()); }catch(NoSuchAlgorithmException e) { returnnull; } } /** * Convert a byte array to a String of hexadecimal digits and return it. * * @param buffer * The byte array to be converted */ privateString toHex(byte[] buffer) { StringBuffer sb =newStringBuffer(buffer.length *2); for(inti =0; i < buffer.length; i++) { sb.append(Character.forDigit((buffer[i] &0xf0) >>4,16)); sb.append(Character.forDigit(buffer[i] &0x0f,16)); } returnsb.toString(); } } |
相关文章
- 《燕云十六声》配置要求介绍 12-25
- 《燕云十六声》搬砖介绍 12-25
- 时空中的绘旅人天宇之间怎么玩 绘旅人天宇之间活动玩法介绍 12-25
- QQ2024年度报告怎么看 2024qq年度报告玩法介绍 12-25
- 归龙潮珠砂什么时候up 归龙潮红缘绮梦卡池介绍 12-25
- 王者荣耀S38赛季有什么更新 12-25