springmvc 防止表单重复提交的两种方法

网友投稿 684 2022-12-22

springmvc 防止表单重复提交的两种方法

springmvc 防止表单重复提交的两种方法

目录1、通过session中的token验证步骤1:创建自定义注解步骤2:创建自定义-(@slf4j是lombok的注解)步骤3:将自定义-添加到配置文件2、通过当前用户上一次请求的url和参数验证重复提交步骤1:创建自定义注解步骤2:创建自定义-步骤3:将自定义-添加到配置文件

最近在本地开发测试的时候,遇到一个表单重复提交的现象。 因为网络延迟的问题,我点击了两次提交按钮,数据库里生成了两条记录。其实这种现象以前也有遇到过,一般都是提交后把按钮置灰,无法再次提交,这是很常见的客户端处理的方式。 但是这不是从根本上解决问题,虽然客户端解决了多次提交的问题,但是接口中依旧存在着问题。假设我们不是从客户端提交,而是被其他的系统调用,当遇到网络延迟,系统补偿的时候,还会遇到这种问题

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:将自定义-添加到配置文件

使用案例

//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

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 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;

http:// } else { //否则,已经访问过页面

if (preUrlParams.toString().equals(nowUrlParams)) { //如果上次url+数据和本次url+数据相同,则表示城府添加数据

return true;

} else { //如果上次 url+数据 和本次url加数据不同,则不是重复提交

httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);

return false;

}

}

}

}

步骤3:将自定义-添加到配置文件

使用案例

//在controller层使用 @SameUrlData 注解即可

@SameUrlData

@RequestMapping(value = "save", method = RequestMethod.POST)

public String save(@Valid LoginUser loginUser, Errors errors, RedirectAttributes redirectAttributes, Model model) throws Exception {

//.....

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:包含小程序与app即时通讯的词条
下一篇:天津车载物联网卡售价(车载物联网流量卡收费)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~