需用读取Excel文档,所以了解了一下大概做法,并整理如下:
1.使用jxl,创建单元格对象,读取文档内容,优点是代码简单,按行读取,缺点是在智能处理03版本的EXCEL文件,如下 :
导入依赖:
1 <!-- https://mvnrepository.com/artifact/net.sourceforge.jexcelapi/jxl --> 2 <dependency> 3 <groupId>net.sourceforge.jexcelapi</groupId> 4 <artifactId>jxl</artifactId> 5 <version>2.6.12</version> 6 </dependency>
接下来是代码实现,逻辑比较简单就不多说了
import jxl.Cell; import jxl.Sheet; import jxl.Workbook; public class simple { public static void main(String[] args) { try { File file = new File("XXX.xls" +""); // 创建文件对象 Workbook wb = Workbook.getWorkbook(file); // 从文件流中获取Excel工作区对象(WorkBook) Sheet sheet = wb.getSheet(0); // 从工作区中取得页(Sheet) for (int i = 0; i < sheet.getRows(); i++) { // 循环打印Excel表中的内容 for (int j = 0; j < sheet.getColumns(); j++) { Cell cell = sheet.getCell(j, i); System.out.printf(cell.getContents()+" "); } System.out.println(); } } catch (Exception e) { e.printStackTrace(); } } }
2.使用阿里巴巴的fastExcel,代码稍微复杂一点,功能多,能处理03和07版本的
我的目录结构如下:
导入依赖
<!--EasyExcel--> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.0-beta2</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.10.1</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> <!--fastJson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.72</version> </dependency> <!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.6</version> </dependency>
根据EXCEL文档表头信息编辑实体类,即pojo中的TableInfo
import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelProperty; import lombok.Data; @Data public class TableInfo { @ExcelIgnore @ExcelProperty("序号") private Integer num; //字段 数据类型 字段标题 字段说明 字段来源 @ExcelProperty("字段") private String fieldName; @ExcelProperty("数据类型") private String dataType; @ExcelProperty("字段标题") private String comment1; @ExcelProperty("字段说明") private String comment2; @ExcelIgnore @ExcelProperty("字段来源") private String url; }
dao层用于处理数据库,如果不需要存储到数据库可以不写具体实现:
1 import ExcelRead.pojo.TableInfo; 2 import java.util.List; 3 4 public class TableDao { 5 public void save(List<TableInfo> list) { 6 // 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入 7 } 8 }
具体实现代码:
1 import ExcelRead.dao.TableDao; 2 import ExcelRead.pojo.TableInfo; 3 import com.alibaba.excel.context.AnalysisContext; 4 import com.alibaba.excel.event.AnalysisEventListener; 5 import com.alibaba.fastjson.JSON; 6 import org.slf4j.Logger; 7 import org.slf4j.LoggerFactory; 8 import java.util.ArrayList; 9 import java.util.List; 10 11 public class TableDataListener extends AnalysisEventListener<TableInfo> { 12 private static final Logger LOGGER = (Logger) LoggerFactory.getLogger(TableDataListener.class); 13 /** 14 * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 15 */ 16 private static final int BATCH_COUNT = 200; 17 List<TableInfo> list = new ArrayList<TableInfo>(); 18 /** 19 * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 20 */ 21 private TableDao tableDao; 22 public TableDataListener() { 23 // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数 24 tableDao = new TableDao(); 25 } 26 /** 27 * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来 28 * 29 * @param tableDao 30 */ 31 public TableDataListener(TableDao tableDao) { 32 this.tableDao = tableDao; 33 } 34 /** 35 * 这个每一条数据解析都会来调用 36 * 37 * @param data 38 * one row value. Is is same as {@link AnalysisContext#readRowHolder()} 39 * @param context 40 */ 41 @Override 42 public void invoke(TableInfo data, AnalysisContext context) { 43 System.out.println(JSON.toJSONString(data)); 44 list.add(data); 45 // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM 46 if (list.size() >= BATCH_COUNT) { 47 saveData(); 48 // 存储完成清理 list 49 list.clear(); 50 } 51 } 52 /** 53 * 所有数据解析完成了 都会来调用 54 * 55 * @param context 56 */ 57 @Override 58 public void doAfterAllAnalysed(AnalysisContext context) { 59 // 这里也要保存数据,确保最后遗留的数据也存储到数据库 60 saveData(); 61 LOGGER.info("所有数据解析完成!"); 62 } 63 /** 64 * 加上存储数据库 65 */ 66 private void saveData() { 67 // System.out.println("{}条数据,开始存储数据库!"+ list.size()); 68 tableDao.save(list); 69 LOGGER.info("存储数据库成功!"); 70 } 71 }
到这里基本就结束了,最后来个测试文件
1 import ExcelRead.listener.TableDataListener; 2 import ExcelRead.pojo.TableInfo; 3 import com.alibaba.excel.EasyExcel; 4 import org.junit.Test; 5 6 public class readTest { 7 @Test 8 public void simpleRead() { 9 // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 10 String fileName ="XXX.xlsx"; 11 12 // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 13 EasyExcel.read(fileName, TableInfo.class, new TableDataListener()).sheet().doRead(); 14 } 15 }