# 客户端Tasker实现WebSocketClientTasker接口规范

## 概述

本文档基于 `ContractRepairAllTasker` 实现 `WebSocketClientTasker` 接口的经验，总结了客户端Tasker类升级为支持WebSocket通信的最佳实践和规范。

## WebSocketClientTasker接口介绍

`WebSocketClientTasker` 接口定义了通过WebSocket与服务器通信的任务的通用方法，包括任务名称、消息更新、进度更新等核心功能。

### 核心方法

1. **getTaskName()** - 获取任务名称，用于在WebSocket通信中标识任务
2. **updateMessage(Level, String)** - 更新任务执行过程中的消息
3. **updateTitle(String)** - 更新任务标题
4. **updateProgress(long, long)** - 更新任务进度
5. **cancelTask()** - 取消任务执行（默认实现为空）
6. **callRemoteTask(MessageHolder, Locale, Object...)** - 调用远程WebSocket任务
7. **callRemoteTaskAsync(MessageHolder, Locale, Object...)** - 异步调用远程WebSocket任务
8. **generateTaskId()** - 生成唯一的任务ID

### 典型实现模式概览

通过分析项目中的17个实现类，我们发现了以下典型实现模式：

1. **标准实现**：继承Tasker<Object>并实现WebSocketClientTasker
2. **属性注入**：使用@Setter注解或手动设置属性传递任务参数
3. **Spring Bean获取**：通过SpringApp.getBean()获取服务实例
4. **消息更新**：简洁的消息更新方式
5. **参数传递**：通过callRemoteTask的可变参数传递任务所需数据

## Tasker实现WebSocketClientTasker最佳实践

### 1. 类定义和继承

```java
/**
 * 任务类描述
 * 用于通过WebSocket与服务器通信执行具体操作
 */
public class 任务类名 extends Tasker<Object> implements WebSocketClientTasker {
    private static final Logger logger = LoggerFactory.getLogger(任务类名.class);
    
    // 实现方法
}
```

### 2. 参数传递模式

#### 2.1 使用@Setter注解注入参数

```java
/**
 * 更新供应商评价表任务
 */
public class CompanyVendorEvaluationFormUpdateTask extends Tasker<Object> implements WebSocketClientTasker {
    private static final Logger logger = LoggerFactory.getLogger(CompanyVendorEvaluationFormUpdateTask.class);
    
    @Setter
    private VendorVo vendor;
    
    @Override
    protected Object execute(MessageHolder holder) throws Exception {
        updateTitle("更新供应商评价表");
        return callRemoteTask(holder, getLocale(), vendor.getId());
    }
}
```

#### 2.2 使用@Getter和@Setter注解

```java
/**
 * 客户文件重建任务类
 */
public class CustomerRebuildFilesTasker extends Tasker<Object> implements WebSocketClientTasker {
    @Getter
    @Setter
    private CustomerVo companyCustomer;
    
    @Override
    protected Object execute(MessageHolder holder) throws Exception {
        updateTitle("重建客户文件");
        return callRemoteTask(holder, getLocale(), companyCustomer.getId());
    }
}
```

### 2. 必要方法实现

#### 2.1 getTaskName()

```java
@Override
public String getTaskName() {
    return "Task名称";  // 必须与服务器端对应Tasker类名匹配
}
```

**注意事项**：
- 任务名称必须与服务器端对应的Tasker注册名（tasker_mapper.json中的key）保持一致
- 名称应简洁明了，反映任务的核心功能

#### 2.2 updateProgress()
updateProgress 方法重载为public，用于外部调用更新进度

```java
@Override
public void updateProgress(long current, long total) {
    super.updateProgress(current, total);  // 调用父类方法更新进度
}
```

#### 2.3 updateTitle()

```java
@Override
public void updateTitle(String title) {
    super.updateTitle(title);  // 使用Tasker的updateTitle方法更新标题
}
```

#### 2.4 execute() 方法重写

**标准实现**：
```java
@Override
protected Object execute(MessageHolder holder) throws Exception {
    logger.info("开始执行任务描述");
    updateTitle("任务标题");
    
    // 调用远程任务，可选传入参数
    Object result = callRemoteTask(holder, getLocale(), 可选参数...);
    
    logger.info("任务执行完成");
    return result;
}
```

