基于SpringBoot+Apache POI的前后端分离外卖项目-苍穹外卖(十九)

数据导出

    • 1. 工作台
      • 1.1 需求分析和设计
        • 1.1.1 产品原型
        • 1.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 读取Excel文件中的数据
    • 3. 导出运营数据Excel报表
      • 3.1 需求分析和设计
        • 3.1.1 产品原型
        • 3.1.2 接口设计
      • 3.2 代码开发
        • 3.2.1 实现步骤
        • 3.2.2 Controller层
        • 3.2.3 Service层接口
        • 3.2.4 Service层实现类
      • 3.3 功能测试

1. 工作台

1.1 需求分析和设计

1.1.1 产品原型

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

工作台展示的数据:

  • 今日数据
  • 订单管理
  • 菜品总览
  • 套餐总览
  • 订单信息

原型图:

名词解释:

  • 营业额:已完成订单的总金额
  • 有效订单:已完成订单的数量
  • 订单完成率:有效订单数 / 总订单数 * 100%
  • 平均客单价:营业额 / 有效订单数
  • 新增用户:新增用户的数量
1.1.2 接口设计

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

接口设计:

  • 今日数据接口
  • 订单管理接口
  • 菜品总览接口
  • 套餐总览接口
  • 订单搜索(已完成)
  • 各个状态的订单数量统计(已完成)

1). 今日数据的接口设计
在这里插入图片描述
2). 订单管理的接口设计
在这里插入图片描述

3). 菜品总览的接口设计
在这里插入图片描述

4). 套餐总览的接口设计
在这里插入图片描述

1.2.1 Controller层

添加WorkSpaceController.java

package com.sky.controller.admin;/*** 工作台*/
@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;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

package com.sky.service.impl;
import java.util.Map;@Service
@Slf4j
public class WorkspaceServiceImpl implements WorkspaceService {@Autowiredprivate OrderMapper 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("begin",begin);map.put("end",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("begin", 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();}
}
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 功能测试

在这里插入图片描述

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). 代码开发

package com.sky.test;public class POITest {/*** 基于POI向Excel文件写入数据* @throws Exception*/public static void write() throws Exception{//在内存中创建一个Excel文件对象XSSFWorkbook excel = new XSSFWorkbook();//创建Sheet页XSSFSheet sheet = excel.createSheet("itcast");//在Sheet页中创建行,0表示第1行XSSFRow row1 = sheet.createRow(0);//创建单元格并在单元格中设置值,单元格编号也是从0开始,1表示第2个单元格row1.createCell(1).setCellValue("姓名");row1.createCell(2).setCellValue("城市");XSSFRow row2 = sheet.createRow(1);row2.createCell(1).setCellValue("张三");row2.createCell(2).setCellValue("北京");XSSFRow row3 = sheet.createRow(2);row3.createCell(1).setCellValue("李四");row3.createCell(2).setCellValue("上海");FileOutputStream out = new FileOutputStream(new File("D:\\itcast.xlsx"));//通过输出流将内存中的Excel文件写入到磁盘上excel.write(out);//关闭资源out.flush();out.close();excel.close();}public static void main(String[] args) throws Exception {write();}
}

2). 实现效果

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

2.2.2 读取Excel文件中的数据

1). 代码开发

package com.sky.test;public class POITest {/*** 基于POI读取Excel文件* @throws Exception*/public static void read() throws Exception{FileInputStream in = new FileInputStream(new File("D:\\itcast.xlsx"));//通过输入流读取指定的Excel文件XSSFWorkbook excel = new XSSFWorkbook(in);//获取Excel文件的第1个Sheet页XSSFSheet sheet = excel.getSheetAt(0);//获取Sheet页中的最后一行的行号int lastRowNum = sheet.getLastRowNum();for (int i = 0; i <= lastRowNum; i++) {//获取Sheet页中的行XSSFRow titleRow = sheet.getRow(i);//获取行的第2个单元格XSSFCell cell1 = titleRow.getCell(1);//获取单元格中的文本内容String cellValue1 = cell1.getStringCellValue();//获取行的第3个单元格XSSFCell cell2 = titleRow.getCell(2);//获取单元格中的文本内容String cellValue2 = cell2.getStringCellValue();System.out.println(cellValue1 + " " +cellValue2);}//关闭资源in.close();excel.close();}public static void main(String[] args) throws Exception {read();}
}

2). 实现效果

将itcast.xlsx文件中的数据进行读取
在这里插入图片描述

3. 导出运营数据Excel报表

3.1 需求分析和设计

3.1.1 产品原型

