自定义注解加反射实现数据类型转换

概述

通过ORM框架从数据库中查询出的实体对象,大部分情况下可能与前端页面展示的数据结果类型略有不同,比如:后端定义的店铺实体类(Shop)中有店铺状态:0-正常,1-未审核,2-违规,3-倒闭,在做脱敏的处理下需要转换成一个VO,其中店铺状态需要后台转换,因此可以通过自定义注解+反射的方式处理。

准备工作:

1、自定义注解

1.1 ConvertEnumField.java

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ConvertEnumField {/** 枚举类.class */Class<?> enumClass();/** 实体类的字段名 */String sourceFieldName() default "";}

1.2 ConvertDateField.java

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ConvertDateField {/** 实体类的字段名 */String sourceFieldName() default "";/*** 日期的格式,例如:** yyyy-MM-dd** yyyy-MM-dd HH:mm:ss** @return*/String pattern() default "";}

2、枚举:ShopStatusEnum.java

public enum ShopStatusEnum {/** 铺状态:0-正常,1-未审核,2-违规,3-倒闭 */NORMAL(0, "正常"),UNAUDITED(1, "未审核"),GET_OUT_OF_LINE(2, "违规"),CLOSE_DOWN(3, "倒闭");/** 状态码 **/private Integer code ;/** 消息 **/private String message ;ShopStatusEnum(Integer code, String message) {this.code = code ;this.message = message ;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
}

3、Shop.java (实体)

@Data
public class Shop implements Serializable {/*** 主键*/private Long id = 22222L;/*** 店铺名称*/private String shopName = "test";/*** 店铺状态:0-正常,1-未审核,2-违规,3-倒闭*/private Integer shopStatus = 1;/*** 创建时间*/private LocalDateTime createTime = LocalDateTime.now();/*** 修改时间*/private Date updateTime;/*** 是否删除:0-正常,1-删除*/private Integer isDeleted;private static final long serialVersionUID = 1L;
}

4、ShopVo.java(前端展示的实体)

@Data
public class ShopVo {/*** 主键*/private Long id;/*** 店铺名称*/private String shopName;/*** 店铺状态:0-正常,1-未审核,2-违规,3-倒闭*/@ConvertEnumField(enumClass = ShopStatusEnum.class, sourceFieldName = "shopStatus")private String shopStatusStr;/*** 创建时间*/@ConvertDateField(sourceFieldName = "createTime", pattern = "yyyy-MM-dd")private String createTimeStr;/*** 修改时间*/private Date updateTime;/*** 是否删除:0-正常,1-删除*/private Integer isDeleted;private static final long serialVersionUID = 1L;
}

自定义工具类:BeanUtil.java

import com.javasetest.annotation.ConvertDateField;
import com.javasetest.annotation.ConvertEnumField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;/*** ClassName: BeanUtil* Package: com.javasetest.utils* Description:** @Author wxz* @Create 2024/4/12 16:08* @Version 1.0*/
public class BeanUtil {private static final Logger logger = LoggerFactory.getLogger(BeanUtil.class);/*** 字段转换** @param sourceObj 源数据* @param targetObj 目标数据*/public static void fieldConvert(Object sourceObj, Object targetObj) {// 获取目标数据的所有字段Field[] targetFields = targetObj.getClass().getDeclaredFields();// 遍历所有字段是否标注了注解Arrays.stream(targetFields).forEach(field -> {// 由于这是私有字段,我们需要设置为可访问field.setAccessible(true);// 获取属性上的注解 ConvertStatusToStrConvertEnumField convertEnumFieldAnno = field.getDeclaredAnnotation(ConvertEnumField.class);if (convertEnumFieldAnno != null) {try {// 处理标注了 ConvertEnumField 注解的字段convertEnumFieldHandler(sourceObj, targetObj, field, convertEnumFieldAnno);} catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException e) {throw new RuntimeException(e);}}ConvertDateField convertDateFieldAnno = field.getDeclaredAnnotation(ConvertDateField.class);if (convertDateFieldAnno != null) {try {// 处理标注了 convertDateField 注解的字段convertDateFieldHandler(sourceObj, targetObj, field, convertDateFieldAnno);} catch (NoSuchFieldException | IllegalAccessException e) {throw new RuntimeException(e);}}});}/*** 处理标注了 convertDateField 注解的字段** @param sourceObj            源数据* @param targetObj            目标数据* @param field                要处理的字段* @param convertDateFieldAnno 自定义的注解* @throws NoSuchFieldException* @throws IllegalAccessException*/private static void convertDateFieldHandler(Object sourceObj, Object targetObj, Field field, ConvertDateField convertDateFieldAnno) throws NoSuchFieldException, IllegalAccessException {// 获取属性上注解的信息String sourceFieldName = convertDateFieldAnno.sourceFieldName();String pattern = convertDateFieldAnno.pattern();// 从源数据中获取需要转化的属性的值Field sourceField = sourceObj.getClass().getDeclaredField(sourceFieldName);// 由于这是私有字段,我们需要设置为可访问sourceField.setAccessible(true);// 字段值Object value = sourceField.get(sourceObj);// 日期类型格式化LocalDateTime dateValue = (LocalDateTime) value;String format = dateValue.format(DateTimeFormatter.ofPattern(pattern));field.set(targetObj, format);}/*** 处理标注了 ConvertEnumField 注解的字段** @param sourceObj            源数据* @param targetObj            目标数据* @param field                要处理的字段* @param convertEnumFieldAnno 自定义的注解*/private static void convertEnumFieldHandler(Object sourceObj, Object targetObj, Field field, ConvertEnumField convertEnumFieldAnno) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {// 获取属性上注解定义的枚举类(全限定类名)String enumClasName = convertEnumFieldAnno.enumClass().getTypeName();// 获取属性上注解定义的实体类的字段名String sourceFieldName = convertEnumFieldAnno.sourceFieldName();// 从源数据中获取需要转化的属性的值Field sourceField = sourceObj.getClass().getDeclaredField(sourceFieldName);// 由于这是私有字段,我们需要设置为可访问sourceField.setAccessible(true);// 字段值Object value = sourceField.get(sourceObj);// 从枚举中获取枚举信息String message = getEnumMessage((int) value, enumClasName);field.set(targetObj, message);}/*** 从枚举中获取枚举信息** @param status 枚举值* @param classPath 枚举信息* @return 枚举信息* @throws ClassNotFoundException*/private static String getEnumMessage(Integer status, String classPath) throws ClassNotFoundException {Object[] enumConstants = Class.forName(classPath).getEnumConstants();if (enumConstants == null || enumConstants.length <= 0) {return "";}String str = "";for (Object enumConstant : enumConstants) {Field codeField = null;Field messageField = null;try {codeField = enumConstant.getClass().getDeclaredField("code");messageField = enumConstant.getClass().getDeclaredField("message");codeField.setAccessible(true);messageField.setAccessible(true);int code = (int) codeField.get(enumConstant);String message = (String) messageField.get(enumConstant);if (status == code) {str = message;break;}} catch (NoSuchFieldException | IllegalAccessException e) {throw new RuntimeException(e);}}return str;}}

测试类:

