苍穹外卖学习 Day10 Day11 Day12

前言

用于记录苍穹外卖Day10、Day11、Day12的学习

Day10 订单状态定时处理 来电提醒 客户催单

订单状态定时处理

Spring Task

Spring Task是一个任务调度工具,可以按照约定的时间自动执行某个代码逻辑(定时自动执行某段Java代码)

cron表达式

cron表达式其实就是一个字符串,通过cron表达式可以定义任务触发的时间。

构成规则:分为6或7个域,用空格隔开,每个域代表一个含义。从左到右依次为秒、分钟、小时、日、月、周、年(可选)

cron在线生成器:https://cron.qqe2.com

Spring Task使用步骤

  • 导入坐标spring-context
  • 启动类添加注解@EnableScheduling开启任务调度
  • 自定义定时任务类

需求开发

存在的问题:

  • 下单后未支付,订单一直处于"待支付"状态
  • 用户收货后管理端未点击完成按钮,订单一直处于"派送中"状态

只需自定义个任务处理类来定时处理即可:

java 复制代码
//定时任务类,定时处理订单状态
@Component
@Slf4j
public class OrderTask {
    @Autowired
    private OrderMapper orderMapper;

    //处理下单后未支付超时的情况
    @Scheduled(cron = "0 * * * * ? *")//每分钟触发一次
//    @Scheduled(cron="0/5 * * * * ?")
    public void processTimeOut(){
        log.info("定时处理下单未支付的订单");
        //当前时间减15分钟
        LocalDateTime localDateTime = LocalDateTime.now().plusMinutes(-15);
        List<Orders> list = orderMapper.getByStatusAndOrderTimeLT(Orders.PENDING_PAYMENT, localDateTime);

        if(list!=null&&list.size()>0){
            for (Orders orders : list) {
                orders.setStatus(Orders.CANCELLED);
                orders.setConsignee("订单超时,自动取消");
                orders.setCancelTime(LocalDateTime.now());

                orderMapper.update(orders);
            }
        }
    }

    //处理一直处于派送中,没有完成的订单
    @Scheduled(cron = "0 0 1 * * ?")//每天凌晨一点触发
//    @Scheduled(cron="0/10 * * * * ?")
    public void processDeliveryOrder(){
        log.info("定时处理一直在派送的订单");
        LocalDateTime localDateTime = LocalDateTime.now().plusMinutes(-60);
        List<Orders> list = orderMapper.getByStatusAndOrderTimeLT(Orders.DELIVERY_IN_PROGRESS, localDateTime);

        if(list!=null&&list.size()>0){
            for (Orders orders : list) {
                orders.setStatus(Orders.COMPLETED);

                orderMapper.update(orders);
            }
        }
    }
}

来电提醒

WebSocket

WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信--浏览器和服务器只需完成一次握手 ,两者之间即可建立持久性 的连接,并进行双向数据传输

WebSocket和HTTP对比:

  • HTTP是短连接;WebSocket是长连接
  • HTTP是单向通信,基于请求响应模型;WebSocket支持双向通信。
  • WebSocket和HTTP都是基于TCP协议

应用场景:

  • 视频弹幕
  • 实况更新
  • 网页聊天

需求开发

实现思路:

  • 通过WebSocket实现管理端页面和服务端保持长连接
  • 当客户支付后,调用WebSocket的相关API从服务端向客户端推送消息
  • 客户端解析服务端发送的消息,判断是来电提醒还是客户催单,并进行相应的语音播报
  • 约定服务端向客户端发送的消息的数据格式为JSON,字段包括:type(消息类型,1为来单提醒、2为客户催单)、orderId、content(消息内容)

这里我们只需要在支付成功后提示管理端即可,在OrderServiceImpl的paySuccess方法中:

java 复制代码
		//通过WebSocket向客户端浏览器推送数据
        Map map=new HashMap();
        map.put("type",1);
        map.put("orderId",ordersDB.getId());
        map.put("content","订单号:"+outTradeNo);

        String Json= JSON.toJSONString(map);
        webSocketServer.sendToAllClient(Json);

注意:启动项目的时候看看你是否连接上WebSocket,如果没连接上可能是因为自己修改过端口号的问题,将端口号改回80或者改下前端代码即可。

客户催单

实现思路和来电提醒差不多。当用户在客户端点击催单按钮时,发起请求

  • OrderController
java 复制代码
	@GetMapping("/reminder/{id}")
    @ApiOperation("客户催单")
    public Result reminder(@PathVariable Long id){
        orderService.reminder(id);
        return Result.success();
    }
  • OrderServiceImpl
java 复制代码
	public void reminder(Long id) {
        // 根据id查询订单
        Orders orders1= orderMapper.getById(id);

        // 校验订单是否存在
        if (orders1 == null) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        //通过WebSocket向客户端浏览器推送数据
        Map map=new HashMap();
        map.put("type",2);
        map.put("orderId",id);
        map.put("content","订单号:"+orders1.getNumber());

        String Json= JSON.toJSONString(map);
        webSocketServer.sendToAllClient(Json);
    }

Day11 数据统计-图形报表

效果如下所示:

Apache ECharts

Apache ECharts是一款基于JavaScript的数据可视化图表库,提供直观、生动、可交互、可个性化定制的数据可视化图表。简单来说,它就是一款数据可视化工具。我们只需大致知道它是干啥的,它是在前端使用的,后端开发中我们使用不到。

营业额统计

业务规则:

  • 营业额指订单状态为已完成的订单金额合计
  • 基于可视化报表的折线图展示营业额数据,x轴为日期,y轴为营业额
  • 根据时间选择区间,展示每天的营业额数据

ReportController:注意时间的数据格式

java 复制代码
@RestController
@Slf4j
@RequestMapping("/admin/report")
@Api(tags = "数据统计相关接口")
public class ReportController {
    @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("营业额数据统计:{},{}",begin,end);
        TurnoverReportVO turnoverReportVO=reportService.getTurnoverStatistics(begin,end);
        return Result.success(turnoverReportVO);
    }
}

ReportServiceImpl:

这里我的实现方法与课程中略有不同,可以参考一下

java 复制代码
public TurnoverReportVO getTurnoverStatistics(LocalDate begin, LocalDate end) {
        TurnoverReportVO turnoverReportVO=new TurnoverReportVO();

        //1.封装日期数据
        //先去得到一个日期集合,包含begin到end中的所有日期
        List<LocalDate> dateList=new ArrayList<>();

        dateList.add(begin);
        while(!begin.equals(end)){
            begin=begin.plusDays(1);
            dateList.add(begin);
        }
        //将集合转成字符串的同时在每个元素间加一个逗号
        String dateList1=StringUtils.join(dateList,",");
        turnoverReportVO.setDateList(dateList1);

        //2.封装营业额数据
        //查询对应日期的订单的总营业额
        List<Double> moneyList=new ArrayList<>();
        for (LocalDate localDate : dateList) {
            //根据日期查询状态为已完成的订单的营业额

            //00:00:00
            LocalDateTime beginTime=LocalDateTime.of(localDate, LocalTime.MIN);
            //23:59:59
            LocalDateTime endTime=LocalDateTime.of(localDate, LocalTime.MAX);

            Map map=new HashMap();
            map.put("begin",beginTime);
            map.put("end",endTime);
            map.put("status", Orders.COMPLETED);
            Double money=orderMapper.getSumByMap(map);
            if(money==null){
                money=0.0;
            }
            moneyList.add(money);
        }
        String moneyList1=StringUtils.join(moneyList,",");
        turnoverReportVO.setTurnoverList(moneyList1);

        return turnoverReportVO;
    }

用户统计

ReportController:

java 复制代码
@GetMapping("/userStatistics")
    @ApiOperation("用户统计")
    public Result<UserReportVO> userStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin, @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
        log.info("用户统计:{},{}",begin,end);
        UserReportVO userReportVO=reportService.getUserStatistics(begin,end);
        return Result.success(userReportVO);
    }

ReportServiceImpl:

java 复制代码
//用户数据统计
    public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
        UserReportVO userReportVO=new UserReportVO();
        //1.封装日期数据
        //先去得到一个日期集合,包含begin到end中的所有日期
        List<LocalDate> dateList=new ArrayList<>();

        dateList.add(begin);
        while(!begin.equals(end)){
            begin=begin.plusDays(1);
            dateList.add(begin);
        }
        //将集合转成字符串的同时在每个元素间加一个逗号
        String dateList1=StringUtils.join(dateList,",");
        userReportVO.setDateList(dateList1);

        //2.封装用户总量数据
        List<Integer> totalList=new ArrayList<>();
        //3.封装新增用户数量数据
        List<Integer> newList=new ArrayList<>();

        for (LocalDate localDate : dateList) {
            //查询用户表createTime这一天的用户的总量
            //00:00:00
            LocalDateTime beginTime=LocalDateTime.of(localDate, LocalTime.MIN);
            //23:59:59
            LocalDateTime endTime=LocalDateTime.of(localDate, LocalTime.MAX);

            Map map=new HashMap();
            map.put("end",endTime);
            Integer total=userMapper.countByMap(map);
            if(total==null){
                total=0;
            }
            totalList.add(total);
            map.put("begin",beginTime);
            Integer today= userMapper.countByMap(map);
            if(today==null){
                today=0;
            }
            newList.add(today);

        }
        String userList1=StringUtils.join(totalList,",");
        userReportVO.setTotalUserList(userList1);

        String list1=StringUtils.join(newList,",");
        userReportVO.setNewUserList(list1);

        return userReportVO;
    }

订单统计

业务规则:

  • 两条折线,一条代表总订单数,另一条代表有效订单数(状态为已完成的订单)
  • 展示订单总数、有效订单数、订单完成率数据

ReportController:

java 复制代码
@GetMapping("/ordersStatistics")
    @ApiOperation("订单统计")
    public Result<OrderReportVO> orderStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin, @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
        log.info("订单统计:{},{}",begin,end);
        OrderReportVO orderReportVO=reportService.getOrderReportStatistics(begin,end);
        return Result.success(orderReportVO);
    }

ReportServiceImpl:

java 复制代码
@Override
    public OrderReportVO getOrderReportStatistics(LocalDate begin, LocalDate end) {
        OrderReportVO orderReportVO=new OrderReportVO();

        //1.封装日期数据
        List<LocalDate> dateList=new ArrayList<>();
        dateList.add(begin);
        while(!begin.equals(end)){
            begin=begin.plusDays(1);
            dateList.add(begin);
        }
        //将集合转成字符串的同时在每个元素间加一个逗号
        String dateList1=StringUtils.join(dateList,",");
        orderReportVO.setDateList(dateList1);

        //2.订单总数
        List<Integer> totalOrder=new ArrayList<>();
        //3.有效订单数
        List<Integer> realOrder=new ArrayList<>();
        //每天的订单总数以及有效订单数
        for (LocalDate localDate : dateList) {
            //00:00:00
            LocalDateTime beginTime=LocalDateTime.of(localDate, LocalTime.MIN);
            //23:59:59
            LocalDateTime endTime=LocalDateTime.of(localDate, LocalTime.MAX);
            Map map=new HashMap();
            map.put("begin",beginTime);
            map.put("end",endTime);
            Integer total=orderMapper.getByMap(map);
            if(total==null){
                total=0;
            }
            totalOrder.add(total);
            map.put("status",Orders.COMPLETED);
            Integer real=orderMapper.getByMap(map);
            if(real==null){
                real=0;
            }
            realOrder.add(real);
        }
        String totalOrder1=StringUtils.join(totalOrder,",");
        String realOrder1=StringUtils.join(realOrder,",");
        //计算时间区间内的订单总数量
        Integer sum=0;
        for (Integer integer : totalOrder) {
            sum+=integer;
        }

        //计算时间区间内的有效订单数量
        Integer real=0;
        for (Integer integer : realOrder) {
            real+=integer;
        }

        //计算订单完成率
        double orderCompletionRate=0.0;
        if (sum!=0) {
            orderCompletionRate= (double) real /sum;
        }
        orderReportVO.setOrderCompletionRate(orderCompletionRate);
        orderReportVO.setOrderCountList(totalOrder1);
        orderReportVO.setValidOrderCountList(realOrder1);
        orderReportVO.setTotalOrderCount(sum);
        orderReportVO.setValidOrderCount(real);

        System.out.println(orderReportVO);
        return orderReportVO;
    }

销量排名统计

ReportController:

java 复制代码
@GetMapping("/top10")
    @ApiOperation("销量排名top10")
    public Result<SalesTop10ReportVO> top10(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin, @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
        log.info("销量排名top10:{},{}",begin,end);
        SalesTop10ReportVO salesTop10ReportVO=reportService.getTop10(begin,end);
        return Result.success(salesTop10ReportVO);
    }

ReportServiceImpl:

java 复制代码
public SalesTop10ReportVO getTop10(LocalDate begin, LocalDate end) {
        SalesTop10ReportVO salesTop10ReportVO=new SalesTop10ReportVO();
        //00:00:00
        LocalDateTime beginTime=LocalDateTime.of(begin, LocalTime.MIN);
        //23:59:59
        LocalDateTime endTime=LocalDateTime.of(end, LocalTime.MAX);

        List<GoodsSalesDTO> goodsSalesDTOList=orderMapper.getSalesTop10(beginTime,endTime);

        //遍历取出DTO中的numa和number放到对应的集合中去
        List<String> nameList=new ArrayList<>();
        List<String> numberList=new ArrayList<>();
        for (GoodsSalesDTO goodsSalesDTO : goodsSalesDTOList) {
            nameList.add(goodsSalesDTO.getName());
            numberList.add(String.valueOf(goodsSalesDTO.getNumber()));
        }
        String nameLists=StringUtils.join(nameList,",");
        String numberLists=StringUtils.join(numberList,",");
        salesTop10ReportVO.setNameList(nameLists);
        salesTop10ReportVO.setNumberList(numberLists);

        return salesTop10ReportVO;
    }

OrderMapper.xml:

分析一下这里的SQL语句,因为我们要根据订单状态(对应orders表中的status)查订单的名称以及数量(对应order_details表中的number),所以涉及到联表查询。查询前10,所以只需limit 0,10

xml 复制代码
	<!--统计销量前10-->
    <select id="getSalesTop10" resultType="com.sky.dto.GoodsSalesDTO">
        select od.name,sum(od.number) number from order_detail od,orders o where od.id=o.id and o.status=5
        <if test="begin!=null">and order_time &gt; #{begin}</if>
        <if test="end!=null">and order_time &lt; #{end}</if>
        group by od.name order by number desc limit 0,10
    </select>

Day12 数据统计-Excel报表

工作台

这里课程中的代码是直接导入的,我还是选择手敲一遍。

工作台展示的数据:

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

为了简便展示,这里我直接给出一个类中的全部代码了,可以根据注释理解。

  • WorkSpaceController
java 复制代码
@RestController
@RequestMapping("/admin/workspace")
@Slf4j
@Api(tags = "工作台相关接口")
public class WorkSpaceController {
    @Autowired
    private WorkSpaceService workSpaceService;

    //查询工作台今日数据
    @GetMapping("/businessData")
    @ApiOperation("查询工作台今日数据")
    public Result<BusinessDataVO> businessData(){
        log.info("查询工作台今日数据");
        //获取开始时间
        LocalDateTime beginTime=LocalDateTime.now().with(LocalTime.MIN);
        //获取结束时间
        LocalDateTime endTime=LocalDateTime.now().with(LocalTime.MAX);

        BusinessDataVO businessDataVO=workSpaceService.getBusinessData(beginTime,endTime);
        return Result.success(businessDataVO);
    }
    //查询订单管理数据
    @GetMapping("/overviewOrders")
    @ApiOperation("查询订单管理数据")
    public Result<OrderOverViewVO> overViewOrders(){
        log.info("查询订单管理数据");
        return Result.success(workSpaceService.getOrderOverView());
    }
    //查询菜品总览
    @GetMapping("/overviewDishes")
    @ApiOperation("查询菜品总览")
    public Result<DishOverViewVO> overViewDishes(){
        return Result.success(workSpaceService.getDishOverView());
    }
    //查询套餐总览
    @GetMapping("/overviewSetmeals")
    @ApiOperation("查询套餐总览")
    public Result<SetmealOverViewVO> overViewSetmeal(){
        return Result.success(workSpaceService.getSetmealOvermeal());
    }
}
  • WorkSpaceService
java 复制代码
public interface WorkSpaceService {
    BusinessDataVO getBusinessData(LocalDateTime beginTime, LocalDateTime endTime);

    OrderOverViewVO getOrderOverView();

    DishOverViewVO getDishOverView();

    SetmealOverViewVO getSetmealOvermeal();
}
  • WorkSpaceServiceImpl(这里很多方法我们都在OrderMapper中已经写好了,直接调用即可)
