JAVA 使用反射比较对象属性的变化,记录修改日志。使用注解【策略模式】,来进行不同属性枚举值到中英文描述的切换,支持前端国际化。

1.首先定义一个接口,接口中有两个方法,分别是将属性转换成英文描述和中文描述。

其实就是将数据库中记录的 0  1 ,转换成后面的描述

这边定义了中文转换为默认方法,是因为有些属性不需要进行中文转换,或者该属性的枚举值中没有中文描述,你也可以不定义为默认方法

public interface ColumnConverter {/*** 英文值*/Object enConverter(Object value);/*** 中文值*/default Object cnConverter(Object value) {return enConverter(value);}
}

2.然后我们就可以定义一个类,该类中有很多静态类【不同的静态类用于不同属性的枚举值转换】,代码如下

@Slf4j
public class ColumnStrategy {private final Map<Class<? extends ColumnConverter>, ColumnConverter> converterMap = new HashMap<>();private ColumnStrategy() {}/*** 获取单例*/public static ColumnStrategy getInstance() {return INSTANCE.Instance;}public ColumnConverter getConverter(Class<? extends ColumnConverter> converterClass) {try {if (converterMap.containsKey(converterClass)) {return converterMap.get(converterClass);}Constructor<? extends ColumnConverter> constructor = converterClass.getConstructor();ColumnConverter columnConverter = constructor.newInstance();converterMap.put(converterClass, columnConverter);return columnConverter;} catch (Exception e) {log.error("构造转换器对象异常", e);return null;}}public ColumnConverter getDefaultConverter() {ColumnConverter defaultConverter = converterMap.get(AutoConverter.class);if (defaultConverter != null) {return defaultConverter;}AutoConverter autoConverter = new AutoConverter();converterMap.put(AutoConverter.class, autoConverter);return autoConverter;}private static class INSTANCE {private static final ColumnStrategy Instance = new ColumnStrategy();}/*** 默认转换器*/public static class AutoConverter implements ColumnConverter {@Overridepublic Object enConverter(Object value) {return value;}}public static class CarrierLevelType implements ColumnConverter {@Overridepublic Object enConverter(Object value) {return Optional.ofNullable(value).map(e -> CarrierTypeEnum.getByCode((int) e)).map(CarrierTypeEnum::getEnDesc).orElse(null);}@Overridepublic Object cnConverter(Object value) {return Optional.ofNullable(value).map(e -> CarrierTypeEnum.getByCode((int) e)).map(CarrierTypeEnum::getDescription).orElse(null);}}/*** 结果集转换器* 将<转换为&lt; (前端要求)*/public static class OperationDescResultConverter implements ColumnConverter {@Overridepublic Object enConverter(Object value) {return ((String) value).replaceAll(KeyboardSpecialCharConstants.LESS, KeyboardSpecialCharConstants.LESS_ESCAPING);}}public static class BusinessStatusType implements ColumnConverter {@Overridepublic Object enConverter(Object value) {return Optional.ofNullable(value).map(e -> BusinessStatusEnum.getByCode((int) e)).map(BusinessStatusEnum::getValue).orElse(null);}@Overridepublic Object cnConverter(Object value) {return Optional.ofNullable(value).map(e -> BusinessStatusEnum.getByCode((int) e)).map(BusinessStatusEnum::getCnValue).orElse(null);}}public static class PriceCheckType implements ColumnConverter {@Overridepublic Object enConverter(Object value) {return Optional.ofNullable(value).map(e -> PriceCheckModeEnum.getEnumByCode((int) e)).map(PriceCheckModeEnum::getModeDescEn).orElse(null);}@Overridepublic Object cnConverter(Object value) {return Optional.ofNullable(value).map(e -> PriceCheckModeEnum.getEnumByCode((int) e)).map(PriceCheckModeEnum::getModeDesc).orElse(null);}}public static class RealPriceCalType implements ColumnConverter {@Overridepublic Object enConverter(Object value) {return Optional.ofNullable(value).map(e -> RealPriceCalMethodEnum.getEnumByCode((int) e)).map(RealPriceCalMethodEnum::getMethodDescEn).orElse(null);}@Overridepublic Object cnConverter(Object value) {return Optional.ofNullable(value).map(e -> RealPriceCalMethodEnum.getEnumByCode((int) e)).map(RealPriceCalMethodEnum::getMethodDesc).orElse(null);}}}

