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

部门同步服务重构说明

重构概述

将部门同步功能重构为**数据查询**和**数据同步**两个独立的服务,实现职责分离和灵活性提升。


架构变化

重构前

┌─────────────────────────────────────────┐
│   DepartmentSyncServiceImpl             │
│                                         │
│   ┌─────────────────────────────────┐  │
│   │ syncBranchDepartments()         │  │
│   │  ├─ 查询 SQL Server             │  │
│   │  └─ 写入 MySQL                  │  │
│   └─────────────────────────────────┘  │
└─────────────────────────────────────────┘

问题
- ❌ 数据查询和同步逻辑耦合
- ❌ 无法使用外部数据源
- ❌ 难以扩展其他数据来源

重构后

┌──────────────────────────────────────────────────────────┐
│  DepartmentSyncDataServiceImpl (新增)                     │
│  职责:从 SQL Server 查询数据                             │
│                                                           │
│  ├─ getBranchDepartments()                               │
│      └─ 返回 List<DepartmentSyncDTO>                     │
└──────────────────────────────────────────────────────────┘
                              │
                              v
┌──────────────────────────────────────────────────────────┐
│  DepartmentSyncServiceImpl (重构)                        │
│  职责:接收数据并写入 MySQL                               │
│                                                           │
│  ├─ syncBranchDepartments()                              │
│  │   └─ 调用 DepartmentSyncDataService 获取数据          │
│  │                                                        │
│  └─ syncBranchDepartments(List<DepartmentSyncDTO>)       │
│      └─ 接收外部传入的数据进行同步                        │
└──────────────────────────────────────────────────────────┘

优势
- ✅ 职责单一,易于维护
- ✅ 支持外部数据源
- ✅ 灵活性高,易于扩展


核心组件

1. IDepartmentSyncDataService(新增)

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

职责: 定义从 SQL Server 查询数据的接口

public interface IDepartmentSyncDataService {
    /**
     * 从 SQL Server 查询合作单位下的所有分公司数据
     * 
     * @return 分公司列表
     */
    List<DepartmentSyncDTO> getBranchDepartments();
}

2. DepartmentSyncDataServiceImpl(新增)

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

职责: 专门负责从 SQL Server 查询部门数据

关键特性:
```java
@Service
public class DepartmentSyncDataServiceImpl implements IDepartmentSyncDataService {
@Autowired
private DepartmentSyncMapper departmentSyncMapper; // 带 @DataSource 注解

@Override
public List<DepartmentSyncDTO> getBranchDepartments() {
    log.info("开始从 SQL Server 查询分公司数据...");

    // 自动切换到 SQL Server 数据源
    List<DepartmentSyncDTO> branchDepts = departmentSyncMapper.selectBranchDepartments();

    log.info("从 SQL Server 查询到 {} 条分公司数据", branchDepts.size());
    return branchDepts;
}

}
```

数据流:
DepartmentSyncDataServiceImpl ↓ DepartmentSyncMapper (@DataSource(SQLSERVER)) ↓ SQL Server 数据库 (uv_department) ↓ 返回 List<DepartmentSyncDTO>


3. IDepartmentSyncService(重构)

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

变化: 新增重载方法,支持外部数据源

public interface IDepartmentSyncService {
    /**
     * 同步分公司和部门数据(从 SQL Server 查询并同步到 MySQL)
     */
    AjaxResult syncBranchDepartments();
    
    /**
     * 同步分公司和部门数据(使用外部传入的数据源)
     * 
     * @param branchDepts 外部传入的分公司数据列表
     */
    AjaxResult syncBranchDepartments(List<DepartmentSyncDTO> branchDepts);
}

4. DepartmentSyncServiceImpl(重构)

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

变化:
1. 移除对 DepartmentSyncMapper 的直接依赖
2. 注入 IDepartmentSyncDataService 获取数据
3. 新增 syncBranchDepartments(List<DepartmentSyncDTO>) 方法

重构后的代码:

@Service
public class DepartmentSyncServiceImpl implements IDepartmentSyncService {
    
