将JavaScript对象数组作为参数发送到控制器

5

这个问题很容易理解。我想通过POST表单将两个不同的对象数组发送到我的控制器,而不使用ajax。

由于参数大小,我改变了我的问题,使用ajax和get请求。目前出现了400(错误请求)。我不知道为什么。请看一下...

我有以下对象:

var phone = {phoneId:"", phoneNumber:"", phoneType:""};
var schedule = {scheduleId:"", time:"", day:""};

我将它们放入 JavaScript 数组中:

var phones = [phone1, phone2, phone3];
var schedules = [schedule1, schedule2];

我使用ajax发送:

var data = {
    index: id,
    schedules: schedules,
    phones: phones
}
var url = "/myController/myUrl"

$.getJSON(url, data, function(result){
    if(result.ok){
         $('#messageAlertSuccess').show();
    } else {
         $('#messageAlertError').show();    
    }
});

我创建了包装类来进行映射,如下:

public class PhoneWrapper(){
    private String phoneId;
    private String phoneNumber;
    private String phoneType;
}

当然,scheduleWrapper也遵循相同的约定。
这是我控制器中的方法:
@ResponseBody
@RequestMapping(value="/myUrl", method=RequestMethod.GET)
public Result doSomething(@RequestParam("index") int index,
                          @RequestParam("phones") Set<PhoneWrapper> phoneWrappers,
                          @RequestParam("schedules") Set<ScheduleWrapper> scheduleWrappers,
                          Model model,
                          HttpSession session){

         //do stuff here.

}

我目前得到了一个400错误。那么问题出在哪里了?


更新:这是 .getJSON jQuery 方法正在构建的 URL:

http://localhost:8080/myApp/myController/myUrl?index=9&schedules%5B0%5D%5BscheduleId%5D=1&schedules%5B0%5D%5BfromDay%5D=Monday&schedules%5B0%5D%5BtoDay%5D=Friday&schedules%5B0%5D%5BfromTime%5D=08%3A30%3A00&schedules%5B0%5D%5BtoTime%5D=16%3A00%3A00&schedules%5B1%5D%5BscheduleId%5D=5&schedules%5B1%5D%5BfromDay%5D=Saturday&schedules%5B1%5D%5BtoDay%5D=Monday&schedules%5B1%5D%5BfromTime%5D=09%3A00%3A00&schedules%5B1%5D%5BtoTime%5D=13%3A00%3A00&phones%5B0%5D%5BphoneId%5D=6&phones%5B0%5D%5BphoneNumber%5D=787-788-1111&phones%5B0%5D%5BphoneType%5D=PHONE&phones%5B1%5D%5BphoneId%5D=106&phones%5B1%5D%5BphoneNumber%5D=787-795-4095&phones%5B1%5D%5BphoneType%5D=FAX
4个回答

3

我发现有几个问题看起来不对劲

除非您在包装器中拥有 getters 和 setters(DTO 是更好的名称),否则我不会在我的 XHR 调用的 DTO 中使用它们,您需要进行更改。

public class PhoneWrapper(){
    private String phoneId;
    private String phoneNumber;
    private String phoneType;
}

公有字段与私有字段的区别

public class PhoneWrapper(){
    public String phoneId;
    public String phoneNumber;
    public String phoneType;
}

你的JS数组实际上是对象,而非真正的数组;
var phones = {phone1, phone2, phone3};
var schedules = {schedule1, schedule2};

这里它们被表示为数组

var phones = [phone1, phone2, phone3];
var schedules = [schedule1, schedule2];

确保文件名在js和java两端是相同的。当排除问题时,打开调试功能非常有帮助。log4j -

<logger name="org.springframework.web.servlet.mvc" >
    <level value="debug" />
</logger>

编辑

在问题更新后,我注意到这与在@RequestParam中绑定列表是相同的问题。


