编辑 | blame | 历史 | 原始文档

转运部同步功能 - 代码修改清单

修改时间

2025-10-18

需求说明

在现有的分公司同步功能基础上,增加转运部同步功能。转运部是总公司(ID=101)下的一个部门,需要同步转运部及其所有子部门。

关键差异

项目 分公司同步 转运部同步
父部门 若依科技(ID=100) 总公司(ID=101)
SQL Server 查询条件 a.departmentName = N'合作单位' a.departmentName = N'转运部'
名称格式 湛江--护士(需要解析"--") 直接使用 departmentName
同步逻辑 创建分公司 + 子部门(两层) 创建转运部 + 子部门(两层)

修改文件列表

1. DepartmentSyncMapper.xml ✅

文件路径: ruoyi-system/src/main/resources/mapper/system/DepartmentSyncMapper.xml

修改内容: 新增查询方法 selectTransportDepartments

<!-- 查询转运部下的所有子部门 -->
<select id="selectTransportDepartments" resultMap="DepartmentSyncResult">
    <![CDATA[
    SELECT TOP 500
        b.departmentID,
        b.departmentName,
        b.parentID,
        a.departmentName AS parentName
    FROM uv_department a WITH (NOLOCK)
    INNER JOIN uv_department b WITH (NOLOCK) ON a.departmentID = b.parentID 
    WHERE a.departmentName = N'转运部'
    ORDER BY b.departmentName
    ]]>
</select>

关键点:
- 使用 CDATA 包裹 SQL 避免 XML 特殊字符问题
- 使用 TOP 500 限制返回数据量
- 使用 WITH (NOLOCK) 提高并发性能
- 中文字符串使用 N 前缀


2. DepartmentSyncMapper.java ✅

文件路径: ruoyi-system/src/main/java/com/ruoyi/system/mapper/DepartmentSyncMapper.java

修改内容: 新增方法声明

/**
 * 查询转运部下的所有子部门
 * 
 * @return 转运部子部门列表
 */
List<DepartmentSyncDTO> selectTransportDepartments();

修改位置: 第 23-28 行(在 selectBranchDepartments() 方法后添加)


3. IDepartmentSyncDataService.java ✅

文件路径: ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncDataService.java

修改内容: 新增方法声明

/**
 * 从 SQL Server 查询转运部下的所有子部门数据
 * 
 * 数据源:SQL Server (uv_department 视图)
 * 
 * @return 转运部子部门列表
 */
List<DepartmentSyncDTO> getTransportDepartments();

修改位置: 第 24-32 行(在 getBranchDepartments() 方法后添加)


4. DepartmentSyncDataServiceImpl.java ✅

文件路径: ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncDataServiceImpl.java

修改内容: 新增方法实现

/**
 * 从 SQL Server 查询转运部下的所有子部门数据
 * 
 * 注意:DepartmentSyncMapper 上有 @DataSource(DataSourceType.SQLSERVER) 注解
 * 此方法会自动切换到 SQL Server 数据源执行查询
 * 
 * @return 转运部子部门列表
 */
@Override
public List<DepartmentSyncDTO> getTransportDepartments()
{
    try
    {
        log.info("开始从 SQL Server 查询转运部子部门数据...");
        
        // 调用 Mapper 查询 SQL Server 数据
        // @DataSource 注解会自动切换数据源
        List<DepartmentSyncDTO> transportDepts = departmentSyncMapper.selectTransportDepartments();
        
        if (transportDepts == null || transportDepts.isEmpty())
        {
            log.warn("未从 SQL Server 查询到转运部子部门数据");
            return transportDepts;
        }
        
        log.info("从 SQL Server 查询到 {} 条转运部子部门数据", transportDepts.size());
        return transportDepts;
    }
    catch (Exception e)
    {
        log.error("从 SQL Server 查询转运部子部门数据失败", e);
        throw new RuntimeException("查询 SQL Server 数据失败: " + e.getMessage(), e);
    }
}

