作者:小傅哥 博客:https://
? 沉淀、分享、成長,讓自己和他人都能有所收獲!??
? 目錄 一、前言
二、需求目的
三、案例開發(fā)
1. 工程結(jié)構(gòu)
2. tab 頁窗體
3. 股票框體設(shè)置
4. 填充主面板到IDEA工具欄
5. 數(shù)據(jù)持久化配置
6. 股票接口
四、測試驗證
1. 配置股票
2. 自選股指數(shù)
3. K線
五、總結(jié)
六、系列推薦
一、前言 沒招了,不寫點刺激的,你總是不好好看!
以前,我不懂。寫的技術(shù)就是技術(shù)內(nèi)容,寫的場景就是場景分析,但從讀者的閱讀我發(fā)現(xiàn),大家更喜歡的是技術(shù)與場景結(jié)合,尤其是用技術(shù)結(jié)合那些羞羞答答的場景,雖然嘴上都不說。
本章節(jié)主要是想給大家介紹關(guān)于在 IDEA 插件開發(fā)中如何使用工具欄和Tab頁,來填充在 IDEA 中底部的窗體,就像 IDEA 中的控制臺一樣。但就這么寫好像是夠嗆能有人看,因為大家只從技術(shù)點來看,很難發(fā)現(xiàn)這里面有什么應用場景,即使看了好像也不知道這技術(shù)能干啥。
那咋辦 ,整點刺激
的吧。大家不是喜歡賠錢炒股
嗎,那就把股票行情
和K線展示
結(jié)合到IDEA插件開發(fā)中??梢宰寣W習插件的伙伴,都能在寫代碼疲憊的時候還能看一眼股票,也許在關(guān)鍵的時候還能提醒你趕緊拋出去!
二、需求目的 安全起見,需要在 IDEA 中以一個比較隱秘的角落,開發(fā)股票插件,讓炒股的同學可以在緊張編碼CRUD之余,不要忘記自己關(guān)注的股票購買和拋售。
那么為了解決這個問題,我們需要幾個技術(shù)點,包括:股票數(shù)據(jù)接口、查詢對象封裝、IDEA 底部窗體和工具欄開發(fā)、定時任務(wù)掃描、Swing UI、股票代碼配置和保存、窗體按鈕事件監(jiān)聽等。
接下來我們就結(jié)合這些技術(shù)點,來解決實際的場景問題,看看如何在 IDEA 中開發(fā)一個股票插件。
三、案例開發(fā) 1. 工程結(jié)構(gòu)guide-idea-plugin-tab ├── .gradle └── src ├── main │ └── java │ └── cn.bugstack.guide.idea.plugin │ ├── domain │ │ ├── model │ │ │ ├── aggregates │ │ │ │ └── StockResult.java │ │ │ └── vo │ │ │ ├── Data.java │ │ │ ├── GoPicture.java │ │ │ └── Stock.java │ │ └── service │ │ ├── impl │ │ │ └── StockImpl.java │ │ └── IStock │ ├── factory │ │ └── TabFactory.java │ ├── infrastructure │ │ ├── DataSetting.java │ │ └── DataState.java │ ├── module │ │ ├── RefreshBar.java │ │ ├── SettingBar.java │ │ └── ViewBars.java │ └── ui │ │ ├── ConsoleUI.java │ │ ├── ConsoleUI.form │ │ ├── GidConfig.java │ │ └── GidConfig.form │ └── Config ├── resources │ └── META-INF │ └── plugin.xml ├── build.gradle └── gradle.properties
源碼獲取 :#公眾號:bugstack蟲洞棧
回復:idea
即可下載全部 IDEA 插件開發(fā)源碼
在此 IDEA 插件工程中,主要分為5塊區(qū)域:
domain:領(lǐng)域?qū)?,提供查詢股票接口的?shù)據(jù)服務(wù),如果你是做的一些其他工具型功能,也可以把業(yè)務(wù)類的內(nèi)容放到 domain 中實現(xiàn)。 factory:工廠層,這里主要提供的是一個工具窗體生成的入口對象,來創(chuàng)建出我們自己添加的窗體內(nèi)容。 infrastructure:基礎(chǔ)層,提供了數(shù)據(jù)存放對象,這個數(shù)據(jù)對象是一個可以落盤的操作,創(chuàng)建好的類配置到 plugin.xml 中即可。這樣我們配置好股票代碼后,關(guān)機重啟 IDEA 也可以把配置讀取出來 module:模塊,提供用于 UI 窗體使用的一些工具頁操作。比如這里的 ViewBars 會在 TabFactory 中實例化,用于展示出你添加的窗體。 ui:這一部分使用的是 IDEA 中自動拖拽生成的窗體,免去了手寫的復雜性,一些簡單的頁面直接拖拽就可以。這也是一種低代碼哦! 接下來 ,我們就分別看下每個核心功能點的實現(xiàn)過程,這個過程中你可以提前把代碼下載下來,對照著學習會更加容易理解。
實現(xiàn) ToolWindowFactory 開發(fā)一個底部的窗體,用于承載所需的內(nèi)容 左側(cè)是側(cè)邊工具欄,配置自選股、刷新股票指數(shù) 右側(cè)是2個 tab 頁,分別用于展示股票數(shù)據(jù)和K線圖,這里的數(shù)據(jù)則需要通過股票接口來提供 2. tab 頁窗體首先這里我們先使用 IDEA 插件開發(fā)中,Swing UI 功能,拖拽出2個簡單的窗體。有了這樣的一個基本結(jié)構(gòu)大家的腦子里應該就可以有畫面
了。
2.1 自選股配置窗體public class GidConfig implements Configurable { private JPanel mainPanel; private JPanel settingPanel; private JLabel gidLabel; private JTextField gidTextField; private ConsoleUI consoleUI; public GidConfig (ConsoleUI consoleUI) { this .consoleUI = consoleUI; } public JTextField getGidTextField () { return gidTextField; } @Override public void apply () throws ConfigurationException { List<String> gidList = DataSetting.getInstance().getGids(); gidList.clear(); String[] gids = gidTextField.getText().trim().split("," ); for (String gid : gids) { gidList.add(gid.trim()); } // 刷新數(shù)據(jù) consoleUI.addRows(gidList); } }
在 GidConfig 對應的 java 類中,可以對一些窗體中出現(xiàn)的屬性進行獲取。當用戶點擊這個窗體的確認按鈕后,我們可以在 apply 中拿到用戶配置的股票代碼,并對其進行讀取和設(shè)置股票數(shù)據(jù)。 2.2 股票展示窗體public class ConsoleUI { private JTabbedPane tabbedPane1; private JPanel one; private JPanel two; private JLabel picMin; private JTable table; private JLabel picDay; // 查詢數(shù)據(jù)服務(wù) private IStock stock = new StockImpl(); private DefaultTableModel defaultTableModel = new DefaultTableModel(new Object[][]{}, new String[]{"股票" , "代碼" , "最新" , "漲跌" , "漲幅" }); public ConsoleUI () { // 初始數(shù)據(jù) table.setModel(defaultTableModel); addRows(DataSetting.getInstance().getGids()); // 添加事件 table.addMouseListener(new MouseAdapter() { @Override public void mouseClicked (MouseEvent e) { int row = table.getSelectedRow(); Object value = table.getValueAt(row, 1 ); GoPicture goPicture = stock.queryGidGoPicture(value.toString()); try { // 分鐘K線 picMin.setSize(545 , 300 ); picMin.setIcon(new ImageIcon(new URL(goPicture.getMinurl()))); // 當日K線 picDay.setSize(545 , 300 ); picDay.setIcon(new ImageIcon(new URL(goPicture.getDayurl()))); } catch (MalformedURLException m) { m.printStackTrace(); } } }); } public JTabbedPane getPanel () { return tabbedPane1; } public void addRows (List<String> gids) { // 查詢 List<Data> dataList = stock.queryPresetStockData(gids); // 清空 int rowCount = defaultTableModel.getRowCount(); for (int i = 0 ; i < rowCount; i++) { defaultTableModel.removeRow(0 ); } // 添加 for (Data data : dataList) { defaultTableModel.addRow(new String[]{data.getName(), data.getGid(), data.getNowPri(), data.getIncrease(), data.getIncrePer()}); table.setModel(defaultTableModel); } } }
展示股票的窗體對應的 ConsoleUI 類,主要負責數(shù)據(jù)的渲染、更新和對每條數(shù)據(jù)的事件操作,當用戶點擊某一條數(shù)據(jù)以后,就可以到 K線
頁中看到對應的股票指數(shù)了。 3. 股票框體設(shè)置在開發(fā)完 UI 窗體后,我們還需要使用一個 SimpleToolWindowPanel 的繼承實現(xiàn)類,承載工具欄和頁面的設(shè)置。
3.1 設(shè)置-工具欄cn.bugstack.guide.idea.plugin.module.SettingBar
public class SettingBar extends DumbAwareAction { private ViewBars panel; public SettingBar (ViewBars panel) { super ("配置股票" , "Click to setting" , IconLoader.getIcon("/icons/config.svg" )); this .panel = panel; } @Override public void actionPerformed (@NotNull AnActionEvent e) { ShowSettingsUtil.getInstance().editConfigurable(panel.getProject(), new GidConfig(panel.getConsoleUI())); } }
設(shè)置工具欄位于自定義插件面板中最左側(cè)的位置,用于設(shè)置自選股票代碼。 通過在方法 actionPerformed
中使用 ShowSettingsUtil
工具類啟動 UI 窗體。 3.2 刷新-工具欄cn.bugstack.guide.idea.plugin.module.RefreshBar
public class RefreshBar extends DumbAwareAction { private ViewBars panel; public RefreshBar (ViewBars panel) { super ("刷新指數(shù)" , "Click to refresh" , IconLoader.getIcon("/icons/refresh.svg" )); this .panel = panel; } @Override public void actionPerformed (@NotNull AnActionEvent e) { panel.getConsoleUI().addRows(DataSetting.getInstance().getGids()); } }
在刷新工具欄中主要是用于手動觸發(fā)刷新股票最新結(jié)果,之所以使用手動刷新主要是這個接口有查詢次數(shù)限制,如果是定時任務(wù)一直跑,一會100次的查詢限制就用完了。不過我們這里也是為了體現(xiàn)專欄內(nèi)對技術(shù)的使用,增加多個設(shè)置按鈕,就更容易知道如何添加了 3.3 窗體填充面板cn.bugstack.guide.idea.plugin.module.ViewBars
public class ViewBars extends SimpleToolWindowPanel { private Project project; private ConsoleUI consoleUI; public ViewBars (Project project) { super (false , true ); this .project = project; consoleUI = new ConsoleUI(); // 設(shè)置窗體側(cè)邊欄按鈕 DefaultActionGroup group = new DefaultActionGroup(); group.add(new SettingBar(this )); group.add(new RefreshBar(this )); ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar("bar" , group, false ); toolbar.setTargetComponent(this ); setToolbar(toolbar.getComponent()); // 添加 JBSplitter splitter = new JBSplitter(false ); splitter.setSplitterProportionKey("main.splitter.key" ); splitter.setFirstComponent(consoleUI.getPanel()); splitter.setProportion(0.3f ); setContent(splitter); } public Project getProject () { return project; } public ConsoleUI getConsoleUI () { return consoleUI; } }
在填充面板中主要是在我們自定義的插件中,在左側(cè)添加工具欄,其余位置添加股票展示面板。 DefaultActionGroup
中可以以此添加設(shè)置和刷新按鈕,并最終填充到 ActionToolbar
里去,這樣就設(shè)置完成了。JBSplitter
是一個分割線,右側(cè)填充上我們的股票指數(shù)展示面板 splitter.setFirstComponent(consoleUI.getPanel())
4. 填充主面板到IDEA工具欄 4.1 窗體工廠cn.bugstack.guide.idea.plugin.factory.TabFactory
public class TabFactory implements ToolWindowFactory { @Override public void createToolWindowContent (@NotNull Project project, @NotNull ToolWindow toolWindow) { // 窗體 ViewBars viewPanel = new ViewBars(project); // 獲取內(nèi)容工廠的實例 ContentFactory contentFactory = ContentFactory.SERVICE.getInstance(); // 獲取 ToolWindow 顯示的內(nèi)容 Content content = contentFactory.createContent(viewPanel, "股票" , false ); // 設(shè)置 ToolWindow 顯示的內(nèi)容 toolWindow.getContentManager().addContent(content, 0 ); // 定時任務(wù),自動刷新股票 /* 因每日查詢次數(shù)限制,這里就不開定時任務(wù)了,用戶可以自行申請 https://dashboard./home Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { viewPanel.getConsoleUI().addRows(DataSetting.getInstance().getGids()); } }, 3000, 2000);*/ } }
在 TabFactory 中主要包括兩部分,一個是把 ViewBars 填充到整個 toolWindow 中,另外一個是我們目前已經(jīng)注釋掉的刷新股票數(shù)據(jù)的定時任務(wù)。 這里由于股票接口查詢次數(shù)限制,所以就把定時任務(wù)注釋掉了,否則一會就把可用次數(shù)跑沒了。 4.2 配置窗體plugin.xml
<idea-plugin > <extensions defaultExtensionNs ="com.intellij" > <!-- Add your extensions here --> <toolWindow id ="XUtil" canCloseContents ="true" anchor ="bottom" factoryClass ="cn.bugstack.guide.idea.plugin.factory.TabFactory" icon ="/icons/stock.png" /> </extensions > </idea-plugin >
這里我們把窗體配置到整個 IDEA 界面的最下方 anchor="bottom"
這個位置既方便又最安全 5. 數(shù)據(jù)持久化配置當我們使用 IDEA 進行配置一些基本參數(shù)后,例如:Maven、Gradle、Git、簽名信息等,在日常的關(guān)閉和重啟 IDEA 時,這些配置信息是會保存下來的,而不會說關(guān)閉就沒了。 那么我們開發(fā)的這款插件需要做的一些自選股票代碼配置,也要進行保存,否則不能每次都在 IDEA 啟動時重新設(shè)置。所以這里我們需要用到 plugin.xml
中 applicationService
配置上實現(xiàn)了 PersistentStateComponent
的數(shù)據(jù)設(shè)置存放類。 5.1 對象數(shù)據(jù)cn.bugstack.guide.idea.plugin.infrastructure.DataState
public class DataState { private List<String> gids = new ArrayList<>(); public List<String> getGids () { return gids; } public void setGids (List<String> gids) { this .gids = gids; } }
這個是數(shù)據(jù)對象類,你可以在這里設(shè)置你需要的屬性存放,就像 gids 一樣,用于存放用戶配置的股票代碼集合。 5.2 持久數(shù)據(jù)cn.bugstack.guide.idea.plugin.infrastructure.DataSetting
@State (name = "DataSetting" ,storages = @Storage ("plugin.xml" ))public class DataSetting implements PersistentStateComponent <DataState > { private DataState state = new DataState(); public static DataSetting getInstance () { return ServiceManager.getService(DataSetting.class ) ; } @Nullable @Override public DataState getState () { return state; } @Override public void loadState (@NotNull DataState state) { this .state = state; } public List<String> getGids () { return state.getGids(); } }
DataSetting 類需要使用到 IDEA 插件開發(fā)的提供的注解 @State 配置持久對象 此外還需要提供一個 getInstance 方法來獲取數(shù)據(jù)對象實例,那么在我們實際使用的時候就可以拿到我們配置的對象了并進行設(shè)置和讀取數(shù)據(jù)。 5.3 plugin.xml 配置<extensions defaultExtensionNs ="com.intellij" > <!-- Add your extensions here --> <applicationService serviceImplementation ="cn.bugstack.guide.idea.plugin.infrastructure.DataSetting" /> </extensions >
在創(chuàng)建好數(shù)據(jù)設(shè)置類以后,則需要使用 applicationService 標簽把你的類配置到 plugin.xml 中 extensions 里面。 6. 股票接口 6.1 技術(shù)調(diào)研無論什么功能開發(fā),在開始之前都需要把這些零碎的事情
處理完,才能進行代碼開發(fā),這個過程也叫做技術(shù)調(diào)研到設(shè)計和評審。就像現(xiàn)在我們需要進行股票信息的查詢,那么就需要找到一個可以提供數(shù)據(jù)查詢的接口,看看這個接口如何申請使用,以及返回的對象都有哪些字段,是否符合我們的預期。
這里小傅哥找到了一個聚合數(shù)據(jù)的接口,不過只能免費100次/天
調(diào)用,如果你有更好的可以更換下。
接口:http://web.:8080/finance/stock/hs?gid=sz000651&key=自己申請 - 這里的 key 需要自己申請
數(shù)據(jù):
6.2 服務(wù)封裝有了股票的查詢接口,接下來就可以對數(shù)據(jù)做一個查詢和對象轉(zhuǎn)換了。
cn.bugstack.guide.idea.plugin.domain.service.impl.StockImpl
public class StockImpl implements IStock { // 自行申請,股票API,替換key即可【一天可免費調(diào)用100次】:https://dashboard./home/ private final String key = "4bc57728***********f0595" ; @Override public List<Data> queryPresetStockData (List<String> gids) { List<Data> dataList = new ArrayList<>(); for (String gid : gids) { StockResult stockResult = JSON.parseObject(HttpUtil.get("http://web.:8080/finance/stock/hs?gid=" + gid + "&key=" + key), StockResult.class ) ; Stock[] stocks = stockResult.getResult(); for (Stock stock : stocks) { dataList.add(stock.getData()); } } return dataList; } }
這里我們在 domain 領(lǐng)域?qū)又卸x數(shù)據(jù) vo 對象,以及提供股票查詢服務(wù)的封裝。這樣調(diào)用方就可以直接使用這份數(shù)據(jù)了,如果你是其他廠商提供的股票查詢接口,也可以進行封裝和更換,做一個接口適配層。 四、測試驗證 如果你下載工程后沒有 Plugin 和一個綠色箭頭,那么可以按照圖自己配置 :runIde
這樣就可以運行了。 運行效果 - 激動人心的時刻到了,再也不用擔心寫代碼影響看股票了哦
1. 配置股票首先你需要在這里配置你關(guān)注的股票代碼,我配置了3個我看好的。 2. 自選股指數(shù)配置好以后你就可以看到自己的自選股指數(shù)了,選中一條以后,在點擊K線。 當你需要看最新數(shù)據(jù)的時候,可以點左側(cè)的刷新按鈕。 3. K線現(xiàn)在這個就是對應的 K線,是不是還挺香的。目前是加了最近K線和日K線,你還可以擴展其他維度的圖。 五、總結(jié) 本章節(jié)我們使用到了在 IDEA 窗體中添加稍微復雜一些的頁面結(jié)構(gòu),有側(cè)邊欄、有Tab頁,并在需要在這些頁面體中進行交互和通信。此外還是用到了數(shù)據(jù)的存儲設(shè)置,這個在很多時候開發(fā)IDEA插件里都會用到。 像是這樣的技術(shù)實踐不只是可以用于展示股票數(shù)據(jù),你還可以結(jié)合自己所需擴展屬于你實際場景中需要的內(nèi)容,比如開發(fā)一個數(shù)據(jù)集中查詢插件,可以查詢數(shù)據(jù)庫、ES、Redis等,也可以是所有的工具類集合頁,這些內(nèi)容會更有技術(shù)價值。 當你自己開始主動的向你學習到的一些源碼、框架、組件、項目等中添加自己想要的功能時,就是你真的開始學習了,否則一個內(nèi)容看過沒多久也就忘記了。 六、系列推薦