产品原型地址:
https://app.mockplus.cn/run/prototype/wDiGCuki3_/iLu4KtCQ8ew/1Bv0BoAUyv
1. 设备状态统计 1.1 需求分析系统内要在首页以饼图的方式显示不同状态设备的占比百分比分布,具体效果如下图:
![](images/4-1.png)
1.2 实现思路(1)编写从ElasticSearch中获取断网设备总数、断网数量、告警数量的方法
(2)通过运算的到正常设备数,将数据组合成前端需要的数据格式返回
1.3 代码实现 1.3.1 设备数量统计(1)在ESRepository添加统计全部设备数量的方法:
public Long getAllDeviceCount(){ CountRequest countRequest=new CountRequest("devices"); countRequest.query( QueryBuilders.matchAllQuery() ); try { CountResponse response = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT); return response.getCount(); } catch (IOException e) { e.printStackTrace(); return 0L; } }
(2)在ESRepository添加统计离线设备数量的方法:
public Long getOfflineCount(){ CountRequest countRequest=new CountRequest("devices"); BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery(); boolQueryBuilder.must( QueryBuilders.termQuery("online",false) ); countRequest.query( boolQueryBuilder ); try { CountResponse response = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT); return response.getCount(); } catch (IOException e) { e.printStackTrace(); return 0L; } }
(3)在ESRepository添加统计报警设备数量的方法:
public Long getAlarmCount(){ CountRequest countRequest=new CountRequest("devices"); BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery(); boolQueryBuilder.must( QueryBuilders.termQuery("online",true) ); boolQueryBuilder.must( QueryBuilders.termQuery("alarm",true) ); countRequest.query( boolQueryBuilder ); try { CountResponse response = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT); return response.getCount(); } catch (IOException e) { e.printStackTrace(); return 0L; } }
编写单元测试:
@Test public void testCount(){ Long allDeviceCount = esRepository.getAllDeviceCount();//设备总数 System.out.println("设备总数:"+allDeviceCount); Long offlineCount = esRepository.getOfflineCount();//离线设备数量 System.out.println("离线设备:"+offlineCount); Long alarmCount = esRepository.getAlarmCount();//告警设备数量 System.out.println("告警设备:"+alarmCount); }1.3.2 设备状态分布
(1)添加vo,用于状态占比的封装
前端采用的图表工具是EChars,EChars饼图需要数据格式如下:
data: [ {value: 10200, name: '正常运转'}, {value: 310, name: '离线'}, {value: 234, name: '报警'} ]
API 定义如下:
![](images/4-90.png)
我们根据前端需要的格式定义vo
package com.yikekong.vo; import lombok.Data; @Data public class PieVO { private String name;//名称 private Long value;//值 }
(2)创建报表服务接口ReportService,并定义获取设备状态分布的方法
package com.yikekong.service; import com.yikekong.vo.PieVO; import java.util.List; public interface ReportService { ListgetStatusCollect(); }
创建实现类,并在实现类中实现该方法
package com.yikekong.service.impl; import com.google.common.collect.Lists; import com.yikekong.es.ESRepository; import com.yikekong.service.ReportService; import com.yikekong.vo.PieVO; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service @Slf4j public class ReportServiceImpl implements ReportService { @Autowired private ESRepository esRepository; @Override public ListgetStatusCollect() { Long allDeviceCount = esRepository.getAllDeviceCount();//全部设备数量 Long offlineCount = esRepository.getOfflineCount();//离线设备数量 Long alarmCount = esRepository.getAlarmCount();//报警设备数量 PieVO devicePie=new PieVO(); devicePie.setName("正常运转"); devicePie.setValue(allDeviceCount-offlineCount-alarmCount); PieVO offlinePie=new PieVO(); offlinePie.setName("离线"); offlinePie.setValue(offlineCount); PieVO alarmPie =new PieVO(); alarmPie.setName("报警"); alarmPie.setValue(alarmCount); List pieVOList= Lists.newArrayList(); pieVOList.add(devicePie); pieVOList.add(offlinePie); pieVOList.add(alarmPie); return pieVOList; } }
(3)DeviceController新增方法
package com.yikekong.controller; import com.yikekong.service.ReportService; import com.yikekong.vo.PieVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("/report") public class ReportController { @Autowired private ReportService reportService; @GetMapping("/statusCollect") public List1.3.3 实时监控数据getStatusCollect(){ return reportService.getStatusCollect(); } }
首页还需要显示设备数量和报警设备数
![](images/4-4.png)
API设计:
![](images/4-5.png)
(1)创建vo类 MonitorVO
@Data public class MonitorVO implements Serializable{ private Long deviceCount; private Long alarmCount; }
(2)ReportController新增方法
@Autowired private ESRepository esRepository; @GetMapping("/monitor") public MonitorVO getMonitorData(){ MonitorVO monitor = new MonitorVO(); monitor.setDeviceCount(esRepository.getAllDeviceCount()); monitor.setAlarmCount(esRepository.getAlarmCount()); return monitor; }2. 异常告警趋势报表 2.1 需求分析
系统要能够根据当前1小时内(每分钟第一次数据,当前分钟无数据,显示上一次数据)、当前1天内(每小时第一次数据,当前小时无数据,显示上一次数据)、当前7天内(7天小时数据的展示),汇总出每一个时间点上报的异常总数,然后前端根据这些数据以折现图的形式进行展现。
具体时间筛选和展现的格式如下:
![](images/3-7.png)
横轴显示时间,纵轴显示的是告警次数汇总值数量。
2.2 实现思路(1)查询influxdb中的quota表,根据时间点进行分组统计
(2)在服务层实现对语句的封装,转化成前端需要的数据格式
2.3 代码实现 2.3.1 influxdb时间分组统计日期格式化命令,执行后可以显示年月日小时分秒
precision rfc3339
执行查询
select count(value) from quota where alarm='1' and time>='2020-09-01' and time<='2020-09-30' group by time(1d)
得到运行结果
![](images/3-9.png)
这里需要说明的是:
在要执行的sql里的group by分组里使用了InfluxDB的time时间函数
group by time(1m):按每分钟进行分组汇总group by time(1h):按每小时进行分组汇总groupby time(1d):按每天进行分组汇总
之后配合select中的count函数就可以获取到具体时间维度里汇总里的总数了,这样就能获取到我们想要的汇总数据了。
InfluxDB除了会根据sql语句返回pointValue也会同时返回每一条数据对应的time时间列。
2.3.2 告警趋势统计(1)定义从InfluxDB中查询结果的pojo类:
package com.yikekong.dto; import lombok.Data; import org.influxdb.annotation.Column; import org.influxdb.annotation.Measurement; import java.io.Serializable; @Data @Measurement(name = "quota") public class TrendPoint implements Serializable{ @Column(name = "time") private String time; @Column(name = "pointValue") private Integer pointValue; }
(3)在ReportService接口中定义获取异常指标趋势的方法:
ListgetAlarmTrend(String start, String end, int type);
在实现类ReportServiceImpl中实现该方法:
@Autowired private InfluxRepository influxRepository; @Override public ListgetAlarmTrend(String start, String end, int type) { StringBuilder ql=new StringBuilder("select count(value) as pointValue from quota where alarm='1' "); ql.append("and time>='"+ start +"' and time<='"+ end+"' "); if(type==1){ ql.append("group by time(1m)"); } if(type==2){ ql.append("group by time(1h)"); } if(type==3){ ql.append("group by time(1d)"); } List trendPointList = influxRepository.query(ql.toString(), TrendPoint.class); return trendPointList; }
单元测试:
@Autowired private ReportService reportService; @Test public void testAlarmTrend(){ ListtrendPointList = reportService.getAlarmTrend("2020-09-01", "2020-09-30", 3); for(TrendPoint trendPoint:trendPointList){ try { System.out.println(JsonUtil.serialize(trendPoint)); } catch (JsonProcessingException e) { e.printStackTrace(); } } }
分别尝试getAlarmTrend的第2个参数为 1、 2、 3 ,观察测试结果,下面是参数为3的测试结果:
{"time":"2020-09-01T00:00:00Z","pointValue":0} {"time":"2020-09-02T00:00:00Z","pointValue":0} {"time":"2020-09-03T00:00:00Z","pointValue":0} {"time":"2020-09-04T00:00:00Z","pointValue":0} {"time":"2020-09-05T00:00:00Z","pointValue":0} {"time":"2020-09-06T00:00:00Z","pointValue":0} {"time":"2020-09-07T00:00:00Z","pointValue":0} {"time":"2020-09-08T00:00:00Z","pointValue":0} {"time":"2020-09-09T00:00:00Z","pointValue":0} {"time":"2020-09-10T00:00:00Z","pointValue":0} {"time":"2020-09-11T00:00:00Z","pointValue":0} {"time":"2020-09-12T00:00:00Z","pointValue":0} {"time":"2020-09-13T00:00:00Z","pointValue":0} {"time":"2020-09-14T00:00:00Z","pointValue":0} {"time":"2020-09-15T00:00:00Z","pointValue":0} {"time":"2020-09-16T00:00:00Z","pointValue":0} {"time":"2020-09-17T00:00:00Z","pointValue":0} {"time":"2020-09-18T00:00:00Z","pointValue":0} {"time":"2020-09-19T00:00:00Z","pointValue":2} {"time":"2020-09-20T00:00:00Z","pointValue":0} {"time":"2020-09-21T00:00:00Z","pointValue":0} {"time":"2020-09-22T00:00:00Z","pointValue":2379} {"time":"2020-09-23T00:00:00Z","pointValue":0} {"time":"2020-09-24T00:00:00Z","pointValue":14412} {"time":"2020-09-25T00:00:00Z","pointValue":5} {"time":"2020-09-26T00:00:00Z","pointValue":0} {"time":"2020-09-27T00:00:00Z","pointValue":0} {"time":"2020-09-28T00:00:00Z","pointValue":0} {"time":"2020-09-29T00:00:00Z","pointValue":0} {"time":"2020-09-30T00:00:00Z","pointValue":0}2.3.3 报表数据封装
前端采用的图表工具是EChars,折线图所需的数据格式为:
xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, yAxis: { type: 'value' }, series: [{ data: [820, 932, 901, 934, 1290, 1330, 1320], type: 'line' }]
以上格式可以在 [https://echarts.apache.org/examples/zh/index.html](https://echarts.apache.org/examples/zh/index.html) 查询
API定义接口定义如下:
![](images/4-7.png)
![](images/4-6.png)
(1)定义前端展示需要的VO类,代码如下:
package com.yikekong.vo; import lombok.Data; import java.io.Serializable; import java.util.List; @Data public class LineVO implements Serializable { private Listxdata;//x轴 private List series;//数据 }
(2)在ReportController中添加方法调用getAlarmTrend获取数据并做转换返回给前端
@GetMapping("/trend/{startTime}/{endTime}/{type}") public LineVO getQuotaTrendCollect(@PathVariable String startTime,@PathVariable String endTime,@PathVariable Integer type){ ListtrendPointList = reportService.getAlarmTrend(startTime, endTime, type); LineVO lineVO=new LineVO(); lineVO.setXdata(Lists.newArrayList()); lineVO.setSeries(Lists.newArrayList()); trendPointList.forEach( t->{ lineVO.getXdata().add( t.getTime() ); lineVO.getSeries().add( t.getPointValue().longValue()); }); return lineVO; }
测试:
http://127.0.0.1:9093/report/trend?start=2020-08-01&end=2020-08-31&type=3
2.3.4 时间格式处理需求:
经过刚才的测试,我们返回的日期格式是 2020-09-01T00:00:00Z。但是前端需要的格式是
如果是分钟,显示分钟值
如果是小时,显示小时值
如果是日,显示 xx月xx日
(1)ReportController新增私有方法,用于格式化日期串
private String formatTime(String time,int type){ LocalDateTime localTime = LocalDateTime.parse(time,DateTimeFormatter.ISO_OFFSET_DATE_TIME); if(type == 1){ return localTime.getMinute()+""; }else if(type == 2){ return localTime.getHour()+""; }else if(type == 3){ return localTime.getMonthValue()+"月"+localTime.getDayOfMonth()+"日"; } return time; }
(2)修改getAlarmTrend方法,调用formatTime实现日期格式化
@GetMapping("/trend/{startTime}/{endTime}/{type}") public LineVO getQuotaTrendCollect(@PathVariable String startTime,@PathVariable String endTime,@PathVariable Integer type){ List3. 告警次数top10设备指标报表 3.1 需求分析trendPointList = reportService.getAlarmTrend(startTime, endTime, type); LineVO lineVO=new LineVO(); lineVO.setXdata(Lists.newArrayList()); lineVO.setSeries(Lists.newArrayList()); trendPointList.forEach( t->{ lineVO.getXdata().add( formatTime(t.getTime(),type) );//修改这一句 lineVO.getSeries().add( t.getPointValue().longValue()); }); return lineVO; }
系统需要展示出当前一小时内、当前1天内、当前7天内的告警次数最多的前10的设备及指标,以柱状图展示,展示效果如下:
![](images/3-8.png)
其中纵轴展示的是设备编号+指标名称,横轴用来展示告警次数,按照从多到少进行排列。
3.2 实现思路(1)编写查询语句,实现异常次数top10统计。我们这里会学习一个新的函数top。
(2)定义InfluxDB中检索出的具体pojo类,包括属性有设备id、指标id、指标名称、统计出来的次数
(3)在AlarmService服务接口里定义获取在一定时间范围内的top10告警设备指标,在实现类里进行实现
(4) 在Controller中调用Service中的方法获取数据返回给前端
3.3 代码实现 3.3.1 告警次数top10查询(1)首先编写查询语句,根据设备ID和指标ID分组查询报警数量
select count(value) as heapValue from quota where alarm='1' and time>='2020-09-01' and time<='2020-09-30' group by deviceId,quotaId,quotaName
注意:在标准的SQL语法中,分组的条件是必须出现在select字句后边的,而influxQL不用那么写。
上边的语句运行效果如下:
![](images/4-8.png)
(2)上边的结果其实是我们要的中间结果,我们还应该在此结果基础上得到前10的数据,需要用到top函数
select top(heapValue,deviceId,quotaId,quotaName,10) as heapValue from ( select count(value) as heapValue from quota where alarm='1' and time>='2020-09-01' and time<='2020-09-30' group by deviceId,quotaId ) order by desc
top函数第一个参数是需要排序的字段,最后一个参数是得到的结果数量,中间的参数是需要列出的其它数据。
上边的语句运行结果如下:
![](images/4-9.png)
3.3.2 报表数据查询与封装API设计如下:
![](images/4-10.png)
(1)定义top10对应的pojo类
package com.yikekong.dto; import lombok.Data; import org.influxdb.annotation.Column; import org.influxdb.annotation.Measurement; import java.io.Serializable; @Data @Measurement(name = "quota") public class HeapPoint implements Serializable{ @Column(name = "deviceId") private String deviceId; @Column(name = "heapValue") private Double heapValue; @Column(name = "quotaId") private String quotaId; @Column(name = "quotaName") private String quotaName; }
(2)在ReportService服务接口里定义获取数据的方法
ListgetTop10Alarm(String startTime, String endTime);
在ReportServiceImpl实现类里实现该方法:
@Override public ListgetTop10Alarm(String startTime, String endTime) { StringBuilder sbSql = new StringBuilder("select top(heapValue,deviceId,quotaId,quotaName,10) as heapValue " + " from(select count(value) as heapValue from quota where alarm='1' "); sbSql.append("and time>='"); sbSql.append(startTime); sbSql.append("' and time<='"); sbSql.append(endTime); sbSql.append("' group by deviceId,quotaId) order by desc"); return influxDBRepository.query(sbSql.toString(),HeapPoint.class); }
这里sql语句的具体实现思路是:sql子查询里获取的是一定时间范围之内根据设备和指标分组之后的告警总数,然后在外部查询里用top函数对倒序之后的结果集取前十就能获取到我们想要的数据。
(3)在ReportController里添加获取前十数据的方法,在该方法里调用服务层的方法返回给前端:
@GetMapping("/top10Alarm/{startTime}/{endTime}") public List4. 自定义指标看板 4.1 需求分析getTop10Alarm(@PathVariable String startTime, @PathVariable String endTime){ return reportService .getTop10Alarm(startTime,endTime); }
系统管理人员能够在系统里可以添加自定义的看板来展示数据,该自定义看板是用户自己选择的指标,及根据指标自主选取上报该指标的一些设备,以方便跟踪和观察该指标下相关设备的趋势,展示的趋势也是多个维度的,按照小时展示当前1小时内60分钟的指标相关设备趋势;按照1天24小时展示当天每小时的指标设备趋势;按照7天展示最近7天之内24小时的指标设备趋势。
添加看板的原型图如下:
![](images/4-2.png)
在首页展示已经添加的看板原型设计如下:
![](images/4-3.png)
横轴展示的是时间,纵轴的数据是每个时间点内的设备首次上报指标数据。
4.2 实现思路(1)在系统添中加看板时只能选择数值型指标,从mysql数据库中分页加载所有数值型指标,指标是单选
(2)添加看板时选择完指标之后,在选择设备时只能选择之前已经选择好的指标下的上报过该指标的设备,设备是多选,最多选择10个设备
(3)在向前端提供数据时,先从mysql中查询出该面板的指标Id,及对应的所有设备编号,根据前端传入的时间类型从InfluxDB中循环获取相应时间段内,对应时间的所有设备指标的首次指标数值
(4)将所有数据组合成前端想要的数据格式返回
4.3 代码实现 4.3.1 获取数值型指标列表![](images/4-11.png)
(1)从mysql数据库中分页加载所有数值型指标,在QuotaService接口中定义方法
IPagequeryNumberQuota(Long page, Long pageSize);
在QuotaServiceImpl实现类中实现该方法:
@Override public IPagequeryNumberQuota(Long page, Long pageSize) { Page pageResult = new Page<>(page,pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper .eq(QuotaEntity::getValueType,"Long") .or() .eq(QuotaEntity::getValueType,"Integer") .or() .eq(QuotaEntity::getValueType,"Double"); return this.page(pageResult,wrapper); }
(2)在QuotaController中添加获取该数据的接口,调用上述方法返回数据给前端
@GetMapping("/numberQuota") public Pager4.3.2 获取某指标相关的设备queryNumberQuota(@RequestParam(value = "page",required = false,defaultValue = "1") Long page, @RequestParam(value = "pageSize",required = false,defaultValue = "10") Long pageSize){ return new Pager<>(quotaService.queryNumberQuota(page,pageSize)); }
(1)查询语句
由于设备数量多,所以我们需要采用分页查询。语句如下:
select distinct(deviceId) as deviceId from(select deviceId,value from quota where quotaId='1' group by deviceId,quotaId) limit 10 OFFSET 0
编写语句获取设备数量,用于分页
select count(distinct(deviceId)) as deviceCount from(select deviceId,value from quota where quotaId='' group by deviceId,quotaId)
(2)在ReportService接口中定义通过指标ID获取关联设备的方法
PagergetDeviceByQuota(Long page,Long pageSize,String quotaId);
在ReportServiceImpl实现类中实现该方法:
@Override public PagergetDeviceByQuota(Long page, Long pageSize, String quotaId) { String fromQl=" from ( select deviceId,value from quota where quotaId='"+ quotaId+"' group by deviceId,quotaId ) "; String listQl="select distinct(deviceId ) as deviceId "+fromQl+" limit "+pageSize +" offset "+(page-1)*pageSize; String countQl=" select count( distinct(deviceId )) as count "+fromQl; List quotaInfoList = influxRepository.query(listQl, QuotaInfo.class); //设备id列表 List deviceIdList = quotaInfoList.stream().map(quotaInfo -> quotaInfo.getDeviceId()).collect(Collectors.toList()); //统计记录个数 List quotaCountList = influxRepository.query(countQl, QuotaCount.class); if( quotaCountList==null || quotaCountList.size()==0 ){ Pager pager=new Pager (0L,0L); pager.setItems(Lists.newArrayList()); return pager; } Long count = quotaCountList.get(0).getCount(); Pager pager=new Pager (count,pageSize); pager.setItems(deviceIdList); return pager; }
(3)在ReportController中添加获取该数据的接口,调用上述方法返回数据给前端:
@GetMapping("/devices") public Pager4.3.3 按设备指标查询指标值序列getDeviceByQuota( @RequestParam(value = "page",required = false,defaultValue = "1") Long page, @RequestParam(value = "pageSize",required = false,defaultValue = "10") Long pageSize, @RequestParam(value = "quotaId")String quotaId){ return reportService.getDeviceByQuota(page,pageSize,quotaId); }
(1)编写查询语句
select first(value) as pointValue from quota where time>='2020-09-01' and time<='2020-09-30' and quotaId='1' and deviceId='100001' group by time(1d)
为了更方便的查看运行效果,我们需要先执行precision rfc3339设置时间显示格式
执行结果如下:
![](images/4-12.png)
(2)编写封装类
package com.yikekong.dto; import lombok.Data; import org.influxdb.annotation.Column; import org.influxdb.annotation.Measurement; import java.io.Serializable; @Data @Measurement(name = "quota") public class TrendPoint2 implements Serializable { @Column(name = "time") private String time;//时间 @Column(name = "pointValue") private Double pointValue;//时间点数据 }
(3)在ReportService接口中定义获取一段时间之内某一指标下的趋势指标点集合的方法
ListgetQuotaTrend( String start, String end, String quotaId,String deviceId,int type);
在ReportServiceImpl实现类中实现该方法
@Override public ListgetQuotaTrend(String startTime, String endTime, String quotaId, String deviceId, int type) { StringBuilder ql=new StringBuilder("select first(value) as pointValue from quota "); ql.append("where time>='"+ startTime+"' and time<='"+ endTime +"' " ); ql.append("and quotaId='"+quotaId +"' "); ql.append("and deviceId='"+ deviceId +"' "); if(type==1){ //1小时 ql.append("group by time(1m)"); } if(type==2){ //1天 ql.append("group by time(1h)"); } if(type==3){ //7天 ql.append("group by time(1d)"); } List trendPoint2List = influxRepository.query(ql.toString(), TrendPoint2.class); return trendPoint2List; }
单元测试:
@Test public void testQuotaTrend(){ ListtrendPoint2List = reportService.getQuotaTrend("2020-09-01 00:00:00", "2020-09-30 23:59:59" , "1", "100001", 3); for( TrendPoint2 trendPoint2:trendPoint2List ){ try { System.out.println( JsonUtil.serialize(trendPoint2) ); } catch (JsonProcessingException e) { e.printStackTrace(); } } }
测试结果如下:
![](images/4-13.png)
4.3.4 空缺数据补全通过上边单元测试的结果,我们发现有很多时间节点并没有值。如果为null值我们在曲线图中该如何显示呢?按0处理吗?显然是不合理的。比如温度来说,温度为0和没有温度数据很显然含义不同!
所以我们这里对空缺的数据做一下处理,处理规则是:
如果某节点的值为null,那么就设置为上一个不为null的值
如果该序列的第一个值为null,则第一个值到第一个不为null的值前面的所有值都为第一个不为null的值。
代码编写如下:
(1)ReportServiceImpl新增私有方法
private Listreplenish(List trendPoint2List){ Double previousValue=null;// 上一个值 for(TrendPoint2 trendPoint2: trendPoint2List ){ if(trendPoint2.getPointValue()!=null){ previousValue=trendPoint2.getPointValue(); break; } } if(previousValue==null){ previousValue=0d; } //数据填充逻辑 for( TrendPoint2 trendPoint2: trendPoint2List){ if(trendPoint2.getPointValue()==null){ trendPoint2.setPointValue(previousValue); } previousValue=trendPoint2.getPointValue(); } return trendPoint2List; }
(2)修改getQuotaTrend方法的返回值
return replenish(trendPoint2List);4.3.5 报表数据预览
前端要求返回的格式如下:
{ "xdata": [ "8月1日", "8月2日", "8月3日" ], "series": [ { "name": "100001", "data": [ 70, 90, 100 ] }, { "name": "100002", "data": [ 50, 60, 80, ] } ], "name": "面板名称" }
(1)定义vo用于封装某个指标的数据序列
package com.yikekong.vo; import lombok.Data; import java.io.Serializable; import java.util.List; @Data public class BoardQuotaData implements Serializable{ private String name; private Listdata; }
(2)定义vo,用于封装整个报表的数据结构
package com.yikekong.vo; import lombok.Data; import java.io.Serializable; import java.util.List; @Data public class BoardQuotaVO implements Serializable{ private Listxdata; private List series; private String name; }
(3)在ReportService接口中定义获取面板指标数据的方法
BoardQuotaVO getBoardData(String quotaId,ListdeviceIds,String startTime,String endTime,Integer type );
在ReportServiceImpl实现类中实现该方法
@Override public BoardQuotaVO getBoardData(String quotaId, ListdeviceIds, String startTime, String endTime, Integer type) { //参数校验 if( quotaId==null || deviceIds==null || deviceIds.size()==0 ){ return new BoardQuotaVO(); } BoardQuotaVO boardQuotaVO=new BoardQuotaVO(); boardQuotaVO.setSeries( Lists.newArrayList()); for( String deviceId:deviceIds ){ //循环每个设备 //每个设备的指标趋势 List trendPoint2List = getQuotaTrend(startTime, endTime, quotaId, deviceId, type); //x轴 if(boardQuotaVO.getXdata()==null){ boardQuotaVO.setXdata( trendPoint2List.stream().map(trendPoint2 -> trendPoint2.getTime() ).collect( Collectors.toList() ) ); } //数据 BoardQuotaData boardQuotaData=new BoardQuotaData(); boardQuotaData.setName( deviceId ); boardQuotaData.setData( trendPoint2List.stream().map( trendPoint2 -> trendPoint2.getPointValue() ).collect(Collectors.toList()) ); boardQuotaVO.getSeries().add(boardQuotaData); } return boardQuotaVO; }
(4)构建vo用于预览报表传入参数
package com.yikekong.vo; import lombok.Data; import java.util.List; @Data public class PreviewVO { private String quotaId; private ListdeviceIdList; private Integer type; private String start; private String end; }
(5)在ReportController调用方法将数据返回给前端
@PostMapping("/preview") public BoardQuotaVO getPreviewData( @RequestBody PreviewVO previewVO ){ BoardQuotaVO boardData = reportService.getBoardData( previewVO.getQuotaId(), previewVO.getDeviceIdList(), previewVO.getStart(), previewVO.getEnd(), previewVO.getType()); //时间处理 Listxdata=Lists.newArrayList(); for(String x:boardData.getXdata()){ xdata.add(formatTime(x,previewVO.getType() )) ; } boardData.setXdata(xdata); return boardData; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)