Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。
注意事项
1、运用多态,excel主要有.xls结尾(2003版本)和. xlsx(2007版本)两种类型结尾的文件,分别需要用HSSFWorkbook对象对.xls文件进行读取,用XSSFWorkbook对象对.xlsx文件进行读取,直接使用他们共同的父类Workbook进行初始化对象有利于代码的易用性。
2、通过流的方式初始化工作簿对象(Workbook),可以通过new XSSFWorkbook(文件绝对路径)和new XSSFWorkbook(输入流)两种方式初始化对象,但是假如我们只是通过修改.xls文件的后缀名为.xlsx,这样子当我们用new XSSFWorkbook(文件绝对路径)来读取文件的时候就会报错,因为他本身就不是一个2007版本的excel类型的文件,读取会报错;假如我们是通过流的方式的话,可以避免这种情况,我们即使你修改了文件的后缀名,我们依然在初始化的时候能获取到该对象是.xls类型文件,使用HSSFWorkbook对象进行处理,即能得出正确的结果。
添加了判断表头是否符合规范,允许表头对象的位置不同。进行了一定的解耦合。
注意: 由于以前的Cell.CELL_TYPE_STRING,获取Cell的类型已经过时,并且poi导入excel判断单元格类型及转换又有比较多的问题,从excel中识别出来数据类型会有偏差,故改成 返回该单元格相应的类型的值 如下的 getRightTypeCell 方法:
备注: 此处的checkDate是明确的日期类型
/**
* 描述:
* 从excel中导入单据数据业务实现
*
* @author selfimpr626
* @version 1.0.0.20190123
* @since JDK V1.8
*/
@Component
public class ImportExcelUtil4Info {
private static InfoService infoService;
private ImportExcelUtil4Info() {}
@Autowired
public void setInfoService(InfoService infoService) {
ImportExcelUtil4Info.infoService = infoService;
}
/**
* @param cell 一个单元格的对象
* @return 返回该单元格相应的类型的值
*/
public static Object getRightTypeCell(Cell cell, String what){
Object object = null;
if (cell!=null && !"".equals(cell)) {
switch (cell.getCellTypeEnum()) {
case STRING:
object = cell.getRichStringCellValue().getString();
break;
case NUMERIC:
if ("checkDate".equals(what)) {
Instant instant = cell.getDateCellValue().toInstant();
ZoneId zone = ZoneId.systemDefault();
object = LocalDateTime.ofInstant(instant, zone);
}else {
object = cell.getNumericCellValue();
if(object instanceof Double) {
object = String.valueOf(object);
}
}
break;
case BOOLEAN:
object = cell.getBooleanCellValue();
break;
case BLANK:
object = "";
break;
case FORMULA:
// 待定
break;
default:
object = cell.toString();
break;
}
}
return object;
}
/**
* 读取出filePath中的所有数据信息
* @param filePath excel文件的绝对路径
*
*/
public static List<Info> getDataFromExcel(String filePath, Long relId)
{
List<Map<String,Integer>> list = new ArrayList<Map<String, Integer>>();
//判断是否为excel类型文件
if(!filePath.endsWith(".xls")&&!filePath.endsWith(".xlsx")) {
}
FileInputStream fis =null;
Workbook wookbook = null;
int flag = 1;
try {
//获取一个绝对地址的流
fis = new FileInputStream(filePath);
} catch(Exception e) {
e.printStackTrace();
}
try {
//2003版本的excel,用.xls结尾
wookbook = new HSSFWorkbook(fis);//得到工作簿
} catch (Exception ex)
{
//ex.printStackTrace();
try {
//这里需要重新获取流对象,因为前面的异常导致了流的关闭———加了这一行
fis = new FileInputStream(filePath);
//2007版本的excel,用.xlsx结尾
wookbook = new XSSFWorkbook(filePath);//得到工作簿
} catch (IOException e) {
e.printStackTrace();
}
}
//得到一个工作表
Sheet sheet = wookbook.getSheetAt(0);
//获得表头
Row rowHead = sheet.getRow(4);
//根据不同的data放置不同的表头
Map<Object,Integer> headMap = new HashMap<Object, Integer>();
if(rowHead == null) {
throw new RuntimeException("表头与要导入的数据库不对应");
}
//判断表头是否合格 ------ 有多少列
if(rowHead.getPhysicalNumberOfCells() != 2) {
throw new RuntimeException("表头列数与要导入的数据库不对应");
}
try {
// 根据表格有多少列
while (flag <= 2)
{
Cell cell = rowHead.getCell(flag);
if (cell != null && !"".equals(cell)) {
if (getRightTypeCell(cell, null).toString() != null && !"".equals(getRightTypeCell(cell, null).toString()) ) {
if (getRightTypeCell(cell, null).toString().equals("号码")) {
headMap.put("code", flag);
} else if (getRightTypeCell(cell, null).toString().equals("检查时间")) {
// 对应实体:检查时间
headMap.put("checkDate", flag);
}
}
}
flag++;
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("表头不合规范,请修改后重新导入");
}
//获得数据的总行数
int totalRowNum = sheet.getLastRowNum();
// 最终返回的List<info>
List<Info> infoList = new ArrayList<>();
if(0 == totalRowNum) {
throw new RuntimeException("Excel内没有数据");
}
Cell codeCell = null,checkDateCell = null;
//获得所有数据
for(int i = 1 ; i <= totalRowNum ; i++) {
//获得第i行对象
Row row = sheet.getRow(i+4);
if(row != null && !"".equals(row) && row.getCell(i) != null) {
try {
codeCell = row.getCell(headMap.get("code"));
checkDateCell = row.getCell(headMap.get("checkDate"));
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("获取单元格错误,请检查表头或数据是否正确");
}
try {
Info info = new Info();
// 号码
String code = (String) getRightTypeCell(codeCell, null);
info.setCode(code);
// 检查时间
info.setCheckDate((LocalDateTime) getRightTypeCell(checkDateCell, "checkDate"));
// 对每一行的号码数据判断:Excel中存在同一号码(唯一)
if(info.getPatientCode() != null) {
Info pf = infoService.findByCode(info.getCode(), relId);
if(pf != null) {
throw new RuntimeException("Excel中存在系统已有单据");
}
}else {
throw new RuntimeException("Excel中存在号码字段缺失");
}
infoList.add(info);
} catch (ClassCastException e) {
e.printStackTrace();
// System.out.println("数据不全是数字或全部是文字!");
}
}
}
if(infoList.size() >0) {
// 返回构造好的实体数据List<info>
return infoList;
}else {
return null;
}
}
}