You've already forked FrameTour-BE
feat(ExtraDevice): 添加外部设备管理功能
- 创建了 ExtraDeviceController 提供分页查询外部设备列表的API接口 - 新增 ExtraDeviceService 和 ExtraDeviceServiceImpl 实现设备查询逻辑 - 添加 ExtraDevicePageQueryReq 和 ExtraDeviceRespVO 请求响应数据模型 - 扩展 ExtraDeviceMapper 支持分页查询外部设备列表 - 实现景区名称填充和设备在线状态判断功能 - 集成 Redis 获取设备心跳时间判断在线状态 - 添加了完整的参数校验和异常处理机制
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
package com.ycwl.basic.service.pc;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.model.pc.extraDevice.req.ExtraDevicePageQueryReq;
|
||||
import com.ycwl.basic.model.pc.extraDevice.resp.ExtraDeviceRespVO;
|
||||
|
||||
/**
|
||||
* 外部设备服务接口
|
||||
*/
|
||||
public interface ExtraDeviceService {
|
||||
/**
|
||||
* 分页查询外部设备列表
|
||||
* @param req 查询请求参数
|
||||
* @return 分页结果
|
||||
*/
|
||||
PageInfo<ExtraDeviceRespVO> pageQuery(ExtraDevicePageQueryReq req);
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package com.ycwl.basic.service.pc.impl;
|
||||
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
|
||||
import com.ycwl.basic.mapper.ExtraDeviceMapper;
|
||||
import com.ycwl.basic.model.pc.extraDevice.req.ExtraDevicePageQueryReq;
|
||||
import com.ycwl.basic.model.pc.extraDevice.resp.ExtraDeviceRespVO;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.service.pc.ExtraDeviceService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 外部设备服务实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ExtraDeviceServiceImpl implements ExtraDeviceService {
|
||||
|
||||
private final ExtraDeviceMapper extraDeviceMapper;
|
||||
private final ScenicRepository scenicRepository;
|
||||
private final RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
/**
|
||||
* Redis Key前缀:ext_device:online:{ident}
|
||||
*/
|
||||
private static final String REDIS_KEY_PREFIX = "ext_device:online:";
|
||||
|
||||
/**
|
||||
* 在线判断阈值:5分钟(300秒)
|
||||
*/
|
||||
private static final long ONLINE_THRESHOLD_SECONDS = 300;
|
||||
|
||||
/**
|
||||
* 时间格式:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
@Override
|
||||
public PageInfo<ExtraDeviceRespVO> pageQuery(ExtraDevicePageQueryReq req) {
|
||||
// 参数校验与默认值设置
|
||||
if (req.getPageNum() == null || req.getPageNum() < 1) {
|
||||
req.setPageNum(1);
|
||||
}
|
||||
if (req.getPageSize() == null || req.getPageSize() < 1) {
|
||||
req.setPageSize(20);
|
||||
}
|
||||
|
||||
// 使用PageHelper进行分页
|
||||
PageHelper.startPage(req.getPageNum(), req.getPageSize());
|
||||
|
||||
// 查询数据库获取设备基础信息
|
||||
List<ExtraDeviceRespVO> devices = extraDeviceMapper.pageQuery(req.getScenicId());
|
||||
|
||||
// 遍历设备列表,填充景区名称和在线状态
|
||||
for (ExtraDeviceRespVO device : devices) {
|
||||
// 1. 填充景区名称
|
||||
fillScenicName(device);
|
||||
|
||||
// 2. 填充在线状态和心跳时间
|
||||
fillOnlineStatus(device);
|
||||
}
|
||||
|
||||
return new PageInfo<>(devices);
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充景区名称
|
||||
* 从景区服务获取景区信息,优先从远程服务获取,失败则降级读取缓存
|
||||
*/
|
||||
private void fillScenicName(ExtraDeviceRespVO device) {
|
||||
try {
|
||||
if (device.getScenicId() != null) {
|
||||
ScenicV2DTO scenic = scenicRepository.getScenicBasic(device.getScenicId());
|
||||
if (scenic != null && StringUtils.isNotBlank(scenic.getName())) {
|
||||
device.setScenicName(scenic.getName());
|
||||
} else {
|
||||
device.setScenicName("未知景区");
|
||||
}
|
||||
} else {
|
||||
device.setScenicName("未知景区");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("获取景区名称失败, scenicId: {}, error: {}", device.getScenicId(), e.getMessage());
|
||||
device.setScenicName("未知景区");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充在线状态和心跳时间
|
||||
* 从Redis获取设备心跳时间戳,判断是否在线(5分钟内有心跳)
|
||||
*/
|
||||
private void fillOnlineStatus(ExtraDeviceRespVO device) {
|
||||
try {
|
||||
if (StringUtils.isBlank(device.getIdent())) {
|
||||
device.setOnline(0);
|
||||
device.setKeepaliveAt("");
|
||||
return;
|
||||
}
|
||||
|
||||
// 从Redis获取心跳时间戳
|
||||
String redisKey = REDIS_KEY_PREFIX + device.getIdent();
|
||||
String timestampStr = redisTemplate.opsForValue().get(redisKey);
|
||||
|
||||
if (StringUtils.isBlank(timestampStr) || !StringUtils.isNumeric(timestampStr)) {
|
||||
// Redis中没有心跳记录或格式不正确
|
||||
device.setOnline(0);
|
||||
device.setKeepaliveAt("");
|
||||
return;
|
||||
}
|
||||
|
||||
// 解析时间戳(秒级)
|
||||
long keepaliveTimestamp = Long.parseLong(timestampStr);
|
||||
long currentTimestamp = System.currentTimeMillis() / 1000;
|
||||
|
||||
// 判断是否在线(5分钟内有心跳)
|
||||
boolean isOnline = (currentTimestamp - keepaliveTimestamp) < ONLINE_THRESHOLD_SECONDS;
|
||||
device.setOnline(isOnline ? 1 : 0);
|
||||
|
||||
// 格式化心跳时间
|
||||
Date keepaliveDate = new Date(keepaliveTimestamp * 1000);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
|
||||
device.setKeepaliveAt(sdf.format(keepaliveDate));
|
||||
|
||||
} catch (Exception e) {
|
||||
log.warn("获取设备在线状态失败, ident: {}, error: {}", device.getIdent(), e.getMessage());
|
||||
device.setOnline(0);
|
||||
device.setKeepaliveAt("");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user