写了个IDEA开源插件,解决让人头疼的 vo2dto
作者:小傅哥 博客:https://bugstack.cn
>沉淀、分享、成长,让自己和他人都能有所收获!😄
头炸,po2vo
、vo2do
、do2dto
,一堆对象属性,取出来塞进来。要不是为了 DDD 架构下的各个分层防腐,真想一竿子怼下去。
那上 BeanUtils.copyProperties
呀,其实对象转换不只这个方法,还有同类的12种手段,但综合来看还是 MapStruct
在编译期生成x.set(y.get)代码的最终效果最好,整体压测数据如下:
BeanUtils.copyProperties
是大家代码里最常出现的工具类,但只要你不把它用错成Apache
包下的,而是使用 Spring 提供的,就基本还不会对性能造成多大影响。- 但如果说性能更好,可替代手动
get、set
的,还是MapStruct
更好用,因为它本身就是在编译期生成get、set
代码,和我们写get、set
一样。 - 其他一些组件包主要基于
AOP
、ASM
、CGlib
,的技术手段实现的,所以也会有相应的性能损耗。
咋办? 给每一个转换对象属性的操作都写一个 MapStruct
吗?也不合适呀,有些就是方法中很简单的操作一下,写写代码就能搞定,问题就是懒的写,一多了还容易写错。别提 BeanUtils.copyProperties 有时候确定有性能问题,从编码上还看不出来属性的添加和减少
所以 我要写个 IDEA Plugin 解决这个问题,目的就一个,通过 IDEA 插件开发能力,定义到我需要转换属性的2个对象,把2个对象的转换代码自动生成出来,并织入到我的对象定位位置上。
设计一个插件
我是这么思考的:在 IDEA 开发工程代码中,在需要转换的2个对象间,复制第一个对象和属性,再把光标定位到转换对象上,接下来我给它提供个按钮或者快捷键,一点就把所有转换代码生成出来,这样不就解决了需要手写的问题了吗,效果如下:
1. 工程结构
vo2dto ├── .gradle └── src ├── main │ └── java │ └── cn.bugstack.guide.idea.plugin │ ├── action │ │ └── Vo2DtoGenerateAction.java │ ├── application │ │ └── IGenerateVo2Dto.java │ ├── domain │ │ ├── model │ │ │ ├── GenerateContext.java │ │ │ ├── GetObjConfigDO.java │ │ │ └── SetObjConfigDO.java │ │ └── service │ │ ├── impl │ │ │ └── GenerateVo2DtoImpl.java │ │ └── AbstractGenerateVo2Dto.java │ └── infrastructure │ └── Utils.java ├── resources │ └── META-INF │ └── plugin.xml ├── build.gradle └── gradle.properties
源码获取:https://github.com/fuzhengwei/vo2dto - 欢迎提交 issue、PR 共同维护
在此 IDEA 插件工程中,主要分为4块区域:
- action:提供菜单栏窗体,在插件中我们把这个菜单栏配置到
Generate
下,也就是通常你生成 get、set、constructor 方法的地方。 - application:应用层定义接口,这里定义了一个用于生成代码并织入到锚点的方法接口。
- domian:领域层专门处理代码的生成和织入动作,这一层把代码的中锚点位置获取、剪切板信息复制、应用上下文、类中get、set的解析,以及最终把生成代码织入到锚点后的操作。
- infrastructure:在基础层提供了工具类,用于获取剪切板信息和锚点位置判断等操作。
2. 织入代码接口
cn.bugstack.guide.idea.plugin.application.IGenerateVo2Dto
public interface IGenerateVo2Dto { void doGenerate(Project project, DataContext dataContext); }
- 定义接口其实非常重要的一步,因为这样一步就把生成的标准定义下来了,所有的生成动作都要从这个接口发起。学习源码也一样,你要找到一个核心的入口点,才能更好的开始学习
3. 定义模板方法
因为生成代码并织入锚点位置的操作,整个来看其实也是一套流程操作,因为在这个过程需要;获取上下文信息(也就是工程对象)、给当前锚点位置的类提取 set 方法集合、之后在给Ctrl+C
剪切板上的信息读取出来提取 get 方法集合,第四步把set、get进行组合并织入代码到锚点位置。整体过程如下:
- 那么在使用模板方法后,就可以非常容易的把写在一个类里的成片的代码按照职责进行拆分。
- 同时因为有了模板的定义,也就定义出了整个一套标准流程,在流程规范下执行代码,后续再补充逻辑迭代功能也会更加容易。
4. 代码织入锚点
关于代码织入锚点前,我们在模板类中定义的方法,需要实现接口进行处理,重点包括:
- 通过
CommonDataKeys.EDITOR.getData(dataContext)
、CommonDataKeys.PSI_ELEMENT.getData(dataContext)
封装 GenerateContext 对象上下文信息,也就是一些类、锚点位置、文档编辑的对象。 - 通过 PsiClass 获取光标位置对应的 Class 类信息,在通过
psiClass.getMethods()
读取对象方法,把 set 方法过滤出来,封装到集合中。 - 通过
Toolkit.getDefaultToolkit().getSystemClipboard()
获取剪切板信息,也就是你在锚点位置给对象生成x.set(y.get)
时,复制的 Y y 对象,并开始提取 get 方法,同样封装到集合中。 - 那么最后就是代码的组装和织入动作了,这部分我们的代码如下;
cn.bugstack.guide.idea.plugin.domain.service.impl.GenerateVo2DtoImpl
@Override protected void weavingSetGetCode(GenerateContext generateContext, SetObjConfigDO setObjConfigDO, GetObjConfigDO getObjConfigDO) { Application application = ApplicationManager.getApplication(); // 获取空格位置长度 int distance = Utils.getWordStartOffset(generateContext.getEditorText(), generateContext.getOffset()) - generateContext.getStartOffset(); application.runWriteAction(() -> { StringBuilder blankSpace = new StringBuilder(); for (int i = 0; i < distance; i++) { blankSpace.append(" "); } int lineNumberCurrent = generateContext.getDocument().getLineNumber(generateContext.getOffset()) + 1; List<string> setMtdList = setObjConfigDO.getParamList(); for (String param : setMtdList) { int lineStartOffset = generateContext.getDocument().getLineStartOffset(lineNumberCurrent++); WriteCommandAction.runWriteCommandAction(generateContext.getProject(), () -> { generateContext.getDocument().insertString(lineStartOffset, blankSpace + setObjConfigDO.getClazzParamName() + "." + setObjConfigDO.getParamMtdMap().get(param) + "(" + (null == getObjConfigDO.getParamMtdMap().get(param) ? "" : getObjConfigDO.getClazzParam() + "." + getObjConfigDO.getParamMtdMap().get(param) + "()") + ");\n"); generateContext.getEditor().getCaretModel().moveToOffset(lineStartOffset + 2); generateContext.getEditor().getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); }); } }); }
- 织入代码的流程动作,主要是对set方法集合进行遍历,把对应的
x.set(y.get)
通过document.insertString
到具体的位置和代码。 - 最终所有生成的代码方法织入完成,即完成了整个
x.set(y.get)
的过程。
5. 配置菜单入口
plugin.xml
<actions> <!-- Add your actions here --> <action id="Vo2DtoGenerateAction" class="cn.bugstack.guide.idea.plugin.action.Vo2DtoGenerateAction" text="Vo2Dto - 小傅哥" description="Vo2Dto generate util" icon="/icons/logo.png"> <add-to-group group-id="GenerateGroup" anchor="last" /> <keyboard-shortcut keymap="$default" first-keystroke="ctrl shift K" /> </action> </actions>
- 这次我们给生成
x.set(y.get)
代码的操作加个快捷键,可以让我们更加方便的进行操作。
安装使用验证
- 由于发布插件需要到 https://plugins.jetbrains.com/ 并等待审核,所以可以在 release 包下载:https://github.com/fuzhengwei/vo2dto/releases/tag/v2.2.2 下载后手动安装即可。
接下来你就可以 So Easy 的转换对象了,操作如下:
- 复制你需要被转换的对象,因为复制以后就可以被插件获取到剪切板信息了,也就能提取到get方法集合。
- 把鼠标定义到需要转换设置值的对象,之后鼠标右键,选择
Generate
->Vo2Dto - 小傅哥
1. 复制对象
2. 生成对象
3. 最终效果
- 最终你就可以看到已经把你全部的对象转换,自动生成出来代码了,是不是很香。
- 如果你直接使用快捷键
Ctrl + Shift + K
也是可以自动生成的。
拿去用用吧,最好再给提一些建议,提交issue、提交PR,都非常的欢迎!</string>
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
企业智能转型对AI技术的挑战及应对,答案是MLOps
企业智能转型对AI技术的挑战及应对,答案是MLOps 前言:笔者在参加12月20日举行的,由LF AI & Data基金会和OpenI启智社区联合举办的2021新一代人工智能院士高峰论坛上分享对于企业智能转型,以及AI技术面临的挑战和应对。 首先什么是企业智能转型? 笔者认为企业智能转型是企业数字化转型的一个较高的阶段,是AI在企业的大规模应用,不是单纯的人脸识别、OCR、语言识别等单个场景的落地,而是用AI来彻底改变企业的核心业务流。达到的效果是:或者彻底改变企业的商业模式,或者在核心效率上有巨大的提升,从而达到企业智能转型的目的。举个例子来说,对于一个连锁餐饮消费企业,它的核心业务流程包括选门店地址、选择商品品类、总店对分店进行铺货和补货、商品促销和线上推荐等,这条核心流程上的多个场景,都采用AI的技术进行优化和重整,从而在多个场景上都取得效率的较多或者较少的提升,累加起来就是效率的巨大提升,从而跟竞争对手相比建立起较大的竞争优势,达到了智能转型的目的。 第四范式在长期帮助1000+企业进行智能转型的过程中,形成了自己独特的企业智能转型方法论---从量变到质变。 把企业的智...
- 下一篇
百度API接口智能化测试探索与实践
导读:API接口自动化测试在服务端分层测试体系中占有重要地位,在持续追求提升研发交付效能的背景下,传统的自动化测试工具面临质量与效率的更高挑战。智能化测试的本质是利用数据和算法相结合赋能质量活动的测试方法,借助智能化测试思维,在API测试全生命周期内进行了多环节的针对性优化、形成合力赋能提升测试质效。 全文5736字,预计阅读时间16分钟。 一、API测试面临的质效问题 1.1API的自动化测试特点 API接口由于具备良好的可测性,很自然的成为服务端程序自动化测试的首选方案: 1、API的结构化有助于程序实现请求与解析接口,当前以Json数据结构为主要的入参、返回结构,可读性强、程序化处理方便。 2、API的业务逻辑集成度较高,具备较高测试性价比,接口的参数组合具备直接的业务含义,主要的业务场景是可以通过不同参数组合达到覆盖。 3、API测试执行与维护成本较低,考虑到需要书写的case量级、调试与维护的代价,在测试分层的金字塔理念之中,是作为腰部支撑的存在。 1.2API自动化测试面对新的挑战 伴随着自动化测试的建设与积累,建成了一站式平台化为主要形式的测试服务,CAS...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8安装Docker,最新的服务器搭配容器使用
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7安装Docker,走上虚拟化容器引擎之路