feat: 实现客户端与服务器端Tasker通信机制及文件管理功能
refactor: 重构Tasker基类与服务获取逻辑 fix: 修复文件路径显示问题及任务注册加载机制 docs: 添加客户端与服务器端Tasker通信规则文档 style: 优化代码格式与日志输出 build: 添加tasker_mapper.json配置文件 chore: 清理无用代码与文件
This commit is contained in:
215
docs/task/client_server_tasker_communication_rules.md
Normal file
215
docs/task/client_server_tasker_communication_rules.md
Normal file
@@ -0,0 +1,215 @@
|
||||
# 客户端 Tasker 至 服务器端 Tasker 通信规则与逻辑
|
||||
|
||||
本文档总结了 Contract-Manager 项目中客户端 Tasker 与服务器端 Tasker 之间的通信规则、调用逻辑和实现模式,基于对以下文件的分析:
|
||||
- `d:\idea-workspace\Contract-Manager\server\src\main\java\com\ecep\contract\ds\customer\tasker\CompanyCustomerEvaluationFormUpdateTask.java`
|
||||
- `d:\idea-workspace\Contract-Manager\client\src\main\java\com\ecep\contract\controller\customer\CompanyCustomerEvaluationFormUpdateTask.java`
|
||||
- `d:\idea-workspace\Contract-Manager\client\src\main\java\com\ecep\contract\controller\customer\CustomerTabSkinFile.java`
|
||||
|
||||
## 1. 架构设计原则
|
||||
|
||||
项目采用了清晰的客户端-服务器分离架构,任务处理遵循以下原则:
|
||||
- **客户端轻量级**:负责任务发起、参数传递和结果展示
|
||||
- **服务器端重量级**:负责实际业务逻辑处理和数据操作
|
||||
- **WebSocket通信**:使用WebSocket实现客户端与服务器端的任务通信和进度同步
|
||||
|
||||
## 2. 类命名与结构规范
|
||||
|
||||
### 2.1 命名规则
|
||||
- 客户端与服务器端的对应Tasker类**必须使用相同的类名**(如示例中的`CompanyCustomerEvaluationFormUpdateTask`)
|
||||
- 客户端Tasker位于`client`模块的控制器包下
|
||||
- 服务器端Tasker位于`server`模块的tasker包下
|
||||
|
||||
### 2.2 任务名称注册规则
|
||||
- 所有服务器端Tasker类必须通过配置文件`tasker_mapper.json`进行注册,并由`WebSocketServerTaskManager`类在`afterPropertiesSet`方法中加载
|
||||
- 注册格式为`"TaskClassName": "fully.qualified.ClassName"`
|
||||
- 注册的Task名称将用于客户端和服务器端之间的任务识别
|
||||
- 配置文件`tasker_mapper.json`应位于`src/main/resources`目录下,格式如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"taskers": {
|
||||
"TaskClassName": "fully.qualified.ClassName",
|
||||
// 更多任务映射...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 任务名称注册实现示例
|
||||
```java
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
// 从tasker_mapper.json文件中加载任务注册信息
|
||||
try {
|
||||
Resource resource = resourceLoader.getResource("classpath:tasker_mapper.json");
|
||||
try (InputStream inputStream = resource.getInputStream()) {
|
||||
JsonNode rootNode = objectMapper.readTree(inputStream);
|
||||
JsonNode taskersNode = rootNode.get("taskers");
|
||||
if (taskersNode != null && taskersNode.isObject()) {
|
||||
Map<String, String> taskMap = new java.util.HashMap<>();
|
||||
taskersNode.fields().forEachRemaining(entry -> {
|
||||
taskMap.put(entry.getKey(), entry.getValue().asText());
|
||||
});
|
||||
taskClzMap = taskMap;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to load tasker_mapper.json", e);
|
||||
// 使用默认值作为fallback
|
||||
taskClzMap = Map.of();
|
||||
}
|
||||
}```
|
||||
|
||||
### 2.3 接口实现区分
|
||||
- 客户端Tasker实现`WebSocketClientTasker`接口
|
||||
- 服务器端Tasker实现`WebSocketServerTasker`接口
|
||||
|
||||
### 2.4 继承关系
|
||||
- 客户端和服务器端Tasker均继承自`Tasker<Object>`基类
|
||||
|
||||
## 3. 客户端Tasker实现规则
|
||||
|
||||
客户端Tasker是任务的发起方,需要遵循以下实现规则:
|
||||
|
||||
### 3.1 核心属性
|
||||
- 通常包含一个可设置的业务对象(如示例中的`@Setter private CompanyCustomerVo customer;`)
|
||||
- 配置Logger日志记录器
|
||||
|
||||
### 3.2 核心方法实现
|
||||
- **getTaskName()**:返回任务名称,通常使用类名
|
||||
- **updateProgress()**:继承或重写进度更新方法
|
||||
- **execute()**:调用`callRemoteTask()`方法将任务发送到服务器端,传递必要参数
|
||||
|
||||
### 3.3 示例实现
|
||||
```java
|
||||
public class CompanyCustomerEvaluationFormUpdateTask extends Tasker<Object> implements WebSocketClientTasker {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompanyCustomerEvaluationFormUpdateTask.class);
|
||||
|
||||
@Setter
|
||||
private CompanyCustomerVo customer; // 业务对象
|
||||
|
||||
@Override
|
||||
public String getTaskName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object execute(MessageHolder holder) throws Exception {
|
||||
updateTitle("客户评估表更新任务"); // 设置任务标题
|
||||
// 调用远程任务,传递locale和业务对象ID
|
||||
return callRemoteTask(holder, getLocale(), customer.getId());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 服务器端Tasker实现规则
|
||||
|
||||
服务器端Tasker是任务的实际执行者,需要遵循以下实现规则:
|
||||
|
||||
### 4.1 参数接收
|
||||
- 实现`init(JsonNode argsNode)`方法接收客户端传递的参数
|
||||
- 从参数中提取业务对象ID并加载完整业务对象
|
||||
|
||||
### 4.2 服务获取
|
||||
- 通过`getCachedBean(Service.class)`方法获取所需的服务实例
|
||||
- 可以提供辅助方法封装服务获取逻辑
|
||||
|
||||
### 4.3 任务执行
|
||||
- 实现`execute(MessageHolder holder)`方法包含实际业务逻辑
|
||||
- 使用`holder.info()/error()`等方法记录任务执行状态
|
||||
- 调用`updateProgress()`方法更新任务进度
|
||||
|
||||
### 4.4 示例实现
|
||||
```java
|
||||
public class CompanyCustomerEvaluationFormUpdateTask extends Tasker<Object> implements WebSocketServerTasker {
|
||||
private CompanyCustomer customer; // 业务对象
|
||||
|
||||
@Override
|
||||
public void init(JsonNode argsNode) {
|
||||
// 从参数中提取业务对象ID并加载
|
||||
int customerId = argsNode.get(0).asInt();
|
||||
customer = getCachedBean(CompanyCustomerService.class).findById(customerId);
|
||||
}
|
||||
|
||||
// 辅助方法获取服务
|
||||
CompanyCustomerFileService getCompanyCustomerFileService() {
|
||||
return getCachedBean(CompanyCustomerFileService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object execute(MessageHolder holder) throws Exception {
|
||||
// 执行实际业务逻辑
|
||||
updateEvaluationForm(holder);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 具体业务逻辑实现
|
||||
public void updateEvaluationForm(MessageHolder holder) {
|
||||
// 业务逻辑代码...
|
||||
updateProgress(1, 10); // 更新进度
|
||||
// 更多业务逻辑...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 客户端Tasker调用流程
|
||||
|
||||
在UI控制器中调用客户端Tasker的标准流程如下:
|
||||
|
||||
### 5.1 实例化与参数设置
|
||||
1. 创建客户端Tasker实例
|
||||
2. 设置必要的业务对象参数
|
||||
|
||||
### 5.2 任务执行与监控
|
||||
1. 使用`UITools.showTaskDialogAndWait()`显示任务对话框
|
||||
2. 调用`initializeTask()`初始化任务执行环境
|
||||
3. 通过消费者函数处理任务消息
|
||||
|
||||
### 5.3 任务完成处理
|
||||
1. 任务完成后执行必要的数据刷新操作
|
||||
|
||||
### 5.4 示例调用
|
||||
```java
|
||||
public void onUpdateEvaluationFormAction(ActionEvent event) {
|
||||
// 1. 创建Tasker并设置参数
|
||||
CompanyCustomerEvaluationFormUpdateTask task = new CompanyCustomerEvaluationFormUpdateTask();
|
||||
task.setCustomer(getCompanyCustomerService().findById(viewModel.getId().get()));
|
||||
|
||||
// 2. 显示任务对话框并执行任务
|
||||
UITools.showTaskDialogAndWait("更新评价表", task, consumer -> {
|
||||
initializeTask(task, "更新评价表", msg -> consumer.accept(Message.info(msg)));
|
||||
});
|
||||
|
||||
// 3. 任务完成后刷新数据
|
||||
loadTableDataSet();
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 任务进度管理
|
||||
|
||||
- 服务器端使用`updateProgress(current, total)`方法更新任务进度
|
||||
- 进度值通常以0-1000或类似小范围数值表示完成百分比
|
||||
- 客户端通过WebSocket接收进度更新并显示
|
||||
|
||||
## 7. 异常处理机制
|
||||
|
||||
- 服务器端使用`MessageHolder.error()`方法记录错误信息
|
||||
- 客户端通过任务对话框展示错误信息
|
||||
- 服务器端在关键操作点进行异常捕获和处理
|
||||
|
||||
## 8. 数据一致性保障
|
||||
|
||||
- 任务完成后客户端通常调用数据刷新方法(如`loadTableDataSet()`)确保UI显示最新数据
|
||||
- 服务器端负责业务数据的持久化操作
|
||||
|
||||
## 9. 最佳实践建议
|
||||
|
||||
1. **任务拆分**:复杂任务应拆分为多个小任务,便于进度跟踪和错误定位
|
||||
2. **状态反馈**:在关键节点提供清晰的状态信息,增强用户体验
|
||||
3. **资源释放**:确保文件流等资源正确关闭,避免资源泄露
|
||||
4. **事务控制**:对于涉及多步数据操作的任务,考虑使用事务确保数据一致性
|
||||
5. **错误重试**:针对网络波动等临时性问题,考虑实现任务重试机制
|
||||
6. **配置管理**:使用`tasker_mapper.json`文件统一管理任务注册信息,避免在代码中硬编码任务映射
|
||||
7. **异常处理**:确保实现配置文件加载失败的fallback机制,保证系统稳定性
|
||||
8. **版本控制**:对任务配置文件进行版本控制,便于追踪变更历史
|
||||
|
||||
通过遵循以上规则和模式,可以确保Contract-Manager项目中客户端与服务器端Tasker通信的一致性、可靠性和可维护性。
|
||||
Reference in New Issue
Block a user