java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot HTTP请求参数转换

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

作者:青衫扶夕

本文主要介绍了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. 两种不同的转换场景

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

2. JSON反序列化流程详解

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

HTTP请求到达

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

3. @JsonValue注解的作用

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

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

当添加了@JsonValue注解后:

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

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

两者的工作层面不同:

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 + "非法");
}

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

缺点

总结

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

您可能感兴趣的文章:
阅读全文