当前位置: 首页 > news >正文

【自定义序列化器】⭐️通过继承JsonSerializer和实现WebMvcConfigurer类完成自定义序列化

目录

前言       

解决方案

具体实现

一、自定义序列化器

二、两种方式指定作用域

        1、注解    @JsonSerialize()

        2、实现自定义全局配置 WebMvcConfigurer

三、拓展 WebMvcConfigurer接口

章末


前言       

        小伙伴们大家好,上次做了自定义对象属性拷贝,解决了重构中尽量不要修改原有逻辑的问题,将String类型的字段转换成Date或者LocalDateTime类型。

【对象属性拷贝】⭐️按照需要转换的类型反射设置拷贝后对象的属性-CSDN博客

但是转换完成后还需要修改Date类型的值为带上时区的,比如

”2024-02-05 14:46:26“  》》》》"2024-02-05 14:46:26 GMT+08:00"

        这种借助序列化器实现,可以在很大程度上减少对原有代码的重构

解决方案

        自定义一个针对于LocalDateTime字段或者Date类型的序列化器,有两种实现方式,一是使用注解的方式标注哪些实体类中的时间属性需要序列化,二是全局序列化器,在处理返回结果前统一处理

具体实现

一、自定义序列化器
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lombok.extern.slf4j.Slf4j;import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;@Slf4j
public class DiyLocalDatetimeSerializer extends JsonSerializer<LocalDateTime> {public static final String DEFAULT_DATE_TIME_FORMAT_WITH_TIME_ZONE = "yyyy-MM-dd HH:mm:ss OOOO";private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT_WITH_TIME_ZONE);//创建一个DateTimeFormatter实例,使用了DEFAULT_DATE_TIME_FORMAT_WITH_TIME_ZONE常量指定的模式。DateTimeFormatter负责根据指定的模式将ZonedDateTime对象格式化为字符串。/*** * @param localDateTime* @param jsonGenerator* @param serializerProvider* @throws IOException*/@Overridepublic void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {ZoneId zoneId = ZoneId.systemDefault();//获取系统默认的时区ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);//转换为具有默认时区的ZonedDateTime对象String format = formatter.format(zonedDateTime);//格式化ZonedDateTime对象jsonGenerator.writeString(format);//将格式化后的字符串写入JSON}
}
二、两种方式指定作用域
        1、注解    @JsonSerialize()

        在指定类的属性上面添加该注解,比如需要将user类的time属性加上时区

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.hb.demo.config.DiyLocalDatetimeSerializer;
import lombok.Data;import java.time.LocalDateTime;@Data
public class User {private Integer id;private String name;private  Integer age;private String address;private String phone;private String sex;@JsonSerialize(using = DiyLocalDatetimeSerializer.class)private LocalDateTime time;
}

        apipost调用接口测试下,测试接口就是简单的查询数据库表中的数据,先来看下未加注解的返回值

        2、实现自定义全局配置 WebMvcConfigurer

        注解实现的方式虽然简单,但是架不住每个接口都要改,对应的每个接口的实体类也要改,通过实现WebMvcConfigurer接口,重写了WebMvcConfigurer 接口中的消息转换方法来处理 HTTP 消息的转换。

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.hb.demo.config.interceptor.DiyInterceptor;
import org.springframework.context.annotation.Bean;
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.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {converters.add(diyConvert());}/*** 自定义消息转换器* @Bean 标记该方法返回一个由Spring管理的Bean对象* @return*/@Beanpublic MappingJackson2HttpMessageConverter diyConvert(){MappingJackson2HttpMessageConverter mappingJackson2CborHttpMessageConverter = new MappingJackson2HttpMessageConverter();ObjectMapper objectMapper = new ObjectMapper();//用于JSON 数据的序列化和反序列化SimpleModule simpleModule = new SimpleModule();simpleModule.addSerializer(LocalDateTime.class,new DiyLocalDatetimeSerializer());//添加针对 LocalDateTime 类型的自定义序列化器 DiyLocalDatetimeSerializerobjectMapper.registerModule(simpleModule);objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);//设置JSON 数据中包含目标对象中不存在的属性时,直接忽略这些属性而不是中断反序列化过程。mappingJackson2CborHttpMessageConverter.setObjectMapper(objectMapper);return mappingJackson2CborHttpMessageConverter;}
}

        测试下,先将之前的@JsonSerialize注解去掉,结果如下,通过这种方式可以实现接口传输数据过程中所有指定的类型自动处理

三、拓展 WebMvcConfigurer接口

        该接口定义了多个方法,可以自行注册拦截器、资源处理器、视图解析器以及自定义参数解析器等。看下可以重写哪些方法,常用的比如拦截器,资源处理器. . . 使用的时候可以自定义各种全局处理器

后续

        使用全局处理后,如果有不需要处理的字段,可以通过加注解的方式标识不需要处理

具体实现

        1.新增实体类SerializerField  用于获取当前序列化类信息
