# 项目页面代码检查优化以及潜在问题处理

> **场景**: 针对在旧版本需求基础上进行新需求的迭代，需要理解旧版本代码的逻辑，并在其基础进行开发新版本需求。
> 
> **作者**: yanrui  
> **日期**: 2025-06-27

---

## 案例背景描述

在旧版本需求上进行功能迭代时，可以通过Cursor对现有代码进行以下操作：
- 分析各个方法的业务逻辑
- 增加异常捕获以及日志补全
- 发现方法中隐藏的潜在问题（NullPointException...）
- 减少代码冗余、硬编码等，提高可读性、健壮性

## 使用 Cursor 的解决过程

### 1. 问题诊断 Prompt

```
@/BerthOccupyOrderServiceImpl 梳理当前业务类中各个方法业务逻辑，优化代码，包括日志补全，异常捕获，潜在异常风险处理，提高代码可读性。分批次进行优化，并指出存在的问题，以及需要优化的建议
```

### 2. 代码分析与优化方案

#### 举例其中一个方法优化分析过程

1. addEntryApply方法

   ### 业务逻辑

   - 创建占用工单对象，设置属性
   - 通过Feign保存工单
   - 保存成功后自动发起初审

   ### 存在问题

   - 参数未校验，可能NPE
   - 异常未捕获
   - 日志不够详细
   - approval返回值未判断

   ### 优化建议

   - 增加参数校验
   - try-catch包裹主流程
   - 日志补全：入参、出参、异常
   - 判断approval返回值

#### 解决方案代码

**优化前的 addEntryApply方法**：

```java
	@Override
    public Long addEntryApply(int occupyType, Date entryTime, String phone,
                              long parkId, String berthIds, String applyReason) {
        BerthOccupyOrder berthOccupyOrder = new BerthOccupyOrder();
        berthOccupyOrder.setWorkOrderId(IdentifyUtils.getId());
        berthOccupyOrder.setBerthIds(berthIds);
        berthOccupyOrder.setOccupyType(occupyType);
        berthOccupyOrder.setEntryTime(entryTime.getTime());
        berthOccupyOrder.setPhone(phone);
        berthOccupyOrder.setParkId(parkId);
        // 在场状态：0-已离场；1-在场中；2-待入场
        berthOccupyOrder.setRecordState(BerthOccupyRecordState.WAIT_ENTER.getCode());
        berthOccupyOrder.setApplyReason(applyReason);
        berthOccupyOrder.setD(0);
        LoginUser loginUser = ReqContextParams.getLoginUser();
        Long userId = Long.parseLong(loginUser.getUserId());
        berthOccupyOrder.setUserId(userId);
        berthOccupyOrder.setState(BerthOccupyOrderState.WAIT_FIRST_APPROVAL.getCode());
        log.info("占用申请创建：{}", JSON.toJSONString(berthOccupyOrder));
        int i = berthOccupyOrderFeignClient.addEntryApply(berthOccupyOrder);
        log.info("占用申请创建条数，i={}", i);
        if (i == 1) {
            //处理记录
            approval(berthOccupyOrder.getWorkOrderId(), BerthOccupyOrderState.WAIT_FIRST_APPROVAL.getCode(), null, BerthOccupyOptions.OCCUPY_IN_APPLY.getCode(),null,null);
        }
        return berthOccupyOrder.getWorkOrderId();
    }
```

**优化后的 addEntryApply方法**：

