增加首页接口,心跳监控信息改为redis存储

This commit is contained in:
gaoyutao
2025-09-09 17:45:39 +08:00
parent 23bf338c8f
commit df7ed79fcb
17 changed files with 519 additions and 41 deletions

View File

@@ -3,6 +3,7 @@ package com.ruoyi.system.api;
import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.constant.ServiceNameConstants; import com.ruoyi.common.core.constant.ServiceNameConstants;
import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.api.domain.AllInterfaceNameRemote;
import com.ruoyi.system.api.domain.EpsInitialTrafficDataRemote; import com.ruoyi.system.api.domain.EpsInitialTrafficDataRemote;
import com.ruoyi.system.api.domain.InitialSwitchInfoDetailsRemote; import com.ruoyi.system.api.domain.InitialSwitchInfoDetailsRemote;
import com.ruoyi.system.api.domain.RmResourceRegistrationRemote; import com.ruoyi.system.api.domain.RmResourceRegistrationRemote;
@@ -37,4 +38,7 @@ public interface RemoteRevenueConfigService
@PostMapping("/registration/updateStatusByResource") @PostMapping("/registration/updateStatusByResource")
public R<String> updateStatusByResource(@RequestBody RmResourceRegistrationRemote queryParam, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); public R<String> updateStatusByResource(@RequestBody RmResourceRegistrationRemote queryParam, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
@PostMapping("/interfaceName/getMsgByClientId")
public R<AllInterfaceNameRemote> getMsgByClientId(@RequestBody AllInterfaceNameRemote queryParam, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
} }

View File

@@ -0,0 +1,77 @@
package com.ruoyi.system.api.domain;
import com.ruoyi.common.core.annotation.Excel;
import com.ruoyi.common.core.web.domain.BaseEntity;
import lombok.Data;
import java.util.Set;
/**
* 所有接口名称对象 all_interface_name
*
* @author gyt
* @date 2025-08-25
*/
@Data
public class AllInterfaceNameRemote extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键ID */
private Long id;
/** 客户端唯一标识 */
@Excel(name = "客户端唯一标识")
private String clientId;
/** 接口名称 */
@Excel(name = "接口名称")
private String interfaceName;
/** 设备序列号 */
@Excel(name = "设备序列号")
private String deviceSn;
/** 节点名称 */
@Excel(name = "节点名称")
private String nodeName;
/** 业务代码 */
@Excel(name = "业务代码")
private String businessCode;
/** 业务名称 */
@Excel(name = "业务名称")
private String businessName;
/** 资源类型 */
@Excel(name = "资源类型")
private String resourceType;
/** 交换机名称 */
@Excel(name = "交换机名称")
private String switchName;
/** 接口连接设备类型 */
@Excel(name = "接口连接设备类型")
private String interfaceDeviceType;
/** 服务器网口 */
@Excel(name = "服务器网口")
private String serverPort;
/** 交换机硬件SN */
@Excel(name = "交换机硬件SN")
private String switchSn;
/** 接口名称集合 */
private Set<String> interfaceNames;
/** 交换机ip */
@Excel(name = "交换机ip")
private String switchIp;
/** 服务器ip */
@Excel(name = "服务器ip")
private String serverIp;
}

View File

@@ -2,6 +2,7 @@ package com.ruoyi.system.api.factory;
import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.api.RemoteRevenueConfigService; import com.ruoyi.system.api.RemoteRevenueConfigService;
import com.ruoyi.system.api.domain.AllInterfaceNameRemote;
import com.ruoyi.system.api.domain.EpsInitialTrafficDataRemote; import com.ruoyi.system.api.domain.EpsInitialTrafficDataRemote;
import com.ruoyi.system.api.domain.InitialSwitchInfoDetailsRemote; import com.ruoyi.system.api.domain.InitialSwitchInfoDetailsRemote;
import com.ruoyi.system.api.domain.RmResourceRegistrationRemote; import com.ruoyi.system.api.domain.RmResourceRegistrationRemote;
@@ -40,6 +41,11 @@ public class RemoteRevenueConfigFallbackFactory implements FallbackFactory<Remot
public R<String> updateStatusByResource(RmResourceRegistrationRemote queryParam, String source) { public R<String> updateStatusByResource(RmResourceRegistrationRemote queryParam, String source) {
return R.fail("资源状态修改失败:" + throwable.getMessage()); return R.fail("资源状态修改失败:" + throwable.getMessage());
} }
@Override
public R<AllInterfaceNameRemote> getMsgByClientId(AllInterfaceNameRemote queryParam, String source) {
return R.fail("获取服务器信息失败:" + throwable.getMessage());
}
}; };
} }
} }

