整合SpringMVC之自定义JSON序列化器和反序列化器-枚举转换

注意正确的使用枚举

在这里插入图片描述
RPC框架大多数会采用JSON的格式进行数据传输
而JSON在反序列化的过程中,对于一个枚举类型,会尝试调用对应的枚举类的valueOf方法来获取到对应的枚举,如果从枚举类中找不到对应的枚举项的时候,就会抛出IllegalArgumentException异常

建议

  • 考虑版本兼容性问题
  • 接口返回时将枚举转换成String类型返回

常用json注解

@JsonIgnoreProperties:
此注解是类注解,作用是在json序列化时将Java bean中的某些属性忽略掉,序列化和反序列化都受影响。
@JsonIgnore:
此注解用于属性或者方法上(最好是属性上),作用和上面的@JsonIgnoreProperties一样。
@JsonFormat:
此注解用于属性或者方法上(最好是属性上),可以方便的把Date类型直接转化为我们想要的模式,比如@JsonFormat(pattern = “yyyy-MM-dd HH-mm-ss”)
@JsonSerialize:
此注解用于属性或者getter方法上,用于在序列化时嵌入我们自定义的序列化器,比如序列化一个double时在其后面限制两位小数点。
@JsonDeserializ:
此注解用于属性或者setter方法上,用于在反序列化时嵌入我们自定义的反序列化器,比如反序列化一个Date类型的时间字符串。
@JsonCreator与@JsonProperty:
该注解的作用就是指定反序列化时替代无参构造函数,构造方法的参数前面需要加上@JsonProperty注解。

json序列化-枚举转换

链接: 整合SpringMVC之自定义JSON序列化器和反序列化器.

package com.zm.constant;

/**
 * 通用枚举接口
 * @param <E>
 * @param <T>
 */
public interface BaseEnum<E extends Enum<?>, T> {

     T getValue();

     String getDisplayName();

     static <T extends Enum<T>> T valueOfEnum(Class<T> enumClass, Integer value) {
          if (value == null)
               throw  new IllegalArgumentException("DisplayedEnum value should not be null");
          if (enumClass.isAssignableFrom(BaseEnum.class))
               throw new IllegalArgumentException("illegal DisplayedEnum type");
          T[] enums = enumClass.getEnumConstants();
          for (T t: enums) {
               BaseEnum displayedEnum = (BaseEnum)t;
               if (displayedEnum.getValue().equals(value))
                    return (T) displayedEnum;
          }
          throw new IllegalArgumentException("cannot parse integer: " + value + " to " + enumClass.getName());
     }

}
package com.zm.constant;

public enum PayTypeEnum implements BaseEnum<PayTypeEnum,Integer>{
    /**
     *现金支付(1)
     */
    CASH(1, "现金支付"),
    /**
     * 扫码支付(2)
     */
    SCAN(2, "扫码支付"),
    /**
     * 会员余额支付(3)
     */
    VIP(3, "会员余额支付"),

    ;
    private Integer value;

    private String displayName;

    PayTypeEnum(Integer value,String displayName) {
        this.value=value;
        this.displayName=displayName;
    }

    public Integer getValue() {
        return value;
    }
    public void setValue(Integer value) {
        this.value = value;
    }
    public String getDisplayName() {
        return displayName;
    }
    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

}


package com.zm.constant;

import com.baomidou.mybatisplus.annotation.IEnum;

public enum PersonType implements IEnum<Integer>,BaseEnum {

    student(1, "学生"),

    teacher(2, "教师"),

    ;

    private Integer value;

    private String displayName;

    PersonType(Integer value, String displayName) {
        this.value = value;
        this.displayName = displayName;
    }

    public Integer getValue() {
        return value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }

    public String getDisplayName() {
        return displayName;
    }

    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

}

package com.zm.config;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.zm.constant.BaseEnum;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.jackson.JsonComponent;

import java.io.IOException;

@JsonComponent
public class Example {

    /**
     * 自定义序列化器 @RestController @ResponseBody
     */
    public static class Serializer extends JsonSerializer<BaseEnum> {
        /**
         * 序列化操作,继承JsonSerializer,重写Serialize函数 返回前端的值
         */
        @Override
        public void serialize(BaseEnum value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            gen.writeString(value.getDisplayName());
        }
    }
    /**
     * 自定义反序列化器 接收前端的值 @RequestBody
     */
    public static class Deserializer extends JsonDeserializer<BaseEnum> {

