提交 2dcdcfd7 编写于 作者: zlt2000's avatar zlt2000

增加天流量趋势,并优化首页图表样式

上级 bd692901
package com.central.search.service.impl; package com.central.search.service.impl;
import cn.hutool.core.util.StrUtil;
import com.central.common.constant.CommonConstant; import com.central.common.constant.CommonConstant;
import com.central.search.model.AggItemVo; import com.central.search.model.AggItemVo;
import com.central.search.service.IAggregationService; import com.central.search.service.IAggregationService;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations; import org.elasticsearch.search.aggregations.Aggregations;
...@@ -19,6 +21,7 @@ import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; ...@@ -19,6 +21,7 @@ import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
...@@ -107,7 +110,8 @@ public class AggregationServiceImpl implements IAggregationService { ...@@ -107,7 +110,8 @@ public class AggregationServiceImpl implements IAggregationService {
public Map<String, Object> requestStatAgg(String indexName, String routing) { public Map<String, Object> requestStatAgg(String indexName, String routing) {
DateTime currDt = DateTime.now(); DateTime currDt = DateTime.now();
LocalDate localDate = LocalDate.now(); LocalDate localDate = LocalDate.now();
SearchResponse response = elasticsearchTemplate.getClient().prepareSearch(indexName) LocalDateTime curDateTime = LocalDateTime.now();
SearchRequestBuilder searchRequestBuilder = elasticsearchTemplate.getClient().prepareSearch(indexName)
.setRouting(routing) .setRouting(routing)
.addAggregation( .addAggregation(
//聚合查询当天的数据 //聚合查询当天的数据
...@@ -115,13 +119,33 @@ public class AggregationServiceImpl implements IAggregationService { ...@@ -115,13 +119,33 @@ public class AggregationServiceImpl implements IAggregationService {
.dateRange("currDate") .dateRange("currDate")
.field("timestamp") .field("timestamp")
.addRange( .addRange(
currDt.withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0), currDt currDt.withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0), currDt.plusDays(1)
) )
.subAggregation( .subAggregation(
AggregationBuilders AggregationBuilders
.cardinality("uv") .cardinality("uv")
.field("ip.keyword") .field("ip.keyword")
) )
.subAggregation(
//聚合并且按小时分组查询当天内的数据
AggregationBuilders
.dateHistogram("statDate")
.field("timestamp")
.dateHistogramInterval(new DateHistogramInterval("90m"))
.format(CommonConstant.DATETIME_FORMAT)
//时区相差8小时
.timeZone(DateTimeZone.forOffsetHours(8))
.minDocCount(0L)
.extendedBounds(new ExtendedBounds(
curDateTime.minusDays(1).format(DateTimeFormatter.ofPattern(CommonConstant.DATETIME_FORMAT)),
curDateTime.format(DateTimeFormatter.ofPattern(CommonConstant.DATETIME_FORMAT))
))
.subAggregation(
AggregationBuilders
.cardinality("uv")
.field("ip.keyword")
)
)
) )
.addAggregation( .addAggregation(
//聚合查询7天内的数据 //聚合查询7天内的数据
...@@ -183,10 +207,11 @@ public class AggregationServiceImpl implements IAggregationService { ...@@ -183,10 +207,11 @@ public class AggregationServiceImpl implements IAggregationService {
.field("ip.keyword") .field("ip.keyword")
) )
) )
.setSize(0) .setSize(0);
.get();
SearchResponse response = searchRequestBuilder.get();
Aggregations aggregations = response.getAggregations(); Aggregations aggregations = response.getAggregations();
Map<String, Object> result = new HashMap<>(9); Map<String, Object> result = new HashMap<>(15);
if (aggregations != null) { if (aggregations != null) {
setCurrDate(result, aggregations); setCurrDate(result, aggregations);
setCurrWeek(result, aggregations); setCurrWeek(result, aggregations);
...@@ -206,6 +231,8 @@ public class AggregationServiceImpl implements IAggregationService { ...@@ -206,6 +231,8 @@ public class AggregationServiceImpl implements IAggregationService {
Cardinality cardinality = bucket.getAggregations().get("uv"); Cardinality cardinality = bucket.getAggregations().get("uv");
result.put("currDate_pv", bucket.getDocCount()); result.put("currDate_pv", bucket.getDocCount());
result.put("currDate_uv", cardinality.getValue()); result.put("currDate_uv", cardinality.getValue());
//赋值天趋势统计
setStatDate(result, bucket.getAggregations());
} }
/** /**
* 赋值周统计 * 赋值周统计
...@@ -271,4 +298,35 @@ public class AggregationServiceImpl implements IAggregationService { ...@@ -271,4 +298,35 @@ public class AggregationServiceImpl implements IAggregationService {
Cardinality cardinality = bucket.getAggregations().get("uv"); Cardinality cardinality = bucket.getAggregations().get("uv");
result.put("currHour_uv", cardinality.getValue()); result.put("currHour_uv", cardinality.getValue());
} }
/**
* 赋值天趋势统计
*/
private void setStatDate(Map<String, Object> result, Aggregations aggregations) {
InternalDateHistogram agg = aggregations.get("statDate");
List<String> items = new ArrayList<>();
List<Long> uv = new ArrayList<>();
List<Long> pv = new ArrayList<>();
Cardinality cardinality;
for (InternalDateHistogram.Bucket bucket : agg.getBuckets()) {
items.add(getTimeByDatetimeStr(bucket.getKeyAsString()));
pv.add(bucket.getDocCount());
cardinality = bucket.getAggregations().get("uv");
uv.add(cardinality.getValue());
}
result.put("statDate_items", items);
result.put("statDate_uv", uv);
result.put("statDate_pv", pv);
}
/**
* 2020-03-10 01:30:00 获取时间值:03-10 01:30
* @return
*/
private String getTimeByDatetimeStr(String datetimeStr) {
if (StrUtil.isNotEmpty(datetimeStr)) {
return datetimeStr.substring(5, 16);
}
return "";
}
} }
package com.central.gateway.filter; package com.central.gateway.filter;
import cn.hutool.core.util.StrUtil;
import eu.bitwalker.useragentutils.UserAgent; import eu.bitwalker.useragentutils.UserAgent;
import com.central.gateway.utils.ReactiveAddrUtil; import com.central.gateway.utils.ReactiveAddrUtil;
import com.central.log.monitor.PointUtil; import com.central.log.monitor.PointUtil;
...@@ -32,8 +33,8 @@ public class RequestStatisticsFilter implements GlobalFilter, Ordered { ...@@ -32,8 +33,8 @@ public class RequestStatisticsFilter implements GlobalFilter, Ordered {
//埋点 //埋点
PointUtil.debug("1", "request-statistics", PointUtil.debug("1", "request-statistics",
"ip=" + ReactiveAddrUtil.getRemoteAddr(request) "ip=" + ReactiveAddrUtil.getRemoteAddr(request)
+ "&browser=" + userAgent.getBrowser() + "&browser=" + getBrowser(userAgent.getBrowser().name())
+ "&operatingSystem=" + userAgent.getOperatingSystem()); + "&operatingSystem=" + getOperatingSystem(userAgent.getOperatingSystem().name()));
return chain.filter(exchange); return chain.filter(exchange);
} }
...@@ -42,4 +43,26 @@ public class RequestStatisticsFilter implements GlobalFilter, Ordered { ...@@ -42,4 +43,26 @@ public class RequestStatisticsFilter implements GlobalFilter, Ordered {
public int getOrder() { public int getOrder() {
return 0; return 0;
} }
private String getBrowser(String browser) {
if (StrUtil.isNotEmpty(browser)) {
if (browser.contains("CHROME")) {
return "CHROME";
} else if (browser.contains("FIREFOX")) {
return "FIREFOX";
}
}
return browser;
}
private String getOperatingSystem(String operatingSystem) {
if (StrUtil.isNotEmpty(operatingSystem)) {
if (operatingSystem.contains("MAC_OS_X")) {
return "MAC_OS_X";
} else if (operatingSystem.contains("ANDROID")) {
return "ANDROID";
}
}
return operatingSystem;
}
} }
package com.central.gateway.filter.pre; package com.central.gateway.filter.pre;
import cn.hutool.core.util.StrUtil;
import com.central.common.utils.AddrUtil; import com.central.common.utils.AddrUtil;
import com.central.log.monitor.PointUtil; import com.central.log.monitor.PointUtil;
import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.ZuulFilter;
...@@ -44,9 +45,31 @@ public class RequestStatisticsFilter extends ZuulFilter { ...@@ -44,9 +45,31 @@ public class RequestStatisticsFilter extends ZuulFilter {
//埋点 //埋点
PointUtil.debug("0", "request-statistics", PointUtil.debug("0", "request-statistics",
"ip=" + AddrUtil.getRemoteAddr(req) "ip=" + AddrUtil.getRemoteAddr(req)
+ "&browser=" + userAgent.getBrowser() + "&browser=" + getBrowser(userAgent.getBrowser().getName())
+ "&operatingSystem=" + userAgent.getOperatingSystem()); + "&operatingSystem=" + getOperatingSystem(userAgent.getOperatingSystem().getName()));
return null; return null;
} }
private String getBrowser(String browser) {
if (StrUtil.isNotEmpty(browser)) {
if (browser.contains("CHROME")) {
return "CHROME";
} else if (browser.contains("FIREFOX")) {
return "FIREFOX";
}
}
return browser;
}
private String getOperatingSystem(String operatingSystem) {
if (StrUtil.isNotEmpty(operatingSystem)) {
if (operatingSystem.contains("MAC_OS_X")) {
return "MAC_OS_X";
} else if (operatingSystem.contains("ANDROID")) {
return "ANDROID";
}
}
return operatingSystem;
}
} }
/** layuiAdmin.std-v2020.1.24 LPPL License By https://www.layui.com/admin/ */
;layui.define(function (e) {
e("echartsTheme", {
color: ["#009688", "#1E9FFF", "#5FB878", "#FFB980", "#D87A80", "#8d98b3", "#e5cf0d", "#97b552", "#95706d", "#dc69aa", "#07a2a4", "#9a7fd1", "#588dd5", "#f5994e", "#c05050", "#59678c", "#c9ab00", "#7eb00a", "#6f5553", "#c14089"],
title: {textStyle: {fontWeight: "normal", color: "#666"}},
dataRange: {itemWidth: 15, color: ["#009688", "#e0ffff"]},
toolbox: {color: ["#1e90ff", "#1e90ff", "#1e90ff", "#1e90ff"], effectiveColor: "#ff4500"},
tooltip: {
backgroundColor: "rgba(50,50,50,0.5)",
axisPointer: {
type: "line",
lineStyle: {color: "#009688"},
crossStyle: {color: "#008acd"},
shadowStyle: {color: "rgba(200,200,200,0.2)"}
}
},
dataZoom: {dataBackgroundColor: "#efefff", fillerColor: "rgba(182,162,222,0.2)", handleColor: "#008acd"},
grid: {borderColor: "#eee"},
categoryAxis: {
axisLine: {lineStyle: {color: "#009688"}},
axisTick: {show: !1},
splitLine: {lineStyle: {color: ["#eee"]}}
},
valueAxis: {
axisLine: {lineStyle: {color: "#009688"}},
splitArea: {show: !0, areaStyle: {color: ["rgba(250,250,250,0.1)", "rgba(200,200,200,0.1)"]}},
splitLine: {lineStyle: {color: ["#eee"]}}
},
polar: {
axisLine: {lineStyle: {color: "#ddd"}},
splitArea: {show: !0, areaStyle: {color: ["rgba(250,250,250,0.2)", "rgba(200,200,200,0.2)"]}},
splitLine: {lineStyle: {color: "#ddd"}}
},
timeline: {
lineStyle: {color: "#009688"},
controlStyle: {normal: {color: "#009688"}, emphasis: {color: "#009688"}},
symbol: "emptyCircle",
symbolSize: 3
},
bar: {itemStyle: {normal: {barBorderRadius: 2}, emphasis: {barBorderRadius: 2}}},
line: {smooth: !0, symbol: "emptyCircle", symbolSize: 3},
k: {
itemStyle: {
normal: {
color: "#d87a80",
color0: "#2ec7c9",
lineStyle: {color: "#d87a80", color0: "#2ec7c9"}
}
}
},
scatter: {symbol: "circle", symbolSize: 4},
radar: {symbol: "emptyCircle", symbolSize: 3},
map: {
itemStyle: {
normal: {areaStyle: {color: "#ddd"}, label: {textStyle: {color: "#d87a80"}}},
emphasis: {areaStyle: {color: "#fe994e"}}
}
},
force: {itemStyle: {normal: {linkStyle: {color: "#1e90ff"}}}},
chord: {
itemStyle: {
normal: {
borderWidth: 1,
borderColor: "rgba(128, 128, 128, 0.5)",
chordStyle: {lineStyle: {color: "rgba(128, 128, 128, 0.5)"}}
},
emphasis: {
borderWidth: 1,
borderColor: "rgba(128, 128, 128, 0.5)",
chordStyle: {lineStyle: {color: "rgba(128, 128, 128, 0.5)"}}
}
}
},
gauge: {
axisLine: {lineStyle: {color: [[.2, "#2ec7c9"], [.8, "#5ab1ef"], [1, "#d87a80"]], width: 10}},
axisTick: {splitNumber: 10, length: 15, lineStyle: {color: "auto"}},
splitLine: {length: 22, lineStyle: {color: "auto"}},
pointer: {width: 5}
},
textStyle: {fontFamily: "微软雅黑, Arial, Verdana, sans-serif"}
})
});
\ No newline at end of file
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<script type="text/javascript" src="../assets/libs/echarts.min.js"></script>
<style> <style>
.layui-card-header { .layui-card-header {
text-align:left; text-align:left;
...@@ -20,6 +19,22 @@ ...@@ -20,6 +19,22 @@
font-size: 250%; font-size: 250%;
height: 30px; height: 30px;
} }
.my-tab-item {
vertical-align: middle;
text-align: center;
line-height: 40px;
margin-right: 20px;
padding: 0 15px 12px 15px;
cursor: pointer;
}
.my-tab-item-select {
border: none;
border-radius: 0;
border-bottom: 2px solid #5FB878;
}
.my-tab-content {
height: 300px;
}
</style> </style>
</head> </head>
<body> <body>
...@@ -80,8 +95,13 @@ ...@@ -80,8 +95,13 @@
<div class="layui-row layui-col-space10"> <div class="layui-row layui-col-space10">
<div class="layui-col-lg12 layui-col-md12"> <div class="layui-col-lg12 layui-col-md12">
<div class="layui-card"> <div class="layui-card">
<div class="card-block"> <div class="layui-card-header">
<div id="week-container" style="height:350px"></div> <a id="weekTab" class="my-tab-item my-tab-item-select">周流量趋势</a>
<a id="dayTab" class="my-tab-item">天流量趋势</a>
</div>
<div class="layui-card-body">
<div id="week-container" tabId="weekTab" class="my-tab-content"></div>
<div id="date-container" tabId="dayTab" class="my-tab-content" style="display: none"></div>
</div> </div>
</div> </div>
</div> </div>
...@@ -105,75 +125,114 @@ ...@@ -105,75 +125,114 @@
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
layui.use(['admin'], function () { layui.use(['admin', "echarts"], function () {
let admin = layui.admin; let admin = layui.admin;
let echarts = layui.echarts;
let statData;
let browserChart = echarts.init(document.getElementById("browser-container")); $(".my-tab-item").click(function() {
let selectId = $(this).attr('id');
$(".my-tab-item").each(function() {
let eachId = $(this).attr('id');
if (eachId === selectId) {
$(this).addClass("my-tab-item-select");
} else {
$(this).removeClass("my-tab-item-select");
}
});
$("[tabId]").each(function() {
let tabId = $(this).attr('tabId');
if (tabId === selectId) {
$(this).show();
if ($(this).html().length === 0) {
showDateChart($(this).attr('id'));
}
} else {
$(this).hide();
}
});
});
let showDateChart = function (contetnId) {
let dateChart = echarts.init(document.getElementById(contetnId), layui.echartsTheme);
dateChart.setOption({
tooltip: {trigger: "axis"},
legend: {
data: ['访问量(PV)', '独立用户(UV)']
},
xAxis: [
{
type: 'category',
boundaryGap: !1,
data: statData.statDate_items
}
],
yAxis: [{type: "value"}],
series: [
{
name: '访问量(PV)',
type: 'line',
smooth: !0,
itemStyle: {normal: {areaStyle: {type: "default"}}},
data: statData.statDate_pv
},
{
name: '独立用户(UV)',
type: 'line',
smooth: !0,
itemStyle: {normal: {areaStyle: {type: "default"}}},
data: statData.statDate_uv
}
]
});
}
let browserChart = echarts.init(document.getElementById("browser-container"), layui.echartsTheme);
browserChart.setOption({ browserChart.setOption({
title : { title : {
text: '浏览器分布', text: '浏览器分布',
subtext: '', subtext: '',
x:'center' x:'center'
}, },
tooltip : { tooltip: {trigger: "item", formatter: "{a} <br/>{b} : {c} ({d}%)"},
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {}, legend: {},
series : [] series : []
}); });
browserChart.showLoading(); browserChart.showLoading();
let osChart = echarts.init(document.getElementById("operatingSystem-container")); let osChart = echarts.init(document.getElementById("operatingSystem-container"), layui.echartsTheme);
osChart.setOption({ osChart.setOption({
title : { title : {
text: '系统分布', text: '系统分布',
subtext: '', subtext: '',
x:'center' x:'center'
}, },
tooltip : { tooltip: {trigger: "item", formatter: "{a} <br/>{b} : {c} ({d}%)"},
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {}, legend: {},
series : [] series : []
}); });
osChart.showLoading(); osChart.showLoading();
let weekChart = echarts.init(document.getElementById("week-container")); let weekChart = echarts.init(document.getElementById("week-container"), layui.echartsTheme);
weekChart.setOption({ weekChart.setOption({
title: { tooltip: {trigger: "axis"},
text: '流量趋势'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: { legend: {
data: ['访问量(PV)', '独立用户(UV)'] data: ['访问量(PV)', '独立用户(UV)']
}, },
xAxis: [ xAxis: [
{ {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: !1,
data: [] data: []
} }
], ],
yAxis: [ yAxis: [{type: "value"}],
{
type: 'value'
}
],
series: [] series: []
}); });
weekChart.showLoading(); weekChart.showLoading();
admin.req('api-log/requestStat', {}, function (data) { admin.req('api-log/requestStat', {}, function (data) {
statData = data;
$('#pv').html(data.currDate_pv); $('#pv').html(data.currDate_pv);
$('#uv').html(data.currDate_uv); $('#uv').html(data.currDate_uv);
$('#weekPv').html(data.currWeek_pv); $('#weekPv').html(data.currWeek_pv);
...@@ -184,23 +243,16 @@ ...@@ -184,23 +243,16 @@
browserChart.setOption({ browserChart.setOption({
legend: { legend: {
orient: 'vertical', orient: 'vertical',
left: 'left', x: 'left',
data: data.browser_legendData data: data.browser_legendData
}, },
series : [ series : [
{ {
name: '浏览器', name: '访问来源',
type: 'pie', type: 'pie',
radius : '55%', radius : '55%',
center: ['50%', '60%'], center: ['60%', '60%'],
data: data.browser_datas, data: data.browser_datas
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
} }
] ]
}); });
...@@ -209,7 +261,7 @@ ...@@ -209,7 +261,7 @@
osChart.setOption({ osChart.setOption({
legend: { legend: {
orient: 'vertical', orient: 'vertical',
left: 'left', x: 'left',
data: data.operatingSystem_legendData data: data.operatingSystem_legendData
}, },
series : [ series : [
...@@ -217,15 +269,8 @@ ...@@ -217,15 +269,8 @@
name: '操作系统', name: '操作系统',
type: 'pie', type: 'pie',
radius : '55%', radius : '55%',
center: ['50%', '60%'], center: ['60%', '60%'],
data: data.operatingSystem_datas, data: data.operatingSystem_datas
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
} }
] ]
}); });
...@@ -235,7 +280,7 @@ ...@@ -235,7 +280,7 @@
xAxis: [ xAxis: [
{ {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: !1,
data: data.statWeek_items data: data.statWeek_items
} }
], ],
...@@ -243,19 +288,15 @@ ...@@ -243,19 +288,15 @@
{ {
name: '访问量(PV)', name: '访问量(PV)',
type: 'line', type: 'line',
areaStyle: {}, smooth: !0,
label: { itemStyle: {normal: {areaStyle: {type: "default"}}},
normal: {
show: true,
position: 'top'
}
},
data: data.statWeek_pv data: data.statWeek_pv
}, },
{ {
name: '独立用户(UV)', name: '独立用户(UV)',
type: 'line', type: 'line',
areaStyle: {}, smooth: !0,
itemStyle: {normal: {areaStyle: {type: "default"}}},
data: data.statWeek_uv data: data.statWeek_uv
} }
] ]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册