原理:在新建页面中Session保存token随机码,当保存时验证,通过后删除,当再次点击保存时由于服务器端的Session中已经不存在了,所有无法验证通过。 

注,如果是集群的方式,则需要将token放入到缓存中即可。 

注解Token代码:java源码  

Java代码 复制代码 收藏代码
.@Target(ElementType.METHOD)
.@Retention (RetentionPolicy.RUNTIME)
.public @interface Token {
.
. boolean needSaveToken () default false ;
.
. boolean needRemoveToken () default false ;
.} 拦截器TokenInterceptor代码: Java代码 复制代码 收藏代码
.public class TokenInterceptor extends HandlerInterceptorAdapter {
.
. @Override
. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throwsException {
. 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( false ).setAttribute( "token" , UUID.randomUUID().toString());
. }
. boolean needRemoveSession = annotation.remove();
. if (needRemoveSession) {
. if (isRepeatSubmit(request)) {
. return false ;
. }
. 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 ;
. }
.} 然后在Spring MVC的配置文件里加入: Xml代码 复制代码 收藏代码
.<!-- 拦截器配置 -->
.< mvc:interceptors >
. <!-- 配置Shiro拦截器,实现注册用户的注入 -->
. < mvc:interceptor >
. < mvc:mapping path = "/**" />
. < bean class = "com.storezhang.video.shiro.ShiroInterceptor" />
. </ mvc:interceptor >
. <!-- 配置Token拦截器,防止用户重复提交数据 -->
. < mvc:interceptor >
. < mvc:mapping path = "/**" />
. < bean class = "com.storezhang.web.spring.TokenInterceptor" />
. </ mvc:interceptor >
.</ mvc:interceptors > 相关代码已经注释,相信你能看懂。
关于这个方法的用法是:在需要生成token的controller上增加@Token(save=true),而在需要检查重复提交的controller上添加@Token(remove=true)就可以了。
另外,你需要在view里在form里增加下面代码: Html代码 复制代码 收藏代码
.< input type = "hidden" name = "token" value = "${token}" /> 在相关方法中加入注解 Java代码 复制代码 收藏代码
.@RequestMapping("/save")
. @AvoidDuplicateSubmission(needRemoveToken = true)
. public synchronized ModelAndView save(ExecutionUnit unit, HttpServletRequest request, HttpServletResponse response)
. throws Exception {
.
.@RequestMapping("/edit")
. @AvoidDuplicateSubmission(needSaveToken = true)
. public ModelAndView edit(Integer id, HttpServletRequest request) throws Exception { 已经完成了,去试试看你的数据还能重复提交了吧。

Spring MVC拦截器+注解方式实现防止表单重复提交的更多相关文章

  1. spring boot 学习(七)小工具篇:表单重复提交

    注解 + 拦截器:解决表单重复提交 前言 学习 Spring Boot 中,我想将我在项目中添加几个我在 SpringMVC 框架中常用的工具类(主要都是涉及到 Spring AOP 部分知识).比如 ...

  2. Spring MVC实现防止表单重复提交(转)

    Spring MVC拦截器+注解方式实现防止表单重复提交  

  3. 写的太细了!Spring MVC拦截器的应用,建议收藏再看!

    Spring MVC拦截器 拦截器是Spring MVC中强大的控件,它可以在进入处理器之前做一些操作,或者在处理器完成后进行操作,甚至是在渲染视图后进行操作. 拦截器概述 对于任何优秀的MVC框架, ...

  4. SSM(spring mvc+spring+mybatis)学习路径——2-2、spring MVC拦截器

    目录 2-2 Spring MVC拦截器 第一章 概述 第二章 Spring mvc拦截器的实现 2-1 拦截器的工作原理 2-2 拦截器的实现 2-3 拦截器的方法介绍 2-4 多个拦截器应用 2- ...

  5. spring mvc 拦截器的使用

    Spring MVC 拦截器的使用 拦截器简介 Spring MVC 中的拦截器(Interceptor)类似于 Servler 中的过滤器(Filter).用于对处理器进行预处理和后处理.常用于日志 ...

  6. Spring Boot 2.X(九):Spring MVC - 拦截器(Interceptor)

    拦截器 1.简介 Spring MVC 中的拦截器(Interceptor)类似于 Servlet 开发中的过滤器 Filter,它主要用于拦截用户请求并作相应的处理,它也是 AOP 编程思想的体现, ...

  7. Spring MVC拦截器浅析

    Spring MVC拦截器 重点:Spring MVC的拦截器只会拦截控制器的请求,如果是jsp.js.image.html则会放行. 什么是拦截器 运行在服务器的程序,先于Servlet或JSP之前 ...

  8. Spring MVC 中采用注解方式 Action中跳转到另一个Action的写法

    Spring MVC 中采用注解方式 Action中跳转到另一个Action的写法 在Action中方法的返回值都是字符串行,一般情况是返回某个JSP,如: return "xx" ...

  9. 【Java Web开发学习】Spring MVC 拦截器HandlerInterceptor

    [Java Web开发学习]Spring MVC 拦截器HandlerInterceptor 转载:https://www.cnblogs.com/yangchongxing/p/9324119.ht ...

随机推荐

  1. C#枚举类型的常用操作总结

    枚举类型是定义了一组"符号名称/值"配对.枚举类型是强类型的.每个枚举类型都是从system.Enum派生,又从system.ValueType派生,而system.ValueTy ...

  2. virtual 修饰符与继承对析构函数的影响(C++)

    以前,知道了虚函数表的低效性之后,一直尽量避免使用之.所以,在最近的工程中,所有的析构函数都不是虚函数.今天趁着还书的机会到图书馆,还书之后在 TP 分类下闲逛,偶然读到一本游戏编程书,里面说建议将存 ...

  3. 如何用easyui+JAVA 实现动态拼凑datagrid表格(续)

    前面一段时间写了一篇文章: 如何用easyui+JAVA 实现动态拼凑datagrid表格 这篇文章的话,效果是可以实现,但是经过我反复试验,还是存在一些问题的. 今天这篇文章就是向大家介绍下如何避免 ...

  4. ProgressBar

    <1>基本信息设置 progressBar1.Maximum = 1000;    //设置ProgressBar的最大值 progressBar1.Value = 0;         ...

  5. SQLServer学习笔记系列11

    一.写在前面的话 身体是革命的本钱,这句放在嘴边常说的话,还是拿出来一起共勉,提醒一起奋斗的同僚们,保证睡眠,注意身体!偶尔加个班,也许不曾感觉到身体发出的讯号,长期晚睡真心扛不住!自己也制定计划,敦 ...

  6. Bootstrap Navbar应用及源码解析

    目的: 用Bootstrap Navbar component 实现一个响应式导航 理解Bootstrap Navbar component是如何工作的(不包括collepse.js) 清楚自己添加一 ...

  7. [AngularJS] AngularJS系列(5) 中级篇之动画

    目录 CSS定义 JS定义 ng动画实际帮我们在状态切换的时候 添加特定的样式 从而实现动画效果. 一般我们会通过C3来实现具体的动画. CSS定义 ng-if 图(实际上,图并不能展现出什么): H ...

  8. QT 中 关键字讲解(emit,signal,slot)

    Qt中的类库有接近一半是从基类QObject上继承下来,信号与反应槽(signals/slot)机制就是用来在QObject类或其子类间通讯的方法.作为一种通用的处理机制,信号与反应槽非常灵活,可以携 ...

  9. C# foreach 中获取索引index的方法

    方法一: int i = 0; foreach (var item in arr) { i++; } 方法二: foreach (var item in arr) { int index = arr. ...

  10. 基于.net mvc 的供应链管理系统(YB-SCM)开发随笔1-开篇

    作为开篇之作,先把这个项目的介绍和一些技术点给各位. 1.项目所用到的技术 (1)前台展示:ASP.NET MVC 3.0+Jquery+Sea+Bootstrap等 (2)开发环境:VS2012/V ...