View File

@@ -1,6 +1,8 @@
package com.ruoyi.system.controller; package com.ruoyi.system.controller;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.security.annotation.InnerAuth;
import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.system.domain.AllInterfaceName; import com.ruoyi.system.domain.AllInterfaceName;
import com.ruoyi.system.service.IAllInterfaceNameService; import com.ruoyi.system.service.IAllInterfaceNameService;
@@ -35,5 +37,16 @@ public class AllInterfaceNameController extends BaseController
List<AllInterfaceName> list = allInterfaceNameService.selectAllInterfaceNameList(allInterfaceName); List<AllInterfaceName> list = allInterfaceNameService.selectAllInterfaceNameList(allInterfaceName);
return list; return list;
} }
/**
* 查询所有接口名称列表
*/
@InnerAuth
@PostMapping("/getMsgByClientId")
public R<AllInterfaceName> getMsgByClientId(@RequestBody AllInterfaceName allInterfaceName)
{
List<AllInterfaceName> list = allInterfaceNameService.selectAllInterfaceNameList(allInterfaceName);
AllInterfaceName allInterfaceName1 = list.isEmpty()?new AllInterfaceName():list.get(0);
return R.ok(allInterfaceName1);
}
} }

View File

@@ -0,0 +1,114 @@
package com.ruoyi.system.controller;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.system.domain.RmResourceRegistration;
import com.ruoyi.system.service.EpsInitialTrafficDataService;
import com.ruoyi.system.service.IEpsServerRevenueConfigService;
import com.ruoyi.system.service.IInitialSwitchInfoDetailsService;
import com.ruoyi.system.service.IRmResourceRegistrationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* 首页Controller
*
* @author gyt
* @date 2025-08-25
*/
@RestController
@RequestMapping("/screen")
public class ScreenController extends BaseController
{
@Autowired
private IEpsServerRevenueConfigService epsServerRevenueConfigService;
@Autowired
private IRmResourceRegistrationService rmResourceRegistrationService;
@Autowired
private EpsInitialTrafficDataService epsInitialTrafficDataService;
@Autowired
private IInitialSwitchInfoDetailsService initialSwitchInfoDetailsService;
/**
* 统计当前在线服务器的流量相关的业务数
* @return
*/
@RequiresPermissions("system:config:list")
@GetMapping("/countBusinessByTraffic")
public AjaxResult countBusinessByTraffic()
{
return success(epsServerRevenueConfigService.countBusinessByTraffic());
}
/**
* 服务器在线率
* @return
*/
@RequiresPermissions("system:config:list")
@GetMapping("/getServerOnlineRate")
public AjaxResult getServerOnlineRate()
{
return rmResourceRegistrationService.getServerOnlineRate();
}
/**
* 交换机在线数量
* @return
*/
@RequiresPermissions("system:config:list")
@GetMapping("/countSwitchNum")
public AjaxResult countSwitchNum()
{
RmResourceRegistration rmResourceRegistration = new RmResourceRegistration();
rmResourceRegistration.setResourceType("2");
// 查询资源列表处理可能的null结果
List<RmResourceRegistration> resourceList = Optional.ofNullable(rmResourceRegistrationService.selectRmResourceRegistrationList(rmResourceRegistration))
.orElse(Collections.emptyList());
int onlineCount = (int) resourceList.stream()
.filter(resource -> "1".equals(resource.getOnlineStatus()))
.count();
return AjaxResult.success()
.put("total", resourceList.size())
.put("onlineCount", onlineCount);
}
/**
* 当日业务的在线设备数量统计TOP5
* @return
*/
@RequiresPermissions("system:config:list")
@GetMapping("/countDeviceNumTop5")
public AjaxResult countDeviceNumTop5()
{
List<Map> maps = epsServerRevenueConfigService.countDeviceNumTop5();
return success(maps);
}
/**
* 当前在线服务器发送带宽总流量
* @return
*/
@RequiresPermissions("system:config:list")
@GetMapping("/sumTrafficByServer")
public AjaxResult sumTrafficByServer()
{
return success(epsInitialTrafficDataService.sumTrafficByServer());
}
/**
* 当前在线交换机接收带宽总流量
* @return
*/
@RequiresPermissions("system:config:list")
@GetMapping("/sumTrafficBySwitch")
public AjaxResult sumTrafficBySwitch()
{
return success(initialSwitchInfoDetailsService.sumTrafficBySwitch());
}
}

