1.数据可视化 Apache Echarts
1.1 介绍
Apache ECharts是一款基于 Javascript 的数据可视化图表库,常见形式有柱形图,折线图,饼图。此处以营业额统计为例,展示一下该图表库在程序中的具体应用。
https://echarts.apache.org/zh/index.html
1.2 营业额统计
1.2.1 需求分析
营业额统计是基于折现图来实现的,并且按照天来展示的。实际上,就是展示某一个时间段之内的每一天的营业额,将光标放在某个点上,那么它就会把具体的数值展示出来。并且还需要注意日期并不是固定写死的,是由上边时间选择器来决定。比如选择是近7天、或者是近30日,或者是本周,就会把相应这个时间段之内的日期通过横坐标展示出来,如下图所示。 ![![[Pasted image 20260315135853.png]]](https://www.171host.com/wp-content/uploads/2026/03/20260315173002-69b6ec9a222fd.png)
1.2.2 代码实现
(1)Controller层:在admin包下创建ReportController类
@RestController
@RequestMapping("/admin/report")
@Slf4j
@Api(tags = "数据统计相关接口")
public class ReportController {
@Autowired
private ReportService turnoverReportService;
@Autowired
private ReportService reportService;
//营业额统计
@GetMapping("/turnoverStatistics")
@ApiOperation("营业额统计")
public Result<TurnoverReportVO> turnoverStatistics(
@DateTimeFormat(pattern = "yyyy-MM-dd")
LocalDate begin,
@DateTimeFormat(pattern = "yyyy-MM-dd")
LocalDate end) {
log.info("营业额统计");
TurnoverReportVO turnoverReportVO = turnoverReportService.getTurnover(begin, end);
return Result.success(turnoverReportVO);
}
(2)Service层:创建ReportService接口,并定义相关方法
public interface ReportService {
/**
* 根据时间区间统计营业额
* @param beginTime
* @param endTime
* @return
*/
TurnoverReportVO getTurnover(LocalDate beginTime, LocalDate endTime);
}
(3)ServiceImpl层:创建ReportServiceImpl实现类,实现getTurnOver方法
@Service
@Slf4j
public class ReportServiceImpl implements ReportService {
@Autowired
private OrderMapper orderMapper;
/**
* 根据时间区间统计营业额
* @param begin
* @param end
* @return
*/
public TurnoverReportVO getTurnover(LocalDate begin, LocalDate end) {
List<LocalDate> dateList = new ArrayList<>();
dateList.add(begin);
while (!begin.equals(end)){
begin = begin.plusDays(1);//日期计算,获得指定日期后1天的日期
dateList.add(begin);
}
List<Double> turnoverList = new ArrayList<>();
for (LocalDate date : dateList) {
LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
Map map = new HashMap();
map.put("status", Orders.COMPLETED);
map.put("begin",beginTime);
map.put("end", endTime);
Double turnover = orderMapper.sumByMap(map);
turnover = turnover == null ? 0.0 : turnover;
turnoverList.add(turnover);
}
//数据封装
return TurnoverReportVO.builder()
.dateList(StringUtils.join(dateList,","))
.turnoverList(StringUtils.join(turnoverList,","))
.build();
}
}
(4)Mapper层:在OrderMapper层中定义方法sumByMap
/**
* 根据动态条件统计营业额
* @param map
*/
Double sumByMap(Map map);
(5)xml层:在OrderMapper.xml文件中用动态sql去实现查询
<select id="sumByMap" resultType="java.lang.Double">
select sum(amount) from orders
<where>
<if test="status != null">
and status = #{status}
</if>
<if test="begin != null">
and order_time >= #{begin}
</if>
<if test="end != null">
and order_time <= #{end}
</if>
</where>
</select>
2.数据导出 Apache Poi
2.1 介绍
(1)Apache POI 是Java处理Miscrosoft Office各种文件格式的一个重要库。简单来说就是,我们可以使用 POI 在 Java 程序中对Miscrosoft Office 各种文件进行读写操作,主要用于处理Excel文件。
(2)常见应用场景:银行网银系统导出交易明细,各种业务系统导出Excel报表,批量导入业务数据等。
2.2 导出运营数据Excel报表
2.2.1 需求分析
在数据统计页面,有一个数据导出按钮,点击该按钮时就会下载一个Excel文件,文件内容会显示最近30日运营相关的数据。因为这个Excel文件模板是固定的,所以只需要通过程序读取该模板文件,然后往空白格填充数据即可。 ![![[Pasted image 20260315150122.png]]](https://www.171host.com/wp-content/uploads/2026/03/20260315173003-69b6ec9b97640.png)
模板文件如下 ![![[Pasted image 20260315150554.png|366]]](https://www.171host.com/wp-content/uploads/2026/03/20260315173005-69b6ec9d26c68.png)
2.2.2 代码实现
(1)在sky-server包下的resource文件下创建template目录,将资料中的模板文件运营数据报表模板.xlsx拷贝到该目录下
(2)Controller层:在admin包下的ReportController中创建export方法
/**
* 运营数据报表导出
*/
@GetMapping("/export")
@ApiOperation("运营数据导出")
public void export(HttpServletResponse response){
//导出excel文件实际上是在响应给客户端时显示下载文件,所以通过响应体将输出流传递过去
reportService.export(response);
}
(3)Service层:在ReportService接口中创建导出运营数据报表的方法
/**
* 运营数据报表导出
*/
void export(HttpServletResponse response);
(4)ServiceImpl层:在ReportServiceImpl类中实现上述export方法
/**
* 导出运营数据报表
* @param response
*/
@Override
public void export(HttpServletResponse response) {
//1.读取模板文件
InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
try {
//2.往模板文件的指定位置填充数据
XSSFWorkbook excel = new XSSFWorkbook(in);
//获取第一个sheet页
XSSFSheet sheet = excel.getSheetAt(0);
//获取指定行数和单元格
LocalDate begin = LocalDate.now().minusDays(30);
LocalDate end = LocalDate.now().minusDays(1);
sheet.getRow(1).getCell(1).setCellValue(begin.toString() + "至" + end.toString());
//填充概览数据
BusinessDataVO businessData = workspaceService.getBusinessData(LocalDateTime.of(begin, LocalTime.MIN), LocalDateTime.of(end, LocalTime.MAX));
//获得第4行
XSSFRow row = sheet.getRow(3);
//获取单元格
row.getCell(2).setCellValue(businessData.getTurnover());
row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
row.getCell(6).setCellValue(businessData.getNewUsers());
//获取第五行
row = sheet.getRow(4);
//获取单元格
row.getCell(2).setCellValue(businessData.getValidOrderCount());
row.getCell(4).setCellValue(businessData.getUnitPrice());
//填充明细数据,循环遍历30天的数据
for (int i = 0; i < 30; i++) {
LocalDateTime beginTime = LocalDateTime.of(begin.plusDays(i), LocalTime.MIN);
LocalDateTime endTime = LocalDateTime.of(begin.plusDays(i), LocalTime.MAX);
BusinessDataVO businessData1 = workspaceService.getBusinessData(beginTime, endTime);
XSSFRow sheetRow = sheet.getRow((i + 7));
sheetRow.getCell(1).setCellValue(beginTime.toString());
sheetRow.getCell(2).setCellValue(businessData.getTurnover());
sheetRow.getCell(3).setCellValue(businessData.getValidOrderCount());
sheetRow.getCell(4).setCellValue(businessData.getOrderCompletionRate());
sheetRow.getCell(5).setCellValue(businessData1.getUnitPrice());
sheetRow.getCell(6).setCellValue(businessData1.getNewUsers());
}
//3.将文件用输出流响应
ServletOutputStream out = response.getOutputStream();
excel.write(out);
//4.清除数据,关闭资源
excel.close();
in.close();
out.flush();
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}