java 复制代码
@Service
public class WorkSpaceServiceImpl implements WorkSpaceService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private SetmealMapper setmealMapper;

    //查询工作台今日数据
    public BusinessDataVO getBusinessData(LocalDateTime beginTime, LocalDateTime endTime) {
        BusinessDataVO businessDataVO=new BusinessDataVO();
        Map map=new HashMap();
        map.put("begin",beginTime);
        map.put("end",endTime);

        //订单总数
        Integer total=orderMapper.getByMap(map);

        map.put("status",5);
        //营业额
        Double sum = orderMapper.getSumByMap(map);
        sum = sum == null? 0.0 : sum;

        //有效订单数
        Integer real=orderMapper.getByMap(map);
        //平均客单价
        double average=0.0;
        //订单完成率
        double complete=0.0;
        if(total!=0&&real!=0){
            complete= (double) real /total;
            average=sum/real;
        }

        //新增用户数
        Integer newUser=userMapper.countByMap(map);

        businessDataVO.setTurnover(sum);
        businessDataVO.setNewUsers(newUser);
        businessDataVO.setOrderCompletionRate(complete);
        businessDataVO.setValidOrderCount(real);
        businessDataVO.setUnitPrice(average);

        return businessDataVO;
    }

    //查询订单管理数据
    @Override
    public OrderOverViewVO getOrderOverView() {
        OrderOverViewVO orderOverViewVO=new OrderOverViewVO();
        Map map = new HashMap();
        map.put("begin", LocalDateTime.now().with(LocalTime.MIN));

        //待接单
        map.put("status", Orders.TO_BE_CONFIRMED);
        Integer status1=orderMapper.getByMap(map);
        //待派送
        map.put("status",Orders.CONFIRMED);
        Integer status2=orderMapper.getByMap(map);
        //已完成
        map.put("status",Orders.COMPLETED);
        Integer status3=orderMapper.getByMap(map);
        //已取消
        map.put("status",Orders.CANCELLED);
        Integer status4=orderMapper.getByMap(map);
        //全部订单
        map.put("status",null);
        Integer status5=orderMapper.getByMap(map);

        orderOverViewVO.setWaitingOrders(status1);
        orderOverViewVO.setDeliveredOrders(status2);
        orderOverViewVO.setCompletedOrders(status3);
        orderOverViewVO.setCancelledOrders(status4);
        orderOverViewVO.setAllOrders(status5);
        return orderOverViewVO;
    }

    //查询菜品总览
    @Override
    public DishOverViewVO getDishOverView() {
        DishOverViewVO dishOverViewVO=new DishOverViewVO();

        Integer on=dishMapper.onStatus();
        Integer off=dishMapper.offStatus();

        dishOverViewVO.setSold(on);
        dishOverViewVO.setDiscontinued(off);

        return dishOverViewVO;
    }

    //查询套餐总览
    @Override
    public SetmealOverViewVO getSetmealOvermeal() {
        SetmealOverViewVO setmealOverViewVO=new SetmealOverViewVO();

        Integer on=setmealMapper.onStatus();
        Integer off=setmealMapper.offStatus();

        setmealOverViewVO.setSold(on);
        setmealOverViewVO.setDiscontinued(off);

        return setmealOverViewVO;
    }
}
  • DishMapper(这里是SQL语句少我使用这种方法,标准的应该是使用动态SQL)
java 复制代码
	@Select("select count(id) from dish where status=1")
    Integer onStatus();

    @Select("select count(id) from dish where status=0")
    Integer offStatus();
  • SetmealMapper
java 复制代码
	@Select("select count(id) from setmeal where status=1")
    Integer onStatus();

    @Select("select count(id) from setmeal where status=0")
    Integer offStatus();

Apache POI

简介:Apache POI可以处理Office的各种文件格式。允许我们使用POI在Java程序中对Office文件进行读写操作。一般用于处理Excel文件。

实例:

写入Excel文件:

java 复制代码
		//在内存中创建一个excel文件
        XSSFWorkbook excel=new XSSFWorkbook();
        //在excel文件中创建一个sheet页同时指定其名称为info
        XSSFSheet sheet=excel.createSheet("info");
        //创建行对象,行和列都从0开始,这里我们指定1表示是第二行
        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:\\Takeout\\info.xlsx"));
        excel.write(out);

        out.close();
        excel.close();

