在现有的分公司同步功能基础上,新增转运部同步功能。转运部是总公司(ID=101)下的一个部门,需要同步转运部及其子部门数据。
uv_department 视图a.departmentName = N'合作单位'湛江--护士 → 分公司:湛江分公司,子部门:护士uv_department 视图a.departmentName = N'转运部'departmentName,无需解析Controller (REST API)
↓
Service (同步逻辑 - MySQL)
↓
DataService (数据查询 - SQL Server)
↓
Mapper (SQL 执行)
文件路径: ruoyi-system/src/main/resources/mapper/system/DepartmentSyncMapper.xml
新增查询方法:xml <!-- 查询转运部下的所有子部门 --> <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>
SQL 优化要点:
- 使用 TOP 500 限制返回数据量
- 使用 WITH (NOLOCK) 提高查询性能
- 中文字符串使用 N 前缀确保正确匹配
- 使用 <![CDATA[...]]> 包裹 SQL 避免 XML 特殊字符问题
文件路径: ruoyi-system/src/main/java/com/ruoyi/system/mapper/DepartmentSyncMapper.java
新增方法:java /** * 查询转运部下的所有子部门 * * @return 转运部子部门列表 */ List<DepartmentSyncDTO> selectTransportDepartments();
特点:
- 接口级别标注 @DataSource(DataSourceType.SQLSERVER)
- 自动切换到 SQL Server 数据源
文件路径: ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncDataService.java
新增方法:java /** * 从 SQL Server 查询转运部下的所有子部门数据 * * 数据源:SQL Server (uv_department 视图) * * @return 转运部子部门列表 */ List<DepartmentSyncDTO> getTransportDepartments();
文件路径: ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncDataServiceImpl.java
新增实现:
```java
@Override
public List getTransportDepartments()
{
try
{
log.info("开始从 SQL Server 查询转运部子部门数据...");
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);
}
}
```
特点:
- 类级别标注 @DataSource(DataSourceType.SQLSERVER)
- 只负责查询 SQL Server 数据,不涉及 MySQL 操作
文件路径: ruoyi-system/src/main/java/com/ruoyi/system/service/IDepartmentSyncService.java
新增方法:java /** * 同步转运部和子部门数据(使用外部传入的数据源) * * 同步逻辑: * 1. 确保总公司(ID=101)下存在"转运部" * 2. 创建转运部的子部门(直接创建,无需解析"--"格式) * * @param transportDepts 外部传入的转运部子部门数据列表 * @return 同步结果 */ AjaxResult syncTransportDepartments(List<DepartmentSyncDTO> transportDepts);
文件路径: ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DepartmentSyncServiceImpl.java
新增实现(核心同步逻辑):
```java
@Override
@Transactional
public AjaxResult syncTransportDepartments(List transportDepts)
{
// 1. 检查总公司(ID=101)是否存在
SysDept headOffice = sysDeptMapper.selectDeptById(101L);
if (headOffice == null)
{
return AjaxResult.error("总公司(ID=101)不存在,请先创建总公司");
}
// 2. 确保"转运部"存在
SysDept existingTransport = sysDeptMapper.checkDeptNameUnique("转运部", 101L);
if (existingTransport == null)
{
// 创建转运部
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();
}
else
{
transportDeptId = existingTransport.getDeptId();
}
// 3. 创建或更新转运部子部门
for (DepartmentSyncDTO dto : transportDepts)
{
String deptName = dto.getDepartmentName();
// 检查是否已存在(通过 departmentId + parentId)
SysDept existingDept = sysDeptMapper.selectDeptByDepartmentIdAndParentId(
dto.getDepartmentId(), transportDeptId);
if (existingDept != null)
{
// 更新已存在的部门
existingDept.setDeptName(deptName);
existingDept.setUpdateBy("sync");
sysDeptMapper.updateDept(existingDept);
}
else
{
// 检查是否存在同名部门
SysDept sameName = sysDeptMapper.checkDeptNameUnique(deptName, transportDeptId);
if (sameName != null)
{
// 更新同名部门的 departmentId
sameName.setDepartmentId(dto.getDepartmentId());
sameName.setUpdateBy("sync");
sysDeptMapper.updateDept(sameName);
}
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);
}
}
}
}
```
特点:
- 只涉及 MySQL 数据库操作
- 使用 @Transactional 保证事务一致性
- 支持幂等性设计(可重复执行)
文件路径: ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/DepartmentSyncController.java
新增接口:java /** * 同步转运部和子部门数据(使用外部传入的数据源) * * @param transportDepts 转运部子部门数据列表 * @return 同步结果 */ @PreAuthorize("@ss.hasPermi('system:dept:sync')") @PostMapping("/transport/data") public AjaxResult syncTransportDepartmentsWithData(@RequestBody List<DepartmentSyncDTO> transportDepts) { return departmentSyncService.syncTransportDepartments(transportDepts); }
POST /system/dept/sync/branch/datasystem:dept:syncList<DepartmentSyncDTO>POST /system/dept/sync/transport/datasystem:dept:syncList<DepartmentSyncDTO>POST /system/dept/sync/user/datasystem:user:syncList<UserSyncDTO>┌─────────────────────────────────────────────────────────┐
│ 外部系统/定时任务 │
└─────────────────────────────────────────────────────────┘
│
│ 调用 REST API
▼
┌─────────────────────────────────────────────────────────┐
│ DepartmentSyncController │
│ • /branch/data (分公司同步) │
│ • /transport/data (转运部同步) ← 新增 │
│ • /user/data (用户同步) │
└─────────────────────────────────────────────────────────┘
│
│ 传递 DTO 列表
▼
┌─────────────────────────────────────────────────────────┐
│ DepartmentSyncServiceImpl (MySQL) │
│ • syncBranchDepartments() │
│ • syncTransportDepartments() ← 新增 │
└─────────────────────────────────────────────────────────┘
│
│ 写入 MySQL
▼
┌─────────────────────────────────────────────────────────┐
│ SysDeptMapper │
│ • 查询已存在部门 │
│ • 插入新部门 │
│ • 更新部门信息 │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 外部系统需要先调用 DataService │
└─────────────────────────────────────────────────────────┘
│
│ 调用数据查询服务
▼
┌─────────────────────────────────────────────────────────┐
│ DepartmentSyncDataServiceImpl (SQL Server) │
│ • getBranchDepartments() (查询分公司) │
│ • getTransportDepartments() (查询转运部) ← 新增 │
└─────────────────────────────────────────────────────────┘
│
│ 切换到 SQL Server
▼
┌─────────────────────────────────────────────────────────┐
│ DepartmentSyncMapper │
│ • selectBranchDepartments() │
│ • selectTransportDepartments() ← 新增 │
└─────────────────────────────────────────────────────────┘
│
│ 查询 SQL Server
▼
┌─────────────────────────────────────────────────────────┐
│ SQL Server - uv_department │
└─────────────────────────────────────────────────────────┘
若依科技 (ID=100)
├── 湛江分公司
│ ├── 护士
│ ├── 医生
│ └── ...
├── 广州分公司
│ ├── 护士
│ ├── 医生
│ └── ...
└── ...
总公司 (ID=101)
└── 转运部
├── 转运队
├── 调度中心
├── 设备维护
└── ...
同步操作支持重复执行,通过以下方式保证幂等性:
departmentId(SQL Server 部门 ID)作为唯一标识@Transactional通过修改 DataSourceAspect.java,实现了智能数据源切换:
详见:多数据源切换问题修复说明.md
假设需要同步转运部数据,可以这样调用:
// 步骤 1: 调用 DataService 查询 SQL Server 数据
List<DepartmentSyncDTO> transportDepts = departmentSyncDataService.getTransportDepartments();
// 步骤 2: 调用 SyncService 将数据同步到 MySQL
AjaxResult result = departmentSyncService.syncTransportDepartments(transportDepts);
# 步骤 1: 查询 SQL Server 数据(需要自行实现获取接口)
curl -X GET http://localhost:8080/system/dept/sync/transport/query
# 步骤 2: 同步数据到 MySQL
curl -X POST http://localhost:8080/system/dept/sync/transport/data \
-H "Content-Type: application/json" \
-d '[
{
"departmentId": 1001,
"departmentName": "转运队",
"parentId": 100,
"parentName": "转运部"
},
{
"departmentId": 1002,
"departmentName": "调度中心",
"parentId": 100,
"parentName": "转运部"
}
]'
system:dept:sync 权限<![CDATA[...]]> 包裹NOLOCK 提示和 TOP 限制部门同步服务重构说明.md - 分公司同步架构说明用户同步服务重构说明.md - 用户同步架构说明多数据源切换问题修复说明.md - 数据源切换问题修复SQL Server数据源查询优化说明.md - SQL Server 查询优化2025-10-18
- 新增转运部同步功能
- 在 DepartmentSyncMapper.xml 中添加 selectTransportDepartments 查询
- 在 IDepartmentSyncDataService 和实现类中添加 getTransportDepartments() 方法
- 在 IDepartmentSyncService 和实现类中添加 syncTransportDepartments() 方法
- 在 DepartmentSyncController 中添加 /transport/data 接口
- 创建本说明文档