IT自学第三十七天补充

4、营业额统计-代码开发1-日期列表构造

当请求为少数参数时,可以直接使用参数请求,当参数比较多时,考虑写实体封装;

放请求参数为JSON格式时,必须用实体封装。

代码开发

根据接口定义设计对应的VO:

返回数据:

代码演示:

java 复制代码
public class TurnoverReportVO implements Serializable {
    //日期,以逗号分隔,例如:2022-10-01,2022-10-02,2022-10-03
    private String dateList;
    //营业额,以逗号分隔,例如:406.0,1520.0,75.0
    private String turnoverList;
}

代码开发

根据接口定义创建ReportController:

代码演示:

java 复制代码
    @ApiOperation("营业额统计")
    @GetMapping("/turnoverStatistics")
    public Result turnoverStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
                                     @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
        log.info("营业额统计,{},{}",begin,end);
        TurnoverReportVO vo = reportService.turnoverStatistics(begin,end);
        return Result.success(vo);
    }

5、营业额统计-代码开发2-营业额数据构造

Service

代码演示:

java 复制代码
    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        //1、准备日期列表数据dateList     -->近7日 5.14,5.15,....5.20
        List<LocalDate> dateList = new ArrayList<>();
        while(!begin.isAfter(end)) {
            //注意:小心死循环 OOM
//            log.info("进入操作...");
            dateList.add(begin);
            begin = begin.plusDays(1);
        }
        log.info("dateList={}",dateList);
        //2、准备营业额列表数据turnoverList
        List<Double> turnoverList = new ArrayList<>();
        //营业额 = 订单状态已完成的订单金额
        //查询订单表orders表,条件,状态-已完成,下单时间
        // select sum(amount) from orders where status = 5 and order_time between '2024-5-17 00:00:00' and '2024-05-17 23:59:59:9999'
        dateList.forEach(date ->{
            Map map = new HashMap();
            map.put("status", Orders.COMPLETED);
            map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN));  //2024-05-14 00:00
            map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));   //2024-05-14 23:59:59.999999999
            Double turnover = ordersMapper.sumByMap(map);
            //用来处理没有营业额的情况
            turnover = turnover == null ? 0.0 : turnover;
            turnoverList.add(turnover);
        });

        //3、构造TurnoverReportVO对象并返回
        //   dateList.toString() ,使用toString()会导致有[]
        return TurnoverReportVO.builder()
                .dateList(StringUtils.join(dateList,","))
                .turnoverList(StringUtils.join(turnoverList,","))
                .build();
    }

注意:List列表转字符串的方式,使用StringUtils.join(dateList,",")。

6、用户统计-代码开发1

需求分析和设计

产品原型

业务规则:

  • 基于可视化报表的折线图展示用户数据,X轴为日期,Y轴为用户数
  • 根据时间选择区间,展示每天的用户总量和新增用户量数据

接口设计:

返回数据

设计VO

代码演示:

java 复制代码
public class UserReportVO implements Serializable {
    //日期,以逗号分隔,例如:2022-10-01,2022-10-02,2022-10-03
    private String dateList;
    //用户总量,以逗号分隔,例如:200,210,220
    private String totalUserList;
    //新增用户,以逗号分隔,例如:20,21,10
    private String newUserList;
}

7、用户统计-代码开发2

使用Ctrl+Alt+M抽取方法,自动抽取方法。

代码演示:

java 复制代码
    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        //1、构造dateList数据
        List<LocalDate> dateList = getDateList(begin, end);
        log.info("dateList={}",dateList);
        //2、构造newUserList数据,新增用户列表
        List<Integer> newUserList = new ArrayList<>();
        List<Integer> totalUserList = new ArrayList<>();
        //查询每日的新增用户数--user
        //  select count(*) from user where create_time between beginTime and endTime
        //循环遍历获取date,计算每日新增用户数
        dateList.forEach(date ->{
            Map map = new HashMap();
            map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN));
            map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));
            Integer newUser = userMapper.countByMap(map);
            newUserList.add(newUser);
            //3、构造totalUserList数据,总用户列表
            //  select count(*) from user where create_time <= 当天最大值
            map.put("beginTime",null);
            map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));
            Integer totalUser = userMapper.countByMap(map);
            //此处不需要totalUser = totalUser == null ? 0 : totalUser;判空,因为使用count(*)得到的结果,必定是0
            totalUserList.add(totalUser);
        });

        //4、构造UserReportVO对象并返回
        return UserReportVO.builder()
                .dateList(StringUtils.join(dateList,","))
                .newUserList(StringUtils.join(newUserList,","))
                .totalUserList(StringUtils.join(totalUserList,","))
                .build()
                ;
    }

    private static List<LocalDate> getDateList(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = new ArrayList<>();
        while(!begin.isAfter(end)) {
            //注意:小心死循环 OOM
//            log.info("进入操作...");
            dateList.add(begin);
            begin = begin.plusDays(1);
        }
        return dateList;
    }

8、订单统计-需求+接口分析

需求分析和设计

产品原型:

业务规则:

  • 有效订单指状态为"已完成"的订单
  • 基于可视化报表的折线图展示订单数据,X轴为日期,Y轴为订单数量
  • 根据时间选择区间,展示每天的订单总数和有效订单数
  • 展示所选时间区间内的有效订单数、总订单数、订单完成率,订单完成率=有效订单数/总订单数*100%

接口设计:

代码演示:

java 复制代码
public class OrderReportVO implements Serializable {
    //日期,以逗号分隔,例如:2022-10-01,2022-10-02,2022-10-03
    private String dateList;
    //每日订单数,以逗号分隔,例如:260,210,215
    private String orderCountList;
    //每日有效订单数,以逗号分隔,例如:20,21,10
    private String validOrderCountList;
    //订单总数
    private Integer totalOrderCount;
    //有效订单数
    private Integer validOrderCount;
    //订单完成率
    private Double orderCompletionRate;
}

9、订单统计-代码开发

代码演示:

java 复制代码
    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        //1、dateList
        List<LocalDate> dateList = getDateList(begin, end);
        List<Integer> orderCountList = new ArrayList<>();
        List<Integer> validOrderCountList = new ArrayList<>();
        Integer totalOrderCount = 0;
        Integer totalValidOrderCount = 0;
        Double orderCompletionRate = 0.0;
        //2、获取每日总订单列表数orderCountList
        // select count(*) from orders where order_time >= beginTime and order_time <= endTime
        for (LocalDate date : dateList) {
            Map map = new HashMap();
            map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN));
            map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));
            Integer totalOrder = ordersMapper.countByMap(map);
            orderCountList.add(totalOrder);
            //3、获取每日有效订单列表数validOrderCountList
            // select count(*) from orders where order_time >= beginTime and order_time <= endTime and status = 5
            map.put("status", Orders.COMPLETED);
            Integer validOrder = ordersMapper.countByMap(map);
            validOrderCountList.add(validOrder);
            //4、获取订单总数totalOrderCount
            totalOrderCount += totalOrder;
            //5、获取有效订单数validOrderCount
            totalValidOrderCount += validOrder;
        }
        //6、计算完成率orderCompletionRate
        if(totalOrderCount != 0){
            orderCompletionRate = (totalValidOrderCount + 0.0)/totalOrderCount;
        }
        //7、封装OrderReportVO,并返回
        return OrderReportVO.builder()
                .dateList(StringUtils.join(dateList,","))
                .orderCountList(StringUtils.join(orderCountList,","))
                .validOrderCountList(StringUtils.join(validOrderCountList,","))
                .totalOrderCount(totalOrderCount)
                .validOrderCount(totalValidOrderCount)
                .orderCompletionRate(orderCompletionRate)
                .build();
    }

10、订单统计-流的方式