**简洁实现**（适用于简单任务）：
```java
@Override
protected Object execute(MessageHolder holder) throws Exception {
    updateTitle("更新供应商评价表");
    return callRemoteTask(holder, getLocale(), vendor.getId());
}
```

**带消息更新的实现**：
```java
@Override
protected Object execute(MessageHolder holder) throws Exception {
    // 设置任务标题
    updateTitle("全量库存同步任务");

    // 更新任务消息
    updateMessage("开始执行全量库存同步...");

    // 调用远程WebSocket任务
    return callRemoteTask(holder, getLocale());
}
```

**关键步骤**：
1. 记录任务开始日志（可选）
2. 设置任务标题
3. 可选：添加任务开始消息
4. 调用远程任务执行核心逻辑，传入必要参数
5. 记录任务完成日志（可选）
6. 返回执行结果

### 3. 日志记录

```java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// 在类中定义
private static final Logger logger = LoggerFactory.getLogger(任务类名.class);

// 在关键位置使用日志
logger.info("任务开始");
logger.warn("警告信息");
logger.error("错误信息", exception);
```

**日志使用建议**：
- 复杂任务建议记录详细日志
- 简单任务可以简化或省略日志记录
- 确保异常情况下有适当的错误日志记录

### 4. 异常处理

在`execute`方法中应妥善处理可能的异常，并通过MessageHolder通知用户：

```java
@Override
protected Object execute(MessageHolder holder) throws Exception {
    try {
        // 任务执行逻辑
    } catch (Exception e) {
        logger.error("任务执行失败", e);
        holder.addMessage(Level.SEVERE, "任务执行失败: " + e.getMessage());
        throw e;  // 向上抛出异常，让框架处理
    }
}
```

**异常处理策略**：
- 对于简单任务，可以依赖框架的异常处理机制
- 对于复杂任务，建议添加自定义的异常处理逻辑
- 确保异常信息对用户友好且具有足够的调试信息

## 完整实现示例

### 示例1：简单任务实现

```java
package com.ecep.contract.task;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ecep.contract.MessageHolder;
import com.ecep.contract.WebSocketClientTasker;

/**
 * 合同修复任务类
 * 用于通过WebSocket与服务器通信执行合同数据修复操作
 */
public class ContractRepairAllTasker extends Tasker<Object> implements WebSocketClientTasker {
    private static final Logger logger = LoggerFactory.getLogger(ContractRepairAllTasker.class);

    @Override
    public void updateProgress(long current, long total) {
        super.updateProgress(current, total);
    }

    @Override
    public void updateTitle(String title) {
        // 使用Tasker的updateTitle方法更新标题
        super.updateTitle(title);
    }

    @Override
    public String getTaskName() {
        return "ContractRepairAllTask";  // 与服务器端对应Tasker类名匹配
    }

    @Override
    protected Object execute(MessageHolder holder) throws Exception {
        logger.info("开始执行合同修复任务");
        updateTitle("合同数据修复");
        Object result = callRemoteTask(holder, getLocale());
        logger.info("合同修复任务执行完成");
        return result;
    }
}
```

### 示例2：带参数的任务实现

```java
package com.ecep.contract.task;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ecep.contract.MessageHolder;
import com.ecep.contract.WebSocketClientTasker;
import com.ecep.contract.vo.VendorVo;

import lombok.Setter;

/**
 * 更新供应商评价表
 */
public class CompanyVendorEvaluationFormUpdateTask extends Tasker<Object> implements WebSocketClientTasker {
    private static final Logger logger = LoggerFactory.getLogger(CompanyVendorEvaluationFormUpdateTask.class);
    @Setter
    private VendorVo vendor;

    @Override
    public void updateProgress(long current, long total) {
        super.updateProgress(current, total);
    }

    @Override
    public String getTaskName() {
        return "CompanyVendorEvaluationFormUpdateTask";  // 与服务器端对应Tasker类名匹配
    }

    @Override
    protected Object execute(MessageHolder holder) throws Exception {
        updateTitle("更新供应商评价表");
        return callRemoteTask(holder, getLocale(), vendor.getId());
    }
}
```

### 示例3：使用Spring Bean的任务实现

