<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 这里使用的是自定义标签 -->
<%@ taglib prefix="syh" uri="http://java.syh.com/jsp/syh/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
//点击 "提交" 按钮, 只能点击一次
var flag = true;
function token(btn){
if(flag){
flag = false;
return true;
}else{
alert('已经提交过了');
}
}
/*
下面的JS代码对 IE 不使用,对于 FF
function token2(btn){
if(flag){
btn.disabled = true;
return true;
}
}
*/
</script>
</head>
<body>
<!--
TokenProcessor.getInstance().saveToken(request)
1. 生成一个随机字符串, 可以保证其唯一
2. 把该字符串放在 Session 域中
3. 返回该字符串
-->
<form action="LoginServlet" method="post" id="regForm">
<!-- 这里使用的是自定义标签 -->
<syh:token/>
<table border="1">
<tr>
<td>Name:</td>
<td>
<input type="text" name="name"/>
</td>
</tr>
<tr>
<td>Password:</td>
<td>
<input type="password" name="password"/>
</td>
</tr>
<tr rowspan="2">
<td>
<input type="submit" value="Submit" onclick="return token2(this);"/>
</td>
<td>
<input type="reset" value="Reset"/>
</td>
</tr>
</table>
</form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
注册成功!
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h4>表单已经提交!请不要多次提交!</h4>
</body>
</html>
package com.syh.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response) ;
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Thread.sleep(3000) ;
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
//模拟网速
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//1. 检验 Token 是否可用
boolean flag = TokenProcessor.getInstance().isTokenValid(request) ;
//2. 去除 Session 中的 Token 标记
if(flag) {
TokenProcessor.getInstance().resetToken(request) ;
}else {
System.out.println("重复提交");
request.getRequestDispatcher("/error.jsp").forward(request, response) ;
return ;
}
String name = request.getParameter("name") ;
System.out.println("添加成功-->" + name);
request.getRequestDispatcher("/success.jsp").forward(request, response) ;
}
}
package com.syh.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class TokenProcessor extends SimpleTagSupport{
@Override
public void doTag() throws JspException, IOException {
PageContext pageContext = (PageContext) getJspContext();
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
String output = "<input type='hidden' name='" + TOKEN_KEY + "' value='" + saveToken(request) + "'/>";
pageContext.getOut().print(output);
}
public static final String TAGLIB_PACKAGE = "org.apache.struts.taglib.html";
public static final String TRANSACTION_TOKEN_KEY =
"org.apache.struts.action.TOKEN";
public static final String TOKEN_KEY = TAGLIB_PACKAGE + ".TOKEN";
private static TokenProcessor instance = new TokenProcessor();
private long previous;
public TokenProcessor() {
super();
}
public static TokenProcessor getInstance() {
return instance;
}
public synchronized boolean isTokenValid(HttpServletRequest request) {
return this.isTokenValid(request, false);
}
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;
}
String saved =
(String) session.getAttribute(TRANSACTION_TOKEN_KEY);
if (saved == null) {
return false;
}
if (reset) {
this.resetToken(request);
}
String token = request.getParameter(TOKEN_KEY);
if (token == null) {
return false;
}
return saved.equals(token);
}
public synchronized void resetToken(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session == null) {
return;
}
session.removeAttribute(TRANSACTION_TOKEN_KEY);
}
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;
}
public synchronized String generateToken(HttpServletRequest request) {
HttpSession session = request.getSession();
return generateToken(session.getId());
}
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;
}
}
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();
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>MyTag 1.0 core</description>
<display-name>MyTag core</display-name>
<tlib-version>1.0</tlib-version>
<short-name>syh</short-name>
<uri>http://java.syh.com/jsp/syh/core</uri>
<tag>
<name>token</name>
<tag-class>com.syh.servlet.TokenProcessor</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
分享到:
相关推荐
本文将深入探讨自定义标签在防止重复提交中的实现原理和应用。 首先,我们要理解什么是自定义标签(Custom Tags)。在JavaServer Pages(JSP)中,自定义标签是扩展JSP功能的一种方式,它可以封装复杂的业务逻辑...
在Web开发中,表单提交是一项基础且关键的操作,它允许用户向服务器发送数据进行...总的来说,防止表单重复提交是一个多层面、多层次的问题,需要综合运用客户端和服务器端的技术,以确保应用的稳定性和数据的一致性。
在Web开发中,表单重复提交是一个常见的问题,它可能导致数据的不一致性或者服务端处理逻辑的混乱。Struts2框架提供了一种解决方案,即使用Token机制来防止表单的重复提交。以下是对这个主题的详细说明: 1. **表单...
在Web应用中,表单重复提交是一种常见的问题。通常,这种问题发生在用户在提交表单后,由于网络延迟或用户的误操作再次点击提交按钮,或者在表单提交后刷新浏览器页面。这两种情况都可能导致服务器接收到重复的请求...
在Struts2中,防止重复提交是一个重要的问题,因为它可能导致数据不一致性和服务器资源的浪费。本文将详细介绍如何在Struts2中解决这个问题,以及相关的技术概念。 首先,我们要理解Struts2中的拦截器(Interceptor...
浅谈利用Session防止表单重复提交 Session是Web应用程序中的一种机制,用于存储用户的会话信息。在Web应用程序中,表单重复...使用Session结合UUID可以有效地防止表单重复提交,提高了Web应用程序的安全性和可靠性。
struts2防止表单重复提交,利用struts的拦截器tokenSession,轻轻松松解决表单重复提交的问题。 附件为源代码,后台延迟了3秒,可直接在web服务器下部署运行,输入用户名和密码后,多点几次提交按钮,然后看控制台...
在ASP.NET web应用程序中,表单重复提交是一个常见的问题,可能导致数据不一致或者数据库操作的冗余。为了确保用户在提交表单时不会无意或有意地多次发送请求,我们需要实施有效的防止表单重复提交的策略。以下是...
总结起来,Struts2通过重定向策略可以有效地防止表单重复提交,结合其他如Token Session Strategy等方法,可以进一步提高应用的安全性和稳定性。开发者可以根据项目需求选择合适的防重提交方案,确保系统正常运行。
在JavaEE应用开发中,Struts2框架是一个广泛使用的MVC框架,它提供了一种有效的方式来组织和控制应用程序的行为。然而,随着Web应用的发展,防止重复提交成为一个重要的问题,尤其是在处理金融交易、投票等关键操作...
### ASP.NET中防止刷新页面造成表单重复提交 在Web应用程序开发中,特别是在使用ASP.NET进行网站构建时,一个常见的问题是表单重复提交。这通常发生在用户通过按下浏览器的F5键来刷新页面的情况下,此时之前的表单...
总结来说,这个SSH笔记涵盖了Web开发中的关键知识点,包括数据验证确保输入合法性,文件上传下载提供交互性,防止表单重复提交保护数据一致性,以及自定义拦截器增强应用的功能和灵活性。掌握这些技能,将有助于提升...
为了防止这种情况,开发者通常会采取一些策略,如在Struts2中使用Token机制。 在Struts2中防止表单重复提交的过程主要包括以下几个步骤: 1. **生成Token**:当用户发起表单请求时,服务器会生成一个唯一的Token并...
在实际应用中,文件上传和下载以及防止表单重复提交是两个常见的需求,同时也是开发者必须掌握的重要技能。 1. **文件上传** 文件上传功能在Struts2中通过`Struts2`提供的插件来实现,主要依赖于`Apache Commons ...
总结来说,Servlet、Struts和SpringMVC都提供了各自的解决方案来防止表单重复提交,主要方法包括使用Session、令牌机制、重定向和拦截器等。开发者可以根据项目需求选择合适的方式来实现,确保应用的稳定性和数据...
综上所述,理解并掌握Struts框架中的数据回显、模型驱动以及防止表单重复提交的原理和实现方法,对于提升Java Web应用的开发效率和质量具有重要意义。在实际开发中,应灵活运用这些技术,以满足项目需求,打造稳定...
在Eclipse项目中,`Struts_0304_Interceptor_token`可能包含了一个示例项目,展示了如何配置和使用Struts2的token拦截器来防止表单重复提交。通过查看该项目的代码和配置文件,你可以更深入地理解和学习这一功能。
总的来说,Struts Token机制通过维护一个临时的、一次性使用的Token,有效地解决了Web应用中的表单重复提交问题,提高了系统的稳定性和安全性。在实际开发中,应根据项目需求灵活运用并优化此机制。