当前位置: 首页 > news >正文

苍穹外卖-工作台实现、Apache POI、导出Excel报表

目录

1. 工作台

1.1 需求分析和设计

1.1.1 产品原型

1.1.2 接口设计

1.2 代码实现

1.2.1 Controller层

1.2.2 Service层接口

1.2.3 Service层实现类

1.2.4 Mapper层

1.3 功能测试

2. Apache POI

2.1 介绍

2.2 入门案例

2.2.1 将数据写入Excel文件

2.2.2 通过POI基于模板写入数据到execl

2.2.3 读取Excel文件中的数据

3.2 代码开发

3.2.1 实现步骤

3.2.2 Controller层

3.2.3 Service层接口

3.2.4 Service层实现类

3.3 功能测试

功能实现:工作台数据导出

工作台效果图:

数据导出效果图:

在数据统计页面点击数据导出:生成Excel报表

1. 工作台

1.1 需求分析和设计

1.1.1 产品原型

工作台是系统运营的数据看板,并提供快捷操作入口,可以有效提高商家的工作效率。

工作台展示的数据:

  • 今日数据

  • 订单管理

  • 菜品总览

  • 套餐总览

  • 订单信息

原型图:

名词解释:

  • 营业额:已完成订单的总金额

  • 有效订单:已完成订单的数量

  • 订单完成率:有效订单数 / 总订单数 * 100%

  • 平均客单价:营业额 / 有效订单数

  • 新增用户:新增用户的数量

1.1.2 接口设计

通过上述原型图分析,共包含6个接口。

接口设计:

  • 今日数据接口

  • 订单管理接口

  • 菜品总览接口

  • 套餐总览接口

  • 订单搜索(已完成)

  • 各个状态的订单数量统计(已完成)

1). 今日数据的接口设计

2). 订单管理的接口设计

3). 菜品总览的接口设计

4). 套餐总览的接口设计

1.2 代码实现

1.2.1 Controller层

添加WorkSpaceController.java

