基于IDEA Plugin插件开发,撸一个DDD脚手架
作者:小傅哥
博客:https://bugstack.cn
沉淀、分享、成長,讓自己和他人都能有所收獲!😄
- 最近很感興趣結合 IDEA Plugin 開發能力,擴展各項功能。也基于此使用不同的案例,探索 IDEA Plugin 插件開發技術。希望這樣的成體系學習和驗證總結,能給更多需要此技術的伙伴,帶來幫助。
- 源碼地址:https://github.com/fuzhengwei/CodeGuide#1-%E6%BA%90%E7%A0%81
一、前言
研發,要避免自嗨!
你做這個東西的價值是什么?有競品調研嗎?能賦能業務嗎?那不已經有同類的了,你為什么還自己造輪子?
你是不是也會被問到這樣的問題,甚至可能還有些頭疼。但做的時候挺嗨,研究技術嘛,還落地了,多刺激。不過要說價值,好像一時半會還體現不出來,能不能賦能業務就不更不一定了。
可誰又能保證以后不能呢,技術的點是一個個攻克嘗試的才有機會再深度學習后把這些內容連成一片,就像單說水、單說沙子、單說泥巴,好像并沒有啥用,但把它們湊到一塊再給把火,就燒成了磚,磚就碼成了墻,墻就蓋成房。
二、需求目的
我們這一章節把 freemarker 能力與 IDEA Plugin 插件能力結合,開發一個DDD 腳手架 IDEA 插件,可能你會想為什么要把腳手架開發到插件里呢?還有不是已經有了成型的腳手架可以用嗎?
首先我們目前看到的腳手架基本都是網頁版的,也就是一次性創建工程使用,不過在我們實際使用的時候,還希望在工程創建過程中把數據庫、ES、Redis等生成對應的 ORM 代碼,減少開發工作量。并且在使用的工程骨架的過程中,還希望可以隨著開發需要再次補充新的功能進去,這個時候網頁版的腳手架都不能很好的支持了。此外一些大廠都會自己的技術體系,完全是使用市面的腳手架基本很難滿足自身的需求,所以就需要有一個符合自己場景的腳手架了。
那么,我們本章節就把腳手架的開發放到 IDEA 插件開發中,一方面學習腳手架的建設,另外一方面學習如何改變工程向導,創建出自己需要的DDD結構腳手架。
三、案例開發
1. 工程結構
guide-idea-plugin-scaffolding ├── .gradle └── src├── main│ └── java│ └── cn.bugstack.guide.idea.plugin │ ├── domain│ │ ├── model │ │ │ └── ProjectConfigVO.java │ │ └── service │ │ ├── impl │ │ │ └── ProjectGeneratorImpl.java │ │ ├── AbstractProjectGenerator.java │ │ ├── FreemarkerConfiguration.java │ │ └── IProjectGenerator.java │ ├── factory│ │ └── TemplateFactory.java │ ├── infrastructure│ │ ├── DataSetting.java │ │ ├── DataState.java │ │ ├── ICONS.java │ │ └── MsgBundle.java │ ├── module │ │ ├── DDDModuleBuilder.java │ │ └── DDDModuleConfigStep.java │ └── ui│ ├── ProjectConfigUI.java │ └── ProjectConfigUI.form├── resources│ ├── META-INF│ │ └── plugin.xml │ └── template│ ├── pom.ftl│ └── yml.ftl ├── build.gradle └── gradle.properties源碼獲取:#公眾號:bugstack蟲洞棧 回復:idea 即可下載全部 IDEA 插件開發源碼
在此 IDEA 插件工程中,主要分為5塊區域:
- domain:領域層,提供創建 DDD 模板工程的服務,其實這部分主要使用的就是 freemarker
- factory:工廠層,提供工程創建模板,這一層的作用就是我們在 IDEA 中創建新工程的時候,可以添加上我們自己的內容,也就是創建出我們定義好的 DDD 工程結構。
- infrastructure:基礎層,提供數據存放、圖片加載、信息映射這些功能。
- module:模塊層,提供 DDD 模板工程的創建具體操作和步驟,也就是說我們創建工程的時候是一步步選擇的,你可以按需添加自己的步驟頁面,允許用戶選擇和添加自己需要的內容。比如你需要連庫、選擇表、添加工程所需要的技術棧等
- ui:界面層,提供Swing 開發的 UI 界面,用于用戶圖形化選擇和創建。
2. UI 工程配置窗體
public class ProjectConfigUI {private JPanel mainPanel;private JTextField groupIdField;private JTextField artifactIdField;private JTextField versionField;private JTextField packageField;}- 使用 Swing UI Designer 創建一個配置工廠信息的 UI 窗體,通過這樣的方式創建可以直接拖拽。
- 在這個 UI 窗體中我們主要需要;roupId、artifactId、version、package
3. 配置工程步驟創建
3.1 數據存放
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@Overridepublic DataState getState() {return state;}@Overridepublic void loadState(@NotNull DataState state) {this.state = state;}public ProjectConfigVO getProjectConfig(){return state.getProjectConfigVO();}}- 在基礎層提供數據存放的服務,把創建工程的配置信息存放到服務中,這樣比較方便設置和獲取。
3.2 擴展步驟
cn.bugstack.guide.idea.plugin.module.DDDModuleConfigStep
public class DDDModuleConfigStep extends ModuleWizardStep {private ProjectConfigUI projectConfigUI;public DDDModuleConfigStep(ProjectConfigUI projectConfigUI) {this.projectConfigUI = projectConfigUI;}@Overridepublic JComponent getComponent() {return projectConfigUI.getComponent();}@Overridepublic boolean validate() throws ConfigurationException {// 獲取配置信息,寫入到 DataSettingProjectConfigVO projectConfig = DataSetting.getInstance().getProjectConfig();projectConfig.set_groupId(projectConfigUI.getGroupIdField().getText());projectConfig.set_artifactId(projectConfigUI.getArtifactIdField().getText());projectConfig.set_version(projectConfigUI.getVersionField().getText());projectConfig.set_package(projectConfigUI.getPackageField().getText());return super.validate();}}- 繼承 ModuleWizardStep 開發一個自己需要的步驟,這個步驟就會出現到我們創建新的工程中。
- 同時在重寫的 validate 方法中,把從工程配置 UI 窗體中獲取到信息,寫入到數據配置文件中。
3.3 配置步驟
cn.bugstack.guide.idea.plugin.module.DDDModuleBuilder
public class DDDModuleBuilder extends ModuleBuilder {private IProjectGenerator projectGenerator = new ProjectGeneratorImpl();@Overridepublic Icon getNodeIcon() {return ICONS.SPRING_BOOT;}/*** 重寫 builderId 掛載自定義模板*/@Nullable@Overridepublic String getBuilderId() {return getClass().getName();}@Overridepublic ModuleWizardStep[] createWizardSteps(@NotNull WizardContext wizardContext, @NotNull ModulesProvider modulesProvider) {// 添加工程配置步驟,可以自己定義需要的步驟,如果有多個可以依次添加DDDModuleConfigStep moduleConfigStep = new DDDModuleConfigStep(new ProjectConfigUI());return new ModuleWizardStep[]{moduleConfigStep};} }- 在 createWizardSteps 方法中,把我們已經創建好的 DDDModuleConfigStep 添加工程配置步驟,可以自己定義需要的步驟,如果有多個可以依次添加。
- 同時需要注意,只有重寫了 getBuilderId() 方法后,你新增加的向導步驟才能生效。
4. 開發腳手架服務
cn.bugstack.guide.idea.plugin.domain.service.AbstractProjectGenerator
public abstract class AbstractProjectGenerator extends FreemarkerConfiguration implements IProjectGenerator {@Overridepublic void doGenerator(Project project, String entryPath, ProjectConfigVO projectConfig) {// 1.創建工程主POM文件generateProjectPOM(project, entryPath, projectConfig);// 2.創建四層架構generateProjectDDD(project, entryPath, projectConfig);// 3.創建 ApplicationgenerateApplication(project, entryPath, projectConfig);// 4. 創建 YmlgenerateYml(project, entryPath, projectConfig);// 5. 創建 CommongenerateCommon(project, entryPath, projectConfig);}}- 在 domain 領域層添加用于創建腳手架框架的 FreeMarker 服務,它是一款 模板引擎: 即一種基于模板和要改變的數據, 并用來生成輸出文本(HTML網頁,電子郵件,配置文件,源代碼等)的通用工具。FreeMarker 在線手冊:http://freemarker.foofun.cn
- 按照 DDD 工程結構,分層包括:application、domain、infrastructure、interfaces,那么我們把這些創建過程抽象到模板方法中,具體交給子類來創建。
5. 調用腳手架服務
cn.bugstack.guide.idea.plugin.module.DDDModuleBuilder
public class DDDModuleBuilder extends ModuleBuilder {private IProjectGenerator projectGenerator = new ProjectGeneratorImpl();@Overridepublic Icon getNodeIcon() {return ICONS.SPRING_BOOT;}@Overridepublic void setupRootModel(@NotNull ModifiableRootModel rootModel) throws ConfigurationException {// 設置 JDKif (null != this.myJdk) {rootModel.setSdk(this.myJdk);} else {rootModel.inheritSdk();}// 生成工程路徑String path = FileUtil.toSystemIndependentName(Objects.requireNonNull(getContentEntryPath()));new File(path).mkdirs();VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(path);rootModel.addContentEntry(virtualFile);Project project = rootModel.getProject();// 創建工程結構Runnable r = () -> new WriteCommandAction<VirtualFile>(project) {@Overrideprotected void run(@NotNull Result<VirtualFile> result) throws Throwable {projectGenerator.doGenerator(project, getContentEntryPath(), DataSetting.getInstance().getProjectConfig());}}.execute();}}- 在 DDDModuleBuilder#setupRootModel 中,添加創建 DDD工程框架的服務,projectGenerator.doGenerator(project, getContentEntryPath(), DataSetting.getInstance().getProjectConfig());
- 另外這里需要用到 IDEA 提供的線程調用方法,new WriteCommandAction 才能正常創建。
6. 配置模板工程
6.1 模板工廠
cn.bugstack.guide.idea.plugin.factory.TemplateFactory
public class TemplateFactory extends ProjectTemplatesFactory {@NotNull@Overridepublic String[] getGroups() {return new String[]{"DDD腳手架"};}@Overridepublic Icon getGroupIcon(String group) {return ICONS.DDD;}@NotNull@Overridepublic ProjectTemplate[] createTemplates(@Nullable String group, WizardContext context) {return new ProjectTemplate[]{new BuilderBasedTemplate(new DDDModuleBuilder())};}}- 模板工廠的核心在于把我們用于創建 DDD 的步驟添加 createTemplates 方法中,這樣算把整個創建自定義腳手架工程的鏈路就串聯完成了。
6.2 文件配置
plugin.xml
<idea-plugin><id>cn.bugstack.guide.idea.plugin.guide-idea-plugin-scaffolding</id><name>Scaffolding</name><vendor email="184172133@qq.com" url="https://bugstack.cn">小傅哥</vendor><!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.htmlon how to target different products --><depends>com.intellij.modules.platform</depends><extensions defaultExtensionNs="com.intellij"><projectTemplatesFactory implementation="cn.bugstack.guide.idea.plugin.factory.TemplateFactory"/><applicationService serviceImplementation="cn.bugstack.guide.idea.plugin.infrastructure.DataSetting"/></extensions></idea-plugin>- 接下來還需要把我們創建的工程模板以及數據服務配置到 plugin.xml 中,這樣在插件啟動的時候就可以把我們自己插件啟動起來了。
四、測試驗證
- 點擊 Plugin 啟動 IDEA 插件,之后創建工程如下:
- 快拿去試試吧,啟動插件,點擊創建工程,傻瓜式點擊,就可以創建出一個 DDD 工程結構了。
五、總結
- 學習使用 IDEA Plugin 開發技術,改變創建工程向導,添加自己需要的工程創建模板,這樣就可以創建出一個 DDD 腳手架工程骨架了,接下來你還可以結合自己實際的業務場景添加自己需要的一些技術棧到腳手架中。
- 如果你愿意嘗試可以在工程創建中鏈接到數據庫,把數據庫中對應的表生成Java代碼,這樣一些簡單的配置、查詢、映射,就不用自己動手寫了。
- 在開發 DDD 腳手架的源碼中還有一些細節過程,包括圖標的展示、文案的信息、Freemarker的使用細節,這些你都可以在源碼中學習并調試驗證。
六、系列推薦
- 使用 Freemarker,創建 SpringBoot 腳手架
- 發布Jar包到Maven中央倉庫(為開發開源中間件做準備)
- DDD 領域層決策規則樹服務設計
- 工作兩三年了,整不明白架構圖都畫啥?
- CodeGuide Github 倉庫開源啦!
總結
以上是生活随笔為你收集整理的基于IDEA Plugin插件开发,撸一个DDD脚手架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 云服务器防火墙关闭 tomcat不能正常
- 下一篇: 闲谈绩效考核——来自项目管理群的讨论[转