发送ajax请求时由于click事件重复绑定导致的请求重复发送问题

确认删除市场活动

问题场景

项目背景:CRM练习项目,通过复选框选择列表中的数据,用户点击删除按钮,弹出确认弹窗,用户点击确认后,前端分装数据到数组,发送ajax请求,将数据传递至Controller进行处理。
JDK:jdk21.0.2
IDE:intelliJ IDEA
数据库:MariaDB10
服务器:Tomcat10
构建工具:apache-maven-3.9.6
项目地址:https://gitcode.com/weixin_44803446/crm-project/overview


问题描述

  1. ajax发送数组数据,后台接收不到的问题
    前端将选中的复选框的value值封装到数组中,在ajax中,使用data:JSON.stringify(Arry)处理并发送。前端部分JavaScript代码如下:
var checkedActivities = $("#listBody input[type='checkbox']:checked");
// 封装数据
var checkedActivitiesIdArray = [];
    checkedActivities.each(function () {
    checkedActivitiesIdArray.push(this.value);
});
 if(window.confirm(confirmMessage)){
        // 用户确认删除,发送ajax请求
        $.ajax({
        	url:"deleteActivitiesByIdArray.do",
        	type:"POST",
        	contentType: 'application/json',
        	data: JSON.stringify(checkedActivitiesIdArray),
        	success:function (data) {
        		if(data.code === "1"){
          		// 刷新市场活动的列表
          		$("#searchBtn").click();
          		$("#deleteConfirmMessage").text("");
         		}else{
           		alert(data.message);
         		}
      		}
   		});
}

后端Controller如下:

@RequestMapping("/workbench/activity/deleteActivitiesByIdArray.do")
	@ResponseBody
	public Object deleteActivitiesByIdArray(@RequestBody List<String> ids){
		System.out.println(ids);
			// 做了一些事情
        }

当这样写的时候,在运行后,一旦前端发送ajax请求,就会报IllegalStateException错误;

java.lang.IllegalStateException: No primary or single unique constructor found for interface java.util.List
		at org.springframework.beans.BeanUtils.getResolvableConstructor(BeanUtils.java:265)
		at org.springframework.validation.DataBinder.createObject(DataBinder.java:924)
		at org.springframework.validation.DataBinder.construct(DataBinder.java:903)
		at org.springframework.web.bind.ServletRequestDataBinder.construct(ServletRequestDataBinder.java:116)
		at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.constructAttribute(ServletModelAttributeMethodProcessor.java:157)
  1. 使用模态框时,在前端进行删除操作的时候,有一个诡异事件,就是服务器第一次启动时,删除任务可以正常进行,但是第二次删除时,后台可以删除数据,但是前端收到的反馈确实删除失败。
    前端页面代码如下:
<!-- 删除市场活动 -->
<div class="modal fade" id="deleteActivityConfirmModal" data-backdrop="static" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="staticBackdropLabel">删除市场活动</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">
                <p id="confirmMessage"></p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
                <button type="button" class="btn btn-danger" id="deleteConfirmBtn">确认删除</button>
            </div>
        </div>
    </div>
</div>

JavaScript代码如下:

// 给删除按钮绑定事件
 $("#deleteActivitiesBtn").on("click", function () {
     var checkedActivities;
     checkedActivities = $("#listBody input[type='checkbox']:checked");
     if (checkedActivities.length <= 0) {
         alert("不可以删除空气!")
         return;
     }
     const confirmMessage = "您确定要删除选中的 " + checkedActivities.length + " 条数据吗?";
     $("#confirmMessage").text(confirmMessage);
     $("#deleteActivityConfirmModal").modal("show");
     // 给删除确认按钮添加事件
     $("#deleteConfirmBtn").on("click", function () {
         // 定义一个数组,遍历选中的复选框,将其value值装入数组中
         var checkedActivitiesIdArray = [];
         checkedActivities.each(function () {
             checkedActivitiesIdArray.push(this.value);
         });
         console.log(checkedActivitiesIdArray);
         if (checkedActivities.length === checkedActivitiesIdArray.length) {
             // 用户确认删除,发送ajax请求
             $.ajax({
                 url: "/crm-core/workbench/activity/deleteActivitiesByIdArray.do",
                 type: "POST",
                 contentType: 'application/json',
                 data: JSON.stringify(checkedActivitiesIdArray),
                 success: function (data) {
                     console.log("ajax发送后的数组" + checkedActivitiesIdArray);
                     if (data.code === "1") {
                         checkedActivitiesIdArray = [];
                         // 刷新市场活动的列表
                         $("#searchBtn").click();
                         $("#confirmMessage").text("");
                         $("#deleteActivityConfirmModal").modal("hide");
                     } else {
                         alert(data.message);
                     }
                 }
             });
         } else {
             console.log("请求发送有问题!")
         }
     });
 });

