前言:
Metersphere 官网支持IDEA插件可以一键导入到MS当中,但一些项目当中自己定义的注解并不支持解析,所以基于这个场景的考虑,自己准备适配一下自定义插件的解析。

官网插件地址:https://github.com/metersphere/metersphere-idea-plugin


一 、MAC 安装gradle

去官网看到插件的结构,是通过java编写,gradle作为构建工具。平时使用Maven比较多,所以这边从0开始搭建一个插件环境。

  1. 跟使用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 跟着官网走

  1. IDEA 官方是有支持的:https://plugins.jetbrains.com/docs/intellij/welcome.html
  2. 官网有插件模板: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本地搭建环境

  1. 前面我们已经安装好了gradle,然后我们打开idea. 新建项目,选择gradle。
  2. 注意,因为我们是要用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

  1. PersistentStateComponent 这个是个接口,是用来持久化存储数据的。上面的注解是指,在运行插件的时候储存的类型。

3.2.3 AppSettingConfigurable

  1. 实现了Configurable接口,初始化配置,这里初始化的是gui的配置文件信息。

3.2.4 AppSettingComponent和AppSettingComponent.form

  1. 这两个是一一对应的,在from当中,只有写了fieldName的值,才会在AppSettingComponent类中显示属性,例如:JPanel,JTextField,JPasswordField,JTabbedPane,JComboBox等。

  1. AppSettingComponent() 这个方法是个构造方法,其中initData(appSettingState)是初始化配置信息的方法,可以看到里面很多Listener,这些个Listener是对gui填写内容的监听,每个类型的Listener不同,但监听原理是相同的。都是当内容发生的时候,触发的动作。

3.2.5 以MS的导出解析:ExportToMSAction

继承了CommonAction


所以核心类就是MeterSphereExporter这个类

这个方法的整体逻辑就是

  1. 先过滤出所有的PsiJavaFile文件,然后通过调用postmanExporter.transform() 方法去进行解析,然后再构建需要导出的文件格式,通过调用MS的API接口导入到MS当中。所以我们的重点在transform这个方法。

3.2.6 Transform

  1. 这边必须要注意:导出的接口要符合restful api 风格,要不然不支持的。

  1. 先判断类上面是否有RequestMapping,用来构建该Controller的访问路径。
  2. 然后迭代该类中所有方法,进行构建json schema。

  1. 其实源码当中注释的挺清楚的,按照一个接口需要哪些部分组成的顺序往下读代码就行了:url, header,body等
  2. 从注解开始,所以在每个方法解析之前获取注解上面的请求类型比如:GET,POST等。

  1. 前面的都很好理解,主要是body的解析。
  2. 校验注解只要含有 RequestBody、RequestParam、RequestPart、RequestBody、RequestPart还有servlet的httpRequest和httpResponse 的。都会被解析。
  3. 这边主要说@RequestBody 的解析方法 getRaw()

  1. 构建导出对象,然后开始渲染,有一个点需要注意,这个使用的语法是Json Scheam 的语法,熟悉了Json Scheam 会对整个构建过程有一个很清晰的认识。

参考链接:Json Schema 官方网站 中文文档 生成Json Schema 工具

  1. 红框标注的是意思为:根据当前类型的全限定名,在全局project当中获取对应的类型PsiClass。
  2. 注意:此方法只能解析对象,数组,基本数据类型等。如果是泛型,例如:Request这种,解析不了,PsiClass为null。

  1. 构建json schema 的数据类型方法,如果有javadoc的注释,以javadoc的注释为主。
  2. 如果PsiClass为null,则走else的方法。


  1. 获取类的所有字段,然后循环开始读取,构建schema数据。
  2. 以此类推,获取字段,判断类型,构建json schema数据,递归循环。

  1. 前面解析完之后,接下来构建导入MS所需要的数据格式,然后生成一个临时文件。

  1. 调用MS的导入接口,导入该文件即可。

3.2.7 整体逻辑

  1. 获取所有的PsiJavaFile。
  2. 解析符合restful风格的类。
  3. 判断javadoc,判断controller 的访问路径,
  4. 获取url
  5. 获取header
  6. 获取body
    1. 循环方法参数。
    2. 判断类型。
      1. 简单类型

        1. 循环所有属性。

          1. 判断类型
          2. 构建json schema
          3. … 不断递归循环
      2. 复杂类型
        1. 循环属性。
        2. 是否为泛型。
          1. 分层解析。先解析外层,在解析内层

            1. 都是判断类型,构建json schema .
            2. …不断递归循环。
  7. 构建需要导出的格式,生成导入文件。
  8. 请求MS导入接口。
  9. 返回上传结果。
  10. 刷新MS接口定义列表,查看结果。

3.3 添加自定义注解

当前测试下来,自定义注解是不支持的,还有复杂的泛型嵌套,也是不支持的。所以基于客户的需求,重构了一下代码。

  1. 新增加一个resolver 文件夹。写了一个构建自定义注解的工厂。

  1. 重构了getRaw中的 对象解析

  1. 在构建properties 的scheam 中添加解析自定义注解方法

经过一番改造后,最后终于支持自定义注解了,并且支持复杂的泛型嵌套。比如

  1. Request
  2. Response
  3. 还有自定义注解:CommonAnnotation、CustNoAnnotation、CertNoAnnotation、CertTypeAnnotation