很不幸,我的原始问题中有一个打字错误。它们被正确地定义为数组(因为我正在使用push将对象插入它们)。我的DTO /包装器中也有设置和获取。我采用了不同的方法,但这个问题仍然保持开放状态。话虽如此,我为你们两个点赞,因为你们都有敏锐的眼光。不幸的是,这并没有解决我的问题 :( - Nimchip
@Nimchip,你应该更新你的问题以匹配你上面的评论。你的问题中仍然有一个对象与一个数组不符。 - denov
好的,已经编辑过了。我相信我也尝试过那种方法,但出于某些原因它没有起作用。从Javascript Object[]PhoneWrapper[]ScheduleWrapper[] 的映射没有被执行。然而,当向控制器传递数据时,使用括号命名参数非常重要,否则它将无法将其视为传入的数组。 - Nimchip
你的请求参数应该长成这样:myparam=myValue1&myparam=myValue2&myparam=myValue3。 - denov
你把方法签名从Set<ScheduleWrapper>改成了ScheduleWrapper[]吗?你可能想切换到http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-modelattrib-method-args - denov
显示剩余2条评论

2

我认为你已经接近成功了!首先需要一个包装器来容纳两个Set<>参数,因为Spring无法直接将集合映射到参数(至少目前还不行)。

此外,有两种处理此类请求的方法:

  • 使用JSON请求和@RequestBody,请求体中只需一个JavaScript对象,然后自动将其映射到Java类。这意味着您需要略微更改数据发送方式,并且该方法有一个副作用:您无法通过将参数定义为模型属性来简单合并数据。

  • 第二种可能性是继续使用表单提交。同样,您需要创建包装器并将其用作RequestParam。每个Set<>参数都可以像Sotirios在他的答案中提到的那样使用,或者一个参数同时包含两个集合。然后,您需要修改提交的数据以将电话和日程信息发送为输入字段。我没有在此情况下使用过Set,但参数名称应如phoneWrapper[0].phoneId所示。第二种方法的优点是,您可以将请求数据与现有值合并,因此无需一次性发送完整的电话信息。


我稍微更新了我的问题,现在我正在使用getjson和@requestbody,但目前收到了400错误。 - Nimchip
你能发布发送到服务器的确切JSON字符串和更新后的RequestMapping方法吗?请记住,您需要恰好一个命令对象,其中包含两个字段Set<PhoneWrapper>和Set<Schedule>。 - Martin Frey
是的。我希望你能看到我修改了主贴中的所有代码。我在那里发布了getJSON调用,其中包含一个索引、一个电话数组和一个时间表数组的数据对象。我将使用该字符串更新主贴。此外,控制器方法也已在帖子中进行了更新。 - Nimchip
1
另外,下载Spring MVC Showcase应用程序并查看。有许多基本用例实现。https://github.com/SpringSource/spring-mvc-showcase - Martin Frey
另外,我刚刚重新阅读了你的消息,我并没有特别使用表单来发送数据。我是使用jQuery的getPOST方法来发送一个包含三个重要部分(索引、电话数组和日程数组)的对象数据。当然,它会将数据作为URL参数发送,所以在某种程度上是相似的。 - Nimchip
显示剩余3条评论

1
var phones = {phone1, phone2, phone3};
var schedules = {schedule1, schedule2};

这两个不是数组(方括号),而是对象(花括号)。 与之比较。
var phones = ["phone1", "phone2", "phone3"];
var schedules = ["schedule1", "schedule2"];

如果您要传递实际的对象引用(phone1、phone2、phone3、schedule1和schedule2是对象变量),那么您需要使用

var phones = [phone1, phone2, phone3];
var schedules = [schedule1, schedule2];

请查看我对denov的回复。 - Nimchip
"phones" 不是有效的对象格式 - 它必须具有键值对。 - Dmitri Zaitsev

0

Spring框架将请求参数映射到类实例字段时,它们必须与参数的名称匹配。

因此,有了:

<input type="hidden" name="someParameter" value="123"/>

并且

public class SomeClass {
    private String someParameter;
    // getters and setters
}

一个Spring控制器将能够注入一个SomeClass实例,该实例的字段someParameter具有来自html隐藏输入请求参数的值123。这也被称为命令对象。

Javascript数组对于html或http都没有意义。

至于解决方案,我建议保留你的PhoneWrapper类,使用javascript填充3个<input>元素,并更改方法定义为

@RequestMapping(value=MY_URL, method=RequestMethod.POST)
public String doSomething(@RequestParam("index") int index, 
                      PhoneWrappers phoneWrappers, 
                      ScheduleWrappers scheduleWrappers,
                      Model model,
                      HttpSession session){

注意,不再需要使用数组[]括号(对于ScheduleWrappers同样适用)。


我不相信你可以通过纯HTML和默认的Spring配置来实现这一点。如果你希望得到它们的集合,你需要使用序列化模式,比如JSON或XML,因此需要使用ajax。 - Sotirios Delimanolis
也许你可以帮我一下,但我编辑了标题和代码以适应ajax。我一直收到404错误。 - Nimchip
如果你没有它,下载Firebug来查看你的ajax调用实际发送请求的URL。根据你所在的页面,你可能需要自己输入整个URL(你可以使用jstl构建它)。 - Sotirios Delimanolis
是的,我一直在使用Chrome的控制台……它被正确映射到localhost:8080/myController/myUrl?index=9&schedules%5B0%5D%5B%scheduleId%5D=1……等等。据我所知,对象构造得很好,但它没有到达控制器。 - Nimchip
实际上你是对的,我没有传递正确的URL。现在我得到了一个400错误(坏请求),但没有堆栈跟踪。 - Nimchip
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接