java常量数据用枚举封装(四)优雅对接前端-post请求体

前言

前文中已对get请求的query参数做了处理,使用的是ConverterFactory方式,当SpringMVC获取不到相应的Converter时,会寻找合适的ConverterFactory创建相应的Converter。
现在准备处理post请求的数据,本文只针对请求体为json格式的数据,使用的是SpringMVC下的jackson工具
枚举类的封装,在之前的文章能看到,本文就不做展示了

jackson-databind-2.13.3.jar

SpringMVC自带的,非本人添加的依赖。

思路

再之前,我们已经处理好单个类型的json化了,本文的目的在于编写通用的序列化和反序列化类,实现通用化
发现问题:Jackson未提供Factory相关内容,也未提供register方法。

考虑自行注册JsonDeserializer(失败)

尝试register

在开始处理问题之前,我测试了一下JsonDeserializer实例化规则:
在碰到一个类型所匹配的JsonDeserializer未实例化时,才会主动调用其无参构造器,而且只为一个类型创建一次JsonDeserializer
但是我们需要在创建JsonDeserializer的时候,给定classJsonDeserializer,使之初始化枚举类型数据
所以我想到去接管实例化Deserializer的过程。
但jackson没有提供如Converter的注册方式

尝试HttpMessageConverters

可以知道的是,SpringMVC是用HttpMessageConverters对请求体数据做转换的,而其中有一个MappingJackson2HttpMessageConverter,就是对json类型的body做处理的。
其中肯定有Deserializer的管理器。

在这里插入图片描述
可以看到当请求过来时,SpringMVC会找到想用的MessageConverter,对请求体做ConvertcontentTypejsonMessageConverter用的就是jackson进行处理的。
在这里插入图片描述
可以看到这个上下文对象,其中就有Deserializer数据的缓存。
但接下来我却发现,这个上下文好像没有提供管理Deserializer的方法。。。
也有可能在别的地方,但是考虑到上下文都没提供此方法,如果在其他地方就不好找了。
所以只能转换思路。

ContextualDeserializer(成功)

过程

在翻看DeserializationContext的源码时,我重点找了找以JsonDeserializer为入参的方法,发现其中有一个方法是这样的
在这里插入图片描述

Deserializer 创建上下文?

再点进另一个参数 JavaType ,可以看到其中的内容
在这里插入图片描述
按照理解,当一个DeserializerContextualDeserializer实例时,就会使用JavaType,调用其createContextual方法,重新实例化 Deserializer,并覆盖原Deserializer

先试一试:

在这里插入图片描述
发现确实能看到当前要封装的数据
同时,经过测试,发现第二次请求时,是不会再执行该方法的,所以可以放心使用。

编写ConstantEnumJsonDeserializer

既然可以使用该方法获取当前要转换的类型,也就表示可以在Deserializer初始化枚举类,这就解决了我们一开始的问题。

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.will.cn.constants.ConstantEnumIFace;

import java.io.IOException;

/**
 * @author jeff
 * @time 2023/5/1 22:19
 * 第一个T,表示这个Deserializer只为实现ConstantEnumIFace的类做反序列化
 * 第二个T,表示ConstantEnumIFace接口中的方法,返回的类型为T
 * 第三个T,表示这个Deserializer只为T类型数据做反序列化
 */
public class ConstantEnumJsonDeserializer<T extends ConstantEnumIFace<T>> extends JsonDeserializer<T > implements ContextualDeserializer {

    private T firstEnum;

    @Override
    public T deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
            throws IOException {
        final String source = jsonParser.getText();
        System.out.println("正在执行deserialize方法:"+source);
        int i = Integer.parseInt(source);
        return firstEnum.theEnum(i);
    }
    private void setFirstEnum(T firstEnum){
        this.firstEnum=firstEnum;
    }

    @Override
    public JsonDeserializer<T> createContextual(DeserializationContext deserializationContext, BeanProperty beanProperty) {
//        重新创建Deserializer
        ConstantEnumJsonDeserializer<T> tUserStatusEnumDeserializer = new ConstantEnumJsonDeserializer<>();
//        设置枚举类型数据
        JavaType type = beanProperty.getType();
        Class<T> rawClass = (Class<T>)type.getRawClass();
        System.out.println("正在创建JsonDeserializer,类型:"+rawClass.getName());
        firstEnum = rawClass.getEnumConstants()[0];
        tUserStatusEnumDeserializer.setFirstEnum(firstEnum);
        return tUserStatusEnumDeserializer;
    }
}

准备测试

然后再在之前抽取出来的ConstantEnumIFace接口上,加上此注解:

@JsonDeserialize(using = ConstantEnumJsonDeserializer.class)

表示碰到此类型时,使用ConstantEnumJsonDeserializer进行反序列化
而在真正实例化Deserializer时,则会传递真实数据类型
这样就达成了为每一个枚举类型创建ConstantEnumJsonDeserializer的目的。

测试

在这里插入图片描述
可以看到首次请求时,创建相应的ConstantEnumJsonDeserializer,并执行了deserialize方法

返回数据的JsonSerializer

JsonSerializer处理起来就不麻烦了,因为抽取了获取value的方法,所以只使用父类引用的getValue方法获取实际常量就好。

代码

/**
 * @author jeff
 * @since 2023/5/1 11:46
 */
public class ConstantEnumJsonSerializer extends JsonSerializer<ConstantEnumIFace> {

    @Override
    public void serialize(ConstantEnumIFace constantEnum, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        System.out.println("正在执行serialize方法:"+constantEnum+",value:"+constantEnum.getValue());
        jsonGenerator.writeNumber(constantEnum.getValue());
        System.out.println("json写入完成");

    }
}

总结

到这里,系统中使用枚举常量,对接前端数据的get,post请求数据的问题就处理完了,也把返回枚举常量的json数据给解决了。
接下来就是mybatis的相关内容了。

发现问题

如果前端发过来的请求数据里,对应的枚举数据为空的话,就不会走json转换,也就意味着,当前端发的请求没有枚举项的数据,我们就无法在json转换时去给默认值,因为它不参与转换了

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值