高性能 Message ToJavaBean 工具 【easy.server.mapper】

news2024/12/23 4:48:21

easy.server.mapper 介绍

后端开发中,消息转换常见问题

  • Map 中的数据 转换成实体Bean
  • 数组 中的数据 转换成实体Bean
  • Servet 中的 param 转换成实体Bean

以上的三个问题是最常见的消息转换困扰。

以Map 举例

常见做法是

  1. 手动转换
Map<String,Object> dataMap;
Person person;

person.setXX(dataMap.get("XXX"))
        ......
        ......
        ......

弊端是 操作繁琐

  1. 采用反射技术实现
   Map<String,Object> dataMap;

   final Class<Person> personClass = Person.class;
    Object person = personClass.newInstance();
    final Field[] fields = personClass.getDeclaredFields();
    for (Field field : fields) {
        // 特殊类型
        if (Modifier.isFinal(field.getModifiers())) {
            continue;
        }
      
        field.setAccessible(Boolean.TRUE);
        field.set(person, dataMap.get(field.getName()));
    }

操作简单,弊端是存在性能消耗

easy.server.mapper
解决实现


  final Class<Person> personClass = Person.class;
  Person person = BeanCopier2Utils.getFullData2Object(Person.class).toMapConverter(dataMap);

操作简单,性能几乎同 手动转换

性能与反射对比

public class ReflectTest {
    public static boolean warmup = false;
    private Map<String, Object> data = new HashMap<>();
    private Map<String, Object> dataMap = new TreeMap<String, Object>() {{
        put("grep", 1234);
        put("name", "liaojl");
        put("age", 26);
        put("birthday", new Date());
        put("arr", Arrays.asList("2312", "12423"));
        put("arr2", data);
        put("array", new int[]{1, 2, 3});
    }};
    private Object[] dataArray = new Object[]{13, "liaojl", 26, new Date(), Arrays.asList("2312", "12423"), data, new int[]{1, 2, 3}};
    private final ICoreData2Object2<Person> data2Object2 = BeanCopier2Utils.getFullData2Object(Person.class);

    @org.junit.Ignore
    @Test
    public void test() throws Exception {
        testMapCustomize2();
        testArrayCustomize2();
        testReflect();
        warmup = true;
        testReflect();
        testMapCustomize2();
        testArrayCustomize2();
    }

    public static final int SIZE = 1000000;

    private void testMapCustomize2() {
        final long start = System.currentTimeMillis();
        Person person;
        for (int i = 0; i < SIZE; i++) {
            final Class<Person> personClass = Person.class;
            person = data2Object2.toMapConverter(dataMap);
        }
        final long end = System.currentTimeMillis();
        if (warmup)
            System.out.println("testMapCustomize2:" + (end - start));
    }

    private void testArrayCustomize2() {
        final long start = System.currentTimeMillis();
        Person person = null;
        for (int i = 0; i < SIZE; i++) {
            person = data2Object2.toArrayConverter(dataArray);
        }
        final long end = System.currentTimeMillis();
        if (warmup)
            System.out.println("testArrayCustomize2:" + (end - start));
    }

    private void testReflect() throws Exception {
        final long start = System.currentTimeMillis();
        for (int i = 0; i < SIZE; i++) {
            final Class<Person> personClass = Person.class;
            Object person = personClass.newInstance();
            final Field[] fields = personClass.getDeclaredFields();
            for (Field field : fields) {
                if (Modifier.isFinal(field.getModifiers())) {
                    continue;
                }
                Ignore annotation = field.getAnnotation(Ignore.class);
                if (annotation != null) {
                    continue;
                }
                field.setAccessible(Boolean.TRUE);
                field.set(person, dataMap.get(field.getName()));
            }
        }
        final long end = System.currentTimeMillis();
        if (warmup)
            System.out.println("testReflect:" + (end - start));
    }
}

在这里插入图片描述

easy.mapper性能消耗远远小于反射

easy.mapper 的使用

easy.mapper 介绍

注意项

  • 需要转换的Bean 必须包含一个无参构造方法
  • 需要转换的属性必须包含其Getter 方法
  1. 普通转换
@Data
public class Mapper {
    private byte b;
    private Byte b1;
    private boolean bool;
    private Boolean bool1;
    private char c;
    private Character c1;
    private short s;
    private Short s1;
    private int i;
    private Integer i1;
    private long l;
    private Long l1;
    private float f;
    private Float f1;
    private double d;
    private Double d1;

    private Date date;
}
// 转换MAP 到Person 并会对Person父类的属性进行扫描赋值
Person person1 = BeanCopier2Utils.getFullData2Object(Person.class).toMapConverter(dataMap);
        // 转换MAP 到Person 不会对Person父类的属性进行扫描赋值
Person person2 = BeanCopier2Utils.getData2Object(Person.class).toMapConverter(dataMap);
        // 转换Servlet 到Person 不会对Person父类的属性进行扫描赋值
Person person3 = BeanCopier2Utils.getFullData2WebObject(Person.class).toHttpServletRequestConverte(servelt);
        // 转换Servlet 到Person 并会对Person父类的属性进行扫描赋值
Person person4 = BeanCopier2Utils.getData2WebObject(Person.class).toHttpServletRequestConverte(servelt);

  1. 字段忽略
io.github.jinlongliao.easy.server.mapper.core.mapstruct2.annotation.Ignore2

提供 @Ignore2 使用标记的字段在转换时并不会进行赋值操作

demo

public class Person extends Grep implements IAnimal {
    private static final Logger log = LoggerFactory.getLogger(Person.class);
    @Ignore
    @Ignore2
    private int ignore;
}
  1. 特殊字段转换
  • 字段名称与bean 中属性名不对应
  • 数据类型,双方不匹配
  • 其他特殊类型

easy.mapper 默认对支持所有基础类型及其包装类,String 。详情查看 io.github.jinlongliao.easy.server.mapper.core.mapstruct2.converter.IDataConverter 实现。针对特殊类型转。提供两种转换方案

  • 重写 IDataConverter 实现

io.github.jinlongliao.easy.server.mapper.core.mapstruct2.converter.InnerConverter 接口 ,重写<T> T getT(Class<T> tClass, Object extra, Object data);
针对不支持类型时,会调用此方法,自己仅需要 依据 参数tClass 的类型进行判断 进行返回相应值,参数中的data 为消息中的值

  • 使用 io.github.jinlongliao.easy.server.mapper.core.mapstruct2.annotation.Mapping2
public @interface Mapping2 {
    /**
     * @return 映射源名称
     */
    String sourceName() default "";

    /**
     * set Method Name
     * @return
     */
    String putMethod() default "";


    /**
     * 针对非基本类型(String,byte,short,int,float,double,long,char)<br/>
     * 除外需要指定自定义 静态转换函数
     * eg:
     * <pre>
     *     public static Person person(Object obj){
     *         return (Person)obj;
     *     }
     * </pre>
     *
     * @return 数据强转函数名称
     */
    String converterMethod() default "";

    /**
     * @return Class Name
     * @see {@link Mapping2#converterMethod()}
     */
    Class converterClass() default InnerConverter.class;
}

converterClass 手动指定转换自己的转换类,
converterMethod 设置转换函数的名称  ___ 此函数必须为 public+static ___ 。
putMethod  假设 bean 中的 属性a setter函数 不为 setA 通过 putMethod 可以指定新的setter函数
sourceName 假设 mesaage 中的名字不是属性a 的名字  sourceName 可以指定获取源的名字

提前编译 支持

  1. 手动指定

通过 io.github.jinlongliao.easy.server.mapper.utils.MapperStructConfig可以指定 自动生成消息转换实现的 class 及其源文件

      MapperStructConfig.setDev(true, "./target/", "./target/");
  1. 通过 maven 插件实现 maven-generator-plugin
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.10.1</version>
                <configuration>
                    <annotationProcessorPaths>
                        <annotationProcessorPath>
                            <groupId>io.github.jinlongliao</groupId>
                            <artifactId>easy.server.mapper</artifactId>
                            <version>${project.version}</version>
                        </annotationProcessorPath>
                        <annotationProcessorPath>
                            <groupId>io.github.jinlongliao</groupId>
                            <artifactId>easy.server.extend</artifactId>
                            <version>${project.version}</version>
                        </annotationProcessorPath>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
            <plugin>
                <groupId>io.github.jinlongliao</groupId>
                <artifactId>maven-generator-plugin</artifactId>
                <version>${project.version}</version>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <arguments>
                        <argument>${project.basedir}/target/classes/</argument>
                        <argument>${project.basedir}/target/generated-sources/annotations/</argument>
                    </arguments>
                </configuration>
            </plugin>
        </plugins>
    </build>

在这里插入图片描述

spring 支持

io.github.jinlongliao.easy.server.mapper.spring.BeanMapperFactoryBean设置spring 托管。既可在 spring 中 使用 IBeanMapper类型 进行操作,IBeanMapper封装了常见的类型操作推荐使用

