当前位置: 首页 > 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;不能慢一步。 一、项目简介 以往的社区疫情防控管理…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象&#xff1a; android studio报错&#xff1a; [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决&#xff1a; 不要动CMakeLists.…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文通过代码驱动的方式&#xff0c;系统讲解PyTorch核心概念和实战技巧&#xff0c;涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...