3.然后我们定义一个注解,该注解用于我们实际进行比较的类中上,具体值是否需要进行枚举值转换,以及字段的中英文名称

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ColumnInfo {/*** 字段中文名*/String cnName() default "";/*** 字段英文名*/String enName() default "";/*** 值转换器(英文)* 适用于枚举型转换*/Class<? extends ColumnConverter> converter() default ColumnStrategy.AutoConverter.class;/*** 是否是用户数组*/boolean isUserList() default false;
}

4.然后我们就可以在实际需要进行比较的类上加上该注解【需要进行枚举值转换的属性,我们可以在属性上面的注解中加上converter ,然后注入对应的转换器即可】,示例代码如下

@Data
public class DTO {/*** 业务名称*/@ColumnInfo(cnName = "业务名称", enName = "Business name")private String bizCode;/*** 国别*/@ColumnInfo(cnName = "国家", enName = "Country")private String country;/*** 国别*/@ColumnInfo(cnName = "到期时间", enName = "Expire time")private String expireTime;/*** 业务状态*/@ColumnInfo(cnName = "业务状态", enName = "status", converter = ColumnStrategy.BusinessStatusType.class)private Integer status;/*** 是否校验价格*/@ColumnInfo(cnName = "是否校验价格", enName = "Is check price", converter = ColumnStrategy.PriceCheckType.class)private Integer priceCheckMode;}

5.现在就可以直接传入修改前后的两个对象,利用反射对其进行修改值的检测了