View File

@@ -79,4 +79,16 @@ public interface EpsServerRevenueConfigMapper
public Map getNodeMsgByIp(@Param("ipAddress") String ipAddress); public Map getNodeMsgByIp(@Param("ipAddress") String ipAddress);
int updateEpsServerRevenueConfigByServerSn(EpsServerRevenueConfig epsServerRevenueConfig); int updateEpsServerRevenueConfigByServerSn(EpsServerRevenueConfig epsServerRevenueConfig);
/**
* 当前在线服务器的流量相关的业务数
* @return
*/
Integer countBusinessByTraffic();
/**
* 当日业务的在线设备数量统计TOP5
* @return
*/
List<Map> countDeviceNumTop5();
} }

View File

@@ -3,6 +3,7 @@ package com.ruoyi.system.service;
import com.ruoyi.system.domain.EpsInitialTrafficData; import com.ruoyi.system.domain.EpsInitialTrafficData;
import com.ruoyi.system.domain.EpsNodeBandwidth; import com.ruoyi.system.domain.EpsNodeBandwidth;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
/** /**
@@ -55,4 +56,9 @@ public interface EpsInitialTrafficDataService {
*/ */
void recalculateServer95Bandwidth(EpsNodeBandwidth epsNodeBandwidth, String dailyStartTime, String dailyEndTime); void recalculateServer95Bandwidth(EpsNodeBandwidth epsNodeBandwidth, String dailyStartTime, String dailyEndTime);
/**
* 当前在线服务器发送带宽总流量
* @return
*/
BigDecimal sumTrafficByServer();
} }

View File

@@ -4,6 +4,7 @@ import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.domain.EpsServerRevenueConfig; import com.ruoyi.system.domain.EpsServerRevenueConfig;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 服务器收益方式配置Service接口 * 服务器收益方式配置Service接口
@@ -66,4 +67,14 @@ public interface IEpsServerRevenueConfigService
* @param epsServerRevenueConfig * @param epsServerRevenueConfig
*/ */
R<String> autoSaveServiceTrafficData(EpsServerRevenueConfig epsServerRevenueConfig); R<String> autoSaveServiceTrafficData(EpsServerRevenueConfig epsServerRevenueConfig);
/**
* 当前在线服务器的流量相关的业务数
* @return
*/
Integer countBusinessByTraffic();
/**
* 当日业务的在线设备数量统计TOP5
* @return
*/
List<Map> countDeviceNumTop5();
} }

View File

@@ -4,6 +4,7 @@ import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.domain.EpsNodeBandwidth; import com.ruoyi.system.domain.EpsNodeBandwidth;
import com.ruoyi.system.domain.InitialSwitchInfoDetails; import com.ruoyi.system.domain.InitialSwitchInfoDetails;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
/** /**
@@ -88,4 +89,9 @@ public interface IInitialSwitchInfoDetailsService
* @return * @return
*/ */
List<InitialSwitchInfoDetails> getRelevantSwitch(EpsNodeBandwidth epsNodeBandwidth, String dailyStartTime, String dailyEndTime); List<InitialSwitchInfoDetails> getRelevantSwitch(EpsNodeBandwidth epsNodeBandwidth, String dailyStartTime, String dailyEndTime);
/**
* 当前在线交换机接收带宽总流量
* @return
*/
BigDecimal sumTrafficBySwitch();
} }

View File

@@ -1,6 +1,7 @@
package com.ruoyi.system.service; package com.ruoyi.system.service;
import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.system.domain.RmResourceRegistration; import com.ruoyi.system.domain.RmResourceRegistration;
import java.util.List; import java.util.List;
@@ -85,4 +86,6 @@ public interface IRmResourceRegistrationService
* @return * @return
*/ */
R<String> updateStatusByResource(RmResourceRegistration rmResourceRegistration); R<String> updateStatusByResource(RmResourceRegistration rmResourceRegistration);
AjaxResult getServerOnlineRate();
} }

