拦截器springmvc防止表单重复提交【1】
【参考博客:http://www.cnblogs.com/hdwpdx/archive/2016/03/29/5333943.html】
springmvc 用拦截器+token防止重复提交
首先,防止用户重复提交有很多种方式,总体分为前端JS限制和后端限制,我个人认为后端限制比较妥当(本着能做到更优秀得理念,舍去了前端JS限制重复提交得想法).
之前没有做过防止用户重复提交,所以直接百度了一大堆,竟然发现基本上可以归为2到3种真正不同实现得代码,文章虽然有很多,不过大部分代码几乎都出自同一人,原文网址:http://blog.icoolxue.com/submitted-by-spring-mvc-to-prevent-data-duplication/,想着这么多人用代码应该没问题,所以该复制复制,该手建手建,终于大工搞成,但是测试得时候发现了一个很重要得问题,永远处于重复提交状态,我得天啊,这就很尴尬了,于是赶紧打断点,F6F6F6,终于怀疑了一行代码,贴代码:

private boolean isRepeatSubmit(HttpServletRequest request) {
String serverToken = (String) request.getSession(true).getAttribute("token");
if (serverToken == null) {
return true;
}
String clinetToken = request.getParameter("token");//就是这行 NULL,永远是NULL。
if (clinetToken == null) {
return true;
}
if (!serverToken.equals(clinetToken)) {
return true;
}
return false;
}

嘿我就那了闷,怎么会接收不到值呢?肯定是页面有问题了,页面就只有一句话
<input type="hidden" name="token" value="${token}" />
我突然脑袋灵光一闪,通过name值传值必须在form表单里才行,我全是AJAX啊,于是赶紧在传递参数中加上token,问题也就顺利得结果了!
但是我就再想,这么多人复制原文得代码,然后发到自己得博客,难道没有出现这种问题嘛?
问题解决了,顺便总结一下token得使用方法,切记代码没问题,复制需谨慎(该改得记得改!)
首先自定义一个注解:

package com.dinfo.interceptor; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Token { boolean save() default false; boolean remove() default false;
}

接着实现一个拦截器借口:

package com.dinfo.interceptor; import java.lang.reflect.Method;
import java.util.UUID; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; public class TokenInterceptor extends HandlerInterceptorAdapter {
private static final Logger LOG = Logger.getLogger(Token.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
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) {
request.getSession(true).setAttribute("token", UUID.randomUUID().toString());
}
boolean needRemoveSession = annotation.remove();
if (needRemoveSession) {
if (isRepeatSubmit(request)) {
LOG.warn("please don't repeat submit,url:"+ request.getServletPath());
return false;
}
request.getSession(true).removeAttribute("token");
}
}
return true;
} else {
return super.preHandle(request, response, handler);
}
} private boolean isRepeatSubmit(HttpServletRequest request) {
String serverToken = (String) request.getSession(true).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;
}
}

最后是配置文件:

<!-- 拦截器配置 -->
<mvc:interceptors>
<!-- 配置Token拦截器,防止用户重复提交数据 -->
<mvc:interceptor>
<mvc:mapping path="/**"/><!--这个地方时你要拦截得路径 我这个意思是拦截所有得URL-->
<bean class="com.dinfo.interceptor.TokenInterceptor"/><!--class文件路径改成你自己写得拦截器路径!! -->
</mvc:interceptor>
</mvc:interceptors>

最最最重要得一点一定要保证页面和后台token得正常传递!!!
在需要生成token(通常是要点击提交得那个页面)得Controller中使用我们刚才自定义好得注解,贴代码:

@SuppressWarnings({ "unchecked", "finally", "rawtypes" })
@RequestMapping("/SaveDataController/show")
@Token(save=true)
public String saveData(HttpServletRequest request,HttpServletResponse response,String task_id){
Map map = new HashMap();
System.out.println(task_id);
try {
map = saveDataService.queryByTaskId(task_id);
} catch (Exception e) {
e.printStackTrace();
map.put("task_id", task_id);
map.put("savetype", "");
map.put("memoryCodes", "1");
map.put("tablename", "");
map.put("trowkey", "");
map.put("columns", "");
map.put("indextablename", "");
map.put("irowkey", "");
map.put("icolumns", "");
} finally {
request.setAttribute("map", map);
return "savedata/index";
}
}

只要通过这个方法跳向得页面都是随机生成一个token,然后再真正再提交触发得方法上加入@token(remove=true),贴代码:

@RequestMapping("/SaveDataController/saveData")
@ResponseBody
@Token(remove=true)
public void saveData(HttpServletRequest request,HttpServletResponse response,
String tablename,String trowkey,String columns,
String indextablename,String irowkey,String icolumns,
String task_id,String savetype,String memoryCodes){
System.out.println(task_id);
saveDataService.saveData(task_id,savetype,memoryCodes,tablename, trowkey, columns, indextablename, irowkey, icolumns);
}

