最近在项目开发中,有需要导入、导出excel的功能,使用了alibaba的easyexcel。自己水平太菜,踩了许多坑。在alibaba-easyexcel使用问题总结 这里总结了一番,也涨了点姿势:
- 恶补了下maven的相关知识:maven包冲突的解决方式
- 如果机器上装了“中软防水坝”等相关的安全软件,文件读写是要失败的。因为 inputStream.markSupported()会返回false 从而无法操作 抛出异常 easyexcel是ExcelAnalysisException
io is must be available markSupported。
发现easyexcel也是引用了apache的poi,在poi基础上做了更改。
今天也来学习下使用poi 3.17来导入、导出excel
参考自这里,写的很好,跟着撸一遍
maven依赖
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-collections4</artifactId>
- <version>4.1</version>
- </dependency>
-
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <version>2.4</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.xmlbeans</groupId>
- <artifactId>xmlbeans</artifactId>
- <version>2.6.0</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi</artifactId>
- <version>3.17</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi-ooxml</artifactId>
- <version>3.17</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi-ooxml-schemas</artifactId>
- <version>3.17</version>
- </dependency>
如果你想简化你的代码,可以加上
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>1.16.10</version>
- <scope>provided</scope>
- </dependency>
导入
准备excel表 人员信息.xlsx
创建与excel列名对应的bean
- package io.github.newmean.demo.domain;
-
- import lombok.Data;
-
- import java.util.Date;
- @Data
- public class Persion {
- private String deptName;
- private String createName;
- private Date createDate;
- private String politicStatus;
- private int age;
- }
Lombok 注解在线帮助文档:http://projectlombok.org/features/index
介绍几个常用的 lombok 注解:
- @Data :注解在类上;提供类所有属性的 get 和 set 方法,此外还提供了equals、canEqual、hashCode、toString 方法
- @Setter:注解在属性上;为属性提供 sett方法
- @Getter:注解在属性上;为属性提供 get 方法
- @Log4j :注解在类上;为类提供一个 属性名为log 的 log4j 日志对象
- @NoArgsConstructor:注解在类上;为类提供一个无参的构造方法
- @AllArgsConstructor:注解在类上;为类提供一个全参的构造方法
再加上一个注解,让属性和列名对应起来
- package io.github.newmean.demo.annotation;
-
- import java.lang.annotation.*;
-
- @Target({ElementType.FIELD})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface ExcelColumn {
- public String value() default "";
- }
那么bean就可以改写为:
- package io.github.newmean.demo.domain;
-
- import io.github.newmean.demo.util.ExcelColumn;
- import lombok.Data;
- import lombok.Setter;
- import lombok.ToString;
-
- import java.util.Date;
- @Data
- @ToString
- public class Persion {
- @Setter
- @ExcelColumn(value = "处室")
- private String deptName;
-
- @Setter
- @ExcelColumn(value = "填表人")
- private String createName;
-
- @Setter
- @ExcelColumn(value = "填表时间")
- private Date createDate;
-
- @Setter
- @ExcelColumn(value = "政治面貌")
- private String politicStatus;
-
- @Setter
- @ExcelColumn(value = "年龄")
- private int age;
- }
采用MultipartFile上传,可以读取.xlsx或者.xls格式的Excel(POI3.15以上版本兼容)
- package io.github.newmean.demo.util;
-
- import java.io.IOException;
- import java.io.InputStream;
- import java.lang.reflect.Field;
- import java.text.DecimalFormat;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.Objects;
-
- import io.github.newmean.demo.annotation.ExcelColumn;
-
- import org.apache.commons.io.IOUtils;
- import org.apache.commons.lang3.time.FastDateFormat;
- import org.apache.poi.ss.usermodel.Cell;
- import org.apache.poi.ss.usermodel.DateUtil;
- import org.apache.poi.ss.usermodel.Row;
- import org.apache.poi.ss.usermodel.Sheet;
- import org.apache.poi.ss.usermodel.Workbook;
- import org.apache.poi.ss.usermodel.WorkbookFactory;
- import org.springframework.util.StringUtils;
- import org.springframework.web.multipart.MultipartFile;
-
- public class ExcelUtil {
-
- private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0");// 格式化 number为整
-
- private static final FastDateFormat FAST_DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
-
- /**
- * 对外提供读取excel 的方法
- * @param file
- * @return
- * @throws IOException
- */
- public static List<List<Object>> readExcel(MultipartFile file) throws IOException {
- String extension = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1).toLowerCase();
- if(Objects.equals("xls", extension) || Objects.equals("xlsx", extension)) {
- return readExcel(file.getInputStream());
- } else {
- throw new IOException("不支持的文件类型");
- }
- }
-
- /**
- * 对外提供读取excel 的方法
- * @param file
- * @param cls
- * @return
- * @throws IOException
- */
- public static <T> List<T> readExcel(MultipartFile file, Class<T> cls) throws IOException {
- String extension = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1).toLowerCase();
- if(Objects.equals("xls", extension) || Objects.equals("xlsx", extension)) {
- return readExcel(file.getInputStream(), cls);
- } else {
- throw new IOException("不支持的文件类型");
- }
- }
-
- /**
- * 读取 office excel
- *
- * @param inputStream
- * @return
- * @throws IOException
- */
- public static List<List<Object>> readExcel(InputStream inputStream) throws IOException {
- List<List<Object>> list = new LinkedList<>();
- Workbook workbook = null;
- try {
- workbook = WorkbookFactory.create(inputStream);
- int sheetsNumber = workbook.getNumberOfSheets();
- for (int n = 0; n < sheetsNumber; n++) {
- Sheet sheet = workbook.getSheetAt(n);
- Object value = null;
- Row row = null;
- Cell cell = null;
- for (int i = sheet.getFirstRowNum() + 1; i <= sheet.getPhysicalNumberOfRows(); i++) { // 从第二行开始读取
- row = sheet.getRow(i);
- if (StringUtils.isEmpty(row)) {
- continue;
- }
- List<Object> linked = new LinkedList<>();
- for (int j = row.getFirstCellNum(); j <= row.getLastCellNum(); j++) {
- cell = row.getCell(j);
- if (StringUtils.isEmpty(cell)) {
- continue;
- }
- value = getCellValue(cell);
- linked.add(value);
- }
- list.add(linked);
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- IOUtils.closeQuietly(workbook);
- IOUtils.closeQuietly(inputStream);
- }
- return list;
- }
-
- /**
- * 获取excel数据 将之转换成bean
- * @param cls
- * @param <T>
- * @return
- */
- public static <T> List<T> readExcel(InputStream inputStream, Class<T> cls) {
- List<T> dataList = new LinkedList<>();
- Workbook workbook = null;
- try {
- workbook = WorkbookFactory.create(inputStream);
- Map<String, List<Field>> classMap = new HashMap<>();
- Field[] fields = cls.getDeclaredFields();
- for (Field field : fields) {
- ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
- if (annotation != null) {
- String value = annotation.value();
- if (!classMap.containsKey(value)) {
- classMap.put(value, new ArrayList<>());
- }
- field.setAccessible(true);
- classMap.get(value).add(field);
- }
- }
- Map<Integer, List<Field>> reflectionMap = new HashMap<>();
- int sheetsNumber = workbook.getNumberOfSheets();
- for (int n = 0; n < sheetsNumber; n++) {
- Sheet sheet = workbook.getSheetAt(n);
- for (int j = sheet.getRow(0).getFirstCellNum(); j < sheet.getRow(0).getLastCellNum(); j++) { //首行提取注解
- Object cellValue = getCellValue(sheet.getRow(0).getCell(j));
- if (classMap.containsKey(cellValue)) {
- reflectionMap.put(j, classMap.get(cellValue));
- }
- }
- Row row = null;
- Cell cell = null;
- for (int i = sheet.getFirstRowNum() + 1; i < sheet.getPhysicalNumberOfRows(); i++) {
- row = sheet.getRow(i);
- T t = cls.newInstance();
- for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
- cell = row.getCell(j);
- if (reflectionMap.containsKey(j)) {
- Object cellValue = getCellValue(cell);
- List<Field> fieldList = reflectionMap.get(j);
- for (Field field : fieldList) {
- try {
- field.set(t, cellValue);
- } catch (Exception e) {
- //logger.error()
- }
- }
- }
- }
- dataList.add(t);
- }
- }
- } catch (Exception e) {
- dataList = null;
- } finally {
- IOUtils.closeQuietly(workbook);
- IOUtils.closeQuietly(inputStream);
- }
- return dataList;
- }
-
- /**
- * 获取excel 单元格数据
- *
- * @param cell
- * @return
- */
- private static Object getCellValue(Cell cell) {
- Object value = null;
- switch (cell.getCellTypeEnum()) {
- case _NONE:
- break;
- case STRING:
- value = cell.getStringCellValue();
- break;
- case NUMERIC:
- if(DateUtil.isCellDateFormatted(cell)){ //日期
- value = FAST_DATE_FORMAT.format(DateUtil.getJavaDate(cell.getNumericCellValue()));
- } else if("@".equals(cell.getCellStyle().getDataFormatString())
- || "General".equals(cell.getCellStyle().getDataFormatString())
- || "0_ ".equals(cell.getCellStyle().getDataFormatString())){
- //文本 or 常规 or 整型数值
- value = DECIMAL_FORMAT.format(cell.getNumericCellValue());
- }
- break;
- case BOOLEAN:
- value = cell.getBooleanCellValue();
- break;
- case BLANK:
- //value = ",";
- break;
- default:
- value = cell.toString();
- }
- return value;
- }
- }