maven依赖
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.5-FINAL</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.5-FINAL</version> </dependency>
解析:
1 解析标题行
2 解析数据行
3 解析结果的抽象
4 解析过程需要考虑容错,容易理解
package com.enterprise.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; 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.ss.usermodel.WorkbookFactory; /** * 解析Excel的工具类 * * @author chen.kuan 2015年11月16日 * */ public class POIParser { public static boolean isExcel(String fileName) { int dotIndex = fileName.lastIndexOf("."); if (dotIndex < 0) { return false; } String fileSuffix = fileName.substring(dotIndex); if (!".xls.xlsx.".contains(fileSuffix)) { return false; } return true; } private boolean ignoreHeadLine = false; public POIParser() { this(false); } /** * @param ignoreHeadLine * 是否忽略标题行 */ public POIParser(boolean ignoreHeadLine) { this.ignoreHeadLine = ignoreHeadLine; } /** * @param is * 输入流,此输入流不管解析成功还是失败都会被释放 * @return */ public POIParseResult doParse(InputStream is) { try { POIParseResult result = new POIParseResult(); Workbook workbook = null; try { workbook = WorkbookFactory.create(is); } catch (InvalidFormatException e) { result.setFormatError(e); return result; } catch (IOException e) { result.setException(e); return result; } Sheet sheet = workbook.getSheetAt(0); Row headRow = sheet.getRow(0); if (headRow == null) { result.setEmpty(); return result; } short cellNumbers = headRow.getLastCellNum(); // LastCellNum可作为单元格的数量理解,不解析LastCellNum对应的单元格,lastCellNumber-1作为最后一列的索引 if (!ignoreHeadLine) { // 处理表头 String[] columnNames = new String[cellNumbers]; for (int c = 0; c < cellNumbers; c++) { Cell cell = headRow.getCell(c); columnNames[c] = cell.getStringCellValue().trim(); } result.setColumnNames(columnNames); } // 解析数据行 List<String[]> rowDatas = new ArrayList<String[]>(); // 确认数据行的startIndex int startIndex = -1; if (!ignoreHeadLine) { startIndex = 1; } else { startIndex = 0; } for (int r = startIndex; r <= sheet.getLastRowNum(); r++) { // getLastRowNum,getRow从0开始编号, // 0表示第一行,getLastRowNum表示最后一行,最后一行需要被解析 Row row = sheet.getRow(r); if (row == null) { continue; } String[] rowData = new String[cellNumbers]; for (int c = 0; c < cellNumbers; c++) { Cell cell = row.getCell(c); if (cell == null) { rowData[c] = ""; } else { rowData[c] = getStringCellValue(cell); } } rowDatas.add(rowData); } result.setRowDatas(rowDatas); result.setSuccess(); // set success return result; } finally { // close resource quietly try { is.close(); } catch (IOException e) { } } } private String getStringCellValue(Cell cell) { String value = null; switch (cell.getCellType()) { case Cell.CELL_TYPE_NUMERIC: // 数字 if (HSSFDateUtil.isCellDateFormatted(cell)) { // 日期 value = new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue()); } else { DecimalFormat df = new DecimalFormat("0"); value = df.format(cell.getNumericCellValue()); } break; case Cell.CELL_TYPE_STRING: // 字符串 value = cell.getStringCellValue(); break; case Cell.CELL_TYPE_FORMULA: // 公式 double numericValue = cell.getNumericCellValue(); if (HSSFDateUtil.isValidExcelDate(numericValue)) { // 日期类型 value = new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue()); } else { value = String.valueOf(numericValue); } break; case Cell.CELL_TYPE_BLANK: // 空白 value = ""; break; case Cell.CELL_TYPE_BOOLEAN: // Boolean value = String.valueOf(cell.getBooleanCellValue()); break; case Cell.CELL_TYPE_ERROR: // Error,返回错误码 value = String.valueOf(cell.getErrorCellValue()); break; default: value = ""; break; } return value; } // --------------------------------------- public static class POIParseResult { private boolean result = false; // 解析结果是否成功 private boolean formatContainsError = false; // 格式是否错误 private InvalidFormatException formatException; private Exception exception; private boolean isEmpty = false; // excel文件的内容是否为空 private String[] columnNames; private List<String[]> rowDatas; public List<String[]> getRowDatas() { return rowDatas; } public void setRowDatas(List<String[]> rowDatas) { this.rowDatas = rowDatas; } public String[] getColumnNames() { return columnNames; } public void setColumnNames(String[] columnNames) { this.columnNames = columnNames; } public Exception getException() { return exception; } public void setException(Exception exception) { this.exception = exception; } public void setSuccess() { result = true; } public boolean isSuccess() { return result; } public void setFormatError(InvalidFormatException formatException) { formatContainsError = false; this.formatException = formatException; } public InvalidFormatException getFormatException() { return formatException; } public boolean containsFormatError() { // 判断是否excel发生了格式错误 return formatContainsError; } public void setEmpty() { isEmpty = true; } public boolean isEmpty() { return isEmpty; } } // ----------------- public static void main(String[] args) throws FileNotFoundException { String path = "C:\\Users\\WALKER\\Desktop\\O2O\\a.xlsx"; File file = new File(path); if (!POIParser.isExcel(file.getName())) { System.err.println("Not excel,file=" + file.getAbsolutePath()); } else { System.out.println("Starting parsing excel,file=" + file.getAbsolutePath()); } InputStream is = new FileInputStream(file); POIParser parser = new POIParser(); POIParseResult result = parser.doParse(is); if (result.isSuccess()) { String[] columnNames = result.getColumnNames(); StringBuilder buffer = new StringBuilder(); for (int i = 0; i < columnNames.length; i++) { buffer.append(columnNames[i]).append(" "); } System.out.println("Column names == " + buffer.toString()); List<String[]> rowDatas = result.getRowDatas(); for (int i = 0; i < rowDatas.size(); i++) { String[] rowData = rowDatas.get(i); buffer.setLength(0); for (int j = 0; j < rowData.length; j++) { buffer.append(rowData[j]).append(" "); } System.out.println("第" + i + "行数据:" + buffer.toString()); } } } }
测试数据
执行伤处应用程序,输出如下,和excel的内容是一致的
Starting parsing excel,file=C:\Users\WALKER\Desktop\O2O\a.xlsx Column names == 扫码支付商家账户 ship 第0行数据:111 a 第1行数据:222 b 第2行数据:333 c 第3行数据:v
------------------------
其它:
构造的测试案列不足够多,有些情况可能没考虑
解析代码可能有些地方没想到,在某种场景下将出错
-------------------------------------------------------------------------
一个用于处理excel批量上传O2O商家的例子:
需要考虑:
1 没有上传文件
2 excel格式错误,导致无法解析
3 excel为空
4 excel中有非法的数据行
@RequestMapping("/uploadO2OMerchants") @ResponseBody public AjaxResult uploadO2OMerchants(MultipartHttpServletRequest request) { MultipartFile file = request.getFile("file"); if (file == null) { return AjaxResult.failed("上传的文件不允许为空"); } String orignalFile = file.getOriginalFilename(); if (!POIParser.isExcel(orignalFile)) { return AjaxResult.failed("上传的文件不是excel"); } InputStream is = null; try { is = file.getInputStream(); } catch (IOException e) { return AjaxResult.failed("文件解析失败"); } POIParser parser = new POIParser(); POIParseResult parseResult = parser.doParse(is); if (!parseResult.isSuccess()) { if (parseResult.isEmpty()) { return AjaxResult.failed("上传文件为空"); } logger.error("Fail to parse excel,file=" + orignalFile, parseResult.getException()); if (parseResult.containsFormatError()) { return AjaxResult.failed("文件解析失败,格式错误"); } return AjaxResult.failed("文件解析失败"); } else { List<String[]> rowDatas = parseResult.getRowDatas(); if (rowDatas == null) { return AjaxResult.failed("文件格式不正确,没有设置商家"); } List<String> fails = new ArrayList<String>(); List<String> successes = new ArrayList<String>(); for (String[] rowData : rowDatas) { String username = rowData[0]; // 取第0列作为user_name,如果有其它列舍去之 if (StringUtils.isBlank(username)) { continue; } Result result = null; try { result = o2oService.addScanCodePayMerchant(username.trim(), super.getCurrentUsername()); } catch (RuntimeException e) { logger.error("Fail to addScanCodePayMerchant ", e); fails.add(username); continue; } if (result.isSuccess()) { successes.add(username); } else { fails.add(username); } } Map<String, Object> ajaxResultMap = new HashMap<String, Object>(); ajaxResultMap.put("fails", fails); ajaxResultMap.put("successes", successes); return AjaxResult.success(ajaxResultMap); } }