开源源码,项目下载地址https://gitee.com/lowcode2/ailowcode.git
AI辅助开发和测试(IDEA插件)
AI辅助开发和测试功能,是通过开发一款AI低代码IDEA插件来实现。插件入口:IDEA主菜单/AI低代码/…,右击菜单/AI低代码/…。插件功能分:AI辅助开发和AI辅助测试。
AI辅助开发:通过调用AI接口获取系统基本信息,再通过源码模板,生成统一标准的源代码。AI辅助开发功能,由初始化系统、逆向生成代码和添加字段3个子菜单组成,子菜单功能如下:
-
- 初始化系统:是通过输入一个系统名称,由AI自动生成系统模型和数据库表,然后通过逆向工具技术生成前后端代码。
- 逆向生成代码:是数据库已存在表的情况下,通过输入表名,然后通过逆向工具技术生成表对应的前后端代码。
- 添加字段:是在插件页面输入新增加的字段信息,一方面向数据库表自动添加字段,另一方面在对应的类文件中添加字段相关代码。
AI辅助测试:通过调用AI接口获取测试对象基本信息,再通过系统处理,生成测试用例,提供API接口测试使用。AI辅助测试由接口测试和API按组批量测试2个子菜单组成,子菜单功能如下:
- 接口测试:是通过右击需要测试的控制类方法,点击右击菜单中接口测试子菜单,打开接口测试对话框。接口测试中可以通过AI自动生成测试用例,然后通过HTTP调用接口完成测试。
- API按组批量测试:是对保存的接口信息进行分组批量执行。详细使用方法见后续介绍。
(一)操作手册
1. IDEA插件安装
1)安装方法
插件文件路径:项目目录/aicodefile/plugin/ailowcode-plugin-1.1.zip,安装方法:
1)打开IDEA settings窗口,点击Plugins菜单,选择从磁盘安装“Install Plugin from Disk…”,选择ailowcode-plugin-1.1.zip文件,如下图所示:
2)安装完成后,确保一下Installed标签页面中插件AILowcode已安装完成,并且是勾中状态,最后,重启IDEA。重新打开IDEA后,工具栏会多出来一个菜单:AI低代码,则表示安装成功。
提示:
在IntelliJ IDEA中,Settings的位置取决于操作系统。
如何打开Settings窗口?
Windows/Linux: 点击左上角的
File
菜单,然后选择Settings
。macOS: 从菜单栏中选择
IntelliJ IDEA
,然后选择Preferences
。
2)AI辅助开发和测试插件生成源码涉及的配置文件说明
IDEA辅助开发和测试插件依赖的文件信息:/ailowcode/aicodefile/*,如下图所示。plugin目录下存放的是IDEA辅助开发和测试的插件安装文件(可本地直接安装)。template目录下存放的是源码生成模板,其中java目录是后端源码生成模板,vue目录是前端源码生成模板,test目录是开发测试使用的模板(仅测试用)。/tastcase/single/目录是单个接口测试报告存放目录。/tastcase/group/目录是API按组批量测试报告存放目录。aicode.properties是IDEA插件运行使用的AI辅助开发配置文件。
AI辅助开发配置文件:IDEA插件在执行时需要调用AI接口、连接数据库、源码生成模板等,相关配置信息配置在配置文件中,配置文件路径:/项目根目录/aicodefile/aicode.properties,如下所示:
- 1. #baidu qian fan
- 2. client_id = xxxxxx
- 3. client_secret = xxxxxx
- 4. api_url = https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-......
- 5.
- 6. # jdbc
- 7. jdbcDriver = com.mysql.cj.jdbc.Driver
- 8. jdbcUrl = jdbc:mysql://127.0.0.1:3309/db_lowcode?......
- 9. username = ……
- 10. password = ……
- 11.
- 12. # 前端文件存放目录
- 13. outputVueDirProj = /lowcode2-ui
- 14. # 后端文件存放目录
- 15. outputJavaDirProj = /lowcode2/flow
- 16. javaDir=/src/main/java
- 17. packagePath=/com/wxy/ej/flow/modules
- 18. contextPath=flow
- 19. module=sap
- 20.
- 21. # 源码生成模板结构说明
- 22. #前端vue模板,会在路径后创建一个表实例对象的目录
- 23. ftlVue=[\
- 24. {"ftl":"/template/vue/list.vue.ftl", "suffixPath":"list.vue", "fullPath":""},\
- 25. ......
- 26. ]
- 27. #后端java模板
- 28. ftlJava=[\
- 29. {"ftl":"/template/java/dto.java.ftl", "codeLastPath":"dto","suffixPath":"%sDto.java", "fullPath":""},\
- 30. ......
- 31. ]
- 32. #后端资源文件xml模板
- 33. ftlXml=[\
- 34. {"ftl":"/template/java/mapper.xml.ftl", "suffixPath":"%sMapper.xml", "fullPath":""},\
- 35. ]
- 36.
- 37. #自定义模板; 当isCreateEntityDir=true时,会在路径后创建一个表实例对象的目录
- 38. ftlAny=[\
- 39. {"ftl":"/template/test/test.java.ftl", "isCreateEntityDir":false, "suffixPath":"%sTest.java", \
- 40. ......
- 41. ]
- 42.
- 43. # AI提问模板:系统结构
- 44. question_structure=你是一位数据库设计师......
- 45.
- 46. # AI提问模板:表sql
- 47. question_table=你是一个数据库设计师......
- 48.
- 49. ### 单元测试 ##############################
- 50. host_testCase = http://127.0.0.1:9900/flow
- 51. # AI提问模板:测试用例
- 52. question_testCase=你是一名软件测试工程师......
AI辅助开发配置文件(aicode.properties)各项说明,如下表所示:
配置字段名称 | 说明 |
百度千帆(AI) | |
client_id | 对应千帆的API KEY |
client_secret | 对应千帆的Secret Key |
api_url | 百度千帆API调用地址 |
数据库连接(JDBC) | |
jdbcDriver | Jdbc驱动 |
jdbcUrl | Jdbc地址 |
username | 连接用户名 |
password | 连接密码 |
源码生成目录及相关配置 | |
outputVueDirProj | 前端项目目录地址 |
outputJavaDirProj | 后端项目目录地址 |
javaDir | Java包路径 |
packagePath | 代码生成的包地址 |
contextPath | 微服务名称 |
module | 当前生成的项目模块名称 |
源码生成模板 | |
ftlVue | 前端vue模板 |
ftlJava | 后端java模板 |
ftlXml | 后端资源文件xml模板 |
ftlAny | 自定义模板 |
AI提问模板:生成源码 | |
question_structure | AI提问模板:系统结构 |
question_table | AI提问模板:表sql |
AI提问模板:单元测试 | |
host_testCase | AI提问模板:主机信息 |
question_testCase | AI提问模板:测试用例 |
- 提示:
1,百度千帆的API KEY和Secret Key获取方法,参考附录1“百度千帆大模型接入使用方法”。
2,有时配置文件修改后,系统还没有生效,这时重启IDEA试试。
2. AI辅助开发-初始化系统
场景:直接输入系统名称,由AI分析系统结构,最后通过内置模板生成系统相应的前后端源代码。
菜单:IDEA主菜单/AI低代码/初始化系统,如下图所示。
1)打开初始化系统对话框,默认打开“步骤1”标签,在该标签页输入:系统名称和表名前缀,点击发送,AI将自动分析生成系统结构。生成的数据,显示在下方的输出框,支持编辑,可人工完善优化,如下图所示。
2)点击打开步骤2标签,点击生成模型脚本,系统将自动与AI交互,生成数据库的建表脚本,同时生成插入测试数据脚本。生成的数据,显示在下方的输出框,支持编辑,可人工完善,如下图所示。
3)点击打开步骤3标签,分别点击执行模型脚本、生成源码和生成菜单按钮,各步骤执行记录,如下图所示。各步骤含义如下:
- 执行模型脚本:执行步骤2生成脚本,生成数据库表,并插入测试数据;
- 生成源码:根据源码生成模板,生成前后端源代码;
生成菜单:向系统中插入菜单,刷新系统页面,可发现多出一个主菜单。
4) AI辅助开发初始化系统,执行“模型脚本”按钮,生成的数据库表如下所示。
5)AI辅助开发初始化系统,执行“生成源码”按钮,生成的前、后端源码如下图所示。后端源码生成在flow微服务项目中,重启flow微服务,使源码生效。前端源码生成在/views/coding/flow/sap/目录,通过npm run dev启动前端项目。
6)AI辅助开发初始化系统,执行“生成菜单”按钮,刷新页面。下图是通过AI辅助开发初始化系统生成的SAP菜单和SAP系统销售渠道功能查询列表(AI自动插入了5条测试数据)。
3. AI辅助开发-逆向生成代码
场景:通过数据库表,逆向生成源代码。
菜单:IDEA主菜单/AI低代码/逆向生成代码,如下图所示。
1)点击菜单“AI低代码/逆向生成代码”,打开逆向生成代码对话框如下图所示。操作方法:1,输入相应表名(多个表名使用逗号分隔)和表前缀;2,点击“生成源码”按钮;3,日志区查看源码生成状态和源码生成路径;4,点击“生成菜单”按钮;5,日志区查看菜单生成状态。
2)刷新系统页面,生成的菜单页面如下图所示。
4. AI辅助开发-添加字段
场景:当需要给表增加字段时,通过此功能,可直接修改表添加字段,同时自动向相应的代码中添加字段属性,涉及代码文件有:相应实体类的Bean、Dto、Mapper.xml、Vue文件等。
菜单:右击相应实体类的Bean文件/AI低代码/添加字段,如下图所示。
1)点击“添加字段”菜单,打开添加字段对话框,输入字段相关信息如下图所示,点击提交,将自动完成数据库表和源代码的添加字段操作。
2)执行添加字段后,系统将自动给相应实体类的Bean、Dto、Mapper.xml、Vue文件添加相关字段源码,新生成的源码如下图所示。
3) 添加字段后,重启flow项目微服务,刷新页面,显示效果,如下图所示.
5. AI辅助开发-自定义源码模板的应用案例
源码生成的原理:针对每张数据表,通过调用一系列FreeMarker模板来生成前后端源代码。下面通过自定义一个模板文件来演示生成源码的过程。
1)在/ailowcode/aicodefile/template/test/目录下,创建2个模板文件用于测试。java后端测试模板:test.java.ftl。前端测试模板:test.js.ftl。如下所示。
- 1. //java后端测试模板:test.java.ftl
- 2. package com.wxy.ej.flow.modules.sap.test;
- 3. import org.springframework.stereotype.Controller;
- 4. @Controller
- 5. public class ${table.entityName}Test {
- 6. public void test(){
- 7. System.out.println("just a test!!!");
- 8. }
- 9. }
- 10.
- 11. //前端测试模板:test.js.ftl
- 12. import request from '@/utils/request'
- 13. export function fetchList(query) {
- 14. return request({
- 15. url: '/${cfg.contextPath}/${cfg.module}/${cfg.domain}/${table.entityPath}/myPage',
- 16. method: 'GET',
- 17. params: query
- 18. })
- 19. }
2)修改AI辅助开发配置文件:/ailowcode/aicodefile/aicode.properties,增加2个测试模板文件(test.java.ftl、test.js.ftl),如下所示。
- 1. ftlAny=[\
- 2. {"ftl":"/template/test/test.java.ftl", "isCreateEntityDir":false, "suffixPath":"%sTest.java","fullPath":"/Users/wxy2020/workspace/ailowcode/lowcode2/flow/src/main/java/com/wxy/ej/flow/modules/sap/test"},\
- 3. {"ftl":"/template/test/test.js.ftl", "isCreateEntityDir":true, "suffixPath":"%stestapi.js","fullPath":"/Users/wxy2020/workspace/ailowcode/lowcode2-ui/src/views/coding/flow/sap/test"},\
- 4. ]
配置文件说明:ftl是模板文件路径,此处配置成测试用的2个模板文件。isCreateEntityDir:是否自动创建实例对象命名的目录,当isCreateEntityDir=true时,会在路径后创建一个表实例对象命名的目录。suffixPath是生成的文件名后缀,其中%s会被替换成数据表对应的实例类名。fullPath是源码生成的完整路径。
3) 通过逆向生成代码功能进行测试,逆向生成代码方法参考“AI辅助开发-逆向生成代码”小节。测试结果如下图所示,其中,测试表名是tai_chatai和tai_chatai_test;自定义测试模板生成的后端类:ChataiTest.java、ChataiTestTest.java; 测试模板生成的前端类:Chataitestapi.js、ChataiTesttestapi.js。
6. AI辅助测试-单元测试
场景:接口测试,通过AI自动生成测试用例。
菜单:在相应的Controller文件对应的方法上右击,右击菜单/AI低代码/接口测试,如下图所示。
1)点击右击菜单中的“接口测试”子菜单,打开接口测试对话框,系统将自动填入相应的测试数据信息。在AI分析标签页,点击发送AI,将生成测试用例,如下图所示。各标签功能说明如下:
AI分析:根据参数中的类对象文件,生成测试用例;
Body:当method是post提交时,使用body中的参数;
Params:当method是get提交时,使用params中的参数;
Headers:当接口提交时,header中需要token认证场景时使用。
2) 看下图接口测试对话框的第一个编辑框是post,说明是post提交;打开Body标签;点击生成Body按钮,将自动从“AI分析”标签中获取数据填入Body参数框;点击发送按钮调用API接口,响应数据在下方的“响应”标签中显示;点击保存按钮,将保存当前接口信息到数据库,方便后续接口的批量测试使用。
3) 点击页面下方的“导出”标签,在导出标签页,点“导出报告”按钮,将在系统目录(/ailowcode/aicodefile/testcase/single/)下生成测试报告,如下图所示。
4) 本次接口测试,向物料主数据页面插入的测试数据,如下图所示.
5)当提交方式是get时,使用Params标签,生成测试参数,操作方式同上。接口测试Params标签页面如下图所示。
7. AI辅助测试-批量测试
场景:当一个功能由多个接口API组成时,将这些API设置成1个组,执行批量测试。
菜单:IDEA主菜单/AI低代码/API按组批量测试,如下图所示。
1) 点击“API按组批量测试”按钮,打开接口测试对话框,如下图所示。首先,在“配置管理”标签页,配置API组信息,配置方法如下:1,输入组名称,点击“添加”按钮;2,选中组名称;3,在API接口管理页面选择API接口;4,点击“引用API并保存”,将选中的API加入当前组。如下图所示.
2)在API按组批量测试对话框的“接口测试”标签页,左框选中API组,右框显示组对应的API接口列表,点击发送按钮,将批量进行API接口测试,如下图所示。
3) 点击页面下方的“导出”标签,在导出标签页,点“导出报告”按钮,将在系统目录(/ailowcode/aicodefile/testcase/group/)下生成测试报告,如下图所示.
(二)设计研发
1. 需求分析
略
2. 总体设计
应用技术:使用IDEA插件技术。AI辅助开发功能主要由AI生成代码和AI测试2部分组成。AI生成代码又分为:初始化系统、逆向生成代码和新增字段生成代码。AI测试分为:接口测试和接口按组测试。功能结构如下所示。
3. 概要设计
用例图设计
AI辅助开发用例图。该系统面向程序员。程序员可以使用该系统完成AI辅助生成代码和AI辅助测试等。用例图如下图所示。
4. 详细设计
1) 数据库表设计
AI辅助开发功能,由AI生成代码和AI辅助测试组成。插件与AI交互时,将AI响应数据缓存在本地数据库表AI缓存表tai_chatai中。接口测试时会将接口相关信息存储在接口表tai_api_url中。tai_api_group是接口分组表,将接口信息进行分组存储。tai_api_group_url_link是接口组与接口表多对多对联表。数据库表结构如下图所示。
AI缓存数据表,表名:tai_chatai。作用:存储AI响应数据。数据表结构信息,如下表所示。
序号 | 列名 | 数据类型 | 主键 | 非空 | 说明 |
1 | id | bigint | 是 | 是 | 主键 |
2 | domain_name | varchar(100) | 系统名称 | ||
3 | q | varchar(1000) | 问题 | ||
4 | table_prefix | varchar(100) | 表前缀 | ||
resp | text | 响应 | |||
5 | deleteflag | int | 是否删除;模板:逻辑删除标志:1:true,0:false | ||
6 | 创建人等字段省略 |
接口测试表,表名:tai_api_url。作用:存储接口测试相关信息。数据表结构信息,如下表所示。
序号 | 列名 | 数据类型 | 主键 | 非空 | 说明 |
1 | id | bigint | 是 | 是 | 主键 |
2 | name | varchar(100) | 名称 | ||
3 | url | varchar(1000) | URL | ||
4 | method | varchar(10) | Method | ||
5 | body | varchar(1000) | body参数 | ||
6 | deleteflag | int | 是否删除;模板:逻辑删除标志:1:true,0:false | ||
7 | 创建人等字段省略 |
接口分组表,表名:tai_api_group。作用:接口信息进行分组存储。数据表结构信息,如下表所示。
序号 | 列名 | 数据类型 | 主键 | 非空 | 说明 |
1 | id | bigint | 是 | 是 | 主键 |
2 | name | varchar(100) | 名称 | ||
3 | deleteflag | int | 是否删除;模板:逻辑删除标志:1:true,0:false | ||
4 | 创建人等字段省略 |
接口与分组多对多关联表,表名:tai_api_group_url_link。作用:接口组与接口表多对多对联表。表结构信息如表3.1.4.4所示。
序号 | 列名 | 数据类型 | 主键 | 非空 | 说明 |
1 | id | bigint | 是 | 是 | 主键 |
2 | tai_api_group_id | bigint | 分组表id | ||
3 | tai_api_url_id | bigint | 接口表id | ||
4 | deleteflag | int | 是否删除;模板:逻辑删除标志:1:true,0:false | ||
5 | 创建人等字段省略 |
5. IDEA插件开发基本功能介绍
1) IDEA插件开发环境
IDEA版本:2021.3.3(Community Edition)
IDEA下载地址:https://www.jetbrains.com/idea/download/other.html
IDEA插件开发,为什么下载使用IDEA社区版本?
IDEA社区版免费,并且源代码开源, 在开发插件的时候可以调试源代码。
如何选择下载的版本?
看你开发的插件想要兼容的最低版本是多少。比如我想兼容2021.3.3及以上的版本,对于更早的版本,无需兼容。我下载的是2021.3版本的IDEA。注意Community Edition这边的下载链接是社区版本的,如下图所示。
2)安装辅助开发插件
从插件市场安装插件:Plugin DevKit、UI Designer。Plugin DevKit:IDEA插件开发,使用 Plugin DevKit可以很方便地创建一个Action。UI Designer:在开发插件的过程中,我们需要进行 UI 界面的开发,但是IntelliJ IDE插件需要使用Swing进行 UI 的开发,因此本文选择使用UI Designer这款插件,通过可视化工具拖拽的方式来实现基本的界面设计。后续“代码解读:如何创建一个新菜单”小节,将讲述如何使用这2个插件进行开发。
3) 导入项目并解读关键文件
打开IDEA,导入我们的插件项目ailowcode-plugin,项目结构如下图所示.
plugin.xml文件是idea插件项目的配置文件,代码如下所示。
- 1. <idea-plugin>
- 2. <id>org.wxy.aicode.ideaplugin</id>
- 3. <name>AiLowcode</name>
- 4. <vendor> wuxiaoyong</vendor>
- 5. <description>……</description>
- 6. <extensions defaultExtensionNs="com.intellij"> </extensions>
- 7. <idea-version since-build="200" >……</idea-version>
- 8. <actions>
- 9. <!--工具栏加一级菜单"AI低代码"-->
- 10. <group id="aicode" text="AI低代码">
- 11. <add-to-group group-id="MainMenu" anchor="last"/>
- 12. </group>
- 13. <!--二给菜单:AI低代码/初始化系统-->
- 14. <action id="aicode-createSystem" class="com.wxy.ideaplugin.action.AiCodeAction" text="初始化系统" description="初始化系统">
- 15. <add-to-group group-id="aicode" anchor="first"/>
- 16. </action>
- 17. <!--二给菜单:AI低代码/逆向生成代码-->
- 18. <action id="aicode-createCode" class="com.wxy.ideaplugin.action.AiCodeTableAction" text="逆向生成代码" description="逆向生成代码">
- 19. <add-to-group group-id="aicode" />
- 20. </action>
- 21. <!--二给菜单:AI低代码/API按组批量测试-->
- 22. <action id="aicode-apiGroupTest" class="com.wxy.ideaplugin.action.ApiTestGroupAction" text="API按组批量测试" description="API按组批量测试">
- 23. <add-to-group group-id="aicode" />
- 24. </action>
- 25. <!--右击菜单"AI低代码"-->
- 26. <group id="aicode_rightMenu" text="AI低代码" popup="true">
- 27. <add-to-group group-id="EditorPopupMenu" anchor="after" relative-to-action="ReplaceInPath"/>
- 28. </group>
- 29. <!--右击菜单"AI低代码/添加字段"-->
- 30. <action id="aicode_rightMenu_addField" class="com.wxy.ideaplugin.action.RightMenuFieldAction" description="添加字段" text="添加字段">
- 31. <add-to-group group-id="aicode_rightMenu"/>
- 32. </action>
- 33. <!--右击菜单"AI低代码/API测试"-->
- 34. <action id="aicode_rightMenu_apitest" class="com.wxy.ideaplugin.action.RightMenuApiTestAction" description="API测试" text="接口测试">
- 35. <add-to-group group-id="aicode_rightMenu"/>
- 36. </action>
- 37. </actions>
- 38. </idea-plugin>
plugin.xml是xml结构,各节点功能介绍,如下表所示。
节点名称 | 说明 |
id | 是在jetbrains插件库中定位到你插件的唯一id,在不同版本中,必须保持一致,建议设置值为:包名 + 插件名称 |
name | 插件的名称,显示在 IDEA 已安装插件列表中 |
vendor | 作者信息 |
description | 插件的描述信息,支持html |
change-notes | 插件版本更新内容说明 |
version | 插件版本号 |
extensions | 用于扩展其他插件功能或者idea平台的功能 |
idea-version | 兼容版本设置,跟build.gradle里的sinceBuild一致即可,意义相同 |
actions | 由用户定义的一个个动作组成。 |
actions/group | 在IDEAL中添加一个菜单栏。如下例:创建一个名为“AI低代码”菜单栏;add-to-group是指将当前菜单栏添加到什么位置?group-id=“MainMenu”是指IDEA主菜单;anchor=“last”是指最后位置。 完整解释:在IDEA的主菜单的最后位置创建一个“AI低代码”的菜单栏,当前group id定义为aicode,供后续action菜单加入使用。
|
actions/action | 在IDEAL中添加一个菜单。如下例:创建一个名为“初始化系统”的菜单,菜单点击时执行的类文件是com.wxy.ideaplugin.action.AiCodeAction(后续做详细说明)。菜单位置:通过add-to-group来指定菜单存入于“AI低代码”菜单栏的第一次位置。
|
关于action: 在 idea 中每个功能都叫 action,一个菜单栏里由多个菜单组成,每个菜单对应一个 action。我们如果想自定义实现一个功能,那么就需要实现IDEA 提供的派生类 AnAction 。当用户在点击一个 action 时,会回调 AnAction 的actionPerformed方法,所以我们需要在 actionPerformed方法中实现自己的逻辑。以“AI低代码/初始化系统”为例,通过plugin.xml可知,当点击菜单时,执行对应的java类是com.wxy.ideaplugin.action.AiCodeAction,实现代码如下所示。
- 1. package com.wxy.ideaplugin.action;
- 2. ……
- 3. public class AiCodeAction extends AnAction {
- 4. @Override
- 5. public void actionPerformed(AnActionEvent e) {
- 6. Project project = e.getData(PlatformDataKeys.PROJECT);
- 7. String projectPath = project.getBasePath();
- 8. AiCodeUi aiCodeUi = new AiCodeUi(projectPath);
- 9. aiCodeUi.initUi();
- 10. }
- 11. }
IDEA对话框实现:通过右击java包,打开右击对话框,然后点击“/New/Swing UI Designer/Create Dialog Class”来创建对话框的类文件,如下图所示。
IDEAL对话框设计器:按上图(IDEA创建对话框类文件)的方法,创建IDEA对话框类文件AiCodeUi。在上面代码(AiCodeAction)中,通过调用AiCodeUi类方法initUi来打开“AI低代码/初始化系统”对话框。双击AiCodeUi/AiCodeUiForm来打开设计器。设计器界面,如下图所示.
6. 代码解读:如何创建一个新菜单
功能需求:在“IDEA主菜单/AI低代码”菜单下,新增一个“关于”菜单,点击打开“关于”对话框,对话框中显示系统功能的介绍信息。
使用插件“Plugin DevKit”来创建Action类:在需要创建类的java包名上右击,打开右击菜单,依次点击“New/Plugin DevKit/Action”菜单,打开New Action对话框,如下图所示。
在New Action对话框中配置如下信息,Class Name:AboutAction(点击菜单执行的类文件),Name:关于(菜单名称)。Add to Group栏:是给当前菜单“关于”指定位置,这里保持空着,后续通过修改plugin.xml文件,将“关于”菜单放入“AI低代码”菜单下,如下图所示。
“New Action”对话框中配置完信息后,点击“OK”按钮,会自动创建一个AboutAction类,类中的方法actionPerformed()是空的,待后续创建好UI对话框类后加入其中。plugin.xml中将自动新增一个action,修改该action,加入
- 1. <!--二级菜单:关于-->
- 2. <action id="aicode-about" class="com.wxy.ideaplugin.action.AboutAction" text="关于" description="关于">
- 3. <add-to-group group-id="aicode" />
- 4. </action>
使用插件Swing UI Designer来创建IDEA UI对话框,用来弹开显示“关于”对话框信息。首先,在需要创建类的java包名上右击,打开右击菜单,依次点击菜单“New/Swing UI Designer/Create Dialog Class”来创建一个带设计器的Java类包文件:AboutUi,如下图所示。
创建一个AboutUi对话框类,双击该类包下的AboutUi.form文件,打开Swing设计器界面,拖入相关组件,如下图所示。
在AboutUi.java类文件中,加入一段给jTextArea_About赋值的方法,如下所示。该类中默认有main()方法(main()方法中加了窗口大小设置和屏幕居中显示语句),当右击运行该类时:1,会自动重构该类的$$$setupUI$$$()方法,该方法对UI界面的控件进行初始化操作;2,显示界面效果。
- 1. public class AboutUi extends JDialog {
- 2. private JTextArea jTextArea_About;
- 3. ......
- 4. public AboutUi() {
- 5. ......
- 6. initAbout();
- 7. }
- 8.
- 9. private void initAbout() {
- 10. jTextArea_About.append("......");
- 11. }
- 12. ......
- 13. public static void main(String[] args) {
- 14. AboutUi dialog = new AboutUi();
- 15. dialog.setSize(800, 700);
- 16. dialog.setLocationRelativeTo(null);
- 17. dialog.setVisible(true);
- 18. System.exit(0);
- 19. }
- 20. ......
- 21. private void $$$setupUI$$$() {
- 22. ......
- 23. }
- 24. }
当点击“关于”菜单时,实际是执行AboutAction类中的actionPerformed()方法,在该方法中,加入显示“关于”对话框的代码,如下所示。
- 1. package com.wxy.ideaplugin.action;
- 2. ......
- 3. public class AboutAction extends AnAction {
- 4. @Override
- 5. public void actionPerformed(AnActionEvent e) {
- 6. AboutUi dialog = new AboutUi();
- 7. dialog.pack();
- 8. dialog.setSize(800, 700);
- 9. dialog.setLocationRelativeTo(null);
- 10. dialog.setVisible(true);
- 11. }
- 12. }
安装运行插件(运行方法见本章“运行、打包、安装、发布插件”小节)。点击菜单“IDEA主菜单/AI低代码/关于”打开“关于”对话框,如下图所示。
7. 代码解读:AI生成代码
本系统使用的AI提供方是百度千帆(以下简称:千帆),千帆接口的调用密钥和api相关信息配置在配置文件ailowcode/aicodefile/aicode.properties中。千帆的配置参数有client_id, client_secret,api_url,其中client_id, client_secret需要用户在千帆的官网提交申请获得。
千帆应用接入方法:1,登录官网https://console.bce.baidu.com/qianfan/;2,在应用接入菜单创建新的应用信息,会自动生成api key, secret key分别对应本系统配置中的client_id, client_secret。
点击“AI低代码/初始化系统”菜单,打开初始化系统功能对话框,如下图所示.
点击“发送”按钮,首先会对生成系统的问题进行优化整理,如:需要生成的系统名称是图书管理系统,则问题优化成:“你是一位数据库设计师,设计一款软件系统,系统名称叫图书管理系统,请编写出系统的数据库表名的JSON结构,对数据库表名进行分类分组,JSON结构格式是……”。
调用AI的关键代码如下所示。通过调用千帆的工具类代码com.wxy.ideaplugin.utils.HttpUtils,来实现与AI接口的交互。简单梳理一下调用过程:
- 调用HttpUtils的getInstance方法时,获取对象实例;getInstance方法内部调用千帆的生成token的API,获取的token供后续调用千帆的API使用;
- 调用HttpUtils的chatApiV2方法,将问题提交给千帆API(带上上一步的token);
- 获取千帆返回的结果存入数据库缓存表tai_chatai(后续查询相同问题时,直接从缓存表获取结果),同时将结果显示在界面的输出框
- 1. HttpUtils.getInstance(projectPath).chatApiV2(q, new EventSourceListener() {
- 2. StringBuilder resultSb = new StringBuilder();
- 3. @Override
- 4. public void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data) {
- 5. log.info("----onEvent");
- 6. JSONObject dataJo = JSONObject.parseObject(data);
- 7. boolean is_end = dataJo.getBoolean("is_end");
- 8. String result = dataJo.getString("result");
- 9. menu_textArea.append(result);
- 10. resultSb.append(result);
- 11. if (is_end == true) {
- 12. log.info(resultSb.toString());
- 13. // 查询出的结果,进行缓存
- 14. String insertSql = "insert into tai_chatai(id, domain_name, q, table_prefix, resp) values(?,?,?,?,?)";
- 15. List paramList = new ArrayList();
- 16. paramList.add(IdUtils.genId());
- 17. paramList.add(softwareName + "###SystemMenuGroup");
- 18. paramList.add(q);
- 19. paramList.add(tablePrefix);
- 20. paramList.add(resultSb.toString());
- 21. JdbcUtils.executeInsert(insertSql, paramList);
- 22. //parse data
- 23. String result2 = HttpUtils.parseGroupMenuList(resultSb.toString());
- 24. menu_textArea.setText(result2);
- 25. }
- 26. super.onEvent(eventSource, id, type, data);
- 27. }
- 28. });
调用千帆工具类的关键代码如下所示。工具类中提供了查询千帆token和调用千帆AI的API接口方法。
- 1. package com.wxy.ideaplugin.utils;
- 2. public class HttpUtils {
- 3. private String client_id;
- 4. private String client_secret;
- 5. private String accessToken;
- 6. private String api_url;
- 7. private Properties properties;
- 8. private static HttpUtils httpUtils = new HttpUtils();
- 9.
- 10. public static HttpUtils getInstance(String projectPath) {
- 11. if (httpUtils.accessToken==null) {
- 12. httpUtils.properties = AiResourceUtils.getProperty(projectPath);
- 13. httpUtils.client_id = httpUtils.properties.getProperty("client_id");
- 14. httpUtils.client_secret = httpUtils.properties.getProperty("client_secret");
- 15. httpUtils.api_url = httpUtils.properties.getProperty("api_url")+"?access_token=";
- 16. httpUtils.accessToken = httpUtils.queryToken();
- 17. }
- 18. return httpUtils;
- 19. }
- 20.
- 21. //查询千帆的token
- 22. public String queryToken() {
- 23. try {
- 24. String url_token = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=" +client_id+"&client_secret="+client_secret;
- 25. OkHttpClient okHttpClient = new OkHttpClient.Builder()
- 26. .connectTimeout(100, TimeUnit.SECONDS)
- 27. .readTimeout(100, TimeUnit.SECONDS)
- 28. .writeTimeout(100, TimeUnit.SECONDS)
- 29. .build();
- 30. Request request = new Request.Builder().url(url_token).method("GET",null).build();
- 31. Call call = okHttpClient.newCall(request);
- 32. Response response = call.execute();
- 33. String data = response.body().string();
- 34. JSONObject jsonObject = JSONObject.parseObject(data);
- 35. String accessToken = jsonObject.getString("access_token");
- 36. return accessToken;
- 37. } catch (Exception e) {
- 38. e.printStackTrace();
- 39. }
- 40. return null;
- 41. }
- 42.
- 43. //调用千帆AI的API
- 44. public void chatApiV2(String q,EventSourceListener eventSourceListener){
- 45. String url = api_url+accessToken;
- 46. OkHttpClient client = new OkHttpClient.Builder()
- 47. .connectTimeout(100, TimeUnit.SECONDS)
- 48. .writeTimeout(100, TimeUnit.SECONDS)
- 49. .readTimeout(100, TimeUnit.MINUTES)
- 50. .build();
- 51. EventSource.Factory factory = EventSources.createFactory(client);
- 52. // 请求体
- 53. JSONObject contentJson = new JSONObject();
- 54. contentJson.put("role", "user");
- 55. contentJson.put("content", q);
- 56. JSONArray contentArr = new JSONArray();
- 57. contentArr.add(contentJson);
- 58. JSONObject json = new JSONObject();
- 59. json.put("messages", contentArr);
- 60. json.put("stream", true);
- 61. RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),json.toJSONString());
- 62. // 请求对象
- 63. Request request = new Request.Builder()
- 64. .url(url)
- 65. .post(body)
- 66. .build();
- 67. // 创建事件
- 68. EventSource eventSource = factory.newEventSource(request, eventSourceListener);
- 69. }
- 70. }
8. 代码解读:AI辅助开发-源码模板
点击“AI低代码/初始化系统”菜单,打开初始化系统功能对话框,点击“步骤3”标签下“生成源码”按钮,系统会根据FreeMarker模板逆向生成前后端源代码,如下图所示。逆向生成代码(对应菜单“AI低代码/逆向生成代码”)功能,同样使用FreeMarker模板逆向生成前后端源代码。
点击“生成源码”按钮时,执行生成源码的关键代码类是com.wxy.ideaplugin.generator.MpGeneratorThread。系统会根据/ailowcode/aicodefile/aicode.properties中配置的模板信息(前后端源码模板:ftlVue、ftlJava、ftlXml和ftlAny)生成相应的源码文件。MpGeneratorThread类的关键代码如下所示,解读:1,读取AI配置文件中模板数据信息:ftlVue、ftlJava、ftlXml和ftlAny(后续详细介绍);2,使用前端模板文件ftlVue来生成源码;3,使用后端模板文件ftlJava来生成源码;4,使用后端资源模板文件ftlXml来生成资源文件;5,使用自定义模板文件ftlAny来生成自定义文件对应源码(应用案例参考“AI辅助开发-自定义源码模板的应用案例”小节)。
- 1. package com.wxy.ideaplugin.generator;
- 2. ......
- 3. public class MpGeneratorThread extends Thread{
- 4. ......
- 5. private void genCode(MpFileWriter genFileWriter){
- 6. //取配置文件中模板数据
- 7. String ftlVueStr = properties.getProperty("ftlVue");
- 8. String ftlJavaStr = properties.getProperty("ftlJava");
- 9. String ftlXmlStr = properties.getProperty("ftlXml");
- 10. String ftlAnyStr = properties.getProperty("ftlAny");
- 11. JSONArray ftlVueArr = JSONArray.parseArray(ftlVueStr);
- 12. JSONArray ftlJavaArr = JSONArray.parseArray(ftlJavaStr);
- 13. JSONArray ftlXmlArr = JSONArray.parseArray(ftlXmlStr);
- 14. JSONArray ftlAnyArr = JSONArray.parseArray(ftlAnyStr);
- 15. //引用前端模板生成代码
- 16. for(int i=0;i<ftlVueArr.size();i++) {
- 17. JSONObject ftlObj = ftlVueArr.getJSONObject(i);
- 18. String ftl = ftlObj.getString("ftl");
- 19. String suffixPath = ftlObj.getString("suffixPath");
- 20. String fullPath = ftlObj.getString("fullPath");
- 21. String outPutPath = outputDirView;
- 22. if (!StringUtils.isNull(fullPath)) {
- 23. outPutPath = fullPath;
- 24. }
- 25. genFileWriter.write(ftl, outPutPath, true, suffixPath, execlog_textArea);
- 26. }
- 27. //引用后端模板生成代码
- 28. for(int i=0;i<ftlJavaArr.size();i++) {
- 29. JSONObject ftlObj = ftlJavaArr.getJSONObject(i);
- 30. String ftl = ftlObj.getString("ftl");
- 31. String codeLastPath = ftlObj.getString("codeLastPath");
- 32. String suffixPath = ftlObj.getString("suffixPath");
- 33. String fullPath = ftlObj.getString("fullPath");
- 34. String outPutPath = pgOutputDir+File.separator+codeLastPath;
- 35. if (!StringUtils.isNull(fullPath)) {
- 36. outPutPath = fullPath;
- 37. }
- 38. genFileWriter.write(ftl, outPutPath,false, suffixPath, execlog_textArea);
- 39. }
- 40. //引用XML模板生成代码
- 41. for(int i=0;i<ftlXmlArr.size();i++) {
- 42. JSONObject ftlObj = ftlXmlArr.getJSONObject(i);
- 43. String ftl = ftlObj.getString("ftl");
- 44. String suffixPath = ftlObj.getString("suffixPath");
- 45. String fullPath = ftlObj.getString("fullPath");
- 46. String outPutPath = mapperXmlOutputDir;
- 47. if (!StringUtils.isNull(fullPath)) {
- 48. outPutPath = fullPath;
- 49. }
- 50. genFileWriter.write(ftl, outPutPath,false, suffixPath, execlog_textArea);
- 51. }
- 52. //自定义Vue模板生成代码
- 53. for(int i=0;i<ftlAnyArr.size();i++) {
- 54. JSONObject ftlObj = ftlAnyArr.getJSONObject(i);
- 55. String ftl = ftlObj.getString("ftl");
- 56. String suffixPath = ftlObj.getString("suffixPath");
- 57. String fullPath = ftlObj.getString("fullPath");
- 58. Boolean isCreateEntityDir = ftlObj.getBoolean("isCreateEntityDir");
- 59. if (StringUtils.isNull(fullPath)) {
- 60. continue;
- 61. }
- 62. genFileWriter.write(ftl,fullPath,isCreateEntityDir,suffixPath,execlog_textArea);
- 63. }
- 64. }
- 65. }
源码模板文件说明:AI辅助开发插件配置文件(aicode.properties)中模板配置信息如下所示。其中,ftlVue是前端vue模板,系统生成源码时,会自动在路径后创建一个表实例对象的目录,生成的list.vue、form-details.vue等源码都存入在该目录下;ftlJava是生成后端java源码的模板;ftlXml是生成后端资源文件的模板;ftlAny是自定义模板(自定义模板使用该当参考“AI辅助开发-自定义源码模板的应用案例”小节)。
各模板子对象配置文件是json结构,说明如下:ftl是模板文件路径。isCreateEntityDir:是否自动创建实例对象命名的目录,当isCreateEntityDir=true时,会在路径后创建一个表实例对象命名的目录。suffixPath是生成的文件名后缀,其中%s会被替换成数据表对应的实例类名。fullPath是源码生成的完整路径,为空时,由系统生成路径,fullPath路径优先级最高,当fullPath有路径时,以fullPath为准。ftlJava中的codeLastPath,是指在系统生成的路径后加一个目录,如:/xxx/flow/oa/userManager(用户管理领域)/{生成目录:dto,bean,mapper,dtomapper,service,controller}/具体源代码文件。
- 1. ......
- 2. #前端vue模板,会在路径后创建一个表实例对象的目录
- 3. ftlVue=[\
- 4. {"ftl":"/template/vue/list.vue.ftl", "suffixPath":"list.vue", "fullPath":""},\
- 5. {"ftl":"/template/vue/form-details.vue.ftl", "suffixPath":"form-details.vue", "fullPath":""},\
- 6. {"ftl":"/template/vue/form-add.vue.ftl", "suffixPath":"form-add.vue", "fullPath":""},\
- 7. {"ftl":"/template/vue/api.js.ftl", "suffixPath":"api.js", "fullPath":""},\
- 8. {"ftl":"/template/vue/data.js.ftl", "suffixPath":"data.js", "fullPath":""},\
- 9. {"ftl":"/template/vue/index.vue.ftl", "suffixPath":"index.vue", "fullPath":""},\
- 10. ]
- 11. #后端java模板
- 12. ftlJava=[\
- 13. {"ftl":"/template/java/dto.java.ftl", "codeLastPath":"dto","suffixPath":"%sDto.java", "fullPath":""},\
- 14. {"ftl":"/template/java/entity.java.ftl", "codeLastPath":"bean","suffixPath":"%s.java", "fullPath":""},\
- 15. {"ftl":"/template/java/mapper.java.ftl", "codeLastPath":"mapper","suffixPath":"%sMapper.java", "fullPath":""},\
- 16. {"ftl":"/template/java/dtomapper.java.ftl", "codeLastPath":"dtomapper","suffixPath":"%sDtoMapper.java", "fullPath":""},\
- 17. {"ftl":"/template/java/service.java.ftl", "codeLastPath":"service","suffixPath":"%sService.java", "fullPath":""},\
- 18. {"ftl":"/template/java/controller.java.ftl", "codeLastPath":"controller","suffixPath":"%sController.java", "fullPath":""},\
- 19. ]
- 20. #后端资源文件xml模板
- 21. ftlXml=[\
- 22. {"ftl":"/template/java/mapper.xml.ftl", "suffixPath":"%sMapper.xml", "fullPath":""},\
- 23. ]
- 24.
- 25. #自定义模板; 当isCreateEntityDir=true时,会在路径后创建一个表实例对象的目录
- 26. ftlAny=[\
- 27. {"ftl":"/template/test/test.java.ftl", "isCreateEntityDir":false, "suffixPath":"%sTest.java", "fullPath":"/Users/wxy2020/workspace/ailowcode/lowcode2/flow/src/main/java/com/wxy/ej/flow/modules/sap/test"},\
- 28. {"ftl":"/template/test/test.js.ftl", "isCreateEntityDir":true, "suffixPath":"%stestapi.js", "fullPath":"/Users/wxy2020/workspace/ailowcode/lowcode2-ui/src/views/coding/flow/sap/test"},\
- 29. ]
- 30. ......
接下来,以生成DTO源码为例,进行说明。由AI辅助开发插件配置文件(aicode.properties)中ftlJava可知,DTO模板文件取的是:/ailowcode/aicodefile/template/java/dto.java.ftl。dto.java.ftl模板文件如下所示.
- 1. <#import "../user_defined_function.ftl" as self_defined>
- 2. package ${cfg.package_name}.dto;
- 3.
- 4. @Data
- 5. @ToString
- 6. @EqualsAndHashCode(callSuper = false)
- 7. @AllArgsConstructor
- 8. @NoArgsConstructor
- 9. public class ${entity}Dto extends BaseV4Dto{
- 10. private static final long serialVersionUID = 1L;
- 11.
- 12. <#list table.fields as field>
- 13. <#if self_defined.isIgnProp(field.propertyName)==true>
- 14. <#continue>
- 15. </#if>
- 16. <#if field.keyFlag>
- 17. <#assign keyPropertyName="${field.propertyName}"/>
- 18. </#if>
- 19. <#if field.keyFlag>
- 20. <#-- 主键 -->
- 21. // 主键 : ${field.name} ${field.comment!}
- 22. <#-- 普通字段 -->
- 23. <#elseif !field.keyFlag>
- 24. // ${field.name}: ${field.comment!}
- 25. </#if>
- 26. <#-- 乐观锁注解 -->
- 27. <#if (versionFieldName!"") == field.name>
- 28. @Version
- 29. </#if>
- 30. <#-- 逻辑删除注解 -->
- 31. <#if (logicDeleteFieldName!"") == field.name>
- 32. @TableLogic
- 33. </#if>
- 34. <#if field.propertyType == "LocalDateTime">
- 35. private Date ${field.propertyName};
- 36. </#if>
- 37. <#if field.propertyType != "LocalDateTime">
- 38. private ${field.propertyType} ${field.propertyName};
- 39. </#if>
- 40. </#list>
- 41. }
生成源码测试:点击菜单“AI低代码/逆向生成代码”,使用表tai_chatai进行测试,生成日志如下所示。
生成的DTO源文件存入到相应module的dto目录下:com.wxy.ej.flow.modules.sap.chatai.dto。生成的源码,如下所示。系统会根据数据库表字段注解,自动生成到源代码中。
- 1. package com.wxy.ej.flow.modules.sap.chatai.dto;
- 2.
- 3. import lombok.*;
- 4. import com.rt.easyjava.common.base.BaseV4Dto;
- 5.
- 6. /**
- 7. *
- 8. * @author wuxiaoyong
- 9. * @since 2024-12-28
- 10. */
- 11. @Data
- 12. @ToString
- 13. @EqualsAndHashCode(callSuper = false)
- 14. @AllArgsConstructor
- 15. @NoArgsConstructor
- 16. public class ChataiDto extends BaseV4Dto{
- 17. private static final long serialVersionUID = 1L;
- 18. // domain_name: 系统名称
- 19. private String domainName;
- 20. // q: 问题
- 21. private String q;
- 22. // table_prefix: 表前缀
- 23. private String tablePrefix;
- 24. // resp: 响应
- 25. private String resp;
- 26. }
9. 运行、打包、安装、发布插件
1) 运行项目
在 Gradle标签页下找到 runIde,右击,点击运行项目(或双击runIde),如下图所示。运行项目成功后,弹出项目对话框,打开ailowcode项目(插件应用到本项目根目录下aicodefile文件)。辅助开发插件会自动安装,检查IDEA工栏具是否有一级菜单“AI低代码”,代表是否安装插件成功。
2)打包项目
在Gradle标签下,右击buildPlugin打开右击菜单,点击运行项目(或双击buildPlugin),如下图所示。运行项目成功后,在/ailowcode-plugin/build/distributions/目录下生成插件的安装包文件ailowcode-plugin-1.1.zip。
3) 安装插件
安装插件方法如下。
本地安装方法1:将插件安装包文件直接拖到IDEA开发工具空白处,IDEA提示需要重启后生效,选择立即重启,完成插件安装。
本地安装方法2:打开IDEA设置框,选择Plugins菜单,通过“Install Plugin From Disk…”按钮安装,如下图所示。
市场安装:在下图的Marketplace标签下搜索AILowcode,进行安装。
4)发布插件
插件上架市场后,可以被所有人使用。首先,登录到https://plugins.jetbrains.com/ ,注册账户后点击 Upload plugin,如下图所示。
然后上传我们上面生成的 zip 文件,并填写一些信息,比如开源证书和插件分类,然后点击 upload 就等待审核通过吧,如下图所示.
升级插件:点击“当前登录用户/My profile”菜单,打开当前项目管理页面,点击右上角“Upload Update”按钮,打开上传对话框,如下图所示,选择新版本的zip插件文件,点击上传,上传成功后,点击Versions标签页,可查看到新的版本插件信息。
安装插件:上传的插件一般审核周期是1-2个工作日,当审核通过了,就可以通过插件市场,搜索安装了,如下图所示。
评论记录:
回复评论: