Apache POI的简单介绍与应用

news2024/9/27 12:10:06

介绍

Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。PS: 一般情况下,POI 都是用于操作 Excel 文件,如图:
在这里插入图片描述
Apache POI 的应用场景:

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

入门案例

  1. 导入Apache POI的maven坐标:
<dependency>
           <groupId>org.apache.poi</groupId>
           <artifactId>poi</artifactId>
</dependency>
<dependency>
		 <groupId>org.apache.poi</groupId>
		 <artifactId>poi-ooxml</artifactId>
</dependency>
  1. 数据写入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开始,写1表示创建第2行
        XSSFRow row = sheet.createRow(1);
        // 在行中创建单元格, columnIndex也是从0开始,使用setCellValue写入文本内容
        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("北京");

        FileOutputStream out = new FileOutputStream("/home/zxy/Projects/info.xlsx");
        excel.write(out);

        // 关闭资源
        out.close();
        excel.close();
    }

    public static void main(String[] args) throws Exception{
        write();
    }
}

运行效果:
在这里插入图片描述

  1. 从Excel中读取数据
    /**
     * 通过POI读取Excel中的内容
     * @throws Exception
     */
    public static void read() throws Exception{
        // 读取磁盘上已经存在的Excel文件
        FileInputStream in = new FileInputStream(new File("/home/zxy/Projects/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 cellValue1 = row.getCell(1).getStringCellValue();
            String cellValue2 = row.getCell(2).getStringCellValue();
            System.out.println(cellValue1 + "  " + cellValue2);
        }

        // 关闭资源
        excel.close();
        in.close();
    }

    public static void main(String[] args) throws Exception{
        read();
    }

效果:
在这里插入图片描述

应用

场景:导出(并下载)商户最近30天的运营数据
注意:对导出数据的请求并没有返回数据,因为报表导出功能本质上是文件下载,服务端会通过输出流将Excel文件下载到客户端浏览器。
实现步骤:

  1. 设计Excel模板文件
  2. 查询近30天的运营数据
  3. 将查询到的运营数据写入模板文件
  4. 通过输出流将Excel文件下载到客户端浏览器

虽然POI可以设置文件的字体、字号、合并单元格等格式,但这会使得代码变得非常复杂,所以提前在文本编辑器中设置好Excel的模版文件,然后通过读取模版文件来填充数据,从而可以简化代码。

具体代码:
controller部分:

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

Service部分:

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

重点: Service的实现类中对应的方法:

	/**
     * 导出运营数据报表
     *
     * @param response
     */
    @Override
    public void exportBusinessData(HttpServletResponse response) {
        // 1. 查询数据库,获取营业数据 --- 查询最近30天的数据
        LocalDate dateBegin = LocalDate.now().minusDays(30);
        LocalDate dateEnd = LocalDate.now().minusDays(1);

        // 查询概览数据
        BusinessDataVO businessData = 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);

            // 获取第4行
            XSSFRow row = sheet.getRow(3);
            row.getCell(2).setCellValue(businessData.getTurnover());
            row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
            row.getCell(6).setCellValue(businessData.getNewUsers());

            // 获取第5行
            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 = dateBegin.plusDays(i);
                // 查询某一天的数据
                BusinessDataVO businessDataVO = 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(businessDataVO.getTurnover());
                row.getCell(3).setCellValue(businessDataVO.getValidOrderCount());
                row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
                row.getCell(5).setCellValue(businessDataVO.getUnitPrice());
                row.getCell(6).setCellValue(businessDataVO.getNewUsers());

            }

            // 3. 通过输出流将Excel文件下载到客户端浏览器
            ServletOutputStream out = response.getOutputStream();
            excel.write(out);

            // 关闭资源
            out.close();
            excel.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

代码细节补充:
workspaceService.getBusinessData:

