1、增加磁盘HDD类型已用空间图形接口。
2、增加磁盘HDD类型总空间字段计算。 3、增加硬盘设备监控列表接口。
This commit is contained in:
+104
-33
@@ -53,7 +53,7 @@ public class EchartsDataUtils {
|
||||
return Math.round(microseconds / 1_000_000.0 * 100.0) / 100.0;
|
||||
}
|
||||
/**
|
||||
* 构建ECharts图表数据(带时间补全和特殊值处理)
|
||||
* 构建ECharts图表数据(带时间补全和特殊值处理)- 修复版本
|
||||
*/
|
||||
public static <T> Map<String, Object> buildEchartsDataAutoPadding(
|
||||
List<T> list,
|
||||
@@ -84,57 +84,64 @@ public class EchartsDataUtils {
|
||||
.sorted(Comparator.comparing(timeExtractor))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 自动检测时间间隔(用于数据期间)
|
||||
// 自动检测时间间隔
|
||||
long timeInterval = detectTimeInterval(sortedList, timeExtractor);
|
||||
|
||||
// 获取数据实际的时间范围
|
||||
Date actualStartTime = timeExtractor.apply(sortedList.get(0));
|
||||
Date actualEndTime = timeExtractor.apply(sortedList.get(sortedList.size() - 1));
|
||||
|
||||
// 计算稀疏间隔(用于数据期间外)
|
||||
// 计算稀疏间隔
|
||||
long totalTimeRange = endDate.getTime() - startDate.getTime();
|
||||
long sparseInterval = totalTimeRange > 12L * 30 * 24 * 60 * 60 * 1000 ?
|
||||
30L * 24 * 60 * 60 * 1000 : 2L * 24 * 60 * 60 * 1000;
|
||||
|
||||
// 生成三段时间序列
|
||||
// 生成完整的时间序列
|
||||
List<Date> fullTimeSeries = new ArrayList<>();
|
||||
|
||||
// 1. 开始时间到数据开始时间(稀疏间隔)
|
||||
if (startDate.before(actualStartTime)) {
|
||||
List<Date> beforeSeries = generateTimeSeries(startDate, actualStartTime, sparseInterval);
|
||||
List<Date> beforeSeries = generateSparseTimeSeries(startDate, actualStartTime, sparseInterval);
|
||||
fullTimeSeries.addAll(beforeSeries);
|
||||
}
|
||||
|
||||
// 2. 数据开始时间到数据结束时间(正常间隔)
|
||||
List<Date> dataSeries = generateTimeSeries(actualStartTime, actualEndTime, timeInterval);
|
||||
// 2. 数据开始时间到数据结束时间 - 以第一个数据点的时间为基准生成序列
|
||||
List<Date> dataSeries = generateTimeSeriesFromDataPoints(actualStartTime, actualEndTime,
|
||||
timeInterval, actualStartTime);
|
||||
fullTimeSeries.addAll(dataSeries);
|
||||
|
||||
// 3. 数据结束时间到结束时间(稀疏间隔)
|
||||
if (actualEndTime.before(endDate)) {
|
||||
// 调整actualEndTime的下一个点开始,避免重复
|
||||
// 从actualEndTime的下一个时间点开始
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(actualEndTime);
|
||||
cal.setTimeInMillis(cal.getTimeInMillis() + timeInterval);
|
||||
cal.add(Calendar.MILLISECOND, (int)timeInterval);
|
||||
Date nextAfterActualEnd = cal.getTime();
|
||||
|
||||
if (nextAfterActualEnd.before(endDate) || nextAfterActualEnd.equals(endDate)) {
|
||||
List<Date> afterSeries = generateTimeSeries(nextAfterActualEnd, endDate, sparseInterval);
|
||||
List<Date> afterSeries = generateSparseTimeSeries(nextAfterActualEnd, endDate, sparseInterval);
|
||||
fullTimeSeries.addAll(afterSeries);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建时间到数据的映射(考虑时间精度)
|
||||
Map<Long, T> timeDataMap = sortedList.stream()
|
||||
.collect(Collectors.toMap(
|
||||
item -> normalizeTime(timeExtractor.apply(item), timeInterval),
|
||||
Function.identity(),
|
||||
(a, b) -> a
|
||||
));
|
||||
// 去重并排序
|
||||
fullTimeSeries = fullTimeSeries.stream()
|
||||
.distinct()
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 创建时间到数据的映射
|
||||
Map<String, T> timeDataMap = new HashMap<>();
|
||||
for (T item : sortedList) {
|
||||
Date itemTime = timeExtractor.apply(item);
|
||||
String timeKey = parseDateToStr(itemTime);
|
||||
timeDataMap.put(timeKey, item);
|
||||
}
|
||||
|
||||
// 检测整个数据集中是否有真实数据
|
||||
boolean hasRealData = checkHasRealData(sortedList, dataExtractors);
|
||||
|
||||
// 特殊处理:查找percentile95的固定值
|
||||
// 查找特殊字段的固定值
|
||||
Object fixedPercentile95Value = findFixedValueForPercentile95(sortedList, dataExtractors);
|
||||
|
||||
// 准备X轴和Y轴数据
|
||||
@@ -145,19 +152,16 @@ public class EchartsDataUtils {
|
||||
dataExtractors.keySet().forEach(name ->
|
||||
yData.put(name, new ArrayList<>()));
|
||||
|
||||
// 记录当前处理的时间点索引
|
||||
int timeIndex = 0;
|
||||
|
||||
for (Date time : fullTimeSeries) {
|
||||
// X轴数据
|
||||
xAxisData.add(parseDateToStr(time));
|
||||
String timeStr = parseDateToStr(time);
|
||||
xAxisData.add(timeStr);
|
||||
|
||||
// 判断当前时间点是否在数据实际时间范围内
|
||||
boolean isInDataRange = !time.before(actualStartTime) && !time.after(actualEndTime);
|
||||
|
||||
// Y轴数据
|
||||
Long normalizedTime = normalizeTime(time, timeInterval);
|
||||
T item = timeDataMap.get(normalizedTime);
|
||||
// 查找对应的数据项
|
||||
T item = timeDataMap.get(timeStr);
|
||||
|
||||
for (Map.Entry<String, Function<T, ?>> entry : dataExtractors.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
@@ -169,20 +173,18 @@ public class EchartsDataUtils {
|
||||
if (item != null) {
|
||||
// 有真实数据
|
||||
Object value = extractor.apply(item);
|
||||
seriesData.add(value != null ? value : getDefaultValue(name, fixedPercentile95Value, timeIndex, hasRealData));
|
||||
seriesData.add(value != null ? value : null);
|
||||
} else {
|
||||
// 智能数据补全
|
||||
if (isInDataRange) {
|
||||
// 在数据时间范围内但该时间点无数据:使用智能补全策略
|
||||
seriesData.add(getDefaultValue(name, fixedPercentile95Value, timeIndex, hasRealData));
|
||||
// 在数据时间范围内但该时间点无数据(数据缺失点)
|
||||
seriesData.add(getDefaultValue(name, fixedPercentile95Value, xAxisData.size()-1, hasRealData));
|
||||
} else {
|
||||
// 在数据时间范围外(开始时间前或结束时间后):使用空数据补全策略
|
||||
seriesData.add(getEmptyDataDefaultValue(name, timeIndex));
|
||||
// 在数据时间范围外
|
||||
seriesData.add(getEmptyDataDefaultValue(name, xAxisData.size()-1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timeIndex++;
|
||||
}
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
@@ -191,12 +193,81 @@ public class EchartsDataUtils {
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
// 记录日志
|
||||
System.err.println("构建图表数据失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return createEmptyResult(dataExtractors.keySet(), startTime, endTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从第一个数据点开始生成时间序列
|
||||
*/
|
||||
private static List<Date> generateTimeSeriesFromDataPoints(Date start, Date end,
|
||||
long interval, Date firstDataPoint) {
|
||||
List<Date> timeSeries = new ArrayList<>();
|
||||
|
||||
if (interval <= 0) {
|
||||
interval = 300000L; // 默认5分钟
|
||||
}
|
||||
|
||||
// 使用第一个数据点的时间作为基准
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(firstDataPoint);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
// 从第一个数据点开始向前找,直到找到小于等于start的时间点
|
||||
while (calendar.getTime().after(start)) {
|
||||
calendar.add(Calendar.MILLISECOND, -(int)interval);
|
||||
}
|
||||
|
||||
// 如果当前位置在start之前,前进一个间隔
|
||||
if (calendar.getTime().before(start)) {
|
||||
calendar.add(Calendar.MILLISECOND, (int)interval);
|
||||
}
|
||||
|
||||
// 生成时间序列
|
||||
while (!calendar.getTime().after(end)) {
|
||||
timeSeries.add(calendar.getTime());
|
||||
calendar.add(Calendar.MILLISECOND, (int)interval);
|
||||
}
|
||||
|
||||
return timeSeries.stream()
|
||||
.distinct()
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成稀疏时间序列
|
||||
*/
|
||||
private static List<Date> generateSparseTimeSeries(Date start, Date end, long interval) {
|
||||
List<Date> timeSeries = new ArrayList<>();
|
||||
|
||||
if (interval <= 0) {
|
||||
interval = 2L * 24 * 60 * 60 * 1000; // 默认2天
|
||||
}
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(start);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
// 包含开始时间
|
||||
timeSeries.add(calendar.getTime());
|
||||
|
||||
while (true) {
|
||||
calendar.add(Calendar.MILLISECOND, (int)interval);
|
||||
if (calendar.getTime().after(end)) {
|
||||
break;
|
||||
}
|
||||
timeSeries.add(calendar.getTime());
|
||||
}
|
||||
|
||||
return timeSeries.stream()
|
||||
.distinct()
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取空数据默认值(用于数据时间范围外的点)
|
||||
*/
|
||||
|
||||
+35
@@ -383,4 +383,39 @@ public class SpeedUtils {
|
||||
if (mbitValue == null) return BigDecimal.ZERO;
|
||||
return mbitValue.multiply(new BigDecimal("1000000"));
|
||||
}
|
||||
public static String determineUnitByValue(Long value) {
|
||||
if (value == null || value == 0) {
|
||||
return "KB";
|
||||
}
|
||||
|
||||
// 注意:这里使用二进制单位(1024)
|
||||
if (value >= 1024L * 1024 * 1024 * 1024) { // >= 1TB
|
||||
return "TB";
|
||||
} else if (value >= 1024L * 1024 * 1024) { // >= 1GB
|
||||
return "GB";
|
||||
} else if (value >= 1024L * 1024) { // >= 1MB
|
||||
return "MB";
|
||||
} else {
|
||||
return "KB";
|
||||
}
|
||||
}
|
||||
// 工具方法:获取单位换算除数
|
||||
public static BigDecimal get1024Divisor(String unit) {
|
||||
switch (unit) {
|
||||
case "GB":
|
||||
case "Gb":
|
||||
return new BigDecimal(1024L * 1024 * 1024); // 1GB = 1024^3
|
||||
case "MB":
|
||||
case "Mb":
|
||||
return new BigDecimal(1024L * 1024); // 1MB = 1024^2
|
||||
case "KB":
|
||||
case "Kb":
|
||||
return new BigDecimal(1024); // 1KB = 1024
|
||||
case "TB":
|
||||
case "Tb":
|
||||
return new BigDecimal(1024L * 1024 * 1024 * 1024); // 1TB = 1024^4
|
||||
default:
|
||||
return new BigDecimal(1024); // 默认返回KB的除数
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user