作者:小傅哥 博客:https:bugstack。cn 沉淀、分享、成长,让自己和他人都能有所收获! Spring有一个脚手架https:start。spring。io阿里云也有一个脚手架https:start。aliyun。com但这些脚手架都是在网页端的,虽然也能在IntelliJIDEA进行使用,但总是不太方便。为此我决定,基于IntelliJIDEA的插件开发技术,扩展创建工程向导步骤,开发一个我用起来方便的工程脚手架。行动是产生结果的唯一方式!一、前言 研发,要避免自嗨! 你做这个东西的价值是什么?有竞品调研吗?能赋能业务吗?那不已经有同类的了,你为什么还自己造轮子? 你是不是也会被问到这样的问题,甚至可能还有些头疼。但做的时候挺嗨,研究技术嘛,还落地了,多刺激。不过要说价值,好像一时半会还体现不出来,能不能赋能业务就不更不一定了。 可谁又能保证以后不能呢,技术的点是一个个攻克尝试的才有机会再深度学习后把这些内容连成一片,就像单说水、单说沙子、单说泥巴,好像并没有啥用,但把它们凑到一块再给把火,就烧成了砖,砖就码成了墙,墙就盖成房。二、需求目的 我们这一章节把freemarker能力与IDEAPlugin插件能力结合,开发一个DDD脚手架IDEA插件,可能你会想为什么要把脚手架开发到插件里呢?还有不是已经有了成型的脚手架可以用吗? 首先我们目前看到的脚手架基本都是网页版的,也就是一次性创建工程使用,不过在我们实际使用的时候,还希望在工程创建过程中把数据库、ES、Redis等生成对应的ORM代码,减少开发工作量。并且在使用的工程骨架的过程中,还希望可以随着开发需要再次补充新的功能进去,这个时候网页版的脚手架都不能很好的支持了。此外一些大厂都会自己的技术体系,完全是使用市面的脚手架基本很难满足自身的需求,所以就需要有一个符合自己场景的脚手架了。 那么,我们本章节就把脚手架的开发放到IDEA插件开发中,一方面学习脚手架的建设,另外一方面学习如何改变工程向导,创建出自己需要的DDD结构脚手架。三、案例开发1。工程结构guideideapluginscaffolding。gradlesrcmainjavacn。bugstack。guide。idea。plugindomainmodelProjectConfigVO。javaserviceimplProjectGeneratorImpl。javaAbstractProjectGenerator。javaFreemarkerConfiguration。javaIProjectGenerator。javafactoryTemplateFactory。javainfrastructureDataSetting。javaDataState。javaICONS。javaMsgBundle。javamoduleDDDModuleBuilder。javaDDDModuleConfigStep。javauiProjectConfigUI。javaProjectConfigUI。formresourcesMETAINFplugin。xmltemplatepom。ftlyml。ftlbuild。gradlegradle。properties 公众号:bugstack虫洞栈回复:idea即可下载工程源码 在此IDEA插件工程中,主要分为5块区域:domain:领域层,提供创建DDD模板工程的服务,其实这部分主要使用的就是freemarkerfactory:工厂层,提供工程创建模板,这一层的作用就是我们在IDEA中创建新工程的时候,可以添加上我们自己的内容,也就是创建出我们定义好的DDD工程结构。infrastructure:基础层,提供数据存放、图片加载、信息映射这些功能。module:模块层,提供DDD模板工程的创建具体操作和步骤,也就是说我们创建工程的时候是一步步选择的,你可以按需添加自己的步骤页面,允许用户选择和添加自己需要的内容。比如你需要连库、选择表、添加工程所需要的技术栈等ui:界面层,提供Swing开发的UI界面,用于用户图形化选择和创建。2。UI工程配置窗体 publicclassProjectConfigUI{privateJPanelmainPanel;privateJTextFieldgroupIdField;privateJTextFieldartifactIdField;privateJTextFieldversionField;privateJTextFieldpackageField;}使用SwingUIDesigner创建一个配置工厂信息的UI窗体,通过这样的方式创建可以直接拖拽。在这个UI窗体中我们主要需要;roupId、artifactId、version、package3。配置工程步骤创建3。1数据存放 cn。bugstack。guide。idea。plugin。infrastructure。DataSettingState(nameDataSetting,storagesStorage(plugin。xml))publicclassDataSettingimplementsPersistentStateComponentDataState{privateDataStatestatenewDataState();publicstaticDataSettinggetInstance(){returnServiceManager。getService(DataSetting。class);}NullableOverridepublicDataStategetState(){returnstate;}OverridepublicvoidloadState(NotNullDataStatestate){this。statestate;}publicProjectConfigVOgetProjectConfig(){returnstate。getProjectConfigVO();}}在基础层提供数据存放的服务,把创建工程的配置信息存放到服务中,这样比较方便设置和获取。3。2扩展步骤 cn。bugstack。guide。idea。plugin。module。DDDModuleConfigSteppublicclassDDDModuleConfigStepextendsModuleWizardStep{privateProjectConfigUIprojectConfigUI;publicDDDModuleConfigStep(ProjectConfigUIprojectConfigUI){this。projectConfigUIprojectConfigUI;}OverridepublicJComponentgetComponent(){returnprojectConfigUI。getComponent();}Overridepublicbooleanvalidate()throwsConfigurationException{获取配置信息,写入到DataSettingProjectConfigVOprojectConfigDataSetting。getInstance()。getProjectConfig();projectConfig。setgroupId(projectConfigUI。getGroupIdField()。getText());projectConfig。setartifactId(projectConfigUI。getArtifactIdField()。getText());projectConfig。setversion(projectConfigUI。getVersionField()。getText());projectConfig。setpackage(projectConfigUI。getPackageField()。getText());returnsuper。validate();}}继承ModuleWizardStep开发一个自己需要的步骤,这个步骤就会出现到我们创建新的工程中。同时在重写的validate方法中,把从工程配置UI窗体中获取到信息,写入到数据配置文件中。3。3配置步骤 cn。bugstack。guide。idea。plugin。module。DDDModuleBuilderpublicclassDDDModuleBuilderextendsModuleBuilder{privateIProjectGeneratorprojectGeneratornewProjectGeneratorImpl();OverridepublicIcongetNodeIcon(){returnICONS。SPRINGBOOT;}重写builderId挂载自定义模板NullableOverridepublicStringgetBuilderId(){returngetClass()。getName();}OverridepublicModuleWizardStep〔〕createWizardSteps(NotNullWizardContextwizardContext,NotNullModulesProvidermodulesProvider){添加工程配置步骤,可以自己定义需要的步骤,如果有多个可以依次添加DDDModuleConfigStepmoduleConfigStepnewDDDModuleConfigStep(newProjectConfigUI());returnnewModuleWizardStep〔〕{moduleConfigStep};}}在createWizardSteps方法中,把我们已经创建好的DDDModuleConfigStep添加工程配置步骤,可以自己定义需要的步骤,如果有多个可以依次添加。同时需要注意,只有重写了getBuilderId()方法后,你新增加的向导步骤才能生效。4。开发脚手架服务 cn。bugstack。guide。idea。plugin。domain。service。AbstractProjectGenerator publicabstractclassAbstractProjectGeneratorextendsFreemarkerConfigurationimplementsIProjectGenerator{OverridepublicvoiddoGenerator(Projectproject,StringentryPath,ProjectConfigVOprojectConfig){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。DDDModuleBuilderpublicclassDDDModuleBuilderextendsModuleBuilder{privateIProjectGeneratorprojectGeneratornewProjectGeneratorImpl();OverridepublicIcongetNodeIcon(){returnICONS。SPRINGBOOT;}OverridepublicvoidsetupRootModel(NotNullModifiableRootModelrootModel)throwsConfigurationException{设置JDKif(null!this。myJdk){rootModel。setSdk(this。myJdk);}else{rootModel。inheritSdk();}生成工程路径StringpathFileUtil。toSystemIndependentName(Objects。requireNonNull(getContentEntryPath()));newFile(path)。mkdirs();VirtualFilevirtualFileLocalFileSystem。getInstance()。refreshAndFindFileByPath(path);rootModel。addContentEntry(virtualFile);ProjectprojectrootModel。getProject();创建工程结构Runnabler()newWriteCommandActionVirtualFile(project){Overrideprotectedvoidrun(NotNullResultVirtualFileresult)throwsThrowable{projectGenerator。doGenerator(project,getContentEntryPath(),DataSetting。getInstance()。getProjectConfig());}}。execute();}}在DDDModuleBuildersetupRootModel中,添加创建DDD工程框架的服务,projectGenerator。doGenerator(project,getContentEntryPath(),DataSetting。getInstance()。getProjectConfig());另外这里需要用到IDEA提供的线程调用方法,newWriteCommandAction才能正常创建。6。配置模板工程6。1模板工厂 cn。bugstack。guide。idea。plugin。factory。TemplateFactorypublicclassTemplateFactoryextendsProjectTemplatesFactory{NotNullOverridepublicString〔〕getGroups(){returnnewString〔〕{DDD脚手架};}OverridepublicIcongetGroupIcon(Stringgroup){returnICONS。DDD;}NotNullOverridepublicProjectTemplate〔〕createTemplates(NullableStringgroup,WizardContextcontext){returnnewProjectTemplate〔〕{newBuilderBasedTemplate(newDDDModuleBuilder())};}}模板工厂的核心在于把我们用于创建DDD的步骤添加createTemplates方法中,这样算把整个创建自定义脚手架工程的链路就串联完成了。6。2文件配置 plugin。xmlideapluginidcn。bugstack。guide。idea。plugin。guideideapluginscaffoldingidnameScaffoldingnamevendoremail184172133qq。comurlhttps:bugstack。cn小傅哥vendor!pleaseseehttp:www。jetbrains。orgintellijsdkdocsbasicsgettingstartedplugincompatibility。htmlonhowtotargetdifferentproductsdependscom。intellij。modules。platformdependsextensionsdefaultExtensionNscom。intellijprojectTemplatesFactoryimplementationcn。bugstack。guide。idea。plugin。factory。TemplateFactoryextensionsideaplugin接下来还需要把我们创建的工程模板以及数据服务配置到plugin。xml中,这样在插件启动的时候就可以把我们自己插件启动起来了。四、测试验证点击Plugin启动IDEA插件,之后创建工程如下: 快拿去试试吧,启动插件,点击创建工程,傻瓜式点击,就可以创建出一个DDD工程结构了。五、总结学习使用IDEAPlugin开发技术,改变创建工程向导,添加自己需要的工程创建模板,这样就可以创建出一个DDD脚手架工程骨架了,接下来你还可以结合自己实际的业务场景添加自己需要的一些技术栈到脚手架中。如果你愿意尝试可以在工程创建中链接到数据库,把数据库中对应的表生成Java代码,这样一些简单的配置、查询、映射,就不用自己动手写了。在开发DDD脚手架的源码中还有一些细节过程,包括图标的展示、文案的信息、Freemarker的使用细节,这些你都可以在源码中学习并调试验证。