【问题标题】:Spring @RequestBody without using a pojo?Spring @RequestBody 不使用 pojo?
【发布时间】:2018-12-17 20:08:18
【问题描述】:

我正在使用 Spring Boot,并且在我的控制器中定义了一个这样的方法

@PostMapping("/update)
public void update(@RequestBody User user) {
    ...
}

但是在我来自客户端(例如前端或邮递员)的帖子请求中,我有这样的事情:

{
    "firstName" : "John",
    "lastName" : "Doe",
    "id" : 1234,
    "metaInfoId" : "5457sdg26sg4636"
}

问题是我的用户 pojo 中只有 firstNameidlastName 实例字段。但是在我的请求中,我 have to send metaInfoId 以及其他一些需求。那么如何在上面的控制器方法中检索或分离 metaInfoIdUser 模型?

我是否必须创建另一个名为 UserModelRequest 的模型类并添加所有 User 字段以及 metaInfoId 字段,然后使用 @RequestBody?有没有办法简单地从请求中删除metaInfoId,然后将其他所有内容转储到User pojo?例如,您可以在 nodejs 中轻松完成此操作(只需拼接您的对象并获取您需要的内容)。

那么有没有办法在 java spring 中做到这一点而不必创建另一个模型类?

【问题讨论】:

    标签: java spring gson pojo


    【解决方案1】:

    您可以使用@JsonIgnoreProperties(ignoreUnknown = true) 注释您的 POJO,以便忽略它不包含的字段。例

    @JsonIgnoreProperties(ignoreUnknown = true)
    public class User {
        private int id;
        private String firstName;
        private String lastName;
    
        ... getters & setters ...
    }
    

    此外,您不应在休息请求的正文中包含元数据。此信息的正确位置应在标题中。这会将您的方法签名更改为:

    @PostMapping("/update)
    public void update(@RequestBody User user, @RequestHeader(value="metaInfoId") String metaInfoId) {
        ...
    }
    

    如果您必须在请求中添加信息,那么您需要更新 User pojo 类以包含此字段(或者让它扩展具有 metaInfoId 字段的类)

    最后,你真的不想创建一个新类型。您可以更改签名以接受地图并检索必要的信息,例如:

    @PostMapping("/update)
    public void update(@RequestBody Map<String, Object> userMap) {
        String metaInfoId = userMap.get("metaInfoId");
    
        ObjectMapper mapper = new ObjectMapper(); // jackson's objectmapper
        final User user = mapper.convertValue(userMap, User.class);
    }
    

    【讨论】:

    • 您好,感谢您的回答。这解决了我一半的问题。现在 Pojo 忽略了未知属性,我不应该得到任何绑定错误。但是,作为请求一部分的metaInfoId 对我来说仍然很重要。如何在我的控制器中检索该值?
    • 不幸的是,我无法更改规格。我知道这并不理想,但这就是项目已经构建的方式,我没有任何发言权来更改发送请求的方式。那么,如果不创建另一个 pojo 或向用户 pojo 添加额外的字段,就没有办法做到这一点吗?谢谢
    • 为了完整性我又添加了一个选项
    • 旧答案,但只是为了确认:当我向控制器发送 2 个字符串时,我只能构建一个 POJO 并使用 [at]RequestBody,或者我也可以使用 Map 作为[在]请求体?但是没有简单的方法可以说“[at]PostMapping("/foo") public void foo([at]SomeCoolAnno String varA, [at]SomeCoolAnno String varA)”?我不想每次我只有 2 个字符串时都构建 POJO,而且 Map 也相当丑陋......
    【解决方案2】:

    我从问题中了解到,您可能需要两种情况:

    • 在 JSON 中发送一个在 User 对象中没有对应字段的属性。在这种情况下,您仍需要将 User 对象与提供的字段一起使用,并忽略 JSON 中提供的其余部分
    • 在 JSON 中发送其他属性,您仍然需要在 User 对象中捕获它们而不在对象中专门定义这些额外属性。

    我认为在这两种情况下,使用 Jackson 比使用 Gson 更好,因为它对对象具有更丰富的编组控制。因此,我下面的解决方案假设您将使用 Jackson 和 Spring web - Jackson 的 maven 依赖项如下:

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
    </dependency>
    

    第一个案例

    在这种情况下,您需要 Jackson 在将 JSON 反序列化为 User 对象时忽略 metaInfoId 属性。为此,请将此注释添加到 User 类的顶部。

    @JsonIgnoreProperties(ignoreUnknown = true)
    class User {
        private String firstName;
        private String lastName;
    
        // the rest of the class definition
    }
    

    第二种情况

    在第二种情况下,您仍然需要捕获额外的属性。我建议添加一个 catch all HashMap,它接受额外的未定义属性,您可以通过键/值访问它。为此,您需要将以下内容添加到您的 User 类中,或者更好地创建一个抽象类,该类具有此代码,User 对其进行了扩展。

    class User {
        private String firstName;
        private String lastName;
        private Map<String, Object> extra;
    
        @JsonAnySetter
        public void addExtra(final String key, final Object value){
            this.extra.put(key, value);  
        }
    
        @JsonAnyGetter
        public Map<String, Object> getExtra() {
            return Collections.unmodifiableMap(this.extra);
        }
    
        // the rest of the class definition
    }
    

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 2017-12-17
      • 2013-12-28
      • 2019-08-10
      • 1970-01-01
      • 2018-03-19
      • 1970-01-01
      相关资源
      最近更新 更多