public interface IBeanMapper {
    /**
     * 基于Map 的转换
     *
     * @param tClass
     * @param data
     * @param <T>
     * @return T
     */
    <T> T mapBeanMapper(Class<T> tClass, Map<String, Object> data);

    /**
     * 基于数组 的转换
     *
     * @param tClass
     * @param data
     * @param <T>
     * @return T
     */
    <T> T arrayBeanMapper(Class<T> tClass, Object[] data);

    /**
     * 基于javax.servlet 的转换
     *
     * @param tClass
     * @param req
     * @param <T>
     * @return T
     */
    <T> T servletBeanMapper(Class<T> tClass, javax.servlet.http.HttpServletRequest req);

}

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

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

相关文章

stm32f407探索者开发板(二十三)——定时器中断实验

文章目录一、通用定时器知识回顾1.1 时钟的选择1.2 内部时钟的选择1.3 计数器模式二、常用寄存器和库函数配置2.1 计数器当前值寄存器CNT2.2 预分频寄存器TIMx_PSC2.3 自动重装载寄存器&#xff08;TIMx_ARR)2.4 控制寄存器1&#xff08;TIMx_CR1&#xff09;2.5 DMA中断使能寄…

基因净化车间装修设计方案SICOLAB

基因净化车间的设计方案应该根据实际需求进行定制&#xff0c;以下是一些规划建设要点和洁净设计要注意的事项&#xff1a;一、净化车间规划建设要点&#xff1a;&#xff08;1&#xff09;基因车间的面积应该根据实验项目的规模进行规划&#xff0c;包括充足的操作区域和足够的…

华为OD机试题,用 Java 解【DNA 序列】问题

最近更新的博客 华为OD机试 - 猴子爬山 | 机试题算法思路 【2023】华为OD机试 - 分糖果(Java) | 机试题算法思路 【2023】华为OD机试 - 非严格递增连续数字序列 | 机试题算法思路 【2023】华为OD机试 - 消消乐游戏(Java) | 机试题算法思路 【2023】华为OD机试 - 组成最大数…

自动化测试selenium

目录 一、为什么引入自动化测试&#xff1f; 二、为什么选择selenium作为自动化测试工具&#xff1f; 三、环境部署 四、什么是驱动&#xff1f;驱动的工作原理&#xff1f; 五、selenium的基础语法 元素定位 元素操作 点击元素 模拟键盘输入 清除对象输入的文本…

vue-draggable浏览器拖拽event事件对象拖动时 DragEvent path undefined

场景&#xff1a; 在做组件拖拽过程中&#xff0c;需要获取到触发元素冒泡过程中的所有元素&#xff0c;所以使用了event.path属性。在Chrome下正常运行&#xff0c;但是在FireFox下测试时发现&#xff0c;完犊子&#xff0c;失效了&#xff0c;通过问题排查&#xff0c;发现了…

开源运维监控工具WGCLOUD - 功能概述及架构介绍(理论篇)

一、项目简介 开源运维监控系统WGCLOUD&#xff0c;基于springboot和golang开发&#xff0c;可以监控各种设备&#xff08;物理机&#xff0c;云主机&#xff0c;虚拟机等都可以&#xff0c;安卓也可以&#xff09;。 二、实现功能 支持windows和redHat、centos、ubuntu、deb…

ASEMI低压MOS管20N06参数,20N06体积,20N06大小

编辑-Z ASEMI低压MOS管20N06参数&#xff1a; 型号&#xff1a;20N06 漏极-源极电压&#xff08;VDS&#xff09;&#xff1a;60V 栅源电压&#xff08;VGS&#xff09;&#xff1a;20V 漏极电流&#xff08;ID&#xff09;&#xff1a;20A 功耗&#xff08;PD&#xff0…

【设计模式】 工厂模式介绍及C代码实现

【设计模式】 工厂模式介绍及C代码实现 背景 在软件系统中&#xff0c;经常面临着创建对象的工作&#xff1b;由于需求的变化&#xff0c;需要创建的对象的具体类型经常变化。 如何应对这种变化&#xff1f;如何绕过常规的对象创建方法(new)&#xff0c;提供一种“封装机制”来…

宝塔搭建实战php悟空CRM前后端分离源码-vue前端篇(二)

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 上一期给大家分享了悟空CRM server端在宝塔部署的方式&#xff0c;但是由于前端是用vue开发的&#xff0c;如果要额外开发新的功能&#xff0c;就需要在本地运行、修改、打包重新发布到宝塔才能实现功能更新&…

Kubernetes之job

