解决表单重复提交问题

分享知识 传递快乐

 

防止表单重复提交有多种,经常用到的有两种:

 

一种是Token(令牌),这种可以用于from表单,但用于ajax就有点力不从心了;

另一种是对请求的url和参数验证,如果一样就不提交,否则提交(推荐)。

 

代码如下:

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.xh.token</groupId>
	<artifactId>prevent-resubmit</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>prevent-resubmit Maven Webapp</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
		<spring.version>4.3.13.RELEASE</spring.version>
		<fastjson.version>1.2.46</fastjson.version>
		<log4j.version>1.2.17</log4j.version>
		<slf4j.version>1.7.25</slf4j.version>
		<servlet.version>3.1.0</servlet.version>
		<ehcache.version>2.6.11</ehcache.version>
		<jackson.version>2.9.0</jackson.version>
	</properties>


	<dependencies>
		<!-- 通用包 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.6</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.4</version>
		</dependency>

		<!-- spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>


		<!-- fastjson -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>${fastjson.version}</version>
		</dependency>


		<!--日志 start -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>${log4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${slf4j.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-simple</artifactId>
			<version>${slf4j.version}</version>
			<scope>test</scope>
		</dependency>

		<!-- servlet 如果用不到jsp个人认为没必要引用 -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>${servlet.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.0</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<!-- ehcache -->
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache-core</artifactId>
			<version>${ehcache.version}</version>
		</dependency>
		
		<!-- jackson begin -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${jackson.version}</version>
		</dependency>
		
	</dependencies>

	<build>
		<finalName>prevent-resubmit</finalName>
	</build>
</project>

 

java核心代码:

 

SameUrlDataInterceptor

package com.xh.token.commons.same;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.alibaba.fastjson.JSON;

/**
 * <p>Title: 一个用户 相同url 同时提交 相同数据 验证  主要通过 session中保存到的url 和 请求参数。如果和上次相同,则是重复提交表单 </p>
 * <p>Description: </p>
 * 
 * @author H.Yang
 * @QQ 1033542070
 * @date 2018年3月7日
 */
public class SameUrlDataInterceptor extends HandlerInterceptorAdapter {

	private final Logger LOGGER = LogManager.getLogger(getClass());
	private static HttpSession session = null;

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		if (handler instanceof HandlerMethod) {
			session = request.getSession();
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			Method method = handlerMethod.getMethod();
			SameUrlData annotation = method.getAnnotation(SameUrlData.class);

//			LOGGER.info("annotation=" + annotation);

			if (annotation != null) {
				// 如果重复相同数据
				if (repeatDataValidator(request)) {
					// 重定向到登录页面
//					LOGGER.info("请求地址:" + session.getAttribute("oldUrl"));
					response.sendRedirect(request.getContextPath() +session.getAttribute("oldUrl"));
					session.removeAttribute("oldUrl");
					session.removeAttribute("repeatData");
					return false;
				} else {
					return true;
				}
			}
//			LOGGER.info("保存请求地址:" + request.getServletPath());
			session.setAttribute("oldUrl", request.getServletPath());
			return true;
		} else {
//			LOGGER.info("handler=" + handler);
			return super.preHandle(request, response, handler);
		}
	}

	/** 
	 * 验证同一个url数据是否相同提交  ,相同返回true 
	 * @param request 
	 * @return 
	 */
	public boolean repeatDataValidator(HttpServletRequest request) {
		String params = JSON.toJSONString(request.getParameterMap());
//		LOGGER.info("params=" + params);
		String url = request.getRequestURI();
//		LOGGER.info("url=" + url);
		Map<String, String> map = new HashMap<String, String>();
		map.put(url, params);
		String nowUrlParams = map.toString();//

		Object preUrlParams = session.getAttribute("repeatData");
		// 如果上一个数据为null,表示还没有访问页面
		if (preUrlParams == null) {
			LOGGER.info("未提交数据");
			session.setAttribute("repeatData", nowUrlParams);
			return false;
		} else {
			// 否则,已经访问过页面
			// 如果上次url+数据和本次url+数据相同,则表示城府添加数据
			if (preUrlParams.toString().equals(nowUrlParams)) {
				LOGGER.info("已经提交数据 ");
				return true;
			} else {
				LOGGER.info("两次提交的数据不一至,可以提交");
				// 如果上次 url+数据 和本次url加数据不同,则不是重复提交
				session.setAttribute("repeatData", nowUrlParams);
				return false;
			}

		}
	}
}

 

controller

package com.xh.token.controller;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import com.xh.token.commons.same.SameUrlData;

@Controller
public class LoginController {

	// 控制器本来就是单例,这样似乎更加合理
	private final Logger LOGGER = LogManager.getLogger(getClass());

	@GetMapping("/login")
	public String login() {
		LOGGER.info("GET请求登录");
		return "login";
	}

	@PostMapping("/login2")
	@SameUrlData
	public String login(HttpServletRequest request, String name, String password) {
		LOGGER.info("from请求如下:name=" + name + "\t password=" + password);

		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return "redirect:/login";
	}

}

 

 

 

源码:点击打开链接

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旷野历程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值