1.实现原理:
提交表单时,从session中取出当前的token值与保存在页面上token值进行比较,如果相等,可以保存表单数据,并将新生成的token保存到session中,如果不相等,则判断为重复提交。
本例采用spring的HandlerInterceptorAdapter拦截器来实现控制重复提交。
2.spring 配置:spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!--
- The controllers are autodetected POJOs labeled with the @Controller annotation.
-->
<context:component-scan base-package="com.allwin" use-default-filters="false" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="com.allwin.erp.web.action.common.WebBindingObjectRegister" />
</property>
</bean>
<!--
- This bean configures the 'prefix' and 'suffix' properties of
- InternalResourceViewResolver, which resolves logical view names
- returned by Controllers. For example, a logical view name of "vets"
- will be mapped to "/WEB-INF/jsp/vets.jsp".
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
<context:annotation-config/>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding"><value>UTF-8</value></property>
<property name="maxUploadSize">
<value>52428800</value>
</property>
</bean>
<!--
- This bean controller double submit
-->
<bean id="doubleSubmitInterceptor" class="com.allwin.erp.web.action.common.DoubleSubmitInterceptor">
<!--
- 配置要拦截的url
-->
<property name="mappingURL" value=".*/(save|approve|active)\.do" />
<property name="viewURL" value=".*/(view|copy)\.do" />
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<ref bean="doubleSubmitInterceptor"/>
</list>
</property>
</bean>
</beans>
红色字体部分是配置判断重复提交的拦截器
3.java类HandlerInterceptorAdapter.java
public class DoubleSubmitInterceptor extends HandlerInterceptorAdapter {
// matches URL
private String mappingURL;
private String viewURL;
// page number
private static long pageNum = 0l;
/**
* summary: filter request(view/save/approve/active method)
*
* @param : request HttpServletRequest
* @param : response HttpServletResponse
* @param : handler Object
*
* @return boolean true:normal false:double submit
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String url=request.getRequestURL().toString();
// 设置页面编号
if(url.matches(viewURL)){
if(Strings.isEmpty(request.getParameter("pageNum"))){
request.getSession().setAttribute("pageNum",++pageNum);
}
}
if(url.matches(mappingURL)){
// 设置当前token名称(即session中存放token数据的key值)
String tokenName = handler.getClass().getSimpleName() + request.getParameter("pageNum");
// 取得当前session中的token值
String sessionToken = (String)request.getSession().getAttribute(tokenName);
if(sessionToken == null || sessionToken.equals("")){
// 生成新的token
long date = new Date().getTime();
request.getSession().setAttribute(tokenName, request.getSession().getId() + String.valueOf(date));
request.getSession().setAttribute("token", request.getSession().getId() + String.valueOf(date));
request.getSession().setAttribute("pageNum",request.getParameter("pageNum"));
return true;
} else { // 判断是否重复提交(如果session中的token值与request中的token值不一致则判定重复提交)
String requestToken = (String)request.getParameter("token");
if(requestToken == null || !requestToken.equals(sessionToken)){
request.getRequestDispatcher("/front/doubleSubmit.jsp").forward(request, response);
return false;
} else {
// 替换旧的token
long date = new Date().getTime();
request.getSession().setAttribute(tokenName, request.getSession().getId() + String.valueOf(date));
request.getSession().setAttribute("token", request.getSession().getId() + String.valueOf(date));
request.getSession().setAttribute("pageNum",request.getParameter("pageNum"));
return true;
}
}
} else {
return true;
}
}
/**
* @param mappingURL the mappingURL to set
*/
public void setMappingURL(String mappingURL) {
this.mappingURL = mappingURL;
}
/**
* @param viewURL the viewURL to set
*/
public void setViewURL(String viewURL) {
this.viewURL = viewURL;
}
}
4.jsp
在保存数据表单的jsp中加如两个隐藏变量
<input type="hidden" name="token" id="token" value="${token}"> session中的token值
<input type="hidden" name="pageNum" id="pageNum" value="${pageNum}">生成页面唯一编号
分享到:
相关推荐
【Spring2.5详解】 Spring 是一款开源的Java平台框架,专注于简化企业级应用程序的开发。Spring 2.5 版本是该框架的一个重要里程碑,它引入了许多增强特性和改进,使得开发者能够更加高效地构建可维护和可扩展的...
### Pro Spring 2.5:核心技能与框架深入解析 #### 概述 《Pro Spring 2.5》是一本由Jan Machacek、Aleksa Vukotic、Anirvan Chakraborty和Jessica Ditt联合编写的书籍,旨在为读者提供Spring Framework 2.5版本的...
- **防止表单重复提交**:为了避免因网络问题等原因导致的表单重复提交问题,Spring MVC提供了相应的解决方案。 - **文件下载**:提供机制来实现文件下载功能。 - **Session管理**:Spring MVC支持多种Session管理...
关闭Spring MVC DispatcherServlet vii. 65.7. 关闭默认的MVC配置 Spring Boot参考指南 7 viii. 65.8. 自定义ViewResolvers v. 66. 日志 i. 66.1. 配置Logback ii. 66.2. 配置Log4j i. 66.2.1. 使用YAML或JSON配置...
- **复杂的数据转换与加载**:当涉及到多个系统的数据集成时,Spring Batch 的Item Reader、Item Writer 和 Item Processor 可以帮助开发者更轻松地实现数据转换和加载任务。 **1.3 Spring Batch 架构** Spring ...
在Spring MVC框架中,注解是实现依赖注入和配置的核心工具。随着Spring 2.5的发布,注解配置逐渐成为主流,因为它简化了XML配置的复杂性,提高了代码的可读性和维护性。以下是对标题和描述中提到的一些关键注解的...
此拦截器用于防止重复提交表单。它会生成一个唯一的令牌并在每次提交时验证这个令牌是否有效。 ##### 2.18 Timer 此拦截器可以记录Action执行的时间,并将时间信息输出到日志或页面上。 ##### 2.19 Validation 此...