在数据统计页面,有一个数据导出的按钮,点击该按钮时,其实就会下载一个文件。这个文件实际上是一个Excel形式的文件,文件中主要包含最近30日运营相关的数据。表格的形式已经固定,主要由概览数据和明细数据两部分组成。真正导出这个报表之后,相对应的数字就会填充在表格中,就可以进行存档。
在这里插入图片描述

业务规则:

  • 导出Excel形式的报表文件
  • 导出最近30天的运营数据
3.1.2 接口设计

通过上述原型图设计对应的接口。
在这里插入图片描述
注意:

  • 当前接口没有传递参数,因为导出的是最近30天的运营数据,后端计算即可,所以不需要任何参数

  • 当前接口没有返回数据,因为报表导出功能本质上是文件下载,服务端会通过输出流将Excel文件下载到客户端浏览器

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 功能测试

在这里插入图片描述

后记
👉👉💕💕美好的一天,到此结束,下次继续努力!欲知后续,请看下回分解,写作不易,感谢大家的支持!! 🌹🌹🌹

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/721010.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

交友盲盒系统PHP开源的盲盒源码

源码介绍&#xff1a; 交友盲盒系统是一款基于PHP开发的开源免费盲盒系统&#xff0c;旨在为用户提供一个充满乐趣和惊喜的社交体验。该系统具有丰富的功能和灵活的扩展性&#xff0c;可以轻松地满足各种线上交友、抽奖活动等场景的需求。 安装说明&#xff1a; PHP版本&…

iptables中的SNAT、DNAT与Firewalld

目录 引言 一、SNAT与DNAT简介 &#xff08;一&#xff09;SNAT 1.SNAT的工作原理 2.SNAT的应用 &#xff08;二&#xff09;DNAT 1.DNAT的工作原理 2.DNAT的应用 二、实现NAT转换 &#xff08;一&#xff09;实现SNAT 1.配置网关服务器 2.修改网关 3.设置SNAT规则…

【leetcode】删除链接的倒数第N个节点

/*** Definition for singly-linked list.* function ListNode(val, next) {* this.val (valundefined ? 0 : val)* this.next (nextundefined ? null : next)* }*/ /*** param {ListNode} head* param {number} n* return {ListNode}*/ var removeNthFromEnd fun…

Java面试题总结8:springboot

Spring Boot自动配置原理 importConfigurationSpring spi 自动配置类由各个starter提供&#xff0c;使用ConfigurationBean定义配置类&#xff0c;放到META-INF/spring.factories下 使用Spring spi扫描META-INF/Spring.factories下的配置类 如何理解Spring Boot中Starter …

04-JNI函数

上一篇&#xff1a;03-JNI 类型和数据结构 本章是 JNI 函数的参考章节。它提供了所有 JNI 函数的完整列表。它还介绍了 JNI 函数表的具体布局。 注意&#xff1a;使用 "必须 "一词来描述对 JNI 程序员的限制。例如&#xff0c;当你看到某个 JNI 函数必须接收一个非 N…

7款炫酷的前端动画特效分享(三)(附效果图及在线演示)

分享7款好玩的前端动画特效 其中有CSS动画、SVG动画、js小游戏等等 下方效果图可能不是特别的生动 那么你可以点击在线预览进行查看相应的动画特效 同时也是可以下载该资源的 CSS3模仿四季交替动画 基于HTML5CSS3实现的卡通风格一年四季交替动画特效 以下效果图只能体现框架的…

超全Chat GPT论文修改指令

文献综述指令润色修改指令论文选题指令论文大指令研究理论指令论文致谢指令参考文献指令论文润色整体逻辑论文整体优化提问指令 1&#xff0e;文献综述指令 请你帮我写一份关于&#xff08;研究主题&#xff09;的文献综述。我的论文选题方向是 XXXX &#xff0c;我已经找到了…

Shell编程——条件测试(五)

在shell编程中&#xff0c;if语句本身不执行任何判断&#xff0c;它实际上接受一个程序作为参数&#xff0c;然后执行这个程序&#xff0c;并依据这个程序的返回值来判断是否执行相应的语句。 程序的返回值是0&#xff0c;则为真&#xff0c;反之则为假。 目录 test命令&…

YOLOv8-Openvino-ByteTrack【CPU】

YOLOv5-Openvino和ONNXRuntime推理【CPU】 YOLOv6-Openvino和ONNXRuntime推理【CPU】 YOLOv8-Openvino和ONNXRuntime推理【CPU】 YOLOv9-Openvino和ONNXRuntime推理【CPU】 注&#xff1a;YOLOv8和YOLOv9代码内容基本一致&#xff01; 全部代码Github&#xff1a;https://gith…

