diff --git a/src/main/java/com/bigdata/controller/AppTrafficController.java b/src/main/java/com/bigdata/controller/AppTrafficController.java index 2a71232..ce6fd3a 100644 --- a/src/main/java/com/bigdata/controller/AppTrafficController.java +++ b/src/main/java/com/bigdata/controller/AppTrafficController.java @@ -31,7 +31,7 @@ public class AppTrafficController { if (request == null) { request = new AppTrafficQueryRequest(); } - + String operator = null; String networkType = null; String appName = null; @@ -41,7 +41,7 @@ public class AppTrafficController { Double maxDownloadTraffic = null; String startDate = null; String endDate = null; - + // 处理运营商参数:ALL 或不传表示查询所有 if (request.getOperator() != null && !request.getOperator().trim().isEmpty()) { String op = request.getOperator().trim().toUpperCase(); @@ -49,17 +49,17 @@ public class AppTrafficController { operator = op; } } - + // 处理网络制式 if (request.getNetworkType() != null && !request.getNetworkType().trim().isEmpty()) { networkType = request.getNetworkType().trim(); } - + // 处理APP名称 if (request.getAppName() != null && !request.getAppName().trim().isEmpty()) { appName = request.getAppName().trim(); } - + // 处理上传流量范围 if (request.getMinUploadTraffic() != null) { minUploadTraffic = request.getMinUploadTraffic(); @@ -67,7 +67,7 @@ public class AppTrafficController { if (request.getMaxUploadTraffic() != null) { maxUploadTraffic = request.getMaxUploadTraffic(); } - + // 处理下载流量范围 if (request.getMinDownloadTraffic() != null) { minDownloadTraffic = request.getMinDownloadTraffic(); @@ -75,7 +75,7 @@ public class AppTrafficController { if (request.getMaxDownloadTraffic() != null) { maxDownloadTraffic = request.getMaxDownloadTraffic(); } - + // 处理日期范围:将 yyyy-MM-dd 格式转换为 yyyyMMdd if (request.getStartDate() != null && !request.getStartDate().trim().isEmpty()) { startDate = request.getStartDate().trim().replace("-", ""); @@ -83,29 +83,29 @@ public class AppTrafficController { if (request.getEndDate() != null && !request.getEndDate().trim().isEmpty()) { endDate = request.getEndDate().trim().replace("-", ""); } - + // 按条件查询 List list = appTrafficService.getByCondition( operator, networkType, appName, minUploadTraffic, maxUploadTraffic, minDownloadTraffic, maxDownloadTraffic, startDate, endDate); - + // 打印到控制台 System.out.println("====== app_traffic query ======"); System.out.println("Operator: " + (operator != null ? operator : "ALL")); System.out.println("Network Type: " + (networkType != null ? networkType : "ALL")); System.out.println("APP Name: " + (appName != null ? appName : "ALL")); - System.out.println("Upload Traffic Range: " + - (minUploadTraffic != null ? minUploadTraffic : "MIN") + " ~ " + - (maxUploadTraffic != null ? maxUploadTraffic : "MAX")); - System.out.println("Download Traffic Range: " + - (minDownloadTraffic != null ? minDownloadTraffic : "MIN") + " ~ " + - (maxDownloadTraffic != null ? maxDownloadTraffic : "MAX")); + System.out.println("Upload Traffic Range: " + + (minUploadTraffic != null ? minUploadTraffic : "MIN") + " ~ " + + (maxUploadTraffic != null ? maxUploadTraffic : "MAX")); + System.out.println("Download Traffic Range: " + + (minDownloadTraffic != null ? minDownloadTraffic : "MIN") + " ~ " + + (maxDownloadTraffic != null ? maxDownloadTraffic : "MAX")); System.out.println("Start Date: " + (startDate != null ? startDate : "ALL")); System.out.println("End Date: " + (endDate != null ? endDate : "ALL")); System.out.println("Total records: " + list.size()); System.out.println("================================================"); - + return list; } @@ -120,11 +120,11 @@ public class AppTrafficController { if (request == null) { request = new AppTrafficQueryRequest(); } - + String operator = null; String startDate = null; String endDate = null; - + // 处理运营商参数:ALL 或不传表示查询所有 if (request.getOperator() != null && !request.getOperator().trim().isEmpty()) { String op = request.getOperator().trim().toUpperCase(); @@ -132,7 +132,7 @@ public class AppTrafficController { operator = op; } } - + // 处理日期范围:将 yyyy-MM-dd 格式转换为 yyyyMMdd if (request.getStartDate() != null && !request.getStartDate().trim().isEmpty()) { startDate = request.getStartDate().trim().replace("-", ""); @@ -140,10 +140,10 @@ public class AppTrafficController { if (request.getEndDate() != null && !request.getEndDate().trim().isEmpty()) { endDate = request.getEndDate().trim().replace("-", ""); } - + // 查询流量占比统计 List result = appTrafficService.getAppTrafficRatio(operator, startDate, endDate); - + // 打印到控制台 System.out.println("====== app_traffic ratio statistics ======"); System.out.println("Operator: " + (operator != null ? operator : "ALL")); @@ -151,15 +151,15 @@ public class AppTrafficController { System.out.println("End Date: " + (endDate != null ? endDate : "ALL")); System.out.println("Total apps: " + result.size()); for (AppTrafficRatioDTO dto : result) { - System.out.println("APP: " + dto.getAppName() + - " (" + dto.getPackageName() + ")" + - ", Operator: " + dto.getOperator() + - ", Total Traffic: " + dto.getTotalTraffic() + - ", Ratio: " + dto.getTrafficRatio() + "%" + - ", Records: " + dto.getRecordCount()); + System.out.println("APP: " + dto.getAppName() + + " (" + dto.getPackageName() + ")" + + ", Operator: " + dto.getOperator() + + ", Total Traffic: " + dto.getTotalTraffic() + + ", Ratio: " + dto.getTrafficRatio() + "%" + + ", Records: " + dto.getRecordCount()); } System.out.println("================================================"); - + return result; } @@ -175,7 +175,7 @@ public class AppTrafficController { if (request == null) { request = new com.bigdata.dto.AppTrafficTimeSeriesRequest(); } - + String operator = null; String networkType = null; Double minUploadTraffic = null; @@ -185,7 +185,7 @@ public class AppTrafficController { String timeGranularity = "DAY"; // 默认按天 String startDate = null; String endDate = null; - + // 处理运营商参数:ALL 或不传表示查询所有 if (request.getOperator() != null && !request.getOperator().trim().isEmpty()) { String op = request.getOperator().trim().toUpperCase(); @@ -193,12 +193,12 @@ public class AppTrafficController { operator = op; } } - + // 处理网络制式 if (request.getNetworkType() != null && !request.getNetworkType().trim().isEmpty()) { networkType = request.getNetworkType().trim(); } - + // 处理流量范围 if (request.getMinUploadTraffic() != null) { minUploadTraffic = request.getMinUploadTraffic(); @@ -212,12 +212,12 @@ public class AppTrafficController { if (request.getMaxDownloadTraffic() != null) { maxDownloadTraffic = request.getMaxDownloadTraffic(); } - + // 处理时间粒度 if (request.getTimeGranularity() != null && !request.getTimeGranularity().trim().isEmpty()) { timeGranularity = request.getTimeGranularity().trim().toUpperCase(); } - + // 处理日期范围:将 yyyy-MM-dd 格式转换为 yyyyMMdd if (request.getStartDate() != null && !request.getStartDate().trim().isEmpty()) { startDate = request.getStartDate().trim().replace("-", ""); @@ -225,15 +225,15 @@ public class AppTrafficController { if (request.getEndDate() != null && !request.getEndDate().trim().isEmpty()) { endDate = request.getEndDate().trim().replace("-", ""); } - + // 查询时间序列数据 - List result = + List result = appTrafficService.getAppTrafficTimeSeries( operator, networkType, minUploadTraffic, maxUploadTraffic, minDownloadTraffic, maxDownloadTraffic, timeGranularity, startDate, endDate); - + // 打印到控制台 System.out.println("====== app_traffic time series ======"); System.out.println("Operator: " + (operator != null ? operator : "ALL")); @@ -243,7 +243,7 @@ public class AppTrafficController { System.out.println("End Date: " + (endDate != null ? endDate : "ALL")); System.out.println("Total records: " + result.size()); System.out.println("================================================"); - + return result; } @@ -259,7 +259,7 @@ public class AppTrafficController { if (request == null) { request = new com.bigdata.dto.AppTrafficUsageRequest(); } - + String operator = null; String networkType = null; String landmark = null; @@ -269,7 +269,7 @@ public class AppTrafficController { Double maxDownloadTraffic = null; String startDate = null; String endDate = null; - + // 处理运营商参数:ALL 或不传表示查询所有 if (request.getOperator() != null && !request.getOperator().trim().isEmpty()) { String op = request.getOperator().trim().toUpperCase(); @@ -277,17 +277,17 @@ public class AppTrafficController { operator = op; } } - + // 处理网络制式 if (request.getNetworkType() != null && !request.getNetworkType().trim().isEmpty()) { networkType = request.getNetworkType().trim(); } - + // 处理典型地标 if (request.getLandmark() != null && !request.getLandmark().trim().isEmpty()) { landmark = request.getLandmark().trim(); } - + // 处理流量范围 if (request.getMinUploadTraffic() != null) { minUploadTraffic = request.getMinUploadTraffic(); @@ -301,7 +301,7 @@ public class AppTrafficController { if (request.getMaxDownloadTraffic() != null) { maxDownloadTraffic = request.getMaxDownloadTraffic(); } - + // 处理日期范围:将 yyyy-MM-dd 格式转换为 yyyyMMdd if (request.getStartDate() != null && !request.getStartDate().trim().isEmpty()) { startDate = request.getStartDate().trim().replace("-", ""); @@ -309,40 +309,40 @@ public class AppTrafficController { if (request.getEndDate() != null && !request.getEndDate().trim().isEmpty()) { endDate = request.getEndDate().trim().replace("-", ""); } - + // 查询流量使用情况统计 - List result = + List result = appTrafficService.getAppTrafficUsage( operator, networkType, landmark, minUploadTraffic, maxUploadTraffic, minDownloadTraffic, maxDownloadTraffic, startDate, endDate); - + // 打印到控制台 System.out.println("====== app_traffic usage statistics ======"); System.out.println("Operator: " + (operator != null ? operator : "ALL")); System.out.println("Network Type: " + (networkType != null ? networkType : "ALL")); System.out.println("Landmark: " + (landmark != null ? landmark : "ALL")); - System.out.println("Upload Traffic Range: " + - (minUploadTraffic != null ? minUploadTraffic : "MIN") + " ~ " + - (maxUploadTraffic != null ? maxUploadTraffic : "MAX")); - System.out.println("Download Traffic Range: " + - (minDownloadTraffic != null ? minDownloadTraffic : "MIN") + " ~ " + - (maxDownloadTraffic != null ? maxDownloadTraffic : "MAX")); + System.out.println("Upload Traffic Range: " + + (minUploadTraffic != null ? minUploadTraffic : "MIN") + " ~ " + + (maxUploadTraffic != null ? maxUploadTraffic : "MAX")); + System.out.println("Download Traffic Range: " + + (minDownloadTraffic != null ? minDownloadTraffic : "MIN") + " ~ " + + (maxDownloadTraffic != null ? maxDownloadTraffic : "MAX")); System.out.println("Start Date: " + (startDate != null ? startDate : "ALL")); System.out.println("End Date: " + (endDate != null ? endDate : "ALL")); System.out.println("Total apps: " + result.size()); for (com.bigdata.dto.AppTrafficUsageDTO dto : result) { - System.out.println("APP: " + dto.getAppName() + - " (" + dto.getPackageName() + ")" + - ", Operator: " + dto.getOperator() + - ", Network: " + dto.getNetworkType() + - ", Landmark: " + dto.getLandmark() + - ", Total Traffic: " + dto.getTotalTraffic() + - ", Records: " + dto.getRecordCount()); + System.out.println("APP: " + dto.getAppName() + + " (" + dto.getPackageName() + ")" + + ", Operator: " + dto.getOperator() + + ", Network: " + dto.getNetworkType() + + ", Landmark: " + dto.getLandmark() + + ", Total Traffic: " + dto.getTotalTraffic() + + ", Records: " + dto.getRecordCount()); } System.out.println("================================================"); - + return result; } @@ -359,26 +359,26 @@ public class AppTrafficController { if (request == null) { request = new com.bigdata.dto.AppTrafficRegionTopRequest(); } - + // 查询区域top1 APP List result = appTrafficService.getRegionTopApp(request); - + // 打印到控制台 System.out.println("====== app_traffic region top1 statistics ======"); System.out.println("Operator: " + (request.getOperator() != null ? request.getOperator() : "ALL")); System.out.println("Network Type: " + (request.getNetworkType() != null ? request.getNetworkType() : "ALL")); System.out.println("Start Date: " + (request.getStartDate() != null ? request.getStartDate() : "ALL")); System.out.println("End Date: " + (request.getEndDate() != null ? request.getEndDate() : "ALL")); - System.out.println("Grid: " + request.getGridRows() + "x" + request.getGridCols() + " = " + - (request.getGridRows() * request.getGridCols()) + " regions"); + System.out.println("Grid: " + request.getGridRows() + "x" + request.getGridCols() + " = " + + (request.getGridRows() * request.getGridCols()) + " regions"); System.out.println("Total regions with data: " + result.size()); for (com.bigdata.dto.AppTrafficRegionTopDTO dto : result) { - System.out.println("Region [" + dto.getRowIndex() + "," + dto.getColIndex() + - "] (" + dto.getCenterLat() + "," + dto.getCenterLon() + - ") Top1: " + dto.getAppName() + - " (" + dto.getPackageName() + ")" + - ", Traffic: " + dto.getTotalTraffic() + - ", Records: " + dto.getRecordCount()); + System.out.println("Region [" + dto.getRowIndex() + "," + dto.getColIndex() + + "] (" + dto.getCenterLat() + "," + dto.getCenterLon() + + ") Top1: " + dto.getAppName() + + " (" + dto.getPackageName() + ")" + + ", Traffic: " + dto.getTotalTraffic() + + ", Records: " + dto.getRecordCount()); } System.out.println("================================================"); @@ -733,7 +733,359 @@ public class AppTrafficController { ", Records: " + dto.getRecordCount()); } System.out.println("================================================"); - + + return result; + } + + /** + * 统计各手机网络质量使用情况,支持按运营商、网络制式、流量范围和日期范围筛选 + * @param request 查询请求参数,所有字段均为可选 + * @return 手机网络质量使用情况统计列表,按总流量降序排列 + */ + @PostMapping("/appTraffic/phoneQuality") + public List getPhoneQualityUsage( + @RequestBody(required = false) com.bigdata.dto.PhoneQualityUsageRequest request) { + // 如果请求体为空,创建默认请求对象 + if (request == null) { + request = new com.bigdata.dto.PhoneQualityUsageRequest(); + } + + String operator = null; + String networkType = null; + Double minUploadTraffic = null; + Double maxUploadTraffic = null; + Double minDownloadTraffic = null; + Double maxDownloadTraffic = null; + String startDate = null; + String endDate = null; + + // 处理运营商参数:ALL 或不传表示查询所有 + if (request.getOperator() != null && !request.getOperator().trim().isEmpty()) { + String op = request.getOperator().trim().toUpperCase(); + if (!"ALL".equals(op)) { + operator = op; + } + } + + // 处理网络制式 + if (request.getNetworkType() != null && !request.getNetworkType().trim().isEmpty()) { + networkType = request.getNetworkType().trim(); + } + + // 处理流量范围 + if (request.getMinUploadTraffic() != null) { + minUploadTraffic = request.getMinUploadTraffic(); + } + if (request.getMaxUploadTraffic() != null) { + maxUploadTraffic = request.getMaxUploadTraffic(); + } + if (request.getMinDownloadTraffic() != null) { + minDownloadTraffic = request.getMinDownloadTraffic(); + } + if (request.getMaxDownloadTraffic() != null) { + maxDownloadTraffic = request.getMaxDownloadTraffic(); + } + + // 处理日期范围:将 yyyy-MM-dd 格式转换为 yyyyMMdd + if (request.getStartDate() != null && !request.getStartDate().trim().isEmpty()) { + startDate = request.getStartDate().trim().replace("-", ""); + } + if (request.getEndDate() != null && !request.getEndDate().trim().isEmpty()) { + endDate = request.getEndDate().trim().replace("-", ""); + } + + // 查询手机网络质量使用情况统计 + List result = + appTrafficService.getPhoneQualityUsage( + operator, networkType, + minUploadTraffic, maxUploadTraffic, + minDownloadTraffic, maxDownloadTraffic, + startDate, endDate); + + // 打印到控制台 + System.out.println("====== app_traffic phone quality statistics ======"); + System.out.println("Operator: " + (operator != null ? operator : "ALL")); + System.out.println("Network Type: " + (networkType != null ? networkType : "ALL")); + System.out.println("Upload Traffic Range: " + + (minUploadTraffic != null ? minUploadTraffic : "MIN") + " ~ " + + (maxUploadTraffic != null ? maxUploadTraffic : "MAX")); + System.out.println("Download Traffic Range: " + + (minDownloadTraffic != null ? minDownloadTraffic : "MIN") + " ~ " + + (maxDownloadTraffic != null ? maxDownloadTraffic : "MAX")); + System.out.println("Start Date: " + (startDate != null ? startDate : "ALL")); + System.out.println("End Date: " + (endDate != null ? endDate : "ALL")); + System.out.println("Total phones: " + result.size()); + for (com.bigdata.dto.PhoneQualityUsageDTO dto : result) { + System.out.println("Phone: " + dto.getPhoneModel() + + ", OS: " + dto.getOs() + + ", OS Version: " + dto.getOsVersion() + + ", Operator: " + dto.getOperator() + + ", Total Traffic: " + dto.getTotalTraffic() + + ", Records: " + dto.getRecordCount()); + } + System.out.println("================================================"); + + return result; + } + + /** + * 统计各手机流量占比,支持按运营商、网络制式、流量范围和日期范围筛选 + * @param request 查询请求参数,所有字段均为可选 + * @return 手机流量占比统计列表,按总流量降序排列 + */ + @PostMapping("/appTraffic/phoneTrafficRatio") + public List getPhoneTrafficRatio( + @RequestBody(required = false) AppTrafficQueryRequest request) { + // 如果请求体为空,创建默认请求对象 + if (request == null) { + request = new AppTrafficQueryRequest(); + } + + String operator = null; + String networkType = null; + Double minUploadTraffic = null; + Double maxUploadTraffic = null; + Double minDownloadTraffic = null; + Double maxDownloadTraffic = null; + String startDate = null; + String endDate = null; + + // 处理运营商参数:ALL 或不传表示查询所有 + if (request.getOperator() != null && !request.getOperator().trim().isEmpty()) { + String op = request.getOperator().trim().toUpperCase(); + if (!"ALL".equals(op)) { + operator = op; + } + } + + // 处理网络制式 + if (request.getNetworkType() != null && !request.getNetworkType().trim().isEmpty()) { + networkType = request.getNetworkType().trim(); + } + + // 处理流量范围 + if (request.getMinUploadTraffic() != null) { + minUploadTraffic = request.getMinUploadTraffic(); + } + if (request.getMaxUploadTraffic() != null) { + maxUploadTraffic = request.getMaxUploadTraffic(); + } + if (request.getMinDownloadTraffic() != null) { + minDownloadTraffic = request.getMinDownloadTraffic(); + } + if (request.getMaxDownloadTraffic() != null) { + maxDownloadTraffic = request.getMaxDownloadTraffic(); + } + + // 处理日期范围:将 yyyy-MM-dd 格式转换为 yyyyMMdd + if (request.getStartDate() != null && !request.getStartDate().trim().isEmpty()) { + startDate = request.getStartDate().trim().replace("-", ""); + } + if (request.getEndDate() != null && !request.getEndDate().trim().isEmpty()) { + endDate = request.getEndDate().trim().replace("-", ""); + } + + // 查询手机流量占比统计 + List result = + appTrafficService.getPhoneTrafficRatio( + operator, networkType, + minUploadTraffic, maxUploadTraffic, + minDownloadTraffic, maxDownloadTraffic, + startDate, endDate); + + // 打印到控制台 + System.out.println("====== app_traffic phone traffic ratio statistics ======"); + System.out.println("Operator: " + (operator != null ? operator : "ALL")); + System.out.println("Network Type: " + (networkType != null ? networkType : "ALL")); + System.out.println("Upload Traffic Range: " + + (minUploadTraffic != null ? minUploadTraffic : "MIN") + " ~ " + + (maxUploadTraffic != null ? maxUploadTraffic : "MAX")); + System.out.println("Download Traffic Range: " + + (minDownloadTraffic != null ? minDownloadTraffic : "MIN") + " ~ " + + (maxDownloadTraffic != null ? maxDownloadTraffic : "MAX")); + System.out.println("Start Date: " + (startDate != null ? startDate : "ALL")); + System.out.println("End Date: " + (endDate != null ? endDate : "ALL")); + System.out.println("Total phones: " + result.size()); + for (com.bigdata.dto.PhoneTrafficRatioDTO dto : result) { + System.out.println("Phone: " + dto.getPhoneModel() + + ", OS: " + dto.getOs() + + ", OS Version: " + dto.getOsVersion() + + ", Operator: " + dto.getOperator() + + ", Total Traffic: " + dto.getTotalTraffic() + + ", Ratio: " + dto.getTrafficRatio() + "%" + + ", Records: " + dto.getRecordCount()); + } + System.out.println("================================================"); + + return result; + } + + /** + * 统计各操作系统流量占比,支持按运营商、网络制式、流量范围和日期范围筛选 + * @param request 查询请求参数,所有字段均为可选 + * @return 操作系统流量占比统计列表,按总流量降序排列 + */ + @PostMapping("/appTraffic/osTrafficRatio") + public List getOsTrafficRatio( + @RequestBody(required = false) AppTrafficQueryRequest request) { + // 如果请求体为空,创建默认请求对象 + if (request == null) { + request = new AppTrafficQueryRequest(); + } + + String operator = null; + String networkType = null; + Double minUploadTraffic = null; + Double maxUploadTraffic = null; + Double minDownloadTraffic = null; + Double maxDownloadTraffic = null; + String startDate = null; + String endDate = null; + + // 处理运营商参数:ALL 或不传表示查询所有 + if (request.getOperator() != null && !request.getOperator().trim().isEmpty()) { + String op = request.getOperator().trim().toUpperCase(); + if (!"ALL".equals(op)) { + operator = op; + } + } + + // 处理网络制式 + if (request.getNetworkType() != null && !request.getNetworkType().trim().isEmpty()) { + networkType = request.getNetworkType().trim(); + } + + // 处理流量范围 + if (request.getMinUploadTraffic() != null) { + minUploadTraffic = request.getMinUploadTraffic(); + } + if (request.getMaxUploadTraffic() != null) { + maxUploadTraffic = request.getMaxUploadTraffic(); + } + if (request.getMinDownloadTraffic() != null) { + minDownloadTraffic = request.getMinDownloadTraffic(); + } + if (request.getMaxDownloadTraffic() != null) { + maxDownloadTraffic = request.getMaxDownloadTraffic(); + } + + // 处理日期范围:将 yyyy-MM-dd 格式转换为 yyyyMMdd + if (request.getStartDate() != null && !request.getStartDate().trim().isEmpty()) { + startDate = request.getStartDate().trim().replace("-", ""); + } + if (request.getEndDate() != null && !request.getEndDate().trim().isEmpty()) { + endDate = request.getEndDate().trim().replace("-", ""); + } + + // 查询操作系统流量占比统计 + List result = + appTrafficService.getOsTrafficRatio( + operator, networkType, + minUploadTraffic, maxUploadTraffic, + minDownloadTraffic, maxDownloadTraffic, + startDate, endDate); + + // 打印到控制台 + System.out.println("====== app_traffic os traffic ratio statistics ======"); + System.out.println("Operator: " + (operator != null ? operator : "ALL")); + System.out.println("Network Type: " + (networkType != null ? networkType : "ALL")); + System.out.println("Upload Traffic Range: " + + (minUploadTraffic != null ? minUploadTraffic : "MIN") + " ~ " + + (maxUploadTraffic != null ? maxUploadTraffic : "MAX")); + System.out.println("Download Traffic Range: " + + (minDownloadTraffic != null ? minDownloadTraffic : "MIN") + " ~ " + + (maxDownloadTraffic != null ? maxDownloadTraffic : "MAX")); + System.out.println("Start Date: " + (startDate != null ? startDate : "ALL")); + System.out.println("End Date: " + (endDate != null ? endDate : "ALL")); + System.out.println("Total OS: " + result.size()); + for (com.bigdata.dto.OsTrafficRatioDTO dto : result) { + System.out.println("OS: " + dto.getOsName() + + ", OS: " + dto.getOs() + + ", OS Version: " + dto.getOsVersion() + + ", Operator: " + dto.getOperator() + + ", Total Traffic: " + dto.getTotalTraffic() + + ", Ratio: " + dto.getTrafficRatio() + "%" + + ", Records: " + dto.getRecordCount()); + } + System.out.println("================================================"); + + return result; + } + + /** + * 统计可视区域内每个区域的流量top1 热门手机 + * 将可视区域划分为300个矩形(20x15),返回每个区域的top1 热门手机 + * @param request 查询请求参数,包含运营商、网络制式、流量范围、日期范围、可视区域范围等 + * @return 各区域的top1 热门手机统计列表 + */ + @PostMapping("/appTraffic/phoneRegionTop") + public List getPhoneRegionTop( + @RequestBody(required = false) com.bigdata.dto.PhoneTrafficRegionTopRequest request) { + // 如果请求体为空,创建默认请求对象 + if (request == null) { + request = new com.bigdata.dto.PhoneTrafficRegionTopRequest(); + } + + // 查询区域top1 热门手机 + List result = appTrafficService.getPhoneRegionTop(request); + + // 打印到控制台 + System.out.println("====== app_traffic phone region top1 statistics ======"); + System.out.println("Operator: " + (request.getOperator() != null ? request.getOperator() : "ALL")); + System.out.println("Network Type: " + (request.getNetworkType() != null ? request.getNetworkType() : "ALL")); + System.out.println("Start Date: " + (request.getStartDate() != null ? request.getStartDate() : "ALL")); + System.out.println("End Date: " + (request.getEndDate() != null ? request.getEndDate() : "ALL")); + System.out.println("Grid: " + request.getGridRows() + "x" + request.getGridCols() + " = " + + (request.getGridRows() * request.getGridCols()) + " regions"); + System.out.println("Total regions with data: " + result.size()); + for (com.bigdata.dto.PhoneTrafficRegionTopDTO dto : result) { + System.out.println("Region [" + dto.getRowIndex() + "," + dto.getColIndex() + + "] (" + dto.getCenterLat() + "," + dto.getCenterLon() + + ") Top1: " + dto.getPhoneModel() + + " (OS: " + dto.getOs() + ", Version: " + dto.getOsVersion() + ")" + + ", Traffic: " + dto.getTotalTraffic() + + ", Records: " + dto.getRecordCount()); + } + System.out.println("================================================"); + + return result; + } + + /** + * 统计可视区域内每个区域的流量top1 手机OS + * 将可视区域划分为300个矩形(20x15),返回每个区域的top1 手机OS + * @param request 查询请求参数,包含运营商、网络制式、流量范围、日期范围、可视区域范围等 + * @return 各区域的top1 手机OS统计列表 + */ + @PostMapping("/appTraffic/osRegionTop") + public List getOsRegionTop( + @RequestBody(required = false) com.bigdata.dto.OsTrafficRegionTopRequest request) { + // 如果请求体为空,创建默认请求对象 + if (request == null) { + request = new com.bigdata.dto.OsTrafficRegionTopRequest(); + } + + // 查询区域top1 手机OS + List result = appTrafficService.getOsRegionTop(request); + + // 打印到控制台 + System.out.println("====== app_traffic OS region top1 statistics ======"); + System.out.println("Operator: " + (request.getOperator() != null ? request.getOperator() : "ALL")); + System.out.println("Network Type: " + (request.getNetworkType() != null ? request.getNetworkType() : "ALL")); + System.out.println("Start Date: " + (request.getStartDate() != null ? request.getStartDate() : "ALL")); + System.out.println("End Date: " + (request.getEndDate() != null ? request.getEndDate() : "ALL")); + System.out.println("Grid: " + request.getGridRows() + "x" + request.getGridCols() + " = " + + (request.getGridRows() * request.getGridCols()) + " regions"); + System.out.println("Total regions with data: " + result.size()); + for (com.bigdata.dto.OsTrafficRegionTopDTO dto : result) { + System.out.println("Region [" + dto.getRowIndex() + "," + dto.getColIndex() + + "] (" + dto.getCenterLat() + "," + dto.getCenterLon() + + ") Top1: " + dto.getOsName() + + ", Traffic: " + dto.getTotalTraffic() + + ", Records: " + dto.getRecordCount()); + } + System.out.println("================================================"); + return result; } } diff --git a/src/main/java/com/bigdata/service/impl/AppTrafficServiceImpl.java b/src/main/java/com/bigdata/service/impl/AppTrafficServiceImpl.java index 1db5c34..33f9326 100644 --- a/src/main/java/com/bigdata/service/impl/AppTrafficServiceImpl.java +++ b/src/main/java/com/bigdata/service/impl/AppTrafficServiceImpl.java @@ -20,14 +20,14 @@ public class AppTrafficServiceImpl implements AppTrafficService { @Override public List getByCondition(String operator, - String networkType, - String appName, - Double minUploadTraffic, - Double maxUploadTraffic, - Double minDownloadTraffic, - Double maxDownloadTraffic, - String startDate, - String endDate) { + String networkType, + String appName, + Double minUploadTraffic, + Double maxUploadTraffic, + Double minDownloadTraffic, + Double maxDownloadTraffic, + String startDate, + String endDate) { return appTrafficMapper.selectByCondition(operator, networkType, appName, minUploadTraffic, maxUploadTraffic, minDownloadTraffic, maxDownloadTraffic, startDate, endDate); @@ -36,12 +36,12 @@ public class AppTrafficServiceImpl implements AppTrafficService { @Override public List getAppTrafficRatio(String operator, String startDate, String endDate) { List result = appTrafficMapper.selectAppTrafficRatio(operator, startDate, endDate); - + // 计算总流量,用于计算占比 double totalTrafficSum = result.stream() .mapToDouble(dto -> dto.getTotalTraffic() != null ? dto.getTotalTraffic() : 0.0) .sum(); - + // 计算每个APP的流量占比 if (totalTrafficSum > 0) { for (AppTrafficRatioDTO dto : result) { @@ -53,7 +53,7 @@ public class AppTrafficServiceImpl implements AppTrafficService { } } } - + return result; } @@ -68,15 +68,15 @@ public class AppTrafficServiceImpl implements AppTrafficService { String timeGranularity, String startDate, String endDate) { - + // 查询时间序列数据(按appName聚合,不区分packageName) - List result = + List result = appTrafficMapper.selectAppTrafficTimeSeries( operator, networkType, minUploadTraffic, maxUploadTraffic, minDownloadTraffic, maxDownloadTraffic, timeGranularity, startDate, endDate); - + // 先计算每个APP的总流量(跨所有时间粒度) java.util.Map appTotalTrafficMap = new java.util.HashMap<>(); for (com.bigdata.dto.AppTrafficTimeSeriesDTO dto : result) { @@ -85,30 +85,30 @@ public class AppTrafficServiceImpl implements AppTrafficService { Double dtoTotal = dto.getTotalTraffic() != null ? dto.getTotalTraffic() : 0.0; appTotalTrafficMap.put(key, currentTotal + dtoTotal); } - + // 按APP总流量降序排序,然后按时间粒度排序 result.sort((a, b) -> { String keyA = a.getAppName() + "|" + a.getOperator(); String keyB = b.getAppName() + "|" + b.getOperator(); Double totalA = appTotalTrafficMap.getOrDefault(keyA, 0.0); Double totalB = appTotalTrafficMap.getOrDefault(keyB, 0.0); - + // 先按APP总流量降序排序 int compare = totalB.compareTo(totalA); if (compare != 0) { return compare; } - + // 如果总流量相同,按APP名称排序 int nameCompare = a.getAppName().compareTo(b.getAppName()); if (nameCompare != 0) { return nameCompare; } - + // 如果APP名称也相同,按时间粒度排序 return a.getTimeGranularity().compareTo(b.getTimeGranularity()); }); - + return result; } @@ -219,6 +219,95 @@ public class AppTrafficServiceImpl implements AppTrafficService { return result; } + @Override + public List getPhoneQualityUsage( + String operator, + String networkType, + Double minUploadTraffic, + Double maxUploadTraffic, + Double minDownloadTraffic, + Double maxDownloadTraffic, + String startDate, + String endDate) { + return appTrafficMapper.selectPhoneQualityUsage( + operator, networkType, + minUploadTraffic, maxUploadTraffic, + minDownloadTraffic, maxDownloadTraffic, + startDate, endDate); + } + + @Override + public List getPhoneTrafficRatio( + String operator, + String networkType, + Double minUploadTraffic, + Double maxUploadTraffic, + Double minDownloadTraffic, + Double maxDownloadTraffic, + String startDate, + String endDate) { + List result = appTrafficMapper.selectPhoneTrafficRatio( + operator, networkType, + minUploadTraffic, maxUploadTraffic, + minDownloadTraffic, maxDownloadTraffic, + startDate, endDate); + + // 计算总流量,用于计算占比 + double totalTrafficSum = result.stream() + .mapToDouble(dto -> dto.getTotalTraffic() != null ? dto.getTotalTraffic() : 0.0) + .sum(); + + // 计算每个手机的流量占比 + if (totalTrafficSum > 0) { + for (com.bigdata.dto.PhoneTrafficRatioDTO dto : result) { + if (dto.getTotalTraffic() != null && dto.getTotalTraffic() > 0) { + double ratio = (dto.getTotalTraffic() / totalTrafficSum) * 100.0; + dto.setTrafficRatio(Math.round(ratio * 100.0) / 100.0); // 保留2位小数 + } else { + dto.setTrafficRatio(0.0); + } + } + } + + return result; + } + + @Override + public List getOsTrafficRatio( + String operator, + String networkType, + Double minUploadTraffic, + Double maxUploadTraffic, + Double minDownloadTraffic, + Double maxDownloadTraffic, + String startDate, + String endDate) { + List result = appTrafficMapper.selectOsTrafficRatio( + operator, networkType, + minUploadTraffic, maxUploadTraffic, + minDownloadTraffic, maxDownloadTraffic, + startDate, endDate); + + // 计算总流量,用于计算占比 + double totalTrafficSum = result.stream() + .mapToDouble(dto -> dto.getTotalTraffic() != null ? dto.getTotalTraffic() : 0.0) + .sum(); + + // 计算每个操作系统的流量占比 + if (totalTrafficSum > 0) { + for (com.bigdata.dto.OsTrafficRatioDTO dto : result) { + if (dto.getTotalTraffic() != null && dto.getTotalTraffic() > 0) { + double ratio = (dto.getTotalTraffic() / totalTrafficSum) * 100.0; + dto.setTrafficRatio(Math.round(ratio * 100.0) / 100.0); // 保留2位小数 + } else { + dto.setTrafficRatio(0.0); + } + } + } + + return result; + } + @Override public List getRegionTopApp(AppTrafficRegionTopRequest request) { // 1. 准备查询参数 @@ -226,13 +315,13 @@ public class AppTrafficServiceImpl implements AppTrafficService { if (request.getOperator() != null && !request.getOperator().trim().isEmpty() && !"ALL".equals(request.getOperator().trim().toUpperCase())) { operator = request.getOperator().trim().toUpperCase(); } - + String networkType = request.getNetworkType(); Double minTraffic = request.getMinTraffic(); Double maxTraffic = request.getMaxTraffic(); String startDate = request.getStartDate() != null ? request.getStartDate().replace("-", "") : null; String endDate = request.getEndDate() != null ? request.getEndDate().replace("-", "") : null; - + // 计算流量范围(总流量 = 上传 + 下载) Double minUploadTraffic = null; Double maxUploadTraffic = null; @@ -246,29 +335,29 @@ public class AppTrafficServiceImpl implements AppTrafficService { maxUploadTraffic = maxTraffic / 2.0; maxDownloadTraffic = maxTraffic / 2.0; } - + // 2. 查询数据 List dataList = appTrafficMapper.selectByCondition( operator, networkType, null, minUploadTraffic, maxUploadTraffic, minDownloadTraffic, maxDownloadTraffic, startDate, endDate); - + if (dataList == null || dataList.isEmpty()) { return new ArrayList<>(); } - + // 3. 确定可视区域范围 Double minLon = request.getMinLon(); Double maxLon = request.getMaxLon(); Double minLat = request.getMinLat(); Double maxLat = request.getMaxLat(); - + if (minLon == null || maxLon == null || minLat == null || maxLat == null) { // 如果没有指定范围,从数据中计算 List validLons = new ArrayList<>(); List validLats = new ArrayList<>(); - + for (AppTraffic traffic : dataList) { try { if (traffic.getUserLon() != null && !traffic.getUserLon().trim().isEmpty()) { @@ -281,17 +370,17 @@ public class AppTrafficServiceImpl implements AppTrafficService { // 忽略无效的经纬度数据 } } - + // 如果没有有效的经纬度数据,返回空列表 if (validLons.isEmpty() || validLats.isEmpty()) { return new ArrayList<>(); } - + minLon = validLons.stream().mapToDouble(Double::doubleValue).min().orElse(116.0); maxLon = validLons.stream().mapToDouble(Double::doubleValue).max().orElse(117.0); minLat = validLats.stream().mapToDouble(Double::doubleValue).min().orElse(39.0); maxLat = validLats.stream().mapToDouble(Double::doubleValue).max().orElse(40.0); - + // 如果范围太小,扩展一点 if (maxLon - minLon < 0.001) { double centerLon = (minLon + maxLon) / 2.0; @@ -304,92 +393,92 @@ public class AppTrafficServiceImpl implements AppTrafficService { maxLat = centerLat + 0.01; } } - + // 4. 网格参数 int gridRows = request.getGridRows() != null ? request.getGridRows() : 20; int gridCols = request.getGridCols() != null ? request.getGridCols() : 15; - + // 确保范围有效 if (maxLon <= minLon || maxLat <= minLat) { return new ArrayList<>(); } - + double lonStep = (maxLon - minLon) / gridCols; double latStep = (maxLat - minLat) / gridRows; - + // 确保步长不为0 if (lonStep <= 0 || latStep <= 0) { return new ArrayList<>(); } - + // 5. 按区域分组统计 Map> regionAppTrafficMap = new HashMap<>(); Map regionRecordCountMap = new HashMap<>(); - + for (AppTraffic traffic : dataList) { if (traffic.getUserLon() == null || traffic.getUserLon().trim().isEmpty() || - traffic.getUserLat() == null || traffic.getUserLat().trim().isEmpty()) { + traffic.getUserLat() == null || traffic.getUserLat().trim().isEmpty()) { continue; } - + try { double lon = Double.parseDouble(traffic.getUserLon()); double lat = Double.parseDouble(traffic.getUserLat()); - + // 检查是否在可视区域内 if (lon < minLon || lon > maxLon || lat < minLat || lat > maxLat) { continue; } - + // 计算所属区域 int colIndex = Math.min((int) ((lon - minLon) / lonStep), gridCols - 1); int rowIndex = Math.min((int) ((lat - minLat) / latStep), gridRows - 1); - + String regionKey = rowIndex + "_" + colIndex; - String appKey = (traffic.getAppName() != null ? traffic.getAppName() : "Unknown") + - "|" + (traffic.getPackageName() != null ? traffic.getPackageName() : ""); - + String appKey = (traffic.getAppName() != null ? traffic.getAppName() : "Unknown") + + "|" + (traffic.getPackageName() != null ? traffic.getPackageName() : ""); + // 计算总流量 double totalTraffic = (traffic.getUploadTraffic() != null ? traffic.getUploadTraffic() : 0.0) + - (traffic.getDownloadTraffic() != null ? traffic.getDownloadTraffic() : 0.0); - + (traffic.getDownloadTraffic() != null ? traffic.getDownloadTraffic() : 0.0); + // 累计流量 regionAppTrafficMap.computeIfAbsent(regionKey, k -> new HashMap<>()) .merge(appKey, totalTraffic, Double::sum); - + regionRecordCountMap.merge(regionKey, 1L, Long::sum); } catch (NumberFormatException e) { // 忽略无效的经纬度数据 continue; } } - + // 6. 找出每个区域的top1 APP List result = new ArrayList<>(); - + for (int row = 0; row < gridRows; row++) { for (int col = 0; col < gridCols; col++) { String regionKey = row + "_" + col; Map appTrafficMap = regionAppTrafficMap.get(regionKey); - + if (appTrafficMap == null || appTrafficMap.isEmpty()) { continue; // 该区域没有数据,跳过 } - + // 找出流量最大的APP Map.Entry topApp = appTrafficMap.entrySet().stream() .max(Map.Entry.comparingByValue()) .orElse(null); - + if (topApp != null) { String[] appInfo = topApp.getKey().split("\\|"); String appName = appInfo[0]; String packageName = appInfo.length > 1 ? appInfo[1] : ""; - + // 计算区域中心点 double centerLon = minLon + (col + 0.5) * lonStep; double centerLat = minLat + (row + 0.5) * latStep; - + AppTrafficRegionTopDTO dto = new AppTrafficRegionTopDTO(); dto.setRowIndex(row); dto.setColIndex(col); @@ -399,7 +488,386 @@ public class AppTrafficServiceImpl implements AppTrafficService { dto.setPackageName(packageName); dto.setTotalTraffic(topApp.getValue()); dto.setRecordCount(regionRecordCountMap.getOrDefault(regionKey, 0L)); - + + result.add(dto); + } + } + } + + return result; + } + + @Override + public List getPhoneRegionTop(com.bigdata.dto.PhoneTrafficRegionTopRequest request) { + // 1. 准备查询参数 + String operator = null; + if (request.getOperator() != null && !request.getOperator().trim().isEmpty() && !"ALL".equals(request.getOperator().trim().toUpperCase())) { + operator = request.getOperator().trim().toUpperCase(); + } + + String networkType = request.getNetworkType(); + Double minUploadTraffic = request.getMinUploadTraffic(); + Double maxUploadTraffic = request.getMaxUploadTraffic(); + Double minDownloadTraffic = request.getMinDownloadTraffic(); + Double maxDownloadTraffic = request.getMaxDownloadTraffic(); + String startDate = request.getStartDate() != null ? request.getStartDate().replace("-", "") : null; + String endDate = request.getEndDate() != null ? request.getEndDate().replace("-", "") : null; + + // 2. 查询数据 + List dataList = appTrafficMapper.selectByCondition( + operator, networkType, null, + minUploadTraffic, maxUploadTraffic, + minDownloadTraffic, maxDownloadTraffic, + startDate, endDate); + + if (dataList == null || dataList.isEmpty()) { + return new ArrayList<>(); + } + + // 3. 确定可视区域范围 + Double minLon = request.getMinLon(); + Double maxLon = request.getMaxLon(); + Double minLat = request.getMinLat(); + Double maxLat = request.getMaxLat(); + + if (minLon == null || maxLon == null || minLat == null || maxLat == null) { + // 如果没有指定范围,从数据中计算 + List validLons = new ArrayList<>(); + List validLats = new ArrayList<>(); + + for (AppTraffic traffic : dataList) { + try { + if (traffic.getUserLon() != null && !traffic.getUserLon().trim().isEmpty()) { + validLons.add(Double.parseDouble(traffic.getUserLon())); + } + if (traffic.getUserLat() != null && !traffic.getUserLat().trim().isEmpty()) { + validLats.add(Double.parseDouble(traffic.getUserLat())); + } + } catch (NumberFormatException e) { + // 忽略无效的经纬度数据 + } + } + + // 如果没有有效的经纬度数据,返回空列表 + if (validLons.isEmpty() || validLats.isEmpty()) { + return new ArrayList<>(); + } + + minLon = validLons.stream().mapToDouble(Double::doubleValue).min().orElse(116.0); + maxLon = validLons.stream().mapToDouble(Double::doubleValue).max().orElse(117.0); + minLat = validLats.stream().mapToDouble(Double::doubleValue).min().orElse(39.0); + maxLat = validLats.stream().mapToDouble(Double::doubleValue).max().orElse(40.0); + + // 如果范围太小,扩展一点 + if (maxLon - minLon < 0.001) { + double centerLon = (minLon + maxLon) / 2.0; + minLon = centerLon - 0.01; + maxLon = centerLon + 0.01; + } + if (maxLat - minLat < 0.001) { + double centerLat = (minLat + maxLat) / 2.0; + minLat = centerLat - 0.01; + maxLat = centerLat + 0.01; + } + } + + // 4. 网格参数 + int gridRows = request.getGridRows() != null ? request.getGridRows() : 20; + int gridCols = request.getGridCols() != null ? request.getGridCols() : 15; + + // 确保范围有效 + if (maxLon <= minLon || maxLat <= minLat) { + return new ArrayList<>(); + } + + double lonStep = (maxLon - minLon) / gridCols; + double latStep = (maxLat - minLat) / gridRows; + + // 确保步长不为0 + if (lonStep <= 0 || latStep <= 0) { + return new ArrayList<>(); + } + + // 5. 按区域分组统计(按手机型号分组) + Map> regionPhoneTrafficMap = new HashMap<>(); + Map regionRecordCountMap = new HashMap<>(); + Map phoneOsMap = new HashMap<>(); // 存储手机型号对应的OS + Map phoneOsVersionMap = new HashMap<>(); // 存储手机型号对应的OS_ANDVERSION + + for (AppTraffic traffic : dataList) { + if (traffic.getUserLon() == null || traffic.getUserLon().trim().isEmpty() || + traffic.getUserLat() == null || traffic.getUserLat().trim().isEmpty()) { + continue; + } + + try { + double lon = Double.parseDouble(traffic.getUserLon()); + double lat = Double.parseDouble(traffic.getUserLat()); + + // 检查是否在可视区域内 + if (lon < minLon || lon > maxLon || lat < minLat || lat > maxLat) { + continue; + } + + // 计算所属区域 + int colIndex = Math.min((int) ((lon - minLon) / lonStep), gridCols - 1); + int rowIndex = Math.min((int) ((lat - minLat) / latStep), gridRows - 1); + + String regionKey = rowIndex + "_" + colIndex; + + // 构建手机型号key(OS + OS_ANDVERSION) + // 注意:实体类中osVersion字段对应数据库的OS_ANDVERSION列 + String os = traffic.getOs() != null ? traffic.getOs() : ""; + String osAndVersion = traffic.getOsVersion() != null ? traffic.getOsVersion() : ""; + String phoneKey = (os.toLowerCase() + osAndVersion).trim(); + + if (phoneKey.isEmpty()) { + continue; // 跳过没有OS信息的记录 + } + + // 计算总流量 + double totalTraffic = (traffic.getUploadTraffic() != null ? traffic.getUploadTraffic() : 0.0) + + (traffic.getDownloadTraffic() != null ? traffic.getDownloadTraffic() : 0.0); + + // 累计流量 + regionPhoneTrafficMap.computeIfAbsent(regionKey, k -> new HashMap<>()) + .merge(phoneKey, totalTraffic, Double::sum); + + regionRecordCountMap.merge(regionKey, 1L, Long::sum); + + // 保存手机型号对应的OS和OS_ANDVERSION + phoneOsMap.put(phoneKey, os); + phoneOsVersionMap.put(phoneKey, osAndVersion); + } catch (NumberFormatException e) { + // 忽略无效的经纬度数据 + continue; + } + } + + // 6. 找出每个区域的top1 热门手机 + List result = new ArrayList<>(); + + for (int row = 0; row < gridRows; row++) { + for (int col = 0; col < gridCols; col++) { + String regionKey = row + "_" + col; + Map phoneTrafficMap = regionPhoneTrafficMap.get(regionKey); + + if (phoneTrafficMap == null || phoneTrafficMap.isEmpty()) { + continue; // 该区域没有数据,跳过 + } + + // 找出流量最大的手机 + Map.Entry topPhone = phoneTrafficMap.entrySet().stream() + .max(Map.Entry.comparingByValue()) + .orElse(null); + + if (topPhone != null) { + String phoneKey = topPhone.getKey(); + String os = phoneOsMap.getOrDefault(phoneKey, ""); + String osVersion = phoneOsVersionMap.getOrDefault(phoneKey, ""); + String phoneModel = (os.toLowerCase() + osVersion).trim(); + + // 计算区域中心点 + double centerLon = minLon + (col + 0.5) * lonStep; + double centerLat = minLat + (row + 0.5) * latStep; + + com.bigdata.dto.PhoneTrafficRegionTopDTO dto = new com.bigdata.dto.PhoneTrafficRegionTopDTO(); + dto.setRowIndex(row); + dto.setColIndex(col); + dto.setCenterLon(centerLon); + dto.setCenterLat(centerLat); + dto.setPhoneModel(phoneModel); + dto.setOs(os); + dto.setOsVersion(osVersion); + dto.setTotalTraffic(topPhone.getValue()); + dto.setRecordCount(regionRecordCountMap.getOrDefault(regionKey, 0L)); + + result.add(dto); + } + } + } + + return result; + } + + @Override + public List getOsRegionTop(com.bigdata.dto.OsTrafficRegionTopRequest request) { + // 1. 准备查询参数 + String operator = null; + if (request.getOperator() != null && !request.getOperator().trim().isEmpty() && !"ALL".equals(request.getOperator().trim().toUpperCase())) { + operator = request.getOperator().trim().toUpperCase(); + } + + String networkType = request.getNetworkType(); + Double minUploadTraffic = request.getMinUploadTraffic(); + Double maxUploadTraffic = request.getMaxUploadTraffic(); + Double minDownloadTraffic = request.getMinDownloadTraffic(); + Double maxDownloadTraffic = request.getMaxDownloadTraffic(); + String startDate = request.getStartDate() != null ? request.getStartDate().replace("-", "") : null; + String endDate = request.getEndDate() != null ? request.getEndDate().replace("-", "") : null; + + // 2. 查询数据 + List dataList = appTrafficMapper.selectByCondition( + operator, networkType, null, + minUploadTraffic, maxUploadTraffic, + minDownloadTraffic, maxDownloadTraffic, + startDate, endDate); + + if (dataList == null || dataList.isEmpty()) { + return new ArrayList<>(); + } + + // 3. 确定可视区域范围 + Double minLon = request.getMinLon(); + Double maxLon = request.getMaxLon(); + Double minLat = request.getMinLat(); + Double maxLat = request.getMaxLat(); + + if (minLon == null || maxLon == null || minLat == null || maxLat == null) { + // 如果没有指定范围,从数据中计算 + List validLons = new ArrayList<>(); + List validLats = new ArrayList<>(); + + for (AppTraffic traffic : dataList) { + try { + if (traffic.getUserLon() != null && !traffic.getUserLon().trim().isEmpty()) { + validLons.add(Double.parseDouble(traffic.getUserLon())); + } + if (traffic.getUserLat() != null && !traffic.getUserLat().trim().isEmpty()) { + validLats.add(Double.parseDouble(traffic.getUserLat())); + } + } catch (NumberFormatException e) { + // 忽略无效的经纬度数据 + } + } + + // 如果没有有效的经纬度数据,返回空列表 + if (validLons.isEmpty() || validLats.isEmpty()) { + return new ArrayList<>(); + } + + minLon = validLons.stream().mapToDouble(Double::doubleValue).min().orElse(116.0); + maxLon = validLons.stream().mapToDouble(Double::doubleValue).max().orElse(117.0); + minLat = validLats.stream().mapToDouble(Double::doubleValue).min().orElse(39.0); + maxLat = validLats.stream().mapToDouble(Double::doubleValue).max().orElse(40.0); + + // 如果范围太小,扩展一点 + if (maxLon - minLon < 0.001) { + double centerLon = (minLon + maxLon) / 2.0; + minLon = centerLon - 0.01; + maxLon = centerLon + 0.01; + } + if (maxLat - minLat < 0.001) { + double centerLat = (minLat + maxLat) / 2.0; + minLat = centerLat - 0.01; + maxLat = centerLat + 0.01; + } + } + + // 4. 网格参数 + int gridRows = request.getGridRows() != null ? request.getGridRows() : 20; + int gridCols = request.getGridCols() != null ? request.getGridCols() : 15; + + // 确保范围有效 + if (maxLon <= minLon || maxLat <= minLat) { + return new ArrayList<>(); + } + + double lonStep = (maxLon - minLon) / gridCols; + double latStep = (maxLat - minLat) / gridRows; + + // 确保步长不为0 + if (lonStep <= 0 || latStep <= 0) { + return new ArrayList<>(); + } + + // 5. 按区域分组统计(按OS分组) + Map> regionOsTrafficMap = new HashMap<>(); + Map regionRecordCountMap = new HashMap<>(); + Map osNameMap = new HashMap<>(); // 存储OS key对应的OS名称 + + for (AppTraffic traffic : dataList) { + if (traffic.getUserLon() == null || traffic.getUserLon().trim().isEmpty() || + traffic.getUserLat() == null || traffic.getUserLat().trim().isEmpty()) { + continue; + } + + try { + double lon = Double.parseDouble(traffic.getUserLon()); + double lat = Double.parseDouble(traffic.getUserLat()); + + // 检查是否在可视区域内 + if (lon < minLon || lon > maxLon || lat < minLat || lat > maxLat) { + continue; + } + + // 计算所属区域 + int colIndex = Math.min((int) ((lon - minLon) / lonStep), gridCols - 1); + int rowIndex = Math.min((int) ((lat - minLat) / latStep), gridRows - 1); + + String regionKey = rowIndex + "_" + colIndex; + + // 构建OS key(只按OS分组,不包含版本号) + String os = traffic.getOs() != null ? traffic.getOs() : ""; + String osKey = os.toLowerCase().trim(); + + if (osKey.isEmpty()) { + continue; // 跳过没有OS信息的记录 + } + + // 计算总流量 + double totalTraffic = (traffic.getUploadTraffic() != null ? traffic.getUploadTraffic() : 0.0) + + (traffic.getDownloadTraffic() != null ? traffic.getDownloadTraffic() : 0.0); + + // 累计流量 + regionOsTrafficMap.computeIfAbsent(regionKey, k -> new HashMap<>()) + .merge(osKey, totalTraffic, Double::sum); + + regionRecordCountMap.merge(regionKey, 1L, Long::sum); + + // 保存OS key对应的OS名称(保留原始大小写) + osNameMap.put(osKey, os); + } catch (NumberFormatException e) { + // 忽略无效的经纬度数据 + continue; + } + } + + // 6. 找出每个区域的top1 手机OS + List result = new ArrayList<>(); + + for (int row = 0; row < gridRows; row++) { + for (int col = 0; col < gridCols; col++) { + String regionKey = row + "_" + col; + Map osTrafficMap = regionOsTrafficMap.get(regionKey); + + if (osTrafficMap == null || osTrafficMap.isEmpty()) { + continue; // 该区域没有数据,跳过 + } + + // 找出流量最大的OS + Map.Entry topOs = osTrafficMap.entrySet().stream() + .max(Map.Entry.comparingByValue()) + .orElse(null); + + if (topOs != null) { + String osKey = topOs.getKey(); + String osName = osNameMap.getOrDefault(osKey, osKey); + + // 计算区域中心点 + double centerLon = minLon + (col + 0.5) * lonStep; + double centerLat = minLat + (row + 0.5) * latStep; + + com.bigdata.dto.OsTrafficRegionTopDTO dto = new com.bigdata.dto.OsTrafficRegionTopDTO(); + dto.setRowIndex(row); + dto.setColIndex(col); + dto.setCenterLon(centerLon); + dto.setCenterLat(centerLat); + dto.setOsName(osName); + dto.setOs(osName); + dto.setTotalTraffic(topOs.getValue()); + dto.setRecordCount(regionRecordCountMap.getOrDefault(regionKey, 0L)); + result.add(dto); } } @@ -783,7 +1251,7 @@ public class AppTrafficServiceImpl implements AppTrafficService { } } } - + return result; } } diff --git a/src/main/resources/mapper/AppTrafficMapper.xml b/src/main/resources/mapper/AppTrafficMapper.xml index a3453ea..219082f 100644 --- a/src/main/resources/mapper/AppTrafficMapper.xml +++ b/src/main/resources/mapper/AppTrafficMapper.xml @@ -5,19 +5,19 @@ SELECT - "APP_NAME" AS appName, - "PACKAGE_NAME" AS packageName, - "NETWORK_NAME" AS operator, - CAST(SUM("UPLOAD_TRAFFIC") AS DOUBLE) AS totalUploadTraffic, - CAST(SUM("DOWNLOAD_TRAFFIC") AS DOUBLE) AS totalDownloadTraffic, - CAST(SUM("UPLOAD_TRAFFIC" + "DOWNLOAD_TRAFFIC") AS DOUBLE) AS totalTraffic, - CAST(0.0 AS DOUBLE) AS trafficRatio, - CAST(COUNT(*) AS BIGINT) AS recordCount + "APP_NAME" AS appName, + "PACKAGE_NAME" AS packageName, + "NETWORK_NAME" AS operator, + CAST(SUM("UPLOAD_TRAFFIC") AS DOUBLE) AS totalUploadTraffic, + CAST(SUM("DOWNLOAD_TRAFFIC") AS DOUBLE) AS totalDownloadTraffic, + CAST(SUM("UPLOAD_TRAFFIC" + "DOWNLOAD_TRAFFIC") AS DOUBLE) AS totalTraffic, + CAST(0.0 AS DOUBLE) AS trafficRatio, + CAST(COUNT(*) AS BIGINT) AS recordCount FROM "APP_TRAFFIC" @@ -89,35 +89,35 @@ SELECT - "COMPANYMODEL" AS phoneModel, - "OS" AS os, - "NETWORK_NAME" AS operator, - "NETWORK_TYPE" AS networkType, - CAST(SUM("UPLOAD_TRAFFIC") AS DOUBLE) AS totalUploadTraffic, - CAST(SUM("DOWNLOAD_TRAFFIC") AS DOUBLE) AS totalDownloadTraffic, - CAST(SUM("UPLOAD_TRAFFIC" + "DOWNLOAD_TRAFFIC") AS DOUBLE) AS totalTraffic, - CAST(COUNT(*) AS BIGINT) AS recordCount + "COMPANYMODEL" AS phoneModel, + "OS" AS os, + "NETWORK_NAME" AS operator, + "NETWORK_TYPE" AS networkType, + CAST(SUM("UPLOAD_TRAFFIC") AS DOUBLE) AS totalUploadTraffic, + CAST(SUM("DOWNLOAD_TRAFFIC") AS DOUBLE) AS totalDownloadTraffic, + CAST(SUM("UPLOAD_TRAFFIC" + "DOWNLOAD_TRAFFIC") AS DOUBLE) AS totalTraffic, + CAST(COUNT(*) AS BIGINT) AS recordCount FROM "APP_TRAFFIC" @@ -276,15 +276,15 @@ ORDER BY totalTraffic DESC, "COMPANYMODEL" - + - SELECT - ("OS" || CASE WHEN "OS_ANDVERSION" != 'NULL' AND "OS_ANDVERSION" != '' THEN ' ' || "OS_ANDVERSION" ELSE '' END) AS osName, - "OS" AS os, - CASE WHEN "OS_ANDVERSION" != 'NULL' THEN "OS_ANDVERSION" ELSE '' END AS osVersion, - "NETWORK_NAME" AS operator, - "OS" AS networkType, - CAST(SUM("UPLOAD_TRAFFIC") AS DOUBLE) AS totalUploadTraffic, - CAST(SUM("DOWNLOAD_TRAFFIC") AS DOUBLE) AS totalDownloadTraffic, - CAST(SUM("UPLOAD_TRAFFIC" + "DOWNLOAD_TRAFFIC") AS DOUBLE) AS totalTraffic, - CAST(0.0 AS DOUBLE) AS trafficRatio, - CAST(COUNT(*) AS BIGINT) AS recordCount + ("OS" || CASE WHEN "OS_ANDVERSION" != 'NULL' AND "OS_ANDVERSION" != '' THEN ' ' || "OS_ANDVERSION" ELSE '' END) AS osName, + "OS" AS os, + CASE WHEN "OS_ANDVERSION" != 'NULL' THEN "OS_ANDVERSION" ELSE '' END AS osVersion, + "NETWORK_NAME" AS operator, + "OS" AS networkType, + CAST(SUM("UPLOAD_TRAFFIC") AS DOUBLE) AS totalUploadTraffic, + CAST(SUM("DOWNLOAD_TRAFFIC") AS DOUBLE) AS totalDownloadTraffic, + CAST(SUM("UPLOAD_TRAFFIC" + "DOWNLOAD_TRAFFIC") AS DOUBLE) AS totalTraffic, + CAST(0.0 AS DOUBLE) AS trafficRatio, + CAST(COUNT(*) AS BIGINT) AS recordCount FROM "APP_TRAFFIC"