酉卒之子

导航

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

不多说,直接上主要错误提示: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的

posted on 2017-11-24 19:51  酉卒之子  阅读(312)  评论(0编辑  收藏  举报