Token注解防止表单的重复提交
注解的一些基础:
参见http://blog.csdn.net/duo2005duo/article/details/50505884和
http://blog.csdn.net/duo2005duo/article/details/50511476这两篇文章
1,自定义一个注解@Token 用来标记需要防止重复提交的方法
package com.bjca.framework.util;
/**
* <p>
*关于这个方法的用法是:
*在需要生成token的controller上增加@Token(save=true),
*而在需要检查重复提交的controller上添加@Token(remove=true)就可以了
*另外,你需要在view里在form里增加下面代码:
*<input type="hidden" name="token" value="${token}">
* 此时会在拦截器中验证是否重复提交
* </p>
*
*/
import java.lang.annotation.*; @Target(ElementType.METHOD)
@Retention (RetentionPolicy.RUNTIME)
public @interface Token { boolean save() default false ; boolean remove() default false ;
}
2,自定义一个针对该注解的拦截器 TokenInterceptor
package com.bjca.framework.util; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.UUID; public class TokenInterceptor extends HandlerInterceptorAdapter {
public static Log log = LogFactory.getLog(TokenInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(handler.getClass());
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
Token annotation = method.getAnnotation(Token. class ); if (annotation != null ) {
boolean needSaveSession = annotation.save();
if (needSaveSession) {
String uuid=UUID.randomUUID().toString();
log.debug("提交生成除令牌"+uuid);
request.getSession( false ).setAttribute( "token" , uuid);
}
boolean needRemoveSession = annotation.remove();
if (needRemoveSession) {
if (isRepeatSubmit(request)) {
return false ;
}
log.debug("提交移除令牌"+request.getSession().getAttribute("token" ));
request.getSession( false ).removeAttribute( "token" );
}
}
return true ;
} else {
return super .preHandle(request, response, handler);
}
} private boolean isRepeatSubmit(HttpServletRequest request) {
String serverToken = (String) request.getSession( false ).getAttribute( "token" );
if (serverToken == null ) {
return true ;
}
String clinetToken = request.getParameter( "token" );
if (clinetToken == null ) {
return true ;
}
if (!serverToken.equals(clinetToken)) {
return true ;
}
return false ;
}
}
3,在spring MVC的配置文件里注册该拦截器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"
>
<!-- 对spring org.lxh包下所有注解扫描 -->
<context:component-scan base-package="com.xxx">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository" />
</context:component-scan>
<!-- 支持spring mvc新的注解类型 详细spring3.0手册 15.12.1 mvc:annotation-driven-->
<mvc:annotation-driven /> <bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 为了使用JSTL Tag修改默认的viewClass属性 -->
<property
name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property
name="prefix"
value="/WEB-INF/views/" />
<property
name="suffix"
value=".jsp"></property>
<property
name="order"
value="1"></property>
</bean>
<!-- 拦截器 -->
<mvc:interceptors>
<!-- 用户登录拦截 -->
<bean class="com.xx.xxx.filter.StageSecurityInterceptor">
<property name="patterns" >
<list>
<value>.*/console/.*\.jhtml</value>
<value>.*/center/.*\.jhtml</value> </list>
</property>
<property name="loginView">
<value>/manage.jsp</value>
</property>
</bean>
54 <!-- 配置Token拦截器,防止用户重复提交数据 -->
55 <mvc:interceptor>
56 <mvc:mapping path="/**"/>
57 <bean class="com.xxx.framework.util.TokenInterceptor"/>
58 </mvc:interceptor>
</mvc:interceptors>
<!--
<bean id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basenames">
<list>
<value>views-stage</value>
</list>
</property>
</bean>
-->
</beans>
4,演示demo
4.1,在跳转至某个需要加上@Token(save = true)
1 @RequestMapping("/personalForm.jhtml")
2 @Token(save = true)
public String personalForm(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) {
Account account = Account.sessionAccount();
if (account == null) {
return "redirect:/login.jsp";
}
//..........业务..............
}
4.2,在上个Controller 跳转的方法上加入${Token}
<div class="main clearfix nav center regist copyright_main5">
<h3 class="registTitle">填写身份信息</h3>
<img alt="" src="<c:url value='/platform/stage/image/regist/wave.png'/>"><br /> <img src="<c:url value='/platform/stage/image/portals/regist-info.png'/>"></img>
<c:if test="${personalInfoForm.checkState eq 2}">
<br/>
<div>
<font color="red" size="2"><span>身份认证意见:${personalInfoForm.checkOpnion}</span></font>
</div>
</c:if>
<form autocomplete="off" style="margin: 0;" id="form1" method="post" name="personalInfoForm" action="<c:url value='/center/member/savePersonalInfo.jhtml'/>" enctype="multipart/form-data">
<input type="hidden" value="${personalInfoForm.id}" name="id" />
<input type="hidden" name="token" value="${token}">
4.3,在表单提交方法的地方加上注解 @Token(remove = true)
@RequestMapping(value = "/savePersonalInfo.jhtml", method = {RequestMethod.POST})
@Token(remove = true)
public String savePersonalInfo(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap, PersonalInfo personalInfoForm) throws Exception {
DateFormat fm = new SimpleDateFormat("yyyy-MM-dd");
Date birthday = fm.parse(request.getParameter("birthday2"));
personalInfoForm.setBirthday(birthday); Account account = Account.sessionAccount();
if(account==null){
return "redirect:/login.jsp";
}
//.....................业务.........................
}
5,完成了。
Token注解防止表单的重复提交的更多相关文章
- 使用aop注解实现表单防重复提交功能
原文:https://www.cnblogs.com/manliu/articles/5983888.html 1.这里采用的方法是:使用get请求进入表单页面时,后台会生成一个tokrn_flag分 ...
- Spring MVC表单防重复提交
利用Spring MVC的过滤器及token传递验证来实现表单防重复提交. 创建注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RU ...
- struts2 文件的上传下载 表单的重复提交 自定义拦截器
文件上传中表单的准备 要想使用 HTML 表单上传一个或多个文件 须把 HTML 表单的 enctype 属性设置为 multipart/form-data 须把 HTML 表单的method 属性设 ...
- Session机制三(表单的重复提交)
1.表单的重复提交的情况 在表单提交到一个servlet,而servlet又通过请求转发的方式响应了一个JSP页面,这个时候地址栏还保留这servlet的那个路径,在响应页面点击刷新. 在响应页面没有 ...
- HttpSession解决表单的重复提交
1). 重复提交的情况: ①. 在表单提交到一个 Servlet, 而 Servlet 又通过请求转发的方式响应一个 JSP(HTML) 页面, 此时地址栏还保留着 Serlvet 的那个路径, 在响 ...
- Struts2 - 表单的重复提交问题
用户重复提交表单在某些场合将会造成非常严重的后果.例如,在使用信用卡进行在线支付的时候,如果服务器的响应速度太慢,用户有可能会多次点击提交按钮,而这可能导致那张信用卡上的金额被消费了多次.因此,重复提 ...
- HttpSession之表单的重复提交 & 验证码
如果采用 HttpServletResponse.sendRedirct() 方法将客户端重定向到成功页面,将不会出现重复提交问题 1.表单的重复提交 1). 重复提交的情况: ①. 在表单提交到一个 ...
- php中如何防止表单的重复提交
在php中如何防止表单的重复提交?其实也有几种解决方法. 下面小编就为大家介绍一下吧.需要的朋友可以过来参考下 代码: <?php /* * php中如何防止表单的重复提交 * by www.j ...
- php-- 避免表单的重复提交
用户提交表单时可能因为网速的原因,或者网页被恶意刷新,致使同一条记录重复插入到数据库中,这是一个比较棘手的问题.我们可以从客户端和服务器端一起着手,设法避免同一表单的重复提交. 1.使用客户端脚本 提 ...
随机推荐
- DbUtility Ex
扩展 DbUtility (1) 2014-05-22 21:48 by Ivony..., 234 阅读, 3 评论, 收藏, 编辑 本文原始路径: https://www.zybuluo.com/ ...
- C# 词法分析器
当前标签: 编译原理 C# 词法分析器(七)总结 CYJB 2014-01-09 12:46 阅读:582 评论:1 C# 词法分析器(六)构造词法分析器 CYJB 2013-05-07 01 ...
- Mysql中实现多表关联查询更新操作
今天一下要记录一下才行了,每次都要去网上查找方法,每次都难找得要命 Mysql在更新某些字段的数据时,有时候会依据其他表的数据进行更新,需要通过关联后对不同的行更新不同的值,传统的update set ...
- linux 之 getopt_long()
文件 #include <getopt.h> 函数原型 int getopt_long(int argc, char * const argv[], const char *optstri ...
- .Net 异步随手记(二)
Task.ContinueWith 这货,和 await 一样有“陷阱”.^^,因为写 ContinueWith 不能直观如人的“过程性”思维,写在 ContinueWith 括号里的部分不一定只在发 ...
- Leetcode: 06/01
今天完成了三道题目,总结一下: 1: Length of last word(细节实现题) 此题有一些细节需要注意(比如 “a_ _” 最后一个单词是a, 而不是遇到空格就直接算成没有),别的基本就是 ...
- Setting up Ubuntu in CoLinux–changing local/keyboard to be English
Today i installed the CoLinux with Ubuntu package, but the default locale setting of the system is G ...
- 模块化与MVC
[javascript激增的思考02]模块化与MVC 前言 之前我们遇到了这么一个项目,也就是我们昨天提到的,有很多的小窗口的,昨天说的太抽象了,今天我们再来理一理什么是小窗口(后面点说下),当时由于 ...
- 自制AutoMapper实现DTO到持久层Entity的转换
自制AutoMapper实现DTO到持久层Entity的转换 项目中经常涉及到页面DTO更新,保存到数据库的操作,这就必然牵扯到DTO和持久层对象的转换,常见的第三方库有: java:dozer .n ...
- network重启失败原因
/etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE='eth0' eth0后面千万不能加空格之类的