    @Autowired
    private IDepartmentSyncDataService departmentSyncDataService; // 数据查询服务
    
    @Autowired
    private SysDeptMapper sysDeptMapper; // MySQL 操作
    
    // 方法 1: 内部查询 + 同步
    @Override
    @Transactional
    public AjaxResult syncBranchDepartments() {
        // 调用数据查询服务获取 SQL Server 数据
        List<DepartmentSyncDTO> branchDepts = departmentSyncDataService.getBranchDepartments();
        
        if (branchDepts == null || branchDepts.isEmpty()) {
            return AjaxResult.warn("未获取到需要同步的分公司数据");
        }
        
        // 调用重载方法执行同步
        return syncBranchDepartments(branchDepts);
    }
    
    // 方法 2: 外部数据源 + 同步(新增)
    @Override
    @Transactional
    public AjaxResult syncBranchDepartments(List<DepartmentSyncDTO> branchDepts) {
        if (branchDepts == null || branchDepts.isEmpty()) {
            return AjaxResult.warn("传入的部门数据为空");
        }
        
        log.info("开始同步 {} 条分公司数据到 MySQL 数据库...", branchDepts.size());
        
        // 同步逻辑(只涉及 MySQL 操作)
        // ...
    }
}

数据流:

流程 1: 内部查询 + 同步

syncBranchDepartments()
    ↓
调用 departmentSyncDataService.getBranchDepartments()
    ↓
获取 List<DepartmentSyncDTO>
    ↓
调用 syncBranchDepartments(List)
    ↓
写入 MySQL 数据库

流程 2: 外部数据源 + 同步

外部调用者提供 List<DepartmentSyncDTO>
    ↓
syncBranchDepartments(List)
    ↓
写入 MySQL 数据库

5. DepartmentSyncController(更新)

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

变化: 新增接口支持外部数据源

@RestController
@RequestMapping("/system/dept/sync")
public class DepartmentSyncController {
    
    @Autowired
    private IDepartmentSyncService departmentSyncService;
    
    /**
     * 接口 1: 同步分公司和部门数据(从 SQL Server 查询并同步)
     */
    @PostMapping("/branch")
    public AjaxResult syncBranchDepartments() {
        return departmentSyncService.syncBranchDepartments();
    }
    
    /**
     * 接口 2: 同步分公司和部门数据(使用外部传入的数据源)
     */
    @PostMapping("/branch/data")
    public AjaxResult syncBranchDepartmentsWithData(@RequestBody List<DepartmentSyncDTO> branchDepts) {
        return departmentSyncService.syncBranchDepartments(branchDepts);
    }
}

使用场景

场景 1: 常规同步(从 SQL Server 查询)

POST http://localhost:8080/system/dept/sync/branch

执行流程:
1. Controller 调用 departmentSyncService.syncBranchDepartments()
2. Service 调用 departmentSyncDataService.getBranchDepartments()
3. 自动切换到 SQL Server 查询数据
4. 将数据写入 MySQL


场景 2: 使用外部数据源

POST http://localhost:8080/system/dept/sync/branch/data
Content-Type: application/json

[
  {
    "departmentId": 1001,
    "departmentName": "湛江--护士",
    "parentId": 100,
    "parentName": "合作单位"
  },
  {
    "departmentId": 1002,
    "departmentName": "湛江--车队",
    "parentId": 100,
    "parentName": "合作单位"
  }
]

执行流程:
1. Controller 接收 JSON 数据并转换为 List<DepartmentSyncDTO>
2. Controller 调用 departmentSyncService.syncBranchDepartments(branchDepts)
3. Service 直接将数据写入 MySQL


场景 3: 从其他系统获取数据后同步

@Service
public class CustomSyncService {
    
    @Autowired
    private IDepartmentSyncService departmentSyncService;
    
    public void syncFromExternalSystem() {
        // 1. 从其他系统获取数据(如 HTTP API、消息队列等)
        List<DepartmentSyncDTO> externalData = fetchDataFromExternalSystem();
        
        // 2. 进行数据预处理
        List<DepartmentSyncDTO> processedData = preprocessData(externalData);
        
        // 3. 调用同步服务
        AjaxResult result = departmentSyncService.syncBranchDepartments(processedData);
        
        log.info("同步结果: {}", result.get("msg"));
    }
}