import io.micrometer.core.instrument.util.StringUtils;
import lombok.Data;
import lombok.experimental.Accessors;import java.util.Objects;/*** 当前序列化的类信息*/
@Data
@Accessors(chain = true)
public class SerializerField {private String fieldName;private Class<?> currentClass;public boolean effective() {return Objects.nonNull(currentClass) && StringUtils.isNotEmpty(fieldName);}@Overridepublic String toString() {if (effective()) {return currentClass.getName() + " " + fieldName;}return "";}}
        2.新增注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreTimeZoneHanding {
}
        3.修改自定义序列化器代码
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.hb.demo.aop.IgnoreTimeZoneHanding;
import com.hb.demo.enity.SerializerField;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;import java.io.IOException;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;@Slf4j
public class DiyLocalDatetimeSerializer extends JsonSerializer<LocalDateTime> {public static final String DEFAULT_DATE_TIME_FORMAT_WITH_TIME_ZONE = "yyyy-MM-dd HH:mm:ss OOOO";private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT_WITH_TIME_ZONE);private static final DateTimeFormatter formatterNew = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");/**** @param localDateTime* @param jsonGenerator* @param serializerProvider* @throws IOException*/@Overridepublic void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {SerializerField serializerField = serializerField(jsonGenerator);//检查是否需要忽略时区处理if (isIgnore(serializerField)) {log.info("ignore timeZone handing:{},{}",serializerField,localDateTime);String format = formatterNew.format(localDateTime);//使用指定的formatterNew格式化localDateTime对象,并将结果写入jsonGeneratorjsonGenerator.writeString(format);return;}ZoneId zoneId = ZoneId.systemDefault();ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);String format = formatter.format(zonedDateTime);jsonGenerator.writeString(format);}//在自定义的序列化器中获取关于当前正在序列化的字段的上下文信息public static SerializerField serializerField(JsonGenerator gen) {JsonStreamContext outputContext = gen.getOutputContext();//从gen(JsonGenerator对象)获取当前的输出上下文if (Objects.isNull(outputContext)) {return null;}Object currentValue = outputContext.getCurrentValue();//获取当前输出上下文中的当前值if (Objects.isNull(currentValue)) {return null;}//构造了一个SerializerField实例,使用当前值的类和当前字段名称进行初始化return new SerializerField().setCurrentClass(currentValue.getClass()).setFieldName(outputContext.getCurrentName());}//在自定义的序列化器中判断当前序列化字段是否被标记为忽略时区信息public static boolean isIgnore(SerializerField serializerField){if(Objects.isNull(serializerField)){return false;}if(!serializerField.effective()){return false;}Field field = ReflectionUtils.findField(serializerField.getCurrentClass(), serializerField.getFieldName());if(Objects.isNull(field)){return false;}//判断是否存在IgnoreTimeZoneHanding注解IgnoreTimeZoneHanding annotation = field.getAnnotation(IgnoreTimeZoneHanding.class);return !Objects.isNull(annotation);}}
        4.测试注解生没生效
    @IgnoreTimeZoneHandingprivate LocalDateTime time;

        如图,加了注解的属性不会带上时区属性

章末

        

相关文章:

【自定义序列化器】⭐️通过继承JsonSerializer和实现WebMvcConfigurer类完成自定义序列化

目录 前言 解决方案 具体实现 一、自定义序列化器 二、两种方式指定作用域 1、注解 JsonSerialize() 2、实现自定义全局配置 WebMvcConfigurer 三、拓展 WebMvcConfigurer接口 章末 前言 小伙伴们大家好&#xff0c;上次做了自定义对象属性拷贝&#x…...

闲聊电脑(5)装个 Windows(一)

​夜深人静&#xff0c;万籁俱寂&#xff0c;老郭趴在电脑桌上打盹&#xff0c;桌子上的小黄鸭和桌子旁的冰箱又开始窃窃私语…… 小黄鸭&#xff1a;冰箱大哥&#xff0c;上次说到硬盘分区和格式化&#xff0c;弄完之后&#xff0c;就该装系统了吧&#xff1f; 冰箱&#x…...

力扣(leetcode)第414题第三大的数(Python)

414.第三大的数 题目链接&#xff1a;414.第三大的数 给你一个非空数组&#xff0c;返回此数组中 第三大的数 。如果不存在&#xff0c;则返回数组中最大的数。 示例 1&#xff1a; 输入&#xff1a;[3, 2, 1] 输出&#xff1a;1 解释&#xff1a;第三大的数是 1 。 示例 2&a…...

使用wda框架实现IOS自动化测试详解

目录 1、weditor元素定位工具 1.1、weditor的安装和使用 2、wda iOS自动化框架 2.1、wda概述 2.2、wda安装 2.3、wda的使用 2.3.1、全局配置 2.3.2、创建客户端 2.3.3、APP相关操作 1、启动APP 2、关闭APP 3、获取APP状态信息 4、获取当前APP的运行信息 2.3.4、设…...

LeetCode--代码详解 2.两数相加

2.两数相加 题目 难度&#xff1a;中等 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数…...

