温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

springmvc中如何防止表单重复提交

发布时间:2021-08-03 14:24:24 来源:亿速云 阅读:191 作者:Leah 栏目:开发技术

这篇文章给大家介绍springmvc中如何防止表单重复提交,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。


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中如何防止表单重复提交就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI