24年最新 idea 插件开发教程,面试鸭插件技术实现!

news2024/9/29 15:15:30

大家好,我是松柏。今天给大家分享下这个JetBrains插件开发教程。
学习过程中可以参考开源项目:https://github.com/yuyuanweb/mianshiya-plugin

首先贴一下官方文档:https://plugins.jetbrains.com/docs/intellij/welcome.html

虽然这个文档教学属性比较弱,更多是一些概念、规范,但是给了一些示例代码仓库,还是很有用的。

技术选型

我们先看下使用到的技术栈:

  • Gradle IntelliJ Plugin 插件开发的核心 SDK
  • lombok 简化开发的工具包
  • hutool-core hutool 工具包的核心模块
  • retrofit2 网络请求工具包,OkHttp的加强版,也可以使用其他的包

除了插件的 SDK ,没有用到什么特殊的东西。这个 SDK 里的很多内容都继承自 Swing ,所以如果有过相关开发经验的话会更加容易上手,当然了,没有的话影响也不大。

这里值得一提的是,官方还提供了一个新的 SDK : IntelliJ Platform Gradle Plugin,不过它不兼容较旧版本的 IDE ,个人不推荐大家用。

实现

定义入口

确定了需求和使用的技术之后,就可以开始编码了。

先来明确两个概念:

plugin.xml 插件的配置文件,定义插件的元数据和配置,比如插件的入口、一些生命周期的监听器。

tool window 主 IDE 窗口内的一个窗格,比如 ProjectCommit 都是一个个的 tool window

首先,我们给插件定义一个入口然后注册到plugin.xml中,这样就能在左侧看到我们的图标:

@Slf4j
public class MyToolWindowFactory implements ToolWindowFactory {

    private static final Logger logger = Logger.getInstance(MyToolWindowFactory.class);

    public MyToolWindowFactory() {}

    @Override
    public void createToolWindowContent(@NotNull Project project, ToolWindow toolWindow) {}
}
<extensions defaultExtensionNs="com.intellij">
  <toolWindow canCloseContents="true"
    icon="/icons/favicon.svg"
    factoryClass="com.github.yuyuanweb.mianshiyaplugin.toolWindow.MyToolWindowFactory" id="">
  </toolWindow>
</extensions>

并且支持挪到其他我们想要的位置,比如底部:

顶部导航栏

接下来是顶部的导航栏:

在插件开发中,有各种各样的 manager,它们用于处理特定功能或资源的管理。比如导航栏这里我们就用到了 ActionManager,我们会定义一系列导航行为,并注册到 ActionManager上:

OpenUrlAction webAction = new OpenUrlAction(WEB_ZH, CommonConstant.WEB_HOST, IconConstant.WEB);
actionGroup.add(webAction);
actionManager.registerAction(WEB, webAction);
ActionToolbar actionToolbar = actionManager.createActionToolbar(ACTION_BAR, actionGroup, true);
mainPanel.add(actionToolbar.getComponent(), BorderLayout.NORTH);

不同的导航行为需要对AnAction定义不同的实现,比如上述 OpenUrlAction 的作用是用默认浏览器打开一个页面,其定义如下:

public class OpenUrlAction extends AnAction implements DumbAware {
    private final String url;
    
    // 构造函数
    public OpenUrlAction(String text, String url, Icon icon) {
        // Action 名称
        super(text, text, icon);
        this.url = url;
    }
    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        // 使用默认浏览器打开指定网址
        BrowserUtil.browse(url);
    }
}

登录功能

接下来是登录功能,在面试鸭网页端已经提供了扫码登录,所以没必要在插件端再搞一套登录逻辑,不仅麻烦,还有可能负优化用户体验。借用网页端的扫码登录,我们只需要打开一个内嵌浏览器弹窗然后监听登录态并记录就可以了:

getJBCefClient().addLoadHandler(cefLoadHandler = new CefLoadHandlerAdapter() {
    @Override
    public void onLoadingStateChange(CefBrowser browser, boolean isLoading, boolean canGoBack, boolean canGoForward) {
        cefCookieManager.visitAllCookies(new CefCookieVisitor() {
            @Override
            public boolean visit(CefCookie cefCookie, int count, int total, BoolRef boolRef) {
                if ("SESSION".equals(cefCookie.name)) {
                    // 记录 session
                }
                return true;
            }
        });
    }
}, getCefBrowser());
loadURL();

这里需要提一下,打开内嵌浏览器需要 JCEF 的支持,JetBrains系列较低的版本(比如 2021.3 以下)或者某些 IDE (比如 <font style="color:rgba(0, 0, 0, 0.85);">Android Studio</font>)是不支持这个功能的,也就是说,这些 IDE 将无法正常使用我们的插件。

题库、题目列表

接下来是插件的核心之一:题库、题目列表的展示。这里以比较简单的题库列表为例给大家讲解。

这块分为三个部分,上面的题库分类,下面的题库列表,以及底部的分页条,其中的数据都来自接口,所以我们先来看下如何从接口获取数据。在本插件中,要用到的接口比较多并且经常会复用一些接口,所以我们选择的网络请求包是 retrofit2 ,方便统一定义、管理这些接口。

首先看下请求工具类的定义:

public class ApiConfig {
    public static MianShiYaApi mianShiYaApi;
    static {
        // 自定义 Gson 实例
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(Date.class, new DateTypeAdapter())
                .create();
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(new HeaderInterceptor())
                .addInterceptor(new LogInterceptor())
                .addInterceptor(new ResponseInterceptor())
                .build();
        String mianShiYaBaseUrl = CommonConstant.API;
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(mianShiYaBaseUrl)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(client)
                .build();

        mianShiYaApi = retrofit.create(MianShiYaApi.class);
    }
}

可以看到,我们在初始化时添加了一些拦截器,用来添加请求头、输出一些日志等。

然后看下题库分类和题库列表两个接口的定义:

/**
 * 获取题库列表
 */
@POST("questionBankCategory/list_questionBank")
Call<BaseResponse<Page<QuestionBank>>> getQuestionBankList(
        @Body QuestionBankCategoryBankQueryRequest queryRequest
);

/**
 * 获取题库分类列表
 */
@POST("questionBankCategory/list")
Call<BaseResponse<List<QuestionBankCategory>>> listQuestionBankCategory(
        @Body PageRequest pageRequest
);

之后,我们就能在代码中使用 MianShiYaApi.getQuestionBankList() 获取数据了。

接下来看题库分类的展示,其实我们要做的就是把 listQuestionBankCategory 接口返回的数据展示出来,同时用插件的方式给每个分类绑定对应的事件,部分代码如下:

JBPanel<?> labelPanel = new JBPanel<>(new WrapLayout(FlowLayout.LEFT, 5, 5));
ApplicationManager.getApplication().executeOnPooledThread(() -> {
    List<QuestionBankCategory> tagList = ApiConfig.mianShiYaApi.listQuestionBankCategory(new PageRequest()).execute().body().getData();
    ApplicationManager.getApplication().invokeLater(() -> {
        for (QuestionBankCategory tag : tagList) {
            JBLabel label = new JBLabel(tag.getName());
            label.addMouseListener(new MouseAdapter() {
                // 点击事件
                @Override
                public void mouseClicked(MouseEvent e) {
                    // 获取数据
                    searchAndLoadData(queryRequest);                    
                }
            });
            labelPanel.add(label);
        }
    });
});

题目列表的展示与之类似,不过是数据的容器从 JBPanel 换成了 MTabModel

ApplicationManager.getApplication().executeOnPooledThread(() -> {
    Page<QuestionBank> data = this.fetchDataFromApi(queryRequest);
    // 创建表格数据模型
    ApplicationManager.getApplication().invokeLater(() -> {
        tableModel = new MTabModel();
        // 将数据添加到表格模型
        for (QuestionBank row : data.getRecords()) {
            tableModel.addRow(new Object[]{row.getId().toString(), row.getTitle(), row.getTagList()});
        }
        JBTable table = PanelUtil.createTablePanel(tableModel, (tempTable, mouseEvent) -> {
           // 双击某一行数据执行
        });
    });
});

可能有小伙伴好奇,executeOnPooledThreadinvokeLater 这些东西是干嘛的,我们慢慢道来。

IDEA 整个应用的 UI 渲染都是由主线程也叫事件调度线程(Event Dispatch Thread, EDT)来处理的,一旦这个线程卡住,整个 IDEA 就会卡住,一定要注意,不是当前的插件,而是整个 IDEA 都会卡住!一些严重的异常或耗时操作甚至会导致 IDEA 卡死、卡退,这个体验是极端糟糕的。

executeOnPooledThread 的作用就是把操作放到线程池中去执行,防止卡住主线程。

invokeLater 的作用是把涉及到 UI 更新的操作放到主线程中,那为什么非要把 UI 更新操作放到主线程呢?

答案很简单,如果不放到主线程,轻则 UI 状态与实际数据状态不一致,造成用户体验不佳;重则干扰主线程的状态,导致 IDEA 卡死!

题目详情

为了保证阅读体验,在题目详情页中我们使用了内嵌网页的形式展示内容。

JetBrains 插件中,我们需要在编辑区打开自定义内容时,一般是以下步骤:

  • 实现 FileEditorProvider 接口:创建一个类,继承 FileEditorProvider,定义如何创建和管理自定义编辑器。
  • 实现 FileEditor 接口:在自定义编辑器类中实现 FileEditor 接口,以定义编辑器的行为和 UI 组件。
  • 注册编辑器提供者:在插件的 plugin.xml 文件中注册自定义的 FileEditorProvider,使其能够被 IntelliJ IDEA 识别和使用。
  • 处理文件类型:如果需要,定义一个自定义的文件类型,以便在打开特定文件时使用自定义编辑器。

我们这里的核心诉求是 打开一个内嵌的浏览器 ,在浏览器里展示对应的内容,由于打开的内容是需要校验登录态的,所以在打开浏览器时需要带上对应 cookie

打开内嵌浏览器的简化代码如下:

public BrowserFileEditor(@NotNull Project project, @NotNull VirtualFile file) {
    this.jbCefBrowser = new JBCefBrowser();
    this.panel = new JPanel(new BorderLayout());

    // 浏览器
    jbCefBrowser.getJBCefClient().addLoadHandler(new CefLoadHandlerAdapter() {
        @Override
        public void onLoadingStateChange(CefBrowser browser, boolean isLoading, boolean canGoBack, boolean canGoForward) {
            cookieManager.setCookie(CommonConstant.WEB_HOST, jbCefCookie, false);
            jbCefBrowser.setJBCefCookieManager(cookieManager);
        }
    }, jbCefBrowser.getCefBrowser());
    jbCefBrowser.loadURL(url);
}

这里说一下在开发时踩的一个大坑:setJBCefCookieManager执行之前一定一定一定要确保JCEF已经初始化完成,不要直接执行,否则会导致 IDE 卡退!一般的做法是放到 onLoadingStateChange 等钩子里,这样就能正常打开一个内嵌网页:

以上就是插件的大概实现了,我们在实际开发中肯定远比这些复杂,篇幅限制,很多细节就不在这里展开了,大家可以前往 Github 页面搜索“mianshiya-plugin”查看源码细节。

有帮助的话欢迎点个赞,祝大家有所收获,拜拜👋🏻!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2177128.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【最新发布】Win10 22H2 19045.4957 正式版免费下载!

今日系统之家小编给大家分享2024年9月第二次更新的Windows10 22H2正式版系统&#xff0c;该版本系统基于最新Windows10 22H2 19045.4957 64位专业版进行离线制作&#xff0c;安全无毒&#xff0c;修复了使用某些环绕声技术时某些媒体的播放可能会停止等多项问题&#xff0c;系统…

基于C#开发的(CS界面)图书管理系统

图书管理系统项目开发说明书 项目简介 项目背景&#xff08;选择这个项目的原因、前景&#xff0c;面向的用户&#xff0c;优势&#xff09;&#xff1b; 根据温州理工学院需要希望能够充分利用现代科技来提高图书管理的效率&#xff0c;在原有的办公系统基础上进行扩展&…

1. 如何在服务器上租GPU跑实验 (以AutoDL为例) - 深度学习·科研实践·从0到1

目录 前言 1. 在AutoDL上注册账号 2. 在算力市场选择GPU 3. 创建实例 4. 控制台-容器实例界面&#xff08;核心&#xff09; 4.1 无卡模式&#xff08;常用&#xff09; 5. 帮助文档 前言 好记性不如烂笔头&#xff0c;本专栏将详细记录下本人学习深度学习工程实践&…

Python通过Sqlalchemy框架实现增删改查

目录 简介 什么是SQLAlchemy&#xff1f; SQLAlchemy可以分为两个部分&#xff1a;Core和ORM。 一、首先安装sqlalchemy 二、在配置文件中添加数据库连接信息&#xff0c;我这里是Mysql 三、 创建数据库连接类&#xff0c;我这里是动态读取数据库的表字段&#xff0c;自动…

神器!GPT让大学生也能轻松实现架构师级的系统设计图

文章目录 零、前言一、实现架构师级的系统设计图操作指导系统背景功能细化 画用例图画系统架构设计图划分html页面画实体类图画服务层类图画时序图画数据库ER图 二、感受 零、前言 粉丝做毕业设计时&#xff0c;不会画架构图&#xff0c;问虚竹哥会不会画&#xff5e; 虽然这…

基于微信小程序的空巢老人健康管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

STM32引脚PB3、PB4、PA15作为输入输出的特殊配置

一、问题描述 简单描述&#xff1a; 最近做的一个项目中&#xff0c;PB3端口配置为输入&#xff0c;不管外部输入是高电平还是低电平&#xff0c;一直读取到的是低电平。 调试过程&#xff1a;在撰写代码过程中&#xff0c;又发现新的问题&#xff0c;Enter按键无法控制屏幕数…

电脑显示缺失msvcp140_1.dll怎样修复,5种快速修复方法让你快速修复

1. msvcp140_1.dll 定义 1.1 Microsoft Visual C 2015 Redistributable组件 msvcp140_1.dll 是 Microsoft Visual C 2015 Redistributable 的关键组件之一&#xff0c;扮演着至关重要的角色。以下是对 msvcp140_1.dll 的详细分析&#xff1a; 组件功能&#xff1a;msvcp140_…

《中国电子报》报道: 安宝特AR为产线作业者的“秘密武器

近日&#xff0c;中国电子报在其文章《下一代工业智能终端重新定义制造业》中对安宝特的增强现实&#xff08;AR&#xff09;解决方案给予了高度评价&#xff0c;称其为产线作业者的“秘密武器”。这一创新技术改变了传统制造业的作业方式&#xff0c;使得操作人员能够在生产过…

Ubuntu中交叉编译armadillo库

网上关于交叉编译armadillo库比较少&#xff0c;借鉴了一些但是在前几天编译时总是磕磕绊绊&#xff0c;于是写一个详细的编译过程。 交叉编译armadillo库包含两个步骤&#xff1a;交叉编译依赖库和交叉编译armadillo。armadillo官网介绍依赖库如下图所示&#xff1a; 需要注意…

【高性能内存池】page cache 5

page cache 1 page cache的框架2 central cache从page cache申请n页span的过程3 page cache 的结构3.1 page cache类框架3.2 central cache向page cache申请span3.3 获取k页的span page cache的结构和central cache是一样的&#xff0c;都是哈希桶的结构&#xff0c;并且挂载的…

JAVA全球互联同城速达国际版同城跑腿快递代取帮买帮送一体化服务系统源码

全球互联&#xff0c;便捷生活新篇章&#xff01; &#x1f31f; 开篇&#xff1a;跨越国界的即时服务革命 在这个快节奏的时代&#xff0c;你是否也曾为忙碌的生活而烦恼&#xff1f;购物、取件、送物……这些日常琐事似乎总在不经意间占据了我们宝贵的时间。但现在&#xf…

003集—— CAD批量划线和text文字(CAD—C#二次开发入门)

本例通过for循环创建255条线&#xff0c;颜色不同&#xff0c;并在线的右端点处注记文字。 效果如下: 本文有个事务的封装函数&#xff0c;如下&#xff1a; private ObjectId AppendEntity(Entity entity) { ObjectId objectId; Database db HostApplication…

❤Node实现接口增删改查(文章为例)

❤Node实现接口增删改查&#xff08;文章为例&#xff09; 1、文章表的创建​ 接下来我们新建一个文章数据表article&#xff0c;实现对于文章部分的管理功能接口 根据文章我们创建一个对应的 SQL 数据表 javascript CREATE TABLE articles (id INT AUTO_INCREMENT PRIMAR…

亚马逊卖家如何利用自养号测评策略低成本提升销量?

在跨境电商的平台上&#xff0c;随着市场逐渐成熟与竞争的白热化&#xff0c;众多卖家正面临流量增长乏力与转化率提升困难的双重挑战。为了在这日益激烈的竞争环境中脱颖而出&#xff0c;卖家们纷纷加大投入&#xff0c;探索多样化的推广策略&#xff0c;但往往因策略不够精准…

探索Kombo:AI与API的完美结合

文章目录 探索Kombo&#xff1a;AI与API的完美结合背景介绍库的定义安装指南简单函数使用场景应用常见问题及解决方案总结 探索Kombo&#xff1a;AI与API的完美结合 背景介绍 在当今快速发展的人工智能领域&#xff0c;Kombo库以其独特的优势脱颖而出。Kombo是一个专注于AI的…

2024年7月大众点评全国爱车前百名城市分析

在做一些城市分析、学术研究分析、商业选址、商业布局分析等数据分析挖掘时&#xff0c;大众点评的数据参考价值非常大&#xff0c;截至2024年7月&#xff0c;大众点评美食店铺剔除了暂停营业、停止营业后的最新数据情况分析如下。 分析研究的字段维度包括大众点评数字id、字母…

微信商城小程序怎么弄_重塑购物体验

在数字化浪潮的推动下&#xff0c;微信商城小程序正逐步成为消费者购物的新宠儿。它不仅打破了传统电商的界限&#xff0c;更以其便捷性、高效性和个性化服务&#xff0c;重新定义了购物体验。今天&#xff0c;让我们一同探索微信商城小程序如何以独特魅力&#xff0c;引领未来…

巴鲁夫rfid读头国产平替版——高频RFID读写器

随着RFID技术的不断发展&#xff0c;国内RFID企业的数量也在不断地变多&#xff0c;国产RFID读写器的质量也越来越高。具有着价格实惠、质量可靠等特点&#xff0c;成为了可平替国外RFID产品的首要选择。健永科技的高频RFID读写器JY-H830&#xff0c;是一款可平替巴鲁夫rfid读头…