```java
package com.ecep.contract.task;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.WebSocketClientTasker;
import com.ecep.contract.service.YongYouU8Service;

/**
 * 合同同步任务
 */
public class ContractSyncTask extends Tasker<Object> implements WebSocketClientTasker {
    private static final Logger logger = LoggerFactory.getLogger(ContractSyncTask.class);

    private YongYouU8Service yongYouU8Service;

    private YongYouU8Service getYongYouU8Service() {
        if (yongYouU8Service == null) {
            yongYouU8Service = SpringApp.getBean(YongYouU8Service.class);
        }
        return yongYouU8Service;
    }

    public String getTaskName() {
        return "ContractSyncTask";  // 与服务器端对应Tasker类名匹配
    }

    @Override
    public void updateProgress(long current, long total) {
        super.updateProgress(current, total);
    }

    @Override
    protected Object execute(MessageHolder holder) throws Exception {
        updateTitle("用友U8系统-同步合同");
        return callRemoteTask(holder, getLocale());
    }
}
```

## 注意事项和最佳实践

### 1. 命名规范
- 任务类名应采用驼峰命名法，以`Tasker`结尾或描述性名称如`Task`
- getTaskName()返回的名称应与服务器端对应Tasker类名完全匹配
- 类注释应清晰描述任务的功能和用途

### 2. 继承关系
- 必须同时继承Tasker类并实现WebSocketClientTasker接口
- Tasker泛型参数通常为Object
- 确保正确导入所有必要的包

### 3. 参数处理
- 对于需要参数的任务，使用@Setter注解简化属性设置
- 对于需要在多处使用的参数，考虑添加@Getter注解
- 确保参数验证（如果必要）

### 4. Spring Bean获取
- 使用SpringApp.getBean()获取所需的服务实例
- 考虑使用懒加载模式，避免不必要的Bean初始化

### 5. 消息和进度更新
- 使用updateTitle()设置有意义的任务标题
- 通过MessageHolder或updateMessage()记录详细的执行消息
- 确保进度更新反映真实的执行进度

### 6. 异常处理
- 在关键操作处添加try-catch块
- 记录异常日志并通知用户
- 适当向上抛出异常以确保框架能正确处理

### 7. 日志级别使用
- INFO: 记录正常的操作流程
- WARNING: 记录可能的问题，但不影响继续执行
- ERROR: 记录严重错误，通常会终止执行

### 8. 远程调用参数
- 确保传入的参数类型与服务器端Tasker期望的一致
- 对于不需要参数的任务，可以不传入额外参数
- 对于需要多个参数的任务，确保参数顺序正确

### 9. 代码风格
- 保持代码简洁明了
- 遵循项目的代码格式化规范
- 添加必要的注释说明核心逻辑

### 10. 实现策略选择
- 简单任务：使用简洁的实现方式，省略不必要的日志
- 复杂任务：添加详细的日志记录和异常处理
- 有特定需求的任务：根据需要重写接口中的其他方法

## 与服务器端交互流程

1. 客户端Tasker通过callRemoteTask()方法提交任务
2. WebSocketClientService负责建立与服务器的连接并发送任务信息
3. 服务器接收到任务后，创建对应的Tasker实例并执行
4. 执行过程中的消息、进度等通过WebSocket实时返回给客户端
5. 客户端Tasker通过updateMessage()、updateProgress()等方法更新UI

## 扩展和自定义

如需为特定任务提供自定义功能，可以：

1. 重写cancelTask()方法实现任务取消逻辑
2. 根据需要添加额外的字段和方法
3. 扩展execute()方法实现更复杂的任务流程

## 总结

通过分析项目中的17个WebSocketClientTasker实现类，我们总结了客户端Tasker实现的多种模式和最佳实践。这些实现从简单到复杂，涵盖了各种使用场景，为后续Tasker的编写提供了全面的参考。

客户端Tasker类实现WebSocketClientTasker接口是实现与服务器实时通信的关键步骤。通过遵循本文档中的规范和最佳实践，可以确保任务执行的可靠性、进度的实时更新和良好的用户体验。

在实际开发中，应根据任务的复杂度和具体需求，选择合适的实现模式和策略，同时保持代码的一致性和可维护性。