Spring Boot中HTTP请求参数转换和请求体JSON反序列化的区别解析

 更新时间:2025年12月08日 08:49:05   作者:青衫扶夕  
本文主要介绍了SpringBoot中HTTP请求参数转换和请求体JSON反序列化的区别,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧

Spring Boot中HTTP请求参数转换和请求体JSON反序列化的区别

问题

假设如下方法和对象

@Operation(summary = "新增或修改标签信息")
@PostMapping("saveOrUpdate")
public Result saveOrUpdateLabel(@RequestBody LabelInfo labelInfo) {
    service.saveOrUpdate(labelInfo);
    return Result.ok();
}
@Schema(description = "标签信息表")
@TableName(value = "label_info")
@Data
public class LabelInfo extends BaseEntity {
    private static final long serialVersionUID = 1L;
    @Schema(description = "类型")
    @TableField(value = "type")
    private ItemType type;
    @Schema(description = "标签名称")
    @TableField(value = "name")
    private String name;
}
@Getter
@AllArgsConstructor
public enum ItemType implements BaseEnum {
    APARTMENT(1, "公寓"),
    ROOM(2, "房间");
    @EnumValue
    @JsonValue
    private Integer code;
    private String name;
}

saveOrUpdateLabel方法中,如果不对ItemType对象的code变量添加@JsonValue注解,若前端发送{ "type": "2", "name": "两室一厅" }会报错

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `com.sense.lease.model.enums.ItemType` from String "2": not one of the values accepted for Enum class: [APARTMENT, ROOM]]

此时ItemType的反序列化流程是什么样的?以及为什么是通过Jackson的@JsonValue实现反序列化而不是WebDataBinderConverter

1. 两种不同的转换场景

首先,我们需要区分两种不同的转换场景:

  • HTTP请求参数转换
    • 场景:URL查询参数或表单数据,如?type=2
    • 处理器:Spring MVC的WebDataBinderConverter接口
    • 转换方向:String → Java对象
  • JSON反序列化
    • 场景:请求体中的JSON数据,如{"type": "2", "name": "两室一厅"}
    • 处理器:Jackson库的ObjectMapper
    • 转换方向:JSON字符串 → Java对象

2. JSON反序列化流程详解

当Spring Boot接收到包含JSON的请求体时,会发生以下过程:

HTTP请求到达

POST /admin/label/saveOrUpdate
Content-Type: application/json
{
  "type": "2",
  "name": "两室一厅"
}
  • Jackson处理JSON
    • Spring Boot使用Jackson的ObjectMapper来解析JSON
    • 当遇到"type": "2"时,Jackson需要将其转换为ItemType枚举
  • 默认枚举反序列化
    • Jackson默认使用枚举的名称进行反序列化
    • 它会尝试匹配"2"与枚举常量名称:[APARTMENT, ROOM]
    • 由于没有名为"2"的枚举常量,所以抛出异常

3. @JsonValue注解的作用

@JsonValue注解告诉Jackson在进行序列化和反序列化时,应该使用哪个字段作为枚举的值:

public enum ItemType implements BaseEnum {
    APARTMENT(1, "公寓"),
    ROOM(2, "房间");
    @EnumValue  // MyBatis-Plus使用此注解确定存储到数据库的值
    @JsonValue  // Jackson使用此注解确定序列化/反序列化的值
    private Integer code;
    // ...
}

当添加了@JsonValue注解后:

  • 序列化:将ItemType.ROOM转换为JSON时,输出2而不是"ROOM"
  • 反序列化:将JSON中的字符串"2"或者数字2转换为ItemType.ROOM对象

4. 为什么Converter不适用于JSON反序列化

Converter接口(如StringToItemTypeConverter)是为Spring MVC的WebDataBinder设计的,专门用于处理HTTP请求参数的转换,而不是JSON数据的反序列化。

两者的工作层面不同:

  • Converter
    • 工作在Spring MVC层面
    • 处理HTTP请求参数(查询参数、表单数据)
    • 在控制器方法参数绑定之前执行
  • Jackson的反序列化
    • 工作在JSON处理层面
    • 处理请求体中的JSON数据
    • 在控制器方法参数绑定之前执行,但独立于Spring MVC的转换机制

5. 验证这个区别

可以通过以下方式验证这个区别:

测试请求参数(使用Converter):

GET /admin/label/list?type=2

这个请求会使用StringToItemTypeConverter进行转换

测试JSON请求体(使用@JsonValue):

POST /admin/label/saveOrUpdate
Content-Type: application/json
{
  "type": "2",
  "name": "两室一厅"
}

