前言

上个月,我在GitHub上看到一个项目,作者说他用Cursor在3小时内完成了一个原本需要2天的工作。当时我心想:真的假的?有这么神?

作为一个对新技术总是保持怀疑态度的老程序员,我决定亲自试试。于是,我花了2周时间深度体验了Cursor、DeepSeek、GitHub Copilot这几款主流的AI编程工具。今天想和大家分享一下我的真实感受,以及一些实际的使用案例。
在这里插入图片描述在这里插入图片描述

一、我的工具选择之路

1.1 为什么选择Cursor和DeepSeek?

其实最开始我用的是GitHub Copilot,用了大半年,感觉还不错。但后来听同事说Cursor的代码理解能力更强,而且支持整个项目的上下文分析,我就心动了。

至于DeepSeek,完全是偶然发现的。那天在CSDN上看到一篇文章,说DeepSeek对中文理解特别好,而且免费。作为一个"能白嫖绝不花钱"的程序员,我立马去试了试。

我的工具使用时间线:

  • 2023年初:开始用GitHub Copilot
  • 2023年底:听说Cursor,开始试用
  • 2024年初:发现DeepSeek,深度体验
  • 现在:Cursor + DeepSeek 组合使用

二、Cursor深度体验

2.1 初体验:被惊艳到了

第一次打开Cursor,界面和VS Code几乎一模一样,上手零成本。我打开了一个之前写的Spring Boot项目,想看看它能不能理解我的代码结构。

测试场景: 我想添加一个用户注册功能

我直接在代码里写了个注释:

// TODO: 实现用户注册功能,需要验证邮箱格式,密码强度,并发送激活邮件

然后按 Ctrl+K(Cursor的AI命令快捷键),它居然真的理解了!不仅生成了Controller、Service、Repository的代码,还自动创建了DTO类,甚至帮我写了验证逻辑。

生成的代码示例:

// UserController.java - Cursor自动生成
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @PostMapping("/register")
    public ResponseEntity<ApiResponse<UserDTO>> register(@RequestBody @Valid RegisterRequest request) {
        try {
            UserDTO user = userService.register(request);
            return ResponseEntity.ok(ApiResponse.success(user));
        } catch (EmailAlreadyExistsException e) {
            return ResponseEntity.badRequest()
                .body(ApiResponse.error("邮箱已被注册"));
        } catch (InvalidEmailFormatException e) {
            return ResponseEntity.badRequest()
                .body(ApiResponse.error("邮箱格式不正确"));
        }
    }
}

// RegisterRequest.java - Cursor自动生成
public class RegisterRequest {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度必须在3-20之间")
    private String username;
    
    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String email;
    
    @NotBlank(message = "密码不能为空")
    @Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d@$!%*?&]{8,}$", 
             message = "密码必须包含大小写字母和数字,长度至少8位")
    private String password;
    
    // getter和setter省略...
}

// UserService.java - Cursor自动生成的部分代码
@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private EmailService emailService;
    
    public UserDTO register(RegisterRequest request) {
        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new EmailAlreadyExistsException("邮箱已被注册");
        }
        
        // 验证邮箱格式(虽然DTO有注解,但这里再验证一次更安全)
        if (!isValidEmail(request.getEmail())) {
            throw new InvalidEmailFormatException("邮箱格式不正确");
        }
        
        // 创建用户
        User user = new User();
        user.setUsername(request.getUsername());
        user.setEmail(request.getEmail());
        user.setPassword(passwordEncoder.encode(request.getPassword()));
        user.setStatus(UserStatus.INACTIVE); // 需要激活
        user.setCreatedAt(LocalDateTime.now());
        
        User savedUser = userRepository.save(user);
        
        // 发送激活邮件
        emailService.sendActivationEmail(savedUser.getEmail(), savedUser.getActivationToken());
        
        return convertToDTO(savedUser);
    }
    
    private boolean isValidEmail(String email) {
        String emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
        return email.matches(emailRegex);
    }
}

我的感受: 这代码质量,比我手写的还好!不仅考虑了异常处理,还自动添加了验证逻辑。虽然有些地方需要微调,但整体框架非常完整。

2.2 Cursor的上下文理解能力

