在 AI 编程助手重塑软件开发范式的今天,Cursor 凭借其智能代码生成与分析能力,成为 Java 开发者的得力工具。然而,要真正驾驭这一工具,需深入理解其核心运行机制,避免陷入 “用 AI 写代码” 的误区。
一、AI 生成代码≠写代码:3 个真实场景对比
场景 1:用户认证与授权
Cursor 生成的代码(仅演示学习,禁止生产环境使用):基础认证逻辑可能忽略密码加密与权限校验:
// Cursor 危险示例!未加密的密码明文比较
public User login(String username, String password) {
User user = userRepository.findByUsername(username);
if (user != null && user.getPassword().equals(password)) { // 明文比较密码
return user;
}
return null;
}
实际写代码:需手动添加密码加密与权限校验:
// 手动优化后的用户登录
@Service
public class AuthService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
public User login(String username, String password) {
User user = userRepository.findByUsername(username);
if (user != null && passwordEncoder.matches(password, user.getPassword())) {
// 验证权限
if (user.getStatus() != UserStatus.ACTIVE) {
throw new BusinessException("用户状态异常,无法登录");
}
return user;
}
throw new BusinessException("用户名或密码错误");
}
}
场景 2:数据持久化与事务管理
Cursor 生成的代码(仅演示学习,禁止生产环境使用):复杂业务操作未考虑事务一致性:
// Cursor 生成的用户信息更新(事务不完整)
public void updateUserProfile(Long userId, UserProfileDTO profileDTO) {
User user = userRepository.findById(userId).orElseThrow();
user.setEmail(profileDTO.getEmail());
userRepository.save(user);
// 更新关联的用户配置
UserConfig config = userConfigRepository.findByUserId(userId);
config.setNotificationEnabled(profileDTO.isNotificationEnabled());
userConfigRepository.save(config);
// 若更新配置失败,用户信息已被修改,导致数据不一致
}
实际写代码:需添加事务管理确保数据一致性:
// 手动优化后的用户信息更新
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private UserConfigRepository userConfigRepository;
@Transactional(rollbackFor = Exception.class)
public void updateUserProfile(Long userId, UserProfileDTO profileDTO) {
User user = userRepository.findById(userId).orElseThrow();
user.setEmail(profileDTO.getEmail());
userRepository.save(user);
// 更新关联的用户配置
UserConfig config = userConfigRepository.findByUserId(userId);
config.setNotificationEnabled(profileDTO.isNotificationEnabled());
userConfigRepository.save(config);
// 事务保证两个操作要么都成功,要么都失败
}
}
场景 3:文件上传与处理
Cursor 生成的代码(仅演示学习,禁止生产环境使用):文件上传未校验文件类型与大小:
// Cursor 生成的文件上传
public String uploadFile(MultipartFile file) {
try {
String fileName = UUID.randomUUID().toString() + "." + getExtension(file.getOriginalFilename());
Path filePath = Paths.get("uploads", fileName);
Files.write(filePath, file.getBytes());
return fileName;
} catch (IOException e) {
throw new BusinessException("文件上传失败", e);
}
}
实际写代码:需完善文件校验与安全处理:
// 手动优化后的文件上传
@Service
public class FileService {
private static final long MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
private static final Set<String> ALLOWED_EXTENSIONS = Set.of("jpg", "png", "pdf");
public String uploadFile(MultipartFile file) {
// 校验文件大小
if (file.getSize() > MAX_FILE_SIZE) {
throw new BusinessException("文件大小超过限制");
}
// 校验文件类型
String extension = getExtension(file.getOriginalFilename());
if (!ALLOWED_EXTENSIONS.contains(extension.toLowerCase())) {
throw new BusinessException("不支持的文件类型");
}
// 防止路径遍历攻击
String safeFileName = UUID.randomUUID().toString() + "." + extension;
Path filePath = Paths.get("uploads", safeFileName);
try {
// 使用 NIO 安全写入文件
Files.createDirectories(filePath.getParent());
Files.write(filePath, file.getBytes());
// 记录文件元数据
FileMetadata metadata = new FileMetadata();
metadata.setFileName(safeFileName);
metadata.setOriginalName(file.getOriginalFilename());
metadata.setSize(file.getSize());
metadata.setContentType(file.getContentType());
fileMetadataRepository.save(metadata);
return safeFileName;
} catch (IOException e) {
throw new BusinessException("文件上传失败", e);
}
}
private String getExtension(String fileName) {
if (fileName == null) return "";
int lastIndex = fileName.lastIndexOf('.');
return lastIndex >= 0 ? fileName.substring(lastIndex + 1) : "";
}
}
避坑案例
某内容管理系统使用 Cursor 生成富文本保存功能,未对用户输入进行 XSS 过滤,导致跨站脚本攻击:
// 危险示例!未过滤用户输入
public void saveArticle(ArticleDTO articleDTO) {
Article article = new Article();
article.setTitle(articleDTO.getTitle());
article.setContent(articleDTO.getContent()); // 未过滤 HTML 内容
articleRepository.save(article);
}
修复方案:
// 修复后的安全代码
@Service
public class ArticleService {
@Autowired
private AntiSamy antiSamy; // OWASP AntiSamy 用于 XSS 防护
public void saveArticle(ArticleDTO articleDTO) throws ScanException, PolicyException {
Article article = new Article();
article.setTitle(articleDTO.getTitle());
// 过滤 HTML 内容,防止 XSS 攻击
CleanResults cleanResults = antiSamy.scan(articleDTO.getContent());
article.setContent(cleanResults.getCleanHTML());
articleRepository.save(article);
}
}
二、规则文件模板:cursorrules.rules 进阶写法(MD 格式)
1. 后端语法与结构检查规则
# Cursor 代码检查规则集(单体架构 Java 项目)
## 一、基础语法检查
### 1. 文件完整性
- ✅ 检查所有 `.java` 文件内容非空
- ✅ 验证文件编码为 UTF-8
### 2. 语法正确性
- ✅ 检查类、接口、枚举定义
- ✅ 验证方法签名与返回类型
- ✅ 检查注解使用(如 `@Override`、`@Service` 等)
## 二、代码规范检查
### 1. 命名规范
- ✅ 包名:小写字母 + 点分隔(如 `com.yyb.service`)
- ✅ 类名:大驼峰(如 `UserService`)
- ✅ 方法名:小驼峰(如 `getUserById`)
- ✅ 常量名:全大写 + 下划线(如 `MAX_PAGE_SIZE`)
### 2. 代码结构
- ✅ MVC 分层:确保 Controller/Service/Repository 职责分离
- ✅ 避免循环依赖:禁止 A → B → A 的依赖关系
- ✅ 减少类复杂度:单个类行数不超过 500(特殊情况除外)
......
### 自动修复内容
- 格式化 {formatted_files} 个文件
- 移除 {unused_imports} 个未使用的导入
- 添加 {override_annotations} 个 `@Override` 注解
- 优化 {collection_initializations} 处集合初始化
- 修复 {syntax_fixes} 处语法错误
### 待处理问题
- 高风险:{high_risk} 处问题需立即处理(如 SQL 注入、敏感信息暴露)
- 中风险:{medium_risk} 处问题建议处理(如性能问题、空指针)
- 低风险:{low_risk} 处问题可稍后处理(如命名不规范、代码风格)
请检查修复后的代码并进行测试!```
2. 检查报告示例
代码审查完成!报告如下:
### 基础检查
- ✅ 文件完整性:35 个 Java 文件检查通过
- ✅ 语法正确性:0 个语法错误
### 代码规范
- ✅ 命名规范:2 处不规范(`UserMgr` 应改为 `UserManager`)
- ✅ 代码结构:1 处循环依赖(`UserService` → `RoleService` → `UserService`)
### 代码质量
- ✅ 安全隐患:2 处 SQL 注入风险(`ArticleDao.search` 方法)
- ✅ 性能优化:3 处 N+1 查询问题
- ✅ 异常处理:2 处未捕获的空指针风险
### 框架特定
- ✅ Spring 相关:1 处 `@Transactional` 标记在 private 方法
- ✅ MyBatis 相关:2 处 SQL 映射不匹配
### 自动修复内容
- 格式化 8 个文件
- 移除 12 个未使用的导入
- 修复 1 处循环依赖
### 待处理问题
- 高风险:2 处 SQL 注入风险(需手动修复)
- 中风险:3 处 N+1 查询、2 处空指针风险
- 低风险:2 处命名不规范、1 处事务配置错误
请检查修复后的代码并进行测试!
3. 修复建议
SQL 注入修复
// 修复前
public List<Article> search(String keyword) {
String sql = "SELECT * FROM articles WHERE title LIKE '%" + keyword + "%'";
return jdbcTemplate.query(sql, new ArticleRowMapper());
}
// 修复后
public List<Article> search(String keyword) {
String sql = "SELECT id, title, content FROM articles WHERE title LIKE ?";
return jdbcTemplate.query(
sql,
new Object[]{"%" + keyword + "%"},
new ArticleRowMapper()
);
}
N+1 查询优化
// 修复前(N+1 查询)
@Service
public class ArticleService {
public List<Article> getArticlesWithComments() {
List<Article> articles = articleRepository.findAll();
for (Article article : articles) {
// 每次循环触发一次数据库查询
List<Comment> comments = commentRepository.findByArticleId(article.getId());
article.setComments(comments);
}
return articles;
}
}
// 修复后(使用 JOIN 查询)
@Service
public class ArticleService {
public List<Article> getArticlesWithComments() {
// 一次性查询文章和评论
return articleRepository.findAllWithComments();
}
}
// ArticleRepository.java
public interface ArticleRepository extends JpaRepository<Article, Long> {
@Query("SELECT a FROM Article a JOIN FETCH a.comments WHERE a.status = 'PUBLISHED'")
List<Article> findAllWithComments();
}
三、避坑指南
- 不要过度依赖 AI:AI 生成的代码需经过人工审查,特别是涉及业务逻辑、安全和性能的部分。
- 定制规则文件:根据项目特点调整
cursorrules.rules,添加团队特有的代码规范。 - 结合单元测试:为关键功能编写单元测试,确保代码质量。
- 持续学习:通过分析 AI 生成的代码,理解其逻辑模式,提升自身编程能力。
四、结语
Cursor 作为 AI 编程助手,能显著提升单体架构项目的开发效率,但只有理解其底层逻辑并合理运用,才能真正发挥其价值。通过本文介绍的三大核心逻辑、规则文件配置和自测表,你可以构建更安全、高效的 Java 开发工作流。