job job用于执行一次性任务&#xff0c;如数据处理、分析、测试、运算等需求&#xff0c;运算完成后&#xff0c;也就结束了&#xff0c;不用一直计算下去。 创建一个job后&#xff0c;会创建一个pod&#xff0c;如果pod执行成功了&#xff0c;则此job结束&#xff0c;若此pod…

Linux 配置NFS与autofs自动挂载

目录 配置NFS服务器 安装nfs软件包 配置共享目录 防火墙放行相关服务 配置NFS客户端 autofs自动挂载 配置autofs 配置NFS服务器 nfs主配置文件参数&#xff08;/etc/exports&#xff09; 共享目录 允许地址1访问&#xff08;选项1&#xff0c;选项2&#xff09; 循序地…

fastadmin:如何点击按钮弹出存在的指定页面的弹窗

样式&#xff1a;方法一&#xff1a;直接使用超链接进行操作{:url(popup/purchase/itemno)}&#xff1a;表示地址信息btn-dialog&#xff1a;表示弹窗<a href"{:url(popup/purchase/itemno)}" title"跳转第三方" class"btn btn-success btn-dialog…

Kali安装配置vulhub

一、vulhubVulhub是一个基于docker和docker-compose的漏洞环境集合&#xff0c;进入对应目录并执行一条语句即可启动一个全新的漏洞环境&#xff0c;主要利用于漏洞复现。Vulhub的官方地址为www.vulhub.org。二、搭建vulhub靶场2.1 开启kali虚拟机2.2 安装docker先更新一下软件…

第四届国际步态识别竞赛HID2023已经启动,欢迎报名

欢迎参加第四届HID 2023竞赛&#xff0c;证明您的实力&#xff0c;推动步态识别研究发展&#xff01;本次竞赛的亮点&#xff1a;总额人民币19,000元奖金&#xff1b;最新的SUSTech-Competition步态数据集&#xff1b;比上一届更充裕的准备时间&#xff1b;OpenGait开源程序帮您…

系统发育树初步剖析

什么是系统发育树如何看系统发育树并确定哪些物种最相关1. 要点 系统发育树是表示生物体之间进化关系的图表。系统发育树是假设的&#xff0c;而不是确定的事实。系统发育树中的分支模式反映了物种或其他群体如何从一系列共同祖先进化而来的关系。在树中&#xff0c;如果两个物…

1301:大盗阿福

经典的dp打家劫舍问题状态设计dp[i][0]&#xff1a;在前i个店铺中选&#xff0c;且不选第i家的最大和dp[i][1]&#xff1a;在前i个店铺中选&#xff0c;且选第i家的最大和状态转移dp[i][0] max(dp[i-1][1], dp[i-1][0];第i家店不选&#xff0c;那么我们可以选第i-1个店 也可以…

Vue3的新特性变化,上手指南!

文章目录一、Vue3相比Vue2&#xff0c;更新了什么变化&#xff1f;二、Proxy 代理响应式原理三、组合式 API (Composition API)setup()函数:ref()函数reactive()函数组合式 setup 中使用 Props 父向子传递参数计算属性watch&#xff08;数据监视&#xff09;watchEffect&#x…

C语言数据结构初阶(2)----顺序表

目录 1. 顺序表的概念及结构 2. 动态顺序表的接口实现 2.1 SLInit(SL* ps) 的实现 2.2 SLDestory(SL* ps) 的实现 2.3 SLPrint(SL* ps) 的实现 2.4 SLCheckCapacity(SL* ps) 的实现 2.5 SLPushBack(SL* ps, SLDataType x) 的实现 2.6 SLPopBack(SL* ps) 的实现 2.7 SLP…

“XXX.app 已损坏,打不开。您应该将它移到废纸篓”,Mac应用程序无法打开或文件损坏的处理方法(2)

1. 检查状态 在sip系统完整性关闭前&#xff0c;我们先检查是否启用了SIP系统完整性保护。打开终端输入以下命令【csrutil status】并回车&#xff1a; 你会看到以下信息中的一个&#xff0c;用来指示SIP状态。已关闭 disabled: System Integrity Protection status: disabl…

学习 Python 之 Pygame 开发魂斗罗(四)

学习 Python 之 Pygame 开发魂斗罗&#xff08;四&#xff09;继续编写魂斗罗1. 创建子弹类2. 根据玩家方向和状态设置子弹发射的位置(1). 站立向右发射子弹(2). 站立向左发射子弹(3). 站立朝上发射子弹(4). 蹲下发射子弹(5). 向斜方发射子弹(6). 奔跑时发射子弹(7). 跳跃时发射…