feat(SMB): 重构SMB文件服务支持多服务器配置和连接池优化
重构SmbFileService以支持多服务器配置,引入连接池和会话池管理机制。主要变更包括: 1. 实现基于主机的多服务器认证配置 2. 新增连接池和会话池管理,提高连接复用率 3. 添加定时清理空闲连接和会话的功能 4. 优化异常处理和重试机制 5. 改进日志记录和资源释放 同时更新相关配置文件和应用属性以支持新功能: 1. 修改application.properties支持多服务器SMB配置 2. 增强SmbConfig类以管理多服务器配置 3. 添加任务映射到tasker_mapper.json 4. 新增客户端和服务端任务规则文档
This commit is contained in:
@@ -0,0 +1,419 @@
|
||||
# 客户端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接口是实现与服务器实时通信的关键步骤。通过遵循本文档中的规范和最佳实践,可以确保任务执行的可靠性、进度的实时更新和良好的用户体验。
|
||||
|
||||
在实际开发中,应根据任务的复杂度和具体需求,选择合适的实现模式和策略,同时保持代码的一致性和可维护性。
|
||||
Reference in New Issue
Block a user