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

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背景介绍 一个应用工程里面&#xff0c;一遍会涉及到很多的模型转换&#xff0c;如DTO模型转DO模型&#xff0c;DO模型转DTO, 或者Request转DTO模型&#xff0c;总的来说&#xff0c;维护起来还是相对比较复杂。每涉及一个转换都需要重新写对应类的get或者set方法&#xff0c…...

springboot实现发送短信验证码

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

2024王道408数据结构P144 T18

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

在windows下安装配置skywalking

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

关于大模型参数微调的不同方法

Adapter Tuning 适配器模块&#xff08;Adapter Moudle&#xff09;可以生成一个紧凑且可扩展的模型&#xff1b;每个任务只需要添加少量可训练参数&#xff0c;并且可以在不重新访问之前任务的情况下添加新任务。原始网络的参数保持不变&#xff0c;实现了高度的参数共享 Pa…...

方法的引用第一版(method reference)

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

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 是有一个默认的扫描包范围的。这就是一个隐私规则。如果你原本不知道&#xff0c;那么犯错概率还是很高的。类似的案例这里不再赘述。 2、默认配置不合理 3、追求奇技淫巧 4、…...

OpenCV基本操(IO操作,读取、显示、保存)

图像的IO操作&#xff0c;读取和保存方法 1.1 API cv.imread()参数&#xff1a; 要读取的图像 读取图像的方式&#xff1a; cv.IMREAD*COLOR:以彩色模式加载图像&#xff0c;任何图像的图像的透明度都将被忽略。这是默认参数 标志&#xff1a; 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算法

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

core dump管理在linux中的前世今生

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

Springboot整合knife4j配置swagger教程-干货

开启swagger文档&#xff0c;直接上教程。 第一步:引入依赖 <!--swagger 依赖--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version></d…...

C++ 中的 Pimpl 惯用法

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

【个人博客系统网站】统一处理 · 拦截器

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

深入探索PHP编程:文件操作与输入/输出(I/O)

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

基于jeecg-boot的flowable流程自定义业务驳回到发起人的一种处理方式

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

【大数据知识】大数据平台和数据中台的定义、区别以及联系

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

华为OD:IPv4地址转换成整数

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

2023.9 - java - 浅拷贝

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

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

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

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

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

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

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...