JavaWeb中HttpSession中表单的重复提交示例
程序员文章站
2024-03-06 10:49:07
表单的重复提交
重复提交的情况:
①. 在表单提交到一个 servlet,而 servlet 又通过请求转发的方式响应了一个 jsp(html)页面,此时地...
表单的重复提交
- 重复提交的情况:
①. 在表单提交到一个 servlet,而 servlet 又通过请求转发的方式响应了一个 jsp(html)页面,此时地址栏还保留着 servlet 的那个路径,在响应页面点击 “刷新”。
②. 在响应页面没有到达时,重复点击 “提交按钮”
③. 点击返回,再点击提交
- 不是重复提交的情况:点击 “返回”,“刷新” 原表单页面,再点击提交。
- 如何避免表单的重复提交:在表单中做一个标记,提交到 servlet 时,检查标记是否存在且和预定义的标记一样,若一致,则受理请求,并销毁标记,若不一致或没有标记,则直接响应提示信息:“重复提交”
①仅提供一个隐藏域不行:<input type="hidden" name="token" value="lsy">
②把标记放在 request 中 , 行不通,表单页面刷新后,request 已经被销毁,再提交表单是一个新的 request 的。
③把标记放在 session 中,可以
1. 在原表单页面,生成一个随机值 token
2. 在原表单页面,把 token 值放入 session 属性中
3. 在原表单页面,把 token 值放入到隐藏域
4. 在目标的 servlet 中:获取 session 和隐藏域中的 token 值
比较两个值是否一致,受理请求,且把 session 域中的 token 属性清除,若不一致,则直接响应提示页面:“重复提交”
我们可以通过 struts1 中写好的类 tokenprocessor 来重构代码, 面向组件编程
package com.lsy.javaweb; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpsession; import java.security.messagedigest; import java.security.nosuchalgorithmexception; public class tokenprocessor { private static final string token_key = "token_key"; private static final string transaction_token_key = "transaction_token_key"; /** * the singleton instance of this class. */ private static tokenprocessor instance = new tokenprocessor(); /** * the timestamp used most recently to generate a token value. */ private long previous; /** * protected constructor for tokenprocessor. use * tokenprocessor.getinstance() to obtain a reference to the processor. */ protected tokenprocessor() { super(); } /** * retrieves the singleton instance of this class. */ public static tokenprocessor getinstance() { return instance; } /** * <p> * return <code>true</code> if there is a transaction token stored in the * user's current session, and the value submitted as a request parameter * with this action matches it. returns <code>false</code> under any of the * following circumstances: * </p> * * <ul> * * <li>no session associated with this request</li> * * <li>no transaction token saved in the session</li> * * <li>no transaction token included as a request parameter</li> * * <li>the included transaction token value does not match the transaction * token in the user's session</li> * * </ul> * * @param request * the servlet request we are processing */ public synchronized boolean istokenvalid(httpservletrequest request) { return this.istokenvalid(request, false); } /** * return <code>true</code> if there is a transaction token stored in the * user's current session, and the value submitted as a request parameter * with this action matches it. returns <code>false</code> * * <ul> * * <li>no session associated with this request</li> * <li>no transaction token saved in the session</li> * * <li>no transaction token included as a request parameter</li> * * <li>the included transaction token value does not match the transaction * token in the user's session</li> * * </ul> * * @param request * the servlet request we are processing * @param reset * should we reset the token after checking it? */ public synchronized boolean istokenvalid(httpservletrequest request, boolean reset) { // retrieve the current session for this request httpsession session = request.getsession(false); if (session == null) { return false; } // retrieve the transaction token from this session, and // reset it if requested string saved = (string) session.getattribute(transaction_token_key); if (saved == null) { return false; } if (reset) { this.resettoken(request); } // retrieve the transaction token included in this request string token = request.getparameter(token_key); if (token == null) { return false; } return saved.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 */ public synchronized void resettoken(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 */ public synchronized string savetoken(httpservletrequest request) { httpsession session = request.getsession(); string token = generatetoken(request); if (token != null) { session.setattribute(transaction_token_key, token); } return token; } /** * generate a new transaction token, to be used for enforcing a single * request for a particular transaction. * * @param request * the request we are processing */ public synchronized string generatetoken(httpservletrequest request) { httpsession session = request.getsession(); return generatetoken(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. */ public synchronized string generatetoken(string id) { try { 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.getbytes()); md.update(now); return tohex(md.digest()); } catch (nosuchalgorithmexception e) { return null; } } /** * convert a byte array to a string of hexadecimal digits and return it. * * @param buffer * the byte array to be converted */ 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(); } }
以上所述是小编给大家介绍的javaweb中httpsession中表单的重复提交示例,希望对大家有所帮助