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

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台

淘宝扭蛋机小程序系统的开发&#xff0c;旨在打造一个互动性强的购物平台&#xff0c;让用户在购物的同时&#xff0c;能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机&#xff0c;实现旋转、抽拉等动作&#xff0c;增…...

PydanticAI快速入门示例

参考链接&#xff1a;https://ai.pydantic.dev/#why-use-pydanticai 示例代码 from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider# 配置使用阿里云通义千问模型 model OpenAIMode…...