报错:org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error 快速排查解决

​Spring Boot JSON 解析错误:HttpMessageNotreadableException 详解与解决方案​

​1. 错误概述​

在 Spring Boot 应用中,当客户端发送 JSON 数据到后端接口时,可能会遇到以下错误:

org.springframework.http.converter.HttpMessageNotReadableException: 
JSON parse error: Cannot construct instance of `com.example.MyRequestVO` 
(although at least one Creator exists): 
no String-argument constructor/factory method to deserialize from String value ('{"key":"value"}')

这个错误表示 ​​Spring 无法将传入的 JSON 数据正确转换成目标 Java 对象​​,通常是由于 JSON 反序列化失败导致的。


​2. 错误原因分析​

​(1) 错误的请求参数接收方式​

  • ​错误示例​​:使用 @RequestParam 或 String 接收 JSON 数据

@PostMapping("/test")
public String test(@RequestParam String jsonData) { // ❌ 错误方式
    // 尝试手动解析 JSON
}
  • 这样会导致 Spring 把整个 JSON 当作一个字符串处理,而不是自动解析成对象。

​正确方式​​:使用 @RequestBody 接收 JSON

@PostMapping("/test")
public String test(@RequestBody MyRequestVO request) { // ✅ 正确方式
    // Spring 会自动解析 JSON 到 request 对象
}

(2) 目标类缺少无参构造方法​

  • ​Jackson 反序列化要求​​:

    • 如果类没有显式定义构造方法,Jackson 会使用默认的无参构造方法。
    • 如果类有带参数的构造方法,但没有无参构造方法,且没有 @JsonCreator 标注,会导致反序列化失败。
  • ​错误示例​​:

public class MyRequestVO {
    private String name;
    private int age;

    public MyRequestVO(String name, int age) { // ❌ 缺少无参构造方法
        this.name = name;
        this.age = age;
    }
}

解决方案​​:

  • ​方法 1​​:添加无参构造方法
public MyRequestVO() {} // ✅ 添加无参构造方法
  • 方法 2​​:使用 @JsonCreator 标注构造方法
@JsonCreator
public MyRequestVO(
    @JsonProperty("name") String name,
    @JsonProperty("age") int age
) {
    this.name = name;
    this.age = age;
}

(3) JSON 格式不正确​

  • ​可能情况​​:

    • JSON 数据格式错误(如缺少引号、多余的逗号)
    • 字段名与 Java 类属性名不匹配(大小写、命名风格不同)
  • ​示例​​:

{
    "userName": "John",  // Java 类属性可能是 `username`
    "age": 30
}
  • 如果 Java 类使用 username,但 JSON 使用 userName,会导致字段无法映射。

​解决方案​​:

  • ​方法 1​​:使用 @JsonProperty 指定 JSON 字段名
public class MyRequestVO {
    @JsonProperty("userName")
    private String username;
}

  • 方法 2​​:配置 Jackson 忽略大小写
@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper()
            .setPropertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE);
    }
}

(4) 目标类不可变(final)或缺少 setter 方法​

  • ​Jackson 默认使用 setter 方法或字段反射赋值​​:

    • 如果类属性是 final 的,或者没有 setter 方法,会导致赋值失败。
  • ​错误示例​​:

public class MyRequestVO {
    private final String name; // ❌ final 字段无法赋值
    private int age;

    // 没有 setter 方法
}

​解决方案​​:

  • ​方法 1​​:提供 setter 方法
public void setName(String name) {
    this.name = name;
}

  • ​方法 2​​:使用 @JsonCreator + @JsonProperty(适用于不可变对象)
@JsonCreator
public MyRequestVO(
    @JsonProperty("name") String name,
    @JsonProperty("age") int age
) {
    this.name = name;
    this.age = age;
}

​3. 解决方案总结​

​问题​​解决方案​
​错误使用 @RequestParam 接收 JSON​改用 @RequestBody
​缺少无参构造方法​添加无参构造方法 或 使用 @JsonCreator
​JSON 字段名与 Java 属性名不匹配​使用 @JsonProperty 或 配置 Jackson 命名策略
​类不可变(final)或缺少 setter​提供 setter 或 使用 @JsonCreator 构造方法
​JSON 格式错误​检查 JSON 数据是否合法

​4. 最佳实践​

​(1) 推荐使用 @RequestBody 接收 JSON​\

@PostMapping("/user")
public ResponseEntity<String> createUser(@RequestBody UserRequest request) {
    // 处理逻辑
    return ResponseEntity.ok("Success");
}

​(2) 确保目标类可被反序列化​

@Data // Lombok 自动生成 getter/setter
@NoArgsConstructor // 无参构造方法
@AllArgsConstructor // 全参构造方法
public class UserRequest {
    private String username;
    private int age;
}

​(3) 使用 @JsonInclude 控制 JSON 行为​

@JsonInclude(JsonInclude.Include.NON_NULL) // 忽略 null 字段
public class UserRequest {
    private String username;
    private Integer age;
}

​(4) 全局 Jackson 配置(可选)​

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper()
            .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }
}

​5. 总结​

  • HttpMessageNotReadableException 通常是由于 JSON 反序列化失败导致的​​。
  • ​主要检查​​:
    1. 是否使用 @RequestBody 接收 JSON?
    2. 目标类是否有无参构造方法或 @JsonCreator
    3. JSON 字段名是否与 Java 属性匹配?
    4. 是否有 setter 方法或 final 限制?
  • ​最佳实践​​:使用 Lombok (@Data + @NoArgsConstructor) + @RequestBody,避免手动解析 JSON。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值