java 请求重复提交表单_JavaWeb中HttpSession中表单的重复提交示例

表单的重复提交

重复提交的情况:

①. 在表单提交到一个 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 来重构代码, 面向组件编程

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;

}

/**

*

* Return true 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 false under any of the

* following circumstances:

*

*

*

*

*

No session associated with this request

*

*

No transaction token saved in the session

*

*

No transaction token included as a request parameter

*

*

The included transaction token value does not match the transaction

* token in the user's session

*

*

*

* @param request

* The servlet request we are processing

*/

public synchronized boolean isTokenValid(HttpServletRequest request) {

return this.isTokenValid(request, false);

}

/**

* Return true 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 false

*

*

*

*

No session associated with this request

*

No transaction token saved in the session

*

*

No transaction token included as a request parameter

*

*

The included transaction token value does not match the transaction

* token in the user's session

*

*

*

* @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中表单的重复提交示例,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值