前言

在工作中,IDEA是开发人员最常用的开发工具,但有时开发的过程又是枯燥乏味的。

我们常常说高端的程序员,往往采用最朴素的编程方式:

image-20220630213606571

但这也是最无聊的开发过程,它不快乐。编程是需要快乐的。

所以,开发可以解决这些枯燥过程的IDEA插件是有效的方法之一。

IDEA插件SDK

开发第一个插件

在编程的世界里,所有起源都从一个HelloWorld开始~

1、使用模板

没错,IDEA插件开发也是可以有模板的~

打开插件模板仓库

点击Use this template使用该模板

image-20220630214302161

咱就叫他hello-world

image-20220630214410637

2、使用IDEA打开模板

克隆hello-world到本机,使用idea打开

image-20220630225949984

如你所见,项目使用gradle构建, 项目默认使用kotlin编写代码,当然,如果你想用Java,可以直接建Java包,该模板同样支持Java

在该项目里,最重要的文件即为:META-INF/plugin.xml文件,里面定义了插件一系列的配置信息

<!-- Plugin Configuration File. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html -->
<idea-plugin>
    <!--  插件id 唯一 -->
    <id>com.github.lzj960515.helloworld</id>
    <!--  插件名称  -->
    <name>Hello World</name>
    <!--  版本  -->
    <version>1.0.0</version>
    <!--  作者或组织  -->
    <vendor url="zijiancode.cn" email="lzj960515@163.com">lzj960515</vendor>
    <!--  支持的idea版本  -->
    <idea-version since-build="211.1" until-build="223.*"/>
    <description>
        <![CDATA[
            <p>这里是插件描述</p>
            <p>这里是插件描述</p>
            <p>这里是插件描述</p>
            <p>这里是插件描述</p>
            <p>这里是插件描述</p>
            <p>这里是插件描述</p>
            <p>这里是插件描述</p>
          ]]>
    </description>
    <!--  更新日志  -->
    <change-notes>Hello World</change-notes>
    <!--  依赖  -->
    <depends>com.intellij.modules.platform</depends>
    <!-- 扩展点   -->
    <extensions defaultExtensionNs="com.intellij">
        <applicationService serviceImplementation="com.github.lzj960515.helloworld.services.MyApplicationService"/>
        <projectService serviceImplementation="com.github.lzj960515.helloworld.services.MyProjectService"/>
    </extensions>
    <!--  监听器  -->
    <applicationListeners>
        <listener class="com.github.lzj960515.helloworld.listeners.MyProjectManagerListener"
                  topic="com.intellij.openapi.project.ProjectManagerListener"/>
    </applicationListeners>
</idea-plugin>

更多插件配置见: 插件配置

为了更好的Hello-World,这里我把示例代码删除,免得干扰到大家,并且使用Java代码编写

image-20220630230804311

3、创建一个Action

没错,IDEA插件也是有Action的!点击鼠标右键 --> 选择New --> Plugin DevKit --> Action

如果没有的话,那么可能需要在先在IDEA中装个 Plugin DevKit插件

image-20220630231016897

填写Action信息

image-20220630231236476

Action ID: 插件的Action ID,在插件中保证唯一

Class Name: 就是ClassName啦

Name: 使用插件时,这个Action对应按钮的名字

Add to Group: 把这个Action的事件绑定到IDEA界面的哪个部分, 我这里的ToolsMenu即为上方菜单栏的Tools,最右边的First即为放到Tools列表的第一位

Keyboard Shortcuts: 快捷键

创建完毕:

image-20220630231720095

同时,在plugin.xml中你会看到多出了个action

image-20220630232224227

4、编写HelloWorld

image-20220630231858520

Messages是一个,嗯..就是个发消息的工具,它还有许多API,请你自己尝试吧~

调试插件

接下来,就是调试插件了

点击右边Gradle中的Run Plugin

image-20220630232317285

此时会运行一个虚拟的IDEA,我们顺便打开个项目,然后点开Tools见证奇迹

image-20220630232602392

效果如下:

image-20220630232802579

发布插件

运行Gradle中的buildPlugin

image-20220630232940024

完毕之后,便可以在build中找到插件的压缩包

image-20220630233058088

现在,你可以直接把这个压缩包分享给你的朋友们,或者上传至idea插件市场~

image-20220630233210689

地址:https://plugins.jetbrains.com/author/me

开发一个有界面的插件

背景

编写复杂的查询时,我们常常需要通过写SQL的方式完成,其中写where条件部分就是枯燥乏味且有规则的。

规则:将参数编写成mybatis中的where语句

比如我们要把以下对象进行转化

image-20220701102308197

转化成

image-20220701102341292

要是手写的话这个过程无疑是非常痛苦的,那么我们是否可以通过IDEA插件完成这个过程呢?

产品原型

image-20220701103020057

image-20220701103106608

需求分析

1、怎么画界面?

2、怎么显示界面?

3、怎么获取到当前文件的内容?

4、怎么获取到用户选择的内容?

5、怎么将内容转化成where语句?

6、怎么把where语句渲染到文本框中?

1、画界面

画界面这个过程堪称【有手就行】,当然,带一点点脑子

右键 --> New --> Swing UI Designer --> GUI Form

image-20220701103559284

image-20220701103808273

输入表单名称,选择布局。

关于布局:

img

然后你就会得到这样的界面

image-20220701104034979

是不是有手就行嘛!

我这里选择的是BorderLayout,根据产品原型,我们将界面分为上下两个大块,上面放前缀输入框和生成按钮,下面放文本框

image-20220701104250685

上方的JPanel位于北方,下方的JPanel位于中央,样式如下

image-20220701104707777

其中JPanel皆为BorderLayout布局

接下来,修改组件的名称

image-20220701104815038

field name:在代码中的名字

text: 界面中显示的名字

image-20220701104950311

接下来,在做一点点优化,加上border样式,以及border title

image-20220701105222672

2、显示界面

首先,我们修改样式对应的Java类,将rootPanel暴露出来,并监听按钮进行测试

image-20220701105657964

至于如何显示界面,只要我们将rootPanel交给Idea的组件即可

我们可以依据官方文档,创建一个对话框,然后将该window交个这个对话框

如何创建对话框:https://plugins.jetbrains.com/docs/intellij/dialog-wrapper.html

同样,我们先创建一个Action

image-20220701162749182

EditorPopupMenu指右键菜单

创建对话框

public class GenerateDialog extends DialogWrapper {

    public GenerateDialog() {
        super(true);
        setTitle("Where语句生成");
        init();
    }

    @Override
    protected JComponent createCenterPanel() {
        return new WhereGenerateWindow().getRootPanel();
    }
}

将对话框加入Action中

public class GenerateWhereAction extends AnAction {

    @Override
    public void actionPerformed(AnActionEvent e) {
        this.show(e);
    }

    private void show(AnActionEvent e){
        new GenerateDialog().show();
    }
}

或者直接使用DialogBuilder

public class GenerateWhereAction extends AnAction {

    @Override
    public void actionPerformed(AnActionEvent e) {
        this.show(e);
    }

    private void show(AnActionEvent e){
        WhereGenerateWindow window = new WhereGenerateWindow();
        DialogBuilder dialogBuilder = new DialogBuilder(e.getProject());
        dialogBuilder.setCenterPanel(window.getRootPanel());
        dialogBuilder.setTitle("Where语句生成");
        dialogBuilder.show();
    }
}

调试插件

image-20220701162805464

image-20220701162854943

这样的界面有点丑,我们需要调整大小。

在gui界面中,选中打开专家模式,然后调整界面大小,同时设置margin,让输入框往里缩一点

image-20220701163024027

同样的,将JScrollPanel也设置一下,再进行调试

image-20220701163156482

这下就好看多了。

3、怎么获取到当前文件的内容?

public class GenerateWhereAction extends AnAction {

    @Override
    public void actionPerformed(AnActionEvent e) {
        // 获取编辑器
        Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
        // 当前打开的文件
        VirtualFile virtualFile = e.getRequiredData(CommonDataKeys.PSI_FILE).getViewProvider().getVirtualFile();
        // 获取选择的数据模型
        SelectionModel selectionModel = editor.getSelectionModel();
        // 获取当前选择的文本
        String selectedText = selectionModel.getSelectedText();
        if(StringUtils.isBlank(selectedText)){
            // 获取当前打开的文件
            Document document = editor.getDocument();
            show(e, document.getText());
        }
        else {
            show(e, selectedText);
        }
    }

    private void show(AnActionEvent e, String text){
        WhereGenerateWindow window = new WhereGenerateWindow(text);
        DialogBuilder dialogBuilder = new DialogBuilder(e.getProject());
        dialogBuilder.setCenterPanel(window.getRootPanel());
        dialogBuilder.setTitle("Where语句生成");
        dialogBuilder.show();
    }
}
public class WhereGenerateWindow {
    private JPanel rootPanel;
    private JTextField prefix;
    private JButton generate;
    private JTextArea whereStatement;

    public WhereGenerateWindow(String text){
        this.init(text);
    }

    private void init(String text){
        whereStatement.setText(text);
        generate.addActionListener(e -> {
            whereStatement.setText(prefix.getText() + "." + whereStatement.getText());
        });
    }

    public JPanel getRootPanel() {
        return rootPanel;
    }
}

调试

image-20220701163436550

接下来的如何解析文件,生成where语句就纯属于Java知识了,我想就不用我赘述了。

如何引入依赖

项目是由gradle构建的,所以引入依赖的方式和平常开发没什么两样

dependencies{
    implementation("cn.hutool:hutool-all:5.6.2")
}

官方样例

官方文档是个不错的学习方式,同样的,官方也具有许多的demo可供我们学习

地址:https://github.com/JetBrains/intellij-sdk-code-samples

本文代码地址

https://github.com/lzj960515/code-generator