java poi导入Excel通用工具类
http://blog.csdn.net/daochuwenziyao/article/details/77914826
问题引入和分析
提示:如果不想看罗嗦的文章,可以直接到最后点击源码下载运行即可
最近在做一个导入Excel的功能,在做之前在百度上面查找“java通用导入Excel工具类”,没有查到,大多数都是java通用导出Excel。后来仔细想想,导出可以利用java的反射,做成通用的,放进相应的实体成员变量中,导入为什么不可以呢?也是可以的,不过在做之前我们要解决如下两个问题:
1.表格中的列数和顺序要和实体类中的成员变量个数和顺序一致。
2.表格中的列的类型要和成员变量的类型一致。
第一个问题:
列数一致可以做到,但是我们最后都是要插入数据库的。那么id是必不可少的,或者良好的习惯可能还有创建时间,创建人等信息。
所以我想到了两个办法:
1.封装一个Vo,只将需要的字段封装进去,并且字段顺序和表格列的顺序一致,再将vo与实体类po转化(用PropertyUtil.copy方法);
2.在需要的成员变量上注入自定义注解,并且加入注解的这些字段顺序和表格列的顺序一致,利用反射得到这些字段。
这里主要利用第二个方法,因为扩展性更好
第二个问题:
获取表格数据的时候,我们要判断类型,并取得相应值,全部转化为String类型,当我们给实体类赋值的时候,利用反射获取需要的成员变量的类型,并赋值。
需求
假设我们需求的excel如下:
我们可以看做两部分:
第一部分:
第二行到第11行,为一个列表数据,共有字段5个,分别为:学号,姓名,身份证号码,性别,分数
第二部分:
第12行第五列,第12行第六列,共有字段2个,分别为:总计,平均
项目
需要导入的jar包
如若maven项目导入下面的jar包
- <!-- poi操作excel -->
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi-ooxml</artifactId>
- <version>3.8</version>
- </dependency>
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi</artifactId>
- <version>3.8</version>
- </dependency>
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi-ooxml-schemas</artifactId>
- <version>3.8</version>
- </dependency>
- <!-- beanutils -->
- <dependency>
- <groupId>commons-beanutils</groupId>
- <artifactId>commons-beanutils</artifactId>
- <version>1.8.3</version>
- </dependency>
- <!-- commons-lang-->
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.6</version>
- </dependency>
非maven项目导入下面的jar(下面例子当中用到的jar,有些没用到,可自行处理)
commons-beanutils-1.8.3.jar
commons-lang-2.6.jar
commons-logging-1.1.jar
dom4j-1.6.1.jar
log4j-1.2.13.jar
poi-3.8-20120326.jar
poi-excelant-3.8-20120326.jar
poi-ooxml-3.8-20120326.jar
poi-ooxml-schemas-3.8-20120326.jar
poi-scratchpad-3.8-20120326.jar
stax-api-1.0.1.jar
xmlbeans-2.3.0.jar
项目结构
工具类
- package com.dao.chu.excel;
- import java.io.IOException;
- import java.io.InputStream;
- import java.lang.reflect.Field;
- import java.math.BigDecimal;
- import java.text.DecimalFormat;
- import java.text.ParseException;
- import java.text.SimpleDateFormat;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.List;
- import java.util.Locale;
- import org.apache.commons.beanutils.PropertyUtils;
- import org.apache.commons.lang.StringUtils;
- import org.apache.poi.hssf.usermodel.HSSFCell;
- import org.apache.poi.hssf.usermodel.HSSFWorkbook;
- import org.apache.poi.ss.usermodel.Cell;
- 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.xssf.usermodel.XSSFWorkbook;
- /**
- *
- * excel读取工具类
- *
- * @author daochuwenziyao
- * @see [相关类/方法]
- * @since [产品/模块版本]
- */
- public class ImportExeclUtil
- {
- private static int totalRows = 0;// 总行数
- private static int totalCells = 0;// 总列数
- private static String errorInfo;// 错误信息
- /** 无参构造方法 */
- public ImportExeclUtil()
- {
- }
- public static int getTotalRows()
- {
- return totalRows;
- }
- public static int getTotalCells()
- {
- return totalCells;
- }
- public static String getErrorInfo()
- {
- return errorInfo;
- }
- /**
- *
- * 根据流读取Excel文件
- *
- *
- * @param inputStream
- * @param isExcel2003
- * @return
- * @see [类、类#方法、类#成员]
- */
- public List<List<String>> read(InputStream inputStream, boolean isExcel2003)
- throws IOException
- {
- List<List<String>> dataLst = null;
- /** 根据版本选择创建Workbook的方式 */
- Workbook wb = null;
- if (isExcel2003)
- {
- wb = new HSSFWorkbook(inputStream);
- }
- else
- {
- wb = new XSSFWorkbook(inputStream);
- }
- dataLst = readDate(wb);
- return dataLst;
- }
- /**
- *
- * 读取数据
- *
- * @param wb
- * @return
- * @see [类、类#方法、类#成员]
- */
- private List<List<String>> readDate(Workbook wb)
- {
- List<List<String>> dataLst = new ArrayList<List<String>>();
- /** 得到第一个shell */
- Sheet sheet = wb.getSheetAt(0);
- /** 得到Excel的行数 */
- totalRows = sheet.getPhysicalNumberOfRows();
- /** 得到Excel的列数 */
- if (totalRows >= 1 && sheet.getRow(0) != null)
- {
- totalCells = sheet.getRow(0).getPhysicalNumberOfCells();
- }
- /** 循环Excel的行 */
- for (int r = 0; r < totalRows; r++)
- {
- Row row = sheet.getRow(r);
- if (row == null)
- {
- continue;
- }
- List<String> rowLst = new ArrayList<String>();
- /** 循环Excel的列 */
- for (int c = 0; c < getTotalCells(); c++)
- {
- Cell cell = row.getCell(c);
- String cellValue = "";
- if (null != cell)
- {
- // 以下是判断数据的类型
- switch (cell.getCellType())
- {
- case HSSFCell.CELL_TYPE_NUMERIC: // 数字
- cellValue = cell.getNumericCellValue() + "";
- break;
- case HSSFCell.CELL_TYPE_STRING: // 字符串
- cellValue = cell.getStringCellValue();
- break;
- case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean
- cellValue = cell.getBooleanCellValue() + "";
- break;
- case HSSFCell.CELL_TYPE_FORMULA: // 公式
- cellValue = cell.getCellFormula() + "";
- break;
- case HSSFCell.CELL_TYPE_BLANK: // 空值
- cellValue = "";
- break;
- case HSSFCell.CELL_TYPE_ERROR: // 故障
- cellValue = "非法字符";
- break;
- default:
- cellValue = "未知类型";
- break;
- }
- }
- rowLst.add(cellValue);
- }
- /** 保存第r行的第c列 */
- dataLst.add(rowLst);
- }
- return dataLst;
- }
- /**
- *
- * 按指定坐标读取实体数据
- * <按顺序放入带有注解的实体成员变量中>
- *
- * @param wb 工作簿
- * @param t 实体
- * @param in 输入流
- * @param integers 指定需要解析的坐标
- * @return T 相应实体
- * @throws IOException
- * @throws Exception
- * @see [类、类#方法、类#成员]
- */
- @SuppressWarnings("unused")
- public static <T> T readDateT(Workbook wb, T t, InputStream in, Integer[]... integers)
- throws IOException, Exception
- {
- // 获取该工作表中的第一个工作表
- Sheet sheet = wb.getSheetAt(0);
- // 成员变量的值
- Object entityMemberValue = "";
- // 所有成员变量
- Field[] fields = t.getClass().getDeclaredFields();
- // 列开始下标
- int startCell = 0;
- /** 循环出需要的成员 */
- for (int f = 0; f < fields.length; f++)
- {
- fields[f].setAccessible(true);
- String fieldName = fields[f].getName();
- boolean fieldHasAnno = fields[f].isAnnotationPresent(IsNeeded.class);
- // 有注解
- if (fieldHasAnno)
- {
- IsNeeded annotation = fields[f].getAnnotation(IsNeeded.class);
- boolean isNeeded = annotation.isNeeded();
- // Excel需要赋值的列
- if (isNeeded)
- {
- // 获取行和列
- int x = integers[startCell][0] - 1;
- int y = integers[startCell][1] - 1;
- Row row = sheet.getRow(x);
- Cell cell = row.getCell(y);
- if (row == null)
- {
- continue;
- }
- // Excel中解析的值
- String cellValue = getCellValue(cell);
- // 需要赋给成员变量的值
- entityMemberValue = getEntityMemberValue(entityMemberValue, fields, f, cellValue);
- // 赋值
- PropertyUtils.setProperty(t, fieldName, entityMemberValue);
- // 列的下标加1
- startCell++;
- }
- }
- }
- return t;
- }
- /**
- *
- * 读取列表数据
- * <按顺序放入带有注解的实体成员变量中>
- *
- * @param wb 工作簿
- * @param t 实体
- * @param beginLine 开始行数
- * @param totalcut 结束行数减去相应行数
- * @return List<T> 实体列表
- * @throws Exception
- * @see [类、类#方法、类#成员]
- */
- @SuppressWarnings("unchecked")
- public static <T> List<T> readDateListT(Workbook wb, T t, int beginLine, int totalcut)
- throws Exception
- {
- List<T> listt = new ArrayList<T>();
- /** 得到第一个shell */
- Sheet sheet = wb.getSheetAt(0);
- /** 得到Excel的行数 */
- totalRows = sheet.getPhysicalNumberOfRows();
- /** 得到Excel的列数 */
- if (totalRows >= 1 && sheet.getRow(0) != null)
- {
- totalCells = sheet.getRow(0).getPhysicalNumberOfCells();
- }
- /** 循环Excel的行 */
- for (int r = beginLine - 1; r < totalRows - totalcut; r++)
- {
- Object newInstance = t.getClass().newInstance();
- Row row = sheet.getRow(r);
- if (row == null)
- {
- continue;
- }
- // 成员变量的值
- Object entityMemberValue = "";
- // 所有成员变量
- Field[] fields = t.getClass().getDeclaredFields();
- // 列开始下标
- int startCell = 0;
- for (int f = 0; f < fields.length; f++)
- {
- fields[f].setAccessible(true);
- String fieldName = fields[f].getName();
- boolean fieldHasAnno = fields[f].isAnnotationPresent(IsNeeded.class);
- // 有注解
- if (fieldHasAnno)
- {
- IsNeeded annotation = fields[f].getAnnotation(IsNeeded.class);
- boolean isNeeded = annotation.isNeeded();
- // Excel需要赋值的列
- if (isNeeded)
- {
- Cell cell = row.getCell(startCell);
- String cellValue = getCellValue(cell);
- entityMemberValue = getEntityMemberValue(entityMemberValue, fields, f, cellValue);
- // 赋值
- PropertyUtils.setProperty(newInstance, fieldName, entityMemberValue);
- // 列的下标加1
- startCell++;
- }
- }
- }
- listt.add((T)newInstance);
- }
- return listt;
- }
- /**
- *
- * 根据Excel表格中的数据判断类型得到值
- *
- * @param cell
- * @return
- * @see [类、类#方法、类#成员]
- */
- private static String getCellValue(Cell cell)
- {
- String cellValue = "";
- if (null != cell)
- {
- // 以下是判断数据的类型
- switch (cell.getCellType())
- {
- case HSSFCell.CELL_TYPE_NUMERIC: // 数字
- if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell))
- {
- Date theDate = cell.getDateCellValue();
- SimpleDateFormat dff = new SimpleDateFormat("yyyy-MM-dd");
- cellValue = dff.format(theDate);
- }
- else
- {
- DecimalFormat df = new DecimalFormat("0");
- cellValue = df.format(cell.getNumericCellValue());
- }
- break;
- case HSSFCell.CELL_TYPE_STRING: // 字符串
- cellValue = cell.getStringCellValue();
- break;
- case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean
- cellValue = cell.getBooleanCellValue() + "";
- break;
- case HSSFCell.CELL_TYPE_FORMULA: // 公式
- cellValue = cell.getCellFormula() + "";
- break;
- case HSSFCell.CELL_TYPE_BLANK: // 空值
- cellValue = "";
- break;
- case HSSFCell.CELL_TYPE_ERROR: // 故障
- cellValue = "非法字符";
- break;
- default:
- cellValue = "未知类型";
- break;
- }
- }
- return cellValue;
- }
- /**
- *
- * 根据实体成员变量的类型得到成员变量的值
- *
- * @param realValue
- * @param fields
- * @param f
- * @param cellValue
- * @return
- * @see [类、类#方法、类#成员]
- */
- private static Object getEntityMemberValue(Object realValue, Field[] fields, int f, String cellValue)
- {
- String type = fields[f].getType().getName();
- switch (type)
- {
- case "char":
- case "java.lang.Character":
- case "java.lang.String":
- realValue = cellValue;
- break;
- case "java.util.Date":
- realValue = StringUtils.isBlank(cellValue) ? null : DateUtil.strToDate(cellValue, DateUtil.YYYY_MM_DD);
- break;
- case "java.lang.Integer":
- realValue = StringUtils.isBlank(cellValue) ? null : Integer.valueOf(cellValue);
- break;
- case "int":
- case "float":
- case "double":
- case "java.lang.Double":
- case "java.lang.Float":
- case "java.lang.Long":
- case "java.lang.Short":
- case "java.math.BigDecimal":
- realValue = StringUtils.isBlank(cellValue) ? null : new BigDecimal(cellValue);
- break;
- default:
- break;
- }
- return realValue;
- }
- /**
- *
- * 根据路径或文件名选择Excel版本
- *
- *
- * @param filePathOrName
- * @param in
- * @return
- * @throws IOException
- * @see [类、类#方法、类#成员]
- */
- public static Workbook chooseWorkbook(String filePathOrName, InputStream in)
- throws IOException
- {
- /** 根据版本选择创建Workbook的方式 */
- Workbook wb = null;
- boolean isExcel2003 = ExcelVersionUtil.isExcel2003(filePathOrName);
- if (isExcel2003)
- {
- wb = new HSSFWorkbook(in);
- }
- else
- {
- wb = new XSSFWorkbook(in);
- }
- return wb;
- }
- static class ExcelVersionUtil
- {
- /**
- *
- * 是否是2003的excel,返回true是2003
- *
- *
- * @param filePath
- * @return
- * @see [类、类#方法、类#成员]
- */
- public static boolean isExcel2003(String filePath)
- {
- return filePath.matches("^.+\\.(?i)(xls)$");
- }
- /**
- *
- * 是否是2007的excel,返回true是2007
- *
- *
- * @param filePath
- * @return
- * @see [类、类#方法、类#成员]
- */
- public static boolean isExcel2007(String filePath)
- {
- return filePath.matches("^.+\\.(?i)(xlsx)$");
- }
- }
- public static class DateUtil
- {
- // ======================日期格式化常量=====================//
- public static final String YYYY_MM_DDHHMMSS = "yyyy-MM-dd HH:mm:ss";
- public static final String YYYY_MM_DD = "yyyy-MM-dd";
- public static final String YYYY_MM = "yyyy-MM";
- public static final String YYYY = "yyyy";
- public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
- public static final String YYYYMMDD = "yyyyMMdd";
- public static final String YYYYMM = "yyyyMM";
- public static final String YYYYMMDDHHMMSS_1 = "yyyy/MM/dd HH:mm:ss";
- public static final String YYYY_MM_DD_1 = "yyyy/MM/dd";
- public static final String YYYY_MM_1 = "yyyy/MM";
- /**
- *
- * 自定义取值,Date类型转为String类型
- *
- * @param date 日期
- * @param pattern 格式化常量
- * @return
- * @see [类、类#方法、类#成员]
- */
- public static String dateToStr(Date date, String pattern)
- {
- SimpleDateFormat format = null;
- if (null == date)
- return null;
- format = new SimpleDateFormat(pattern, Locale.getDefault());
- return format.format(date);
- }
- /**
- * 将字符串转换成Date类型的时间
- * <hr>
- *
- * @param s 日期类型的字符串<br>
- * datePattern :YYYY_MM_DD<br>
- * @return java.util.Date
- */
- public static Date strToDate(String s, String pattern)
- {
- if (s == null)
- {
- return null;
- }
- Date date = null;
- SimpleDateFormat sdf = new SimpleDateFormat(pattern);
- try
- {
- date = sdf.parse(s);
- }
- catch (ParseException e)
- {
- e.printStackTrace();
- }
- return date;
- }
- }
- }
自定义注解
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- /**
- *
- * 是否需要从解析excel赋值
- * @author daochuwenziyao
- * @see [相关类/方法]
- * @since [产品/模块版本]
- */
- @Retention(value = RetentionPolicy.RUNTIME)
- @Target(value = {ElementType.FIELD})
- public @interface IsNeeded
- {
- /**
- * 是否需要从解析excel赋值
- * @return
- * true:需要 false:不需要
- * @see [类、类#方法、类#成员]
- */
- boolean isNeeded() default true;
- }
学生基本信息
- import java.math.BigDecimal;
- /**
- *
- * 学生基本信息
- * @author daochuwenziyao
- * @see [相关类/方法]
- * @since [产品/模块版本]
- */
- public class StudentBaseInfo
- {
- private Integer id;
- @IsNeeded
- private String no;
- @IsNeeded
- private String name;
- @IsNeeded
- private String idnum;
- @IsNeeded
- private String sex;
- @IsNeeded
- private BigDecimal grade;
- @Override
- public String toString()
- {
- return "StudentBaseInfo [id=" + id + ", no=" + no + ", name=" + name + ", idnum=" + idnum + ", sex=" + sex
- + ", grade=" + grade + "]";
- }
- public Integer getId()
- {
- return id;
- }
- public void setId(Integer id)
- {
- this.id = id;
- }
- public String getNo()
- {
- return no;
- }
- public void setNo(String no)
- {
- this.no = no;
- }
- public String getName()
- {
- return name;
- }
- public void setName(String name)
- {
- this.name = name;
- }
- public String getSex()
- {
- return sex;
- }
- public void setSex(String sex)
- {
- this.sex = sex;
- }
- public String getIdnum()
- {
- return idnum;
- }
- public void setIdnum(String idnum)
- {
- this.idnum = idnum;
- }
- public BigDecimal getGrade()
- {
- return grade;
- }
- public void setGrade(BigDecimal grade)
- {
- this.grade = grade;
- }
- }
学生统计信息
- /**
- *
- * 学生统计信息
- * @author daochuwenziyao
- * @see [相关类/方法]
- * @since [产品/模块版本]
- */
- public class StudentStatistics
- {
- private Integer id;
- @IsNeeded
- private BigDecimal totalGrade;
- @IsNeeded
- private BigDecimal avgGrade;
- @Override
- public String toString()
- {
- return "StudentStatistics [id=" + id + ", totalGrade=" + totalGrade + ", avgGrade=" + avgGrade + "]";
- }
- public Integer getId()
- {
- return id;
- }
- public void setId(Integer id)
- {
- this.id = id;
- }
- public BigDecimal getTotalGrade()
- {
- return totalGrade;
- }
- public void setTotalGrade(BigDecimal totalGrade)
- {
- this.totalGrade = totalGrade;
- }
- public BigDecimal getAvgGrade()
- {
- return avgGrade;
- }
- public void setAvgGrade(BigDecimal avgGrade)
- {
- this.avgGrade = avgGrade;
- }
- }
测试类
- package com.dao.chu.excel;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.List;
- import org.apache.poi.ss.usermodel.Workbook;
- public class TestImportExcel
- {
- public static void main(String[] args) throws IOException, Exception
- {
- String fileName="student.xlsx";
- InputStream in = new FileInputStream(new File("excelfile\\student.xlsx"));
- Workbook wb = ImportExeclUtil.chooseWorkbook(fileName, in);
- StudentStatistics studentStatistics = new StudentStatistics();
- //读取一个对象的信息
- StudentStatistics readDateT =
- ImportExeclUtil.readDateT(wb, studentStatistics, in, new Integer[] {12, 5}, new Integer[] {13, 5});
- System.out.println(readDateT);
- //读取对象列表的信息
- StudentBaseInfo studentBaseInfo = new StudentBaseInfo();
- //第二行开始,到倒数第三行结束(总数减去两行)
- List<StudentBaseInfo> readDateListT = ImportExeclUtil.readDateListT(wb, studentBaseInfo, 2, 2);
- System.out.println(readDateListT);
- }
- }
输出结果
StudentStatistics [id=null, totalGrade=845, avgGrade=84]
[StudentBaseInfo [id=null, no=2012240001, name=张三1, idnum=233314199009062304, sex=男, grade=80], StudentBaseInfo [id=null, no=2012240002, name=张三2, idnum=233314199009062304, sex=男, grade=81], StudentBaseInfo [id=null, no=2012240003, name=张三3, idnum=233314199009062304,
sex=男, grade=82], StudentBaseInfo [id=null, no=2012240004, name=张三4, idnum=233314199009062304, sex=男, grade=83], StudentBaseInfo [id=null, no=2012240005, name=张三5, idnum=233314199009062304, sex=男, grade=84], StudentBaseInfo [id=null, no=2012240006, name=张三6,
idnum=233314199009062304, sex=男, grade=85], StudentBaseInfo [id=null, no=2012240007, name=张三7, idnum=233314199009062304, sex=男, grade=86], StudentBaseInfo [id=null, no=2012240008, name=张三8, idnum=233314199009062304, sex=男, grade=87], StudentBaseInfo [id=null,
no=2012240009, name=张三9, idnum=233314199009062304, sex=男, grade=88], StudentBaseInfo [id=null, no=2012240010, name=张三10, idnum=233314199009062304, sex=男, grade=89]]
源码下载
源码分享给大家,上面提到的都在这里,由于很多的数据类型没有试验到,可能会有些类型有问题,所以希望大家如果遇到问题回复我,我会将其完善。谢谢
http://download.csdn.net/download/daochuwenziyao/9971228
相关推荐
- java利用poi和jfinal框架将excel导入数据库
- java之poi操作excel-批量导入导出
- java poi导入Excel通用工具类
- JAVA使用POI完成Excel批量导入操作
- Java POI Mysql与excel间的数据导入导出
- Java Xml导出Excel文件,Java Excel 导出工具类,Java导出Excel工具类
- 分享一个大神写的Java通用工具类库
- JAVA实现数据库数据导入/导出到Excel(POI)
- java用poi导出excel的工具类
- Java 报表工具--如何在报表软件Style Report中导入Excel数据表
- Excel导入导出数据库
- DataGrip 2019.2.5 —— 中文列名(字段名)(columns name)乱码问题解决方案