场景 4: 批量同步多个数据源

@Service
public class BatchSyncService {
    
    @Autowired
    private IDepartmentSyncDataService departmentSyncDataService;
    
    @Autowired
    private IDepartmentSyncService departmentSyncService;
    
    public void batchSync() {
        // 1. 从 SQL Server 获取数据
        List<DepartmentSyncDTO> sqlServerData = departmentSyncDataService.getBranchDepartments();
        
        // 2. 从其他来源获取数据
        List<DepartmentSyncDTO> otherData = getDataFromOtherSource();
        
        // 3. 合并数据
        List<DepartmentSyncDTO> allData = new ArrayList<>();
        allData.addAll(sqlServerData);
        allData.addAll(otherData);
        
        // 4. 统一同步
        departmentSyncService.syncBranchDepartments(allData);
    }
}

接口对比

接口 路径 数据来源 适用场景
接口 1 POST /system/dept/sync/branch 内部查询 SQL Server 常规定时同步
接口 2 POST /system/dept/sync/branch/data 外部传入 JSON 手动数据导入、数据预处理、多源整合

定时任务更新

定时任务可以继续使用原有方式,无需修改:

@Component("oaSyncTask")
public class OaSyncTask {
    
    @Autowired
    private IDepartmentSyncService departmentSyncService;
    
    public void syncOaData() {
        // 自动从 SQL Server 查询并同步
        AjaxResult result = departmentSyncService.syncBranchDepartments();
        log.info("定时同步结果: {}", result.get("msg"));
    }
}

优势总结

1. 职责分离 ✅

  • DepartmentSyncDataService: 只负责查询数据
  • DepartmentSyncService: 只负责同步数据

2. 灵活性提升 ✅

  • 支持从 SQL Server 查询
  • 支持外部数据源
  • 支持数据预处理
  • 支持多源数据整合

3. 易于扩展 ✅

// 扩展:支持其他数据源
public interface IDepartmentSyncDataService {
    List<DepartmentSyncDTO> getBranchDepartments();           // SQL Server
    List<DepartmentSyncDTO> getBranchDepartmentsFromOracle(); // Oracle
    List<DepartmentSyncDTO> getBranchDepartmentsFromAPI();    // HTTP API
}

4. 易于测试 ✅

@Test
public void testSyncWithMockData() {
    // 创建测试数据
    List<DepartmentSyncDTO> testData = createTestData();
    
    // 测试同步逻辑
    AjaxResult result = departmentSyncService.syncBranchDepartments(testData);
    
    // 验证结果
    assertEquals(200, result.get("code"));
}

迁移指南

对于现有代码

无需修改!原有调用方式完全兼容:

// 原有代码
departmentSyncService.syncBranchDepartments();

// 仍然有效,行为不变

对于新功能

使用新增的重载方法:

// 新功能:使用外部数据源
List<DepartmentSyncDTO> externalData = getExternalData();
departmentSyncService.syncBranchDepartments(externalData);

文件清单

新增文件

文件 说明
IDepartmentSyncDataService.java 数据查询服务接口
DepartmentSyncDataServiceImpl.java 数据查询服务实现

修改文件

文件 变化
IDepartmentSyncService.java 新增重载方法
DepartmentSyncServiceImpl.java 重构实现,支持外部数据源
DepartmentSyncController.java 新增接口 /branch/data

无需修改

文件 说明
DepartmentSyncMapper.java Mapper 接口不变
DepartmentSyncMapper.xml SQL 映射不变
OaSyncTask.java 定时任务不变

总结

通过本次重构,实现了:

职责分离: 数据查询和同步逻辑解耦
灵活性提升: 支持多种数据来源
易于扩展: 可轻松添加新的数据源
向后兼容: 原有代码无需修改
易于测试: 可使用 Mock 数据进行单元测试


相关文档