修改位置: 第 67-102 行(在 getBranchDepartments() 方法后、类结束前添加)


5. IDepartmentSyncService.java ✅

文件路径: ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncService.java

修改内容: 新增方法声明

/**
 * 同步转运部和子部门数据(使用外部传入的数据源)
 * 
 * 同步逻辑:
 * 1. 确保总公司(ID=101)下存在"转运部"
 * 2. 创建转运部的子部门(直接创建,无需解析"--"格式)
 * 
 * @param transportDepts 外部传入的转运部子部门数据列表
 * @return 同步结果
 */
AjaxResult syncTransportDepartments(List<DepartmentSyncDTO> transportDepts);

修改位置: 第 29-40 行(在 syncBranchDepartments() 方法后添加)


6. DepartmentSyncServiceImpl.java ✅

文件路径: ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncServiceImpl.java

修改内容: 新增方法实现(核心同步逻辑)

完整方法: 第 189-324 行

关键逻辑:

  1. 检查总公司是否存在(第 197-202 行)
    java SysDept headOffice = sysDeptMapper.selectDeptById(101L); if (headOffice == null) { log.error("总公司(ID=101)不存在,无法同步转运部"); return AjaxResult.error("总公司(ID=101)不存在,请先创建总公司"); }

  2. 确保转运部存在(第 204-227 行)
    ```java
    SysDept existingTransport = sysDeptMapper.checkDeptNameUnique("转运部", 101L);

if (existingTransport != null)
{
transportDeptId = existingTransport.getDeptId();
log.info("转运部已存在: ID={}", transportDeptId);
}
else
{
// 创建新的转运部
SysDept newTransport = new SysDept();
newTransport.setParentId(101L);
newTransport.setDeptName("转运部");
newTransport.setAncestors("0,101");
newTransport.setOrderNum(1);
newTransport.setStatus("0");
newTransport.setCreateBy("sync");

sysDeptMapper.insertDept(newTransport);
transportDeptId = newTransport.getDeptId();
log.info("创建新转运部: ID={}", transportDeptId);

}
```

  1. 同步子部门(第 229-293 行)
    ```java
    for (DepartmentSyncDTO dto : transportDepts)
    {
    String deptName = dto.getDepartmentName();

    // 先根据departmentId查询是否已存在
    SysDept existingDept = sysDeptMapper.selectDeptByDepartmentIdAndParentId(
    dto.getDepartmentId(), transportDeptId);

    if (existingDept != null)
    {
    // 更新已存在的部门
    existingDept.setDeptName(deptName);
    existingDept.setUpdateBy("sync");
    sysDeptMapper.updateDept(existingDept);
    updatedDept++;
    }
    else
    {
    // 检查是否存在同名部门
    SysDept sameName = sysDeptMapper.checkDeptNameUnique(deptName, transportDeptId);
    if (sameName != null)
    {
    // 更新同名部门的 departmentId
    sameName.setDepartmentId(dto.getDepartmentId());
    sameName.setUpdateBy("sync");
    sysDeptMapper.updateDept(sameName);
    updatedDept++;
    }
    else
    {
    // 创建新部门
    SysDept newDept = new SysDept();
    newDept.setParentId(transportDeptId);
    newDept.setDeptName(deptName);
    newDept.setAncestors("0,101," + transportDeptId);
    newDept.setOrderNum(1);
    newDept.setStatus("0");
    newDept.setDepartmentId(dto.getDepartmentId());
    newDept.setCreateBy("sync");

        sysDeptMapper.insertDept(newDept);
        createdDept++;
    }
    
    }
    }
    ```

设计特点:
- 支持幂等性(可重复执行)
- 自动判断创建还是更新
- 使用 @Transactional 保证事务一致性
- 详细的日志记录


7. DepartmentSyncController.java ✅

文件路径: ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java

