From 19403c9a1770a8f3e0eda2ed1f54c399d6b2c3c6 Mon Sep 17 00:00:00 2001 From: xiepufeng <1072271977@qq.com> Date: Mon, 15 Apr 2024 14:54:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8C=87=E6=A0=87=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/constant/RedisKeyConstants.java | 5 + .../controller/DcDeviceController.java | 1 - .../controller/DcMetricsController.java | 192 ++++++++++++++++++ .../java/com/zc/business/domain/DcDevice.java | 5 + .../request/DcMessageAccessCountRequest.java | 58 ++++++ .../business/service/IDcMetricsService.java | 32 +++ .../service/impl/DcMetricsServiceImpl.java | 55 +++++ 7 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 zc-business/src/main/java/com/zc/business/controller/DcMetricsController.java create mode 100644 zc-business/src/main/java/com/zc/business/request/DcMessageAccessCountRequest.java create mode 100644 zc-business/src/main/java/com/zc/business/service/IDcMetricsService.java create mode 100644 zc-business/src/main/java/com/zc/business/service/impl/DcMetricsServiceImpl.java diff --git a/zc-business/src/main/java/com/zc/business/constant/RedisKeyConstants.java b/zc-business/src/main/java/com/zc/business/constant/RedisKeyConstants.java index 003a8ab5..96985260 100644 --- a/zc-business/src/main/java/com/zc/business/constant/RedisKeyConstants.java +++ b/zc-business/src/main/java/com/zc/business/constant/RedisKeyConstants.java @@ -29,4 +29,9 @@ public class RedisKeyConstants public static String getDcDevicesTrafficStatisticsKey(Byte direction) { return DC_DEVICES_TRAFFIC_STATISTICS + ":" + direction; } + + /** + * 监控物联服务器 + */ + public static final String MONITOR_IOT_SERVER = "monitor:iotServer:"; } diff --git a/zc-business/src/main/java/com/zc/business/controller/DcDeviceController.java b/zc-business/src/main/java/com/zc/business/controller/DcDeviceController.java index 9a4b4312..d3aed00c 100644 --- a/zc-business/src/main/java/com/zc/business/controller/DcDeviceController.java +++ b/zc-business/src/main/java/com/zc/business/controller/DcDeviceController.java @@ -366,7 +366,6 @@ public class DcDeviceController extends BaseController { OkHttp okHttp = new OkHttp(); - String string = JSON.toJSONString(props); JSONObject jsonObject = JSON.parseObject(string); RequestParams requestParams = new RequestParams(jsonObject); diff --git a/zc-business/src/main/java/com/zc/business/controller/DcMetricsController.java b/zc-business/src/main/java/com/zc/business/controller/DcMetricsController.java new file mode 100644 index 00000000..9185c987 --- /dev/null +++ b/zc-business/src/main/java/com/zc/business/controller/DcMetricsController.java @@ -0,0 +1,192 @@ +package com.zc.business.controller; + +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.redis.RedisCache; +import com.zc.business.request.DcMessageAccessCountRequest; +import com.zc.business.service.IDcMetricsService; +import com.zc.common.core.httpclient.OkHttp; +import com.zc.common.core.httpclient.exception.HttpException; +import com.zc.common.core.httpclient.request.RequestParams; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import okhttp3.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static com.zc.business.constant.RedisKeyConstants.MONITOR_IOT_SERVER; + +/** + * 指标数据 + * @author xiepufeng + */ +@Api(tags = "指标数据") +@RestController +@RequestMapping("/business/metrics") +public class DcMetricsController { + + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Resource + private IDcMetricsService dcMetricsService; + + @Value("${iot.address}") + private String iotAddress; + + @Resource + private RedisCache redisCache; + + /** + * 设备总数 + */ + @ApiOperation("设备总数") + @GetMapping("/device/count") + public AjaxResult deviceCount(){ + return AjaxResult.success(dcMetricsService.deviceCount()); + } + + /** + * 产品总数 + */ + @ApiOperation("产品总数") + @GetMapping("/product/count") + public AjaxResult productCount(){ + return AjaxResult.success(dcMetricsService.productCount()); + } + + /** + * 异常设备总数 + */ + @ApiOperation("异常设备总数") + @GetMapping("/device-abnormal/count") + public AjaxResult deviceAbnormalCount(){ + return AjaxResult.success(dcMetricsService.deviceAbnormalCount()); + } + + /** + * 获取消息接入总数 + * + * @param request 请求参数对象,包含消息接入的相关条件 + * @return 返回AjaxResult对象,其中包含消息接入总数 + * @throws HttpException 当HTTP请求发生错误时抛出 + * @throws IOException 当进行网络读写操作发生错误时抛出 + */ + @ApiOperation("接入数据总数") + @GetMapping("/message-access/count") + public AjaxResult messageAccessCount(@Validated DcMessageAccessCountRequest request) throws HttpException, IOException { + // 初始化OkHttp客户端 + OkHttp okHttp = new OkHttp(); + + // 将请求对象转换为JSON字符串 + String string = JSON.toJSONString(request); + JSONObject jsonObject = JSON.parseObject(string); + + jsonObject.put("direction", "received_message"); + + // 将JSON对象转换为请求参数 + RequestParams requestParams = new RequestParams(jsonObject); + + // 默认请求URL + String url = iotAddress + "/api/iot/metrics/device-gateway/message/count"; + + // 如果请求中包含产品ID,则修改请求URL + if (request.getProductId() != null) { + url = iotAddress + "/api/iot/metrics/device/message/count"; + } + + // 发起HTTP GET请求并获取响应 + Response response // 请求响应 + = okHttp + .url(url) // 设置请求地址 + .data(requestParams) // 设置请求参数 + .get(); // 执行GET请求 + // 将响应内容解析为AjaxResult对象并返回 + return JSON.parseObject(response.body().string(), AjaxResult.class); + } + + @ApiOperation("物联系统监控") + @GetMapping("/iot-server/monitor") + public AjaxResult iotServerMonitor() throws HttpException, IOException { + + OkHttp okHttp = new OkHttp(); + + String url = iotAddress + "/monitor/server"; + + Response response // 请求响应 + = okHttp + .url(url) // 请求地址 + .get(); // 请求方法 + return JSON.parseObject(response.body().string(), AjaxResult.class); + } + + /** + * 物联系统监控指标前天昨天数据查询 + * 该接口不接受任何参数,返回前天和昨天的物联系统监控指标数据。 + * + * @return AjaxResult 返回一个包含前天和昨天监控指标数据的列表,如果数据不存在,则返回错误信息。 + */ + @ApiOperation("物联系统监控指标前天昨天数据") + @GetMapping("/iot-server/monitor-previous") + public AjaxResult iotServerChain() { + // 从Redis缓存中获取昨天和前天的监控数据 + JSONObject yesterdayData = redisCache.getCacheObject(MONITOR_IOT_SERVER + DateUtil.formatDate(DateUtil.yesterday())); + JSONObject beforeYesterdayData = redisCache.getCacheObject(MONITOR_IOT_SERVER + DateUtil.formatDate(DateUtil.offsetDay(DateUtil.date(), -2))); + + // 如果昨天或前天的数据为空,则返回错误信息 + if (yesterdayData == null || beforeYesterdayData == null) { + return AjaxResult.error("暂无数据"); + } + + // 将数据放入列表并返回 + List dataList = new ArrayList<>(); + dataList.add(beforeYesterdayData); + dataList.add(yesterdayData); + return AjaxResult.success(dataList); + } + + + /** + * 定时缓存物联系统监控数据。 + * 该方法使用CRON表达式“0 0 0 * * ?”定时在每天的0点执行。 + * 方法不接受参数,也不返回任何值。 + * 主要步骤包括: + * 1. 构造缓存键值,基于监控数据和前一天的日期。 + * 2. 获取物联系统监控的详细数据。 + * 3. 设定缓存过期时间为3天。 + * 4. 将监控数据缓存起来。 + * 如果在执行过程中遇到HttpException或IOException,会记录错误日志。 + */ + @Scheduled(cron = "0 0 0 * * ?") + public void cacheIotServerMonitor() { + try { + // 构造缓存键,使用MONITOR_IOT_SERVER常量和前一天的日期 + String cacheKey = MONITOR_IOT_SERVER + DateUtil.formatDate(DateUtil.yesterday()); + // 获取监控数据中的"data"部分 + Object cacheValue = this.iotServerMonitor().get("data"); + // 设定缓存过期时间为3天 + Integer expireTime = 3; + + // 将监控数据缓存到Redis中,设定过期时间 + redisCache.setCacheObject(cacheKey, cacheValue, expireTime, TimeUnit.DAYS); + } catch (HttpException | IOException e) { + // 记录缓存失败的错误日志 + logger.error("缓存物联系统监控数据失败", e); + } + } + + +} diff --git a/zc-business/src/main/java/com/zc/business/domain/DcDevice.java b/zc-business/src/main/java/com/zc/business/domain/DcDevice.java index e19dbf00..ba999a9e 100644 --- a/zc-business/src/main/java/com/zc/business/domain/DcDevice.java +++ b/zc-business/src/main/java/com/zc/business/domain/DcDevice.java @@ -17,6 +17,11 @@ public class DcDevice { public static final Integer UNUSEDSTATE = 0; public static final Integer USEOFSTATE = 1; + // 异常的 + public static final String ABNORMAL = "0"; + // 正常的 + public static final String NORMAL = "1"; + // 离线状态 public static final String OFFLINE = "0"; // 在线状态 diff --git a/zc-business/src/main/java/com/zc/business/request/DcMessageAccessCountRequest.java b/zc-business/src/main/java/com/zc/business/request/DcMessageAccessCountRequest.java new file mode 100644 index 00000000..0cc56eea --- /dev/null +++ b/zc-business/src/main/java/com/zc/business/request/DcMessageAccessCountRequest.java @@ -0,0 +1,58 @@ +package com.zc.business.request; + +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.util.Date; + +@Data +public class DcMessageAccessCountRequest { + + // 年、月、日、小时,用于定义时间周期类型 + public static final String YEAR = "year"; + public static final String MONTH = "month"; + public static final String DAY = "day"; + public static final String HOUR = "hour"; + + @NotNull(message = "开始时间不能为空") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private String startTime; + + // 查询结束时间 + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @NotNull(message = "结束时间不能为空") + private String endTime; + + // 时间周期类型(年、月、日、小时) + private String periodType; + + private String productId; + + /** + * 根据给定的周期类型字符串,将其转换为简写的字符串表示。 + * @return 对应的简写字符串,比如"1y"、"1m"等。 + * @throws IllegalArgumentException 如果传入的periodType不是预期的值或为null。 + */ + public String convertPeriodType() throws IllegalArgumentException { + // 检查输入参数是否为null或空字符串 + if (periodType == null || periodType.isEmpty()) { + throw new IllegalArgumentException("periodType不能为null或空"); + } + + // 使用switch语句处理不同的周期类型 + switch (periodType) { + case YEAR: + return "1y"; + case MONTH: + return "1M"; + case DAY: + return "1d"; + case HOUR: + return "1h"; + default: + // 对于未预期的输入值,抛出异常 + throw new IllegalArgumentException("不受支持的 periodType: " + periodType); + } + } +} diff --git a/zc-business/src/main/java/com/zc/business/service/IDcMetricsService.java b/zc-business/src/main/java/com/zc/business/service/IDcMetricsService.java new file mode 100644 index 00000000..9135a3e2 --- /dev/null +++ b/zc-business/src/main/java/com/zc/business/service/IDcMetricsService.java @@ -0,0 +1,32 @@ +package com.zc.business.service; + + +/** + * DcMetricsService 接口定义了与指标相关的服务操作。 + */ +public interface IDcMetricsService { + + /** + * 获取设备数量。 + * + * @return 设备数量,返回类型为整数。 + */ + int deviceCount(); + + + /** + * 获取产品数量。 + * 该方法用于统计当前系统中的产品总数,不需要传入任何参数。 + * + * @return 产品数量,返回类型为整数。 + */ + int productCount(); + + /** + * 获取设备异常数量 + * 该方法用于统计当前系统中的异常设备总数,不需要传入任何参数。 + * + * @return 返回设备异常数量,类型为int。 + */ + int deviceAbnormalCount(); +} diff --git a/zc-business/src/main/java/com/zc/business/service/impl/DcMetricsServiceImpl.java b/zc-business/src/main/java/com/zc/business/service/impl/DcMetricsServiceImpl.java new file mode 100644 index 00000000..784725af --- /dev/null +++ b/zc-business/src/main/java/com/zc/business/service/impl/DcMetricsServiceImpl.java @@ -0,0 +1,55 @@ +package com.zc.business.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zc.business.domain.DcDevice; +import com.zc.business.service.IDcMetricsService; +import com.zc.business.service.IDcDeviceService; +import com.zc.business.service.IDcProductService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +@Service +public class DcMetricsServiceImpl implements IDcMetricsService { + + @Resource + private IDcDeviceService dcDeviceService; + + @Resource + private IDcProductService dcProductService; + + + /** + * 获取设备数量。 + * + * @return 设备数量,返回类型为整数。 + */ + @Override + public int deviceCount() { + return dcDeviceService.count(); + } + + /** + * 获取产品数量。 + * 该方法用于统计当前系统中的产品总数,不需要传入任何参数。 + * + * @return 产品数量,返回类型为整数。 + */ + @Override + public int productCount() { + return dcProductService.count(); + } + + /** + * 获取设备异常数量 + * 该方法用于统计当前系统中的异常设备总数,不需要传入任何参数。 + * + * @return 返回设备异常数量,类型为int。 + */ + @Override + public int deviceAbnormalCount() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(DcDevice::getDeviceState, DcDevice.ABNORMAL); + return dcDeviceService.count(queryWrapper); + } +}