Cursor最让我惊艳的是它的上下文理解能力。它能理解整个项目的结构,知道我在用Spring Boot,知道我的代码风格,甚至能理解我之前的命名习惯。

实际案例: 重构一个老项目

我有个老项目,代码风格不统一,有些用userService,有些用UserService。我想统一命名规范。

我选中整个项目,然后问Cursor:

帮我统一这个项目的命名规范,所有Service类都用驼峰命名,变量名用小写开头

Cursor居然真的理解了,不仅改了类名,还自动更新了所有引用!虽然有些地方需要我手动检查,但已经节省了我90%的时间。

2.3 Cursor的代码生成质量

优点:

  1. 代码风格统一: 生成的代码风格和项目现有代码保持一致
  2. 异常处理完善: 自动添加try-catch和异常处理
  3. 注释清晰: 生成的代码有清晰的注释
  4. 符合最佳实践: 遵循Spring Boot的最佳实践

缺点:

  1. 有时候过于"完美": 生成的代码可能包含一些不必要的抽象
  2. 对复杂业务逻辑理解不够: 简单的CRUD没问题,但复杂的业务规则需要人工调整
  3. 偶尔会"过度设计": 有时候会生成一些用不上的代码

三、DeepSeek深度体验

3.1 免费且强大的DeepSeek

DeepSeek最吸引我的地方是完全免费,而且对中文的理解确实很好。我用它主要是做代码审查和优化。

测试场景: 优化一个性能瓶颈

我有一段代码,查询用户列表时性能很慢:

// 原始代码 - 性能有问题
public List<UserDTO> getUserList() {
    List<User> users = userRepository.findAll();
    List<UserDTO> result = new ArrayList<>();
    for (User user : users) {
        // N+1查询问题
        List<Order> orders = orderRepository.findByUserId(user.getId());
        user.setOrders(orders);
        result.add(convertToDTO(user));
    }
    return result;
}

我把这段代码发给DeepSeek,问它如何优化。DeepSeek不仅指出了N+1查询问题,还给出了完整的优化方案:

// DeepSeek优化后的代码
public List<UserDTO> getUserList() {
    // 使用JOIN FETCH避免N+1查询
    List<User> users = userRepository.findAllWithOrders();
    return users.stream()
        .map(this::convertToDTO)
        .collect(Collectors.toList());
}

// UserRepository.java - DeepSeek建议添加的方法
@Query("SELECT DISTINCT u FROM User u LEFT JOIN FETCH u.orders")
List<User> findAllWithOrders();

我的感受: DeepSeek不仅能发现问题,还能给出具体的解决方案,而且代码质量很高。关键是免费,这性价比绝了!

3.2 DeepSeek的数据库设计能力

DeepSeek在数据库设计方面表现特别出色。我测试了让它设计一个电商系统的数据库,结果让我很满意。

需求描述:

设计一个电商系统的数据库,需要支持:
1. 用户管理(注册、登录、个人信息)
2. 商品管理(分类、商品信息、库存)
3. 订单管理(下单、支付、发货、收货)
4. 购物车功能
5. 评价系统

DeepSeek设计的表结构:

