在java poi导入Excel通用工具类示例详解
前言
本文主要给大家介绍了关于java poi导入excel通用工具类的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。
问题引入和分析
提示:如果不想看罗嗦的文章,可以直接到最后点击源码下载运行即可
最近在做一个导入excel的功能,在做之前在百度上面查找“java通用导入excel工具类”,没有查到,大多数都是java通用导出excel。后来仔细想想,导出可以利用java的反射,做成通用的,放进相应的实体成员变量中,导入为什么不可以呢?也是可以的,不过在做之前我们要解决如下两个问题:
1.表格中的列数和顺序要和实体类中的成员变量个数和顺序一致。
2.表格中的列的类型要和成员变量的类型一致。
第一个问题:
列数一致可以做到,但是我们最后都是要插入数据库的。那么id是必不可少的,或者良好的习惯可能还有创建时间,创建人等信息。
所以我想到了两个办法:
1.封装一个vo,只将需要的字段封装进去,并且字段顺序和表格列的顺序一致,再将vo与实体类po转化(用propertyutil.copy
方法);
2.在需要的成员变量上注入自定义注解,并且加入注解的这些字段顺序和表格列的顺序一致,利用反射得到这些字段。
这里主要利用第二个方法,因为扩展性更好
第二个问题:
获取表格数据的时候,我们要判断类型,并取得相应值,全部转化为string类型,当我们给实体类赋值的时候,利用反射获取需要的成员变量的类型,并赋值。
需求
假设我们需求的excel如下:
我们可以看做两部分:
第一部分:
第二行到第11行,为一个列表数据,共有字段5个,分别为:学号,姓名,身份证号码,性别,分数
第二部分:
第12行第五列,第12行第六列,共有字段2个,分别为:总计,平均
项目
需要导入的jar包
1.poi的相关jar包,主要用来处理excel
2.beanutils 利用反射为成员变量赋值
3.commons-lang string判断非空的方法,可以不用自己判断
如若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://xiazai.jb51.net/201709/yuanma/importexcelutil(jb51.net).rar
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
上一篇: 详解Java单元测试Junit框架实例
下一篇: 数据结构之栈的实现