前言
在第一次使用 Cursor 完成需求开发后,我深受震撼。这种“用自然语言描述需求,直接实现功能”的编程体验,正是我高中第一次接触编程时所憧憬的。然而,Cursor 生成的代码有时显得不够规范,难以维护。对于小型工具,这或许可以接受,但在工程级项目中,这种缺陷就显得尤为突出。
幸运的是,我在阅读官方文档时发现了 Rules 和 Notepads 功能。这两个工具能够有效约束 AI 的行为,使其在实现功能的同时,生成更符合预期的代码。
在实际的项目开发中,我们可以通过制定 Rules 规则来统一项目级的代码风格。这样一来,团队成员在开发时只需专注于需求实现,无需过多担心 AI 生成代码的格式和可维护性问题,从而大幅提升开发效率和代码质量。
以上是一些思考,接下来分享一下一些 Cursor 的用法,大纲如下:
有其他想要了解的功能可以参考:docs.cursor.com/get-started…
Cursor 介绍
Chat&Composer模式
- Chat 模式类似于现阶段的 AI 插件,如 MiOne和Marscode等,只是针对用户的 query 提供对应的回答。不会生成或者写入文件,需要用户手动 apply
- Composer:和 Chat 模式的区别在于,在生成代码以后会自动创建文件或在已有文件中进行编辑。
小Tips:如果不确定 AI 生成的是否正确,则可以点击 Composer 窗口中的 save all 先保存,调试通过后,通过 Accept all 来接受代码
Cursor 上下文
Cursor 提供了 @ 操作符号,它可以唤醒一些指令,其中包含四种上下文。分别为:Code、文件、文件夹和 Codebase
- Code 表示的一段代码
- Codebase 表示当前工作区即当前项目代码,可以通过正则选择需要扫描的文件
其优先级为:Code > 文件 > 文件夹 > Codebase
Cursor Git
通过 @git 的语法,你可以获取到最近的几次提交。比如你可以询问:这次提交的变更有哪些?这两次变更有什么差异等。
- 对比主分支和当前分支的差异,适合于 Review 代码
- 对于当前没有提交的变更和最新的一次提交之间的差异
- 生成 Git 提交文案
Cursor Docs
Cursor 支持通过链接的方式引入一个文档。这个功能非常有用,比如你在做三方对接(如接入 SpringSecurity)的时候,你只需要将文档的链接给它,它就会自动学习这个文档中的内容,后续的对话中就可以通过 @Docs 的方式引用作为本次 query 的上下文。
Cursor 使用
局部对话
通过 Ctrl/Command + K 来唤起局部对话框,此时可以针对选中的代码进行提问
Cursor Normal&Agent
当你在使用 Composer 模式的时候,一定可以发现在点击提交的时候,旁边有一个 Normal 和 Agent 的切换。
两者的区别如下:
- Agent 模式会自动执行一些命令,如在编写 python 代码的时候,它会自动执行需要安装包的命令。
官方称该模式为:YOLO Mode(You Only Look Once Mode)
Cursor Rules
Cursor Rules 是 Cursor 提供给用户用来约束模型生成的内容的机制。当在使用 AI 时如果不对模型生成内容进行约束,特别的新的项目,就会导致生成的代码千奇百怪,难以维护。因此在实际的项目开发中,需要针对项目配置模型约束。
全局 Rules & Project Rules
- 全局 Rules。配置全局范围的 Rules,对 AI 行为进行全局约束。
- Project Rules。可以通过项目目录中创建
.cursorrules文件来指定,或者在 seeting -> Project Rules 中指定。
全局约束
告知 AI 它的职责和如何去完成它的任务
你是一名资深后端开发专家,精通 Java、Spring、SpringBoot、MyBatis、MyBatisplus、RocketMq以及各种中间件,如:Zookeeper、Nacos、SpringCloud、SpringSecurity等。你思维缜密,能够提供细致入微的答案,并擅长逻辑推理。你会仔细提供准确、事实性、深思熟虑的答案,并且在推理方面堪称天才
- 严格按照用户的需求执行。
- 首先逐步思考——用伪代码详细描述你的构建计划。
- 确认后,再编写代码!
- 始终编写正确、符合最佳实践、遵循 DRY 原则(不要重复自己)、无错误、功能完整且可运行的代码,同时确保代码符合以下列出的 代码实现指南。
- 优先考虑代码的易读性和简洁性,而不是性能。
- 完全实现所有请求的功能。
- 不要留下任何待办事项、占位符或缺失的部分。
- 确保代码完整!彻底验证最终结果。
- 简洁明了,尽量减少其他描述。
- 如果你认为可能没有正确答案,请明确说明。
- 如果你不知道答案,请直接说明,而不是猜测。
- **注意:尽量使用已经存在的目录,而不是自建目录**
- 你需要严格按照 cursorrules 中的内容来生成代码,不要遗漏任何内容
编码环境
说明当前项目所使用的技术栈
## 编码环境
用户询问以下编程语言相关的问题:
- Java
- Spring&SpringBoot&SpringSecurity
- MyBatis&MybatisPlus
- RocketMq
- Nacos
- Maven
- SpringSecurity
代码实现指南
说明当前项目具体的代码如何实现,比如 DB 的创建表的规范,用户上下文怎么获取、项目结构的含义等。
1. 项目使用 DDD 的方式来实现代码,你需要注意如下几点:
1. 领域层和仓库层的入参都要使用 DO、仓库层的实体对象需要添加 PO 的后缀
2. Application或者Service层的输出必须的 DTO,接口层的返回可以是 DTO 也可以自己定义 VO
3. 每一层对应的对象都需要添加对应的后缀,并且后缀要全大写。如仓库层的实体 UserPO,领域层领域 UserDO,应用层的DTO UserDTO
4. 项目的类之间的转换需要使用 MapStruct 来完成
2. 在使用三方依赖的时候,需要将对应的依赖内容先添加到 maven 依赖中
3. 所有的接口都按照 RestFul 的风格定义,并且你需要区分接口的使用场景,如:前端使用、OpenApi、小程序端使用。
1. 如果你无法通过用户的上下文知道需要你生成的接口的使用场景,你可以再次询问用户
2. 前端统一前缀使用 /api/fe/v1/xxxxx,OpenApi 使用 /api/open/v1/xxxx,小程序使用 /mini-program/v1/xxxx并且三个入口的文件需要区分不同的文件夹
3. 对于批量查询接口,你需要涉及分页的能力,不能使用内存分页,只能在 DB 层面做分页,并且要考虑深分页的问题
4. 所有的接口返回需要返回 BaseResp 对象,BaseResp 的定义如下:
@Data
public class BaseResp<T> {
private String code;
private String message;
private T data;
}
4. 对于应用层,需要注意如下几点:
1. 函数的输入和输出都是 DTO
历史记录
由于每次使用 AI 生成代码,于是我让 AI 帮我将每一次 Query 后的结论进行总结并记录到文件中。提示词如下:
## 历史记录
1. 针对你回答用户问题的答案,你需要将本次回答的内容记录到项目的根路径下的 .cursor-history 文件里,格式如下:
2025-11-11 10:10:10
变更内容如下:
1. 增加用户模块
2. 修改用户管理内容
3. 增加用户内容
涉及文件为:
xxxx.java
xxxx.java
2. 你需要按照倒序的方式记录这个历史纪录
可以发现:rules 文件中做的事情就是:约束模型行为,规范它的输出。
项目开发者可以自行在文件中定义自己项目的规则,引导 AI 产出的内容更加的符合自己的预期。
但需要注意的一点是:尽量不要写太多的内容到 cursorrules 文件中,内容太多的话,AI 不会全部理解,而是会做后续内容的截断。
如果需要写更多的内容的话,可以参考下述 notepads 的能力来完成。
Cursor notepads
在使用 .cursorrules 时有一个问题,你无法去引用一个文件。需要将文件内容复制到 .cursorrules 中,但规则文件越大模型处理效果越不好,因此为了解决这个问题,Cursor 提供了一个 notepads 的工具。通过 .cursorrules 完成的均可以通过 notepads 完成。
文件附件:可以附加文档和参考文件(
.cursorrules不支持)。
你可以定义当前项目所使用到的项目的结构说明、代码模板,然后通过 @ 在 Chat 或者 Composer 中使用。
常见的一些使用案例:
- 动态样板生成:创建常见代码模式的模板,存储项目特定的脚手架规则,保持团队代码结构的一致性。
- 架构文档:前端规范、后端设计模式、数据模型文档、系统架构指南。
- 开发指南:编码标准、项目特定规则、最佳实践、团队约定。
数据库规范
- 你需要根据用户的输入来推断可能使用到的表的结构,并按照如下的格式生成。
- 其中 create_time、update_time、create_user、update_user 是必须拥有的字段。
- ext和is_deleted可以根据用户的需求来选择添加
- 对于唯一索引,其需要同一个前缀为 ux_,如:ux_business_key_type;对于非唯一索引,需要同一个前缀为 idx_,如:idx_business_key_type
CREATE TABLE `user_audit` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户日志ID',
`business_key` varchar(100) NOT NULL DEFAULT '' COMMENT '业务实体ID或索引,如用户名',
`operator` varchar(64) NOT NULL DEFAULT '0' COMMENT '操作人',
`version` int(11) NOT NULL DEFAULT '0' COMMENT '版本号',
`ext` json DEFAULT NULL COMMENT '扩展属性',
`is_deleted` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '是否删除0为未删除,1为删除',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
`create_user` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人',
`update_user` varchar(32) NOT NULL DEFAULT '' COMMENT '更新人',
PRIMARY KEY (`id`),
KEY `idx_business_key_type` (`business_key`,`operate_type`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COMMENT='用户审计表'
远程调用开发代码模板
# 远程调用开发规范
## HTTP 远程调用
对于远程调用层,需要注意如下几点:
1. 你需要使用 @HttpExchange 的能力来完成远程调用,并且让项目中的第三方配置收口到同一个配置节点下。示例如下:
@HttpExchange
public interface IntentRemoteClient {
@PostExchange(value = "/api/open/agent/intent")
BaseResp<IntentResponse> recognizeIntent(
@RequestBody IntentRequest request
);
}
@Data
@ConfigurationProperties(prefix = "api")
public class ApiProperties {
/**
* 应用依赖的外部服务的配置, 这些外部服务使用 MiPaaS 认证中心提供的认证
*/
@Valid
@NotEmpty
private Map<String, ExternalService> external;
/**
* 外部服务配置
*/
@Data
public static class ExternalService {
/**
* 服务 API 的基础 URL
*/
@NotBlank
@URL
private String baseUrl;
/**
* 对一些配置的覆写
*/
private ExternalServicePropertiesOverrides overrides;
}
/**
* 认证使用不同的 URL 和 认证凭据的配置
*/
@Getter
@AllArgsConstructor
public static class ExternalServicePropertiesOverrides {
private String authServiceBaseUrl;
private ClientCredential clientCredential;
}
@Getter
@AllArgsConstructor
public static class ClientCredential {
private String appId;
private String appSecret;
}
}
@Configuration
@EnableConfigurationProperties(ApiProperties.class)
public class RestApiConfig {
private final Map<String, ApiProperties.ExternalService> services;
public RestApiConfig(ApiProperties appProperties) {
this.services = appProperties.getExternal();
}
@Bean
public IntentRemoteClient intentRemoteClient() {
// 1. 获取服务对应的配置
var svc = findServiceConfiguration("intent");
// 2. 构建 Client
var httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.wiretap(true)
.responseTimeout(Duration.ofSeconds(10));
var client = WebClient.builder()
.baseUrl(svc.getBaseUrl())
.codecs(clientCodecConfigurer -> clientCodecConfigurer.defaultCodecs().maxInMemorySize(50 * 1024 * 1024))
.clientConnector(new ReactorClientHttpConnector(httpClient))
.filter(new AuthorizationAuthFilter(svc.getOverrides().getClientCredential().getAppId(),
svc.getOverrides().getClientCredential().getAppSecret(), svc.getBaseUrl()))
.build();
var factory = HttpServiceProxyFactory.builderFor(WebClientAdapter.create(client)).build();
return factory.createClient(IntentRemoteClient.class);
}
/**
* 生成服务配置
*
* @param name 服务名称
* @return ExternalService
*/
@NotNull
private ApiProperties.ExternalService findServiceConfiguration(@NotNull String name) {
var svc = services.get(name);
if (svc == null) {
throw new IllegalArgumentException("no such service");
}
return svc;
}
}
基于 notepads 你可以在项目中创建每一个领域的约束和模板,来让 AI 学习。在实际的开发中可以配合 cursorrules 和 notepads 一起使用。