四、写在最后

  1. 初次上手中间还是遇到了很多坑的,不过等写完之后,还是有一点点成就感的。
  2. 静下心来,多研究下源码,去github也找一些插件研究一下。
  3. 虽然当前插件功能不是很完善,但目前内部业务基本都支持了。
  4. 以上内容仅个人学习心得,如有错误,欢迎指正。
  5. 整理下参考的资料:
    1. 官网插件地址:https://github.com/metersphere/metersphere-idea-plugin
    2. gradle官方: https://gradle.org/install/
    3. IDEA 官方是有支持的:https://plugins.jetbrains.com/docs/intellij/welcome.html
    4. 官网有插件模板:https://github.com/JetBrains/intellij-platform-plugin-template
    5. idea插件介绍:https://cloud.tencent.com/developer/article/1348741
    6. 参考插件:
      1. https://github.com/docer-savior/docer-savior-idea-plugin
      2. https://github.com/tangcent/easy-yapi
    7. 源码地址:https://github.com/hao65103940/metersphere-idea-plugin/tree/master-fg

MeterSphere 之 Idea插件开发相关推荐

  1. ATS插件开发中内存泄露问题的解决方法探讨

    接触ATS开发已经有几年了,开发过内核的模块,也从事过插件的开发.内存泄露问题一直是一个困扰大多数ATS开发者的头疼的问题,下面说说我自己的感受和思考.这里这关注ATS插件开发这个话题.源码的exam ...

  2. jQuery插件开发 - 其实很简单

    [前言] jQuery已经被广泛使用,凭借其简洁的API,对DOM强大的操控性,易扩展性越来越受到web开发人员的喜爱,我在社区也发布了很多的jQuery插件,经常有人询问一些技巧,因此干脆写这么一篇 ...

  3. jquery 插件开发的作用域及基础

    2019独角兽企业重金招聘Python工程师标准>>> 之前一直有开发jquery插件的冲动,所以一直想学习如何进行插件开发,最近一个项目需要使用图片上传组件及自动无限下拉组件,百度 ...

  4. Nutch插件开发及发布流程

    2019独角兽企业重金招聘Python工程师标准>>>  一,插件开发流程: 1,Nutch开发客户端环境搭建 2,plugin的源代码则保存在/src/java/org/apach ...

  5. 深入理解 Mybatis 插件开发

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:风一样的码农 cnblogs.com/chenpi/p/10 ...

  6. 【直播回顾】蚂蚁金服高级开发工程师萧恺:IDEA 插件开发入门教程

    主讲人:萧恺(蚂蚁金服-支付宝事业群-高级开发工程师) 本名:肖汉松 讲师介绍: 热爱阅读,喜欢挑战,热衷尝试新的技术,关注技术背后的原理. 关注领域:Java 服务端开发,分布式系统 关注语言:Ja ...

  7. 黄聪:《跟黄聪学WordPress插件开发》

    续<跟黄聪学WordPress主题开发>之后,又一个作品完成!<跟黄聪学Wordpress插件开发>,国内最好的Wordpress插件开发视频教程!! 目录预览: WordPr ...

  8. discuz x3插件开发傻瓜图文教程,用demo说话

    2019独角兽企业重金招聘Python工程师标准>>> 此demo功能是在模板footer部位插入一段javascript代码,这段代码可以是alert提示,也可以是加载广告等等. ...

  9. chrome 插件开发各种功能demo_Chrome 插件开发全攻略

    Chrome 浏览器相信大家都用得比较多,有很多的优点,比如简洁.强大的开发者工具等,但是更让大家映像深刻的是有各种各样有趣.有用的插件,今天要给大家推荐的开源项目是 Chrome 插件开发全攻略,你 ...

最新文章

  1. 设计模式java装饰模式范例_Java设计模式之装饰模式详解
  2. 通过阅读 Douglas Crockford 的源码学习如何写 JSON parser(一)
  3. 怎么把分开的pdf放在一起_糖和盐混在一起了要怎么分开?| 趣问万物
  4. java单例方法_Java单例模式
  5. linux io函数,unix/Linux低级IO函数的用法有哪些? 爱问知识人
  6. while循环与for循环
  7. Cannot load module file xxx.iml Intellij
  8. 强大的Win7计算器
  9. 理财APP的低成本ASO优化实战
  10. 扫雷游戏(可展开,可标记)C语言实现
  11. 云上架构和传统IT架构有什么区别及优势?
  12. 烧一根不均匀的绳,从头烧到尾总共需要1个小时。现在有若干条材质相同的绳子,问如何用烧绳的方法来计时一 个小时十五分钟呢?(微软面试题)
  13. appstore上传截图的各种尺寸
  14. 5G NR — 载波聚合
  15. iis启动和停止的方法介绍
  16. 疫情开发,软件测试行情趋势是怎么样的?
  17. leetcode 455 分发饼干(c++和python) 贪心算法
  18. 一文读懂 druid连接池
  19. centso7.2上mysql安装
  20. C练题笔记之:Leetcode-565. 数组嵌套

热门文章

  1. 【Go】Go 语言的循环语句: for、break、continue、goto、range
  2. 如何升级 Admui 至最新版?
  3. Android推送方案
  4. Mysql中的varchar类型转换成int类型
  5. SpringMvc实现一个账号只能在一个地方登陆,其他地方强制下线
  6. 【Python】Python安装教程
  7. 便携版的数学计算Python--WinPython
  8. 猫眼、淘票票环伺 豆瓣影评危机被指公信力下降
  9. neo4j教程 java_neo4j 教程
  10. 操作系统的镜像是什么