在spring mvc控制器接收json并反序列化为对象列表
Posted
技术标签:
【中文标题】在spring mvc控制器接收json并反序列化为对象列表【英文标题】:receiving json and deserializing as List of object at spring mvc controller 【发布时间】:2014-05-25 14:58:17 【问题描述】:我的代码如下:
控制器
@RequestMapping(value="/setTest", method=RequestMethod.POST, consumes="application/json")
public @ResponseBody ModelMap setTest(@RequestBody List<TestS> refunds, ModelMap map)
for(TestS r : refunds)
System.out.println(r.getName());
// other codes
TestS pojo
public class TestS implements Serializable
private String name;
private String age;
//getter setter
Json 请求
var z = '["name":"1","age":"2","name":"1","age":"3"]';
$.ajax(
url: "/setTest",
data: z,
type: "POST",
dataType:"json",
contentType:'application/json'
);
它给出了这个错误
java.lang.ClassCastException:java.util.LinkedHashMap 无法转换为 com.air.cidb.entities.TestS
我正在使用 spring 3.1.2 和 jackson 2.0.4
编辑:我想在我的控制器方法中接收 TestS 对象的列表,并处理它们。我无法找到我是否发送了错误的 json 或我的方法签名错误。
【问题讨论】:
您确定这是您当前的代码吗?客户端调用/cmp/approveRefunds
,你的控制器映射到/setTest
。
参考这个,***.com/questions/10864049/…
【参考方案1】:
我相信这会解决问题
var z = '["name":"1","age":"2","name":"1","age":"3"]';
z = JSON.stringify(JSON.parse(z));
$.ajax(
url: "/setTest",
data: z,
type: "POST",
dataType:"json",
contentType:'application/json'
);
【讨论】:
【参考方案2】:解决方案效果很好,
public List<String> savePerson(@RequestBody Person[] personArray)
对于这个签名,你可以像邮递员一样传递Person
数组
[
"empId": "10001",
"tier": "Single",
"someting": 6,
"anything": 0,
"frequency": "Quaterly"
,
"empId": "10001",
"tier": "Single",
"someting": 6,
"anything": 0,
"frequency": "Quaterly"
]
别忘了加consumes
标签:
@RequestMapping(value = "/getEmployeeList", method = RequestMethod.POST, consumes="application/json", produces = "application/json")
public List<Employee> getEmployeeDataList(@RequestBody Employee[] employeearray) ...
【讨论】:
【参考方案3】:对我来说,下面的代码有效,首先发送带有正确标题的 json 字符串
$.ajax(
type: "POST",
url : 'save',
data : JSON.stringify(valObject),
contentType:"application/json; charset=utf-8",
dataType:"json",
success : function(resp)
console.log(resp);
,
error : function(resp)
console.log(resp);
);
然后在 Spring 方面 -
@RequestMapping(value = "/save",
method = RequestMethod.POST,
consumes="application/json")
public @ResponseBody String save(@RequestBody ArrayList<KeyValue> keyValList)
//Saving call goes here
return "";
这里的 KeyValue 是简单的 pojo,对应于你的 JSON 结构,你也可以根据需要添加产品,我只是返回字符串。
我的json对象是这样的-
["storedKey":"vc","storedValue":"1","clientId":"1","locationId":"1",
"storedKey":"vr","storedValue":"","clientId":"1","locationId":"1"]
【讨论】:
【参考方案4】:@RequestMapping(
value="person",
method=RequestMethod.POST,
consumes="application/json",
produces="application/json")
@ResponseBody
public List<String> savePerson(@RequestBody Person[] personArray)
List<String> response = new ArrayList<String>();
for (Person person: personArray)
personService.save(person);
response.add("Saved person: " + person.toString());
return response;
我们可以使用如上所示的数组。
【讨论】:
这应该是公认的答案。以数组为主体,在控制器方法中将其转换为列表。无需包装类或更改 JSON 的格式。【参考方案5】:这是适合我的代码。关键是你需要一个包装类。
public class Person
private String name;
private Integer age;
public String getName()
return name;
public void setName(String name)
this.name = name;
public Integer getAge()
return age;
public void setAge(Integer age)
this.age = age;
@Override
public String toString()
return "Person [name=" + name + ", age=" + age + "]";
一个 PersonWrapper 类
public class PersonWrapper
private List<Person> persons;
/**
* @return the persons
*/
public List<Person> getPersons()
return persons;
/**
* @param persons the persons to set
*/
public void setPersons(List<Person> persons)
this.persons = persons;
我的控制器方法
@RequestMapping(value="person", method=RequestMethod.POST,consumes="application/json",produces="application/json")
@ResponseBody
public List<String> savePerson(@RequestBody PersonWrapper wrapper)
List<String> response = new ArrayList<String>();
for (Person person: wrapper.getPersons())
personService.save(person);
response.add("Saved person: " + person.toString());
return response;
发送的请求是 POST 中的 json
"persons":["name":"shail1","age":"2","name":"shail2","age":"3"]
响应是
["Saved person: Person [name=shail1, age=2]","Saved person: Person [name=shail2, age=3]"]
【讨论】:
感谢您的回答。但我想知道为什么我们需要做一个包装器?为什么这不能使用地图来完成? 这里我怎样才能以不同的方式命名persons标签 --> "CustomName":["name":"shail1","age":"2","name":" shail2","age":"3"]?【参考方案6】:这在您尝试的方式中是不可能的。 Jackson 解组处理在 类型擦除之后编译的java 代码。所以你的
public @ResponseBody ModelMap setTest(@RequestBody List<TestS> refunds, ModelMap map)
真的只有
public @ResponseBody ModelMap setTest(@RequestBody List refunds, ModelMap map)
(列表 arg 中没有泛型)。
Jackson 在解组List
时创建的默认类型是LinkedHashMap
。
正如@Saint 所提到的,您可以通过为列表创建自己的类型来规避这种情况,如下所示:
class TestSList extends ArrayList<TestS>
然后将你的控制器签名修改为
public @ResponseBody ModelMap setTest(@RequestBody TestSList refunds, ModelMap map)
【讨论】:
这不是真的。 Spring 4 支持这一点。您始终可以通过反射获得带有实际类型参数的参数化方法参数。 但是由于他们没有使用 Spring 4,因此您的这部分答案是合适的。删除类型擦除位。 @SotiriosDelimanolis 很好的提示,不知道。您能否将我引导到 spring 文档中提到它的部分或它被埋在源代码中的部分? 我现在没有链接。对于反射部分,可以使用Method#getGenericParameterTypes()
获取类型信息。至于杰克逊与之合作,MVC章节中必须有一个条目。以上是关于在spring mvc控制器接收json并反序列化为对象列表的主要内容,如果未能解决你的问题,请参考以下文章
Spring MVC灵活控制返回json的值(自定义过滤字段)