View File

@@ -17,7 +17,9 @@ import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -257,6 +259,38 @@ public class EpsInitialTrafficDataServiceImpl implements EpsInitialTrafficDataSe
} }
} }
/**
* 当前在线服务器发送带宽总流量
* @return
*/
@Override
public BigDecimal sumTrafficByServer() {
// 获取当前时间
LocalDateTime now = LocalDateTime.now();
// 结束时间
LocalDateTime endTime = now.minusSeconds(1);
// 开始时间
LocalDateTime startTime = now.minusMinutes(5);
// 定义日期时间格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 格式化为字符串
String dailyStartTime = startTime.format(formatter);
String dailyEndTime = endTime.format(formatter);
BigDecimal total = BigDecimal.ZERO;
EpsInitialTrafficData epsInitialTrafficData = new EpsInitialTrafficData();
epsInitialTrafficData.setStartTime(dailyStartTime);
epsInitialTrafficData.setEndTime(dailyEndTime);
List<EpsInitialTrafficData> dataList = query(epsInitialTrafficData);
if(!dataList.isEmpty()){
for (EpsInitialTrafficData initialTrafficData : dataList) {
// 服务器发送带宽流量
BigDecimal outSpeed = CalculateUtil.parseSpeedToMbps(initialTrafficData.getOutSpeed());
total = total.add(outSpeed);
}
}
return total.setScale(0, RoundingMode.HALF_UP);
}
/** /**
* 处理单个设备的带宽计算 * 处理单个设备的带宽计算
*/ */

View File

@@ -213,6 +213,23 @@ public class EpsServerRevenueConfigServiceImpl implements IEpsServerRevenueConfi
return R.fail("数据保存失败:" + e.getMessage()); return R.fail("数据保存失败:" + e.getMessage());
} }
} }
/**
* 当前在线服务器的流量相关的业务数
* @return
*/
@Override
public Integer countBusinessByTraffic() {
return epsServerRevenueConfigMapper.countBusinessByTraffic();
}
/**
* 当日业务的在线设备数量统计TOP5
* @return
*/
@Override
public List<Map> countDeviceNumTop5() {
return epsServerRevenueConfigMapper.countDeviceNumTop5();
}
private static String getNullableString(Map<String, Object> map, String key) { private static String getNullableString(Map<String, Object> map, String key) {
Object value = map.get(key); Object value = map.get(key);
return value != null ? value.toString() : null; return value != null ? value.toString() : null;

View File

@@ -16,6 +16,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@@ -342,8 +344,9 @@ public class InitialSwitchInfoDetailsServiceImpl implements IInitialSwitchInfoDe
List<BigDecimal> speedsInMbps = dataList.stream() List<BigDecimal> speedsInMbps = dataList.stream()
.map(data -> { .map(data -> {
// 根据 interfaceDeviceType 选择 inSpeed 或 outSpeed // 根据 interfaceDeviceType 选择 inSpeed 或 outSpeed
String speed = ("1".equals(data.getInterfaceDeviceType())) ? String speed = "1".equals(data.getInterfaceDeviceType())
data.getInSpeed() + "" : data.getOutSpeed() + ""; ? (data.getInSpeed() != null ? data.getInSpeed().toString() : BigDecimal.ZERO.toString())
: (data.getOutSpeed() != null ? data.getOutSpeed().toString() : BigDecimal.ZERO.toString());
// 如果 speed 是纯数字,补充单位 "B/S"Bytes/s // 如果 speed 是纯数字,补充单位 "B/S"Bytes/s
if (speed.matches("^\\d+(\\.\\d+)?$")) { if (speed.matches("^\\d+(\\.\\d+)?$")) {
speed += " B/S"; speed += " B/S";
@@ -388,6 +391,40 @@ public class InitialSwitchInfoDetailsServiceImpl implements IInitialSwitchInfoDe
return dataList; return dataList;
} }
@Override
public BigDecimal sumTrafficBySwitch() {
// 获取当前时间
LocalDateTime now = LocalDateTime.now();
// 结束时间
LocalDateTime endTime = now.minusSeconds(1);
// 开始时间
LocalDateTime startTime = now.minusMinutes(5);
// 定义日期时间格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 格式化为字符串
String dailyStartTime = startTime.format(formatter);
String dailyEndTime = endTime.format(formatter);
BigDecimal total = BigDecimal.ZERO;
InitialSwitchInfoDetails switchInfoDetails = new InitialSwitchInfoDetails();
switchInfoDetails.setStartTime(dailyStartTime);
switchInfoDetails.setEndTime(dailyEndTime);
List<InitialSwitchInfoDetails> dataList = initialSwitchInfoDetailsMapper
.selectInitialSwitchInfoDetailsList(switchInfoDetails);
if(!dataList.isEmpty()){
for (InitialSwitchInfoDetails initialSwitchInfoDetails : dataList) {
// 交换机接收带宽流量
String speed = initialSwitchInfoDetails.getInSpeed() != null ? initialSwitchInfoDetails.getInSpeed().toString() : BigDecimal.ZERO.toString();
// 如果 speed 是纯数字,补充单位 "B/S"Bytes/s
if (speed.matches("^\\d+(\\.\\d+)?$")) {
speed += " B/S";
}
BigDecimal inSpeed = CalculateUtil.parseSpeedToMbps(speed);
total = total.add(inSpeed);
}
}
return total.setScale(0, RoundingMode.HALF_UP);
}
/** /**
* 处理单个交换机的带宽计算 * 处理单个交换机的带宽计算
@@ -565,8 +602,10 @@ public class InitialSwitchInfoDetailsServiceImpl implements IInitialSwitchInfoDe
// 1. 提取并转换带宽值 // 1. 提取并转换带宽值
List<BigDecimal> speedsInMbps = dataList.stream() List<BigDecimal> speedsInMbps = dataList.stream()
.map(data -> { .map(data -> {
String speed = ("1".equals(data.getInterfaceDeviceType())) ? // 根据 interfaceDeviceType 选择 inSpeed 或 outSpeed
data.getInSpeed() + "" : data.getOutSpeed() + ""; String speed = "1".equals(data.getInterfaceDeviceType())
? (data.getInSpeed() != null ? data.getInSpeed().toString() : BigDecimal.ZERO.toString())
: (data.getOutSpeed() != null ? data.getOutSpeed().toString() : BigDecimal.ZERO.toString());
if (speed.matches("^\\d+(\\.\\d+)?$")) { if (speed.matches("^\\d+(\\.\\d+)?$")) {
speed += " B/S"; speed += " B/S";
} }

View File

@@ -2,6 +2,7 @@ package com.ruoyi.system.service.impl;
import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.DateUtils; import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.domain.EpsNodeBandwidth; import com.ruoyi.system.domain.EpsNodeBandwidth;
import com.ruoyi.system.domain.EpsServerRevenueConfig; import com.ruoyi.system.domain.EpsServerRevenueConfig;
@@ -15,6 +16,8 @@ import com.ruoyi.system.service.IRmResourceRegistrationService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -241,4 +244,41 @@ public class RmResourceRegistrationServiceImpl implements IRmResourceRegistratio
return R.ok("状态修改成功"); return R.ok("状态修改成功");
} }
/**
* 服务器在线率
* @return
*/
@Override
public AjaxResult getServerOnlineRate() {
// 查询所有符合条件的资源
RmResourceRegistration queryParam = new RmResourceRegistration();
queryParam.setResourceType("1");
List<RmResourceRegistration> resourceList = rmResourceRegistrationMapper.selectRmResourceRegistrationList(queryParam);
// 计算在线数量和总数
int totalCount = resourceList.size();
if (totalCount == 0) {
return AjaxResult.error("没有找到符合条件的资源");
}
int onlineCount = (int) resourceList.stream()
.filter(resource -> "1".equals(resource.getOnlineStatus()))
.count();
int offlineCount = (int) resourceList.stream()
.filter(resource -> "0".equals(resource.getOnlineStatus()))
.count();
// 计算在线率
BigDecimal onlineRate = BigDecimal.valueOf(onlineCount)
.divide(BigDecimal.valueOf(totalCount), 0, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
// 返回结果
return AjaxResult.success()
.put("onlineCount", onlineCount)
.put("offlineCount", offlineCount)
.put("total", totalCount)
.put("onlineRate", onlineRate);
}
} }

View File

@@ -152,4 +152,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectEpsServerRevenueConfigVo"/> <include refid="selectEpsServerRevenueConfigVo"/>
where hardware_sn = #{hardwareSn} where hardware_sn = #{hardwareSn}
</select> </select>
<select id="countBusinessByTraffic" resultType="java.lang.Integer">
select count(1) from eps_server_revenue_config a left join rm_resource_registration b on a.hardware_sn=b.hardware_sn where a.revenue_method = '1' and b.online_status='1'
</select>
<select id="countDeviceNumTop5" resultType="java.util.Map">
select count(1) total,a.business_name businessName from eps_server_revenue_config a left join rm_resource_registration b on a.hardware_sn=b.hardware_sn where a.revenue_method = '1' and b.online_status='1' group by a.business_name order by total desc limit 5
</select>
</mapper> </mapper>

View File

@@ -267,6 +267,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updaterId != null">updater_id = #{updaterId},</if> <if test="updaterId != null">updater_id = #{updaterId},</if>
<if test="updaterName != null">updater_name = #{updaterName},</if> <if test="updaterName != null">updater_name = #{updaterName},</if>
</trim> </trim>
where id = #{id} where ip_address = #{ipAddress}
</update> </update>
</mapper> </mapper>

View File

@@ -2,21 +2,26 @@ package com.ruoyi.rocketmq.consumer;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.DateUtils; import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.rocketmq.domain.*; import com.ruoyi.rocketmq.domain.*;
import com.ruoyi.rocketmq.enums.MessageCodeEnum; import com.ruoyi.rocketmq.enums.MessageCodeEnum;
import com.ruoyi.rocketmq.producer.ConsumeException; import com.ruoyi.rocketmq.producer.ConsumeException;
import com.ruoyi.rocketmq.service.*; import com.ruoyi.rocketmq.service.*;
import com.ruoyi.rocketmq.utils.JsonDataParser; import com.ruoyi.rocketmq.utils.JsonDataParser;
import com.ruoyi.system.api.RemoteRevenueConfigService; import com.ruoyi.system.api.RemoteRevenueConfigService;
import com.ruoyi.system.api.domain.AllInterfaceNameRemote;
import com.ruoyi.system.api.domain.EpsInitialTrafficDataRemote; import com.ruoyi.system.api.domain.EpsInitialTrafficDataRemote;
import com.ruoyi.system.api.domain.InitialSwitchInfoDetailsRemote; import com.ruoyi.system.api.domain.InitialSwitchInfoDetailsRemote;
import com.ruoyi.system.api.domain.RmResourceRegistrationRemote;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@@ -27,7 +32,7 @@ import java.math.RoundingMode;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -38,11 +43,15 @@ import java.util.stream.Collectors;
@Component @Component
public class RocketMsgListener implements MessageListenerConcurrently { public class RocketMsgListener implements MessageListenerConcurrently {
// 在类中添加以下成员变量来记录心跳状态 private static final String HEARTBEAT_STATUS_PREFIX = "heartbeat:status:";
private final Map<String, Integer> heartbeatStatusMap = new ConcurrentHashMap<>(); // 客户端ID -> 连续丢失心跳次数 private static final String HEARTBEAT_TIME_PREFIX = "heartbeat:time:";
private final Map<String, Long> lastHeartbeatTimeMap = new ConcurrentHashMap<>(); // 客户端ID -> 最后心跳时间 private static final String HEARTBEAT_ALERT_PREFIX = "heartbeat:alert:";
String HEARTBEAT_RECOVERY_COUNT_PREFIX = "heartbeat:recovery:count:";
private static final long HEARTBEAT_TIMEOUT = 180000; // 3分钟超时
@Autowired
private RedisTemplate<String, String> redisTemplate;
private final IInitialBandwidthTrafficService initialBandwidthTrafficService; private final IInitialBandwidthTrafficService initialBandwidthTrafficService;
private final RemoteRevenueConfigService remoteRevenueConfigService; private final RemoteRevenueConfigService remoteRevenueConfigService;
@Autowired @Autowired
@@ -396,26 +405,43 @@ public class RocketMsgListener implements MessageListenerConcurrently {
* @param message * @param message
*/ */
private void handleHeartbeatMessage(DeviceMessage message) { private void handleHeartbeatMessage(DeviceMessage message) {
try {
List<InitialHeartbeatListen> heartbeats = JsonDataParser.parseJsonData(message.getData(), InitialHeartbeatListen.class); List<InitialHeartbeatListen> heartbeats = JsonDataParser.parseJsonData(message.getData(), InitialHeartbeatListen.class);
if(!heartbeats.isEmpty()){ if(!heartbeats.isEmpty()){
InitialHeartbeatListen heartbeat = heartbeats.get(0); InitialHeartbeatListen heartbeat = heartbeats.get(0);
String clientId = message.getClientId(); String clientId = message.getClientId();
log.info("处理心跳消息客户端ID: {}, 时间: {}", clientId, heartbeat.getTimestamp()); log.info("处理心跳消息客户端ID: {}, 时间: {}", clientId, heartbeat.getTimestamp());
// 使用Redis存储状态
String statusKey = HEARTBEAT_STATUS_PREFIX + clientId;
String timeKey = HEARTBEAT_TIME_PREFIX + clientId;
String recoveryCountKey = HEARTBEAT_RECOVERY_COUNT_PREFIX + clientId; // 恢复次数计数器
try {
// 重置丢失计数为0设置最后心跳时间
redisTemplate.opsForValue().set(statusKey, "0");
redisTemplate.opsForValue().set(timeKey, String.valueOf(System.currentTimeMillis()));
// 更新心跳状态 // 检查是否之前有告警状态
heartbeatStatusMap.put(clientId, 0); // 重置为0表示收到心跳 if (Boolean.TRUE.equals(redisTemplate.hasKey(HEARTBEAT_ALERT_PREFIX + clientId))) {
lastHeartbeatTimeMap.put(clientId, System.currentTimeMillis()); // 获取当前恢复次数
String recoveryCountStr = redisTemplate.opsForValue().get(recoveryCountKey);
int recoveryCount = (recoveryCountStr == null) ? 1 : Integer.parseInt(recoveryCountStr) + 1;
// 检查是否之前有丢失心跳的情况 if (recoveryCount == 2) {
if (heartbeatStatusMap.getOrDefault(clientId, 0) > 0) { // 达到2次恢复执行状态修改
// 之前有丢失心跳,现在恢复了,记录恢复日志 log.warn("客户端ID: {} 心跳恢复达到2次修改设备状态为在线", clientId);
log.warn("客户端ID: {} 心跳恢复", clientId); insertHeartbeatLog(clientId, "2", "心跳恢复,设备在线状态改为在线");
insertHeartbeatLog(clientId, "2", "心跳恢复,服务器在线"); // 1表示恢复 redisTemplate.delete(HEARTBEAT_ALERT_PREFIX + clientId);
redisTemplate.delete(recoveryCountKey); // 清除恢复计数器
// 修改资源状态
getResourceMsg(clientId, "1");
} else {
// 未达到2次只记录恢复次数
log.info("客户端ID: {} 心跳恢复第{}次", clientId, recoveryCount);
redisTemplate.opsForValue().set(recoveryCountKey, String.valueOf(recoveryCount));
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("处理心跳消息异常", e); log.error("处理心跳消息异常, clientId: {}", clientId, e);
}
} }
} }
@@ -423,31 +449,94 @@ public class RocketMsgListener implements MessageListenerConcurrently {
@Scheduled(fixedRate = 60000) // 每分钟检查一次 @Scheduled(fixedRate = 60000) // 每分钟检查一次
public void checkHeartbeatStatus() { public void checkHeartbeatStatus() {
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
long heartbeatTimeout = 180000; // 3分钟无心跳认为丢失 // 获取所有客户端时间键
Set<String> timeKeys = redisTemplate.keys(HEARTBEAT_TIME_PREFIX + "*");
if (timeKeys == null) return;
for (Map.Entry<String, Long> entry : lastHeartbeatTimeMap.entrySet()) { for (String timeKey : timeKeys) {
String clientId = entry.getKey(); String clientId = timeKey.substring(HEARTBEAT_TIME_PREFIX.length());
long lastHeartbeatTime = entry.getValue(); String statusKey = HEARTBEAT_STATUS_PREFIX + clientId;
if (currentTime - lastHeartbeatTime > heartbeatTimeout) { try {
// 心跳超时 String lastTimeStr = redisTemplate.opsForValue().get(timeKey);
int lostCount = heartbeatStatusMap.getOrDefault(clientId, 0) + 1; if (lastTimeStr == null) continue;
heartbeatStatusMap.put(clientId, lostCount);
long lastHeartbeatTime = Long.parseLong(lastTimeStr);
if (currentTime - lastHeartbeatTime > HEARTBEAT_TIMEOUT) {
// 心跳超时处理
String lostCountStr = redisTemplate.opsForValue().get(statusKey);
int lostCount = (lostCountStr == null ? 0 : Integer.parseInt(lostCountStr)) + 1;
redisTemplate.opsForValue().set(statusKey, String.valueOf(lostCount));
log.warn("客户端ID: {} 心跳丢失,连续次数: {}", clientId, lostCount); log.warn("客户端ID: {} 心跳丢失,连续次数: {}", clientId, lostCount);
if (lostCount == 3) { if (lostCount == 3) {
// 两次获取不到心跳 insertHeartbeatLog(clientId, "3", "连续三次心跳丢失");
insertHeartbeatLog(clientId, "3", "连续三次心跳丢失,服务器离线"); redisTemplate.opsForValue().set(HEARTBEAT_ALERT_PREFIX + clientId, "1");
// 把资源注册表资源信息改为离线 // 修改资源状态
// RmResourceRegistrationRemote rmResourceRegistrationRemote = new RmResourceRegistrationRemote(); getResourceMsg(clientId, "0");
// rmResourceRegistrationRemote.setOnlineStatus("0");
// remoteRevenueConfigService.updateStatusByResource(rmResourceRegistrationRemote, SecurityConstants.INNER);
} }
} }
} catch (Exception e) {
log.error("检查心跳状态异常, clientId: {}", clientId, e);
}
} }
} }
/**
* 修改资源在线状态
* @param clientId
* @param status
*/
private void getResourceMsg(String clientId, String status){
String ipAddress = null;
AllInterfaceNameRemote interfaceNameRemote = new AllInterfaceNameRemote();
interfaceNameRemote.setClientId(clientId);
// 1. 先获取交换机IP
interfaceNameRemote.setResourceType("2");
R<AllInterfaceNameRemote> switchResult = remoteRevenueConfigService.getMsgByClientId(
interfaceNameRemote, SecurityConstants.INNER);
if (switchResult != null && switchResult.getData() != null &&
StringUtils.isNotEmpty(switchResult.getData().getSwitchIp())) {
// 更新交换机状态
ipAddress = switchResult.getData().getSwitchIp();
updateResourceStatus(ipAddress, status);
// 2. 再获取服务器IP
interfaceNameRemote.setResourceType("1");
R<AllInterfaceNameRemote> serverResult = remoteRevenueConfigService.getMsgByClientId(
interfaceNameRemote, SecurityConstants.INNER);
if (serverResult != null && serverResult.getData() != null &&
StringUtils.isNotEmpty(serverResult.getData().getServerIp())) {
// 更新服务器状态
updateResourceStatus(serverResult.getData().getServerIp(), status);
}
} else {
// 3. 如果没有交换机IP只获取服务器IP
interfaceNameRemote.setResourceType("1");
R<AllInterfaceNameRemote> serverResult = remoteRevenueConfigService.getMsgByClientId(
interfaceNameRemote, SecurityConstants.INNER);
if (serverResult != null && serverResult.getData() != null &&
StringUtils.isNotEmpty(serverResult.getData().getServerIp())) {
// 更新服务器状态
updateResourceStatus(serverResult.getData().getServerIp(), status);
} else {
log.warn("未找到客户端ID: {} 对应的IP地址", clientId);
}
}
}
// 更新资源状态的公共方法
private void updateResourceStatus(String ipAddress, String status) {
RmResourceRegistrationRemote rmResourceRegistrationRemote = new RmResourceRegistrationRemote();
rmResourceRegistrationRemote.setOnlineStatus(status);
rmResourceRegistrationRemote.setIpAddress(ipAddress);
remoteRevenueConfigService.updateStatusByResource(rmResourceRegistrationRemote, SecurityConstants.INNER);
}
// 插入心跳日志到数据库 // 插入心跳日志到数据库
private void insertHeartbeatLog(String machineId, String status, String remark) { private void insertHeartbeatLog(String machineId, String status, String remark) {
try { try {