大龄后端转后厨...|

Vermeer

园龄:3年7个月粉丝:6关注:0

2022-03-20 01:08阅读: 198评论: 0推荐: 0

SpringMVC 之 自定义系列化(Get请求无效)

此方式仅仅对 @RequestBody 方式的请求生效,对 parame 方式传参并不生效(?key=value&key=value),比如 Get 请求

GET 请求参数配置请参考: https://www.cnblogs.com/chxlay/p/16028839.html
>>>>>>>>>>>>>  码云中有封装号的:
https://gitee.com/chxlay/iserver-common.git   <<<<<<<<<<<<<<<<<<<<<

Java8 时间自定义系列化 与 反系列化:

复制代码
public class Java8TimeModule extends SimpleModule {
    public Java8TimeModule() {
        super(PackageVersion.VERSION);
    // ======================= 时间序列化规则 ===============================
    // yyyy-MM-dd HH:mm:ss
        this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    // yyyy-MM-dd
        this.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
    // HH:mm:ss
        this.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
 
    // ======================= 时间反序列化规则 ==============================
    // yyyy-MM-dd HH:mm:ss
        this.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    // yyyy-MM-dd
        this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
    // HH:mm:ss
        this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
    }
}
复制代码

将自定义的系列化规则配置到服务中:(本文页底和自定义枚举系列化一起)


自定义枚举系列化:
1、抽象约束枚举接口:

复制代码
@JsonDeserialize(using = IServerEnumDeserializer.class)
public interface IServerEnum extends Serializable {

    /**
     * 获取枚举编码
     *
     * @return
     */
    int getCode();

    /**
     * 获取枚举名称
     *
     * @return
     */
    default String getName() {
        return this.name();
    }

    /**
     * 获取枚举名称
     *
     * @return
     */
    String name();

    /**
     * 根据枚举名称获取枚举对象
     *
     * @param clazz
     * @param name
     * @param <E>
     * @return
     */
    @SneakyThrows
    static <E extends Enum<E> & IServerEnum> E sourceOf(Class<E> clazz, String name) {
        Method valuesMethod = clazz.getMethod("values");
        E[] enumInstanceArr = (E[]) valuesMethod.invoke(null);
        for (E enumInstance : enumInstanceArr) {
            if (Objects.equals(enumInstance.name(), name)) {
                return enumInstance;
            }
        }
        throw ExceptionUtil.create(IRuntimeException.class, ErrorResult.PARAMETER_ERROR);
    }

    /**
     * 根据编码获取枚举对象
     *
     * @param clazz
     * @param code
     * @param <E>
     * @return
     */
    @SneakyThrows
    static <E extends Enum<E> & IServerEnum> E codeOf(Class<E> clazz, int code) {
        Method valuesMethod = clazz.getMethod("values");
        E[] enumInstanceArr = (E[]) valuesMethod.invoke(null);
        for (E enumInstance : enumInstanceArr) {
            if (code == enumInstance.getCode()) {
                return enumInstance;
            }
        }
        throw ExceptionUtil.create(IRuntimeException.class, ErrorResult.PARAMETER_ERROR);
    }

}
复制代码

 

具体枚举类:

复制代码
public enum SexEnum implements IServerEnum<String> {
    /**
     * 男性
     */
    MALE(1, "男"),
    /**
     * 女性
     */
    FEMALE(2, "女"),
    /**
     * 未知
     */
    UNKNOWN(3, "未知");
    /**
     * 枚举编码
     */
    @EnumValue
    private int code;
    /**
     * 枚举值
     */
    private String value;
}
复制代码

手动编写反系列化器(根据自己的业务需求自行编写逻辑)

复制代码
public class IServerEnumDeserializer extends JsonDeserializer<IServerEnum> {

