本文是使用 org.apache.poi 进行一次简单的封装,适用于大部分 excel 导入导出功能。过程中可能会用到反射,如若有对于性能有极致强迫症的同学,看看就好。

由于 poi 本身只是针对于 excel 等office软件的一个工具包,在一些常规的 excel 导入导出时,还需要再做一次精简的封装,简化代码耦合。

一、现状

本人经历过几家公司的代码封装,导入导出一般存在下面的情况。

1.1 导入

  1. 传入文件地址,返回 Sheet 对象,在业务代码中进行循环遍历,做相对应的类型转换,业务处理(二零零几年的代码框架)
  2. 传入文件地址,返回 List<String, Object> 的对象,外部直接做强转
  3. 传入文件地址,返回 List<String, String> 的对象,外部将字符串对象转换为对应的类型

总结:如果只有上述的选择,本人是比较倾向于第二种,毕竟对外层是非常友好的

1.2 导出

  1. 直接在逻辑代码中进行遍历封装sheet,传入到生成file的方法中(二零零几年的代码框架)
  2. 先循环遍历 List 对象,转换为 List<Map<String, String>> 对象,带上 fieldName 传入到封装好excel生成的方法中,内部则使用 map.get() 方法操作
  3. 直接将 List 对象带上 fieldName 传入到封装好excel生成的方法中,内部将 Model 对象转换为 JSONObject,然后使用 jsonObj.get() 方法操作
  4. 先将 List 转换为 JSONArray ,带上 fieldName 传入到封装好excel生成的方法中,内部将 Model 对象转换为 JSONObject,然后使用 jsonObj.get() 方法操作。(使用这种做法,据分析应该是为了执行 jsonConfig.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor(“yyyy-MM-dd HH:mm:ss”)); 这行代码,可能是为了解决日期类型格式问题)

总结:如果只有上述的选择,本人是比较倾向于第三种,第三种只遍历一次,并且外部未做处理。但是按第四种模式来看,那么第三种模式还是会存在日期格式问题,这个我们后续再分析如何处理。

二、导入

2.1 方法定义

/**
* excel导入
* @param keys 字段名称数组,如 ["id", "name", ... ]
* @param filePath 文件物理地址
* @return
* @author yzChen
* @date 2016年12月18日 下午2:46:51
*/
public static List<Map<String, Object>> imp(String filePath, String[] keys)
throws Exception {}

2.2 循环处理模块

// 遍历该行所有列
for (short j = 0; j < cols; j++) {
cell = row.getCell(j);
if(null == cell) continue; // 为空时,下一列 // 根据poi返回的类型,做相应的get处理
if(Cell.CELL_TYPE_STRING == cell.getCellType()) {
value = cell.getStringCellValue();
} else if(Cell.CELL_TYPE_NUMERIC == cell.getCellType()) {
value = cell.getNumericCellValue(); // 由于日期类型格式也被认为是数值型,此处判断是否是日期的格式,若时,则读取为日期类型
if(cell.getCellStyle().getDataFormat() > 0) {
value = cell.getDateCellValue();
}
} else if(Cell.CELL_TYPE_BOOLEAN == cell.getCellType()) {
value = cell.getBooleanCellValue();
} else if(Cell.CELL_TYPE_BLANK == cell.getCellType()) {
value = cell.getDateCellValue();
} else {
throw new Exception("At row: %s, col: %s, can not discriminate type!");
} map.put(keys[j], value);
}

2.3 使用

String filePath = "E:/order.xls";
String[] keys = new String[]{"id","brand"}; List<Map<String, Object>> impList;
try {
impList = ExcelUtil.imp(filePath, keys); for (Map<String, Object> map : impList) {
System.out.println(map.get("brand"));
}
} catch (Exception e) {
e.printStackTrace();
}

2.4 分析

  1. 入口只需要传入文件名称,以及外部需要读取的key即可
  2. 内部处理,则针对 数值型、日期类型、字符串 类型已经做了对应处理,外部则直接进行强转对应的类型即可

三、导出

3.1 方法定义

/**
* excel导出
* @param fileNamePath 导出的文件名称
* @param sheetName 导出的sheet名称
* @param list 数据集合
* @param titles 第一行表头
* @param fieldNames 字段名称数组
* @return
* @throws Exception
* @author yzChen
* @date 2017年5月6日 下午3:53:47
*/
public static <T> File export(String fileNamePath, String sheetName,
List<T> list, String[] titles, String[] fieldNames) throws Exception {}

3.2 循环处理模块

// 遍历生成数据行,通过反射获取字段的get方法
for (int i = 0; i < list.size(); i++) {
t = list.get(i);
HSSFRow row = sheet.createRow(i+1);
Class<? extends Object> clazz = t.getClass();
for(int j = 0; j < fieldNames.length; j++){
methodName = "get" + capitalize(fieldNames[j]);
try {
method = clazz.getDeclaredMethod(methodName);
} catch (java.lang.NoSuchMethodException e) { // 不存在该方法,查看父类是否存在。此处只支持一级父类,若想支持更多,建议使用while循环
if(null != clazz.getSuperclass()) {
method = clazz.getSuperclass().getDeclaredMethod(methodName);
}
}
if(null == method) {
throw new Exception(clazz.getName() + " don't have menthod --> " + methodName);
}
ret = null == method.invoke(t) ? null : method.invoke(t) + "";
setCellGBKValue(row.createCell(j), ret + "");
}
}

3.3 使用

String[] titles = new String[]{"Id", "Brand"};
String[] fieldNames = new String[]{"id", "brand"};
List<Order> expList = new ArrayList<Order>();
Order order = new Order();
order.setId(1L);
order.setBrand("第三方手动阀");
expList.add(order);
order = new Order();
order.setId(2L);
order.setBrand("scsdsad");
expList.add(order); String fileNamePath = "E:/order.xls";
try {
ExcelUtil.export(fileNamePath, "订单", expList, titles, fieldNames);
} catch (Exception e) {
e.printStackTrace();
}

3.4 总结

  1. 入口主要是需要传入 List 数据集合,以及 fieldNames 字段名称
  2. 内部处理,是直接通过反射获得 get 方法的返回值,进行强转为字符串进行导出
  3. 为了兼容继承父类的一些共有字段的设计,则加上了一层父类的方法读取

四、关于日期类型导出处理

1.1 日期字段导出指定格式内容

  1. 建议在 Model 类中,新增一个扩展字段,并封装一个 get 方法,内容则只是对原字段进行转换,导出时,fieldName 则传递扩展字段即可。如 createTime,示例如下:
private Date createTime;
private String createTimeStr; // 扩展字段 public Date getCreateTime() {
return createTime;
} public void setCreateTime(Date createTime) {
this.createTime = createTime;
} public String getCreateTimeStr() {
createTimeStr = DateUtil.formatDatetime(this.createTime);
return createTimeStr;
}

My Blog

blog.guijianpan.com

技术交流

