MeterSphere 之 Idea插件开发
前言:
Metersphere 官网支持IDEA插件可以一键导入到MS当中,但一些项目当中自己定义的注解并不支持解析,所以基于这个场景的考虑,自己准备适配一下自定义插件的解析。
官网插件地址:https://github.com/metersphere/metersphere-idea-plugin
一 、MAC 安装gradle
去官网看到插件的结构,是通过java编写,gradle作为构建工具。平时使用Maven比较多,所以这边从0开始搭建一个插件环境。
- 跟使用Maven一样,直接去官方 https://gradle.org/install/ 查看下载适合自己的方式。我使用安装包下载。安装之后解压,配置PATH环境变量即可。
vi ~/.zshrc (我本地安装了item2,所以是这个文件。)
验证 gradle --version
注意:安装gradle先安装jdk,安装jdk网上资料很多。
具体的用法不在这里介绍了,直接查看官网即可。
参考:
https://docs.gradle.org/7.4.2/userguide/what_is_gradle.html
https://www.iteye.com/blog/shmilyaw-hotmail-com-2345439
二、使用gradle构建IDEA插件环境
2.1 跟着官网走
- IDEA 官方是有支持的:https://plugins.jetbrains.com/docs/intellij/welcome.html
- 官网有插件模板:https://github.com/JetBrains/intellij-platform-plugin-template
官网模板是kotlin写的。
可以先看下整体的目录结构
.
├── .github/ GitHub Actions workflows and Dependabot configuration files
├── .run/ Predefined Run/Debug Configurations
├── gradle
│ └── wrapper/ Gradle Wrapper
├── build/ Output build directory
├── src Plugin sources
│ └── main
│ ├── kotlin/ Kotlin production sources 存放项目的源码
│ └── resources/ Resources - plugin.xml, icons, messages 存放项目的资源配置,图标,信息等
│ └── test
│ ├── kotlin/ Kotlin test sources
│ └── testData/ Test data used by tests
├── .gitignore Git ignoring rules
├── build.gradle.kts Gradle configuration
├── CHANGELOG.md Full change history
├── gradle.properties Gradle configuration properties
├── gradlew *nix Gradle Wrapper script
├── gradlew.bat Windows Gradle Wrapper script
├── LICENSE License, MIT by default
├── qodana.yml Qodana configuration file
├── README.md README
└── settings.gradle.kts Gradle project settings
plunig.xml
<idea-plugin><id>org.jetbrains.plugins.template</id><name>Template</name><vendor>JetBrains</vendor><depends>com.intellij.modules.platform</depends><extensions defaultExtensionNs="com.intellij"><applicationService serviceImplementation="..."/><projectService serviceImplementation="..."/></extensions><projectListeners><listener class="..." topic="..."/></projectListeners>
</idea-plugin>
了解了项目架构之后,开始自己搭建一个环境。
2.2本地搭建环境
- 前面我们已经安装好了gradle,然后我们打开idea. 新建项目,选择gradle。
- 注意,因为我们是要用java开发的插件,所以我们要勾选两个,java和intelliJ platform plugin
新建之后的目录结构是这样子的:
src--main--java // 一般我们写的java文件都会放到这个里面。--resources --META-INF--plugin.xml // 插件的配置文件build.gradle // 构建gradle的配置文件,相当于maven里面的pom.xml文件,我们所需要的依赖信息都会放到这里面来。
**plugin.xml **
<idea-plugin><!-- 插件名称,别人在官方插件库搜索你的插件时使用的名称 --><name>MyPlugin</name><!-- 插件唯一id,不能和其他插件项目重复,所以推荐使用com.xxx.xxx的格式插件不同版本之间不能更改,若没有指定,则与插件名称相同 --><id>com.example.plugin.myplugin</id><!-- 插件的描述 --><description>my plugin description</description><!-- 插件版本变更信息,支持HTML标签;将展示在 settings | Plugins 对话框和插件仓库的Web页面 --><change-notes>Initial release of the plugin.</change-notes><!-- 插件版本 --><version>1.0</version><!-- 供应商主页和email--><vendor url="http://www.jetbrains.com" email="support@jetbrains.com" /><!-- 插件所依赖的其他插件的id --><depends>MyFirstPlugin</depends><!-- 插件兼容IDEA的最大和最小 build 号,两个属性可以任选一个或者同时使用官网详细介绍:http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html--><idea-version since-build="3000" until-build="3999"/><!-- application components --><application-components><component><!-- 组件接口 --><interface-class>com.foo.Component1Interface</interface-class><!-- 组件的实现类 --><implementation-class>com.foo.impl.Component1Impl</implementation-class></component></application-components><!-- project components --><project-components><component><!-- 接口和实现类相同 --><interface-class>com.foo.Component2</interface-class></component></project-components><!-- module components --><module-components><component><interface-class>com.foo.Component3</interface-class></component></module-components><!-- Actions --><actions>...</actions><!-- 插件定义的扩展点,以供其他插件扩展该插件 --><extensionPoints>...</extensionPoints><!-- 声明该插件对IDEA core或其他插件的扩展 --><extensions xmlns="com.intellij">...</extensions>
</idea-plugin>
到此,插件的环境已经搭建好了。
三、基于MS官方插件适配自定义注解
IDEA 插件官方提供了一些PSI接口,可以方便我们分析源代码文件。
3.1 PSI介绍
官方介绍: 程序结构接口,通常被称为PSI,是IntelliJ 平台中负责解析文件和创建语法和语义代码模型的层,改模型支持平台的许多功能。
简单理解就是我们要想分析源代码文件的内容,就需要PSI的帮助。
我们知道,JVM在加载类之前,首先需要读取Class文件,并将Class文件解析成一个结构体对象,对应的是Class文件结构。与JVM解析Class文件不同的是,IDEA解析的Java的源代码,但IDEA也是将Java文件解析为一个结构体对象。
请记住一句话,对于任何拥有固定结构的文件或者代码,都可以使用访问者模式。
不仅Java文件,任何代码文件都会有一定的结构,否则编译器也不能识别,也是因为如此,IDEA实现的PSI与Java字节码操作工具ASM有非常多的相似之处,除了都是将文件解析成结构外,也都支持使用访问者模式编辑文件,一个大的结构下面包含许多小的结构,小的结构也支持使用访问者模式编辑。
因为很相似,所以我们可以用学习使用 ASM 工具分析、创建、或改写Class文件的思维去学习PSI。
由于不同的编程语言编写的代码文件有不同的结构,IDEA将文件结构抽象为接口,叫程序结构接口文件(PSI File),不同类型的文件解析后生成不同的PsiFile接口的实现类实例,这也是IDEA能够扩展支持多语言的基础。
3.1.1 PsiFile 接口
一个文件就是一个PsiFile,也是一个文件的结构树的根节点,PsiFile是一个接口,如果文件是一个.java文件,那么解析生成的PsiFile就是PsiJavaFile对象,如果是一个Xml文件,则解析后生成的是XmlFile对象。
3.1.2 PsiElement接口
Class文件结构包含字段表、属性表、方法表等,每个字段、方法也都有属性表,但在PSI中,总体上只有PsiFile和PsiElement。
Element即元素,一个PsiFile(本身也是PsiElement)由许多的PsiElement构成,每个PsiElement也可以由许多的PsiElement构成。
PsiElement用于描述源代码的内部结构,不同的结构对应不同的实现类。
对应Java文件的PsiElement种类有:PsiClass、PsiField、PsiMethod、PsiCodeBlock、PsiStatement、PsiMethodCallExpression等等。其中,PsiField、PsiMethod都是PsiClass的子元素,PsiCodeBlock是PsiMethod的子元素,PsiMethodCallExpression是PsiCodeBlock的子元素,正是这种关系构造成了一棵树。
解析一个Java文件有上百种类型的PsiElement,对于一个新手,我们如何才能快速的认识对应Java代码文件中的每行代码都会解析生成呢?好在IDEA提供了PSI视图查看器。
如果你正在编写插件,那么IDEA会自动在“工具”菜单中显示“查看PSI结构”的选项,否则,我们需要修改IDEA的配置文件才能在“工具”菜单中看到这个选项。
工具
配置文件在IDEA安装路径的bin目录下,找到idea.properties文件,如下图所示。
添加配置后重启IDEA就能看到tools菜单下新加了两个选择,如下图所示。
其中View PSI Structure of Current File是将当前查看的文件解析为结构树,选中选项后弹出如下图所示的窗口。
- Show PSI structure for:选择PsiFile类型;
- Show PsiWhiteSpace:去掉勾选后可以隐藏表示连续空格(包括换行符)的元素PsiElement;
当我们选中源码时,IDEA会找到对应的PsiElement标志为选中状态,如上图左侧的PSI Tree窗口所示
这个小工具可以帮我们刚好的理解PSI的源码
3.1.3 PsiReference 接口
一个PsiReference表示代码中某个PsiElement链接到相应的声明。
简单理解,PsiReference就是我们选中鼠标右键弹出菜单中Go To的Declaration or Usages、或者按住command键+鼠标点击后能够跳转到相应声明的依据。
理解了核心的几个接口,在IDEA的PSI中,有很多工具类可以帮助我们在写插件的时候事半功倍。
源码当中写的都比较清楚。具体的可以研究下。
3.2 MS插件源码解析
在介绍MS分析源码之前先看下效果。
具体用法参考官网
https://github.com/metersphere/metersphere-idea-plugin
结果
针对业务开发人员来讲,就是一个idea的插件,通过对接Metersphere,将项目中的Controller 一键导出到Metersphere当中,完美的融化了开发部门和测试部门的配合。
- 效果看完之后我们开始解析
首先去官网clone 到本地 https://github.com/metersphere/metersphere-idea-plugin
项目结构:
目前MS支持两种导出方式:1. postman 2. metersphere
- action : 触发事件的类。
- gui: gui的配置页面
- exporter:两种类型的导出代码
- 其他目录:都是其它工具类和配置
3.2.1 看一个插件从 plugin.xml 开始
这个配置文件是这个插件的整体配置信息,可以从中获取到插件的ID,名称,邮箱等基本信息和Action以及扩展插件的信息,具体意思参考上面的本地环境搭建。
- 从MS 当中可以看到,这个插件有两个action和两个service 。
- Service 是一个Component,可以理解成一个容器。
- Action 可以理解成是一个事件触发器,比如在IDEA中导出的动作,就可以是一个action。
3.2.2 AppSettingService
- PersistentStateComponent 这个是个接口,是用来持久化存储数据的。上面的注解是指,在运行插件的时候储存的类型。
3.2.3 AppSettingConfigurable
- 实现了Configurable接口,初始化配置,这里初始化的是gui的配置文件信息。
3.2.4 AppSettingComponent和AppSettingComponent.form
- 这两个是一一对应的,在from当中,只有写了fieldName的值,才会在AppSettingComponent类中显示属性,例如:JPanel,JTextField,JPasswordField,JTabbedPane,JComboBox等。
- AppSettingComponent() 这个方法是个构造方法,其中initData(appSettingState)是初始化配置信息的方法,可以看到里面很多Listener,这些个Listener是对gui填写内容的监听,每个类型的Listener不同,但监听原理是相同的。都是当内容发生的时候,触发的动作。
3.2.5 以MS的导出解析:ExportToMSAction
继承了CommonAction
所以核心类就是MeterSphereExporter这个类
这个方法的整体逻辑就是
- 先过滤出所有的PsiJavaFile文件,然后通过调用postmanExporter.transform() 方法去进行解析,然后再构建需要导出的文件格式,通过调用MS的API接口导入到MS当中。所以我们的重点在transform这个方法。
3.2.6 Transform
- 这边必须要注意:导出的接口要符合restful api 风格,要不然不支持的。
- 先判断类上面是否有RequestMapping,用来构建该Controller的访问路径。
- 然后迭代该类中所有方法,进行构建json schema。
- 其实源码当中注释的挺清楚的,按照一个接口需要哪些部分组成的顺序往下读代码就行了:url, header,body等
- 从注解开始,所以在每个方法解析之前获取注解上面的请求类型比如:GET,POST等。
- 前面的都很好理解,主要是body的解析。
- 校验注解只要含有 RequestBody、RequestParam、RequestPart、RequestBody、RequestPart还有servlet的httpRequest和httpResponse 的。都会被解析。
- 这边主要说@RequestBody 的解析方法 getRaw()
- 构建导出对象,然后开始渲染,有一个点需要注意,这个使用的语法是Json Scheam 的语法,熟悉了Json Scheam 会对整个构建过程有一个很清晰的认识。
参考链接:Json Schema 官方网站 中文文档 生成Json Schema 工具
- 红框标注的是意思为:根据当前类型的全限定名,在全局project当中获取对应的类型PsiClass。
- 注意:此方法只能解析对象,数组,基本数据类型等。如果是泛型,例如:Request这种,解析不了,PsiClass为null。
- 构建json schema 的数据类型方法,如果有javadoc的注释,以javadoc的注释为主。
- 如果PsiClass为null,则走else的方法。
- 获取类的所有字段,然后循环开始读取,构建schema数据。
- 以此类推,获取字段,判断类型,构建json schema数据,递归循环。
- 前面解析完之后,接下来构建导入MS所需要的数据格式,然后生成一个临时文件。
- 调用MS的导入接口,导入该文件即可。
3.2.7 整体逻辑
- 获取所有的PsiJavaFile。
- 解析符合restful风格的类。
- 判断javadoc,判断controller 的访问路径,
- 获取url
- 获取header
- 获取body
- 循环方法参数。
- 判断类型。
- 简单类型
- 循环所有属性。
- 判断类型
- 构建json schema
- … 不断递归循环
- 循环所有属性。
- 复杂类型
- 循环属性。
- 是否为泛型。
- 分层解析。先解析外层,在解析内层
- 都是判断类型,构建json schema .
- …不断递归循环。
- 分层解析。先解析外层,在解析内层
- 简单类型
- 构建需要导出的格式,生成导入文件。
- 请求MS导入接口。
- 返回上传结果。
- 刷新MS接口定义列表,查看结果。
3.3 添加自定义注解
当前测试下来,自定义注解是不支持的,还有复杂的泛型嵌套,也是不支持的。所以基于客户的需求,重构了一下代码。
- 新增加一个resolver 文件夹。写了一个构建自定义注解的工厂。
- 重构了getRaw中的 对象解析
- 在构建properties 的scheam 中添加解析自定义注解方法
经过一番改造后,最后终于支持自定义注解了,并且支持复杂的泛型嵌套。比如
- Request
- Response
- 还有自定义注解:CommonAnnotation、CustNoAnnotation、CertNoAnnotation、CertTypeAnnotation
四、写在最后
- 初次上手中间还是遇到了很多坑的,不过等写完之后,还是有一点点成就感的。
- 静下心来,多研究下源码,去github也找一些插件研究一下。
- 虽然当前插件功能不是很完善,但目前内部业务基本都支持了。
- 以上内容仅个人学习心得,如有错误,欢迎指正。
- 整理下参考的资料:
- 官网插件地址:https://github.com/metersphere/metersphere-idea-plugin
- gradle官方: https://gradle.org/install/
- IDEA 官方是有支持的:https://plugins.jetbrains.com/docs/intellij/welcome.html
- 官网有插件模板:https://github.com/JetBrains/intellij-platform-plugin-template
- idea插件介绍:https://cloud.tencent.com/developer/article/1348741
- 参考插件:
- https://github.com/docer-savior/docer-savior-idea-plugin
- https://github.com/tangcent/easy-yapi
- 源码地址:https://github.com/hao65103940/metersphere-idea-plugin/tree/master-fg
MeterSphere 之 Idea插件开发相关推荐
- ATS插件开发中内存泄露问题的解决方法探讨
接触ATS开发已经有几年了,开发过内核的模块,也从事过插件的开发.内存泄露问题一直是一个困扰大多数ATS开发者的头疼的问题,下面说说我自己的感受和思考.这里这关注ATS插件开发这个话题.源码的exam ...
- jQuery插件开发 - 其实很简单
[前言] jQuery已经被广泛使用,凭借其简洁的API,对DOM强大的操控性,易扩展性越来越受到web开发人员的喜爱,我在社区也发布了很多的jQuery插件,经常有人询问一些技巧,因此干脆写这么一篇 ...
- jquery 插件开发的作用域及基础
2019独角兽企业重金招聘Python工程师标准>>> 之前一直有开发jquery插件的冲动,所以一直想学习如何进行插件开发,最近一个项目需要使用图片上传组件及自动无限下拉组件,百度 ...
- Nutch插件开发及发布流程
2019独角兽企业重金招聘Python工程师标准>>> 一,插件开发流程: 1,Nutch开发客户端环境搭建 2,plugin的源代码则保存在/src/java/org/apach ...
- 深入理解 Mybatis 插件开发
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:风一样的码农 cnblogs.com/chenpi/p/10 ...
- 【直播回顾】蚂蚁金服高级开发工程师萧恺:IDEA 插件开发入门教程
主讲人:萧恺(蚂蚁金服-支付宝事业群-高级开发工程师) 本名:肖汉松 讲师介绍: 热爱阅读,喜欢挑战,热衷尝试新的技术,关注技术背后的原理. 关注领域:Java 服务端开发,分布式系统 关注语言:Ja ...
- 黄聪:《跟黄聪学WordPress插件开发》
续<跟黄聪学WordPress主题开发>之后,又一个作品完成!<跟黄聪学Wordpress插件开发>,国内最好的Wordpress插件开发视频教程!! 目录预览: WordPr ...
- discuz x3插件开发傻瓜图文教程,用demo说话
2019独角兽企业重金招聘Python工程师标准>>> 此demo功能是在模板footer部位插入一段javascript代码,这段代码可以是alert提示,也可以是加载广告等等. ...
- chrome 插件开发各种功能demo_Chrome 插件开发全攻略
Chrome 浏览器相信大家都用得比较多,有很多的优点,比如简洁.强大的开发者工具等,但是更让大家映像深刻的是有各种各样有趣.有用的插件,今天要给大家推荐的开源项目是 Chrome 插件开发全攻略,你 ...
最新文章
- 设计模式java装饰模式范例_Java设计模式之装饰模式详解
- 通过阅读 Douglas Crockford 的源码学习如何写 JSON parser(一)
- 怎么把分开的pdf放在一起_糖和盐混在一起了要怎么分开?| 趣问万物
- java单例方法_Java单例模式
- linux io函数,unix/Linux低级IO函数的用法有哪些? 爱问知识人
- while循环与for循环
- Cannot load module file xxx.iml Intellij
- 强大的Win7计算器
- 理财APP的低成本ASO优化实战
- 扫雷游戏(可展开,可标记)C语言实现
- 云上架构和传统IT架构有什么区别及优势?
- 烧一根不均匀的绳,从头烧到尾总共需要1个小时。现在有若干条材质相同的绳子,问如何用烧绳的方法来计时一 个小时十五分钟呢?(微软面试题)
- appstore上传截图的各种尺寸
- 5G NR — 载波聚合
- iis启动和停止的方法介绍
- 疫情开发,软件测试行情趋势是怎么样的?
- leetcode 455 分发饼干(c++和python) 贪心算法
- 一文读懂 druid连接池
- centso7.2上mysql安装
- C练题笔记之:Leetcode-565. 数组嵌套