修改内容: 新增 REST API 接口

/**
 * 同步转运部和子部门数据(使用外部传入的数据源)
 * 
 * 同步逻辑:
 * 1. 确保总公司(ID=101)下存在"转运部"
 * 2. 创建转运部的子部门
 * 
 * @param transportDepts 转运部子部门数据列表
 * @return 同步结果
 */
@PreAuthorize("@ss.hasPermi('system:dept:sync')")
@PostMapping("/transport/data")
public AjaxResult syncTransportDepartmentsWithData(@RequestBody List<DepartmentSyncDTO> transportDepts)
{
    return departmentSyncService.syncTransportDepartments(transportDepts);
}

修改位置: 第 50-64 行(在 /branch/data 接口后添加)

接口信息:
- URL: POST /system/dept/sync/transport/data
- 权限: system:dept:sync
- 请求体: List<DepartmentSyncDTO>
- 响应: AjaxResult


新增文档

1. 转运部同步功能说明.md ✅

文件路径: 转运部同步功能说明.md

内容包括:
- 功能概述
- 同步逻辑说明
- 实现架构
- 核心类详细说明
- REST API 接口
- 数据流程图
- 部门层级结构
- 幂等性设计
- 事务管理
- 数据源切换机制
- 完整调用示例
- 注意事项

2. 转运部同步功能测试指南.md ✅

文件路径: 转运部同步功能测试指南.md

内容包括:
- 测试环境准备
- 测试步骤
- 测试场景(5个场景)
- 完整测试流程(Java 代码)
- 日志监控
- 常见问题排查
- 性能测试
- 回滚测试数据
- 测试清单


代码统计

文件类型 新增文件 修改文件 总计
Mapper XML 0 1 1
Java 接口 0 3 3
Java 实现类 0 2 2
Controller 0 1 1
文档 3 0 3
总计 3 7 10

新增代码行数统计

文件 新增行数
DepartmentSyncMapper.xml 12 行
DepartmentSyncMapper.java 7 行
IDepartmentSyncDataService.java 9 行
DepartmentSyncDataServiceImpl.java 35 行
IDepartmentSyncService.java 12 行
DepartmentSyncServiceImpl.java 138 行
DepartmentSyncController.java 17 行
代码总计 230 行
转运部同步功能说明.md 455 行
转运部同步功能测试指南.md 411 行
转运部同步功能-修改清单.md 本文档
文档总计 866+ 行

技术要点

1. SQL Server 查询优化

  • ✅ 使用 TOP 500 限制返回数据量
  • ✅ 使用 WITH (NOLOCK) 提高并发性能
  • ✅ 中文字符串使用 N 前缀确保正确匹配
  • ✅ 使用 <![CDATA[...]]> 包裹 SQL 避免 XML 解析问题

2. 多数据源架构

  • ✅ DataService 标注 @DataSource(DataSourceType.SQLSERVER) 查询 SQL Server
  • ✅ SyncService 使用默认数据源操作 MySQL
  • ✅ 智能数据源切换(详见:多数据源切换问题修复说明.md)

3. 幂等性设计

  • ✅ 使用 departmentId 作为唯一标识
  • ✅ 先查询后决定插入或更新
  • ✅ 支持重复执行不会产生重复数据

4. 事务管理

  • ✅ 所有同步方法标注 @Transactional
  • ✅ 异常时自动回滚
  • ✅ 保证数据一致性

5. 职责分离

  • ✅ DataService: 专门负责查询 SQL Server
  • ✅ SyncService: 专门负责同步到 MySQL
  • ✅ Controller: 提供 REST API 接口

测试验证

编译检查 ✅

所有修改的文件均通过编译检查,无语法错误。

功能测试

