Commit 5111b8c7 by HlQ

[add]

1.添加 Mall 列表查询
2.添加服务器指标报表
3.列表数据冗余
[chg]
1.Agent 获取升级包信息接口修改
2.代码格式修改,错误命名修改
1 parent 613ae9cc
Showing 35 changed files with 571 additions and 199 deletions
......@@ -10,7 +10,7 @@ public enum MqttMessageType {
REGISTER("REGISTER"),
DEVICE_OFFLINE("DEVICE_OFFLINE"),
UPGRADE("UPGRADE"),
WHOLEDAYA_ANALYZE("WHOLE_ANALYZE_EXCEPTION");
WHOLEDAY_ANALYZE("WHOLE_ANALYZE_EXCEPTION");
private final String type;
......
......@@ -3,13 +3,16 @@ package vion.controller.monitor;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import vion.dto.monitor.AgentDTO;
import vion.model.monitor.AgentRecord;
import vion.model.monitor.RAgentService;
import vion.model.monitor.ServiceInfo;
import vion.service.monitor.IAgentService;
import vion.vo.monitor.AgentVO;
import java.time.LocalDateTime;
import java.util.List;
/**
......@@ -41,11 +44,10 @@ public class AgentController {
return agentService.update(dto);
}
@PostMapping("/upgrade/{id}")
@PostMapping("/upgrade/{uid}")
@SaCheckPermission(value = "agent:upgrade", orRole = "admin")
public String upgradeCommand(@RequestBody AgentDTO dto) {
//todo
return "";
public String upgradeCommand(@PathVariable String uid, Long upgradeId) {
return agentService.upgradeCommand(uid, upgradeId);
}
@GetMapping("/service/{uid}")
......@@ -77,4 +79,12 @@ public class AgentController {
public String assign(@PathVariable String uid, @RequestBody List<ServiceInfo> serviceInfoList) {
return agentService.assign(uid, serviceInfoList);
}
@GetMapping("/form/{uid}")
@SaCheckPermission(value = "agent:form", orRole = "admin")
public List<AgentRecord> getForm(@PathVariable String uid,
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
return agentService.getForm(uid, startTime, endTime);
}
}
......@@ -59,7 +59,7 @@ public class EventController {
return eventService.removeById(id) ? "事件删除成功" : "事件删除失败";
}
@GetMapping("/bind/{agentUid}")
@GetMapping("/bind")
@SaCheckPermission(value = "event:bind:list", orRole = "admin")
public Page<EventVO> listAgentEvent(EventDTO dto) {
return eventService.list(dto);
......
package vion.controller.monitor;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import vion.dto.monitor.MallDTO;
import vion.service.monitor.IMallService;
import vion.vo.monitor.MallVO;
/**
* mall 信息
*/
@RestController
@RequestMapping("/api/mall")
@RequiredArgsConstructor
public class MallController {
private final IMallService mallService;
@GetMapping
@SaCheckPermission(value = "mall:list", orRole = "admin")
public Page<MallVO> list(MallDTO dto) {
return mallService.list(dto);
}
@GetMapping("/{id}")
@SaCheckPermission(value = "mall:get", orRole = "admin")
public MallVO get(@PathVariable Long id) {
return mallService.get(id);
}
}
......@@ -36,12 +36,12 @@ public class MonitorController {
/**
* Agent 获取升级包信息
*
* @param type 1:store 2:mall
* @param id 升级包id
* @return Upgrade 升级包信息
*/
@GetMapping("/upgrade")
public Upgrade getUpgradeInfo(Short type) {
return agentService.getUpgradeInfo(type);
public Upgrade getUpgradeInfo(Long id) {
return agentService.getUpgradeInfo(id);
}
/**
......
package vion.cron;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import vion.service.monitor.IAgentService;
/**
* 系统级事件监控
*/
@Component
@Slf4j
@RequiredArgsConstructor
public class SystemRunner {
private final IAgentService agentService;
// @Scheduled(cron = "0 0 9 * * ?")
public void checkLicense() {
log.info("监测授权文件到期日开始");
agentService.checkLicense();
log.info("监测授权文件到期日结束");
}
}
......@@ -5,7 +5,6 @@ import lombok.Setter;
import vion.dto.BaseDTO;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 监测事件
......@@ -16,6 +15,11 @@ public class EventDTO extends BaseDTO {
private Long id;
/**
* 类型 0:store+mall 1:store,2:mall
*/
private Short type;
/**
* 唯一标识
*/
private String uid;
......@@ -56,6 +60,11 @@ public class EventDTO extends BaseDTO {
private Object rule;
/**
* 描述
*/
private String describe;
/**
* 备注
*/
private String remark;
......@@ -70,10 +79,6 @@ public class EventDTO extends BaseDTO {
*/
private String updateBy;
private LocalDateTime createTime;
private LocalDateTime updateTime;
/**
* agent uid
*/
......
package vion.dto.monitor;
import lombok.Getter;
import lombok.Setter;
import vion.dto.BaseDTO;
/**
* 项目mall信息
*/
@Getter
@Setter
public class MallDTO extends BaseDTO {
private Long id;
/**
* agent uid
*/
private String agentUid;
/**
* agent类型 1:store,2:mall
*/
private Short agentType;
/**
* 所属集团uid
*/
private String accountUid;
private String accountName;
/**
* mall unid
*/
private String uid;
/**
* mall名称
*/
private String name;
/**
* mall营业状态
*/
private Boolean status;
/**
* 时区
*/
private String timeZone;
}
\ No newline at end of file
package vion.event.mqtt;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import net.dreamlu.iot.mqtt.codec.MqttPublishMessage;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.iot.mqtt.codec.MqttQoS;
import net.dreamlu.iot.mqtt.core.client.IMqttClientMessageListener;
import net.dreamlu.iot.mqtt.spring.client.MqttClientSubscribe;
import net.dreamlu.iot.mqtt.spring.client.MqttClientTemplate;
import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.tio.core.ChannelContext;
import vion.constant.EventStatusEnum;
import vion.constant.MqttMessageType;
import vion.dto.OfflineDevice;
import vion.mapper.monitor.AgentMapper;
import vion.mapper.monitor.RAgentEventMapper;
import vion.model.monitor.EventRecord;
import vion.model.monitor.OfflineDevice;
import vion.model.monitor.RAgentEvent;
import vion.service.monitor.IAgentService;
import vion.service.monitor.IEventRecordService;
......@@ -32,123 +25,110 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import static vion.constant.MqttMessageType.WHOLEDAYA_ANALYZE;
/**
* 客户端消息监听的另一种方式
*
* @author L.cm
*/
@Service
@MqttClientSubscribe("${mqtt.client.server-topic:/MS/receive}")
@RequiredArgsConstructor
public class MqttClientMessageListener implements IMqttClientMessageListener {
private static final Logger logger = LoggerFactory.getLogger(MqttClientMessageListener.class);
private final MqttClientTemplate client;
private final IAgentService agentService;
private final IEventRecordService recordService;
private final AgentMapper agentMapper;
private final RAgentEventMapper agentEventMapper;
@Override
public void onMessage(ChannelContext context, String topic, MqttPublishMessage message, byte[] payload) {
String payloadStr = new String(payload, StandardCharsets.UTF_8);
logger.info("topic:{} payload:{}", topic, payloadStr);
try {
JsonNode object = JsonUtil.parseTree(payloadStr);
String type = object.get("eventType").asText();
switch (MqttMessageType.getEnumByType(type)) {
case MqttMessageType.REGISTER:
logger.info("设备注册:{}", payloadStr);
String agentUid = object.get("agentUid").asText();
updateTaskByAgent(agentUid);
break;
case MqttMessageType.DEVICE_OFFLINE:
//设备离线
handleDeviceOffline(payloadStr);
break;
case MqttMessageType.WHOLEDAYA_ANALYZE:
//全天分析异常
handleWholeDayAnalyze(payloadStr);
break;
default:
logger.info("未定义的消息类型:{}, payload:{}", type, payloadStr);
break;
}
} catch (Exception e) {
logger.error("解析数据异常", e);
}
}
//下发事件
private void updateTaskByAgent(String agentUid) {
// 发送消息
// MqttClientKit.publish(topic, payload);
QueryWrapper<RAgentEvent> wrapper = new QueryWrapper<RAgentEvent>().eq("agent_uid", agentUid).eq("control_switch", 1);
List<RAgentEvent> list = agentEventMapper.selectList(wrapper);
if (list == null || list.isEmpty()) {
logger.info("agent:{} 未配置事件监测", agentUid);
return;
}
String topic = agentService.getAgentEventTopic(agentUid);
if (topic == null) {
logger.info("agent:{} 获取topic失败", agentUid);
return;
}
logger.info("agent:{} 开始下发事件监测", agentUid);
for (RAgentEvent agentEvent : list) {
client.publish(StrUtil.format("/SA/{}/event/push", agentUid), JsonUtil.toJsonByte(agentEvent), MqttQoS.QOS2);
}
logger.info("agent:{} 结束下发事件监测", agentUid);
}
//设备离线上报
private void handleDeviceOffline(String payloadStr) {
EventRecord eventRecord = JsonUtil.parseObject(payloadStr, EventRecord.class);
String list = (String) eventRecord.getData();
List<OfflineDevice> deviceList = JsonUtil.parseArray(list, OfflineDevice.class);
List<EventRecord> records = new ArrayList<>();
if (deviceList == null || deviceList.isEmpty()) {
EventRecord eventRecord1 = new EventRecord();
BeanUtil.copyProperties(eventRecord, eventRecord1);
eventRecord1.setEventUid(eventRecord.getEventUid());
//入库
records.add(eventRecord1);
} else {
for (int i = 0; i < deviceList.size(); i++) {
OfflineDevice device = deviceList.get(i);
EventRecord eventRecord1 = new EventRecord();
BeanUtil.copyProperties(eventRecord, eventRecord1);
eventRecord1.setEventUid(eventRecord.getEventUid());
eventRecord1.setData(JsonUtil.toJsonString(device));
eventRecord1.setMallUid(deviceList.get(i).getMallUid());
if (StringUtils.isEmpty(device.getDevices())) {
eventRecord1.setStatus(EventStatusEnum.SUCCESS.getCode());
} else {
eventRecord1.setStatus(EventStatusEnum.FAIL.getCode());
}
//入库
records.add(eventRecord1);
}
}
if (!records.isEmpty()) {
recordService.saveBatch(records);
}
// logger.info("设备离线:{}", JSON.toJSONString(eventRecord));
}
//全天分析异常上报
private void handleWholeDayAnalyze(String payloadStr) {
EventRecord eventRecord = JsonUtil.parseObject(payloadStr, EventRecord.class);
recordService.save(eventRecord);
}
@Slf4j
public class MqttClientMessageListener {
private final MqttClientTemplate client;
private final IAgentService agentService;
private final IEventRecordService recordService;
private final IRAgentEventService agentEventService;
@MqttClientSubscribe("${mqtt.client.server-topic:/MS/receive}")
public void onMessage(String topic, byte[] payload) {
String payloadStr = new String(payload, StandardCharsets.UTF_8);
log.info("topic:{} payload:{}", topic, payloadStr);
try {
JsonNode object = JsonUtil.parseTree(payloadStr);
String type = object.path("eventType").asText();
switch (MqttMessageType.getEnumByType(type)) {
case MqttMessageType.REGISTER:
log.info("设备注册:{}", payloadStr);
String agentUid = object.path("agentUid").asText();
updateTaskByAgent(agentUid);
break;
case MqttMessageType.DEVICE_OFFLINE:
//设备离线
handleDeviceOffline(payloadStr);
break;
case MqttMessageType.WHOLEDAY_ANALYZE:
//全天分析异常
handleWholeDayAnalyze(payloadStr);
break;
default:
log.info("未定义的消息类型:{}, payload:{}", type, payloadStr);
break;
}
} catch (Exception e) {
log.error("解析数据异常", e);
}
}
//下发事件
private void updateTaskByAgent(String agentUid) {
List<RAgentEvent> list = agentEventService.lambdaQuery().eq(RAgentEvent::getAgentUid, agentUid)
.eq(RAgentEvent::getControlSwitch, 1).list();
if (CollUtil.isEmpty(list)) {
log.info("agent:{} 未配置事件监测", agentUid);
return;
}
String topic = agentService.getAgentEventTopic(agentUid);
if (StrUtil.isBlank(topic)) {
log.info("agent:{} 获取topic失败", agentUid);
return;
}
log.info("agent:{} 开始下发事件监测", agentUid);
for (RAgentEvent agentEvent : list) {
client.publish(StrUtil.format("/SA/{}/event/push", agentUid), JsonUtil.toJsonByte(agentEvent), MqttQoS.QOS2);
}
log.info("agent:{} 结束下发事件监测", agentUid);
}
//设备离线上报
private void handleDeviceOffline(String payloadStr) {
EventRecord eventRecord = JsonUtil.parseObject(payloadStr, EventRecord.class);
String list = (String) eventRecord.getData();
List<OfflineDevice> deviceList = JsonUtil.parseArray(list, OfflineDevice.class);
List<EventRecord> records = new ArrayList<>();
if (CollUtil.isEmpty(deviceList)) {
EventRecord eventRecord1 = new EventRecord();
BeanUtil.copyProperties(eventRecord, eventRecord1);
eventRecord1.setEventUid(eventRecord.getEventUid());
records.add(eventRecord1);
} else {
for (int i = 0; i < deviceList.size(); i++) {
OfflineDevice device = deviceList.get(i);
EventRecord eventRecord1 = new EventRecord();
BeanUtil.copyProperties(eventRecord, eventRecord1);
eventRecord1.setEventUid(eventRecord.getEventUid());
eventRecord1.setData(JsonUtil.toJsonString(device));
eventRecord1.setMallUid(deviceList.get(i).getMallUid());
if (StringUtils.isEmpty(device.getDevices())) {
eventRecord1.setStatus(EventStatusEnum.SUCCESS.getCode());
} else {
eventRecord1.setStatus(EventStatusEnum.FAIL.getCode());
}
records.add(eventRecord1);
}
}
if (CollUtil.isNotEmpty(records)) {
recordService.saveBatch(records);
}
}
//全天分析异常上报
private void handleWholeDayAnalyze(String payloadStr) {
EventRecord eventRecord = JsonUtil.parseObject(payloadStr, EventRecord.class);
recordService.save(eventRecord);
}
}
package vion.mapper.monitor;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.github.yulichang.base.MPJBaseMapper;
import vion.model.monitor.EventRecord;
/**
* @author vion
* @date 2024/10/31
*/
public interface EventRecordMapper extends BaseMapper<EventRecord> {
public interface EventRecordMapper extends MPJBaseMapper<EventRecord> {
}
\ No newline at end of file
package vion.mapper.monitor;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.github.yulichang.base.MPJBaseMapper;
import vion.model.monitor.MAccount;
/**
* @author vion
* @date 2024/10/31
*/
public interface MAccountMapper extends BaseMapper<MAccount> {
public interface MAccountMapper extends MPJBaseMapper<MAccount> {
}
\ No newline at end of file
package vion.mapper.monitor;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.github.yulichang.base.MPJBaseMapper;
import vion.model.monitor.Mall;
/**
* @author vion
* @date 2024/10/31
*/
public interface MallMapper extends BaseMapper<Mall> {
public interface MallMapper extends MPJBaseMapper<Mall> {
}
\ No newline at end of file
......@@ -3,7 +3,8 @@ package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import vion.dto.DeviceDTO;
import vion.vo.DeviceVO;
......@@ -13,7 +14,8 @@ import java.time.LocalDateTime;
/**
* 设备表
*/
@Data
@Getter
@Setter
@TableName(value = "tbl_device")
@AutoMappers({
@AutoMapper(target = DeviceVO.class),
......
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
/**
* @author vion
* @date 2024/8/12
*/
/**
* 设备变更日志表
*/
@Data
@Getter
@Setter
@TableName(value = "tbl_device_log")
public class DeviceLog {
@TableId(value = "id", type = IdType.AUTO)
......
......@@ -12,7 +12,7 @@ import java.time.LocalDateTime;
*/
@Getter
@Setter
@TableName(value = "m_agent_record")
@TableName(value = "m_agent_record", autoResultMap = true)
public class AgentRecord {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
......@@ -72,4 +72,10 @@ public class AgentRecord {
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
/**
* 授权到期日期
*/
@TableField(exist = false)
private String licenseDate;
}
\ No newline at end of file
......@@ -26,6 +26,12 @@ public class Event extends BaseDTO {
private Long id;
/**
* 类型 0:store+mall 1:store,2:mall
*/
@TableField(value = "type")
private Short type;
/**
* 唯一标识
*/
@TableField(value = "uid")
......@@ -74,6 +80,13 @@ public class Event extends BaseDTO {
private Object rule;
/**
* 描述
*/
@TableField(value = "describe")
private String describe;
/**
* 备注
*/
@TableField(value = "remark")
......
......@@ -12,7 +12,7 @@ import java.time.LocalDateTime;
*/
@Getter
@Setter
@TableName(value = "m_event_record")
@TableName(value = "m_event_record", autoResultMap = true)
public class EventRecord {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
......@@ -60,9 +60,9 @@ public class EventRecord {
private Short status;
/**
* 设备上报数据
* 上报数据
*/
@TableField(value = "\"data\"", typeHandler = JsonbTypeHandler.class)
@TableField(value = "data", typeHandler = JsonbTypeHandler.class)
private Object data;
@TableField(value = "create_time", fill = FieldFill.INSERT)
......
......@@ -37,7 +37,7 @@ public class MAccount {
/**
* 集团名称
*/
@TableField(value = "\"name\"")
@TableField(value = "\"name\"", condition = SqlCondition.LIKE)
private String name;
/**
......
package vion.model.monitor;
import com.baomidou.mybatisplus.annotation.*;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import lombok.Getter;
import lombok.Setter;
import vion.dto.monitor.MallDTO;
import vion.vo.monitor.MallVO;
import java.time.LocalDateTime;
......@@ -12,6 +16,10 @@ import java.time.LocalDateTime;
@Getter
@Setter
@TableName(value = "m_mall")
@AutoMappers({
@AutoMapper(target = MallVO.class),
@AutoMapper(target = MallDTO.class),
})
public class Mall {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
......@@ -43,7 +51,7 @@ public class Mall {
/**
* mall名称
*/
@TableField(value = "\"name\"")
@TableField(value = "\"name\"", condition = SqlCondition.LIKE)
private String name;
/**
......
package vion.dto;
package vion.model.monitor;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Data
@Getter
@Setter
public class OfflineDevice {
private String mallUid;
private String devices;
......
......@@ -72,4 +72,7 @@ public class ServiceInfo extends BaseDTO {
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(exist = false)
private ServiceRecord serviceRecord;
}
\ No newline at end of file
......@@ -38,7 +38,13 @@ public class ServiceRecord {
* 状态
*/
@TableField(value = "\"status\"")
private Boolean status;
private Integer status;
/**
* 响应结果的状态
*/
@TableField(value = "body_status")
private Integer bodyStatus;
/**
* 监测时间
......
package vion.service.impl.monitor;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
......@@ -15,7 +16,6 @@ import org.dromara.hutool.core.date.TimeUtil;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.text.split.SplitUtil;
import org.dromara.hutool.core.util.ByteUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.core.util.RandomUtil;
import org.springframework.beans.factory.annotation.Value;
......@@ -33,7 +33,7 @@ import vion.service.monitor.*;
import vion.utils.JsonUtil;
import vion.vo.monitor.AgentVO;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
......@@ -54,6 +54,7 @@ public class AgentServiceImpl extends MPJBaseServiceImpl<AgentMapper, Agent> imp
private final IRAgentServiceService rAgentServiceService;
private final IRAgentEventService irAgentEventService;
private final IUpgradeService upgradeService;
private final IEventRecordService eventRecordService;
private final Converter converter;
private final MqttClientTemplate client;
private final IMAccountService accountService;
......@@ -65,19 +66,26 @@ public class AgentServiceImpl extends MPJBaseServiceImpl<AgentMapper, Agent> imp
public Page<AgentVO> list(AgentDTO dto) {
var wrapper = new MPJLambdaWrapper<>(converter.convert(dto, Agent.class))
.selectAll(Agent.class)
.selectAssociation(AgentRecord.class, AgentVO::getAgentRecord)
.leftJoin(AgentRecord.class, AgentRecord::getAgentUid, Agent::getUid)
.orderByAsc(Agent::getCreateTime);
var agentVOPage = this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), AgentVO.class, wrapper);
Opt.ofEmptyAble(agentVOPage.getRecords())
.ifPresent(r -> {
var agentUidList = r.stream().map(AgentVO::getUid).toList();
// 查询服务器信息
var agentRecWrapper = Wrappers.<AgentRecord>query()
.select("DISTINCT on (agent_uid) *")
.in("agent_uid", agentUidList)
.orderByDesc("agent_uid", "create_time");
var agentRecordList = agentRecordService.list(agentRecWrapper);
var uid2AgentRecMap = agentRecordList.stream().collect(Collectors.toMap(AgentRecord::getAgentUid, Function.identity()));
r.forEach(a -> a.setAgentRecord(uid2AgentRecMap.get(a.getUid())));
// 查询异常服务的名称
var serviceRecordWrapper = new MPJLambdaWrapper<ServiceRecord>()
.select("DISTINCT on (agent_uid, service_uid) t.*")
.selectAs("si", ServiceInfo::getName, ServiceRecord::getName)
.leftJoin(ServiceInfo.class, "si", ServiceInfo::getUid, "t", ServiceRecord::getServiceUid)
.in(ServiceRecord::getAgentUid, agentUidList)
.eq(ServiceRecord::getStatus, false)
.orderByDesc(ServiceRecord::getAgentUid, ServiceRecord::getServiceUid, ServiceRecord::getMonitorTime);
var serviceRecordList = serviceRecordService.selectJoinList(ServiceRecord.class, serviceRecordWrapper);
var serviceNameMap = serviceRecordList.stream().collect(Collectors.groupingBy(ServiceRecord::getAgentUid, Collectors.mapping(ServiceRecord::getName, Collectors.joining(","))));
......@@ -104,6 +112,14 @@ public class AgentServiceImpl extends MPJBaseServiceImpl<AgentMapper, Agent> imp
}
@Override
public String upgradeCommand(String uid, Long upgradeId) {
var topic = StrUtil.format("/SA/{}/ota", uid);
var node = JsonUtil.createObj().put("upgradeId", upgradeId);
client.publish(topic, JsonUtil.toJsonByte(node), MqttQoS.QOS2);
return "升级指令下发成功,请稍后查看Agent版本号";
}
@Override
public List<ServiceInfo> getServicesByUid(String uid) {
var wrapper = new MPJLambdaWrapper<ServiceInfo>()
.selectAs(RAgentService::getId, ServiceInfo::getId)
......@@ -121,6 +137,18 @@ public class AgentServiceImpl extends MPJBaseServiceImpl<AgentMapper, Agent> imp
.eq(RAgentService::getAgentUid, uid)
.orderByAsc(ServiceInfo::getCreateTime);
var serviceInfoList = serviceInfoService.selectJoinList(ServiceInfo.class, wrapper);
Opt.ofEmptyAble(serviceInfoList)
.ifPresent(r -> {
var serviceUidList = r.stream().map(ServiceInfo::getUid).toList();
var serviceRecWrapper = Wrappers.<ServiceRecord>query()
.select("DISTINCT on (service_uid) *")
.in("service_uid", serviceUidList)
.eq("agent_uid", uid)
.orderByDesc("service_uid", "monitor_time");
var serviceRecordList = serviceRecordService.list(serviceRecWrapper);
var serviceUid2SelfMap = serviceRecordList.stream().collect(Collectors.toMap(ServiceRecord::getServiceUid, Function.identity()));
r.forEach(tmp -> tmp.setServiceRecord(serviceUid2SelfMap.get(tmp.getUid())));
});
return serviceInfoList;
}
......@@ -155,9 +183,17 @@ public class AgentServiceImpl extends MPJBaseServiceImpl<AgentMapper, Agent> imp
@Override
public String assign(String uid, List<ServiceInfo> serviceInfoList) {
var servicesJson = JsonUtil.toJsonString(serviceInfoList);
String SERVICE_PUSH_TOPIC = "/SA/{}/service/push";
return client.publish(StrUtil.format(SERVICE_PUSH_TOPIC, uid), ByteUtil.toBytes(servicesJson, StandardCharsets.UTF_8), MqttQoS.QOS2) ? "服务列表下发成功" : "服务列表下发失败";
return client.publish(StrUtil.format(SERVICE_PUSH_TOPIC, uid), JsonUtil.toJsonByte(serviceInfoList), MqttQoS.QOS2) ? "服务列表下发成功" : "服务列表下发失败";
}
@Override
public List<AgentRecord> getForm(String uid, LocalDateTime startTime, LocalDateTime endTime) {
return agentRecordService.lambdaQuery()
.eq(AgentRecord::getAgentUid, uid)
.between(AgentRecord::getCreateTime, startTime, endTime)
.orderByAsc(AgentRecord::getCreateTime)
.list();
}
@Override
......@@ -201,18 +237,18 @@ public class AgentServiceImpl extends MPJBaseServiceImpl<AgentMapper, Agent> imp
}
@Override
public Upgrade getUpgradeInfo(Short type) {
return upgradeService.lambdaQuery()
.eq(Upgrade::getType, type)
.orderByDesc(Upgrade::getBuildTime)
.last("limit 1")
.one();
public Upgrade getUpgradeInfo(Long id) {
return upgradeService.getById(id);
}
@Override
public String recAgentRecord(AgentRecord agentRecord) {
agentRecord.setBootTime(TimeUtil.of(agentRecord.getBootTimestamp() * 1000));
return agentRecordService.save(agentRecord) ? "success" : "error";
agentRecordService.save(agentRecord);
// 更新授权信息
var licenseDate = agentRecord.getLicenseDate();
this.lambdaUpdate().set(Agent::getLicenseDate, licenseDate).eq(Agent::getUid, agentRecord.getAgentUid()).update();
return "success";
}
@Override
......@@ -328,6 +364,25 @@ public class AgentServiceImpl extends MPJBaseServiceImpl<AgentMapper, Agent> imp
}
@Override
public void checkLicense() {
/*var agentList = this.lambdaQuery().isNotNull(Agent::getLicenseDate).list();
List<EventRecord> recList = new ArrayList<>();
agentList.forEach(a -> {
var licenseDate = TimeUtil.parseDateByISO(a.getLicenseDate());
// 当前日期减去30天,小于等于 licenseDate
if (LocalDate.now().minusDays(30).isAfter(licenseDate) {
var eventRecord = new EventRecord();
eventRecord.setAgentUid(a.getUid());
eventRecord.setEventUid("ttt");
eventRecord.setEventType("LICENSE_EXPIRED");
eventRecord.setStatus((short) 0);
recList.add(eventRecord);
}
});
eventRecordService.saveBatch(recList);*/
}
@Override
public String getAgentEventTopic(String agentUid) {
Agent agent = this.lambdaQuery().eq(Agent::getUid, agentUid).one();
if (ObjUtil.isNull(agent)) {
......
package vion.service.impl.monitor;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.base.MPJBaseServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.monitor.EventRecordMapper;
import vion.model.monitor.EventRecord;
......@@ -10,6 +10,6 @@ import vion.service.monitor.IEventRecordService;
* @date 2024/10/31
*/
@Service
public class EventRecordServiceImpl extends ServiceImpl<EventRecordMapper, EventRecord> implements IEventRecordService {
public class EventRecordServiceImpl extends MPJBaseServiceImpl<EventRecordMapper, EventRecord> implements IEventRecordService {
}
package vion.service.impl.monitor;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.Opt;
import org.springframework.stereotype.Service;
import vion.dto.monitor.EventDTO;
import vion.mapper.monitor.EventMapper;
import vion.model.monitor.Event;
import vion.model.monitor.EventRecord;
import vion.model.monitor.RAgentEvent;
import vion.service.monitor.IEventRecordService;
import vion.service.monitor.IEventService;
import vion.vo.monitor.EventVO;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author vion
* @date 2024/10/31
......@@ -22,18 +29,38 @@ import vion.vo.monitor.EventVO;
@RequiredArgsConstructor
public class EventServiceImpl extends MPJBaseServiceImpl<EventMapper, Event> implements IEventService {
private final IEventRecordService eventRecordService;
private final Converter converter;
@Override
public Page<EventVO> list(EventDTO dto) {
Assert.notNull(dto.getAgentUid(), "agentUid 不能为空");
Assert.notNull(dto.getMallUid(), "mallUid 不能为空");
var wrapper = new MPJLambdaWrapper<>(converter.convert(dto, Event.class))
.selectAs(Event::getName, EventVO::getName)
.selectAs(Event::getUid, EventVO::getUid)
.selectAsClass(RAgentEvent.class, EventVO.class)
.leftJoin(RAgentEvent.class, RAgentEvent::getEventUid, Event::getUid)
.eq(RAgentEvent::getMallUid, dto.getMallUid())
.orderByDesc(RAgentEvent::getUpdateTime);
return this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), EventVO.class, wrapper);
var eventVOPage = this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), EventVO.class, wrapper);
Opt.ofEmptyAble(eventVOPage.getRecords())
.ifPresent(r -> {
var eventUidList = r.stream().map(EventVO::getUid).toList();
// fixme data 是字符串
/* var eventRecWrapper1 = new MPJLambdaWrapper<EventRecord>()
.select("DISTINCT on (event_uid) *")
.in("event_uid", eventUidList)
.orderByDesc("event_uid", "create_time");
var eventRecordList1 = eventRecordService.selectJoinList(EventRecord.class, eventRecWrapper1);*/
var eventRecWrapper = Wrappers.<EventRecord>query()
.select("DISTINCT on (event_uid) *")
.in("event_uid", eventUidList)
.orderByDesc("event_uid", "create_time");
var eventRecordList = eventRecordService.list(eventRecWrapper);
var eventUid2SelfMap = eventRecordList.stream().collect(Collectors.toMap(EventRecord::getEventUid, Function.identity()));
r.forEach(tmp -> tmp.setEventRecord(eventUid2SelfMap.get(tmp.getUid())));
});
return eventVOPage;
}
}
package vion.service.impl.monitor;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.base.MPJBaseServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.monitor.MAccountMapper;
import vion.model.monitor.MAccount;
......@@ -11,6 +11,6 @@ import vion.service.monitor.IMAccountService;
* @date 2024/10/31
*/
@Service
public class MAccountServiceImpl extends ServiceImpl<MAccountMapper, MAccount> implements IMAccountService {
public class MAccountServiceImpl extends MPJBaseServiceImpl<MAccountMapper, MAccount> implements IMAccountService {
}
package vion.service.impl.monitor;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.Opt;
import org.springframework.stereotype.Service;
import vion.dto.monitor.MallDTO;
import vion.mapper.monitor.MallMapper;
import vion.model.monitor.EventRecord;
import vion.model.monitor.MAccount;
import vion.model.monitor.Mall;
import vion.service.monitor.IEventRecordService;
import vion.service.monitor.IMallService;
import vion.vo.monitor.MallVO;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author vion
* @date 2024/10/31
*/
@Service
public class MallServiceImpl extends ServiceImpl<MallMapper, Mall> implements IMallService {
@RequiredArgsConstructor
public class MallServiceImpl extends MPJBaseServiceImpl<MallMapper, Mall> implements IMallService {
private final IEventRecordService eventRecordService;
private final Converter converter;
@Override
public Page<MallVO> list(MallDTO dto) {
Assert.notNull(dto.getAgentType(), "agentType 不能为空");
var wrapper = new MPJLambdaWrapper<>(converter.convert(dto, Mall.class))
.selectAll(Mall.class)
.selectAs(MAccount::getName, MallVO::getAccountName)
.leftJoin(MAccount.class, MAccount::getUid, Mall::getAccountUid)
.orderByDesc(Mall::getUpdateTime);
var mallVOPage = this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), MallVO.class, wrapper);
Opt.ofEmptyAble(mallVOPage.getRecords())
.ifPresent(r -> {
var mallUidList = r.stream().map(MallVO::getUid).toList();
// fixme {@link EventServiceImpl #51}
var eventRecWrapper = Wrappers.<EventRecord>query()
.select("DISTINCT on (mall_uid) *")
.in("mall_uid", mallUidList)
.orderByDesc("mall_uid", "create_time");
var eventRecordList = eventRecordService.list(eventRecWrapper);
var eventUid2SelfMap = eventRecordList.stream().collect(Collectors.toMap(EventRecord::getEventUid, Function.identity()));
r.forEach(tmp -> tmp.setEventRecord(eventUid2SelfMap.get(tmp.getUid())));
});
return mallVOPage;
}
@Override
public MallVO get(Long id) {
var wrapper = new MPJLambdaWrapper<Mall>()
.selectAll(Mall.class)
.selectAs(MAccount::getName, MallVO::getAccountName)
.leftJoin(MAccount.class, MAccount::getUid, Mall::getAccountUid)
.eq(Mall::getId, id);
return this.selectJoinOne(MallVO.class, wrapper);
}
}
package vion.service.monitor;
import com.baomidou.mybatisplus.extension.service.IService;
import com.github.yulichang.base.MPJBaseService;
import vion.model.monitor.AgentRecord;
/**
* @author vion
* @date 2024/10/31
*/
public interface IAgentRecordService extends IService<AgentRecord>{
public interface IAgentRecordService extends MPJBaseService<AgentRecord> {
}
......@@ -11,6 +11,7 @@ import vion.dto.monitor.OrgDTO;
import vion.model.monitor.*;
import vion.vo.monitor.AgentVO;
import java.time.LocalDateTime;
import java.util.List;
/**
......@@ -19,12 +20,15 @@ import java.util.List;
*/
public interface IAgentService extends MPJBaseService<Agent> {
// region Agent 页面
Page<AgentVO> list(AgentDTO dto);
AgentVO getVOById(Long id);
String update(AgentDTO dto);
String upgradeCommand(String uid, Long upgradeId);
List<ServiceInfo> getServicesByUid(String uid);
String saveServicesByUid(String uid, @RequestBody List<ServiceInfo> ServiceInfoList);
......@@ -35,10 +39,13 @@ public interface IAgentService extends MPJBaseService<Agent> {
String assign(String uid, List<ServiceInfo> serviceInfoList);
List<AgentRecord> getForm(String uid, LocalDateTime startTime, LocalDateTime endTime);
// endregion
// region Agent 主动发送信息
String reg(Agent agent);
Upgrade getUpgradeInfo(Short type);
Upgrade getUpgradeInfo(Long id);
String recAgentRecord(AgentRecord agentRecord);
......@@ -55,6 +62,10 @@ public interface IAgentService extends MPJBaseService<Agent> {
void disconnect(JsonNode disconnectInfo);
// endregion
// region 系统级别事件监控
void checkLicense();
// endregion
String getAgentEventTopic(String agentUid);
......
package vion.service.monitor;
import com.baomidou.mybatisplus.extension.service.IService;
import com.github.yulichang.base.MPJBaseService;
import vion.model.monitor.EventRecord;
/**
* @author vion
* @date 2024/10/31
*/
public interface IEventRecordService extends IService<EventRecord>{
public interface IEventRecordService extends MPJBaseService<EventRecord> {
}
package vion.service.monitor;
import com.baomidou.mybatisplus.extension.service.IService;
import com.github.yulichang.base.MPJBaseService;
import vion.model.monitor.MAccount;
/**
* @author vion
* @date 2024/10/31
*/
public interface IMAccountService extends IService<MAccount>{
public interface IMAccountService extends MPJBaseService<MAccount> {
}
package vion.service.monitor;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseService;
import vion.dto.monitor.MallDTO;
import vion.model.monitor.Mall;
/**
import vion.vo.monitor.MallVO;
/**
* @author vion
* @date 2024/10/31
*/
public interface IMallService extends IService<Mall>{
public interface IMallService extends MPJBaseService<Mall> {
Page<MallVO> list(MallDTO dto);
MallVO get(Long id);
}
......@@ -131,7 +131,7 @@ public class DingMod {
.put("field_filter_list", "sys00-name,sys00-mobile,sys00-mainDeptId,sys00-mainDept,sys01-employeeStatus");
var jsonNode = oDingRestClient.post()
.uri("/topapi/smartwork/hrm/employee/v2/list?access_token=" + accessToken)
.uri("/topapi/smartwork/hrm/employee/v2/list?access_token={accessToken}", accessToken)
.contentType(MediaType.APPLICATION_JSON)
.body(paramJson.toString())
.retrieve()
......@@ -185,7 +185,7 @@ public class DingMod {
// 2:试用期 3:正式 5:待离职 -1:无状态
Long value = deptIdList.get(idx++);
var jsonNode = oDingRestClient.post()
.uri("/topapi/v2/department/listsub?access_token=" + accessToken)
.uri("/topapi/v2/department/listsub?access_token={accessToken}", accessToken)
.contentType(MediaType.APPLICATION_JSON)
.body(JsonUtil.createObj().put("dept_id", value).toString())
.retrieve()
......@@ -223,7 +223,7 @@ public class DingMod {
public String workMsg(String msg) {
String token = getToken();
var res = oDingRestClient.post()
.uri("/topapi/message/corpconversation/asyncsend_v2?access_token=" + token)
.uri("/topapi/message/corpconversation/asyncsend_v2?access_token={accessToken}", token)
.contentType(MediaType.APPLICATION_JSON)
.body(msg)
.retrieve()
......@@ -268,7 +268,7 @@ public class DingMod {
.body(JsonNode.class);
var unionId = userInfoNode.path("unionId").asText();
var useridNode = oDingRestClient.post()
.uri("/topapi/user/getbyunionid?access_token=" + getToken())
.uri("/topapi/user/getbyunionid?access_token={1}", getToken())
.body(JsonUtil.createObj().put("unionid", unionId).toString())
.retrieve()
.body(JsonNode.class);
......@@ -311,7 +311,7 @@ public class DingMod {
var unionId = userInfoNode.path("user_info").path("unionid").asText();
var useridNode = oDingRestClient.post()
.uri("/topapi/user/getbyunionid?access_token=" + getToken())
.uri("/topapi/user/getbyunionid?access_token={1}", getToken())
.contentType(MediaType.APPLICATION_JSON)
.body(JsonUtil.createObj().put("unionid", unionId).toString())
.retrieve()
......@@ -375,7 +375,7 @@ public class DingMod {
var accessToken = accessTokenNode.path("access_token").asText();
var userInfoNode = oDingRestClient.post()
.uri("/topapi/v2/user/getuserinfo?access_token=" + accessToken)
.uri("/topapi/v2/user/getuserinfo?access_token={accessToken}", accessToken)
.contentType(MediaType.APPLICATION_JSON)
.body(JsonUtil.createObj().put("code", authCode).toString())
.retrieve()
......@@ -447,7 +447,7 @@ public class DingMod {
public String robotPush(String accessToken, String body) {
var res = oDingRestClient.post()
.uri("/robot/send?access_token=" + accessToken)
.uri("/robot/send?access_token={accessToken}", accessToken)
.contentType(MediaType.APPLICATION_JSON)
.body(body)
.retrieve()
......
......@@ -2,6 +2,7 @@ package vion.vo.monitor;
import lombok.Getter;
import lombok.Setter;
import vion.model.monitor.EventRecord;
import java.time.LocalDate;
import java.time.LocalDateTime;
......@@ -15,6 +16,11 @@ public class EventVO {
private Long id;
/**
* 类型 0:store+mall 1:store,2:mall
*/
private Short type;
/**
* 唯一标识
*/
private String uid;
......@@ -55,6 +61,11 @@ public class EventVO {
private Object rule;
/**
* 描述
*/
private String describe;
/**
* 备注
*/
private String remark;
......@@ -93,4 +104,6 @@ public class EventVO {
* 过期日期
*/
private LocalDate expire;
private EventRecord eventRecord;
}
\ No newline at end of file
package vion.vo.monitor;
import lombok.Getter;
import lombok.Setter;
import vion.model.monitor.EventRecord;
import java.time.LocalDateTime;
/**
* 项目mall信息
*/
@Getter
@Setter
public class MallVO {
private Long id;
/**
* agent uid
*/
private String agentUid;
/**
* agent类型 1:store,2:mall
*/
private Short agentType;
/**
* 所属集团uid
*/
private String accountUid;
private String accountName;
/**
* mall unid
*/
private String uid;
/**
* mall名称
*/
private String name;
/**
* mall营业状态
*/
private Boolean status;
/**
* 时区
*/
private String timeZone;
/**
* 备注
*/
private String remark;
private LocalDateTime createTime;
private LocalDateTime updateTime;
private EventRecord eventRecord;
}
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!