300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Java使用POI读取和写入Excel指南

Java使用POI读取和写入Excel指南

时间:2019-06-26 11:35:08

相关推荐

Java使用POI读取和写入Excel指南

Java使用POI读取和写入Excel指南

做项目时经常有通过程序读取Excel数据,或是创建新的Excel并写入数据的需求;

网上很多经验教程里使用的POI版本都比较老了,一些API在新版里已经废弃,这里基于最新的Apache POI 4.0.1版本来总结一下整个读取和写入Excel的过程,希望能帮助到需要的人 ^_^

1. 准备工作

1.1 在项目中引入Apache POI相关类库

引入Apache POIApache POI-OOXML这两个类库,Maven坐标如下:

<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.0.1</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.0.1</version></dependency>

2. 读取或写入Excel数据

2.1 示例程序结构说明

简单说明一下示例程序的整体结构:

ExcelReader.java是实现读取Excel数据功能的类;ExcelWriter.java是创建新的Excel并向其中写入数据的类;ExcelDataVO.java封装了读取或写入时每一“行”的数据;MainTest.java是示例程序的入口类,其中演示了读取和写入Excel数据的整个过程;

2.2 读取数据

示例程序需要从桌面读取 readExample.xlsx 内的数据,readExample.xlsx 的内容如下:

读取Excel时主要调用ExcelReader.java类来读取和解析Excel的具体内容,这里以读取系统文件的形式演示读取过程:(兼容 xls 和 xlsx)

2.2.1 主程序入口类代码:

