【问题标题】:Ajax POST Array of Objects to Spring MVC Controller - Multiple ErrorsAjax POST 对象数组到 Spring MVC 控制器 - 多个错误
【发布时间】:2019-09-27 13:07:35
【问题描述】:

我需要向 Spring MVC 控制器提交一个 JS 形式的对象数组。所有属性名称都匹配。

@PostMapping("/addAdmin")
public void addAdmin(@RequestParam List<UserRolesGUIBean> userRolesGUIBeans)
{
    // ...      
}   

JS:

 var entries = [];
 //...
 // entries is an array of objects of the form {id: "..", role: ".."}
 // verified to be correct before submission

 $.ajax({
        type : "post",
        dataType : "json", 
        url : 'addAdmin',  
        data : JSON.stringify(entries)
 })

豆子

public class UserRolesGUIBean implements Serializable {
    private String id;
    private String role;
    // + Constructors (Empty + Full), Getters and setters
}

错误:

Required List parameter 'userRolesGUIBeans' is not present]

还尝试使用ModelAttributeArrayList

PostMapping("/addAdmin")
    public void addAdmin(@ModelAttribute ArrayList<UserRolesGUIBean> userRolesGUIBeans)  {

现在没有错误,但是列表是空的,没有收到数据

尝试了所有方法——数组与列表、JSON.stringify(data) 或带有data {"entries" : entries}RequestBody 的数据对象不起作用并给出 UTF 错误;和上面的RequestParam 也不起作用。

这对于一个简单的任务来说太复杂了。

【问题讨论】:

    标签: ajax spring spring-boot spring-mvc


    【解决方案1】:

    您正在尝试使用帖子发送 JSON 对象。你应该使用@RequestBody注解。

    尝试以这种方式改变你的方法:

    @PostMapping("/addAdmin")
    public void addAdmin(@RequestBody List<UserRolesGUIBean> userRolesGUIBeans)
    {
        // ...      
    } 
    

    这样Spring会拦截Json并将其转换为List of wished objects

    【讨论】:

    • 不,很遗憾不起作用。这个错误是org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported。这里也有报道,在建议的 cmets 中,stackoverflow.com/a/44696610/1005607。事实上,解决这个 UTF 错误的方法是 remove RequestBody, stackoverflow.com/a/38252958/1005607
    • 必须将内容类型设置为application/json
    • @geneb。我认为您应该回到基础并了解 Spring 的各种注释和默认行为的目的。 Angelo 给你的代码是我在这么多端点中编写的。使用 Postman 向您的端点提交请求,首先将 Content-Type 设置为 application/json。让它在那里工作,然后再回到你的 JS 代码。
    • @AngeloImmedia 即使使用application/json 也出现同样的 UTF 错误,我试过了。
    • 我认为问题是,我没有提交表单 (@ModelAttribute),所以我必须提交一个“自定义”序列化 JSON 字符串为 @RequestBody .但是当我做那个自定义@RequestBody时,我可以在控制器中接收一个普通的字符串,但是我不能接收一个像@ModelAttribute这样的映射对象。以下作为字符串工作:@RequestBody String json 和 JS 中的常规 json 数据类型。
    【解决方案2】:

    解决方案

    1) 理论上,如果我正在提交表单(如$('#myForm').submit()),我可以使用@ModelAttribute 自动将我的表单绑定到bean。这就是@ModelAttribute 所做的——它用于表单提交。我没有真实的形式;只有我自己的自定义值。

    我仍然可以通过“即时”创建动态表单来“伪造”表单提交,但我无法获得数组字段表单提交(例如,obj[] 在 HTML 中带有 [] 符号Name) 映射到@ModelAttribute List&lt;Bean&gt;,所以我忽略了这种不寻常的表单提交方法。

    2) 真正有效的方法是提交一个我自己的自定义 JSON 字符串。 与任何表单提交无关,因此不能使用@ModelAttribute。相反,这是@RequestBody 方法。然后我必须自己解析 JSON RequestBody 字符串——这里我们必须使用 Jackson、Java JSON 或 GS​​ON 来解析 JSON 数组。

    就我而言,

    JS:

     $.ajax({
            type : "post",
            dataType : 'json', 
            url : 'addAdmin',  
            data : JSON.stringify(entries)
     })
    

    控制器(注意它只需要一个自定义字符串)。然后它使用 Jackson 手动解析字符串,因为在这种情况下 Spring 不会这样做。 (Spring 只会在你使用 @ModelAttribute 表单绑定时自动解析。)

    @PostMapping("/addAdmin")
    public boolean addAdmin(@RequestBody String json) throws Exception {
    
          String decodedJson = java.net.URLDecoder.decode(json, "UTF-8");
          ObjectMapper jacksonObjectMapper = new ObjectMapper(); // This is Jackson
          List<UserRolesGUIBean> userRolesGUIBeans =  jacksonObjectMapper.readValue(
                  decodedJson, new TypeReference<List<UserRolesGUIBean>>(){});
          // Now I have my list of beans populated.
    

    }

    【讨论】:

    • 使用 Spring Boot 和 Spring MVC 的全部意义在于让框架为您完成这种样板工作。互联网上有很多教程向您展示如何实现它(javadevjournal.com/spring/spring-request-response-body)。如果您认为这是使用 Spring 的“真正”方法,那么您肯定有大量的手动工作等着您。
    • 这些都是简单的案例——我当然可以@RequestBody MyBean bean。一旦你偏离了幸福的道路,就像使用数组/列表一样,它就不再那么简单了。无法自动映射@RequestBody List&lt;MyBean&gt; 或数组。
    • 兄弟,出于某种原因,您一直认为您的场景很特别。你不认为框架背后的人以前已经处理过你的情况吗?我会给你一个最小的可运行代码来证明它甚至可以与 List 一起工作。
    • 我同意@Mr.J4mes 你在你的场景中遗漏了一些东西
    【解决方案3】:

    按照承诺,请转到https://start.spring.io/ 并为spring-boot-starter-web 创建一个具有单一依赖关系的新项目。

    之后,您可以在项目中创建以下 bean。

    import java.util.List;
    
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class DemoController {
        @PostMapping("/request-body")
        public void getRequestBody(@RequestBody List<Person> list) {
            for (Person person : list) {
                System.out.println(person.name);
            }
        }
    
        public static class Person {
            private String name;
            private String phoneNo;
    
            /**
             * @return the name
             */
            public String getName() {
                return name;
            }
            /**
             * @param name the name to set
             */
            public void setName(String name) {
                this.name = name;
            }
            /**
             * @return the phoneNo
             */
            public String getPhoneNo() {
                return phoneNo;
            }
            /**
             * @param phoneNo the phoneNo to set
             */
            public void setPhoneNo(String phoneNo) {
                this.phoneNo = phoneNo;
            }
        }
    }
    

    没什么特别的,只需输入Person 的列表并打印出名称即可。您可以右键单击并直接从 IDE 运行项目。

    您可以如下打开 Postman 并发出 POST 请求。

    这是在控制台中打印的内容。

    如果它与 Postman 一起工作,你可以让它在 JS 中工作。你只是还没弄清楚怎么做。我认为您应该找出在 JS 中提交请求的正确方法,而不是解决您找到的“解决方法”。此外,对 Spring 框架的一些了解也会有所帮助。否则,您将只是随意尝试诸如@ModelAttribute 之类的东西而无处可去。

    【讨论】:

      猜你喜欢
      • 2016-05-01
      • 2016-05-06
      • 1970-01-01
      • 2013-04-13
      • 2012-12-30
      • 2012-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多