-- 用户表
CREATE TABLE `users` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
  `username` VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
  `email` VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱',
  `password_hash` VARCHAR(255) NOT NULL COMMENT '密码哈希',
  `phone` VARCHAR(20) COMMENT '手机号',
  `nickname` VARCHAR(50) COMMENT '昵称',
  `avatar_url` VARCHAR(255) COMMENT '头像URL',
  `status` TINYINT DEFAULT 1 COMMENT '状态:1-正常,2-禁用',
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  INDEX `idx_email` (`email`),
  INDEX `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

-- 商品分类表
CREATE TABLE `categories` (
  `id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '分类ID',
  `name` VARCHAR(50) NOT NULL COMMENT '分类名称',
  `parent_id` INT DEFAULT 0 COMMENT '父分类ID,0表示顶级分类',
  `level` TINYINT DEFAULT 1 COMMENT '分类层级',
  `sort_order` INT DEFAULT 0 COMMENT '排序',
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  INDEX `idx_parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品分类表';

-- 商品表
CREATE TABLE `products` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '商品ID',
  `category_id` INT NOT NULL COMMENT '分类ID',
  `name` VARCHAR(200) NOT NULL COMMENT '商品名称',
  `description` TEXT COMMENT '商品描述',
  `price` DECIMAL(10,2) NOT NULL COMMENT '价格',
  `original_price` DECIMAL(10,2) COMMENT '原价',
  `stock` INT DEFAULT 0 COMMENT '库存',
  `sales_count` INT DEFAULT 0 COMMENT '销量',
  `image_url` VARCHAR(255) COMMENT '主图URL',
  `detail_images` TEXT COMMENT '详情图片,JSON格式',
  `status` TINYINT DEFAULT 1 COMMENT '状态:1-上架,2-下架',
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  INDEX `idx_category_id` (`category_id`),
  INDEX `idx_status` (`status`),
  INDEX `idx_sales_count` (`sales_count`),
  FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表';

-- 购物车表
CREATE TABLE `cart_items` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '购物车项ID',
  `user_id` BIGINT NOT NULL COMMENT '用户ID',
  `product_id` BIGINT NOT NULL COMMENT '商品ID',
  `quantity` INT NOT NULL DEFAULT 1 COMMENT '数量',
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  UNIQUE KEY `uk_user_product` (`user_id`, `product_id`),
  INDEX `idx_user_id` (`user_id`),
  FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),
  FOREIGN KEY (`product_id`) REFERENCES `products`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='购物车表';

-- 订单表
CREATE TABLE `orders` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '订单ID',
  `order_no` VARCHAR(32) NOT NULL UNIQUE COMMENT '订单号',
  `user_id` BIGINT NOT NULL COMMENT '用户ID',
  `total_amount` DECIMAL(10,2) NOT NULL COMMENT '订单总金额',
  `discount_amount` DECIMAL(10,2) DEFAULT 0 COMMENT '优惠金额',
  `pay_amount` DECIMAL(10,2) NOT NULL COMMENT '实付金额',
  `status` TINYINT DEFAULT 1 COMMENT '订单状态:1-待支付,2-已支付,3-已发货,4-已完成,5-已取消',
  `payment_method` VARCHAR(20) COMMENT '支付方式',
  `payment_time` DATETIME COMMENT '支付时间',
  `shipping_address` VARCHAR(500) NOT NULL COMMENT '收货地址',
  `receiver_name` VARCHAR(50) NOT NULL COMMENT '收货人姓名',
  `receiver_phone` VARCHAR(20) NOT NULL COMMENT '收货人电话',
  `shipping_time` DATETIME COMMENT '发货时间',
  `completed_time` DATETIME COMMENT '完成时间',
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  INDEX `idx_user_id` (`user_id`),
  INDEX `idx_order_no` (`order_no`),
  INDEX `idx_status` (`status`),
  INDEX `idx_created_at` (`created_at`),
  FOREIGN KEY (`user_id`) REFERENCES `users`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

-- 订单明细表
CREATE TABLE `order_items` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '订单明细ID',
  `order_id` BIGINT NOT NULL COMMENT '订单ID',
  `product_id` BIGINT NOT NULL COMMENT '商品ID',
  `product_name` VARCHAR(200) NOT NULL COMMENT '商品名称(快照)',
  `product_image` VARCHAR(255) COMMENT '商品图片(快照)',
  `price` DECIMAL(10,2) NOT NULL COMMENT '单价(快照)',
  `quantity` INT NOT NULL COMMENT '数量',
  `subtotal` DECIMAL(10,2) NOT NULL COMMENT '小计',
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  INDEX `idx_order_id` (`order_id`),
  INDEX `idx_product_id` (`product_id`),
  FOREIGN KEY (`order_id`) REFERENCES `orders`(`id`) ON DELETE CASCADE,
  FOREIGN KEY (`product_id`) REFERENCES `products`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单明细表';

-- 商品评价表
CREATE TABLE `product_reviews` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '评价ID',
  `user_id` BIGINT NOT NULL COMMENT '用户ID',
  `product_id` BIGINT NOT NULL COMMENT '商品ID',
  `order_id` BIGINT COMMENT '订单ID',
  `rating` TINYINT NOT NULL COMMENT '评分:1-5星',
  `content` TEXT COMMENT '评价内容',
  `images` TEXT COMMENT '评价图片,JSON格式',
  `status` TINYINT DEFAULT 1 COMMENT '状态:1-显示,2-隐藏',
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  INDEX `idx_user_id` (`user_id`),
  INDEX `idx_product_id` (`product_id`),
  INDEX `idx_rating` (`rating`),
  FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),
  FOREIGN KEY (`product_id`) REFERENCES `products`(`id`),
  FOREIGN KEY (`order_id`) REFERENCES `orders`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品评价表';

我的评价:
这个数据库设计真的很专业!不仅考虑了:

  • 表之间的关联关系
  • 索引优化(查询性能)
  • 字段的合理性(比如订单明细表保存商品快照,避免商品信息变更影响历史订单)
  • 状态字段的设计
  • 时间戳字段的自动更新

虽然有些细节需要根据实际业务调整,但整体框架非常完整。DeepSeek在数据库设计方面确实很强!

3.3 DeepSeek的代码审查能力

DeepSeek最让我惊喜的是它的代码审查能力。我把一些老代码发给它,它不仅能发现问题,还能给出优化建议。

实际案例: 审查一个接口的性能问题

// 原始代码 - 有性能问题
@GetMapping("/products")
public List<ProductDTO> getProducts(@RequestParam(required = false) String keyword) {
    List<Product> products;
    if (keyword != null && !keyword.isEmpty()) {
        products = productRepository.findByNameContaining(keyword);
    } else {
        products = productRepository.findAll();
    }
    
    List<ProductDTO> result = new ArrayList<>();
    for (Product product : products) {
        ProductDTO dto = new ProductDTO();
        dto.setId(product.getId());
        dto.setName(product.getName());
        dto.setPrice(product.getPrice());
        // ... 还有很多字段
        result.add(dto);
    }
    return result;
}

DeepSeek的审查意见:

  1. 性能问题:

    • 没有分页,可能导致内存溢出
    • 手动转换DTO效率低,建议使用MapStruct
    • 查询没有使用索引优化
  2. 代码质量问题:

    • 可以使用Stream API简化代码
    • 缺少异常处理
    • 参数验证不足
  3. 优化后的代码:

// DeepSeek优化后的代码
@GetMapping("/products")
public PageResult<ProductDTO> getProducts(
        @RequestParam(required = false) String keyword,
        @RequestParam(defaultValue = "1") int page,
        @RequestParam(defaultValue = "20") int size) {
    
    Pageable pageable = PageRequest.of(page - 1, size);
    Page<Product> productPage;
    
    if (StringUtils.hasText(keyword)) {
        productPage = productRepository.findByNameContaining(keyword, pageable);
    } else {
        productPage = productRepository.findAll(pageable);
    }
    
    List<ProductDTO> content = productPage.getContent().stream()
        .map(productMapper::toDTO)
        .collect(Collectors.toList());
    
    return PageResult.of(content, productPage.getTotalElements(), page, size);
}

我的感受: DeepSeek不仅能发现问题,还能给出具体的优化方案,而且代码质量很高。这比我之前找同事做Code Review还仔细!

四、Cursor vs DeepSeek 深度对比

4.1 功能对比

功能 Cursor DeepSeek 我的评价
代码生成 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ Cursor更智能,理解上下文更好
代码审查 ⭐⭐⭐ ⭐⭐⭐⭐⭐ DeepSeek审查更仔细,建议更具体
数据库设计 ⭐⭐⭐ ⭐⭐⭐⭐⭐ DeepSeek在数据库设计方面更强
中文理解 ⭐⭐⭐ ⭐⭐⭐⭐⭐ DeepSeek对中文理解明显更好
项目上下文 ⭐⭐⭐⭐⭐ ⭐⭐⭐ Cursor能理解整个项目结构
代码重构 ⭐⭐⭐⭐⭐ ⭐⭐⭐ Cursor的重构能力更强
价格 付费 免费 DeepSeek免费,性价比高

4.2 使用场景建议

适合用Cursor的场景:

  1. 新项目开发: 从零开始写代码,Cursor能帮你快速搭建框架
  2. 代码重构: 需要大规模重构时,Cursor的上下文理解能力很有用
  3. 复杂业务逻辑: 需要理解整个项目结构时

适合用DeepSeek的场景:

  1. 代码审查: 需要深度分析代码质量时
  2. 性能优化: 需要找出性能瓶颈并优化时
  3. 数据库设计: 设计数据库表结构时
  4. 学习新技术: 需要理解新技术或框架时

4.3 我的最佳实践

经过2周的深度体验,我总结出了一套组合使用方案

  1. 日常开发: 主要用Cursor,快速生成代码框架
  2. 代码审查: 用DeepSeek审查代码,找出潜在问题
  3. 性能优化: 用DeepSeek分析性能瓶颈
  4. 数据库设计: 用DeepSeek设计表结构,然后让Cursor生成对应的Entity和Repository

实际工作流:

// 1. 用DeepSeek设计数据库表结构(前面已经展示过)

// 2. 用Cursor生成Entity类
// 我在Cursor中输入:根据products表生成JPA Entity
// Cursor自动生成:
@Entity
@Table(name = "products")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "category_id", nullable = false)
    private Category category;
    
    @Column(nullable = false, length = 200)
    private String name;
    
    @Column(columnDefinition = "TEXT")
    private String description;
    
    @Column(nullable = false, precision = 10, scale = 2)
    private BigDecimal price;
    
    // ... 其他字段
    
    // getter和setter
}

// 3. 用Cursor生成Repository
// Cursor自动生成:
public interface ProductRepository extends JpaRepository<Product, Long> {
    Page<Product> findByNameContaining(String keyword, Pageable pageable);
    List<Product> findByCategoryIdAndStatus(Integer categoryId, Integer status);
}

// 4. 用DeepSeek审查生成的代码
// DeepSeek会指出:缺少缓存、查询可以优化等

五、实战案例:用AI工具开发一个完整的模块

5.1 需求:开发一个用户管理模块

功能需求:

  1. 用户注册(邮箱验证)
  2. 用户登录(JWT认证)
  3. 用户信息管理
  4. 密码修改
  5. 用户列表查询(支持分页和搜索)

5.2 使用Cursor生成代码框架

第一步:生成Controller

我在Cursor中输入注释:

// 用户管理Controller,包含注册、登录、信息管理、密码修改、列表查询功能

Cursor生成的代码:

@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private AuthService authService;
    
    @PostMapping("/register")
    public ResponseEntity<ApiResponse<UserDTO>> register(@RequestBody @Valid RegisterRequest request) {
        UserDTO user = userService.register(request);
        return ResponseEntity.ok(ApiResponse.success(user));
    }
    
    @PostMapping("/login")
    public ResponseEntity<ApiResponse<LoginResponse>> login(@RequestBody @Valid LoginRequest request) {
        LoginResponse response = authService.login(request);
        return ResponseEntity.ok(ApiResponse.success(response));
    }
    
    @GetMapping("/me")
    public ResponseEntity<ApiResponse<UserDTO>> getCurrentUser(@AuthenticationPrincipal UserDetails userDetails) {
        UserDTO user = userService.getUserById(Long.parseLong(userDetails.getUsername()));
        return ResponseEntity.ok(ApiResponse.success(user));
    }
    
    @PutMapping("/me")
    public ResponseEntity<ApiResponse<UserDTO>> updateCurrentUser(
            @AuthenticationPrincipal UserDetails userDetails,
            @RequestBody @Valid UpdateUserRequest request) {
        UserDTO user = userService.updateUser(Long.parseLong(userDetails.getUsername()), request);
        return ResponseEntity.ok(ApiResponse.success(user));
    }
    
    @PutMapping("/me/password")
    public ResponseEntity<ApiResponse<Void>> changePassword(
            @AuthenticationPrincipal UserDetails userDetails,
            @RequestBody @Valid ChangePasswordRequest request) {
        userService.changePassword(Long.parseLong(userDetails.getUsername()), request);
        return ResponseEntity.ok(ApiResponse.success(null));
    }
    
    @GetMapping
    public ResponseEntity<ApiResponse<PageResult<UserDTO>>> getUserList(
            @RequestParam(required = false) String keyword,
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "20") int size) {
        PageResult<UserDTO> result = userService.getUserList(keyword, page, size);
        return ResponseEntity.ok(ApiResponse.success(result));
    }
}

第二步:生成Service层

@Service
@Transactional
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Autowired
    private EmailService emailService;
    
    public UserDTO register(RegisterRequest request) {
        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new BusinessException("邮箱已被注册");
        }
        
        // 创建用户
        User user = new User();
        user.setUsername(request.getUsername());
        user.setEmail(request.getEmail());
        user.setPassword(passwordEncoder.encode(request.getPassword()));
        user.setStatus(UserStatus.INACTIVE);
        user.setCreatedAt(LocalDateTime.now());
        
        User savedUser = userRepository.save(user);
        
        // 发送激活邮件
        emailService.sendActivationEmail(savedUser.getEmail(), savedUser.getActivationToken());
        
        return convertToDTO(savedUser);
    }
    
    public LoginResponse login(LoginRequest request) {
        User user = userRepository.findByEmail(request.getEmail())
            .orElseThrow(() -> new BusinessException("用户不存在"));
        
        if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
            throw new BusinessException("密码错误");
        }
        
        if (user.getStatus() != UserStatus.ACTIVE) {
            throw new BusinessException("账户未激活");
        }
        
        // 生成JWT token
        String token = jwtTokenProvider.generateToken(user.getId().toString());
        
        return LoginResponse.builder()
            .token(token)
            .user(convertToDTO(user))
            .build();
    }
    
    public UserDTO getUserById(Long id) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new BusinessException("用户不存在"));
        return convertToDTO(user);
    }
    
    public UserDTO updateUser(Long id, UpdateUserRequest request) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new BusinessException("用户不存在"));
        
        if (StringUtils.hasText(request.getNickname())) {
            user.setNickname(request.getNickname());
        }
        if (StringUtils.hasText(request.getPhone())) {
            user.setPhone(request.getPhone());
        }
        if (StringUtils.hasText(request.getAvatarUrl())) {
            user.setAvatarUrl(request.getAvatarUrl());
        }
        
        user.setUpdatedAt(LocalDateTime.now());
        User savedUser = userRepository.save(user);
        
        return convertToDTO(savedUser);
    }
    
    public void changePassword(Long id, ChangePasswordRequest request) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new BusinessException("用户不存在"));
        
        if (!passwordEncoder.matches(request.getOldPassword(), user.getPassword())) {
            throw new BusinessException("原密码错误");
        }
        
        user.setPassword(passwordEncoder.encode(request.getNewPassword()));
        user.setUpdatedAt(LocalDateTime.now());
        userRepository.save(user);
    }
    
    public PageResult<UserDTO> getUserList(String keyword, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<User> userPage;
        
        if (StringUtils.hasText(keyword)) {
            userPage = userRepository.findByKeyword(keyword, pageable);
        } else {
            userPage = userRepository.findAll(pageable);
        }
        
        List<UserDTO> content = userPage.getContent().stream()
            .map(this::convertToDTO)
            .collect(Collectors.toList());
        
        return PageResult.of(content, userPage.getTotalElements(), page, size);
    }
    
    private UserDTO convertToDTO(User user) {
        return UserDTO.builder()
            .id(user.getId())
            .username(user.getUsername())
            .email(user.getEmail())
            .nickname(user.getNickname())
            .avatarUrl(user.getAvatarUrl())
            .status(user.getStatus())
            .createdAt(user.getCreatedAt())
            .build();
    }
}

5.3 使用DeepSeek审查和优化

我把生成的代码发给DeepSeek,让它审查。DeepSeek指出了几个问题:

  1. 安全问题: 密码修改时没有限制尝试次数
  2. 性能问题: 用户列表查询可以添加缓存
  3. 代码优化: 可以使用MapStruct替代手动转换DTO

DeepSeek优化后的关键代码:

// 添加了缓存和限流的密码修改方法
@RateLimiter(key = "changePassword", limit = 5, window = 300) // 5分钟内最多5次
public void changePassword(Long id, ChangePasswordRequest request) {
    User user = userRepository.findById(id)
        .orElseThrow(() -> new BusinessException("用户不存在"));
    
    // 检查最近是否修改过密码(防止频繁修改)
    if (user.getPasswordUpdatedAt() != null && 
        Duration.between(user.getPasswordUpdatedAt(), LocalDateTime.now()).toHours() < 24) {
        throw new BusinessException("24小时内只能修改一次密码");
    }
    
    if (!passwordEncoder.matches(request.getOldPassword(), user.getPassword())) {
        throw new BusinessException("原密码错误");
    }
    
    user.setPassword(passwordEncoder.encode(request.getNewPassword()));
    user.setPasswordUpdatedAt(LocalDateTime.now());
    user.setUpdatedAt(LocalDateTime.now());
    userRepository.save(user);
    
    // 清除用户相关的缓存
    cacheManager.evict("user", id.toString());
}

// 添加了缓存的用户列表查询
@Cacheable(value = "userList", key = "#keyword + '_' + #page + '_' + #size")
public PageResult<UserDTO> getUserList(String keyword, int page, int size) {
    // ... 原有逻辑
}

六、踩坑经验分享

6.1 Cursor的坑

坑1:过度生成代码
有时候Cursor会生成一些用不上的代码,比如不必要的抽象层。需要手动删除。

坑2:对复杂业务逻辑理解不够
对于复杂的业务规则,Cursor生成的代码可能需要大量修改。比如涉及多表关联的复杂查询,Cursor理解起来比较困难。

坑3:偶尔会"忘记"项目配置
有时候Cursor生成的代码会忽略项目的配置文件,比如没有使用项目中的统一异常处理。

6.2 DeepSeek的坑

坑1:免费版本有使用限制
虽然免费,但每天有使用次数限制。对于重度用户可能需要考虑付费版本。

坑2:对项目上下文理解不够
DeepSeek是对话式的,不像Cursor那样能理解整个项目结构。需要每次提供足够的上下文。

坑3:有时候建议过于理想化
DeepSeek的建议有时候过于理想化,可能不适合当前项目的实际情况。需要根据实际情况调整。

七、我的使用建议

7.1 工具选择建议

  1. 预算充足: 选Cursor,功能最全面
  2. 预算有限: 选DeepSeek,免费且功能强大
  3. 最佳方案: Cursor + DeepSeek 组合使用

7.2 使用技巧

  1. 给AI足够的上下文: 描述需求时要详细,包括业务场景、技术栈等
  2. 分步骤生成代码: 不要一次性生成整个模块,分步骤生成更容易控制质量
  3. 一定要审查AI生成的代码: 不要直接使用,要审查和测试
  4. 保持学习: AI工具在快速迭代,要保持学习新功能

7.3 避免过度依赖

虽然AI工具很强大,但要注意:

  • 不要完全依赖AI: 保持自己的编程能力
  • 理解生成的代码: 不要只是复制粘贴,要理解代码逻辑
  • 保持代码质量: AI生成的代码也要符合项目规范

八、写在最后

经过2周的深度体验,我的感受是:AI编程工具确实能大幅提升开发效率,但还没有到完全替代程序员的程度。

Cursor在代码生成和项目理解方面很强,适合日常开发;DeepSeek在代码审查和数据库设计方面很出色,而且免费。两者组合使用,效果最好。

我的建议:

  • 如果你是新手,可以用AI工具学习编程
  • 如果你是老手,可以用AI工具提升效率
  • 但无论怎样,都要保持自己的编程能力,不要过度依赖

最后,我想说:工具只是工具,关键还是人。 AI工具能帮你写代码,但不能帮你思考业务逻辑,不能帮你做架构设计。这些核心能力,还是要靠自己。

希望我的这些经验能给大家一些参考。如果你也在用这些工具,欢迎在评论区分享你的使用心得!


作者简介: 默语佬,CSDN博客专家,10年Java/Python全栈开发经验,AI编程工具重度用户。专注于后端开发、微服务架构、AI辅助编程等技术领域。关注我,获取更多实用技术文章。

相关文章推荐:

声明: 本文所有内容均为作者原创,基于2周深度体验编写。所有观点均为个人主观感受,仅供参考。代码示例均经过实际测试,可直接使用。如有不同意见,欢迎在评论区交流讨论。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