/*** Author: Dreamer-1* Date: -03-01* Time: 10:13* Description: 示例程序入口类*/public class MainTest {public static void main(String[] args) {// 设定Excel文件所在路径String excelFileName = "/Users/Dreamer-1/Desktop/myBlog/java解析Excel/readExample.xlsx";// 读取Excel文件内容List<ExcelDataVO> readResult = ExcelReader.readExcel(excelFileName);// todo 进行业务操作}}

读取和写入时封装每一“行”数据的ExcelDataVO.java代码如下:

/*** Author: Dreamer-1* Date: -03-01* Time: 11:33* Description: 读取Excel时,封装读取的每一行的数据*/public class ExcelDataVO {/*** 姓名*/private String name;/*** 年龄*/private Integer age;/*** 居住地*/private String location;/*** 职业*/private String job;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getLocation() {return location;}public void setLocation(String location) {this.location = location;}public String getJob() {return job;}public void setJob(String job) {this.job = job;}}

2.2.2 Excel解析类的代码:

/*** Author: Dreamer-1* Date: -03-01* Time: 10:21* Description: 读取Excel内容*/public class ExcelReader {private static Logger logger = Logger.getLogger(ExcelReader.class.getName()); // 日志打印类private static final String XLS = "xls";private static final String XLSX = "xlsx";/*** 根据文件后缀名类型获取对应的工作簿对象* @param inputStream 读取文件的输入流* @param fileType 文件后缀名类型(xls或xlsx)* @return 包含文件数据的工作簿对象* @throws IOException*/public static Workbook getWorkbook(InputStream inputStream, String fileType) throws IOException {Workbook workbook = null;if (fileType.equalsIgnoreCase(XLS)) {workbook = new HSSFWorkbook(inputStream);} else if (fileType.equalsIgnoreCase(XLSX)) {workbook = new XSSFWorkbook(inputStream);}return workbook;}/*** 读取Excel文件内容* @param fileName 要读取的Excel文件所在路径* @return 读取结果列表,读取失败时返回null*/public static List<ExcelDataVO> readExcel(String fileName) {Workbook workbook = null;FileInputStream inputStream = null;try {// 获取Excel后缀名String fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());// 获取Excel文件File excelFile = new File(fileName);if (!excelFile.exists()) {logger.warning("指定的Excel文件不存在!");return null;}// 获取Excel工作簿inputStream = new FileInputStream(excelFile);workbook = getWorkbook(inputStream, fileType);// 读取excel中的数据List<ExcelDataVO> resultDataList = parseExcel(workbook);return resultDataList;} catch (Exception e) {logger.warning("解析Excel失败,文件名:" + fileName + " 错误信息:" + e.getMessage());return null;} finally {try {if (null != workbook) {workbook.close();}if (null != inputStream) {inputStream.close();}} catch (Exception e) {logger.warning("关闭数据流出错!错误信息:" + e.getMessage());return null;}}}/*** 解析Excel数据* @param workbook Excel工作簿对象* @return 解析结果*/private static List<ExcelDataVO> parseExcel(Workbook workbook) {List<ExcelDataVO> resultDataList = new ArrayList<>();// 解析sheetfor (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {Sheet sheet = workbook.getSheetAt(sheetNum);// 校验sheet是否合法if (sheet == null) {continue;}// 获取第一行数据int firstRowNum = sheet.getFirstRowNum();Row firstRow = sheet.getRow(firstRowNum);if (null == firstRow) {logger.warning("解析Excel失败,在第一行没有读取到任何数据!");}// 解析每一行的数据,构造数据对象int rowStart = firstRowNum + 1;int rowEnd = sheet.getPhysicalNumberOfRows();for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) {Row row = sheet.getRow(rowNum);if (null == row) {continue;}ExcelDataVO resultData = convertRowToData(row);if (null == resultData) {logger.warning("第 " + row.getRowNum() + "行数据不合法,已忽略!");continue;}resultDataList.add(resultData);}}return resultDataList;}/*** 将单元格内容转换为字符串* @param cell* @return*/private static String convertCellValueToString(Cell cell) {if(cell==null){return null;}String returnValue = null;switch (cell.getCellType()) {case NUMERIC: //数字Double doubleValue = cell.getNumericCellValue();// 格式化科学计数法,取一位整数DecimalFormat df = new DecimalFormat("0");returnValue = df.format(doubleValue);break;case STRING: //字符串returnValue = cell.getStringCellValue();break;case BOOLEAN: //布尔Boolean booleanValue = cell.getBooleanCellValue();returnValue = booleanValue.toString();break;case BLANK:// 空值break;case FORMULA: // 公式returnValue = cell.getCellFormula();break;case ERROR:// 故障break;default:break;}return returnValue;}/*** 提取每一行中需要的数据,构造成为一个结果数据对象** 当该行中有单元格的数据为空或不合法时,忽略该行的数据** @param row 行数据* @return 解析后的行数据对象,行数据错误时返回null*/private static ExcelDataVO convertRowToData(Row row) {ExcelDataVO resultData = new ExcelDataVO();Cell cell;int cellNum = 0;// 获取姓名cell = row.getCell(cellNum++);String name = convertCellValueToString(cell);resultData.setName(name);// 获取年龄cell = row.getCell(cellNum++);String ageStr = convertCellValueToString(cell);if (null == ageStr || "".equals(ageStr)) {// 年龄为空resultData.setAge(null);} else {resultData.setAge(Integer.parseInt(ageStr));}// 获取居住地cell = row.getCell(cellNum++);String location = convertCellValueToString(cell);resultData.setLocation(location);// 获取职业cell = row.getCell(cellNum++);String job = convertCellValueToString(cell);resultData.setJob(job);return resultData;}}

2.2.3 应用场景补充

一般我们会有这样的应用场景,即:在前台页面的文件上传入口上传本地的Excel文件到后台,后台收到Excel文件后进行解析并做对应的业务操作;

这里假设前台已经有了上传文件的入口,再简单贴一下后台的解析代码;

后台接收前台数据的Controller层代码示例:

@PostMapping("/uploadExcel")public ResponseEntity<?> uploadImage(MultipartFile file) {// 检查前台数据合法性if (null == file || file.isEmpty()) {logger.warning("上传的Excel商品数据文件为空!上传时间:" + new Date());return new ResponseEntity<>(HttpStatus.BAD_REQUEST);}try {// 解析ExcelList<ExcelDataVO> parsedResult = ExcelReader.readExcel(file);// todo 进行业务操作return new ResponseEntity<>(HttpStatus.OK);} catch (Exception e) {logger.warning("上传的Excel商品数据文件为空!上传时间:" + new Date());return new ResponseEntity<>(HttpStatus.BAD_REQUEST);}}

ExcelReader.java中的readExcel()方法需要做一定的修改,代码如下:

/*** 读取Excel文件内容* @param file 上传的Excel文件* @return 读取结果列表,读取失败时返回null*/public static List<ExcelDataVO> readExcel(MultipartFile file) {Workbook workbook = null;try {// 获取Excel后缀名String fileName = file.getOriginalFilename();if (fileName == null || fileName.isEmpty() || fileName.lastIndexOf(".") < 0) {logger.warning("解析Excel失败,因为获取到的Excel文件名非法!");return null;}String fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());// 获取Excel工作簿workbook = getWorkbook(file.getInputStream(), fileType);// 读取excel中的数据List<ExcelDataVO> resultDataList = parseExcel(workbook);return resultDataList;} catch (Exception e) {logger.warning("解析Excel失败,文件名:" + file.getOriginalFilename() + " 错误信息:" + e.getMessage());return null;} finally {try {if (null != workbook) {workbook.close();}} catch (Exception e) {logger.warning("关闭数据流出错!错误信息:" + e.getMessage());return null;}}}

2.3 写入数据

写入数据时主要调用ExcelWriter.java来创建Excel工作簿对象并写入数据,这里以写入系统文件数据为例演示写入的过程:

2.3.1 主程序入口类代码

/*** Author: Dreamer-1* Date: -03-01* Time: 10:13* Description: 示例程序入口类*/public class MainTest {private static Logger logger = Logger.getLogger(MainTest.class.getName());public static void main(String[] args) {// 创建需要写入的数据列表List<ExcelDataVO> dataVOList = new ArrayList<>(2);ExcelDataVO dataVO = new ExcelDataVO();dataVO.setName("小明");dataVO.setAge(18);dataVO.setLocation("广州");dataVO.setJob("大学生");ExcelDataVO dataVO2 = new ExcelDataVO();dataVO2.setName("小花");dataVO2.setAge(19);dataVO2.setLocation("深圳");dataVO2.setJob("大学生");dataVOList.add(dataVO);dataVOList.add(dataVO2);// 写入数据到工作簿对象内Workbook workbook = ExcelWriter.exportData(dataVOList);// 以文件的形式输出工作簿对象FileOutputStream fileOut = null;try {String exportFilePath = "/Users/Dreamer-1/Desktop/myBlog/java解析Excel/writeExample.xlsx";File exportFile = new File(exportFilePath);if (!exportFile.exists()) {exportFile.createNewFile();}fileOut = new FileOutputStream(exportFilePath);workbook.write(fileOut);fileOut.flush();} catch (Exception e) {logger.warning("输出Excel时发生错误,错误原因:" + e.getMessage());} finally {try {if (null != fileOut) {fileOut.close();}if (null != workbook) {workbook.close();}} catch (IOException e) {logger.warning("关闭输出流时发生错误,错误原因:" + e.getMessage());}}}}

2.3.2 写入Excel类的代码

ExcelWriter.java类中,你可以根据实际需要替换CELL_HEADS列头的信息,然后重写convertDataToRow方法,转换你自己的行数据;

/*** Author: Dreamer-1* Date: -03-01* Time: 11:09* Description: 生成Excel并写入数据*/public class ExcelWriter {private static List<String> CELL_HEADS; //列头static{// 类装载时就载入指定好的列头信息,如有需要,可以考虑做成动态生成的列头CELL_HEADS = new ArrayList<>();CELL_HEADS.add("姓名");CELL_HEADS.add("年龄");CELL_HEADS.add("居住城市");CELL_HEADS.add("职业");}/*** 生成Excel并写入数据信息* @param dataList 数据列表* @return 写入数据后的工作簿对象*/public static Workbook exportData(List<ExcelDataVO> dataList){// 生成xlsx的ExcelWorkbook workbook = new SXSSFWorkbook();// 如需生成xls的Excel,请使用下面的工作簿对象,注意后续输出时文件后缀名也需更改为xls//Workbook workbook = new HSSFWorkbook();// 生成Sheet表,写入第一行的列头Sheet sheet = buildDataSheet(workbook);//构建每行的数据内容int rowNum = 1;for (Iterator<ExcelDataVO> it = dataList.iterator(); it.hasNext(); ) {ExcelDataVO data = it.next();if (data == null) {continue;}//输出行数据Row row = sheet.createRow(rowNum++);convertDataToRow(data, row);}return workbook;}/*** 生成sheet表,并写入第一行数据(列头)* @param workbook 工作簿对象* @return 已经写入列头的Sheet*/private static Sheet buildDataSheet(Workbook workbook) {Sheet sheet = workbook.createSheet();// 设置列头宽度for (int i=0; i<CELL_HEADS.size(); i++) {sheet.setColumnWidth(i, 4000);}// 设置默认行高sheet.setDefaultRowHeight((short) 400);// 构建头单元格样式CellStyle cellStyle = buildHeadCellStyle(sheet.getWorkbook());// 写入第一行各列的数据Row head = sheet.createRow(0);for (int i = 0; i < CELL_HEADS.size(); i++) {Cell cell = head.createCell(i);cell.setCellValue(CELL_HEADS.get(i));cell.setCellStyle(cellStyle);}return sheet;}/*** 设置第一行列头的样式* @param workbook 工作簿对象* @return 单元格样式对象*/private static CellStyle buildHeadCellStyle(Workbook workbook) {CellStyle style = workbook.createCellStyle();//对齐方式设置style.setAlignment(HorizontalAlignment.CENTER);//边框颜色和宽度设置style.setBorderBottom(BorderStyle.THIN);style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); // 下边框style.setBorderLeft(BorderStyle.THIN);style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); // 左边框style.setBorderRight(BorderStyle.THIN);style.setRightBorderColor(IndexedColors.BLACK.getIndex()); // 右边框style.setBorderTop(BorderStyle.THIN);style.setTopBorderColor(IndexedColors.BLACK.getIndex()); // 上边框//设置背景颜色style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());style.setFillPattern(FillPatternType.SOLID_FOREGROUND);//粗体字设置Font font = workbook.createFont();font.setBold(true);style.setFont(font);return style;}/*** 将数据转换成行* @param data 源数据* @param row 行对象* @return*/private static void convertDataToRow(ExcelDataVO data, Row row){int cellNum = 0;Cell cell;// 姓名cell = row.createCell(cellNum++);cell.setCellValue(null == data.getName() ? "" : data.getName());// 年龄cell = row.createCell(cellNum++);if (null != data.getAge()) {cell.setCellValue(data.getAge());} else {cell.setCellValue("");}// 所在城市cell = row.createCell(cellNum++);cell.setCellValue(null == data.getLocation() ? "" : data.getLocation());// 职业cell = row.createCell(cellNum++);cell.setCellValue(null == data.getJob() ? "" : data.getJob());}}

示例程序运行后将会在指定的系统路径下生成writeExample.xlsx文件,其内容如下:

2.3.3 应用场景补充

一般写入Excel时会有这样的场景:前台页面上有一个导出按钮,点击后将后台某张表里的数据以Excel的形式导出,导出的Excel文件通过浏览器下载到用户系统中;

这里默认前台页面已经有相应的按钮功能,给出对应的Controller层代码供参考:

@GetMapping("/exportExcel")public void exportExcel(HttpServletRequest request, HttpServletResponse response) {Workbook workbook = null;OutputStream out = null;try {// todo 根据业务需求获取需要写入Excel的数据列表 dataList// 生成Excel工作簿对象并写入数据workbook = ExcelWriter.exportData(dataList);// 写入Excel文件到前端if(null != workbook){String excelName = "示例Excel导出";String fileName = excelName + DateUtil.format(new Date(), DateUtil.SHORT_DATE) + ".xlsx";fileName = new String(fileName.getBytes("UTF-8"),"iso8859-1");response.setHeader("Content-Disposition", "attachment;filename=" + fileName);response.setContentType("application/x-download");response.setCharacterEncoding("UTF-8");response.addHeader("Pargam", "no-cache");response.addHeader("Cache-Control", "no-cache");response.flushBuffer();out = response.getOutputStream();workbook.write(out);out.flush();}} catch (Exception e) {logger.WARNING("写入Excel过程出错!错误原因:" + e.getMessage());} finally {try {if (null != workbook) {workbook.close();}if (null != out) {out.close();}} catch (IOException e) {logger.WARNING("关闭workbook或outputStream出错!");}}}

// 前台页面发送请求到后台Controller时的JS代码可参考:var url = "/exportExcel";window.location=url;

3. 源码下载

点我哦

原文地址/Dreamer-1/p/10469430.html

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。