poi 和 EasyPoi

poi 和 EasyPoi
POI
什么是 POI
Apache Poi 是 Apache 的一个开源项目,通过 poi 的 api 可以 实现Java代码 读取 和 生成 Excel 文档

为什么要学这个技术?
应用场景

Excel 导入,批量注册

教务管理系统,Excel文件中----》通过Poi读取到系统中

Excel 导出

批量导出,凭条打印,收据打印,统计信息导出(订单量 销售量)等

xls 07版以前

xlsx 07版以后

poi 支持两种格式 jxl只支持一种格式xls

文件读取导出只能是流

文件

文本文件 java txt 代码通过流读取之后可以直接解析为被识别字符串
二进制文件 mp3 MP4 Excel 流不能直接识别 解码器 通过Poi来解析Excel文件
Poi中常见API
通过Windows电脑怎么操作Excel? 写入华为两个字儿

新建一个Excel文件 HSSFWorkbook
在文件中新建一张表 HSSFSheet
确定数据要写到哪一行 3 HSSFRow
确定哪一个单元格 3 HSSFCell
将数据写入单元格中 set方法
保存
Excel中的概念 Poi对应的对象
Excel 文件 HSSFWorkbook (xls老版本的Excel)XSSFWorkbook(xlsx新版本的Excel)
Excel 的工作表 HSSFSheet
Excel 的行 HSSFRow
Excel 中的单元格 HSSFCell
Excel 字体 HSSFFont
Excel 单元格样式 HSSFCellStyle
Excel 颜色 HSSFColor
合并单元格 CellRangeAddress
第一个demo
通过Java代码生成如下Excel文件

1601172222503

导入依赖

org.apache.poi poi 3.16 在测试类中直接写代码