代码开发

11、销量前10统计-分析

分组统计group by

需求分析与设计

产品原型:

业务规则:

  • 根据时间选择区间,展示销量前10的商品(包括菜品和套餐)
  • 基于可视化报表的柱状图降序展示商品销量
  • 此处的销量为商品销售的份数

接口设计:

设计VO

java 复制代码
public class SalesTop10ReportVO implements Serializable {
    //商品名称列表,以逗号分隔,例如:鱼香肉丝,宫保鸡丁,水煮鱼
    private String nameList;
    //销量列表,以逗号分隔,例如:260,215,200
    private String numberList;
}

注意:只有订单状态为5的商品才算销量

12、销量前10统计-代码开发

代码演示:

java 复制代码
    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {
        //1、构造nameList,商品名称列表
        List<String> nameList = new ArrayList<>();
        List numberList = new ArrayList<>();
        // 查询订单明细表 order_detail + orders ,条件:订单状态为5,已完成;下单时间
        Map map = new HashMap();
        map.put("beginTime", LocalDateTime.of(begin, LocalTime.MIN));
        map.put("endTime", LocalDateTime.of(end, LocalTime.MAX));
        map.put("status", Orders.COMPLETED);
        List<Map> list = ordersMapper.sumTop10(map);
        for (Map m : list) {
            String name = (String) m.get("name");
            nameList.add(name);
            //2、构造numberList,商品销量列表
            Object sumNum = m.get("sumNum");
            numberList.add(sumNum);
        }
        //3、封装 SalesTop10ReportVO 返回
        return SalesTop10ReportVO.builder()
                .nameList(StringUtils.join(nameList,","))
                .numberList(StringUtils.join(numberList,","))
                .build();
    }

条件查询

代码演示:

XML 复制代码
<!--    top10销量-->
    <select id="sumTop10" resultType="java.util.Map" parameterType="java.util.Map">
        select od.name,sum(od.number) sumNum from orders o,order_detail od
        where o.id = od.order_id
        and o.status=#{status}
          and order_time &gt;= #{beginTime}
          and order_time &lt;= #{endTime}
        group by od.name
        order by sumNum desc limit 0,10
    </select>

流式查询

注意:可以使用map封装,也可以创建封装实体类dto进行访问。


数据统计,工作台,报表的导出


1、今日内容

报表导出,Apache POI。实现报表导出。

2、工作台-需求+接口分析

需求分析和设计

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

工作台展示的数据:今日数据;订单管理;菜品/套餐总览;订单信息。

名词解释:

接口设计:

3、工作台-代码导入并测试

注意:功能测试,对界面数据进行验证,清除脏数据。

4、Apache POI-介绍

介绍

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

一般情况下,POI都是用来操作Excel文件。

小记:还有easy-Excel。

Apache POI的应用场景:

  • 银行网银系统导出交易明细
  • 各种业务系统导出Excel报表
  • 批量导入业务数据

5、Apache POI-案例1-写数据

入门案例-需求

例子程序进行效果展示:

Apache POI的maven坐标:

代码演示:

java 复制代码
    //需求:通过POI写入数据到指定的excel中
    @Test
    public void testWrite() throws Exception {

        //1、通过POI创建工作簿(文件)对象  --excel对象
        XSSFWorkbook workbook = new XSSFWorkbook();
        //2、通过XSSFWorkbook创建Sheet对象
        XSSFSheet sheet = workbook.createSheet("itcast");
        //3、通过XSSFSheet 创建行对象 Row,下标从0开始,创建第一行就为0
        XSSFRow row = sheet.createRow(0);
        XSSFRow row1 = sheet.createRow(1);
        XSSFRow row2 = sheet.createRow(2);
        //4、通过XSSFRow创建格子,并往格子里填充数据
        //第一行
        row.createCell(0).setCellValue("姓名");
        row.createCell(1).setCellValue("爱好");

        //第二行
        row1.createCell(0).setCellValue("李力");
        row1.createCell(1).setCellValue("篮球");

        //第三行
        row2.createCell(0).setCellValue("刘兵");
        row2.createCell(1).setCellValue("足球");
        //5、将excel文件写出到指定的文件中
        FileOutputStream fos = new FileOutputStream("D:\\demo.xlsx");
        workbook.write(fos);
        System.out.println("写入成功");
        //6、释放资源
        fos.close();
        workbook.close();
    }

6、Apache POI-案例2-基于模板写数据

代码演示:

java 复制代码
    //需求:通过POI写入数据到指定的excel中--基于模板写入
    @Test
    public void testWrite2() throws Exception {

        //1、基于Excel模板文件-->通过POI创建工作簿(文件)对象  --excel对象
        FileInputStream fis = new FileInputStream("D:\\demo.xlsx");
        XSSFWorkbook workbook = new XSSFWorkbook(fis);
        //2、通过XSSFWorkbook 获取Sheet对象
        XSSFSheet sheet = workbook.getSheet("itcast");
        //3、通过XSSFSheet 创建行对象 Row,下标从0开始,创建第一行就为0
        XSSFRow row = sheet.getRow(0);
        XSSFRow row1 = sheet.getRow(1);
        XSSFRow row2 = sheet.getRow(2);
        //4、通过XSSFRow创建格子,并往格子里填充数据
        //第一行
        row.getCell(0).setCellValue("姓名");
        row.getCell(1).setCellValue("爱好");

        //第二行
        row1.getCell(0).setCellValue("李力");
        row1.getCell(1).setCellValue("篮球");

        //第三行
        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();
    }

7、Apache POI-案例3-读数据

代码演示:

java 复制代码
    //需求:通过POI读磁盘中指定的excel文件到Java内存中,输出到控制台
    @Test
    public void testRead() throws Exception {

        //1、基于Excel模板文件-->通过POI创建工作簿(文件)对象  --excel对象
        FileInputStream fis = new FileInputStream("D:\\demo1.xlsx");
        XSSFWorkbook workbook = new XSSFWorkbook(fis);
        //2、通过XSSFWorkbook 获取Sheet对象
        XSSFSheet sheet = workbook.getSheet("itcast");
        //3、循环读取表中的每一行数据
        int firstRowNum = sheet.getFirstRowNum();
        int lastRowNum = sheet.getLastRowNum();
        System.out.println("firstRowNum"+firstRowNum);
        System.out.println("lastRowNum"+lastRowNum);
        for (int rowNum = firstRowNum; rowNum <= lastRowNum; rowNum++) {
            XSSFRow row = sheet.getRow(rowNum);
            String name = row.getCell(0).getStringCellValue();
            String hobby = row.getCell(1).getStringCellValue();
            System.out.println(name+"|"+hobby);
        }
        //5、将获取到的数据输出到控制台
        //6、释放资源
        fis.close();
        workbook.close();
    }
相关推荐
少司府2 小时前
C++基础入门:初识模板
开发语言·c++·c·模板·函数模板·类模板·泛型编程
jinanwuhuaguo2 小时前
OpenClaw范式深度剖析:从技术突破到安全治理的系统性研究(第二篇)
开发语言·人工智能·安全·架构·kotlin·openclaw
knight_9___2 小时前
RAG面试篇7
java·面试·agent·rag·智能体
lly2024062 小时前
C++ 命名空间
开发语言
song8546011342 小时前
idea问题解决
java·ide·intellij-idea
问水っ2 小时前
Qt高级编程 第7章 用QtConcurrent实现线程处理
java·开发语言
SimonKing2 小时前
AI编程工具装了一大堆,Skills 管理乱成粥?这个开源神器一招搞定!
java·后端·程序员
one_love_zfl2 小时前
java面试-微服务篇
java·微服务·面试
代码中介商2 小时前
C语言进程管理与内存管理深度解析
c语言·开发语言