OK,到这里大功告成,你就可以发现已经没有办法重复提交数据了!有问题可以随时找我沟通。
拦截器springmvc防止表单重复提交【1】的更多相关文章
- 拦截器springmvc防止表单重复提交【3】3秒后自动跳回首页【重点明白如何跳转到各自需要的页面没有实现 但是有思路】
[1]定义异常类 [重点]:异常类有个多参数的构造函数public CmsException(String s, String... args),可以用来接受多个参数:如(“异常信息”,“几秒跳转”, ...
- 拦截器springmvc防止表单重复提交【3】自己实际项目
1:[定义注解] package com.jspxcms.ext.interceptor; import java.lang.annotation.ElementType; import java.l ...
- 拦截器springmvc防止表单重复提交【2】
[参考博客:http://my.oschina.net/mushui/blog/143397] 原理:在新建页面中Session保存token随机码,当保存时验证,通过后删除,当再次点击保存时由于服务 ...
- springmvc防止表单重复提交demo
原理:在去某个页面直接生成一个随机数(这里使用的是UUID)并放入session中,用户提交表单时将这个随机数传入服务端与session中的值进行比较,如果不不存在或不相等,则认为是重复提交:如果相等 ...
- SpringMVC防止表单重复提交
最近公司上线,有同志进行攻击,表当防重复提交也没有弄,交给我 ,本人以前也没弄过,知道大概的思路,但是那样实在是太麻烦了,虽然后面试过使用过滤器加拦截器实现,不过还是有点小麻烦. 后来在网上搜索后发现 ...
- spring boot 学习(七)小工具篇:表单重复提交
注解 + 拦截器:解决表单重复提交 前言 学习 Spring Boot 中,我想将我在项目中添加几个我在 SpringMVC 框架中常用的工具类(主要都是涉及到 Spring AOP 部分知识).比如 ...
- 12、Struts2表单重复提交
什么是表单重复提交 表单的重复提交: 若刷新表单页面, 再提交表单不算重复提交. 在不刷新表单页面的前提下: 多次点击提交按钮 已经提交成功, 按 "回退" 之后, 再点击 &qu ...
- java struts2入门学习--防止表单重复提交.OGNL语言学习
一.知识点回顾 防止表单重复提交核心思想: 客户端和服务器端和写一个token,比较两个token的值相同,则非重复提交;不同,则是重复提交. 1.getSession三种方式比较: request. ...
- 防止Web表单重复提交的方法总结
在Web开发中,对于处理表单重复提交是经常要面对的事情.那么,存在哪些场景会导致表单重复提交呢?表单重复提交会带来什么问题?有哪些方法可以避免表单重复提交? 表单重复提交的场景 1.场景一:服务端未能 ...
随机推荐
- 【Github教程】史上最全github使用方法:github入门到精通(转自eoeandroid.com)
本文来源:http://www.eoeandroid.com/thread-274556-1-1.html 另附经典教程网址 :http://wuyuans.com/2012/05/github-si ...
- NIO复习02
Selector 1. Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件.这样,一个单独的线程可以管理多个channel,从而管 ...
- 微信小程序获取验证码倒计时
getVerificationCode: function() { var that = this; var currentTime = that.data.currentTime; that.set ...
- 属性检测 In,hasOwnPreperty()和propertyIsEnumerable()
IN 左侧是属性名:右侧是对象名, 如果 属性是 自有属性 或者继承属性 则返回 TRUE var o={x:1,y:2} "x" in o 返回 true: hasOw ...
- C++中 int main(int argc, char **argv) 命令行传递参数
C++中,比较常见的是不带参数的主函数int main(),如果使用命令行执行程序,主函数也可以接收预先输入的参数,形式如下. int main(int argc,char **argv) argc: ...
- yum安装mysql后root用户的临时密码
1.查看root用户临时随机密码 yum 安装mysql后,无法通过空密码登录数据库,如下: [root@ mysql]# mysql -u root -p Enter password: ERROR ...
- SpringBoot ControllerAdvice
在Spring3.2中新增了@ControllerAdvice注解,可用于定义@ExceptionHandler @ModelAttribute @InitBinder,并应用到所有被@Request ...
- 通过Collections将集合转换为线程安全类集合
通过Collections将集合转换为线程安全类集合 List集合: List<String> list=new ArrayList<String>();list.add(&q ...
- vim 中的常用编辑
1.将1到3列行首添加‘#’ :1,3s/^/#/g 2.将1到3列行首去除‘#’ :1,3s/^#//g 3.将1到3列中前两列字符去掉 :1,3s/^..//g 4.将1到3列中行末前两个字符去掉 ...
- Pandas日期功能
日期功能扩展了时间序列,在财务数据分析中起主要作用.在处理日期数据的同时,我们经常会遇到以下情况 - 生成日期序列 将日期序列转换为不同的频率 创建一个日期范围 通过指定周期和频率,使用date.ra ...