```java
	@Override
    public Long addEntryApply(int occupyType, Date entryTime, String phone,
                              long parkId, String berthIds, String applyReason) {
        log.info("addEntryApply开始执行，入参：occupyType={}, entryTime={}, phone={}, parkId={}, berthIds={}, applyReason={}", 
                occupyType, entryTime, phone, parkId, berthIds, applyReason);
        
        try {
            // 参数校验
            if (entryTime == null) {
                log.warn("addEntryApply参数校验失败：entryTime为空");
                throw new IllegalArgumentException("入场时间不能为空");
            }
            if (StringUtils.isStrTrimNull(phone)) {
                log.warn("addEntryApply参数校验失败：phone为空");
                throw new IllegalArgumentException("手机号不能为空");
            }
            if (StringUtils.isStrTrimNull(berthIds)) {
                log.warn("addEntryApply参数校验失败：berthIds为空");
                throw new IllegalArgumentException("泊位ID不能为空");
            }
            if (parkId <= 0) {
                log.warn("addEntryApply参数校验失败：parkId无效，parkId={}", parkId);
                throw new IllegalArgumentException("车场ID无效");
            }
            
            // 获取当前登录用户
            LoginUser loginUser = ReqContextParams.getLoginUser();
            if (loginUser == null || StringUtils.isStrTrimNull(loginUser.getUserId())) {
                log.error("addEntryApply获取登录用户信息失败");
                throw new RuntimeException("获取用户信息失败");
            }
            
            // 创建工单对象
            BerthOccupyOrder berthOccupyOrder = new BerthOccupyOrder();
            berthOccupyOrder.setWorkOrderId(IdentifyUtils.getId());
            berthOccupyOrder.setBerthIds(berthIds);
            berthOccupyOrder.setOccupyType(occupyType);
            berthOccupyOrder.setEntryTime(entryTime.getTime());
            berthOccupyOrder.setPhone(phone);
            berthOccupyOrder.setParkId(parkId);
            // 在场状态：0-已离场；1-在场中；2-待入场
            berthOccupyOrder.setRecordState(BerthOccupyRecordState.WAIT_ENTER.getCode());
            berthOccupyOrder.setApplyReason(applyReason);
            berthOccupyOrder.setD(0);
            
            Long userId = Long.parseLong(loginUser.getUserId());
            berthOccupyOrder.setUserId(userId);
            berthOccupyOrder.setState(BerthOccupyOrderState.WAIT_FIRST_APPROVAL.getCode());
            
            log.info("占用申请创建，工单信息：{}", JSON.toJSONString(berthOccupyOrder));
            
            // 保存工单
            int saveResult = berthOccupyOrderFeignClient.addEntryApply(berthOccupyOrder);
            log.info("占用申请创建结果，影响行数：{}", saveResult);
            
            if (saveResult != 1) {
                log.error("占用申请创建失败，预期影响行数：1，实际影响行数：{}", saveResult);
                throw new RuntimeException("占用申请创建失败");
            }
            
            // 发起初审
            log.info("开始发起初审，工单ID：{}", berthOccupyOrder.getWorkOrderId());
            ResponseResult<?> approvalResult = approval(berthOccupyOrder.getWorkOrderId(), 
                    BerthOccupyOrderState.WAIT_FIRST_APPROVAL.getCode(), null, 
                    BerthOccupyOptions.OCCUPY_IN_APPLY.getCode(), null, null);
            
            if (approvalResult == null || !approvalResult.isSuccess()) {
                log.error("初审发起失败，工单ID：{}，返回结果：{}", berthOccupyOrder.getWorkOrderId(), 
                        approvalResult != null ? approvalResult.getMsg() : "null");
                throw new RuntimeException("初审发起失败：" + (approvalResult != null ? approvalResult.getMsg() : "未知错误"));
            }
            
            log.info("addEntryApply执行成功，工单ID：{}", berthOccupyOrder.getWorkOrderId());
            return berthOccupyOrder.getWorkOrderId();
            
        } catch (IllegalArgumentException e) {
            log.warn("addEntryApply参数校验异常：{}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("addEntryApply执行异常：{}", e.getMessage(), e);
            throw new RuntimeException("创建占用申请失败：" + e.getMessage(), e);
        }
    }
```

### 3. 优化总结

- ✅ 增加参数校验（entryTime、phone、berthIds、parkId）

- ✅ 增加异常处理和详细日志

- ✅ 增加用户信息校验

- ✅ 增加approval返回值判断

- ✅ 增加数据库操作结果校验

  

## 使用体验

### Cursor 的优势（基于代码交接或者在其他开发人员开发的需求基础进行迭代维护）
- 代码健壮性大幅提升，异常和空指针风险大幅降低。
- 日志更详细，便于排查问题。
- 结构更清晰，便于后续维护和扩展。

### 注意事项
- 针对较大的文件，建议分批次进行优化，或者指定明确需要优化的方法
- 合理性接受Cursor做出的代码更改（例如:登录用户判空，其实已经在Controller层通过@NeedLogin注解增加了校验）

---

## 相关资源

- [完整对话记录](./original-conversations/cursor-service-code-optimize-conversation.md) - 查看与 Cursor AI 的完整问题分析过程

---

## 💡 学习建议

想要了解完整的问题分析过程？点击查看 [原始 Cursor 对话记录](./original-conversations/cursor-emqx-mqtt-reconnect-conversation.md)，包含：
- AI 的完整分析思路
- 多轮问题诊断过程
- 代码生成和优化过程