原理:在新建页面中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. (四)WebGIS中通过行列号来换算出多种瓦片的URL 之离线地图

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.前言 在前面我花了两个篇幅来讲解行列号的获取,也解释了为什么要获取行 ...

  2. jquery动画,基础以及我发现的新大陆

    $.animate()在jquery官方介绍有2中方式,其实我发现的新大陆也是第二种方式的扩展! 一.$.animate( properties [, duration ] [, easing ] [ ...

  3. jQuery-1.9.1源码分析系列(十四) 一些jQuery工具

    为了给下一章分析动画处理做准备,先来看一下一些工具.其中队列工具在动画处理中被经常使用. jQuery.fn. queue(([ queueName ] [, newQueue ]) || ([ qu ...

  4. 1.什么是Code First(EF Code First 系列)

    EF4.1中开始支持Code First .这种方式在领域设计模式中非常有用.使用Code First模式,你可以专注于领域设计,根据需要,为你一个领域的对象创建类集合,而不是首先来设计数据库,然后来 ...

  5. (1-1)文件结构的升级(Area和Filter知识总结) - ASP.NET从MVC5升级到MVC6

    ASP.NET从MVC5升级到MVC6 总目录 MVC5项目结构 带有Areas和Filter的项目结构 一般来说,小的MVC项目是不考虑领域的,但是,如果是稍微复杂一点的项目,往往是需要领域这个概念 ...

  6. h5输入框提示语 + 正常文本框提示语

    <input id="username" name="username" type="text" placeholder=" ...

  7. Java字节、十进制、十六进制、字符串之间的相互转换

    1. 字节转10进制 直接使用(int)类型转换. /* * 字节转10进制 */ public static int byte2Int(byte b){ int r = (int) b; retur ...

  8. 修改nginx版本名称伪装任意web server

    如何修改nginx默认的名称,可以稍微的伪装一下,也可以装x 一般来说修改3个位置,一个是nginx.h.另一个是ngx_http_header_filter_module.c.还有一个ngx_htt ...

  9. php实现设计模式之 访问者模式

    <?php /** * 访问者模式 * 封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作. * 行为类模式 */ /** 抽象访问者:抽象类或 ...

  10. js中this的绑定

    人们对于this的绑定常常有两个误解,一:指向函数本身,二:指向函数作用域.这两种想法都是错的,this并不指向函数本身,也不指向函数作用域. function foo(){ this.count++ ...