• 前后台数据传输的一次爬坑


    不多说,直接上主要错误提示:Status Code:400 Mauvaise Requête

    顺便把异常的Response Headers:

    1. Connection:close
    2. Content-Language:fr
    3. Content-Length:983
    4. Content-Type:text/html;charset=utf-8
    5. Date:Fri, 24 Nov 2017 09:36:00 GMT
    6. Server:Apache-Coyote/1.1

    下面上上前后端的代码,以供比较和说明:

    后端的js:(只上封装对象和ajax部分的)

    //封装传入参数
        var record = {
                    id : $("#rowId")[0].dataset.rowId,
            employeeNo : window.localStorage.EMPLOYEENO,
                  name : window.localStorage.EMPLOYEENAME,
             projectNo : projectNo,
           projectName : projectName,
                  type : type,//0:系统项目,1:自建项目
           //beginDate : strData2Int($("#beginDate").val()),//对应实体类里面是Date类型的
             //endDate : strData2Int($("#endDate").val()),
                  asdf : "sdjshjk",
        }
    $.ajax({
            type: "POST",
            url: "admin/plantask/edit/save?type="+operate,//向后台传一个操作类型的字符串
            dataType: "json",
            //contentType: 'application/json',
            data: record,//向后台传的一个对象,里面是对应操作的一条数据,因为这个页面被新增和修改复用,所有会额外向后台传一个操作类型的字符串
            success: function (flag) {}
    })

    控制器代码:

    @ResponseBody
    @RequestMapping(value="admin/plantask/edit/save", method = RequestMethod.POST)
        public int save(PlanTask obj, @RequestParam("type")String type)
        {
        int flag;
            return 0;
        }

    先直接说错误点吧,想必大家也没耐心看完爬坑的过程,直接揭晓答案吧,

    错就错在对象record里面的属性(type),和地址栏里面定义的操作类型健值(刚好也是type)重名了,重名了,重名了,,,好了,其实最开始如果知道是这个的话,一改就OK了!!!

    下面说下慢慢揭开迷雾的过程,及明白的一些东西:

    (1)最开始,因为错误码报400,没找到接口,所以给后台type参数,加了上了@RequestParam("type");-----------(跟@pathVariable的区别(可能敲错了))

    (2)因为Response Headers:里面有一句Content-Language:fr;以为是页面默认编码的问题,取模板页改了<meta http-equiv="content-language" content="zh-CN" />,差点把<html lang="en">这个也给改了

    (3)后面竟然怀疑POST能不能地址栏传参(说实话,已经怀疑人生了!!),答案是肯定的,post不但支持,还安全,参数允许长度还比get大好多。。。

    (4)。。。。。

    当然,以上种种想法并没有解决问题,于是用了分解问题的办法,也就是想具体定位问题,也是最后水落石出的关键,拆分过程:

    (1)当然是先验证接口(不过这里说一下,最开始是绕过了后台接收”对象 + 字符串参数”的方法,用了直接前后端分别转包拆包,中间用json字符串传递的方法,虽然万能,但实在麻烦和不易于阅读理解,后面会附上具体代码,也算是一种实现方式),让后台接口只接收一个对象、或一个字符串

    (a)只接收单个对象,最开始,我没注释掉两个日期类型属性前,也是保错的,也是吧参数分开传才发现(为什么后台拆json字符串两个日期的值一样),于是发现,其实js封装对象的方法有N种,比如:

    var obj = {}
        obj["id"] = $("#rowId")[0].dataset.rowId;
        obj["employeeNo"]=window.localStorage.EMPLOYEENO;
        obj["name"] = window.localStorage.EMPLOYEENAME;
        obj["projectNo"] = projectNo;
        obj["projectName"] = projectName;
    //中括号,里面双引号,定义健,= 等号赋值的方法;
    var obj = {}
        obj.id = $("#rowId")[0].dataset.rowId;
        obj.employeeNo = window.localStorage.EMPLOYEENO;
        obj.name = window.localStorage.EMPLOYEENAME;
        obj.projectNo = projectNo;
        obj.projectName = projectName;
    //直接对象‘点’属性,= 等号赋值的方法
    var obj = {
                "id" : $("#rowId")[0].dataset.rowId,
                "employeeNo" : window.localStorage.EMPLOYEENO,
                "name" : window.localStorage.EMPLOYEENAME,
                "projectNo" : projectNo,
                "projectName" : projectName
        }
    //全部在一对{}大括号里面,直接“健”:值的方法(这里健用了双引号,其实不用也是可以的,如最开始的js部分)
    最后说下,这里定义obj之后,定义健及给健赋值的方式(点、中括号、冒号),还有每个健直接的分隔符,就是最后的,是逗号还是分号
    也就是,目前一共有了四种在js定义对象的方法,两优两劣,各有所爱

    回到正题,分开后当然是OK!的,于是开始单参数传递字符串

    (b)去掉对象,单参数地址栏传递字符串

    发现debug看到type显示的值为:type="update,0"(id=20580) hash=0 value="20582"(点开看是:[u, p, d, a, t, e, ,, 0])

    也就是说type里面有两个值,一个updat,一个0;讲真,其实到这里其实问题已经解决了,可以恕我**,我当时没理解为什么==、

    (5)回到主干,当时和同事讨论后,同事建议我建一个View,把对象和单个字符串拼在一个View里面(当然,这是万能的,但是缺点不用多言。。)

    于是,突然发现,我在record对象里面,随意加的键值对,如果后台PlanTask实体类里面如果没有对应属性值接收的话,正常情况后台是获取不到值的,但是如果在接口入参(即形参)加上@RequestParam("js里面定义的键") String str;是可以直接把record里面,或者地址栏里面定义的值取到的(当时震撼了,豁然开朗,一万种传参情况涌了出来,但是入参多了,写的麻烦,不易阅读)

    于是另一种完美解决的方案又出来了,必封装拆分json字符串的形式好了很多很多,但终究是绕过了问题,于是。。。

    (6)也是为了进一步测试(5)中在接口定义@RequestParam("jsKey") String str;这种方式,把url: "admin/plantask/edit/save?type=value",里面的键type改成了别的,嗖的一下,嗖的一下,嗖的一下,OK!了,至此,一切水落石出了,

    就是重名引起的问题,于是回头重新验证了一遍,都是OK的;结束!!!

    最后附上,最原始的解决方案,就是封装拆分json字符串的形式的

    JS封装:

    //封装传入参数
        var record = {
                    id : $("#rowId")[0].dataset.rowId,
            employeeNo : window.localStorage.EMPLOYEENO,
                  name : window.localStorage.EMPLOYEENAME,
             projectNo : projectNo,
           projectName : projectName,
                  type : type,//0:系统项目,1:自建项目
             //beginDate : strData2Int($("#beginDate").val()),
               //endDate : strData2Int($("#endDate").val()),
           initPrecent : $("#initPrecent").val(),
        achievePrecent : $("#achievePrecent").val(),
         planTotalHour : $("#planTotalHour").val(),
           description : $("#description").val().trim(),//去空格
                  asdf : "sdjshjk",
        }
            
        var param = {
              "record" : record,
                "type" : operate//新增还是修改
        }
    $.ajax({
            type: "POST",
            url: "admin/plantask/edit/save?typee="+operate,
            data: {            //"param" : URLEncoder.encoder(JSON.stringify(param), "UTF-8"),//然而这种并不能在js端解决乱码问题            "param" : JSON.stringify(param),        },
            dataType: "json",
            data: record,
            success: function (flag) {}
    })

    后台解析代码:

    @ResponseBody
        @RequestMapping(value="admin/plantask/edit/save", method = RequestMethod.POST)
        public int save(String param)
        {
            String str = HttpHelper.UTF8(param);//首先要解决乱码问题
            JSONObject jsonObject = JSONObject.fromObject(str);
            Map map = (Map)jsonObject;
            String type = (String) map.get("type");//获取字符串参数
            Object plantask = map.get("record");//获取对象
            JSONObject json = JSONObject.fromObject(plantask);
            PlanTask obj = (PlanTask) JSONObject.toBean(json,PlanTask.class);
            int flag;
            //do someingreturn 0;

    这种方式虽然繁琐一点,但是1、可以不用管重名问题,调用接口也不会报错,因为参数都封装在一个map形式的json里,2、不用考虑时间,但也是两个时间值相同的问题所在

    但是,问题解决后,当然会采取最开始想的那种方案,毕竟简单明了,而且没有乱码问题(框架的强大之处)

    url: "admin/plantask/edit/save?type=operate",//
    问号后面的type=值,中的type(键)随便改成了别的,嗖的一下,嗖的一下,嗖的一下,OK!了,到此,问题水落石出
    就是重名引起的,于是回头都验证了一遍,都是OK的
  • 相关阅读:
    docker for windows 中挂载文件到容器
    docker for windows 中 镜像 microsoft/donet 的文件结构
    window7下docker toolbox 启用数据卷报错: Error response from daemon: invalid mode:
    无法创建虚拟目录
    docker 内时区和宿主机差8个小时,怎么办?
    多线程之同时更改数据问题--启用lock
    Linux shell Bash的基本功能1
    Linux shell 脚本执行方式
    Linux vim编辑器使用技巧
    Linux vim编辑器命令
  • 原文地址:https://www.cnblogs.com/zz-3m23d-begining/p/7892134.html
Copyright © 2020-2023  润新知