package com.sky.controller.admin;import com.sky.service.WorkspaceService;
import com.sky.result.Result;
import com.sky.vo.BusinessDataVO;
import com.sky.vo.DishOverViewVO;
import com.sky.vo.OrderOverViewVO;
import com.sky.vo.SetmealOverViewVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
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.time.LocalDateTime;
import java.time.LocalTime;/*** 工作台*/
@RestController
@RequestMapping("/admin/workspace")
@Slf4j
@Api(tags = "工作台相关接口")
public class WorkSpaceController {@Autowiredprivate WorkspaceService workspaceService;/*** 工作台今日数据查询* @return*/@GetMapping("/businessData")@ApiOperation("工作台今日数据查询")public Result<BusinessDataVO> businessData(){//获得当天的开始时间LocalDateTime begin = LocalDateTime.now().with(LocalTime.MIN);//获得当天的结束时间LocalDateTime end = LocalDateTime.now().with(LocalTime.MAX);BusinessDataVO businessDataVO = workspaceService.getBusinessData(begin, end);return Result.success(businessDataVO);}/*** 查询订单管理数据* @return*/@GetMapping("/overviewOrders")@ApiOperation("查询订单管理数据")public Result<OrderOverViewVO> orderOverView(){return Result.success(workspaceService.getOrderOverView());}/*** 查询菜品总览* @return*/@GetMapping("/overviewDishes")@ApiOperation("查询菜品总览")public Result<DishOverViewVO> dishOverView(){return Result.success(workspaceService.getDishOverView());}/*** 查询套餐总览* @return*/@GetMapping("/overviewSetmeals")@ApiOperation("查询套餐总览")public Result<SetmealOverViewVO> setmealOverView(){return Result.success(workspaceService.getSetmealOverView());}
}

1.2.2 Service层接口

添加WorkspaceService.java

package com.sky.service;import com.sky.vo.BusinessDataVO;
import com.sky.vo.DishOverViewVO;
import com.sky.vo.OrderOverViewVO;
import com.sky.vo.SetmealOverViewVO;
import java.time.LocalDateTime;public interface WorkspaceService {/*** 根据时间段统计营业数据* @param begin* @param end* @return*/BusinessDataVO getBusinessData(LocalDateTime begin, LocalDateTime end);/*** 查询订单管理数据* @return*/OrderOverViewVO getOrderOverView();/*** 查询菜品总览* @return*/DishOverViewVO getDishOverView();/*** 查询套餐总览* @return*/SetmealOverViewVO getSetmealOverView();}

1.2.3 Service层实现类

添加WorkspaceServiceImpl.java

@Service
@Slf4j
public class WorkspaceServiceImpl implements WorkspaceService {@Autowiredprivate OrdersMapper orderMapper;@Autowiredprivate UserMapper userMapper;@Autowiredprivate DishMapper dishMapper;@Autowiredprivate SetmealMapper setmealMapper;/*** 根据时间段统计营业数据* @param begin* @param end* @return*/public BusinessDataVO getBusinessData(LocalDateTime begin, LocalDateTime end) {/*** 营业额:当日已完成订单的总金额* 有效订单:当日已完成订单的数量* 订单完成率:有效订单数 / 总订单数* 平均客单价:营业额 / 有效订单数* 新增用户:当日新增用户的数量*/Map map = new HashMap();map.put("beginTime",begin);map.put("endTime",end);//查询总订单数Integer totalOrderCount = orderMapper.countByMap(map);map.put("status", Orders.COMPLETED);//营业额Double turnover = orderMapper.sumByMap(map);turnover = turnover == null? 0.0 : turnover;//有效订单数Integer validOrderCount = orderMapper.countByMap(map);Double unitPrice = 0.0;Double orderCompletionRate = 0.0;if(totalOrderCount != 0 && validOrderCount != 0){//订单完成率orderCompletionRate = validOrderCount.doubleValue() / totalOrderCount;//平均客单价unitPrice = turnover / validOrderCount;}//新增用户数Integer newUsers = userMapper.countByMap(map);return BusinessDataVO.builder().turnover(turnover).validOrderCount(validOrderCount).orderCompletionRate(orderCompletionRate).unitPrice(unitPrice).newUsers(newUsers).build();}/*** 查询订单管理数据** @return*/public OrderOverViewVO getOrderOverView() {Map map = new HashMap();map.put("beginTime", LocalDateTime.now().with(LocalTime.MIN));map.put("status", Orders.TO_BE_CONFIRMED);//待接单Integer waitingOrders = orderMapper.countByMap(map);//待派送map.put("status", Orders.CONFIRMED);Integer deliveredOrders = orderMapper.countByMap(map);//已完成map.put("status", Orders.COMPLETED);Integer completedOrders = orderMapper.countByMap(map);//已取消map.put("status", Orders.CANCELLED);Integer cancelledOrders = orderMapper.countByMap(map);//全部订单map.put("status", null);Integer allOrders = orderMapper.countByMap(map);return OrderOverViewVO.builder().waitingOrders(waitingOrders).deliveredOrders(deliveredOrders).completedOrders(completedOrders).cancelledOrders(cancelledOrders).allOrders(allOrders).build();}/*** 查询菜品总览** @return*/public DishOverViewVO getDishOverView() {Map map = new HashMap();map.put("status", StatusConstant.ENABLE);Integer sold = dishMapper.countByMap(map);map.put("status", StatusConstant.DISABLE);Integer discontinued = dishMapper.countByMap(map);return DishOverViewVO.builder().sold(sold).discontinued(discontinued).build();}/*** 查询套餐总览** @return*/public SetmealOverViewVO getSetmealOverView() {Map map = new HashMap();map.put("status", StatusConstant.ENABLE);Integer sold = setmealMapper.countByMap(map);map.put("status", StatusConstant.DISABLE);Integer discontinued = setmealMapper.countByMap(map);return SetmealOverViewVO.builder().sold(sold).discontinued(discontinued).build();}
}

一定要注意这里map里的属性名称要与xml文件中对应,否则sql语句的查询条件会出现错误。

1.2.4 Mapper层

在SetmealMapper中添加countByMap方法定义

/*** 根据条件统计套餐数量* @param map* @return*/Integer countByMap(Map map);

在SetmealMapper.xml中添加对应SQL实现

<!--    根据状态统计套餐数量--><select id="countByMap" resultType="java.lang.Integer">select count(id) from setmeal<where><if test="status != null">and status = #{status}</if><if test="categoryId != null">and category_id = #{categoryId}</if></where></select>

在DishMapper中添加countByMap方法定义

/*** 根据状态统计菜品数量* @param map* @return*/Integer countByMap(Map map);

在DishMapper.xml中添加对应SQL实现

<!--    根据状态统计菜品数量--><select id="countByMap" resultType="java.lang.Integer">select count(id) from dish<where><if test="status != null">and status = #{status}</if><if test="categoryId != null">and category_id = #{categoryId}</if></where></select>

1.3 功能测试

启动nginx,访问 http://localhost,进入工作台

进入开发者模式,分别查看今日数据、订单管理、菜品总览、套餐总览

1). 今日数据查询

2). 订单管理数据查询