    @Testpublic void test8() {Shop shop = new Shop();ShopVo shopVo = JSONObject.parseObject(JSON.toJSONString(shop), ShopVo.class);BeanUtil.fieldConvert(shop, shopVo);logger.info(shopVo.toString());}

测试结果:

ShopVo(id=22222, shopName=test, shopStatusStr=未审核, createTimeStr=2024-04-12, updateTime=null, isDeleted=null)

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

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

相关文章

[amateurs CTF 2024] crypto/pilfer-techies

这题费了几天,昨天写到11点半才基本完成程序,需要交互2000多,远程太慢了交互两次就断掉了&#xff0c;反正本地能成&#xff0c;程序逻辑上正确了。小鸡块也写了WP了等写完马上去看小鸡块神的思路。也许有的问题很大呢&#xff1f; 先简单看下题&#xff1a; #!/usr/local/bi…

二分查找基本模版

二分&#xff1a;通过不断取中点&#xff0c;重复将一个区域一份为二&#xff0c;使其不断缩小范围直至找到答案 本质&#xff1a;性质/边界&#xff0c;而不是单调性 时间复杂度&#xff1a;O(logN) 代码模版&#xff1a; //找到的是最左侧的数值点 while(l < r){ //尽…

[数据结构]——二叉树——堆的实现

1. 堆的概念及结构 如果有一个关键码的集合K { &#xff0c; &#xff0c; &#xff0c;…&#xff0c; }&#xff0c;把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中&#xff0c;并满足&#xff1a; < 且 < ( > 且 > ) i 0&#xff0c;1&…

前端面试题(1)

1&#xff0c;CSS盒子模型 CSS的盒模型有两种&#xff1a;标准盒模型&#xff0c;IE盒模型。IE盒模型&#xff0c;其中content包含了内边距padding和边框border。盒子的实际宽度 contentmargin。标准盒模型&#xff0c;盒子的实际宽度 content(内容)padding(内边距)border(边…

rocky9 yum 安装与配置MySQL8

1.前置条件&#xff1a; 把yum包更新到最新 [rootlocalhost ~]# yum update 查看系统中是否已安装 MySQL 服务 rpm -qa|grep mysql 如果有安装mysql,则需要先卸载之前安装的mysql&#xff1a;yum -y remove mysql 然后再查看mysql是否都卸载完成,如果还有没卸载完成的&am…

小程序开发SSL证书下载和安装

在开发小程序时&#xff0c;确保数据的安全传输至关重要&#xff0c;而实现这一目标的关键在于正确获取与安装SSL证书。以下详细介绍了从获取到安装SSL证书的完整流程&#xff0c;以助您为小程序构建可靠的加密通信环境。 一、小程序SSL证书类型选择&#xff1a; 域名验证型D…

创新指南|全球需求低迷中国企业出海趋势洞察和创新机会

对于企业出海来说&#xff0c;第一步判断趋势非常重要&#xff0c;这甚至事关企业生死。比如十年前的2014年&#xff0c;中国最大的两家电商平台阿里和京东成功IPO&#xff08;上市&#xff09;后&#xff0c;认为接下来最大的机会在于中国市场的消费升级。与阿里、京东不同&am…

TypeScript基础语法

这里写自定义目录标题 变量条件控制循环函数类和接口模块开发 变量 TypeScript在JavaScript的基础上加入了静态类型检查功能&#xff0c;因此每一个变量都有固定的数据类型。 let msg: string hello worldlet 声明变量的关键字&#xff0c; const 则代表常量 msg 变量名称 &…

Linux:软件包管理器 - yum

Linux&#xff1a;软件包管理器 - yum Linux的软件安装方式源代码安装rpm包安装yum安装 yum三板斧yum listyum installyum remove yum生态yum源 Linux的软件安装方式 源代码安装 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序 源代码安…

git知识

如何将develop分支合并到master分支 #简单版 git checkout master git pull origin master git merge origin/develop # 解决可能的冲突并提交 git push origin master#复杂版 git checkout master # 拉取远程 master 分支的最新代码并合并到本地 git pull origin master # 拉…

新时代·高质量·硬道理丨开放的大门越开越大、开放的水平越来越高

新时代下&#xff0c;中国坚定不移地实施扩大高水平对外开放战略&#xff0c;致力于构建更高层次、更宽领域的开放型经济体系。以下是对新时代高质量硬道理这一主题下&#xff0c;中国开放大门越开越大、开放水平越来越高的几个关键点分析&#xff1a; 全方位开放格局 政府工…

YOLOv8打印模型结构配置信息并查看网络模型详细参数:参数量、计算量(GFLOPS)

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

计算机基础知识-第7章-程序的本质(2)——算法与数据结构概论

一、算法数据结构程序 提出这一公式并以此作为其一本专著的书名的瑞士计算机科学家尼克劳斯沃思&#xff08;Niklaus Wirth&#xff09;由于发明了多种影响深远的程序设计语言&#xff0c;并提出结构化程序设计这一革命性概念而获得了1984年的图灵奖。他是至今惟一获此殊荣的瑞…

Java——测试相关

1、测试的常用方法 单元测试&#xff1a;针对软件中最小可测试单元进行的测试&#xff0c;如类、方法等。功能测试&#xff1a;检查软件的各项功能是否按照需求规格书执行&#xff0c;通常包括正常功能、边界情况和异常情况的测试。性能测试&#xff1a;检查软件的速度、响应时…

【Linux杂货铺】文件系统

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 硬盘 &#x1f4c2; 物理结构 &#x1f4c2; 存储结构 &#x1f4c2; CHS定址法 &#x1f4c2; 操作系统对硬盘的管理和抽象 &#x1f4c1; 文件系统 &#x1f4c2; 分区 &#x1f4c2; 分组 &#x1f4c2; inode号 分配…

1113. 红与黑--Flood Fill 算法

目录 1113. 红与黑--Flood Fill 算法---宽搜&#xff08;BFS&#xff09; 输入格式 输出格式 数据范围 输入样例&#xff1a; 输出样例&#xff1a; 思路&#xff1a; 代码&#xff1a; 运行结果&#xff1a; 1113. 红与黑--Flood Fill 算法---宽搜&#xff08;BFS&am…

无人机技术在光伏电站勘探中的重要应用

随着科技的不断进步和创新&#xff0c;无人机技术在各个领域中都发挥着越来越重要的作用。其中&#xff0c;光伏电站对于无人机的应用也成为了行业内的高效运维方式之一&#xff0c;凭借无人机卓越的性能和可靠性&#xff0c;有效的减少了人力运维的危险性和延迟性&#xff0c;…

Java研学-RBAC权限控制(三)

四 部门管理 1 数据库表 CREATE TABLE department (id bigint(20) NOT NULL AUTO_INCREMENT,name varchar(255) DEFAULT NULL,sn varchar(255) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT9 DEFAULT CHARSETutf8;2 实体类 Data public class Department {…

股票价格预测 | Python股票价格数据导入和处理

文章目录 文章概述代码设计导入处理文章概述 股票价格预测 | Python股票价格数据导入和处理 代码设计 导入 import os import numpy as np import csv import pandas as pd import matplotlib.pyplot

【NC16596】计算系数

题目 计算系数 组合数&#xff0c;快速幂 思路 这是一道数学题&#xff0c;由之前的数学知识可以知道&#xff0c;题目要我们算一个数&#xff1a; ( C k m a n b m ) m o d 10007 (C_k^ma^nb^m)\mod\ 10007 (Ckm​anbm)mod 10007 题意很明显&#xff0c;没有弯弯绕&#xff…