/**
* 测试导出
*/
@Test
public void test1() throws IOException {
// 1. 新建一个Excel文件 HSSFWorkbook
HSSFWorkbook workbook = new HSSFWorkbook();

// 2. 在文件中新建一张表 HSSFSheet
HSSFSheet sheet = workbook.createSheet(“brands”);

// 3. 确定数据要写到哪一行 3 HSSFRow 下标从0开始
HSSFRow row = sheet.createRow(2);

// 4. 确定哪一个单元格 3 HSSFCell
HSSFCell cell = row.createCell(2);

// 5. 将数据写入单元格中 set方法
cell.setCellValue(“华为”);

// 6. 保存 将workbook保存到磁盘中 生成Excel文件
/**
* 流 本身只能够读取和写出数据
* - 文本文件 可以被Java代码识别
* - 二进制文件 mp3 mp4 Excel 等 一般都需要特殊的编解码器
*
* 流负责读取和写出
* Poi 负责解析和生成【Excel文件的编解码器】
*/
workbook.write(new FileOutputStream(“E://brands.xls”));
}
作业:

使用POI生成如下Excel文件 表头

1601172849412

使用POI生成如下Excel文件【选做】

将数据库中品牌表的内容写出到Excel文件,效果如下

1601172934078

复习一下反射

作业
/**
*
/
@Test
public void test2() throws IOException {
String[] titles = {“品牌id”,“名字”,“首字母”,“排序”,“状态”,“logo”,“描述”};
List brands = brandService.list();
/
*
* 1. 写出表头数据
*/
HSSFWorkbook workbook = new HSSFWorkbook();

    HSSFSheet sheet = workbook.createSheet("brands");

    HSSFRow titleRow = sheet.createRow(0);

    for (int i = 0; i < titles.length; i++) {

// 创建单元格
HSSFCell cell = titleRow.createCell(i);

        cell.setCellValue(titles[i]);
    }
    /**
     * 2. 写出品牌数据
     *
     * 1 ---- x
     */
    for (int i = 0; i < brands.size(); i++) {
        HSSFRow row = sheet.createRow(i + 1);

// 将对象的数据写入行中
PmsBrand brand = brands.get(i);

        row.createCell(0).setCellValue(brand.getBrandId());
        row.createCell(1).setCellValue(brand.getName());
        row.createCell(2).setCellValue(brand.getFirstLetter());
        row.createCell(3).setCellValue(brand.getSort());
        row.createCell(4).setCellValue(brand.getShowStatus());
        row.createCell(5).setCellValue(brand.getLogo());
        row.createCell(6).setCellValue(brand.getBrandStory());
    }


    workbook.write(new FileOutputStream("E://allBrands.xls"));
}

Excel文件的导入
Excel文件的导入是导出的反过程

通过流读取文件 —》 通过POi解析流 获取流中的数据

/**
* 读取
*/
@Test
public void test3() throws Exception {
// 通过流读取数据
FileInputStream inputStream = new FileInputStream(“E://brands.xls”);

// 通过Poi解析流
HSSFWorkbook workbook = new HSSFWorkbook(inputStream);

// 通过文件对象获取表对象 getSheetAt 根据下标获取表
HSSFSheet sheet = workbook.getSheetAt(0);

// 根据表获取行
// 获取最后一行的下标 1—>最后一行的下标
int lastRowNum = sheet.getLastRowNum();

    for (int i = 1; i <= lastRowNum; i++) {

// 获取行
HSSFRow row = sheet.getRow(i);
// 获取行中的数据 封装到对象中
PmsBrand pmsBrand = new PmsBrand();
/**
* getNumericCellValue 获取数字类型
* getStringCellValue 获取String类型
*/
double id = row.getCell(0).getNumericCellValue();
pmsBrand.setBrandId((long) id);

        String name = row.getCell(1).getStringCellValue();
        pmsBrand.setName(name);

        pmsBrand.setFirstLetter(row.getCell(2).getStringCellValue());

        pmsBrand.setSort((int) row.getCell(3).getNumericCellValue());

        pmsBrand.setShowStatus((int) row.getCell(4).getNumericCellValue());

        pmsBrand.setLogo(row.getCell(5).getStringCellValue());

        pmsBrand.setBrandStory(row.getCell(6).getStringCellValue());

// 添加数据库
brandMapper.insert(pmsBrand);
}
}
反射优化导出代码【了解】
1601190740649

复习反射
/**
* 复习反射
*/
@Test
public void test4() throws Exception {
PmsBrand brand = new PmsBrand();
brand.setName(“华为”);

    PmsBrand brand1 = new PmsBrand();
    brand1.setName("苹果");
    /**
     * 获取类对象 三种获取方式
     *
     * 类对象 记录类定义的所有信息 例如:有什么方法  有什么属性  属性是什么类型
     *
     * 能直接拿到属性值吗?不能
     *
     * 可以通过类对象+具体的某个品牌对象 获取品牌对象的属性值
     */
    Class<? extends PmsBrand> brandClass = brand.getClass();

    /**
     * 获取属性信息
     * getFields 获取所有公开的属性对象
     * getDeclaredFields 获取所有的属性对象
     */
    Field[] fields = brandClass.getDeclaredFields();

    for (Field field : fields) {
        /**
         * 根据 属性对象+brand对象 获取属性值
         *
         * setAccessible 设置访问权限
         *
         * get 获取对象的属性值
         */
        field.setAccessible(true);

        Object o = field.get(brand1);

        System.out.println(o);
    }

    System.out.println("----------------------------------");
    /**
     * 获取方法对象
     */
    Method[] methods = brandClass.getMethods();

    for (Method method : methods) {

// 获取方法的实际类型 属于哪个类
Class<?> methodDeclaringClass = method.getDeclaringClass();
// 根据方法属于的类 筛选 只留下在PmsBrand中定义方法
if (methodDeclaringClass.getSimpleName().equals(“PmsBrand”)) {
// 筛选出来get方法
if (method.getName().contains(“get”)) {
// 调用get方法 invoke调用方法 获取返回值
// 参数1 要调用哪个对象的方法 参数2 被调用方法的形参
Object invoke = method.invoke(brand1, null);
System.out.println(invoke);
}
}

    }
}

优化导出代码
@Test
public void test2() throws Exception {
/**
* 准备数据
*/
String[] titles = {“品牌id”,“品牌名字”,“首字母”,“排序”,“显示状态”,“logo”,“描述”};
List pmsBrands = brandMapper.selectList(null);

// 创建文件对象
HSSFWorkbook workbook = new HSSFWorkbook();

// 创建表
HSSFSheet sheet = workbook.createSheet(“brands”);

    /**
     * 写入表头
     */
    HSSFRow titleRow = sheet.createRow(0);

    for (int i = 0; i < titles.length; i++) {

// 创建单元格
HSSFCell cell = titleRow.createCell(i);

        cell.setCellValue(titles[i]);
    }

    /**
     * 写入品牌表的数据
     */
    for (int i = 0; i < pmsBrands.size(); i++) {

// 创建行
HSSFRow row = sheet.createRow(i + 1);

// 获得品牌对象
PmsBrand brand = pmsBrands.get(i);

// 将数据写入到行中
/**
* 问题:一个字段就需要写一行,一百个字段就需要写一百行。
* 如果说可以遍历对象的属性值,就可以实现一个循环获取对象的所有数据
* 写出到Excel中
*
* 如何遍历对象的属性值?通过反射可以达到
*/
// 1.获取类对象
Class<? extends PmsBrand> brandClass = brand.getClass();

// 2.获取属性对象
Field[] fields = brandClass.getDeclaredFields();

        for (int j = 0; j < fields.length; j++) {

// 3.创建单元格
HSSFCell cell = row.createCell(j);

// 4.获取属性值
Field field = fields[j];
field.setAccessible(true);
Object value = field.get(brand);

// 5.将属性值写入到单元格中
cell.setCellValue(value.toString());
}

    }

    workbook.write(new FileOutputStream("E://brands.xls"));
}

问题:读取的时候可能会保存

image-20200512150054483

解决方案:在读取的时候 添加判断

image-20200512150445831

EasyPoi
实际开发中

如果需求简单,需要使用poi的模块不过 使用原始poi即可

需求非常的复杂的时候

如果需求稍微复杂 会使用封装好的工具类

自己封装 【很少见】
公司的大牛封装 【很少见】
使用开源的项目 EasyPoi EasyExcel
EasyPoi简介
参考资料:

阿里开源EasyExcel【大批量数据导入导出】
SpringBoot集成easypoi【没有什么明显短板 常用的功能都有封装 大批量数据导入导出性能不如EasyExcel】
easypoi官网
easypoi功能如同名字easy,主打的功能就是容易,让一个没有接触过poi的人员就可以方便的写出Excel导出,Excel导入,通过简单的注解,完成以前复杂的写法

EasyPoi 的基本导入导出
导入依赖

image-20200512161418070

cn.afterturn easypoi-base 3.2.0 cn.afterturn easypoi-web 3.2.0 cn.afterturn easypoi-annotation 3.2.0 给要导入导出的实体类加注解

image-20200512161634630

1601195826475

@Data
@EqualsAndHashCode(callSuper = false)
public class PmsBrand implements Serializable {

/**
 * 品牌id
 */
@TableId(value = "brand_id", type = IdType.AUTO)
@Excel(name = "品牌id")
private Long brandId;
/**
 * 名称
 */
@Excel(name = "品牌名字")
private String name;
/**
 * 首字母
 */
@Excel(name = "首字母")
private String firstLetter;
/**
 * 排序
 */
@Excel(name = "排序")
private Integer sort;
/**
 * 是否显示[0-不显示;1-显示]
 */
@Excel(name = "显示状态")
private Integer showStatus;
/**
 * 品牌logo
 */
@Excel(name = "logo")
private String logo;
/**
 * 品牌描述
 */
@Excel(name = "描述")
private String brandStory;
}


3. 直接使用EasyPoi的api完成导入导出

   1. 导出
   /**
       * 导出
       */
      @Test
      public void test1() throws Exception {
          /**
           * 准备数据
           */
          List<PmsBrand> pmsBrands = brandMapper.selectList(null);
          /**
           * 导出参数对象
           * 参数1 标题
           * 参数2 表名
           */
          ExportParams params = new ExportParams("所有的品牌数据","brands");
          /**
           * ExcelExportUtil 导出工具类
           * exportExcel 导出方法
           * 参数1 导出参数对象
           * 参数2 要导出数据的类对象
           * 参数3 要导出的数据
           */
          Workbook workbook = ExcelExportUtil.exportExcel(params, PmsBrand.class, pmsBrands);

          /**
           * 可以自适应两种格式 xls xlsx
           */
          workbook.write(new FileOutputStream("E://easyBrands.xlsx"));
      }

导入

只要能够正常导出 就能够导入 不需要修改注解

/**
* 导入
/
@Test
public void test2() throws Exception {
FileInputStream inputStream = new FileInputStream(“E://easyBrands.xlsx”);
/
*
* 导入参数对象
* setTitleRows 声明标题占有的行数
* setHeadRows 声明表头占有的行数
/
ImportParams importParams = new ImportParams();
importParams.setTitleRows(1);
importParams.setHeadRows(1);
/
*
* 导入方法
* 参数1 流
* 参数2 类对象
* 参数3 导入参数对象
*/
List pmsBrands = ExcelImportUtil.importExcel(inputStream, PmsBrand.class, importParams);

    for (PmsBrand brand : pmsBrands) {
        System.out.println(brand);
    }
}

值的替换
Easypoi的功能 都是通过注解实现的 基本来所有的功能修改都不需要修改代码

只需要修改注解即可

1601196608720

在实体类修改注解

1592556545156

1601196750077

直接使用导入导出代码

图片的导出
1592557054271

相对路径很多情况下 和打包之后的项目结构有关系 能不用相对路径就不要使用相对路径

绝对路径

本地绝对路径
F:\IDEAWorkSpace\cmfzdemo\src\main\webapp\img\captcha.jpg

1592557729002

网络绝对路径 项目必须启动才能访问到数据
http://192.168.22.192:8802/cmfz/hhh.jpg

实现步骤

修改数据库测试数据

image-20201224152809781

实体类加注解

1601197170175

直接导出即可

/**

  • 导出
    /
    @Test
    public void test1() throws IOException {
    /
    *
    • logo.JPG
      /
      List list = brandMapper.selectList(null);
      /
      *
    • 处理路径
    • 本地绝对 G:\05 后期项目\bzmall\bzmall-admin\src\main\webapp\img\logo.JPG
      /
      for (PmsBrand brand : list) {
      brand.setLogo(“G:\05 后期项目\bzmall\bzmall-admin\src\main\webapp\img\”+brand.getLogo());
      }
      /
      *
    • 导出参数对象
    • 参数1 标题
    • 参数2 表名
      /
      ExportParams params = new ExportParams(“所有品牌数据”,“brands”);
      /
      *
    • ExcelExportUtil Excel导出工具类
    • 参数1 导出参数对象
    • 参数2 普通Java对象的类对象 要导入导出的类
    • 参数3 要导出数据集合
      /
      Workbook workbook = ExcelExportUtil.exportExcel(params, PmsBrand.class, list);
      /
      *
    • xls 07版
    • xlsx 07版
      */
      workbook.write(new FileOutputStream(“E://brands.xlsx”));
      }
      图片导入
      默认Easypoi是开启图片导入的,但是默认的图片上传路径时 /excel/upload

默认的文件上传路径,是相对于当前盘符,例如:如果项目在E盘,图片上传的默认路径就是 E:\excel\upload\img

1601197968417

需求:进行图片导入的配置,自定义图片保存的路径

例如:保存到E:\后期项目\bzmall\bzmall-admin\src\main\webapp\img文件夹中

1592791615071

修改实体类注解

1604388956999

直接使用导入就可以导入图片 效果如下

1592791756030

模板导出【了解】
导出 收据 凭条 单据 等等 有固定格式的Excel文件,例如:

1592791854987

模板导出流程:

准备一个固定格式的Excel文件 作为模板

通过Easypoi的表达式定义模板

1601259456298

通过程序读取Excel模板 将数据填充到Excel文件中

数据如何填写Excel文件中?通过Map

将填充好数据的Excel文件输出

EasyPoi 模板导出

准备好一个Excel模板文件 在模板中需要写入指令

1592792231958

1592791854987

直接使用Easypoi导出数据

1592792572598


模板导出的代码
*/
@Test
public void test10() throws IOException {

/**
 * 0 读取准备好的模板文件
 */
TemplateExportParams params = new TemplateExportParams("F://专项支出用款申请书_模板.xls");

/**
 * 1 准备要往模板中填写的数据 需要是一个map
 *
 * 模板中的表达式 会在写出的时候获取map中的值 填写到模板中
 */
Map<String, Object> map = new HashMap<String, Object>();
map.put("date", "2014-12-25");
map.put("money", 2000000.00);
map.put("upperMoney", "贰佰万");
map.put("company", "执笔潜行科技有限公司");
map.put("bureau", "财政局");
map.put("person", "JueYue");
map.put("phone", "1879740****");
List<Map<String, String>> listMap = new ArrayList<Map<String, String>>();
for (int i = 0; i < 4; i++) {
    Map<String, String> lm = new HashMap<String, String>();
    lm.put("id", i + 1 + "");
    lm.put("zijin", i * 10000 + "");
    lm.put("bianma", "A001");
    lm.put("mingcheng", "设计");
    lm.put("xiangmumingcheng", "EasyPoi " + i + "期");
    lm.put("quancheng", "开源项目");
    lm.put("sqje", i * 10000 + "");
    lm.put("hdje", i * 10000 + "");

    listMap.add(lm);
}
map.put("maplist", listMap);
       /**
        * 2.执行导出代码
        *
        * 参数1 模板导出参数对象TemplateExportParams  本质上就读取了模板文件(模板文件就是 固定的格式+表达式)
        * 参数2 需要向模板中填充的数据 Map
        */
       Workbook workbook = ExcelExportUtil.exportExcel(params, map);
// 写出
FileOutputStream fos = new FileOutputStream("F://专项支出用款申请书_导出文件1.xls");
workbook.write(fos);
fos.close();

   }

   效果如下 

   ![1592793274120](https://gitee.com/bingqilinpeishenme/blogimg/raw/master/img/20210409162242.png)



## POI和项目集成的方案【作业】

需要在品牌模块上集成 导入导出功能

![1606382613330](https://gitee.com/bingqilinpeishenme/blogimg/raw/master/img/20210409162243.png)



> 前端代码几乎和之前的图片上传 下载没有什么区别

1. 上传的关键代码

   ![image-20200302174908713](https://gitee.com/bingqilinpeishenme/blogimg/raw/master/img/20210409162244.png)



2. 下载的关键代码
response.setHeader("Content-Disposition",
"attachment;fileName="

       + URLEncoder.encode(fileName,"utf-8"));
response.setContentType("application/vnd.ms-excel");

workbook.write(response.getOutputStream());

总结:

Easypoi基本使用 练习

值的替换 练习

poi 集成 品牌模块

反射优化 【了解内容】

图片 导入导出 测试类按照demo练习

模板导出 【了解】

百万数据导入导出 【了解】

数据库中添加百万数据 Mybatis 批量添加

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值