2. Apache POI

2.1 介绍

Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。 一般情况下,POI 都是用于操作 Excel 文件。

Apache POI 的应用场景:

  • 银行网银系统导出交易明细

  • 各种业务系统导出Excel报表

  • 批量导入业务数据

2.2 入门案例

Apache POI既可以将数据写入Excel文件,也可以读取Excel文件中的数据,接下来分别进行实现。

Apache POI的maven坐标:(项目中已导入)

<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.16</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.16</version>
</dependency>

2.2.1 将数据写入Excel文件

1). 代码开发

/*** POI读写excel测试*/
public class TestPOI {/*** Excel的组成*      excel文件--->工作表对象*      excel里面可以有很多个Sheet表--->工作表对象*      Sheet表里面有很多行--->行对象*      行里面有很多单元格--->单元格对象*      单元格里面有数据--->数据对象*///需求:通过POI写入数据到执行的excel文件中@Testpublic void testWrite() throws Exception {//1.通过POI创建工作簿对象(文件)对象--excel对象XSSFWorkbook workbook = new XSSFWorkbook();//2.通过XSSFWorkbook创建工作表对象--Sheet对象XSSFSheet sheet = workbook.createSheet("itcast");//3.通过XSSFSheet创建行对象--Row对象,下标从0开始,创建第一行就写0XSSFRow row = sheet.createRow(0);//4.通过XSSFRow创建单元格对象--Cell对象(下标从0开始),并往格子中填充数据row.createCell(0).setCellValue("姓名");row.createCell(1).setCellValue("爱好");//第二行XSSFRow row1 = sheet.createRow(1);row1.createCell(0).setCellValue("张三");row1.createCell(1).setCellValue("足球");//5.将excel文件写出到指定的文件中FileOutputStream fos = new FileOutputStream("D:/itcast.xlsx");workbook.write(fos);System.out.println("写出完毕...");//6.释放资源fos.close();workbook.close();}

2). 实现效果

在D盘中生成itcast.xlsx文件,创建名称为itcast的Sheet页,同时将内容成功写入。

2.2.2 通过POI基于模板写入数据到execl

