在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.2jackson 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并反序列化为对象列表的主要内容,如果未能解决你的问题,请参考以下文章

支持Java Spring MVC

Spring MVC灵活控制返回json的值(自定义过滤字段)

Spring mvc 实现jsonp和json数据类型

从api逻辑任务和反序列化对象并反序列化json

Spring Boot,Spring MVC JSON RequestBody:未知属性被忽略

@JsonCreator 不适用于 Spring MVC 中的 @RequestParams