当前位置: 首页 > 后端技术 > Java

写了一个IDEA开源插件,vo2dto一键生成对象转换

时间:2023-04-01 22:42:55 Java

对象转换很头疼,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有时会出现性能问题,从编码上看不到属性的增减。所以想写一个IDEAPlugin来解决这个问题。目的只有一个。通过IDEA插件开发能力,定义我需要转换属性2个对象,自动生成2个对象的转换代码,编织到我的对象定位位置。我设计一个插件的思路是这样的:在IDEA开发项目代码中,在两个需要转换的对象之间,复制第一个对象和属性,然后把光标定位到转换对象上,然后我会给它提供一个按钮或者快捷键,所有的转换代码都可以一键生成,所以解决了手写的问题,效果如下:1.项目结构vo2dto├──.gradle└──src├───主要│└──java│└──cn.bugstack.guide.idea.plugin│├──动作││└──Vo2DtoGenerateAction.java│├──应用程序││└──IGenerateVo2Dto.java│├──域││├──模型││├──GenerateContext.java│││├──GetObjConfigDO.java││└──SetObjConfigDO.java││└──服务││├──│││││─GenerateVo2DtoImpl.java│└──AbstractGenerateVo2Dto.java│└──基础设施│└──Utils.java├──资源│└──META-INF│└──plugin.xml├──构建d.gradle└──gradle.properties源码获取:https://github.com/fuzhengwei/vo2dto-欢迎提交issue和PR共同维护本IDEA插件项目,主要分为4个方面:action:提供一个菜单栏Form,在插件中,我们把这个菜单栏配置在Generate下,一般就是在这里生成get、set、constructor方法。方法接口。domian:领域层专门负责代码生成和编织动作。该层获取代码中的锚点位置,复制剪贴板信息,应用上下文,解析类中的get和set,最后将生成的代码编织成到达锚点后的操作。infrastructure:提供底层的工具类,用于获取剪贴板信息、锚点位置判断等操作。2.编入代码接口cn.bugstack.guide.idea.plugin.application.IGenerateVo2DtopublicinterfaceIGenerateVo2Dto{voiddoGenerate(Projectproject,DataContextdataContext);}定义接口其实是很重要的一步,因为这一步定义了生成的standard之后,所有的生成动作都必须从这个接口发起。学习源代码也是如此。您需要找到一个核心切入点才能更好地开始学习。3.定义模板方法因为生成代码并织入锚点位置的操作实际上是一个整体的一组流程操作,因为在这个流程中需要;获取context信息(即project对象),提取当前锚点位置的类的set方法集,然后读取ctrl+C剪贴板上的信息提取get方法集,第四步是toset,get组合并将代码编织到锚点位置。整体流程如下:使用模板方法后,很容易将写在一个类中的代码块按照职责进行拆分。同时,因为模板的定义,定义了一整套标准的流程,在流程规范下执行代码会更容易,后期添加逻辑迭代功能。4.代码织入锚点在代码织入锚点之前,我们在模板类中定义的方法需要实现接口进行处理。关键点包括:通过CommonDataKeys.EDITOR.getData(dataContext),CommonDataKeys.PSI_ELEMENT.getData(dataContext)封装了GenerateContext对象的上下文信息,即一些类的对象,锚点位置,文档编辑等。通过PsiClass获取光标所在位置对应的Class信息,通过psiClass.getMethods()读取对象方法,过滤掉set方法,封装成集合。通过Toolkit.getDefaultToolkit().getSystemClipboard()获取剪贴板信息,即当你为锚点处的对象生成x.set(y.get)时,复制Yy对象,开始提取get方法,它也被封装到集合中。那么最后就是代码的组装和编织了。这部分我们的代码如下;{应用程序应用程序=ApplicationManager.getApplication();//获取空格位置长度intdistance=Utils.getWordStartOffset(generateContext.getEditorText(),generateContext.getOffset())-generateContext.getStartOffset();application.runWriteAction(()->{StringBuilderblankSpace=newStringBuilder();for(inti=0;isetMtdList=setObjConfigDO.getParamList();对于(字符串参数:setMtdList){intlineStartOffset=generateContext.getDocument().getLineStartOffset(lineNumberCur租金++);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方法集合,通过document.insertString将对应的x.set(y.get)织入具体位置和代码,最后生成的全部代码方法完成。x.set(y.get)的整个过程。5.配置菜单项plugin.xml这次我们在生成x.set(y.get)代码的操作中加入一个快捷键,可以更方便的进行我们经营。安装及使用验证由于插件的发布需要到https://plugins.jetbrains.com/等待审核,可以在发布包中下载:https://github.com/fuzhengwei/vo2dto/releases/tag/v2.2.2下载后手动安装即可。然后就可以转换SoEasy的对象了,操作如下:复制你需要转换的对象,因为复制之后,剪贴板信息可以通过插件获取,get方法集也可以提取出来.将鼠标定义到需要转换设置值的对象上,然后鼠标右键选择Generate->Vo2Dto-付兄1.复制对象2.生成对象3.最终效果最后可以看到你所有的对象都转换好了,代码自动生成,是不是很香。如果直接使用快捷键Ctrl+Shift+K,也可以自动生成。拿来用,最好提点建议,提交issue,提交PR,都非常欢迎!