【Django开发】美多商城项目第3篇:用户注册和图片验证码开发(附代码,文档已分享)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论django商城项目开发相关知识。本项目利用Django框架开发一套前后端不分离的商城项目&#xff08;4.0版本&#xff09;含代码和文档。功能包括前后端不分离&#xff0c;方便SEO。采用Django Jinja2模板引擎 Vue.js实现…...

代码随想录算法训练营DAY10 | 栈与队列 (1)

理论基础及Java实现参考文章&#xff1a;栈和队列 一、LeetCode 232 用栈实现队列 题目链接&#xff1a;232.用栈实现队列https://leetcode.cn/problems/implement-queue-using-stacks/ 思路&#xff1a;使用两个栈stack1、stack2实现队列&#xff1b;stack1用来存储入队元素&…...

flinkjar开发 自定义函数

编写自定义加密函数&#xff0c;继承ScalarFunction类&#xff0c;实现eval方法&#xff0c;参数个数类型和返回值根据业务来自定义。 import org.apache.flink.table.functions.ScalarFunction; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax…...

Golang 学习(一)基础知识

面向对象 Golang 也支持面向对象编程(OOP)&#xff0c;但是和传统的面向对象编程有区别&#xff0c;并不是纯粹的面向对象语言。 Golang 没有类(class)&#xff0c;Go 语言的结构体(struct)和其它编程语言的类(class)有同等的地位&#xff0c;Golang 是基于 struct 来实现 OOP…...

C++学习:string的了解

1.string的介绍 #include<string> 对于字符串的操作 自动处理内存的分配和释放 2.string的声明与初始化 1.std::string str1;空的 2.string str2 "afhsihsa" 3.string str3 str2 4.string str3 str2.substr(0,5) .substr(位置&#xff0c;长度) 5.c…...

Webpack源码浅析

webpack启动方式 webpack有两种启动方式&#xff1a; 通过webpack-cli脚手架来启动&#xff0c;即可以在Terminal终端直接运行&#xff1b; webpack ./debug/index.js --config ./debug/webpack.config.js通过require(webpack)引入包的方式执行&#xff1b;其实第一种方式最终…...

Hadoop:HDFS学习巩固——基础习题及编程实战

一 HDFS 选择题 1.对HDFS通信协议的理解错误的是&#xff1f; A.客户端与数据节点的交互是通过RPC&#xff08;Remote Procedure Call&#xff09;来实现的 B.HDFS通信协议都是构建在IoT协议基础之上的 C.名称节点和数据节点之间则使用数据节点协议进行交互 D.客户端通过一…...

SASS 官方文档速通

前言&#xff1a;参考 Sass 中文网。 一. 特色功能 Sass 是一款强化 CSS 的辅助工具&#xff0c;在 CSS 语法的基础上增加了变量、嵌套、混合、导入等高级功能。有助于组织管理样式文件&#xff0c;更高效地开发项目。 二. 语法格式 .scss 拓展名&#xff1a;在 CSS3 语法的基…...

《动手学深度学习(PyTorch版)》笔记7.4

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过&…...

关于自动驾驶概念的学习和一些理解

文章目录 对于自动驾驶的认识自动驾驶技术的优势自动驾驶的技术要求自动驾驶技术的挑战自动驾驶技术的潜在影响总结 对于自动驾驶的认识 自动驾驶是指车辆在没有人类驾驶员控制的情况下进行行驶的技术。随着人工智能的快速发展&#xff0c;自动驾驶技术已经成为将来交通行业的…...

C++ dfs搜索枚举(四十八)【第八篇】

曾经我们讲过枚举算法&#xff0c;那假设我们把枚举算法应用到搜索里呢&#xff1f; 1.搜索枚举 以前我们在进行枚举的时候是用了多层循环嵌套&#xff0c;但是当枚举的变量过多或者是输入的数量的时候就很难利用循环完成枚举了&#xff0c;不过我们可以尝试利用搜索进行枚举。…...

【优先级队列(大顶堆 小顶堆)】【遍历哈希表键值对】Leetcode 347 前K个高频元素

【优先级队列&#xff08;大顶堆 小顶堆&#xff09;】【排序】Leetcode 347 前K个高频元素 1.不同排序法归纳2.大顶堆和小顶堆3.PriorityQueue操作4.PriorityQueue的升序&#xff08;默认&#xff09;与降序5.问题解决&#xff1a;找前K个最大的元素 &#xff1a;踢走最小的&…...

Java设计模式-模板方法模式(14)

行为型模式 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对…...

【C++ 二维前缀和】约会

题目描述 从前&#xff0c;小兔发现了一个神秘的花园。 花园是一个 n 行 m 列的矩阵&#xff0c;第 i 行 j 列的花的美丽度为 ai,j&#xff0c;一个合法的约会场所为任意一个正方形子矩阵&#xff0c;定义子矩阵的浪漫度为这个子矩阵的两条对角线上的花的美丽度之和。 现在小兔…...

基于Springboot的社区疫情防控平台

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是墨韵&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML墨韵 学如逆水行舟&#xff0c;不进则退。学习如赶路&#xff0c;不能慢一步。 一、项目简介 以往的社区疫情防控管理…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...