@Override
    public BusinessDataVO getBusinessData(LocalDateTime begin, LocalDateTime end) {

        /**
         * 营业额:当日完成订单的总额
         * 有效订单:当日完成订单的数量
         * 订单完成率:有效订单数 / 总订单数
         * 新增用户:当日新增用户的数量
         */

        Map map = new HashMap();
        map.put("begin",begin);
        map.put("end",end);

        // 查询订单总数
        Integer totalOrderCount = orderMapper.getByMap(map);

        map.put("status", Orders.COMPLETED);
        // 营业额
        Double turnover = orderMapper.sumByMap(map);
        turnover = turnover ==null? 0.0 :turnover;

        // 有效订单数
        Integer validOrderCount = orderMapper.getByMap(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();
    }

实现效果:
在这里插入图片描述

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

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

相关文章

韦东山嵌入式Liunx入门驱动开发五

文章目录 一、驱动程序基石1-1 休眠与唤醒1-2 POLL机制1-3 异步通知(1) 异步通知程序解析(2) 异步通知机制内核代码详解 1-4 阻塞与非阻塞1-5 定时器(1) 内核函数(2) 定时器时间单位 1-6 中断下半部 tasklet 本人学习完韦老师的视频&#xff0c;因此来复习巩固&#xff0c;写以…

【web | CTF】BUUCTF [HCTF 2018]WarmUp

天命&#xff1a;这题本地php代码是无法复现的 首先打开网站&#xff0c;啥也没有&#xff0c;查看源码 发现文件&#xff0c;打开访问一下看看&#xff0c;发现是代码审计 <?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whit…

IOS 发布遇到“Unable to authenticate with App Store Connect”错误咋解决?

问题&#xff1a; 在开发ios app后&#xff0c;先发布adhoc版本&#xff0c;测试通过后&#xff0c;再发布testflight版本测试&#xff0c;但是可能会遇到一下问题。 解决办法&#xff1a; 在Signing &Capabilities中&#xff0c;在ios下边要指定有发布权限的Team账号&a…

文件底层的理解之缓冲区

目录 一、缓冲区的初步认识 二、向文件中写数据的具体过程 三、缓冲区刷新的时机 一、缓冲区的初步认识 缓冲区其实就是一块内存区域&#xff0c;采用空间来换时间&#xff0c;可以提高使用者的效率。我们一直说的缓冲区其实是语言层面上的缓冲区&#xff0c;其实操作系统内部…

黑马点评-商户查询业务

缓存原理 本文的业务就是redis的经典应用&#xff0c;标准的操作方式就是查询数据库之前先查询缓存&#xff0c;如果缓存数据存在&#xff0c;则直接从缓存中返回&#xff0c;如果缓存数据不存在&#xff0c;再查询数据库&#xff0c;然后将数据存入redis。 缓存更新策略 根据…

iMazing 3.0.0.3 for mac 中文破解版2024最新图文安装教程

我们刚刚发布了iMazing 3.0.0.3 for mac 中文版本。Windows和macOS用户现在都可以试驾并体验iPhone管理的未来。 备受期待的第一个Windows版本得益于过去几个月macOS测试版的所有改进&#xff0c;使其成为一个稳定的初始版本。 我们的开发团队创造了一种无缝的外观和体验&#…

sql 注入 之sqli-labs/less-6 双注入,双引号报错注入

和第五关类似&#xff0c;只不过闭合符号是双引号 1&#xff0c;查数据库 1"and%20(updatexml(1,concat(0x7e,(select%20database()),0x7e),1))%20-- 2.查表 内容有多行&#xff0c;所以使用limit依次查询 1"and%20(updatexml(1,concat(0x7e,(select%20table_nam…

Spring中的数据校验---JSR303

介绍–什么是JSR303 JSR 303是Java中的一项规范&#xff0c;用于定义在Java应用程序中执行数据校验的元数据模型和API。JSR 303的官方名称是"Bean Validation"&#xff0c;它提供了一种在Java对象级别上执行验证的方式&#xff0c;通常用于确保输入数据的完整性和准…

app软件开发的费用大约多少

现在手机的用户在增多&#xff0c;大部分的人都是通过手机软件去操作完成的东西比较多&#xff0c;所以导致现在的流量都在手机端。那么不管是电脑端还是手机端都是在同时发展的&#xff0c;使用电脑的人群只是倾向在了工作人群&#xff0c;而手机的流量大部分是来自于生活中。…

HarmonyOS—配置编译构建信息

在进行应用/服务的编译构建前&#xff0c;需要对工程和编译构建的Module进行设置。API Version 9、API Version 8与API Version 4~7的构建体系不同&#xff0c;因此在设置编译构建信息时也存在差异&#xff1a; API Version 9&#xff1a;需要对构建配置文件、构建脚本、应用依…

Springboot+vue的考勤管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的考勤管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层…

边缘计算网关的重要作用-天拓四方

随着物联网技术的迅猛发展&#xff0c;数据量的爆炸式增长对数据处理和分析提出了更高的要求。边缘计算网关作为连接物理世界和数字世界的桥梁&#xff0c;正逐渐受到各行业的重视。本文将从行业背景、功能特点以及带来的效益等方面&#xff0c;探讨边缘计算网关在当前及未来的…

HTML中自定义鼠标右键菜单

今天突然有人跟我提到了HTML中如何自定义鼠标右键菜单&#xff0c;这里大概记录一下吧&#xff0c;方便下次直接复制。免得还去看API文档。 文章目录 HTML中自定义鼠标右键菜单结果如下所示可以稍微改一下鼠标悬浮到右键菜单时的样式结果如下所示 只在某个特定的div才可以显示…

来不及了!大学必须完成的四件事!

老师们常说&#xff0c;上大学就轻松了 其实不然 大学不是人生的终点&#xff0c;而是新的起跑线 不是休息站&#xff0c;而是进入社会的最后冲刺跑道 大学生活苦乐参半&#xff0c;成人世界即将来临 出了校门&#xff0c;你会发现社会复杂多变&#xff0c;需要不断学习 稍…

C++之结构体以及通讯录管理系统

1&#xff0c;结构体基本概念 结构体属于自定义的数据概念&#xff0c;允许用户存储不同的数据类型 2&#xff0c;结构体的定义和使用 语法&#xff1a;struct 结构体名{ 结构体成员列表}&#xff1b; 通过结构体创建变量的方式有三种&#xff1a; 1&#xff0c;struct …

在Jupyter-lab中使用RDKit画分子2D图

在Jupyter-lab中使用RDKit画分子2D图 在做完分子对接后&#xff0c;想看看筛选后的分子的结构。因此想利用Jupyter-lab来画分子的2D图。 1. 安装Jupyter-lab与RDKit 系统&#xff1a;Win11已安装conda RDKit 是一个功能强大、灵活易用的化学信息学工具包&#xff0c;广泛应…

前端CSS常考问题总结

目录 CSS盒模型 CSS选择器的优先级 隐藏元素的方法 px和rem的区别是什么? 重绘重排有什么区别? 重排&#xff08;回流&#xff09;&#xff1a; 重绘&#xff1a; 浏览器的渲染机制: 浏览器如何解析CSS&#xff1f; 元素水平垂直居中的方式 CSS的哪些属性哪些可以…

队列循环——C++引用详解【入队元素不引用 出队元素引用】(C语言版)

出队元素引用 入队元素不引用解释&#xff1a; 在给定的代码中&#xff0c;对于 DeQueue 函数的参数使用引用 (&)&#xff0c;而对于 EnQueue 函数的参数没有使用引用&#xff0c;是基于函数内部对这些参数值的修改方式来确定的。 让我们分析一下每个函数&#xff1a; En…

SQL-Labs靶场“29-31”关通关教程

君衍. 一、二十九关 基于错误的WAF单引号注入1、源码分析2、HTTP参数污染3、联合查询注入4、updatexml报错注入 二、三十关 基于错误的WAF双引号注入1、源码分析2、联合查询注入3、updatexml报错注入 三、三十一关 基于错误的WAF双引号括号注入1、源码分析2、联合查询注入3、up…

windows10下如何通过命令行方式新增一个外部WLAN的Wifi热点并连接

☞ ░ 前往老猿Python博客 ░ https://blog.csdn.net/LaoYuanPython 一、背景 最近碰到2个家人windows下连接电脑热点的问题&#xff0c;一个是在某个培训场所显示的热点名称不是公布的热点名称&#xff0c;而是一个乱码&#xff0c;在家里和工作单位热点则显示正常&#xff…