这个请求会使用Jackson的反序列化机制,依赖于@JsonValue注解

6. 替代方案:@JsonCreator注解

除了使用@JsonValue,您还可以使用@JsonCreator注解提供自定义的反序列化方法:

// @JsonCreator注解指定自定义反序列化方法,静态工厂函数,根据code属性值返回对应的枚举对象实例
// 参数类型需与Json数据中code属性的数据类型一致,或者声明为Object类型,否则无法将json数据与参数绑定
// 参数名可直接使用Json数据中的属性名,否则需使用@JsonProperty注解指定属性名。
@JsonCreator
public static ItemType forValue(@JsonProperty("code") String c) {
    for (ItemType type : ItemType.values()) {
        if (type.getCode().equals(Integer.valueOf(c))) {
            return type;
        }
    }
    throw new IllegalArgumentException("code: " + c + "非法");
}

优点:灵活,可进行额外的处理流程

缺点

  • 繁琐,需要为每个枚举类单独实现
  • 需要注意参数的变量类型和变量名与JSON数据是否对应,否则无法触发;而@JsonValue注解时,JSON数据既可以是字符串也可以是数字

总结

  • HTTP请求参数转换:使用Converter接口,由Spring MVC的WebDataBinder处理
  • JSON反序列化:使用Jackson的机制,依赖于@JsonValue@JsonCreator注解,不仅是请求体中的JSON数据反序列化,任何时候涉及到JSON数据反序列化,只要使用的是Spring Boot默认的ObejctMapper或配置了相同Jackson设置的ObejctMapper,相关注解都会生效。
  • 两者是独立的机制,解决不同场景下的类型转换问题
  • 为了完整支持两种场景,需要同时提供Converter和适当的Jackson注解

到此这篇关于Spring Boot中HTTP请求参数转换和请求体JSON反序列化的区别的文章就介绍到这了,更多相关Java线程池内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • IDEA设置maven修改settings.xml配置文件无法加载仓库的解决方案

    IDEA设置maven修改settings.xml配置文件无法加载仓库的解决方案

    这篇文章主要介绍了IDEA设置maven修改settings.xml配置文件无法加载仓库的解决方案,帮助大家更好的利用IDEA进行JAVA的开发学习,感兴趣的朋友可以了解下
    2021-01-01
  • 工厂方法在Spring框架中的运用

    工厂方法在Spring框架中的运用

    这篇文章介绍了工厂方法在Spring框架中的运用,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-10-10
  • Java中的动态代理使用

    Java中的动态代理使用

    这篇文章主要介绍了Java中的动态代理使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • Java集合框架实战HashMap与HashSet的使用案例

    Java集合框架实战HashMap与HashSet的使用案例

    本文通过两个案例详细介绍了HashMap和HashSet在Java中的应用,通过这些案例,我们学习了如何选择合适的集合类型、重写equals和hashCode方法、利用泛型和并发集合等最佳实践,感兴趣的朋友跟随小编一起看看吧
    2025-11-11
  • SpringBoot多模块打包部署Docker的项目实战

    SpringBoot多模块打包部署Docker的项目实战

    本文通过介绍最常见的Maven管理的Spring Boot项目多模块打包部署Docker来介绍一下项目部署过程中操作流程和几个需要注意的点,具有一定的参加价值,感兴趣的可以了解一下
    2023-08-08
  • Java锁升级的实现过程

    Java锁升级的实现过程

    这篇文章主要介绍了Java锁升级的实现过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • spring boot异步(Async)任务调度实现方法

    spring boot异步(Async)任务调度实现方法

    在没有使用spring boot之前,我们的做法是在配置文件中定义一个任务池,然后将@Async注解的任务丢到任务池中去执行,那么在spring boot中,怎么来实现异步任务的调用了,下面通过本文给大家讲解,需要的朋友参考下
    2018-02-02
  • Java Swing JCheckBox复选框的实现方法

    Java Swing JCheckBox复选框的实现方法

    这篇文章主要介绍了Java Swing JCheckBox复选框的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • springCloud gateWay 统一鉴权的实现代码

    springCloud gateWay 统一鉴权的实现代码

    这篇文章主要介绍了springCloud gateWay 统一鉴权的实现代码,统一鉴权包括鉴权逻辑和代码实现,本文给大家介绍的非常详细,需要的朋友可以参考下
    2022-02-02
  • springboot之配置双kafka全过程

    springboot之配置双kafka全过程

    这篇文章主要介绍了springboot之配置双kafka全过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04

最新评论