请参考 转运部同步功能测试指南.md 进行以下测试:

  • [ ] 测试 1: 从 SQL Server 查询转运部数据
  • [ ] 测试 2: 通过 REST API 同步转运部
  • [ ] 测试 3: 验证 MySQL 中的同步结果
  • [ ] 场景 1: 首次同步
  • [ ] 场景 2: 重复同步(幂等性)
  • [ ] 场景 3: 部分更新
  • [ ] 场景 4: 同名部门处理
  • [ ] 场景 5: 总公司不存在错误处理

部署说明

1. 数据库准备

确保 MySQL 中存在总公司:
```sql
-- 检查总公司是否存在
SELECT * FROM sys_dept WHERE dept_id = 101;

-- 如果不存在,创建总公司
INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, status, create_by, create_time)
VALUES (101, 0, '0', '总公司', 1, '0', 'admin', NOW());
```

2. 代码部署

  1. 编译项目:mvn clean package
  2. 部署到服务器
  3. 重启应用

3. 权限配置

确保需要调用同步接口的用户拥有 system:dept:sync 权限。


调用示例

REST API 调用

curl -X POST http://localhost:8080/system/dept/sync/transport/data \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '[
    {
      "departmentId": 1001,
      "departmentName": "转运队",
      "parentId": 100,
      "parentName": "转运部"
    },
    {
      "departmentId": 1002,
      "departmentName": "调度中心",
      "parentId": 100,
      "parentName": "转运部"
    }
  ]'

Java 代码调用

// 步骤 1: 查询 SQL Server 数据
List<DepartmentSyncDTO> transportDepts = departmentSyncDataService.getTransportDepartments();

// 步骤 2: 同步到 MySQL
AjaxResult result = departmentSyncService.syncTransportDepartments(transportDepts);

后续优化建议

1. 添加查询接口

可以添加一个 GET 接口直接返回 SQL Server 的转运部数据:
java @GetMapping("/transport/query") public AjaxResult queryTransportDepartments() { List<DepartmentSyncDTO> transportDepts = departmentSyncDataService.getTransportDepartments(); return AjaxResult.success(transportDepts); }

2. 添加内部查询模式

像分公司同步一样,添加一个不需要传参的同步方法:
```java
// 接口
AjaxResult syncTransportDepartments();

// 实现
@Override
@Transactional
public AjaxResult syncTransportDepartments()
{
List transportDepts = departmentSyncDataService.getTransportDepartments();
return syncTransportDepartments(transportDepts);
}

// Controller
@PostMapping("/transport")
public AjaxResult syncTransportDepartments()
{
return departmentSyncService.syncTransportDepartments();
}
```

3. 批量同步

添加一个接口同时同步分公司和转运部:
```java
@PostMapping("/all")
public AjaxResult syncAllDepartments()
{
// 同步分公司
AjaxResult branchResult = syncBranchDepartments();

// 同步转运部
AjaxResult transportResult = syncTransportDepartments();

// 合并结果返回
return AjaxResult.success("全部同步完成", 
    Map.of("branch", branchResult, "transport", transportResult));

}
```


相关文档链接

  1. 转运部同步功能说明.md - 功能详细说明
  2. 转运部同步功能测试指南.md - 测试指南
  3. 部门同步服务重构说明.md - 分公司同步架构
  4. 用户同步服务重构说明.md - 用户同步架构
  5. 多数据源切换问题修复说明.md - 数据源切换机制
  6. [SQL Server数据源查询优化说明.md](SQL Server数据源查询优化说明.md) - SQL 优化

版本信息

  • 功能版本: v1.0
  • 开发日期: 2025-10-18
  • 开发人员: AI Assistant
  • 审核状态: 待测试
  • 框架版本: RuoYi-Vue (Spring Boot 2.5.15)

更新日志

v1.0 (2025-10-18)

  • ✅ 新增转运部数据查询功能
  • ✅ 新增转运部同步功能
  • ✅ 新增 REST API 接口
  • ✅ 编写功能说明文档
  • ✅ 编写测试指南文档
  • ✅ 编写修改清单文档