    @Override
    public IServerEnum deserialize(JsonParser jp, DeserializationContext deserializationContext) throws IOException {
        JsonNode node = jp.getCodec().readTree(jp);
        String currentName = jp.currentName();
        Object currentValue = jp.getCurrentValue();
        @SuppressWarnings("rawtypes")
        Class enumClazz = BeanUtils.findPropertyType(currentName, currentValue.getClass());

        IServerEnum iEnum;
        if (node instanceof IntNode) {
            // 当客户端传值为枚举的 code 的值得时候
            iEnum = (IServerEnum) IServerEnum.codeOf(enumClazz, node.asInt());
        } else if (node instanceof TextNode) {
            // 当客户端传值为 枚举的 name 时候
            iEnum = (IServerEnum) IServerEnum.sourceOf(enumClazz, node.asText());
        } else {
            // 若传参的是枚举对象时, JsonNode 为 ObjectNode 类,枚举对象的数据放在一个 LinkedHashMap 中,只需要从 Map 中读取出 name 即可
            iEnum = (IServerEnum) IServerEnum.sourceOf(enumClazz, node.get("name").asText());
        }
        return iEnum;
    }
}
复制代码
复制代码
public class IServerEnumSerializer extends JsonSerializer<IServerEnum> {

    @Override
    public void serialize(IServerEnum iServerEnum, JsonGenerator generator, SerializerProvider provider) throws IOException {
        // 枚举的code 作为系列化
        int code = iServerEnum.getCode();
        generator.writeNumber(code);
    }
}
复制代码

将反系列化器注册:

复制代码
public class IEnumModule extends SimpleModule {

    public IEnumModule() {
        super(PackageVersion.VERSION);

        super
                // 自定义凡系列化
                .addSerializer(IServerEnum.class, new IServerEnumSerializer())
                // 自定义通用枚举类反系列化处理
                .addDeserializer(IServerEnum.class, new IServerEnumDeserializer());
    }
}
复制代码

 


转换器配置注册(注册方式二选一即可)

1、简单配置使用

复制代码
@Configuration
@ConditionalOnClass(ObjectMapper.class)
@AutoConfigureBefore(JacksonAutoConfiguration.class)
public class JacksonConfig {
    private static final String ASIA_SHANGHAI = "Asia/Shanghai";
    /**
     * 处理 @RequestBody 方式传参的自定义转换
     * java8 时间系列化/反系列化
     */
    @Bean
    @ConditionalOnMissingBean
    public Jackson2ObjectMapperBuilderCustomizer java8Customizer() {
        return (Jackson2ObjectMapperBuilder builder) -> {
            builder.locale(Locale.CHINA);
            builder.timeZone(TimeZone.getTimeZone(ASIA_SHANGHAI));
            builder.simpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
            builder.modules(new Java8TimeModule(), new IEnumModule());
        };
    }
}
复制代码

全配置:(有些类这里没有公示)

复制代码
@Configuration
@RequiredArgsConstructor
@ConditionalOnClass(ObjectMapper.class)
@AutoConfigureBefore(JacksonAutoConfiguration.class)
public class JacksonConfig {

    private static final String ASIA_SHANGHAI = "Asia/Shanghai";
    private final HttpServletRequest request;

    @Bean
    @Primary
    @ConditionalOnMissingBean
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder
                // 地区时区配置
                .locale(Locale.CHINA).timeZone(TimeZone.getTimeZone(ASIA_SHANGHAI))
                // 时间格式
                .simpleDateFormat(DatePattern.NORM_DATETIME_PATTERN)
                .createXmlMapper(false).build();
        objectMapper
                // Java8 时间系列化
                .registerModule(new Java8TimeModule())
                // 自定义枚举系列化
                .registerModule(new IEnumModule())
                // 人民币金额系列化、反系列化规则(元 <====> 分)
                .registerModule(new MoneyPennyModule(request))
                // 空的 Bean 不报错
                .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
                // 如果 json 中字段是 实体类中不存在的,不报错
                .configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
                // 如果存在位置属性,则忽略
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                // 允许 Json 中的 key 没有双引号
                .configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)
                // 允许 Json 中的 key 是 单引号的
                .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true)
                // 允许 整数 以 0 开头
                .configure(JsonReadFeature.ALLOW_NON_NUMERIC_NUMBERS.mappedFeature(), true)
                // 允许存在 回车 换行符号
                .configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true)
        // 忽略 NULL 值
        // .setSerializationInclusion(JsonInclude.Include.NON_NULL)
        ;
        return objectMapper;
    }

}
复制代码

 

posted @   Vermeer  阅读(198)  评论(0编辑  收藏  举报

喜欢请打赏

扫描二维码打赏

了解更多

点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起