设备控制完善日志,以及更新用户获取工具

master
lld 2026-01-30 02:12:44 +08:00
parent f8f37ae22b
commit c7d19dd442
8 changed files with 68 additions and 18 deletions

View File

@ -43,7 +43,7 @@ server:
# 日志配置 # 日志配置
logging: logging:
level: level:
com.agri: debug com.agri: info
org.springframework: warn org.springframework: warn
# 用户配置 # 用户配置

View File

@ -5,6 +5,8 @@ import com.agri.common.constant.HttpStatus;
import com.agri.common.core.domain.entity.SysRole; import com.agri.common.core.domain.entity.SysRole;
import com.agri.common.core.domain.model.LoginUser; import com.agri.common.core.domain.model.LoginUser;
import com.agri.common.exception.ServiceException; import com.agri.common.exception.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@ -22,6 +24,8 @@ import java.util.stream.Collectors;
public class SecurityUtils public class SecurityUtils
{ {
private static final Logger log = LoggerFactory.getLogger(SecurityUtils.class);
/** /**
* ID * ID
**/ **/
@ -72,14 +76,16 @@ public class SecurityUtils
**/ **/
public static LoginUser getLoginUser() public static LoginUser getLoginUser()
{ {
LoginUser loginUser = null;
try try
{ {
return (LoginUser) getAuthentication().getPrincipal(); loginUser = (LoginUser) getAuthentication().getPrincipal();
} }
catch (Exception e) catch (Exception e)
{ {
throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED); log.error("获取用户信息异常: {}", HttpStatus.UNAUTHORIZED);
} }
return loginUser;
} }
/** /**

View File

@ -31,7 +31,7 @@ public class MybatisPlusHandler implements MetaObjectHandler {
// 填充创建时间字段名createTime当前时间 // 填充创建时间字段名createTime当前时间
this.strictInsertFill(metaObject, "createTime", Date.class, new Date()); this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
// 示例填充创建人假设从上下文获取当前用户ID // 示例填充创建人假设从上下文获取当前用户ID
this.strictInsertFill(metaObject, "createBy", String.class, getLoginUser().getUsername()); this.strictInsertFill(metaObject, "createBy", String.class, getLoginUser()!=null?getLoginUser().getUsername():"");
} }
// 更新操作时自动填充 // 更新操作时自动填充
@ -40,6 +40,6 @@ public class MybatisPlusHandler implements MetaObjectHandler {
// 填充更新时间字段名updateTime当前时间 // 填充更新时间字段名updateTime当前时间
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
// 示例:填充更新人 // 示例:填充更新人
this.strictUpdateFill(metaObject, "updateBy", String.class, getLoginUser().getUsername()); this.strictUpdateFill(metaObject, "updateBy", String.class, getLoginUser()!=null?getLoginUser().getUsername():"");
} }
} }

View File

@ -190,6 +190,7 @@ public class DeviceStatusHandler {
.set(SysDevOperLog::getAckReceived,1) .set(SysDevOperLog::getAckReceived,1)
.set(SysDevOperLog::getIsLockSuc,1) .set(SysDevOperLog::getIsLockSuc,1)
.set(SysDevOperLog::getAckSuc, 1) .set(SysDevOperLog::getAckSuc, 1)
.set(SysDevOperLog::getUpdateBy,"自动关")
.set(SysDevOperLog::getIsTask,autoOffSeconds > 0?1:0) .set(SysDevOperLog::getIsTask,autoOffSeconds > 0?1:0)
.set(ObjectUtils.isEmpty(autoOffSeconds), SysDevOperLog::getNoTaskReason,"当前运行时间:【"+autoOffSeconds+"】") .set(ObjectUtils.isEmpty(autoOffSeconds), SysDevOperLog::getNoTaskReason,"当前运行时间:【"+autoOffSeconds+"】")
.set(SysDevOperLog::getAck, payload) .set(SysDevOperLog::getAck, payload)
@ -289,7 +290,7 @@ public class DeviceStatusHandler {
} }
} catch (MqttException e) { } catch (MqttException e) {
WxUtil.pushText( WxUtil.pushText(
"【消息转发失败】\n deviceId: "+deviceId+"\n payload: "+payload+"\n msg: "+e.getMessage()+"\n cause: "+e.getCause()); "【消息转发失败】\n deviceId: "+deviceId+"\n payload: "+payload+"\n cause: "+e);
log.error("【消息转发失败】deviceId={}, msg={}", deviceId, e.getMessage(), e); log.error("【消息转发失败】deviceId={}, msg={}", deviceId, e.getMessage(), e);
} }
} }

View File

@ -9,6 +9,7 @@ import com.agri.system.service.ISysAgriInfoService;
import com.agri.system.service.ISysAgriLimitService; import com.agri.system.service.ISysAgriLimitService;
import com.agri.system.service.ISysDevOperLogService; import com.agri.system.service.ISysDevOperLogService;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference; import com.alibaba.fastjson2.TypeReference;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttException;
@ -67,7 +68,7 @@ public class FrontendControlHandler {
private ISysDevOperLogService sysDevOperLogService; private ISysDevOperLogService sysDevOperLogService;
@Value("${dtu-ctl-lock-ttl}") @Value("${spring.mqtt.dtu-ctl-lock-ttl}")
private int dtuCtlLockTTL; private int dtuCtlLockTTL;
private static final Map<String, Function<SysAgriLimit, Integer>> LIMIT_MAP = new HashMap<>(); private static final Map<String, Function<SysAgriLimit, Integer>> LIMIT_MAP = new HashMap<>();
static { static {
@ -94,7 +95,20 @@ public class FrontendControlHandler {
log.error("【指令处理】clientId或deviceId为空topic={}", topic); log.error("【指令处理】clientId或deviceId为空topic={}", topic);
return; return;
} }
// 4. 转发指令到设备
String deviceTopic = "dtu/" + deviceId + "/down";
JSONObject payloadObj;
try {
payloadObj = JSON.parseObject(payload);
} catch (Exception e) {
log.error("【设备处理】JSON解析失败payload={}", payload, e);
return;
}
if (payloadObj.containsKey("read")) {
mqttMessageSender.publish(deviceTopic, payload);
log.info("【主动读取】设备{}主动读取payload={}",deviceId, payload);
return;
}
// 解析功能码({"功能码":状态码}格式) // 解析功能码({"功能码":状态码}格式)
Map<String, Integer> funcCodeMap = null; Map<String, Integer> funcCodeMap = null;
try { try {
@ -139,11 +153,9 @@ public class FrontendControlHandler {
log.info("【指令处理】前端{}于{}控制设备{}的{}功能,指令:{}", log.info("【指令处理】前端{}于{}控制设备{}的{}功能,指令:{}",
clientId, LocalDateTime.now(), deviceId, funcType, payload); clientId, LocalDateTime.now(), deviceId, funcType, payload);
// 4. 转发指令到设备
String deviceTopic = "dtu/" + deviceId + "/down";
//todo //todo
mqttMessageSender.publish(deviceTopic, payload); mqttMessageSender.publish(deviceTopic, payload);
// testAutoOffTask(deviceId,funcCodeMap);
SysAgriInfo agriInfo = sysAgriInfoService.lambdaQuery() SysAgriInfo agriInfo = sysAgriInfoService.lambdaQuery()
.eq(SysAgriInfo::getImei, deviceId) .eq(SysAgriInfo::getImei, deviceId)
@ -159,7 +171,11 @@ public class FrontendControlHandler {
logDto.setLockAcquired(1); logDto.setLockAcquired(1);
logDto.setLockHolder(clientId); logDto.setLockHolder(clientId);
logDto.setExecResult(1); logDto.setExecResult(1);
sysDevOperLogService.save(logDto); logDto.setCreateBy("手动控制");
boolean save = sysDevOperLogService.save(logDto);
// if (save) {
// testAutoOffTask(deviceId,funcCodeMap);
// }
log.info("【指令转发】前端{} → 设备{}的{}功能", clientId, deviceId, funcType); log.info("【指令转发】前端{} → 设备{}的{}功能", clientId, deviceId, funcType);
} }
@ -169,7 +185,10 @@ public class FrontendControlHandler {
Integer funcValue = funcCodeMap.get(funcType); Integer funcValue = funcCodeMap.get(funcType);
// 释放对应功能的分布式锁 // 释放对应功能的分布式锁
String lockKey = "lock:" + deviceId + ":" + funcType; String lockKey = "lock:" + deviceId + ":" + funcType;
stringRedisTemplate.delete(lockKey); Boolean delete = stringRedisTemplate.delete(lockKey);
if (delete) {
log.info("【设备控制锁删除成功!】");
}
// 回执成功且值=1时启动自动关闭任务保留原有逻辑 // 回执成功且值=1时启动自动关闭任务保留原有逻辑
if (StringUtils.hasText(funcType) && funcValue != null && funcValue == 1) { if (StringUtils.hasText(funcType) && funcValue != null && funcValue == 1) {
@ -184,9 +203,27 @@ public class FrontendControlHandler {
if (autoOffSeconds > 0) { if (autoOffSeconds > 0) {
mqttAutoOffManager.scheduleAutoOff(deviceId, funcType, autoOffSeconds); mqttAutoOffManager.scheduleAutoOff(deviceId, funcType, autoOffSeconds);
log.debug("【自动关任务】标记需要执行deviceId={}, funcType={}, delay={}s", deviceId, funcType, autoOffSeconds); log.debug("【自动关任务】标记需要执行deviceId={}, funcType={}, delay={}s", deviceId, funcType, autoOffSeconds);
} else { } else {
log.debug("【自动关任务】标记不符合执行运行时间未配置deviceId={}, funcType={}, delay={}s", deviceId, funcType, autoOffSeconds); log.debug("【自动关任务】标记不符合执行运行时间未配置deviceId={}, funcType={}, delay={}s", deviceId, funcType, autoOffSeconds);
} }
sysDevOperLogService.lambdaUpdate()
.eq(SysDevOperLog::getImei, deviceId)
.eq(SysDevOperLog::getFuncCode, funcType)
.eq(SysDevOperLog::getOpType, funcValue)
.eq(SysDevOperLog::getLockAcquired,1)
.orderByDesc(SysDevOperLog::getCreateTime)
.last("LIMIT 1")
.set(SysDevOperLog::getAckReceived,1)
.set(SysDevOperLog::getIsLockSuc,1)
.set(SysDevOperLog::getAckSuc, 1)
.set(SysDevOperLog::getIsTask, 1)
.set(SysDevOperLog::getUpdateBy,"自动关")
.set(autoOffSeconds <= 0, SysDevOperLog::getNoTaskReason,"当前运行时间:【"+autoOffSeconds+"】")
.set(SysDevOperLog::getUpdateBy, "测试")
.set(SysDevOperLog::getExecResult, 1)
.update();
} }
if (StringUtils.hasText(funcType) && funcValue != null && funcValue == 0) { if (StringUtils.hasText(funcType) && funcValue != null && funcValue == 0) {

View File

@ -70,7 +70,7 @@ public class MqttAutoOffManager {
@Value("${spring.mqtt.auto-off-thread-pool-size:5}") @Value("${spring.mqtt.auto-off-thread-pool-size:5}")
private int autoOffThreadPoolSize; private int autoOffThreadPoolSize;
@Value("${dtu-ctl-lock-ttl}") @Value("${spring.mqtt.dtu-ctl-lock-ttl}")
private int dtuCtlLockTTL; private int dtuCtlLockTTL;
@Autowired @Autowired
@ -191,7 +191,7 @@ public class MqttAutoOffManager {
try { try {
runAutoOff(deviceId, funcType); runAutoOff(deviceId, funcType);
} catch (Exception e) { } catch (Exception e) {
WxUtil.pushText("【自动关任务】提交任务失败! \n deviceId: "+deviceId+"\n funcType: "+funcType+"\n msg: "+e.getMessage()+"\n cause: "+e.getCause()); WxUtil.pushText("【自动关任务】提交任务失败! \n deviceId: "+deviceId+"\n funcType: "+funcType+"\n cause: "+e);
log.error("【自动关任务】执行失败deviceId={}, funcType={}", deviceId, funcType, e); log.error("【自动关任务】执行失败deviceId={}, funcType={}", deviceId, funcType, e);
} finally { } finally {
// 任务执行完成后移除映射 // 任务执行完成后移除映射
@ -226,7 +226,7 @@ public class MqttAutoOffManager {
latestObj = JSON.parseObject(latest); latestObj = JSON.parseObject(latest);
} catch (Exception e) { } catch (Exception e) {
skipReason = "【自动关任务】执行报错-解析异常"; skipReason = "【自动关任务】执行报错-解析异常";
WxUtil.pushText("自动关任务执行报错-解析异常:\n deviceId: " + deviceId + "\n funcType:" + funcType+"\n 异常:"+e.getMessage()+"\n Cause: "+e.getCause()); WxUtil.pushText("自动关任务执行报错-解析异常:\n deviceId: " + deviceId + "\n funcType:" + funcType+"\n Cause: "+e);
log.warn("【自动关任务】最新状态JSON解析失败跳过deviceId={}, funcType={}", deviceId, funcType); log.warn("【自动关任务】最新状态JSON解析失败跳过deviceId={}, funcType={}", deviceId, funcType);
return; return;
} }
@ -244,7 +244,9 @@ public class MqttAutoOffManager {
} catch (Exception ignore) { } catch (Exception ignore) {
skipReason = "【自动关任务】最新状态功能码获取失败"; skipReason = "【自动关任务】最新状态功能码获取失败";
} }
if (current == null || current!=1) {
skipReason = "【自动关任务】检测未运行或状态未知";
}
sysDevOperLogService.lambdaUpdate() sysDevOperLogService.lambdaUpdate()
.eq(SysDevOperLog::getImei, deviceId) .eq(SysDevOperLog::getImei, deviceId)
.eq(SysDevOperLog::getFuncCode, funcType) .eq(SysDevOperLog::getFuncCode, funcType)
@ -256,6 +258,7 @@ public class MqttAutoOffManager {
.last("LIMIT 1") .last("LIMIT 1")
.set(SysDevOperLog::getExecResult,1) .set(SysDevOperLog::getExecResult,1)
.set(SysDevOperLog::getLatestState, latest) .set(SysDevOperLog::getLatestState, latest)
.set(SysDevOperLog::getUpdateBy,"自动关")
.set(!skipReason.isEmpty(), SysDevOperLog::getSkipReason, skipReason) .set(!skipReason.isEmpty(), SysDevOperLog::getSkipReason, skipReason)
.update(); .update();
@ -289,6 +292,7 @@ public class MqttAutoOffManager {
logDto.setLockHolder("autoOff"); logDto.setLockHolder("autoOff");
logDto.setExecResult(1); logDto.setExecResult(1);
logDto.setLatestState(latest); logDto.setLatestState(latest);
logDto.setCreateBy("自动关");
logDto.setTaskStatus(getFutureStatus().toString()); logDto.setTaskStatus(getFutureStatus().toString());
sysDevOperLogService.save(logDto); sysDevOperLogService.save(logDto);
log.info("【自动关任务】检测仍在运行已下发关闭deviceId={}, funcType={}, payload={}", deviceId, funcType, down.toJSONString()); log.info("【自动关任务】检测仍在运行已下发关闭deviceId={}, funcType={}, payload={}", deviceId, funcType, down.toJSONString());

View File

@ -142,7 +142,7 @@ public class MqttClientManager implements SmartLifecycle {
log.error("【MQTT连接异常】连接断开clientId{},原因:{}", log.error("【MQTT连接异常】连接断开clientId{},原因:{}",
safeClientId(), (cause == null ? "unknown" : cause.getMessage()), cause); safeClientId(), (cause == null ? "unknown" : cause.getMessage()), cause);
WxUtil.pushText("【MQTT连接异常】连接断开\n clientId"+safeClientId()+"\n 原因:"+(cause == null ? "unknown" : cause.getMessage())+"\n Cause: "+cause.getCause()); WxUtil.pushText("【MQTT连接异常】连接断开\n clientId"+safeClientId()+"\n Cause: "+cause);
// 【方案A】不再触发自写重连Paho自动重连会接管重连过程 // 【方案A】不再触发自写重连Paho自动重连会接管重连过程
// 这里只记录日志即可 // 这里只记录日志即可
if (isRunning.get()) { if (isRunning.get()) {

View File

@ -1,5 +1,6 @@
package com.agri.framework.web.dispatcher; package com.agri.framework.web.dispatcher;
import com.agri.common.utils.wechat.WxUtil;
import com.agri.framework.interceptor.DeviceStatusHandler; import com.agri.framework.interceptor.DeviceStatusHandler;
import com.agri.framework.interceptor.FrontendControlHandler; import com.agri.framework.interceptor.FrontendControlHandler;
import com.agri.framework.interceptor.FrontendOnlineHandler; import com.agri.framework.interceptor.FrontendOnlineHandler;
@ -64,6 +65,7 @@ public class MqttMessageDispatcher {
} }
// todo 是否加回复主题?? // todo 是否加回复主题??
} catch (Exception e) { } catch (Exception e) {
WxUtil.pushText("【MQTT消息处理异常】\n topic: "+ topic+"\n cause: "+e);
log.error("【MQTT消息处理异常】topic={}", topic, e); log.error("【MQTT消息处理异常】topic={}", topic, e);
} }
} }