一、工作台
需求分析和设计
接口设计
- 今日数据接口
- 订单管理接口
- 菜品总览接口
- 套餐总览接口
- 订单搜索(已完成)
- 各个状态的订单数量统计(已完成)
代码实现
今日数据接口
1. WorkspaceController
注意不要导错包了
package com.sky.controller.admin;
import com.sky.result.Result;
import com.sky.service.WorkspaceService;
import com.sky.vo.BusinessDataVO;
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 {
@Autowired
private 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);
}
}
2. WorkspaceService
/**
* 根据时间段统计营业数据
* @param begin
* @param end
* @return
*/
BusinessDataVO getBusinessData(LocalDateTime begin, LocalDateTime end);
3. WorkspaceServiceImpl
package com.sky.service.impl;
import com.sky.entity.Orders;
import com.sky.mapper.DishMapper;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.SetmealMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.WorkspaceService;
import com.sky.vo.BusinessDataVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@Service
@Slf4j
public class WorkspaceServiceImpl implements WorkspaceService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private UserMapper userMapper;
@Autowired
private DishMapper dishMapper;
@Autowired
private SetmealMapper setmealMapper;
/**
* 根据时间段统计营业数据
* @param begin
* @param end
* @return
*/
@Override
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();
}
}
4. 功能测试
订单管理接口
1. WorkspaceController
/**
* 查询订单管理数据
* @return
*/
@GetMapping("/overviewOrders")
@ApiOperation("查询订单管理数据")
public Result<OrderOverViewVO> orderOverView() {
return Result.success(workspaceService.getOrderOverView());
}
2. WorkspaceService
/**
* 查询订单管理数据
* @return
*/
OrderOverViewVO getOrderOverView();
3. WorkspaceServiceImpl
/**
* 查询订单管理数据
* @return
*/
@Override
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();
}
4. 测试
菜品总览接口
1. WorkspaceController
/**
* 查询菜品总览
* @return
*/
@GetMapping("/overviewDishes")
@ApiOperation("查询菜品总览")
public Result<DishOverViewVO> dishOverView() {
return Result.success(workspaceService.getDishOverView());
}
2. WorkspaceService
/**
* 查询菜品总览
* @return
*/
DishOverViewVO getDishOverView();
3. WorkspaceServiceImpl
/**
* 查询菜品总览
* @return
*/
@Override
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();
}
4. DishMapper
/**
* 根据条件统计菜品数量
* @param map
* @return
*/
Integer countByMap(Map map);
5. DishMapper.xml
<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>
6. 测试
套餐总览接口
1. WorkspaceController
/**
* 查询套餐总览
* @return
*/
@GetMapping("/overviewSetmeals")
@ApiOperation("查询套餐总览")
public Result<SetmealOverViewVO> setmealOverView() {
return Result.success(workspaceService.getSetmealOverView());
}
2. WorkspaceService
/**
* 查询套餐总览
* @return
*/
SetmealOverViewVO getSetmealOverView();
3. WorkspaceServiceImpl
/**
* 查询套餐总览
* @return
*/
@Override
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();
}
4. SetmealMapper
/**
* 根据条件统计套餐数量
* @param map
* @return
*/
Integer countByMap(Map map);
5. SetmealMapper.xml
<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>
6. 测试
二、Apache POI
介绍
Apache PIO是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用POI在Java程序中对Miscrosoft Office各种文件进行读写操作。一般情况下,POI都是用于操作Excel文件。
Apache POI的应用场景
- 银行网银系统导出交易明细
- 各种业务系统导出Excel报表
- 批量导入业务数据
入门案例
1. 导入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. POITest
package com.sky.test;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/**
* 使用POI操作excel文件
*/
public class POITest {
/**
* 通过POI创建EXCEL文件并且写入文件内容
*/
public static void write() throws Exception {
// 在内存中创建一个excel文件
XSSFWorkbook excel = new XSSFWorkbook();
// 在excel文件中创建一个新的sheet页
XSSFSheet sheet = excel.createSheet("info");
// 在sheet页中创建行对象,rownum编号从0开始
XSSFRow row = sheet.createRow(1);
// 在行上面创建单元格,并且写入文件内容
row.createCell(1).setCellValue("姓名");
row.createCell(2).setCellValue("城市");
// 创建一个新行
row = sheet.createRow(2);
// 创建单元格
row.createCell(1).setCellValue("张三");
row.createCell(2).setCellValue("北京");
// 创建一个新行
row = sheet.createRow(3);
// 创建单元格
row.createCell(1).setCellValue("李四");
row.createCell(2).setCellValue("南京");
// 通过输出流将内存中的excel文件写入到磁盘
FileOutputStream out = new FileOutputStream(new File("E:\\info.xlsx"));
excel.write(out);
// 关闭资源
out.close();
excel.close();
}
/**
* 通过POI读取EXCEL文件中的内容
* @throws Exception
*/
public static void read() throws Exception {
// 读取磁盘上已经存在的excel文件
FileInputStream in = new FileInputStream(new File("E:\\info.xlsx"));
XSSFWorkbook excel = new XSSFWorkbook(in);
// 读取excel文件中的第一个sheet页
XSSFSheet sheet = excel.getSheetAt(0);
// 获取sheet中最后一行的行号
int lastRowNum = sheet.getLastRowNum();
for (int i = 1; i <= lastRowNum; i++) {
// 获得某一行
XSSFRow row = sheet.getRow(i);
// 获得某个单元格对象
String cellValue = row.getCell(1).getStringCellValue();
String cellValue2 = row.getCell(2).getStringCellValue();
System.out.println(cellValue + " " + cellValue2);
}
// 关闭资源
in.close();
excel.close();
}
public static void main(String[] args) throws Exception {
write();
read();
}
}
3. 测试
三、导出运营数据Excel报表
需求分析和设计
产品原型
导出的Excel报表格式
业务规则
- 导出Excel形式的报表文件
- 导出最近30天的运营数据
接口设计
注意:当前接口没有返回数据,因为报表导出功能本质上是文件下载,服务端会通过输出流将Excel文件下载到客户端浏览器。
代码开发
实现步骤:
- ①设计Excel模板文件
- ②查询近30天的运营数据
- ③将查询到的运营数据写入模板文件
- ④通过输出流将Excel文件下载到客户端浏览器
1. ReportController
/**
* 导出运营数据报表
* @param response
*/
@GetMapping("/export")
@ApiOperation("导出运营数据报表")
public void export(HttpServletResponse response) {
reportService.exportBusinessData(response);
}
2. ReportService
/**
* 导出运营数据报表
* @param response
*/
void exportBusinessData(HttpServletResponse response);
3. ReportServiceImpl
@Autowired
private WorkspaceService workspaceService;
/**
* 导出运营数据报表
* @param response
*/
@Override
public void exportBusinessData(HttpServletResponse response) {
// 1. 查询数据库,获取营业数据--查询最近30天的运营数据
LocalDate dateBegin = LocalDate.now().minusDays(30);
LocalDate dateEnd = LocalDate.now().minusDays(1);
LocalDateTime beginTime = LocalDateTime.of(dateBegin, LocalTime.MIN);
LocalDateTime endTime = LocalDateTime.of(dateEnd, LocalTime.MAX);
// 查询概览数据
BusinessDataVO businessDataVO = workspaceService.getBusinessData(beginTime, endTime);
// 2. 通过POI把查询到的数据写道到excel文件中
InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
try {
// 基于模板文件创建一个新的excel文件
XSSFWorkbook excel = new XSSFWorkbook(in);
// 获取表格文件的sheet页
XSSFSheet sheet = excel.getSheet("Sheet1");
// 填充数据——时间区间
sheet.getRow(1).getCell(1).setCellValue("时间:" + dateBegin + " 至 " + dateEnd);
// 获取第4行
XSSFRow row = sheet.getRow(3);
// 营业额
row.getCell(2).setCellValue(businessDataVO.getTurnover());
// 订单完成率
row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
// 新增用户数
row.getCell(6).setCellValue(businessDataVO.getNewUsers());
// 获得第5行
row = sheet.getRow(4);
// 有效订单
row.getCell(2).setCellValue(businessDataVO.getValidOrderCount());
// 平均客单价
row.getCell(4).setCellValue(businessDataVO.getUnitPrice());
// 填充明细数据
for (int i = 0; i < 30; i++) {
LocalDate date = dateBegin.plusDays(i);
// 查询某一天的营业数据
BusinessDataVO 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());
}
// 3. 通过输出流将excel文件下载到客户端浏览器
ServletOutputStream out = response.getOutputStream();
excel.write(out);
// 4. 关闭资源
out.close();
excel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
功能测试
完结撒花~~~
后端完整源码:https://pan.baidu.com/s/1hHnA-H_xOFiVEeIVi92A3Q?pwd=0k80