# AMT 实时状态检测功能
## 功能概述
实现了 AMT 设备状态的实时检测和自动更新功能,无需手动刷新即可看到设备的在线/离线状态变化。
## 实现方案
### 后端实现
#### 1. 定时任务 (AmtStatusCheckTask.java)
**位置**: `backend/src/main/java/com/soybean/admin/task/AmtStatusCheckTask.java`
**功能**:
- 每 30 秒自动检测一次所有设备的 AMT 状态
- 使用线程池并发检测,提高效率
- 只在状态变化时更新数据库,减少写入操作
- 使用 Socket 连接检测 AMT 端口(16992/16993)可用性
**关键特性**:
```java
@Scheduled(fixedRate = 30000, initialDelay = 10000)
public void checkAmtStatus() {
// 每 30 秒执行一次
// 初始延迟 10 秒,等待应用完全启动
}
```
**检测逻辑**:
1. 查询所有有 IP 地址的设备
2. 并发检测每个设备的 AMT 端口连接性
3. 先尝试 HTTP (16992),失败则尝试 HTTPS (16993)
4. 根据连接结果更新设备的 `amt_status` 字段
5. 只有状态变化时才更新数据库和记录日志
**线程池配置**:
- 固定 20 个线程
- 使用 CompletableFuture 异步执行
- 等待所有检测完成后结束任务
#### 2. 启用定时任务
**修改**: `backend/src/main/java/com/soybean/admin/SoybeanAdminApplication.java`
添加 `@EnableScheduling` 注解启用 Spring 定时任务功能:
```java
@SpringBootApplication
@MapperScan("com.soybean.admin.mapper")
@EnableScheduling // 启用定时任务
public class SoybeanAdminApplication {
// ...
}
```
### 前端实现
#### 1. 自动轮询刷新
**位置**: `src/views/device/list/index.vue`
**功能**:
- 页面加载后每 10 秒自动刷新设备列表
- 组件卸载时自动清除定时器
- 显示"自动刷新中"状态标签
**实现代码**:
```typescript
onMounted(() => {
loadData();
// 启动定时刷新,每 10 秒刷新一次设备状态
const refreshInterval = setInterval(() => {
loadData();
}, 10000);
// 组件卸载时清除定时器
onUnmounted(() => {
clearInterval(refreshInterval);
});
});
```
#### 2. 手动刷新按钮
添加了"刷新状态"按钮,用户可以随时手动刷新:
```vue
刷新状态
```
#### 3. 状态指示器
显示自动刷新状态:
```vue
自动刷新中
```
## 工作流程
### 完整流程图
```
后端定时任务 (每30秒)
↓
检测所有设备 AMT 端口
↓
更新数据库状态
↓
前端轮询 (每10秒)
↓
获取最新设备列表
↓
更新界面显示
```
### 时间线示例
```
T=0s: 后端启动,10秒后开始第一次检测
T=10s: 后端第一次检测所有设备
T=10s: 前端页面加载,开始第一次数据获取
T=20s: 前端第二次刷新
T=30s: 前端第三次刷新
T=40s: 后端第二次检测 + 前端第四次刷新
T=50s: 前端第五次刷新
...
```
## 性能优化
### 后端优化
1. **并发检测**: 使用 20 个线程并发检测,大幅提升检测速度
2. **快速超时**: Socket 连接超时设置为 3 秒,避免长时间等待
3. **增量更新**: 只在状态变化时更新数据库
4. **简单检测**: 只检测端口连接性,不进行完整的 AMT 认证
### 前端优化
1. **合理间隔**: 10 秒刷新间隔,平衡实时性和性能
2. **自动清理**: 组件卸载时清除定时器,避免内存泄漏
3. **加载状态**: 显示加载状态,提升用户体验
## 状态检测逻辑
### 检测方法
使用 TCP Socket 连接检测,而不是完整的 AMT 认证:
```java
private boolean checkAmtConnectivity(String ipAddress) {
try {
// 尝试连接 AMT HTTP 端口
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ipAddress, 16992), 3000);
socket.close();
return true;
} catch (Exception e) {
// HTTP 失败,尝试 HTTPS
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ipAddress, 16993), 3000);
socket.close();
return true;
} catch (Exception ex) {
return false;
}
}
}
```
### 优点
1. **快速**: 不需要完整的 SOAP 请求和认证
2. **轻量**: 只检测端口可用性
3. **可靠**: 能准确判断 AMT 服务是否运行
### 缺点
1. **不验证认证**: 不检查凭证是否正确
2. **端口占用**: 如果端口被其他服务占用,可能误判
## 使用说明
### 1. 执行数据库更新
如果还没有执行过数据库更新,先运行:
```bash
update_device_status.bat
```
### 2. 重新编译后端
```bash
cd backend
mvn clean package -DskipTests
```
### 3. 启动后端服务
```bash
start_backend.bat
```
后端启动后,会在 10 秒后开始第一次 AMT 状态检测,之后每 30 秒检测一次。
### 4. 打开前端页面
访问设备列表页面,会看到:
- 右上角显示"自动刷新中"标签
- 设备的 AMT 状态列实时更新
- 可以点击"刷新状态"按钮手动刷新
## 日志查看
### 后端日志
查看后端控制台输出,会看到类似日志:
```
开始 AMT 状态检测任务
开始检测 10 个设备的 AMT 状态
设备 Server-01 (192.168.8.100) AMT 状态变化: offline -> online
设备 Server-02 (192.168.8.101) AMT 状态变化: online -> offline
AMT 状态检测任务完成
```
### 前端日志
打开浏览器开发者工具,可以看到每 10 秒发送一次设备列表请求。
## 测试场景
### 场景 1: 设备上线
1. 启动一台 AMT 设备
2. 等待最多 30 秒(后端检测周期)
3. 前端会在下次刷新时显示设备状态变为"在线"
### 场景 2: 设备下线
1. 关闭一台 AMT 设备
2. 等待最多 30 秒(后端检测周期)
3. 前端会在下次刷新时显示设备状态变为"离线"
### 场景 3: 手动刷新
1. 点击"刷新状态"按钮
2. 立即获取最新的设备状态
3. 不需要等待自动刷新周期
## 配置参数
### 后端配置
在 `AmtStatusCheckTask.java` 中可以调整:
```java
// 检测周期(毫秒)
@Scheduled(fixedRate = 30000, initialDelay = 10000)
// fixedRate: 30000 = 30秒
// initialDelay: 10000 = 10秒初始延迟
// 线程池大小
private final ExecutorService executorService = Executors.newFixedThreadPool(20);
// 20 个线程
// Socket 超时时间(毫秒)
socket.connect(new InetSocketAddress(ipAddress, 16992), 3000);
// 3000 = 3秒
```
### 前端配置
在 `index.vue` 中可以调整:
```typescript
// 刷新周期(毫秒)
const refreshInterval = setInterval(() => {
loadData();
}, 10000); // 10000 = 10秒
```
## 性能影响
### 后端资源消耗
- **CPU**: 低(主要是网络 I/O 等待)
- **内存**: 低(20 个线程 + 设备列表)
- **网络**: 每个设备每 30 秒一次连接检测
### 前端资源消耗
- **网络**: 每 10 秒一次 API 请求
- **内存**: 低(只更新设备列表数据)
- **CPU**: 低(简单的数据更新和渲染)
### 数据库影响
- **读取**: 每 30 秒读取所有设备列表
- **写入**: 只在状态变化时写入(增量更新)
- **索引**: 建议在 `ip_address` 和 `amt_status` 字段上建立索引
## 后续优化建议
### 1. WebSocket 推送
替代轮询方式,使用 WebSocket 实时推送状态变化:
**优点**:
- 更实时
- 减少网络请求
- 降低服务器负载
**实现**:
- 后端使用 Spring WebSocket
- 状态变化时主动推送到前端
- 前端监听 WebSocket 消息更新界面
### 2. 智能检测频率
根据设备状态调整检测频率:
- 在线设备: 每 60 秒检测一次
- 离线设备: 每 30 秒检测一次
- 新添加设备: 每 10 秒检测一次(前 5 分钟)
### 3. 批量状态查询接口
添加专门的状态查询接口,只返回状态信息:
```java
@GetMapping("/device/status")
public Result