读取Excel文件:

java 复制代码
		InputStream in=new FileInputStream(new File("E:\\Takeout\\info.xlsx"));

        //读取磁盘上已经存在的Excel文件
        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 stringCellValue1 = row.getCell(1).getStringCellValue();
            String stringCellValue2 = row.getCell(2).getStringCellValue();
            System.out.println(stringCellValue1+" "+stringCellValue2);
        }
        excel.close();
        in.close();

导出Excel报表

业务规则:

  • 导出Excel文件形式的报表文件
  • 导出进30天的运营数据

实现步骤:

  • 设计Excel模板文件
  • 查询近30日的运营数据
  • 将查询到的运营数据写入模板文件内
  • 通过输出流将Excel文件下载到客户端浏览器

实现:

  • ReportController
java 复制代码
	@GetMapping("/export")
    @ApiOperation("导出Excel报表")
    public Result export(HttpServletResponse response){
        log.info("导出Excel报表");
        reportService.export(response);
        return Result.success();
    }
  • ReportServiceImpl
java 复制代码
	//导出运营数据报表
    @Override
    public void export(HttpServletResponse response) {
        //1.查询数据库,获取近30日的营业数据
        LocalDate dateBegin=LocalDate.now().minusDays(30);
        LocalDate dateEnd=LocalDate.now().minusDays(1);

        //查询概览数据
        BusinessDataVO businessDataVO=workSpaceService.getBusinessData(LocalDateTime.of(dateBegin,LocalTime.MIN),LocalDateTime.of(dateEnd,LocalTime.MAX));

        //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);
            //填充概览数据其他数据
            //第四行
            XSSFRow row= sheet.getRow(3);
            row.getCell(2).setCellValue(businessDataVO.getTurnover());
            row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
            row.getCell(6).setCellValue(businessDataVO.getNewUsers());
            //第五行
            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 businessDataVO1=workSpaceService.getBusinessData(LocalDateTime.of(date,LocalTime.MIN),LocalDateTime.of(date,LocalTime.MAX));

                //获取某一行并填充数据
                row= sheet.getRow(7+i);
                row.getCell(1).setCellValue(businessDataVO1.toString());
                row.getCell(2).setCellValue(businessDataVO1.getTurnover());
                row.getCell(3).setCellValue(businessDataVO1.getValidOrderCount());
                row.getCell(4).setCellValue(businessDataVO1.getOrderCompletionRate());
                row.getCell(5).setCellValue(businessDataVO1.getUnitPrice());
                row.getCell(6).setCellValue(businessDataVO1.getNewUsers());
            }

            //3.通过输出流将Excel文件下载到客户端浏览器
            ServletOutputStream out= response.getOutputStream();
            excel.write(out);
            //关闭资源
            out.close();
            excel.close();
        }catch (Exception e){
            e.printStackTrace();
        }

这里我们需要注意的一个地方,这里老师没有加上这个后缀,不加的话我这里会报错:

苍穹外卖的学习就到这里啦,完结撒花!!!

相关推荐
愤怒的代码6 分钟前
Spring Boot对访问密钥加解密——HMAC-SHA256
java·spring boot·后端
带多刺的玫瑰7 分钟前
Leecode刷题C语言之切蛋糕的最小总开销①
java·数据结构·算法
栗豆包22 分钟前
w118共享汽车管理系统
java·spring boot·后端·spring·tomcat·maven
夜半被帅醒28 分钟前
MySQL 数据库优化详解【Java数据库调优】
java·数据库·mysql
万亿少女的梦16835 分钟前
基于Spring Boot的网络购物商城的设计与实现
java·spring boot·后端
汤姆和佩琦1 小时前
2024-12-25-sklearn学习(20)无监督学习-双聚类 料峭春风吹酒醒,微冷,山头斜照却相迎。
学习·聚类·sklearn
醒了就刷牙1 小时前
黑马Java面试教程_P9_MySQL
java·mysql·面试
好学近乎知o1 小时前
正则表达式(学习Django过程中可能涉及的)
学习·正则表达式·django
雨中奔跑的小孩1 小时前
爬虫学习案例8
爬虫·学习
m0_748233641 小时前
SQL数组常用函数记录(Map篇)
java·数据库·sql