//调用示例
getChangeFields(DTO.class, from, to, descCnList, descEnList);    //具体方法代码如下
private void getChangeFields(Class clazz, Object obj1, Objectobj2, ArrayList<String> cnList, ArrayList<String> enList) {try {// 解析对象1和对象2的JSONObjectJSONObject object1 = JSONUtil.parseObj(obj1);JSONObject object2 = JSONUtil.parseObj(obj2);if (object1.isEmpty() || object2.isEmpty()) {return;}// 获取该类的所有属性Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {// 设置属性可访问field.setAccessible(true);// 获取属性名String name = field.getName();ColumnInfo targetColumnInfo = field.getAnnotation(ColumnInfo.class);ColumnConverter columnConverter = getColumnConverter(targetColumnInfo);// 判断对象1和对象2的属性数量是否不为0(如果是创建则object2为null)// 判断对象1和对象2的属性值是否都不为空(由于有一些属性始终为null,所以需要过滤掉,不然会空指针异常)Object o1 = object1.get(name);Object o2 = object2.get(name);// 判断对象1和对象2的属性值是否不相等if (ObjectUtil.equals(o1, o2)) {continue;}if (Constants.CHECK_CONVERT_FILED.contains(name)) {Object cnFrom = ObjectUtil.isNotEmpty(o1) ? columnConverter.cnConverter(o1) : StringPool.EMPTY;Object cnTo = ObjectUtil.isNotEmpty(o2) ? columnConverter.cnConverter(o2) : StringPool.EMPTY;Object enFrom = ObjectUtil.isNotEmpty(o1) ? columnConverter.enConverter(o1) : StringPool.EMPTY;Object enTo = ObjectUtil.isNotEmpty(o2) ? columnConverter.enConverter(o2) : StringPool.EMPTY;// 添加属性名到列表中cnList.add(String.format("%s【%s】更新为【%s】", targetColumnInfo.cnName(), cnFrom, cnTo));enList.add(String.format("%s【%s】 changed to 【%s】", targetColumnInfo.enName(), enFrom, enTo));} else {o1 = ObjectUtil.isNotEmpty(o1) ? o1 : StringPool.EMPTY;o2 = ObjectUtil.isNotEmpty(o2) ? o2 : StringPool.EMPTY;if (ObjectUtil.isNotEmpty(targetColumnInfo.cnName())) {cnList.add(String.format("%s【%s】更新为【%s】", targetColumnInfo.cnName(), o1, o2));}if (ObjectUtil.isNotEmpty(targetColumnInfo.enName())) {enList.add(String.format("%s【%s】 changed to 【%s】", targetColumnInfo.enName(), o1, o2));}}}} catch (Exception e) {// 获取异常信息详情log.error("---Failed to check attributes---", e);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/66962.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

webrtc入门系列(五)amazon-kinesis-video-streams-webrtc-sdk-c编译

《webrtc入门系列&#xff08;一&#xff09;easy_webrtc_server 入门环境搭建》 《webrtc入门系列&#xff08;二&#xff09;easy_webrtc_server 入门example测试》 《webrtc入门系列&#xff08;三&#xff09;云服务器coturn环境搭建》 《webrtc入门系列&#xff08;四&…

AIGC大模型详解(ChatGPT,Cursor,豆包,文心一格)

定义与概念 AIGC&#xff08;AI Generated Content&#xff09;大模型是基于人工智能技术&#xff0c;具有海量参数、强大算力支持&#xff0c;能处理和生成多种类型内容的深度学习模型。可自主学习数据中的模式和规律&#xff0c;生成文本、图像、音频等内容&#xff0c;如Ch…

.NET9增强OpenAPI规范,不再内置swagger

ASP.NETCore in .NET 9.0 OpenAPI官方文档ASP.NET Core API 应用中的 OpenAPI 支持概述 | Microsoft Learnhttps://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/openapi/overview?viewaspnetcore-9.0https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/ope…

第38周:猫狗识别 (Tensorflow实战第八周)

目录 前言 一、前期工作 1.1 设置GPU 1.2 导入数据 输出 二、数据预处理 2.1 加载数据 2.2 再次检查数据 2.3 配置数据集 2.4 可视化数据 三、构建VGG-16网络 3.1 VGG-16网络介绍 3.2 搭建VGG-16模型 四、编译 五、训练模型 六、模型评估 七、预测 总结 前言…

我的2024年年度总结

序言 在前不久&#xff08;应该是上周&#xff09;的博客之星入围赛中铩羽而归了。虽然心中颇为不甘&#xff0c;觉得这一年兢兢业业&#xff0c;每天都在发文章&#xff0c;不应该是这样的结果&#xff08;连前300名都进不了&#xff09;。但人不能总抱怨&#xff0c;总要向前…

Trimble三维激光扫描-地下公共设施维护的新途径【沪敖3D】

三维激光扫描技术生成了复杂隧道网络的高度详细的三维模型 项目背景 纽约州北部的地下通道网络已有100年历史&#xff0c;其中包含供暖系统、电线和其他公用设施&#xff0c;现在已经开始显露出老化迹象。由于安全原因&#xff0c;第三方的进入受到限制&#xff0c;在没有现成纸…

QT 中 UDP 的使用

目录 一、UDP 简介 二、QT 中 UDP 编程的基本步骤 &#xff08;一&#xff09;包含头文件 &#xff08;二&#xff09;创建 UDP 套接字对象 &#xff08;三&#xff09;绑定端口 &#xff08;四&#xff09;发送数据 &#xff08;五&#xff09;接收数据 三、完整示例代…

开源鸿蒙开发者社区记录

lava鸿蒙社区可提问 Laval社区 开源鸿蒙项目 OpenHarmony 开源鸿蒙开发者论坛 OpenHarmony 开源鸿蒙开发者论坛

Git上传了秘钥如何彻底修改包括历史记录【从安装到实战详细版】

使用 BFG Repo-Cleaner 清除 Git 仓库中的敏感信息 1. 背景介绍 在使用 Git 进行版本控制时&#xff0c;有时会不小心将敏感信息&#xff08;如 API 密钥、密码等&#xff09;提交到仓库中。即使后续删除&#xff0c;这些信息仍然存在于 Git 的历史记录中。本文将介绍如何使用…

多层 RNN原理以及实现

数学原理 多层 RNN 的核心思想是堆叠多个 RNN 层&#xff0c;每一层的输出作为下一层的输入&#xff0c;从而逐层提取更高层次的抽象特征。 1. 单层 RNN 的数学表示 首先&#xff0c;单层 RNN 的计算过程如下。对于一个时间步 t t t&#xff0c;单层 RNN 的隐藏状态 h t h_t…

RNA 测序技术概览(RNA-seq)

前言 转录组测序&#xff08;RNA-seq&#xff09;是当下最流行的二代测序&#xff08;NGS&#xff09;方法之一&#xff0c;使科研工作者实现在转录水平上定量、定性的研究&#xff0c;它的出现已经革命性地改变了人们研究基因表达调控的方式。然而&#xff0c;转录组测序&…

C语言练习(16)

猴子吃桃问题。猴子第一天摘下若干个桃子&#xff0c;当即吃了一半&#xff0c;还不过瘾&#xff0c;又多吃了一个。第二天早上又将剩下的桃子吃掉一半&#xff0c;又多吃了一个。以后每天早上都吃了前一天剩下的一半加一个。到第10天早上想再吃时&#xff0c;见只剩一个桃子了…

【机器学习】自定义数据集使用框架的线性回归方法对其进行拟合

一、使用框架的线性回归方法 1. 基础原理 在自求导线性回归中&#xff0c;我们需要先自定义参数&#xff0c;并且需要通过数学公式来对w和b进行求导&#xff0c;然后在反向传播过程中通过梯度下降的方式来更新参数&#xff0c;从而降低损失值。 2. 实现步骤 ① 散点输入 有一…

pytest执行报错:found no collectors

今天在尝试使用pytest运行用例的时候出现报错&#xff1a;found no collectors&#xff1b;从两个方向进行排查&#xff0c;一是看文件名和函数名是不是符合规范&#xff0c;命名要是"test_*"格式&#xff1b;二是是否存在修改文件名的情况&#xff0c;如果修改过文件…

mysql-06.JDBC

目录 什么是JDBC: 为啥存在JDBC: JDBC工作原理&#xff1a; JDBC的优势&#xff1a; 下载mysql驱动包&#xff1a; 用java程序操作数据库 1.创建dataSource: 2.与服务端建立连接 3.构造sql语句 4.执行sql 5.关闭连接&#xff0c;释放资源 参考代码&#xff1a; 插…

微信小程序wxs实现UTC转北京时间

微信小程序实现UTC转北京时间 打脸一刻&#xff1a;最近在迭代原生微信小程序&#xff0c;好一段时间没写原生的&#xff0c;有点不习惯&#xff1b; 咦&#xff0c;更新数据咋不生效呢&#xff1f;原来还停留在 this.xxx&#xff1b; 哟&#xff0c;事件又没反应了&#xff1f…

机器学习-线性回归(对于f(x;w)=w^Tx+b理解)

一、&#x1d453;(&#x1d499;;&#x1d498;) &#x1d498;T&#x1d499;的推导 学习线性回归&#xff0c;我们那先要对于线性回归的表达公示&#xff0c;有所认识。 我们先假设空间是一组参数化的线性函数&#xff1a; 其中权重向量&#x1d498; ∈ R&#x1d437; …

R语言学习笔记之语言入门基础

一、R语言基础 快速熟悉R语言中的基本概念&#xff0c;先入个门。 1、运算符 运算符含义例子加1 1-减3 - 2*乘3 * 2/除9 / 3^(**)乘方2 ^ 3 2 ** 3%%取余5 %% 2%/%取整5 %/% 2 2、赋值符号 等号a 1三者等价&#xff1a;把1赋值给变量a左箭头<−a <- 1右箭头−&g…

计算机网络三张表(ARP表、MAC表、路由表)总结

参考&#xff1a; 网络三张表&#xff1a;ARP表, MAC表, 路由表&#xff0c;实现你的网络自由&#xff01;&#xff01;_mac表、arp表、路由表-CSDN博客 网络中的三张表&#xff1a;ARP表、MAC表、路由表 首先要明确一件事&#xff0c;如果一个主机要发送数据&#xff0c;那么必…

【Nomoto 船舶模型】

【Nomoto 船舶模型】 1. Nomoto 船舶模型简介2. 来源及发展历程3. 构建 一阶模型Nomoto 船舶模型3.1 C 实现3.2 Python 实现3.3 说明 5. 参数辨识方法5.1 基于最小二乘法的参数辨识5.2 数学推导5.3 Python 实现5.4 说明 4. 结论参考文献 1. Nomoto 船舶模型简介 Nomoto 模型是…