对于网络IO的理解

网络IO理解 首先服务端将本机地址和端口bind在listensock上&#xff0c;再用listen()去将listensock套接字设置为listen状态&#xff0c;然后调用accept&#xff0c;进入阻塞状态。如果此时有客户端请求连接&#xff0c;就是第一次握手的开始。 客户端会先调用connect来申请连…

BUUCTF crypto做题记录(13)新手向

一、[MRCTF2020]vigenere 这是一道维吉尼亚密码&#xff0c;但由于不知道密钥&#xff0c;所以我们需要采用爆破的方式。Vigenere Solver | guballa.de 答案&#xff1a;flag{vigenere_crypto_crack_man} 二、[MRCTF2020]keyboard 之前做过一个类似的题目&#xff0c;用九宫格…

97 spring 中的泛型类型注入

前言 呵呵 同样是 最近同事碰到的一个问题 他不太懂 英语, 看到的说明是 缺少一个 RedisTemplate 的实例, 但是找到了一个 RedisTemplate 的实例 呵呵 和我这里 spring 版本似乎是不太一样, 错误信息 有一些差异 以下环境基于 jdk8 spring-5.0.4-RELEASE 测试用例 BeanCon…

高效备考一级数据分析师考试《CDA Level I 实操训练营》3月30日开课!

曾经报名了考试&#xff0c;买了教程辅导书&#xff0c;却因为各种原因没有坚持学习&#xff0c;这样的经历可能让你感到沮丧和失望。但是&#xff0c;失败并不代表终结&#xff0c;而是迈向成功的必经之路。为了帮助大家能够快速学习考试相关知识&#xff0c;特别为CDA LEVEL …

transformer--解码器

在编码器中实现了编码器的各种组件&#xff0c;其实解码器中使用的也是这些组件&#xff0c;如下图&#xff1a; 解码器组成部分: 由N个解码器层堆叠而成每个解码器层由三个子层连接结构组成第一个子层连接结构包括一个多头自注意力子层和规范化层以及一个残差连接第二个子层连…

小巧且强大,一键批量操作谁不爱?

软件简介&#xff1a; 软件【下载地址】获取方式见文末。注&#xff1a;推荐使用&#xff0c;更贴合此安装方法&#xff01; 两款Office批量打印工具展现了优秀的人性化设计&#xff1a;其界面清晰、操作简便。这些工具支持Word、Excel、PPT等多种文档格式进行批量打印&#…

VMware虚拟机安装linux教程

CentOS7下载 下载 (centos.org)https://www.centos.org/download/新建虚拟机 选择自定义安装 这里要注意兼容性&#xff0c;如果是VMware12创建的虚拟机复制到VM11、10或者更低的版本会出现一不兼容的现象。如果是用VMware10创建的虚拟机在VMware12中打开则不会出现兼容性问题…

vue中使用echarts实现人体动态图

最近一直处于开发大屏的项目&#xff0c;在开发中遇到了一个小知识点&#xff0c;在大屏中如何实现人体动态图。然后看了下echarts官方文档&#xff0c;根据文档中的示例调整出来自己想要的效果。 根据文档上发现 series 中 type 类型设置为 象形柱形图&#xff0c;象形柱图是…

SpringCloud之Nacos入门与实战系列

目录 一、Nacos介绍 1.1、配置中心和注册中心的概念 1.2 Nacos 优点 二、Nacos的使用 2.1 以单机模式启动Nacos 2.2 Nacos部署方式介绍 2.3 配置数据源 2.4 开启控制台权限登录 三、配置中心的使用 3.1 创建配置信息 3.2 SpringBoot使用配置中心 四、注册中心的使用 4…

图书推荐|Word文稿之美

让你的文档从平凡到出众&#xff01; 本书内容 《Word文稿之美》是一本全面介绍Word排版技巧和应用的实用指南。从初步认识数字排版到高效利用模板、图文配置和表格与图表的排版技巧&#xff0c;再到快速修正错误和保护文件&#xff0c;全面系统地讲解数字排版的技术和能力&…

基于Docker部署本地ChatGPT环境

基于Docker部署本地ChatGPT环境 一、拉取镜像 docker pull pengzhile/pandora二、运行镜像 docker run -e PANDORA_CLOUDcloud -e PANDORA_SERVER0.0.0.0:8899 -p 8899:8899 -d pengzhile/pandora三、查看容器是否启动成功 docker ps四、登录 http://IP:8899 这里有两种方…