本节目标
本节还是以开源项目RuoYi-Vue-Plus 为例,看看如何对已有项目添加和修改功能的一个完整流程。这个开源项目地址:gitee.com/dromara/Ruo…。
- 了解/new命令作用
- 了解 /init 命令作用
- 了解 AGENTS.md文件的重要性
- 仅增加后端接口,不实现前端页面
先让RuoYi-Vue-Plus 跑起来
这个步骤,我们也利用 AI 帮我们做很多事情。比如:
- 数据库的初始化工作
- 配置修改工作
这里我选用的大模型是 claude sonnet 4.6 模型。为什么订阅 GitHub copilot ,就是因为它其中包含 Claude 这几个编程模型。非常好用!其中 sonnet 模型用于一般编程工作;而 opus 用于框架设计和复杂编程工作。不过这里是需要科学上网才能使用。这个要想用的话,需要自行解决。
数据库初始化
按照上节中提到的思路,让 opencode 通过官方文档进行学习。自动帮我们进行数据库初始化工作。
官方学习文档:plus-doc.dromara.org/#/_readme
-
提示词
帮我在远程的 mysql 数据库上创建本项目所需的数据库。 官方学习文档:https://plus-doc.dromara.org/#/_readme 我的 mysql 数据库的相关信息如下: mysql服务器 ip:your mysql server ip 端口:3306 用户名:root 密码:your password 根据官网文档介绍,帮我创建所需的库和表吧。这里特别说明下,我仅仅需要ruoyi-vue-plus的基础库表。 -
执行结果
补充说明:
其实我开始用的是一个opencode免费的模型MiniMax M2.5 Free模型。结果这个模型,告诉我无法直接操作远程的mysql数据库。它找不到对应的mysql客户端工具。但是用claude的模型它就能通过安装Node.js的mysql2包来连接mysql数据库。虽然免费的模型最后也能给我所有执行的脚本和完整步骤,但是依然没有“全自动”创建库表。所以,一个好的模型是灵魂。
配置文件修改
由于还是在这个上下文中沟通,所以不用再特别强调官方学习文档地址了。
-
提示词
帮我修改dev环境的配置文件,仅仅保留最基础的功能,其他功能都先关闭。 修改数据库连接为刚才创建的库连接。 redis相关信息如下: host: your redis host ip port: 6379 password: your redis password -
执行结果
在 idea 中跑起来
这个 5.X 版本最低也要 JDK17 版本,我的环境是 JDK21 的。完全满足。启动最后打印的内容如下:
/new 命令
在 opencode 中,/new表示开始新的会话。这个命令会清空上下文记忆。也就是再次和模型对话时省 token 了。但是也失去了历史的上下文记忆了。特别适合在新功能开发;或者提交代码后的 bug 修复。总之是任务告一段落了。
和在UI 中点击新建会话一样:
我们这里用/new是表示,前期的准备告一段落了。在和大模型沟通的上下文中不用包含历史对话信息了。
/init 命令
这个命令会给项目做一个全面扫描,了解项目后生成一个 AGENTS.md文档。如果已经存在这个AGENTS.md文档,再次执行/init 命令时,该命令会尝试在其基础上进行补充。我们来执行这个命令,并且大概看下它生成的文档。记住哈,这一步很重要,新加功能和修改已有功能都基于此文档中定义的规则和约束进行的。
看下执行结果:
看起来还不错,只不过都是英文的。我们可以让 opencode 转为中文。当然为了避免这种情况,我们可以在全局规则中增加简体中文的交互规则。
AGENTS.md 文件
这个AGENTS.md文件,你可以理解成大模型的参考手册。是用于定义、配置和规范 AI Agent(智能体)的行为准则与技术细节的文档。这个文件可以是在项目下的,也可以在用户目录下的。一般在用户目录下的AGENTS.md就是全局的规则文件了。
生成全局 AGENTS.md文件
这步我们可以在 opencode 中直接让它来帮我们创建出来。
-
提示词
在全局规则中增加始终使用简体中文与我交流 -
执行结果
-
全局规则文件内容
C:\Users\mayuanfei.config\opencode\AGENTS.md
# 全局规则 始终使用简体中文与用户交流。 -
可以增加更多自己的配置信息
# 语言要求 * 始终使用简体中文与我交流。 * 思考过程(Thinking)和最终回答都必须使用中文。 * 即便我用英文提问,也请用中文回答。 # JAVA环境 * JDK21在/Users/mayuanfei/.sdkman/candidates/java/21.0.8-zulu目录。默认JDK21环境。 * JDK8在/Users/mayuanfei/.sdkman/candidates/java/8.0.442-zulu。根据当前项目使用。 # MAVEN环境 * maven在/Users/mayuanfei/apache-maven-3.8.3 * maven的默认配置文件在/Users/mayuanfei/apache-maven-3.8.3/conf/settings-jdk21.xml * 编译项目时加上-DskipTests,来排除测试类。 # 编码整体要求 * 一个方法不能超过40行 * 如果是JDK21的项目,语法尽量使用JDK21新的语法。注意:这个全局规则文件尽量不要太长,因为它是所有项目都要遵循的规则。
项目AGENTS.md文件
尽量将全局配置的内容和项目配置的区分开。尽量不要配置冲突项。比如:全局配置一个方法不能超过40行代码;而你在项目的规则文件中定义一个方法不能超过20行。那么本地的约束>全局的配置。
-
翻译为中文
把当前项目的AGENTS.md文档都翻译为中文 -
添加自己的规则
这个可以按照自己平时项目中的规则,增加相应的约束。比如我这里在公有方法和私有方法之间增加个分割线。
## 公私有方法分割线 在类的公有方法和私有方法 中间加上"//////////////////////////////////////公私有方法分割线//////////////////////////////////"。例如: ```java public String publicA() { return ""; } public String publicB() { return ""; } //////////////////////////////////////公私有方法分割线////////////////////////////////// private String privateA() { } private String privateB() { } ``` 但是如下情况不用加分割线标识: 1. 接口类不用加 2. 如果一个类中只有public方法,那么结尾不用加
增加新接口
业务功能
这里假设做一个商品类别的增删改查接口吧。商品类别的表名:t_goods_category。结构如下:
| 字段名 | 数据类型 | 约束 | 备注 |
|---|---|---|---|
| id | bigint | PK, 自增 | 分类ID (雪花算法值) |
| parent_id | bigint | Not Null | 父分类ID (一级分类为 0) |
| name | varchar(64) | Not Null | 分类名称 |
| level | tinyint | Not Null | 层级 (1-一级, 2-二级, 3-三级) |
| sort_order | int | Default 0 | 排序值 (数值越小越靠前) |
| icon | varchar(255) | - | 图标地址 |
| is_visible | tinyint(1) | Default 1 | 是否显示 (0-隐藏, 1-显示) |
| remark | varchar(200) | - | 备注说明 |
| create_time | datetime | Not Null | 创建时间 |
| update_time | datetime | - | 更新时间 |
| deleted_flag | tinyint(1) | Default 0 | 逻辑删除 (0-正常, 1-已删除) |
这个表就是在 md 文档中直接进行设计的。下面也会用这个设计内容直接创建表和测试数据。
创建表和测试数据
这步还是利用 opencode 帮我们来创建。
-
执行/new 来创建一个新会话
-
提示词
结合当前项目 dev 环境配置的 mysql连接相关配置信息。做如下事情: 1. 在库中创建t_goods_category表,表结构如下: | **字段名** | **数据类型** | **约束** | **备注** | | ---------------- | -------------- | --------- | ----------------------------- | | **id** | `bigint` | PK, 自增 | 分类ID (雪花算法值) | | **parent_id** | `bigint` | Not Null | 父分类ID (一级分类为 0) | | **name** | `varchar(64)` | Not Null | 分类名称 | | **level** | `tinyint` | Not Null | 层级 (1-一级, 2-二级, 3-三级) | | **sort_order** | `int` | Default 0 | 排序值 (数值越小越靠前) | | **icon** | `varchar(255)` | - | 图标地址 | | **is_visible** | `tinyint(1)` | Default 1 | 是否显示 (0-隐藏, 1-显示) | | **remark** | `varchar(200)` | - | 备注说明 | | **create_time** | `datetime` | Not Null | 创建时间 | | **update_time** | `datetime` | - | 更新时间 | | **deleted_flag** | `tinyint(1)` | Default 0 | 逻辑删除 (0-正常, 1-已删除) | 2. 在t_goods_category表中创建 10 条测试数据 -
创建结果
在 ry-vue 库中多了一个 t_goods_category 表,并且已经有 10 条测试记录了。
生成商品分类表的接口方法
-
提示词
结合当前项目的开发规范,在项目的合适包中,生成针对t_goods_category 表的增删改查接口。 -
生成代码结果
测试生成的新代码
-
让框架不验证权限
我要通过reqable工具来请求/goods/category/listAll,帮我设置一下不校验相关的权限。这里看到它用@SaIgnore 注解来忽略权限校验了
-
通过 reqable 测试接口
说明:
我是一边操作一边来写这篇文档的。这里能一次测试通过,也的确是没有想到。说明这个 opus 模型是真的厉害。
浏览下生成的代码
package org.dromara.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.system.domain.GoodsCategory;
import org.dromara.system.domain.bo.GoodsCategoryBo;
import org.dromara.system.domain.vo.GoodsCategoryVo;
import org.dromara.system.mapper.GoodsCategoryMapper;
import org.dromara.system.service.IGoodsCategoryService;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
/**
* 商品分类 服务层实现
*
* @author mayuanfei
*/
@RequiredArgsConstructor
@Service
public class GoodsCategoryServiceImpl implements IGoodsCategoryService {
private final GoodsCategoryMapper baseMapper;
/**
* 分页查询商品分类列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 商品分类分页列表
*/
@Override
public TableDataInfo<GoodsCategoryVo> selectPageCategoryList(GoodsCategoryBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<GoodsCategory> lqw = buildQueryWrapper(bo);
Page<GoodsCategoryVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(page);
}
/**
* 查询商品分类详情
*
* @param id 分类ID
* @return 商品分类信息
*/
@Override
public GoodsCategoryVo selectCategoryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 查询商品分类列表
*
* @param bo 查询条件
* @return 商品分类集合
*/
@Override
public List<GoodsCategoryVo> selectCategoryList(GoodsCategoryBo bo) {
LambdaQueryWrapper<GoodsCategory> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
/**
* 新增商品分类
*
* @param bo 商品分类信息
* @return 结果
*/
@Override
public int insertCategory(GoodsCategoryBo bo) {
GoodsCategory category = MapstructUtils.convert(bo, GoodsCategory.class);
return baseMapper.insert(category);
}
/**
* 修改商品分类
*
* @param bo 商品分类信息
* @return 结果
*/
@Override
public int updateCategory(GoodsCategoryBo bo) {
GoodsCategory category = MapstructUtils.convert(bo, GoodsCategory.class);
return baseMapper.updateById(category);
}
/**
* 删除商品分类
*
* @param id 分类ID
* @return 结果
*/
@Override
public int deleteCategoryById(Long id) {
return baseMapper.deleteById(id);
}
/**
* 批量删除商品分类
*
* @param ids 需要删除的分类ID
* @return 结果
*/
@Override
public int deleteCategoryByIds(Long[] ids) {
return baseMapper.deleteByIds(Arrays.asList(ids));
}
//////////////////////////////////////公私有方法分割线//////////////////////////////////
/**
* 构建查询条件
*
* @param bo 查询条件对象
* @return LambdaQueryWrapper
*/
private LambdaQueryWrapper<GoodsCategory> buildQueryWrapper(GoodsCategoryBo bo) {
LambdaQueryWrapper<GoodsCategory> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getParentId() != null, GoodsCategory::getParentId, bo.getParentId());
lqw.like(StringUtils.isNotBlank(bo.getName()), GoodsCategory::getName, bo.getName());
lqw.eq(bo.getLevel() != null, GoodsCategory::getLevel, bo.getLevel());
lqw.eq(bo.getIsVisible() != null, GoodsCategory::getIsVisible, bo.getIsVisible());
lqw.orderByAsc(GoodsCategory::getSortOrder);
return lqw;
}
}
说明:
1.生成的代码很符合咱们在
AGENTS.md文件定义的公私有方法中有分割线。2.但是很多生成的代码在 ruoyi-system 模块中了。理论上需要新增自己的业务模块。
本节总结
- 我们用 RuoYi-Vue-Plus 做示例项目,用 opencode 让它跑起来。
- 了解一个项目的最快方式就是让 AI 直接告诉你
- /new 新开一个会话
- /init 创建或更新
AGENTS.md文件 - 全局
AGENTS.md是给所有项目的规约 - 一个好用的大模型,是愉快 coding 的前提