//需求:通过POI写入数据到执行的excel文件中--基于模板写入@Testpublic void testWrite2() throws Exception {//1.基于excel模板文件通过POI创建工作簿对象(文件)对象--有字体模板的excel对象FileInputStream fis = new FileInputStream("D:\\demo.xlsx");XSSFWorkbook workbook = new XSSFWorkbook(fis);//2.通过XSSFWorkbook获取工作表对象--Sheet对象,注意不要createSheet,会覆盖的。XSSFSheet sheet = workbook.getSheet("itcast");//3.通过XSSFSheet获取行对象--Row对象,下标从0开始,创建第一行就写0XSSFRow row = sheet.getRow(0);//4.通过XSSFRow创建单元格对象--Cell对象(下标从0开始),并往格子中填充数据row.getCell(0).setCellValue("姓名");row.getCell(1).setCellValue("爱好");//第二行XSSFRow row1 = sheet.getRow(1);row1.getCell(0).setCellValue("张三");row1.getCell(1).setCellValue("足球");//第三行XSSFRow row2 = sheet.getRow(2);row2.getCell(0).setCellValue("李四");row2.getCell(1).setCellValue("书法");//5.将excel文件写出到指定的文件中FileOutputStream fos = new FileOutputStream("D:\\demo1.xlsx");workbook.write(fos);System.out.println("写出完毕...");//6.释放资源fos.close();workbook.close();}

一定注意这里面的create换成了get,如果继续用create会覆盖原本单元格里的格式

2.2.3 读取Excel文件中的数据

1). 代码开发

 //需求:通过POI读磁盘中指定的excel文件到Java内存中,并输出到控制台@Testpublic void testRead() throws Exception {//1.基于excel模板文件通过POI创建工作簿对象(文件)对象--有字体模板的excel对象FileInputStream fis = new FileInputStream("D:\\itcast.xlsx");XSSFWorkbook workbook = new XSSFWorkbook(fis);//2.通过XSSFWorkbook获取工作表对象--Sheet对象,注意不要createSheet,会覆盖的。XSSFSheet sheet = workbook.getSheet("itcast");//3.通过XSSFSheet获取行对象--Row对象,下标从0开始,创建第一行就写0
//        XSSFRow row = sheet.getRow(0);//        //4.通过XSSFRow创建单元格对象--Cell对象(下标从0开始),并往格子中填充数据
//        String name = row.getCell(0).getStringCellValue();
//        String hobby = row.getCell(1).getStringCellValue();
//        System.out.println(name + "|" + hobby);
//        //读第二行
//        XSSFRow row1 = sheet.getRow(1);
//        String name1 = row1.getCell(0).getStringCellValue();
//        String hobby1 = row1.getCell(1).getStringCellValue();
//        System.out.println(name1 + "|" + hobby1);//循环读取表中的每一行数据int firstRowNum = sheet.getFirstRowNum();int lastRowNum = sheet.getLastRowNum();System.out.println("firstRowNum = " + firstRowNum);System.out.println("lastRowNum = " + lastRowNum);for (int i = firstRowNum; i <= lastRowNum; i++) {XSSFRow row = sheet.getRow(i);String name = row.getCell(0).getStringCellValue();String hobby = row.getCell(1).getStringCellValue();System.out.println(name + "|" + hobby);}//6.释放资源fis.close();workbook.close();}

2). 实现效果

将itcast.xlsx文件中的数据进行读取

3.2 代码开发


3.2.1 实现步骤

1). 设计Excel模板文件

2). 查询近30天的运营数据

3). 将查询到的运营数据写入模板文件

4). 通过输出流将Excel文件下载到客户端浏览器

3.2.2 Controller层

根据接口定义,在ReportController中创建export方法:

	/*** 导出运营数据报表* @param response*/@GetMapping("/export")@ApiOperation("导出运营数据报表")public void export(HttpServletResponse response){reportService.exportBusinessData(response);}

3.2.3 Service层接口

在ReportService接口中声明导出运营数据报表的方法:

	/*** 导出近30天的运营数据报表* @param response**/void exportBusinessData(HttpServletResponse response);

3.2.4 Service层实现类

在ReportServiceImpl实现类中实现导出运营数据报表的方法:

提前将资料中的运营数据报表模板.xlsx拷贝到项目的resources/template目录中

    /**导出近30天的运营数据报表* @param response**/public void exportBusinessData(HttpServletResponse response) {LocalDate begin = LocalDate.now().minusDays(30);LocalDate end = LocalDate.now().minusDays(1);//查询概览运营数据,提供给Excel模板文件BusinessDataVO businessData = workspaceService.getBusinessData(LocalDateTime.of(begin,LocalTime.MIN), LocalDateTime.of(end, LocalTime.MAX));InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");try {//基于提供好的模板文件创建一个新的Excel表格对象XSSFWorkbook excel = new XSSFWorkbook(inputStream);//获得Excel文件中的一个Sheet页XSSFSheet sheet = excel.getSheet("Sheet1");sheet.getRow(1).getCell(1).setCellValue(begin + "至" + end);//获得第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());for (int i = 0; i < 30; i++) {LocalDate date = begin.plusDays(i);//准备明细数据businessData = workspaceService.getBusinessData(LocalDateTime.of(date,LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX));row = sheet.getRow(7 + i);row.getCell(1).setCellValue(date.toString());row.getCell(2).setCellValue(businessData.getTurnover());row.getCell(3).setCellValue(businessData.getValidOrderCount());row.getCell(4).setCellValue(businessData.getOrderCompletionRate());row.getCell(5).setCellValue(businessData.getUnitPrice());row.getCell(6).setCellValue(businessData.getNewUsers());}//通过输出流将文件下载到客户端浏览器中ServletOutputStream out = response.getOutputStream();excel.write(out);//关闭资源out.flush();out.close();excel.close();}catch (IOException e){e.printStackTrace();}}

3.3 功能测试

直接使用前后端联调测试。

进入数据统计

点击数据导出:Excel报表下载成功

http://www.dtcms.com/a/465414.html

相关文章:

  • 自定义类型:联合与枚举
  • Java9
  • 基于Spring Boot + Vue 3的乡村振兴综合服务平台
  • Java-145 深入浅出 MongoDB 基本操作详解:数据库查看、切换、创建集合与删除完整教程
  • disable-devtool 网络安全 禁止打开控制台
  • TCP协议的可靠性保障
  • ktv支付订房网站模板商业策划书范文6篇
  • 十一、OpenCV中图形的绘制
  • 用户中心网站设计北京社保网址
  • 安卓13_ROM修改定制化-----如何给安卓手机里安装或者内置数字证书文件 cer类型的证书文件如何转换为可内置文件
  • 仿mudou——Connection模块(连接管理)
  • vue3 + el-upload组件集成阿里云视频点播从本地上传至点播存储
  • 外贸网站是用什么软件做的法制教育网站
  • c/c++字符串比较
  • 国外建站公司上海企业自助建站系统
  • AI 生产工艺参数优化:中小型制造企业用 “智能调参“ 提升产品合格率与生产效率
  • 《Linux基础入门指令》:从零开始理解Linux系统
  • NVIDIA HGX H100 GPU 服务器现已在 DigitalOcean 欧洲数据中心上线
  • 工程师招聘网站住建局网站官网
  • SAP-ABAP:SAP中的用户确认对话框:深入理解与实践POPUP_TO_CONFIRM
  • 购物网站上分期怎么做的广东移动手机营业厅网站
  • 云辉泵阀通过订单日记实现流程重构之路
  • 黑马商城微服务项目准备工作并了解什么是微服务、SpringCloud
  • 濮阳市城乡建设管理局网站怎么建网站
  • 腾讯云网站建设教学视频免费行情软件有哪些
  • 电子商务网站建设技术解决方案别人给公司做的网站字体侵权吗
  • 软考软件设计师常考知识点:(三)数据结构
  • 双向链表----“双轨联动,高效运行” (第九讲)
  • CEX-DEX 稳定币套利模型
  • 【C++STL :list类 (一) 】C++98 完全指南:std::list 详解与源码剖析