基于 POI 封装 ExcelUtil 精简的 Excel 导入导出的更多相关文章

  1. 基于EPPlus和NPOI实现的Excel导入导出

    基于EPPlus和NPOI实现的Excel导入导出 CollapseNav.Net.Tool.Excel(NuGet地址) 太长不看 导入 excel 文件流将会转为 ExcelTestDto 类型的 ...

  2. Java基础学习总结(49)——Excel导入导出工具类

    在项目的pom文件中引入 <dependency> <groupId>net.sourceforge.jexcelapi</groupId> <artifac ...

  3. 一个基于POI的通用excel导入导出工具类的简单实现及使用方法

    前言: 最近PM来了一个需求,简单来说就是在录入数据时一条一条插入到系统显得非常麻烦,让我实现一个直接通过excel导入的方法一次性录入所有数据.网上关于excel导入导出的例子很多,但大多相互借鉴. ...

  4. java简易excel导入导出工具(封装POI)

    Octopus 如何导入excel 如何导出excel github项目地址 Octopus Octopus 是一个简单的java excel导入导出工具. 如何导入excel 下面是一个excel文 ...

  5. Java之POI的excel导入导出

    一.Apache POI是一种流行的API,它允许程序员使用Java程序创建,修改和显示MS Office文件.这由Apache软件基金会开发使用Java分布式设计或修改Microsoft Offic ...

  6. poi excel导入导出

    pom <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artif ...

  7. SpringBoot集成文件 - 集成POI之Excel导入导出

    Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能.本文主要介绍通过Spr ...

  8. 利用反射实现通用的excel导入导出

    如果一个项目中存在多种信息的导入导出,为了简化代码,就需要用反射实现通用的excel导入导出 实例代码如下: 1.创建一个 Book类,并编写set和get方法 package com.bean; p ...

  9. 土制Excel导入导出及相关问题探讨

    转载请注明出处https://www.cnblogs.com/funnyzpc/p/10392085.html 新的一年,又一个开始,不见收获,却见年龄,好一个猪年,待我先来一首里尔克的诗: < ...

随机推荐

  1. google hacker语法

    intext:关键字 搜索网页正文中含有这些关键字的网页. intitle:关键字 搜索网页标题中含有这些关键字的网页. cache:关键字 搜索含有关键字内容的cache. define:关键字 搜 ...

  2. 进制转换 Java day6

    今天周末学习的不多,只学习了一些二进制转十进制,八进制.十六进制,以及数据单位 二进制转十进制 我们都知道十进制转二进制就是除以2取余的方法.那二进制转到十进制又如何处理呢,今天我来学习以下 我们看看 ...

  3. luoguP4859 已经没有什么好害怕的了(二项式反演)

    luoguP4859 已经没有什么好害怕的了(二项式反演) 祭奠天国的bzoj. luogu 题解时间 先特判 $ n - k $ 为奇数无解. 为了方便下记 $ m = ( n + k ) / 2 ...

  4. bzoj4596/luoguP4336 [SHOI2016]黑暗前的幻想乡(矩阵树定理,容斥)

    bzoj4596/luoguP4336 [SHOI2016]黑暗前的幻想乡(矩阵树定理,容斥) bzoj Luogu 题解时间 看一看数据范围,求生成树个数毫无疑问直接上矩阵树定理. 但是要求每条边都 ...

  5. CSC3100

    其实是存一下代码 1. AVL的java实现 维护一下每个点左右子树深度差,差绝对值大于2就转,转的方式和treap, splay转的方式差不多.旋转操作可以使两端差归零变得更平衡. 虽然平衡但转的次 ...

  6. 【vue】中英文切换(使用 vue-i18n )

    一.准备工作 1.vue-i18n 1.仓库地址 2.兼容性:支持 Vue.js 2.x 以上版本 1-1.安装依赖vue-i18n (c)npm install vue-i18n 1-2.使用 在 ...

  7. spring-boot-learning 缓存之redis

    什么是BSD协议: BSD是"Berkeley Software Distribution"的缩写,意思是"伯克利软件发行版". BSD开源协议是一个给于使用者 ...

  8. SpringDataJdbc整合MyBatis方式

    由于官方文档springdatajdbc整合mybatis过于简述,导致死磕了一段时间, SpringDataJdbc整合Mybatis的官方文档:https://docs.spring.io/spr ...

  9. 爬虫-数据解析-xpath

    xpath 解析 模块安装 : pip install lxml xpath的解析原理 实例化一个etree类型的对象,且将页面源码数据加载到该对象中 需要调用该对象的xpath方法结合着不同形式的x ...

  10. 用 JWT 实现小程序本地用户标识

    panda-chat-room 继上节「理解小程序 session」 ,本节我们以 jsonwebtoken 来实现小程序端的用户状态标识.如果你对小程序用户登录流程及 session 管理还有些疑惑 ...