springmvc 防止表单重复提交的两种方法
更新时间:2021年8月3日 16:00 点击:1643
最近在本地开发测试的时候,遇到一个表单重复提交的现象。 因为网络延迟的问题,我点击了两次提交按钮,数据库里生成了两条记录。其实这种现象以前也有遇到过,一般都是提交后把按钮置灰,无法再次提交,这是很常见的客户端处理的方式。 但是这不是从根本上解决问题,虽然客户端解决了多次提交的问题,但是接口中依旧存在着问题。假设我们不是从客户端提交,而是被其他的系统调用,当遇到网络延迟,系统补偿的时候,还会遇到这种问题
1、通过session中的token验证
- 初始化页面时生成一个唯一token,将其放在页面隐藏域和session中
- 拦截器拦截请求,校验来自页面请求中的token与session中的token是否一致
- 判断,如果一致则提交成功并移除session中的token,不一致则说明重复提交并记录日志
步骤1:创建自定义注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Token { boolean save() default false; boolean remove() default false; }
步骤2:创建自定义拦截器(@slf4j是lombok的注解)
@Slf4j public class RepeatSubmitInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HandlerMethod handlerMethod = null; try { handlerMethod = (HandlerMethod)handler; } catch (Exception e) { return true; } Method method = handlerMethod.getMethod(); Token token = method.getAnnotation(Token.class); if(token != null ){ boolean saveSession = token.save(); if(saveSession){ request.getSession(true).setAttribute("token", UUID.randomUUID()); } boolean removeSession = token.remove(); if(removeSession){ if(isRepeatSubmitSession(request)){ log.info("repeat submit session :" + request.getServletPath()); response.sendRedirect("/error/409"); return false; } request.getSession(true).removeAttribute("token"); } } return true; } private boolean isRepeatSubmitSession(HttpServletRequest request){ String sessionToken = String.valueOf(request.getSession(true).getAttribute("token") == null ? "" : request.getSession(true).getAttribute("token")); String clientToken = String.valueOf(request.getParameter("token") == null ? "" : request.getParameter("token")); if(sessionToken == null || sessionToken.equals("")){ return true; } if(clientToken == null || clientToken.equals("")){ return true; } if(!sessionToken.equals(clientToken)){ return true; } return false; } }
步骤3:将自定义拦截器添加到配置文件
<mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.chinagdn.base.common.interceptor.RepeatSubmitInterceptor"/> </mvc:interceptor>
使用案例
//save = true 用于生成token @Token(save = true) @RequestMapping(value = "save", method = RequestMethod.GET) public String save(LoginUser loginUser, Model model) throws Exception { return "sys/user/edit"; } //remove = true 用于验证token @Token(remove = true) @RequestMapping(value = "save", method = RequestMethod.POST) public String save(@Valid LoginUser loginUser, Errors errors, RedirectAttributes redirectAttributes, Model model) throws Exception { //..... }
jsp页面隐藏域添加token
<input type="hidden" name="token" value="${sessionScope.token}">
2、通过当前用户上一次请求的url和参数验证重复提交
拦截器拦截请求,将上一次请求的url和参数和这次的对比
判断,是否一致说明重复提交并记录日志
步骤1:创建自定义注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface SameUrlData { }
步骤2:创建自定义拦截器
public class SameUrlDataInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); //是否有 SameUrlData 注解 SameUrlData annotation = method.getAnnotation(SameUrlData.class); if (annotation != null) { if (repeatDataValidator(request)) {//如果重复相同数据 response.sendRedirect("/error/409"); return false; } else { return true; } } return true; } else { return super.preHandle(request, response, handler); } } /** * 验证同一个url数据是否相同提交 ,相同返回true * @param httpServletRequest * @return */ private boolean repeatDataValidator(HttpServletRequest httpServletRequest) { String params = JsonMapper.toJsonString(httpServletRequest.getParameterMap()); String url = httpServletRequest.getRequestURI(); Map<String, String> map = new HashMap<>(); map.put(url, params); String nowUrlParams = map.toString();// Object preUrlParams = httpServletRequest.getSession().getAttribute("repeatData"); if (preUrlParams == null) { //如果上一个数据为null,表示还没有访问页面 httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams); return false; } else { //否则,已经访问过页面 if (preUrlParams.toString().equals(nowUrlParams)) { //如果上次url+数据和本次url+数据相同,则表示城府添加数据 return true; } else { //如果上次 url+数据 和本次url加数据不同,则不是重复提交 httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams); return false; } } } }
步骤3:将自定义拦截器添加到配置文件
<mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.chinagdn.base.common.interceptor.SameUrlDataInterceptor"/> </mvc:interceptor>
使用案例
//在controller层使用 @SameUrlData 注解即可 @SameUrlData @RequestMapping(value = "save", method = RequestMethod.POST) public String save(@Valid LoginUser loginUser, Errors errors, RedirectAttributes redirectAttributes, Model model) throws Exception { //..... }
到此这篇关于springmvc 防止表单重复提交的两种方法的文章就介绍到这了,更多相关springmvc 防止表单重复提交内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
相关文章
- artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口。本文给大家介绍JS中artdialog弹出框控件之提交表单思路详解,对本文感兴趣的朋友一起学习吧...2016-04-19
- 有时候我们为了省事就操作键盘组合键去代替使用鼠标,我们今天就使用JQuery实现Ctrl+Enter提交表单。我们发帖时,在内容输入框中输入完内容后,可以点击“提交”按钮来发表内容。可是,如果你够“懒”,你可以不用动鼠标,只需按...2015-10-23
- 为了网站的安全性,很多朋友都把密码设的比较复杂,但是如何密码不能明显示,不知道输的是对是错,为了安全起见可以把密码显示的,那么基于js代码如何实现的呢?下面通过本文给大家介绍JavaScript实现表单密码的隐藏和显示,需要的朋友参考下...2016-03-03
- 这篇文章主要为大家详细解析了BootStrap栅格系统、表单样式与按钮样式源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2017-01-23
- 这篇文章主要介绍了react使用antd表单赋值,用于修改弹框的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-29
- 在html表单提交中method请求Get和Post区别其实很显示的,get提交会是url形式的并且数据量不能太多,而post数据是在浏览器url看不到的并且可以是大数据量而且get安全性非...2016-09-20
- 这篇文章主要介绍了微信小程序 PHP后端form表单提交实例详解的相关资料,需要的朋友可以参考下...2017-01-16
- 这篇文章主要介绍了解决antd Form 表单校验方法无响应的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-28
基于Bootstrap实现Material Design风格表单插件 附源码下载
Jquery Material Form Plugin是一款基于Bootstrap的Material Design风格的jQuery表单插件。这篇文章主要介绍了基于Bootstrap的Material Design风格表单插件附源码下载,感兴趣的朋友参考下...2016-04-19- 本篇文章主要介绍了vue2 中如何实现动态表单增删改查实例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 ...2017-06-15
- 本文介绍在表单提交之前修改提交的值的方法,希望给需要的朋友一些帮助。...2016-04-17
- 本文主要介绍AngularJS表单的知识,这里整理了表单的基础知识和简单的示例代码,有需要的小伙伴可以参考下...2016-08-24
- 一聚教程网 从零开始的html教程(7),html表单的基础,零基础也能轻松学会html,希望大家喜欢 一、html的表单 表单负责网页中用户输入数据采集的功能,利用<form>标签来定...2016-12-31
基于bootstrap插件实现autocomplete自动完成表单
这篇文章主要介绍了基于bootstrap插件实现autocomplete自动完成表单的相关资料,感兴趣的朋友可以参考一下...2016-05-09- JavaScript 可用来在数据被送往服务器前对 HTML 表单中的这些输入数据进行验证。本文给大家介绍javascript的表单与验证-非空验证,对javascript表单验证相关知识感兴趣的朋友一起学习吧...2016-03-22
- 这篇文章主要介绍了JQuery异步提交表单与文件上传功能,结合实例形式分析了jQuery表单提交及文件传输操作的相关实现技巧,需要的朋友可以参考下...2017-01-16
JQuery form表单提交前验证单选框是否选中、删除记录时验证经验总结(整理)
这篇文章主要介绍了JQuery form表单提交前验证单选框是否选中、删除记录时验证经验总结,非常不错,具有参考借鉴价值,需要的朋友参考下吧...2017-06-15- 这篇文章主要介绍了jquery插件EasyUI中form表单提交实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2016-01-14
使用jQuery.form.js/springmvc框架实现文件上传功能
这篇文章主要介绍了使用jQuery.form.jsspringmvc框架实现文件上传功能,非常具有参考借鉴价值,感兴趣的朋友一起学习吧...2016-05-14- 这篇文章主要介绍了SpringMVC和rabbitmq集成的使用案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-20