spring 自定义类型转换-ConverterRegistry
1背景介绍
一个应用工程里面,一遍会涉及到很多的模型转换,如DTO模型转DO模型,DO模型转DTO, 或者Request转DTO模型,总的来说,维护起来还是相对比较复杂。每涉及一个转换都需要重新写对应类的get或者set方法,并且这些方法散落在不同的模块里面,非常不方便管理。 下面介绍 转换器设计模式来解决上面这个问题。
在这篇文章中,会介绍 Converter Design Pattern。由于Java8 功能不仅提供了相应类型之间的通用双向转换方式,而且还提供了转换相同类型对象集合的常用方法,从而将样板代码减少到绝对最小值。
2Converter接口
/*** A converter converts a source object of type {@code S} to a target of type {@code T}.** <p>Implementations of this interface are thread-safe and can be shared.** <p>Implementations may additionally implement {@link ConditionalConverter}.** @author Keith Donald* @since 3.0* @param <S> the source type* @param <T> the target type*/
public interface Converter<S, T> {/*** Convert the source object of type {@code S} to target type {@code T}.* @param source the source object to convert, which must be an instance of {@code S} (never {@code null})* @return the converted object, which must be an instance of {@code T} (potentially {@code null})* @throws IllegalArgumentException if the source cannot be converted to the desired target type*/T convert(S source);}
该接口为函数式接口,因此可以用lamda方式实现转换。这种简单方式本篇不再介绍。可以参考这篇文章(https://wenku.baidu.com/view/d64211654731b90d6c85ec3a87c24028915f859c.html?wkts=1693142368160&bdQuery=Converter+java),本篇这样介绍设计模式相关内容。
3MyConverter接口
public interface MyConverter<S, T> extends Converter<S, T> {/*** 将DTO对象转换为领域对象* @param dtoData 原模型* @return 目标模型*/T convert(S dtoData);/*** 转换领域模型列表* @param dtoDatas 原模型列表* @return 目标模型列表*/List<T> convert(List<S> dtoDatas);
}
在使用上,一般先基于开始接口定位自己业务接口,这里满足了,单数据,或者列表数据。
4TemplateConverter
然后写自己模版类,后面的具体模型转换器基于这个模版实现
public abstract class TemplateConverter<S, T> implements MyConverter<S, T> {/** 实体sourceClass */protected final Class<S> sourceClass;/** targetClass */protected final Class<T> targetClass;/** 构造方法,约束泛型类型 */public TemplateConverter() {try {ParameterizedType parameterizedType = ((ParameterizedType) getClass().getGenericSuperclass());sourceClass = (Class<S>) parameterizedType.getActualTypeArguments()[0];targetClass = (Class<T>) parameterizedType.getActualTypeArguments()[1];} catch (Exception e) {throw new RuntimeException("no definition");}}/*** 源模型 转 目标模型* @param sourceModel 源模型* @return 目标模*/public T convert(S sourceModel) {// 空请求默认返回空if (sourceModel == null) {return null;}T domainModel;try {domainModel = targetClass.newInstance();// 执行转换excuteConvert(sourceModel, domainModel);} catch (Exception e) {StringBuilder bf = new StringBuilder("conversion error,source:");bf.append(sourceClass.getSimpleName()).append(",target:").append(targetClass.getSimpleName());throw new RuntimeException("convert RuntimeException");}return domainModel;}/*** 源模型(List)转换为目标模型(List)** @param sourceModels 源模型列表* @return 目标模型列表*/public List<T> convert(List<S> sourceModels) {// 空请求,默认返回空if (CollectionUtils.isEmpty(sourceModels)) {return null;}List<T> result = new ArrayList<>();for (S dtoData : sourceModels) {T resData = convert(dtoData);if (resData != null) {result.add(resData);}}return result;}/*** 执行具体的模型转换* @param sourceModel 源模型* @param targetModel 目标模型*/public abstract void excuteConvert(S sourceModel, T targetModel);}
5 具体模型转换-StudentModeConverter
具体到模型转换器,这里还可以有很多个,这里以StudentModeConverter为例,只涉及到DTO模型转 DO模型
public class StudentModeConverter extendsTemplateConverter<StudentModeDTO, StudentModeDO> {@Overridepublic void doConvert(StudentModeDTO sourceModel,StudentModeDO targetModel) {targetModel.setName(sourceModel.getName());// 下面省略很多get/settargetModel.setAge(sourceModel.getAge());}
}
后面还可以写具体的转换器。基于之前模版。
6 通用转换服务-CommonConversionServiceImpl
public class CommonConversionServiceImpl extends GenericConversionService{/** constructor */public CommonConversionServiceImpl() {// 添加转换器addDefaultConverters(this);}/*** 添加转换器* @param converterRegistry*/public void addDefaultConverters(ConverterRegistry converterRegistry) {// 添加通用集合转换器converterRegistry.addConverter(new StudentModeConverter1());converterRegistry.addConverter(new StudentModeConverter2());// ....converterRegistry.addConverter(new StudentModeConverter3());}
7 封装工具-CommonConvertUtil
public class CommonConvertUtil {/*** 通用转换服务*/private static CommonConversionService conversionService = new CommonConversionServiceImpl();/*** 类型转换* @param source* @param targetType* @param <T>* @return*/public static <T> T convert(Object source, Class<T> targetType) {return conversionService.convert(source, targetType);}
8 使用工具
使用场景:
studentModeDTO 转 StudentModeDO
StudentModeDTO studentModeDTO = new StudentModeDTO();
StudentModeDO studentModeDO= CommonConvertUtil.convert(studentModeDTO, StudentModeDO.class);
通过调用该封装好的工具即可。
以后只需要在 CommonConversionServiceImpl 加具体转换器即可使用在CommonConvertUtil 中使用 。
当时用于 CommonConversionServiceImpl 是需要默认初始化,所有可以声明为工厂bean
public class CommonConversionServiceFactoryBean implements FactoryBean<CommonConversionService>,InitializingBean {/** 转换器定义 */private Set<?> converters;/** 通用转换服务 */private CommonConversionService conversionService;/*** 注入转换器* @param converters*/public void setConverters(Set<?> converters) {this.converters = converters;}@Overridepublic CommonConversionService getObject() throws Exception {return this.conversionService;}@Overridepublic Class<?> getObjectType() {return GenericConversionService.class;}@Overridepublic boolean isSingleton() {return false;}/*** 创建转换服务* @return*/protected CommonConversionService createConversionService() {return new CommonConversionServiceImpl();}@Overridepublic void afterPropertiesSet() throws Exception {this.conversionService = createConversionService();ConversionServiceFactory.registerConverters(this.converters, this.conversionService);}
}
相关文章:

spring 自定义类型转换-ConverterRegistry
1背景介绍 一个应用工程里面,一遍会涉及到很多的模型转换,如DTO模型转DO模型,DO模型转DTO, 或者Request转DTO模型,总的来说,维护起来还是相对比较复杂。每涉及一个转换都需要重新写对应类的get或者set方法,…...

springboot实现发送短信验证码
目录 一、选择并注册短信服务提供商: 二、添加依赖: 三、配置短信服务信息: 四、编写发送短信验证码的方法: 五、调用发送短信验证码的方法: 一、选择并注册短信服务提供商: 1、选择一个可靠的短信服…...

2024王道408数据结构P144 T18
2024王道408数据结构P144 T18 思考过程 首先还是先看题目的意思,让我们在中序线索二叉树里查找指定结点在后序的前驱结点,这题有一点难至少对我来说…我讲的不清楚理解一下我做的也有点糊涂。在创建结构体时多两个变量ltag和rtag,当ltag0时…...

在windows下安装配置skywalking
1.下载地址 Downloads | Apache SkyWalkinghttp://skywalking.apache.org/downloads/ 2.文件目录说明 将文件解压后,可看到agent和bin目录: Agent:作为探针,安装在服务器端,进行数据采集和上报。 Config:…...

关于大模型参数微调的不同方法
Adapter Tuning 适配器模块(Adapter Moudle)可以生成一个紧凑且可扩展的模型;每个任务只需要添加少量可训练参数,并且可以在不重新访问之前任务的情况下添加新任务。原始网络的参数保持不变,实现了高度的参数共享 Pa…...

方法的引用第一版(method reference)
1、体验方法引用 在使用Lambda表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿参数做操作那么考虑一种情况:如果我们在Lanbda中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再重复逻辑呢&#…...

Android DataBinding 基础入门(学习记录)
目录 一、DataBinding简介二、findViewById 和 DataBinding 原理及优缺点1. findViewById的优缺点2. DataBinding的优缺点 三、Android mvvm 之 databinding 原理1. 简介和三个主要的实体DataViewViewDataBinding 2.三个功能2.1. rebind 行为2.2 observe data 行为2.3 observe …...

spring 错误百科
一、使用Spring出错根源 1、隐式规则的存在 你可能忽略了 Sping Boot 中 SpringBootApplication 是有一个默认的扫描包范围的。这就是一个隐私规则。如果你原本不知道,那么犯错概率还是很高的。类似的案例这里不再赘述。 2、默认配置不合理 3、追求奇技淫巧 4、…...

OpenCV基本操(IO操作,读取、显示、保存)
图像的IO操作,读取和保存方法 1.1 API cv.imread()参数: 要读取的图像 读取图像的方式: cv.IMREAD*COLOR:以彩色模式加载图像,任何图像的图像的透明度都将被忽略。这是默认参数 标志: 1 cv.IMREAD*GRAYSCALE :以…...

1.快速搭建Flask项目
一.Pear Admin Flask 官网文档:http://www.pearadmin.com/doc/index.html 1.1下载安装 # 下 载 git clone https://gitee.com/pear-admin/pear-admin-flask# 安 装 pip install -r requirements.txt1.2修改配置 applications下的config.py docker运行的修改dockerdata/conf…...

编程题四大算法思想(三)——贪心法:找零问题、背包问题、任务调度问题、活动选择问题、Prim算法
文章目录 贪心法找零问题(change-making problem)贪心算法要求基本思想适合求解问题的特征 背包问题0/1背包问题0/1背包问题——贪心法 分数背包问题 任务调度问题活动选择问题活动选择——贪心法最早结束时间优先——最优性证明 Prim算法 贪心法 我在当…...

core dump管理在linux中的前世今生
目录 一、什么是core dump? 二、coredump是怎么来的? 三、怎么限制coredump文件的产生? ulimit 半永久限制 永久限制 四、从源码分析如何对coredump文件的名字和路径管理 命名 管理 一些问题的答案 1、为什么新的ubuntu不能产生c…...

Springboot整合knife4j配置swagger教程-干货
开启swagger文档,直接上教程。 第一步:引入依赖 <!--swagger 依赖--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version></d…...

C++ 中的 Pimpl 惯用法
C 中的 Pimpl 惯用法 介绍 Pimpl(Pointer to Implementation)是一种常见的 C 设计模式,用于隐藏类的实现细节,从而减少编译依赖和提高编译速度。本文将通过一个较为复杂的例子,展示如何使用智能指针(如 s…...

【个人博客系统网站】统一处理 · 拦截器
【JavaEE】进阶 个人博客系统(2) 文章目录 【JavaEE】进阶 个人博客系统(2)1. 统一返回格式处理1.1 统一返回类common.CommonResult1.2 统一返回处理器component.ResponseAdvice 2. 统一异常处理3. 拦截器实现3.1 全局变量SESSI…...

深入探索PHP编程:文件操作与输入/输出(I/O)
深入探索PHP编程:文件操作与输入/输出(I/O) 在PHP编程中,文件操作和输入/输出(I/O)是不可或缺的关键部分。无论是读取、写入文件,还是处理上传的文件,这些操作都是Web开发的重要组成…...

基于jeecg-boot的flowable流程自定义业务驳回到发起人的一种处理方式
有些粉丝,希望对自定义业务中,驳回到发起人进行处理,比如可以重新进行发起流程,下面就给出一种方式,当然不一定是最好的方式,只是提供一种参考而已,以后可以考虑动态根据流程状态或节点信息进行…...

【大数据知识】大数据平台和数据中台的定义、区别以及联系
数据行业有太多数据名词,例如大数据、大数据平台、数据中台、数据仓库等等。但大家很容易混淆,也很容易产生疑问,今天我们就来简单聊聊大数据平台和数据中台的定义、区别以及联系。 大数据平台和数据中台的定义 大数据平台:一个…...

华为OD:IPv4地址转换成整数
题目描述: 存在一种虚拟IPv4地址,由4小节组成,每节的范围为0-255,以#号间隔,虚拟IPv4地址可以转换为一个32位的整数,例如: 128#0#255#255,转换为32位整数的结果为2147549183&#…...

2023.9 - java - 浅拷贝
与 js的浅拷贝不同: 在 JavaScript 中, Object.assign() 或 spread 运算符等方法可以实现浅拷贝,但只针对对象的第一层属性进行复制。如果一个对象只包含基本数据类型的属性,那么对浅拷贝出来的对象进行修改不会影响原始对象&…...

STM32f103入门(10)ADC模数转换器
ADC模数转换器 ADC简介AD单通道初始化代码编写第一步开启时钟第二步 RCCCLK分频 6分频 72M/612M第三步 配置GPIO 配置为AIN状态第四步,选择规则组的输入通道第五步 用结构体 初始化ADC第六步 对ADC进行校准编写获取电压函数初始化代码如下 Main函数编写 ADC简介 ADC…...

实训笔记8.28
实训笔记8.28 8.28笔记一、大数据计算场景主要分为两种1.1 离线计算场景1.2 实时计算场景 二、一般情况下大数据项目的开发流程2.1 数据采集存储阶段2.2 数据清洗预处理阶段2.3 数据统计分析阶段2.4 数据挖掘预测阶段2.5 数据迁移阶段2.6 数据可视化阶段 三、纯大数据离线计算项…...

机器学习笔记之最优化理论与方法(五)凸优化问题(上)
机器学习笔记之最优化理论与方法——凸优化问题[上] 引言凸优化问题的基本定义凸优化定义:示例 凸优化与非凸优化问题的区分局部最优解即全局最优解凸优化问题的最优性条件几种特殊凸问题的最优性条件无约束凸优化等式约束凸优化非负约束凸优化 引言 本节将介绍凸优…...

在Windows10上编译grpc工程,得到protoc.exe和grpc_cpp_plugin.exe
grpc是google于2015年发布的一款跨进程、跨语言、开源的RPC(远程过程调用)技术。使用C/S模式,在客户端、服务端共享一个protobuf二进制数据。在点对点通信、微服务、跨语言通信等领域应用很广,下面介绍grpc在windows10上编译,这里以编译grpc …...

一些测试知识
希望能起到帮助,博主主页: https://blog.csdn.net/qq_57785602/category_12023254.html?spm1001.2014.3001.5482 软件测试理论 测试的依据: 需求,规格说明,模型,用户需求等 什么是软件测试 描述一种来…...

Socket交互的基本流程?
TCP socket通信过程图 什么是网络编程,网络编程就是编写程序使两台连联网的计算机相互交换数据。怎么交换数据呢?操作系统提供了“套接字”(socket)的组件我们基于这个组件进行网络通信开发。tcp套接字工作流程都以“打电话”来生…...

css 分割线中间带文字
效果图 代码块(自适应) <div class"line"><span class"text">我是文字</span></div>.line{height:0;border-top:1px solid #000;text-align:center;}.text{position:relative;top:-14px;background-color:#…...

会不会激发对modern c++的新兴趣
可变参数好像很厉害的样子,会节省很多手写代码,让编译器自动帮我们生成代码 template<typename Fun, typename...Args> void invoke(Fun&& fun, Args&&...args) { fun(std::forward<Args>(args)...); } 任意函数包装器…...

Nginx服务器如何配合Java开发项目
Nginx服务器如何才能配合好相关的编程语言进行服务器搭建呢?下面我们就来看看有关的技术如何融合。希望大家有所收获。 在进行Nginx服务器建设的时候有很多语言的应用,其中Java 开发的web项目就是很常见的。下面我们就看看Nginx服务器如何才能与Java编程…...

【LeetCode-中等题】994. 腐烂的橘子
文章目录 题目方法一:bfs层序遍历 题目 该题值推荐用bfs,因为是一层一层的感染,而不是一条线走到底的那种,所以深度优先搜索不适合 方法一:bfs层序遍历 广度优先搜索,就是从起点出发,每次都尝…...