java通过poi来读写excel目前很方便,支持xls和xlsx格式,目前代码支持按照sheet模板导出,并且支持sheet页级的模板复制功能。
附上poi的maven配置:
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.16</version> </dependency>
我使用了最新的版本。
先贴一下sheet页模板数据的封装:
/** * sheet页数据定制 * @author lyf * */ public class SheetData { /** * sheet页中存储 #{key} 的数据 */ private Map<String, Object> map = new HashMap<String, Object>(); /** * 列表数据存储 sheet页中替换${key} 并以列为单位向下赋值 */ private List<Object> datas = new LinkedList<Object> (); private String name ; public void setName(String name) { this.name = name; } public String getName() { return name; } public SheetData(String name) { super(); this.name = name; } public void put(String key , Object value) { map.put(key, value); } public void remove(String key) { map.remove(key); } public Object get(String key) { return map.get(key); } /** * 清理map存储和数据存储 */ public void clear() { map.clear(); datas.clear(); } public void addData(Object t){ datas.add(t); } public void addDatas(List<? extends Object> list) { datas.addAll(list); } public List<Object> getDatas() { return datas; } }
以下是针对sheet模板的封装类:
/** * excel操作公共类-提供excel按照模板输出 * @author lyf * */ public class ExcelUtils { /** * Sheet复制 * @param fromSheet * @param toSheet * @param copyValueFlag */ public static void copySheet(Workbook wb,Sheet fromSheet, Sheet toSheet, boolean copyValueFlag) { //合并区域处理 mergerRegion(fromSheet, toSheet); int index = 0; for (Iterator<Row> rowIt = fromSheet.rowIterator(); rowIt.hasNext();) { Row tmpRow = rowIt.next(); Row newRow = toSheet.createRow(tmpRow.getRowNum()); CellStyle style = tmpRow.getRowStyle(); if(style != null) newRow.setRowStyle(tmpRow.getRowStyle()); newRow.setHeight(tmpRow.getHeight()); //针对第一行设置行宽 if(index == 0) { int first = tmpRow.getFirstCellNum(); int last = tmpRow.getLastCellNum(); for(int i = first ; i < last ; i++) { int w = fromSheet.getColumnWidth(i); toSheet.setColumnWidth(i, w + 1); } toSheet.setDefaultColumnWidth(fromSheet.getDefaultColumnWidth()); } //行复制 copyRow(wb,tmpRow,newRow,copyValueFlag); index++ ; } } /** * 行复制功能 * @param fromRow * @param toRow */ static void copyRow(Workbook wb,Row fromRow,Row toRow,boolean copyValueFlag){ for (Iterator<Cell> cellIt = fromRow.cellIterator(); cellIt.hasNext();) { Cell tmpCell = cellIt.next(); Cell newCell = toRow.createCell(tmpCell.getColumnIndex()); copyCell(wb,tmpCell, newCell, copyValueFlag); } } /** * 复制原有sheet的合并单元格到新创建的sheet * * @param sheetCreat 新创建sheet * @param sheet 原有的sheet */ static void mergerRegion(Sheet fromSheet, Sheet toSheet) { int sheetMergerCount = fromSheet.getNumMergedRegions(); for (int i = 0; i < sheetMergerCount; i++) { CellRangeAddress cra = fromSheet.getMergedRegion(i); toSheet.addMergedRegion(cra); } } /** * 复制单元格 * * @param srcCell * @param distCell * @param copyValueFlag * true则连同cell的内容一起复制 */ public static void copyCell(Workbook wb,Cell srcCell, Cell distCell, boolean copyValueFlag) { CellStyle newstyle=wb.createCellStyle(); //copyCellStyle(srcCell.getCellStyle(), newstyle); //distCell.setEncoding(srcCell.); newstyle.cloneStyleFrom(srcCell.getCellStyle()); //样式 distCell.setCellStyle(newstyle); //评论 if (srcCell.getCellComment() != null) { distCell.setCellComment(srcCell.getCellComment()); } // 不同数据类型处理 CellType srcCellType = srcCell.getCellTypeEnum(); distCell.setCellType(srcCellType); if (copyValueFlag) { if (srcCellType == CellType.NUMERIC) { if (DateUtil.isCellDateFormatted(srcCell)) { distCell.setCellValue(srcCell.getDateCellValue()); } else { distCell.setCellValue(srcCell.getNumericCellValue()); } } else if (srcCellType == CellType.STRING ) { distCell.setCellValue(srcCell.getRichStringCellValue()); } else if (srcCellType == CellType.BLANK ) { // nothing21 } else if (srcCellType == CellType.BOOLEAN ) { distCell.setCellValue(srcCell.getBooleanCellValue()); } else if (srcCellType == CellType.ERROR ) { distCell.setCellErrorValue(srcCell.getErrorCellValue()); } else if (srcCellType == CellType.FORMULA ) { distCell.setCellFormula(srcCell.getCellFormula()); } else { // nothing29 } } } /** * 写入excel数据 * @param model 采用的模板 位置在 src/model/下 模板第一个sheet页必须是模板sheet * @param sheetDatas 模板数据 */ public static void writeData(String model , OutputStream out,SheetData... sheetDatas ) { Workbook wb = null; try { InputStream input = ExcelUtils.class.getResourceAsStream("/model/" + model); if(input == null) { throw new RuntimeException("model excel file load error :/model/" + model + " , check model file is exists !"); } if(model.endsWith(".xlsx")) wb = new XSSFWorkbook(input); else if(model.endsWith(".xls")) wb = new HSSFWorkbook(input); else throw new RuntimeException("model file format is not valid , this : " + model + " , eg:.xlsx or xls"); } catch (IOException e) { // TODO Auto-generated catch block //e.printStackTrace(); throw new RuntimeException("model excel file load error :/model/" + model); } Sheet source = wb.getSheetAt(0); //就一个的话 直接用模板 int size = sheetDatas.length ; for(int i = 0 ; i < size ; i++) { if(i == 0) { wb.setSheetName(0, sheetDatas[0].getName()); } else { Sheet toSheet = wb.createSheet(sheetDatas[i].getName()); //复制格式 copySheet(wb, source, toSheet, true); } } for(int i = 0 ; i < size ; i++) { //写数据 writeData(sheetDatas[i], wb.getSheetAt(i)); } try { wb.write(out); out.flush(); wb.close(); out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 向sheet页中写入数据 * @param values 数据Map * @param sheet sheet */ public static void writeData(SheetData sheetData , Sheet sheet) { //从sheet中找到匹配符 #{}表示单个 , ${}表示集合,从该单元格开始向下追加 for(Iterator<Row> rowIt = sheet.rowIterator(); rowIt.hasNext();) { Row row = rowIt.next(); //取cell for(int j = row.getFirstCellNum() ; j < row.getLastCellNum() ; j++) { Cell cell = row.getCell(j); //判断cell的内容是否包含 $ 或者# if(cell != null && cell.getCellTypeEnum() == CellType.STRING && cell.getStringCellValue() != null && (cell.getStringCellValue().contains("$") || cell.getStringCellValue().contains("#") )) { //剥离# $ String[] winds = CommonUtils.getWildcard(cell.getStringCellValue().trim()); for(String wind : winds) { writeData(sheetData, wind , cell , sheet); } } } } } /** * 填充数据 * @param values * @param keyWind #{name}只替换当前 or ${names} 从当前行开始向下替换 */ static void writeData(SheetData sheetData , String keyWind , Cell cell , Sheet sheet) { String key = keyWind.substring(2 , keyWind.length() - 1); if(keyWind.startsWith("#")) { //简单替换 Object value = sheetData.get(key); //为空则替换为空字符串 if(value == null) value = "" ; String cellValue = cell.getStringCellValue(); cellValue = cellValue.replace(keyWind, value.toString()); cell.setCellValue(cellValue); } else if(keyWind.startsWith("$")) { //从list中每个实体开始解,行数从当前开始 int rowindex = cell.getRowIndex(); int columnindex = cell.getColumnIndex(); List<? extends Object> listdata = sheetData.getDatas(); //不为空的时候开始填充 if(listdata != null && !listdata.isEmpty()){ for(Object o : listdata) { Object cellValue = CommonUtils.getValue(o, key); Row row = sheet.getRow(rowindex); if(row == null) { row = sheet.createRow(rowindex); } //取出cell Cell c = row.getCell(columnindex); if(c == null) c = row.createCell(columnindex); if(cell.getCellStyle() != null){ c.setCellStyle(cell.getCellStyle()); } if(cell.getCellTypeEnum() != null) { c.setCellType(cell.getCellTypeEnum()); } if(cellValue != null) { if(cellValue instanceof Number || CommonUtils.isNumber(cellValue) ) c.setCellValue( Double.valueOf(cellValue.toString())); else if(cellValue instanceof Boolean) c.setCellValue((Boolean)cellValue); else if(cellValue instanceof Date) c.setCellValue((Date)cellValue); else c.setCellValue(cellValue.toString()); } else { //数据为空 如果当前单元格已经有数据则重置为空 if(c.getStringCellValue() != null) { c.setCellValue(""); } } rowindex++ ; } } else { //list数据为空则将$全部替换空字符串 String cellValue = "" ; cell.setCellValue(cellValue); } } } }
其中注意我的 模板文件全部放在 source/model/ 目录下,大家用的时候改成自己实际的位置。
其中用到了CommonUtils公共类中封装的几个静态方法:
/** * 从实体中解析出字段数据 * @param data 可能为pojo或者map 从field中解析 * @param field 字段名称 * @return */ @SuppressWarnings("rawtypes") public static Object getValue(Object data , String field) { if(data instanceof Map) { Map map = (Map) data; return map.get(field); } try { String method = "get" + field.substring(0 , 1).toUpperCase() + field.substring(1); Method m = data.getClass().getMethod(method, null); if(m != null) { return m.invoke(data, null); } } catch (Exception e) { // TODO Auto-generated catch block // e.printStackTrace(); logger.error("data invoke error , data:" + data + " , key:" + field); return null; } return null ; } /** * 判断是否为数字 * @param v * @return */ public static boolean isNumber(Object v) { if(v == null) return false; if(v instanceof Number) { return true ; } else if(v.toString().matches("^\\d+$")) { return true ; } else if(v.toString().matches("^-?\\d+\\.?\\d+$")) { return true ; } else { try{ Double.parseDouble(v.toString()); return true ; }catch(Exception e) { return false; } } } /** * 返回 #{} 或者 ${} 中包含的值 * @param str * @param type * @return eg:#{name} ${ages} */ public static String[] getWildcard(String str ) { List<String> list = new ArrayList<String>(); int start = 0; while(start < str.length() && start >= 0) { start = str.indexOf("{", start); int end = str.indexOf("}", start); if(start > 0) { String wc = str.substring(start - 1 , end + 1); list.add(wc); } if(start < 0) break ; start = end + 1; } return list.toArray(new String[0]); }
下面开始写测试,编辑一个excel模板:
编写一个测试数据实体(实际使用Map效率会更好一些):
public class TestData { private int id ; private int p_id ; private String name ; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getP_id() { return p_id; } public void setP_id(int p_id) { this.p_id = p_id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public TestData(int id, int p_id, String name) { super(); this.id = id; this.p_id = p_id; this.name = name; } }
编写测试类,注意模型test.xlsx 已经放入src/model/ 目录下:
import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import com.xahl.data.common.ExcelUtils; import com.xahl.data.pojo.SheetData; public class TestExcel2 { public static void main(String[] args) { //获取模板 String model = "test.xlsx" ; File f = new File("e:/test.xlsx"); SheetData[] sds = new SheetData[5]; //创建5个数据sheet for( int i = 0 ; i < 5 ; i++) { SheetData sd = new SheetData("测试" + i); sd.put("name", "张三" + i); sd.put("age", 13); //每个sheet页加入100条测试数据 //注意这里可以加入pojo也可以直接使用map,理论上map在这里效率更高一些 for(int j = 0 ; j < 100 ; j++) { TestData td = new TestData(j, j * -1, "t" + j); sd.addData(td);; } sds[i] = sd ; } try { ExcelUtils.writeData(model, new FileOutputStream(f) ,sds); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
输出文件如下:
模板中单元格的样式会延续复制,包含颜色,宽度等等。有兴趣大家可以一起扩展一下。
相关推荐
### POI 基于模板导出 Excel 的实现方法 #### 概述 Apache POI 是一个用于读写 Microsoft Office 格式文件的 Java 库,其中包括对 Excel 文件的支持。在实际开发过程中,经常会遇到需要根据现有的 Excel 模板来...
以上就是基于Apache POI通过模板导出Excel的基本流程。实际开发中,你可能还需要处理更复杂的情况,如多Sheet操作、合并单元格、处理图表、嵌入图片等。同时,为了提高性能,可以考虑使用SXSSFWorkbook,它提供了一...
在本案例中,我们关注的是如何使用 Apache POI 库来导出 Excel 文件,特别是根据模板导出和简单列表导出。下面将详细介绍这个过程。 1. **Apache POI 概述** Apache POI 提供了 Java API 来读写 Microsoft Office ...
本篇文章将深入探讨如何使用Apache POI基于模板来导出Excel文件,以满足数据展示和报告生成的需求。 首先,我们需要理解Apache POI的工作原理。POI库允许Java程序与Microsoft Excel的文件格式进行交互,提供了对XLS...
在这个特定的例子中,我们将讨论如何使用POI库基于一个Excel模板文件循环输出数据行,并将结果导出为新的Excel文件。 首先,我们需要理解POI库的基本概念。POI提供了HSSF(Horizontally SpreadSheet Format)和XSSF...
2. **通过模板导出Excel表格**: - 在开发中,通常会预先准备好一个Excel模板文件,这个模板文件包含了固定格式和一些基本的数据结构。 - Java程序通过读取这个模板文件,然后填充数据,最后将填充后的文件导出为...
模板中的单元格、公式、样式、图表等元素都以XML的形式存在,Java POI通过解析这些XML来操作Excel内容。 在使用Java POI处理模板时,我们需要做以下步骤: 1. **读取模板**:使用`XSSFWorkbook`类打开模板文件,它...
除了平时简单的数据导出需求外,我们也经常...源码案例提供了模板,单个数据写入与列表数据写入以及文件导出的代码,详细的说明请参照个人博客“Excel模板导出”,源码可以让读者更加详细的了解Excel导出的过程和原理。
这篇博客"java使用POI Excel模板导出数据"探讨了如何利用POI库在Java中创建Excel模板并填充数据。下面将详细介绍这个过程以及相关知识点。 首先,我们需要理解Apache POI的基本概念。POI是Apache软件基金会的一个...
Apache POI提供了一种高效、灵活的方式,使Java开发者能够根据模板导出Excel文件。通过熟练掌握POI API,可以实现各种定制化的Excel处理需求,提高工作效率,简化数据报告的生成流程。 以上内容涵盖了使用Apache ...
四、导出Excel文件 1. 写入输出流:创建FileOutputStream,将填充好的工作簿写入到输出流中。 ```java FileOutputStream out = new FileOutputStream("output.xlsx"); workbook.write(out); out.close(); ``` 2. ...
在Java编程中,导出复杂的Excel模板是一项常见的需求,尤其在数据分析、报表生成或数据交换等场景中。本文将深入探讨如何使用Java实现这一功能,包括选用的库、步骤、以及处理复杂模板的关键技巧。 首先,Java中最...
本教程将详细介绍如何使用JAVA POI库来创建一个包含图片的完整Excel导出功能。 首先,你需要在项目中引入Apache POI依赖。如果你使用的是Maven,可以在pom.xml文件中添加以下依赖: ```xml <groupId>org.apache....
poi导入、导出,支持百万级数据模板导出、合并excel。项目为spring-boot-2上开发。resource里面有模板,在junit测试类中修改为本地存在路径即可导出文件,在junit测试类中修改for循环的i可以模拟百万级数据导出。注意...
在"Apache POI 模板导出excel.rar"这个压缩包中,我们聚焦于使用Apache POI 3.16版本来生成基于Excel模板的数据导出功能。这个过程涉及到多个关键知识点,下面将详细阐述。 1. **Apache POI库**:Apache POI是一个...
springboot+poi导出指定格式Excel模板,完整项目,导出即用。springboot+poi导出指定格式Excel模板,完整项目,导出即用。springboot+poi导出指定格式Excel模板,完整项目,导出即用。springboot+poi导出指定格式...
提供的"poi模板导出excel文件jar包.zip"压缩包包含两个重要的Java档案(JAR)文件:`commons-collections4-4.1.wso2v1.jar`和`commons-math3-3.0.jar`,它们是POI项目所依赖的库。 1. **Apache Commons Collections...
String outputFile = "D:\\excel\\excel.xlsx"; OutputStream outputStream = new FileOutputStream(outputFile); UtilExcel utilExcel = new UtilExcel(); String titles = "所属区域,所属车间,当前处理人,描述...
通过这个“java的poi生成excel图表demo”,我们可以学习如何利用POI创建动态的、数据驱动的Excel曲线图,进一步提升数据的可视性和理解性。这个压缩包中的“EexcelChart”可能是示例代码、测试数据或生成的Excel文件...