原因分析

  1. ajax发送数组数据,后台接收不到的问题原因分析:
    这个从报错信息中可以看出原因,大致意思就是说List是一个接口,Spring框架无法确定如何实例化 java.util.List 接口的实例对象,所以需要用有具体实现类的类作为参数;我在这里使用了ArrayList<String>来接收前端传递来的数组数据,经过亲自验证,使用String[]数组来接收参数也是可以的。
  2. 使用模态框时,点击一次发送两次请求的诡异问题原因分析:
    查看日志:
# 第一次发送的删除请求
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3e15312a]
JDBC Connection [org.mariadb.jdbc.Connection@23c57da9] will be managed by Spring
==>  Preparing: delete from tbl_activity where id in ( ? )
==> Parameters: 13e08e9d72ac4bd7abe4203abddb6a02(String)
<==    Updates: 1
Creating a new SqlSession
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@27c6725c]
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1f9813e2]
JDBC Connection [org.mariadb.jdbc.Connection@3e9bbae4] will be managed by Spring
JDBC Connection [org.mariadb.jdbc.Connection@623508ea] will be managed by Spring
# 一次发了两个请求,其中一个还是上一次已经删除过了的数据
==>  Preparing: delete from tbl_activity where id in ( ? )
==>  Preparing: delete from tbl_activity where id in ( ? )
==> Parameters: 7ef3f93c34504922be02f3a9b1de4526(String)
==> Parameters: 13e08e9d72ac4bd7abe4203abddb6a02(String)
<==    Updates: 0
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@27c6725c]
<==    Updates: 1

查看Mybatis日志后发现,每次前端一旦点击删除确认按钮,就会在发送本次选中的删除的项目时,将前一次已经删过的数据又向后台发送了一遍,已经删除过了,所以后台肯定就会报错。由于前面使用window.confirm()时功能是正常的,所以可以断定后端代码是没有问题,问题就出在前端JavaScript中。
在查看了前面的JavaScript代码后,发现有以下问题:
将$(“#deleteConfirmBtn”).on(“click”, function () {});写在了$(“#deleteActivitiesBtn”).on(“click”, function () {});函数中,这就导致了在点击删除按钮时,内部再次为删除确认按钮绑定了点击事件。这意味着每次点击删除按钮时,都会为删除确认按钮重复添加一次事件监听器。如果多次点击删除按钮,点击删除确认按钮时会执行多次ajax请求。


解决方案:

  1. ajax发送数组数据,后台接收不到的问题解决方案:
    避免使用List<>这种接口类型作为接收前端传递的数据,可以使用ArrayList<>集合或者String[]数组来接收前端传递的数组数据
	@RequestMapping("/workbench/activity/deleteActivitiesByIdArray.do")
	@ResponseBody
	public Object deleteActivitiesByIdArray(@RequestBody ArrayList<String> ids){
	// 做了一些事情
}
	@RequestMapping("/workbench/activity/deleteActivitiesByIdArray.do")
	@ResponseBody
	public Object deleteActivitiesByIdArray(@RequestBody String[] ids){
	// 做了一些事情
}
  1. 使用模态框时,点击一次发送两次请求的诡异问题解决方案
    针对事件绑定类操作,避免嵌套,应该独立放置,否则就会导致重复绑定。调整后的JavaScript代码如下:
// 定义在外面
var checkedActivities;
var checkedActivitiesIdArray = [];
// 给删除按钮绑定事件
$("#deleteActivitiesBtn").on("click", function () {
    checkedActivities = $("#listBody input[type='checkbox']:checked");
    if (checkedActivities.length <= 0) {
        alert("不可以删除空气!")
        return;
    }
    const confirmMessage = "您确定要删除选中的 " + checkedActivities.length + " 条数据吗?";
    $("#confirmMessage").text(confirmMessage);
    $("#deleteActivityConfirmModal").modal("show");
});
// 给删除确认按钮添加事件
$("#deleteConfirmBtn").on("click", function () {
    // 定义一个数组,遍历选中的复选框,将其value值装入数组中
    checkedActivities.each(function () {
        checkedActivitiesIdArray.push(this.value);
    });
    console.log(checkedActivitiesIdArray);
    if (checkedActivities.length === checkedActivitiesIdArray.length) {
        // 用户确认删除,发送ajax请求
        $.ajax({
            url: "/crm-core/workbench/activity/deleteActivitiesByIdArray.do",
            type: "POST",
            contentType: 'application/json',
            data: JSON.stringify(checkedActivitiesIdArray),
            success: function (data) {
                console.log("ajax发送后的数组" + checkedActivitiesIdArray);
                if (data.code === "1") {
                    checkedActivitiesIdArray = [];
                    // 刷新市场活动的列表
                    $("#searchBtn").click();
                    $("#confirmMessage").text("");
                    $("#deleteActivityConfirmModal").modal("hide");
                } else {
                    alert(data.message);
                }
            }
        });
    } else {
        console.log("请求发送有问题!")
    }
});
});
  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凉拌糖醋鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值