        @Override
        public BaseEnum deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException{
            JsonNode value = jsonParser.getCodec().readTree(jsonParser);
            // 获取到当前的json key 名称
            String currentName = jsonParser.currentName();
            System.out.println(currentName);
            // 获取到当前的json转换的对象
            Object currentValue = jsonParser.getCurrentValue();
            System.out.println(currentValue);
            // 获取当前对象key名称相同的属性类
            Class findPropertyType = BeanUtils.findPropertyType(currentName, currentValue.getClass());
            // 属性为枚举
            if (findPropertyType.isEnum()) {
                BaseEnum[] enumConstants = (BaseEnum[]) findPropertyType.getEnumConstants();
                for (BaseEnum e : enumConstants) {
                    if (e.getValue().equals(value.asInt())) {
                        return e;
                    }
                }
            }
            // 否则返回空
            return null;
        }
    }

}


package com.zm.entity;

import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.zm.config.Example;
import com.zm.constant.PayTypeEnum;
import com.zm.constant.PersonType;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;
import java.util.Date;

/**
 * <p>
 * 学生信息表
 * </p>
 *
 * @author zhoum
 * @since 2021-10-23
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("label")
public class LabelEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 名称
     */
    private String name;

    /**
     * 排序号
     */
    private Integer sort;

    /**
     * 乐观锁
     */
    @Version
    private Integer version;

    @TableLogic
    private Boolean deleted;

    /**
     * 支付类型
     */
    @JsonSerialize(using = Example.Serializer.class)
    @JsonDeserialize(using = Example.Deserializer.class)
    @TableField("pay_type")
    private PayTypeEnum payType;


    /**
     * 学生类型
     */
    @JsonSerialize(using = Example.Serializer.class)
    @JsonDeserialize(using = Example.Deserializer.class)
    @TableField("person_type")
    private PersonType personType;


    /**
     * 创建时间
     */
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    /**
     * 更新时间
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;


}

import com.zm.entity.LabelEntity;
import com.zm.mapper.LabelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
public class Test11 {

    @Autowired
    private LabelMapper labelMapper;

    @PostMapping("test11")
    public LabelEntity test2(@RequestBody LabelEntity LabelEntity){
        System.out.println(LabelEntity);
        LabelEntity labelEntitie = labelMapper.selectById("16");
        return labelEntitie;
    }

}

get请求枚举转换 实现Converter完成String到IEnum的转换

链接: SpringMVC中将前端请求参数转为枚举类并将响应信息中的枚举类转为对应的值.

package com.zm.config;

import com.zm.constant.BaseEnum;
import org.springframework.util.StringUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.stereotype.Component;

/**
 * 枚举转换工厂
 */
@Component
public class EnumConvertFactory implements ConverterFactory<String, BaseEnum> {

    @Override
    public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
        return new StringToIEnum<>(targetType);
    }

    private static class StringToIEnum<T extends BaseEnum> implements Converter<String, T> {

        private Class<T> targerType;

        public StringToIEnum(Class<T> targerType) {
            this.targerType = targerType;
        }

        @Override
        public T convert(String source) {
            if(StringUtils.isEmpty(source)){
                return null;
            }
            for (T t : targerType.getEnumConstants()) {
                if (source.equals(String.valueOf(t.getValue()))) {
                    return t;
                }
            }
            return null;
        }
    }
}

package com.zm.config;

import org.springframework.format.FormatterRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
    @Autowired
    private EnumConvertFactory enumConvertFactory;

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(enumConvertFactory);
    }
}

    @GetMapping("test11")
    public LabelEntity test1(LabelEntity LabelEntity){
        System.out.println("getPayType:"+LabelEntity.getPayType().getDisplayName());
        System.out.println("getPersonType:"+LabelEntity.getPersonType().getDisplayName());
        LabelEntity labelEntitie = labelMapper.selectById("16");
        return labelEntitie;
    }

long类型精度丢失

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.format.FormatterRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
    @Autowired
    private EnumConvertFactory enumConvertFactory;

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();

        ObjectMapper objectMapper = new ObjectMapper();
        /**
         * 序列换成json时,将所有的long变成string
         * 因为js中得数字类型不能包含所有的java long值
         */
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);

        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(0,jackson2HttpMessageConverter);
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(enumConvertFactory);
    }
}

日期格式化

链接: VO中@RequestBody接收Date参数注意.

参考链接

链接: 两个坑:long类型精度丢失,枚举类序列化和反序列化问题.
链接: 枚举与json的序列化/反序列化.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值