|
|
@@ -1,15 +1,34 @@
|
|
|
package cn.reghao.tnb.search.app.log;
|
|
|
|
|
|
-import cn.reghao.jutil.jdk.web.log.NginxLog;
|
|
|
import cn.reghao.jutil.jdk.converter.DateTimeConverter;
|
|
|
-import cn.reghao.tnb.search.app.log.model.vo.DateCount;
|
|
|
+import cn.reghao.jutil.jdk.io.TextFile;
|
|
|
+import cn.reghao.jutil.jdk.serializer.JsonConverter;
|
|
|
+import cn.reghao.jutil.jdk.web.log.NginxLog;
|
|
|
+import cn.reghao.tnb.common.db.SelectOption;
|
|
|
+import cn.reghao.tnb.search.app.config.AppProperties;
|
|
|
+import cn.reghao.tnb.search.app.es.EsQuery;
|
|
|
+import cn.reghao.tnb.search.app.es.SearchService;
|
|
|
+import cn.reghao.tnb.search.app.log.ip.GeoIpTool;
|
|
|
+import cn.reghao.tnb.search.app.log.ip.Location;
|
|
|
+import cn.reghao.tnb.search.app.log.model.dto.DateTimeRange;
|
|
|
+import cn.reghao.tnb.search.app.log.model.vo.ChartData;
|
|
|
+import cn.reghao.tnb.search.app.log.model.vo.ChartMap;
|
|
|
+import cn.reghao.tnb.search.app.log.model.vo.GroupCount;
|
|
|
+import co.elastic.clients.elasticsearch._types.SortOrder;
|
|
|
+import co.elastic.clients.elasticsearch._types.query_dsl.Query;
|
|
|
+import co.elastic.clients.elasticsearch._types.query_dsl.RangeQuery;
|
|
|
+import co.elastic.clients.json.JsonData;
|
|
|
+import com.google.gson.JsonElement;
|
|
|
+import com.google.gson.JsonObject;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
-import java.time.*;
|
|
|
-import java.time.format.DateTimeFormatter;
|
|
|
+import java.time.Duration;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* @author reghao
|
|
|
@@ -18,16 +37,34 @@ import java.util.*;
|
|
|
@Slf4j
|
|
|
@Service
|
|
|
public class NginxLogService {
|
|
|
- private String indexName = "nginx_log";
|
|
|
+ private final String indexName = "nginx_log";
|
|
|
private final NginxLogDocument nginxLogDocument;
|
|
|
+ private final SearchService searchService;
|
|
|
+ private final GeoIpTool geoIpTool;
|
|
|
+ private final String geoJson;
|
|
|
|
|
|
- public NginxLogService(NginxLogDocument nginxLogDocument) {
|
|
|
+ public NginxLogService(NginxLogDocument nginxLogDocument, SearchService searchService,
|
|
|
+ GeoIpTool geoIpTool, AppProperties appProperties) {
|
|
|
this.nginxLogDocument = nginxLogDocument;
|
|
|
+ this.searchService = searchService;
|
|
|
+ this.geoIpTool = geoIpTool;
|
|
|
+ this.geoJson = new TextFile().readFile(appProperties.getGeojsonPath());
|
|
|
}
|
|
|
|
|
|
public void processNginxLog(NginxLog nginxLog) {
|
|
|
saveNginxLog(nginxLog);
|
|
|
- //processNginxLog0(nginxLog);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void saveNginxLogs(List<NginxLog> list) {
|
|
|
+ if (list.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ nginxLogDocument.batchAddDocument(indexName, list);
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private void saveNginxLog(NginxLog nginxLog) {
|
|
|
@@ -38,146 +75,248 @@ public class NginxLogService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- String matchedMethod = "GET";
|
|
|
- String matchedUrl = "/";
|
|
|
- Map<String, Map<Long, Integer>> map = new HashMap<>();
|
|
|
- Map<Long, Integer> ngxLogMap = new TreeMap<>();
|
|
|
- DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss+08:00").withZone(ZoneId.of("UTC"));
|
|
|
- DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(ZoneId.of("UTC"));
|
|
|
- private void processNginxLog0(NginxLog nginxLog) {
|
|
|
- String todayStr = LocalDateTime.now().toLocalDate().format(formatter1);
|
|
|
- String method = nginxLog.getRequestMethod();
|
|
|
- String url = nginxLog.getUrl();
|
|
|
- if (method.equals(matchedMethod) && url.startsWith(matchedUrl)) {
|
|
|
- String date = nginxLog.getTimeIso8601();
|
|
|
- LocalDateTime localDateTime = LocalDateTime.parse(date, formatter);
|
|
|
- LocalDate localDate = localDateTime.toLocalDate();
|
|
|
- String localDateStr = localDate.format(formatter1);
|
|
|
- Map<Long, Integer> ngxLogMap = map.computeIfAbsent(localDateStr, k -> new TreeMap<>());
|
|
|
-
|
|
|
- LocalTime localTime = localDateTime.toLocalTime();
|
|
|
- Long timestampSecond = LocalDateTime.parse(date, formatter).toEpochSecond(ZoneOffset.of("+8"));
|
|
|
- Integer count = ngxLogMap.get(timestampSecond);
|
|
|
- if (count == null) {
|
|
|
- ngxLogMap.put(timestampSecond, 1);
|
|
|
- } else {
|
|
|
- int count1 = ngxLogMap.get(timestampSecond) + 1;
|
|
|
- ngxLogMap.put(timestampSecond, count1);
|
|
|
- }
|
|
|
+ public List<SelectOption> getDateList() {
|
|
|
+ try {
|
|
|
+ String aggregateField = "timeIso8601";
|
|
|
+ Query query = Query.of(q -> q.matchAll(m -> m));
|
|
|
+ Map<String, Long> groupMap = searchService.aggregateByDay(indexName, aggregateField, query);
|
|
|
+
|
|
|
+ Set<String> dateSet = groupMap.keySet();
|
|
|
+ return dateSet.stream()
|
|
|
+ .sorted(Comparator.reverseOrder())
|
|
|
+ .map(dateStr -> new SelectOption(dateStr, dateStr))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
}
|
|
|
+ return Collections.emptyList();
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * NginxLog 在前端 echarts 中的可视化
|
|
|
- *
|
|
|
- * @param
|
|
|
- * @return
|
|
|
- * @date 2023-12-01 17:41:07
|
|
|
- */
|
|
|
- class PushTask implements Runnable {
|
|
|
- @Override
|
|
|
- public void run() {
|
|
|
- while (!Thread.interrupted()) {
|
|
|
- Set<String> dateSet = map.keySet();
|
|
|
- try {
|
|
|
- if (ngxLogMap.size() < 3) {
|
|
|
- Thread.sleep(10_000);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- List<Object> chartData = getChartData();
|
|
|
- /*TextMessage textMessage = new TextMessage(JsonConverter.objectToJson(chartData));
|
|
|
- pullSessionMap.values().forEach(webSocketSession -> {
|
|
|
- try {
|
|
|
- webSocketSession.sendMessage(textMessage);
|
|
|
- } catch (IOException e) {
|
|
|
- e.printStackTrace();
|
|
|
- }
|
|
|
- });*/
|
|
|
- Thread.sleep(3_000);
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- }
|
|
|
- }
|
|
|
+ public List<Object> getNginxLog2(DateTimeRange dateTimeRange) throws Exception {
|
|
|
+ String start = dateTimeRange.getStartDateTime();
|
|
|
+ LocalDateTime start1 = DateTimeConverter.localDateTime2(start);
|
|
|
+ String end = dateTimeRange.getEndDateTime();
|
|
|
+ LocalDateTime end1 = DateTimeConverter.localDateTime2(end);
|
|
|
+
|
|
|
+ Duration duration = Duration.between(start1, end1);
|
|
|
+ long days = duration.toHours();
|
|
|
+ if (days < 0) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ } else if (days > 24) {
|
|
|
+ return Collections.emptyList();
|
|
|
}
|
|
|
+ return null;
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * x 轴显示时分秒
|
|
|
- * y 轴显示访问次数
|
|
|
- *
|
|
|
- * @param
|
|
|
- * @return
|
|
|
- * @date 2025-12-24 17:48:10
|
|
|
- */
|
|
|
- private List<Object> getChartData() {
|
|
|
- Long timestampSecondCurrent = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
|
|
|
- List<String> xList = new ArrayList<>();
|
|
|
- List<Integer> yList = new ArrayList<>();
|
|
|
- Set<Long> keys = new HashSet<>();
|
|
|
- for (Long timestampSecond : ngxLogMap.keySet()) {
|
|
|
- if (timestampSecond < timestampSecondCurrent) {
|
|
|
- // x 轴显示时分秒
|
|
|
- xList.add(DateTimeConverter.format(timestampSecond*1000).split(" ")[1]);
|
|
|
- // y 轴显示访问次数
|
|
|
- yList.add(ngxLogMap.get(timestampSecond));
|
|
|
- keys.add(timestampSecond);
|
|
|
- }
|
|
|
- }
|
|
|
+ public List<ChartData> getTopN(String dateStr) throws IOException {
|
|
|
+ int pageSize = 100;
|
|
|
+ int pageNumber = 1;
|
|
|
|
|
|
- keys.forEach(ngxLogMap::remove);
|
|
|
- keys.clear();
|
|
|
- List<Object> results = new ArrayList<>();
|
|
|
- results.add(xList.toArray());
|
|
|
- results.add(yList.toArray());
|
|
|
- return results;
|
|
|
- }
|
|
|
+ String startDate = dateStr;
|
|
|
+ String endDate = dateStr;
|
|
|
+ String start1 = String.format("%sT00:00:00", startDate);
|
|
|
+ String end1 = String.format("%sT23:59:59", endDate);
|
|
|
+ Query dateQuery = RangeQuery.of(q -> q.field("timeIso8601")
|
|
|
+ .gte(JsonData.of(start1)).lte(JsonData.of(end1)))._toQuery();
|
|
|
+ Query termQuery = EsQuery.getTermQuery("status", "200");
|
|
|
+ Query combinedQuery = Query.of(q -> q.bool(b -> b.filter(termQuery).filter(dateQuery)));
|
|
|
+
|
|
|
+ String sortField = "requestTime";
|
|
|
+ SortOrder sortOrder = SortOrder.Desc;
|
|
|
+ List<NginxLog> list = searchService.searchByPage(indexName, pageSize, pageNumber, combinedQuery, sortField, sortOrder);
|
|
|
+ List<ChartData> chartDataList = new ArrayList<>();
|
|
|
+ list.forEach(nginxLog -> {
|
|
|
+ String method = nginxLog.getRequestMethod();
|
|
|
+ String url = nginxLog.getUrl();
|
|
|
+ String name = String.format("%s %s", method, url);
|
|
|
+ double requestTime = nginxLog.getRequestTime();
|
|
|
+ chartDataList.add(new ChartData(name, requestTime));
|
|
|
+ });
|
|
|
+ return chartDataList;
|
|
|
}
|
|
|
|
|
|
- private List<Object> getChartData(Map<Long, Integer> timeMap) {
|
|
|
- Long timestampSecondCurrent = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
|
|
|
- List<String> xList = new ArrayList<>();
|
|
|
- List<Integer> yList = new ArrayList<>();
|
|
|
- Set<Long> keys = new HashSet<>();
|
|
|
- for (Long timestampSecond : timeMap.keySet()) {
|
|
|
- if (timestampSecond < timestampSecondCurrent) {
|
|
|
- // x 轴显示时分秒
|
|
|
- xList.add(DateTimeConverter.format(timestampSecond*1000).split(" ")[1]);
|
|
|
- // y 轴显示访问次数
|
|
|
- yList.add(timeMap.get(timestampSecond));
|
|
|
- keys.add(timestampSecond);
|
|
|
- }
|
|
|
+ public long countNginxLog(String dateStr) {
|
|
|
+ String startDate = dateStr;
|
|
|
+ String endDate = dateStr;
|
|
|
+ String start1 = String.format("%sT00:00:00", startDate);
|
|
|
+ String end1 = String.format("%sT23:59:59", endDate);
|
|
|
+ RangeQuery dateQuery = RangeQuery.of(q -> q.field("timeIso8601").gte(JsonData.of(start1)).lte(JsonData.of(end1)));
|
|
|
+ return searchService.count(indexName, dateQuery._toQuery());
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<Object> getChartData2(String dateStr, String fieldValue) throws Exception {
|
|
|
+ String aggregateField = "timeIso8601";
|
|
|
+ String dateField = "timeIso8601";
|
|
|
+ String fieldName = "url.raw";
|
|
|
+
|
|
|
+ String start = String.format("%sT00:00:00", dateStr);
|
|
|
+ String end = String.format("%sT23:59:59", dateStr);
|
|
|
+ /*String start1 = startDateTime.replace(" ", "T");
|
|
|
+ String end1 = endDateTime.replace(" ", "T");*/
|
|
|
+ RangeQuery dateQuery = RangeQuery.of(q -> q.field(dateField).gte(JsonData.of(start)).lte(JsonData.of(end)));
|
|
|
+ Query combinedQuery;
|
|
|
+ if (fieldValue == null || fieldValue.isBlank()) {
|
|
|
+ combinedQuery = Query.of(q -> q.bool(b -> b.filter(dateQuery._toQuery())));
|
|
|
+ } else {
|
|
|
+ Query termQuery = EsQuery.getTermQuery(fieldName, fieldValue);
|
|
|
+ combinedQuery = Query.of(q -> q.bool(b -> b.filter(dateQuery._toQuery()).filter(termQuery)));
|
|
|
}
|
|
|
+ Map<String, Long> urlGroupMap = searchService.aggregateByQuery(indexName, aggregateField, combinedQuery);
|
|
|
+
|
|
|
+ List<String> xList = new ArrayList<>();
|
|
|
+ List<Long> yList = new ArrayList<>();
|
|
|
+ urlGroupMap.forEach((key, value) -> {
|
|
|
+ // x 轴显示时分秒
|
|
|
+ xList.add(key);
|
|
|
+ // y 轴显示访问次数
|
|
|
+ yList.add(value);
|
|
|
+ });
|
|
|
|
|
|
- keys.forEach(timeMap::remove);
|
|
|
- keys.clear();
|
|
|
List<Object> results = new ArrayList<>();
|
|
|
results.add(xList.toArray());
|
|
|
results.add(yList.toArray());
|
|
|
return results;
|
|
|
}
|
|
|
|
|
|
- public List<DateCount> getDateCountList() {
|
|
|
- Map<String, Integer> result = new TreeMap<>();
|
|
|
- List<DateCount> list = new LinkedList<>();
|
|
|
- for (Map.Entry<String, Map<Long, Integer>> entry : map.entrySet()) {
|
|
|
- String dateStr = entry.getKey();
|
|
|
- Integer count = entry.getValue().size();
|
|
|
- list.add(new DateCount(dateStr, count));
|
|
|
- result.put(dateStr, count);
|
|
|
- }
|
|
|
+ public List<GroupCount> getChartData3(String aggregateField, String dateStr) throws Exception {
|
|
|
+ String dateField = "timeIso8601";
|
|
|
+ DateTimeRange dateTimeRange = getDateTimeRange(dateStr);
|
|
|
+ String startDateTime = dateTimeRange.getStartDateTime();
|
|
|
+ String endDateTime = dateTimeRange.getEndDateTime();
|
|
|
+ String start = startDateTime.replace(" ", "T");
|
|
|
+ String end = endDateTime.replace(" ", "T");
|
|
|
+ Query query = RangeQuery.of(q -> q.field(dateField).gte(JsonData.of(start)).lte(JsonData.of(end)))._toQuery();
|
|
|
+ Map<String, Long> groupMap = searchService.aggregateByQuery(indexName, aggregateField, query);
|
|
|
+
|
|
|
+ List<GroupCount> list = new ArrayList<>();
|
|
|
+ groupMap.forEach((key, value) -> {
|
|
|
+ list.add(new GroupCount(key, value));
|
|
|
+ });
|
|
|
+ list.sort(new Comparator<>() {
|
|
|
+ @Override
|
|
|
+ public int compare(GroupCount groupCount1, GroupCount groupCount2) {
|
|
|
+ // 降序
|
|
|
+ long result = groupCount2.getTotal() - groupCount1.getTotal();
|
|
|
+ return (int) result;
|
|
|
+ }
|
|
|
+ });
|
|
|
return list;
|
|
|
}
|
|
|
|
|
|
- public List<Object> getChartData1(String dateStr) {
|
|
|
- Map<Long, Integer> timeMap = map.get(dateStr);
|
|
|
- return getChartData(timeMap);
|
|
|
+ public ChartMap getChartMap(String aggregateField, String dateStr) throws Exception {
|
|
|
+ int deep = 1;
|
|
|
+ String dateField = "timeIso8601";
|
|
|
+ DateTimeRange dateTimeRange = getDateTimeRange(dateStr);
|
|
|
+ String startDateTime = dateTimeRange.getStartDateTime();
|
|
|
+ String endDateTime = dateTimeRange.getEndDateTime();
|
|
|
+ String start = startDateTime.replace(" ", "T");
|
|
|
+ String end = endDateTime.replace(" ", "T");
|
|
|
+ RangeQuery dateQuery = RangeQuery.of(q -> q.field(dateField).gte(JsonData.of(start)).lte(JsonData.of(end)));
|
|
|
+ Query query = dateQuery._toQuery();
|
|
|
+ Map<String, Long> groupMap1 = searchService.aggregateByQuery(indexName, aggregateField, query);
|
|
|
+
|
|
|
+ Map<String, Long> map0 = new HashMap<>();
|
|
|
+ Map<String, Map<String, Set<String>>> map = new HashMap<>();
|
|
|
+ groupMap1.forEach((key, value) -> {
|
|
|
+ String accessIp = key;
|
|
|
+ Location location = geoIpTool.getLocation(accessIp);
|
|
|
+ String country0 = location.getCountry();
|
|
|
+ String[] array = country0.split("–");
|
|
|
+ int len = array.length;
|
|
|
+ String country = array[0];
|
|
|
+ if (!"中国".equals(country) || len < 2) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ String province = array[1];
|
|
|
+ Long count = map0.get(province);
|
|
|
+ if (count == null) {
|
|
|
+ count = 1L;
|
|
|
+ } else {
|
|
|
+ count += 1L;
|
|
|
+ }
|
|
|
+ map0.put(province, count);
|
|
|
+
|
|
|
+ Map<String, Set<String>> map1 = map.computeIfAbsent(province, k -> new HashMap<>());
|
|
|
+ if (len == 3) {
|
|
|
+ String city = array[2];
|
|
|
+ Set<String> set = map1.computeIfAbsent(city, k -> new HashSet<>());
|
|
|
+ } else if (len == 4) {
|
|
|
+ String city = array[2];
|
|
|
+ Set<String> set = map1.computeIfAbsent(city, k -> new HashSet<>());
|
|
|
+ String county = array[3];
|
|
|
+ set.add(county);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ Map<Integer, String> geoMap = new HashMap<>();
|
|
|
+ JsonObject jsonObject = JsonConverter.jsonToJsonElement(geoJson).getAsJsonObject();
|
|
|
+ for (JsonElement jsonElement : jsonObject.get("features").getAsJsonArray()) {
|
|
|
+ JsonObject propertiesObject = jsonElement.getAsJsonObject().get("properties").getAsJsonObject();
|
|
|
+ int adcode = propertiesObject.get("adcode").getAsInt();
|
|
|
+ String name = propertiesObject.get("name").getAsString();
|
|
|
+ if (deep == 3) {
|
|
|
+ geoMap.put(adcode, name);
|
|
|
+ } else if (deep == 2) {
|
|
|
+ String adcodeStr = (""+adcode).substring(0, 4);
|
|
|
+ geoMap.put(Integer.parseInt(adcodeStr), name);
|
|
|
+ } else if (deep == 1) {
|
|
|
+ String adcodeStr = (""+adcode).substring(0, 2);
|
|
|
+ geoMap.put(Integer.parseInt(adcodeStr), name);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ List<String> areaNames = new ArrayList<>(geoMap.values());
|
|
|
+ List<ChartData> chartDataList = new ArrayList<>();
|
|
|
+ map0.forEach((key, value) -> {
|
|
|
+ for (String areaName : areaNames) {
|
|
|
+ if (areaName.startsWith(key)) {
|
|
|
+ chartDataList.add(new ChartData(areaName, value));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return new ChartMap(geoJson, chartDataList);
|
|
|
}
|
|
|
|
|
|
- public List<DateCount> getNginxLogs() {
|
|
|
- return getDateCountList();
|
|
|
+ private DateTimeRange getDateTimeRange(String dateStr) {
|
|
|
+ LocalDate localDate = LocalDate.parse(dateStr);
|
|
|
+ String startDate = localDate.minusDays(7).toString();
|
|
|
+ String endDate = localDate.toString();
|
|
|
+
|
|
|
+ String start1 = String.format("%sT00:00:00", startDate);
|
|
|
+ String end1 = String.format("%sT23:59:59", endDate);
|
|
|
+ return new DateTimeRange(start1, end1);
|
|
|
}
|
|
|
|
|
|
- public List<Object> getChartData(String dateStr) {
|
|
|
- return getChartData1(dateStr);
|
|
|
+ public List<Object> getChartData5(String dateStr, String fieldValue) throws Exception {
|
|
|
+ String aggregateField = "timeIso8601";
|
|
|
+ String fieldName = "url.raw";
|
|
|
+
|
|
|
+ Query query = Query.of(q -> q.matchAll(m -> m));
|
|
|
+ DateTimeRange dateTimeRange = getDateTimeRange(dateStr);
|
|
|
+ String start1 = dateTimeRange.getStartDateTime();
|
|
|
+ String end1 = dateTimeRange.getEndDateTime();
|
|
|
+ RangeQuery dateQuery = RangeQuery.of(q -> q.field("timeIso8601").gte(JsonData.of(start1)).lte(JsonData.of(end1)));
|
|
|
+ Query combinedQuery;
|
|
|
+ if (fieldValue != null && !fieldValue.isBlank()) {
|
|
|
+ Query termQuery = EsQuery.getTermQuery(fieldName, fieldValue);
|
|
|
+ combinedQuery = Query.of(q -> q.bool(b -> b.filter(termQuery).filter(dateQuery._toQuery())));
|
|
|
+ } else {
|
|
|
+ combinedQuery = Query.of(q -> q.bool(b -> b.filter(dateQuery._toQuery())));
|
|
|
+ }
|
|
|
+ Map<String, Long> groupMap = searchService.aggregateByDay(indexName, aggregateField, combinedQuery);
|
|
|
+
|
|
|
+ List<String> xList = new ArrayList<>();
|
|
|
+ List<Long> yList = new ArrayList<>();
|
|
|
+ groupMap.forEach((key, value) -> {
|
|
|
+ // x 轴显示时分秒
|
|
|
+ xList.add(key);
|
|
|
+ // y 轴显示访问次数
|
|
|
+ yList.add(value);
|
|
|
+ });
|
|
|
+ List<Object> results = new ArrayList<>();
|
|
|
+ results.add(xList.toArray());
|
|
|
+ results.add(yList.toArray());
|
|
|
+ return results;
|
|
|
}
|
|
|
}
|