JXLS是一个简单易用的用于生成和读入Excel的工具。因本人对其接触使用不是很久,所以这里不再陈述,有兴趣的朋友可以取其源代码进行研究,其SVN地址:https://jxls.svn.sourceforge.net/svnroot/jxls
因在项目中需生成具有较大数据量的Excel报表,所以一次读入再模板化将降低系统的效率。能够以分页追加的方式来处理将显得尤为必要。基于此需求,于是写了一个比较简单的处理程序。
主要思路如下:
1. 构造一个ExcelBuilder
2. 提供一个Excel处理接口来具体处理Excel文件
2. 提供一个putValues,和addValue方法用于设置值(putServices及addService设置回调)
3. 提供一个parseWorkbook方法,用于追加至最终文件尾
4. 调用create方法,持久化最终文件
下面看具体代码:
1.ExcelBuilder类
package net.sf.jxls; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.util.CellRangeAddress; /** * Excel文件追加(基于POI3.6) * * @author zz(email:zhangzhen@foreveross.com) * @date 2011-4-19 * */ public class ExcelBuilder { private File templateFile;// 模板文件 private File tempFile;// 临时文件 private File resultFile;// 最终文件 private HSSFWorkbook workbook;// 工作簿 private int[] loopStartRows;//模板各sheet循环开始位置 private boolean deleteTemp = true;//删除临时文件 private Map<String,Object> beans,services; private WorkbookProcessor processor;// private HSSFWorkbook templateWorkbook; /** * * @param templateFilePath 模板路径 * @param resultFilePath 生成文件路径 * @param loopStartRows 模板各sheet循环开始位置 */ public ExcelBuilder(String templateFilePath, String resultFilePath,int[] loopStartRows) { this.templateFile = new File(templateFilePath); this.resultFile = new File(resultFilePath); this.loopStartRows = loopStartRows; initBuilder(); } /** * * @param templateFile 模板文件 * @param resultFile 生成文件 * @param loopStartRows 模板各sheet循环开始位置 */ public ExcelBuilder(File templateFile, File resultFile,int[] loopStartRows) { this.templateFile = templateFile; this.resultFile = resultFile; this.loopStartRows = loopStartRows; initBuilder(); } /** * * @param templateFilePath 模板文件路径 * @param resultFilePath 生成文件路径 * @param tempFilePath 临时文件路径 * @param loopStartRows 模板各sheet循环开始位置 * @param deleteTemp 是否删除临时文件 */ public ExcelBuilder(String templateFilePath, String resultFilePath, String tempFilePath,int[] loopStartRows,boolean deleteTemp) { this(templateFilePath, resultFilePath,loopStartRows); this.deleteTemp = deleteTemp; this.tempFile = new File(tempFilePath); initBuilder(); } /** * 初始化 */ private void initBuilder() { this.templateWorkbook = this.openWorkbook(this.templateFile); String filePath = this.resultFile.getPath(); if (this.tempFile == null && filePath.indexOf("\\") > -1){ String tempPath = filePath.substring(0, filePath.lastIndexOf("\\") + 1) + new Date().getTime() + "_temp.xls"; this.tempFile = new File(tempPath); } } /** * 添加值 * @param key 关键字 * @param val 值 */ public void addValue(String key,Object val){ if(this.beans==null) this.beans = new HashMap<String,Object>(); this.beans.put(key, val); } /** * 添加服务 * @param key 关键字 * @param service 服务 */ public void addService(String key,Object service){ if(this.services == null) this.services = new HashMap<String,Object>(); this.services.put(key, service); } /** * 添加值Map集合 * @param vals 值集合 */ public void putValues(Map<String,Object> vals){ this.beans = vals; } /** * 添加服务Map集合 * @param services 服务集合 */ public void putServices(Map<String,Object> services){ Set<String> keys = services.keySet(); for (Iterator<String> it = keys.iterator(); it.hasNext();) { String key = it.next(); this.addService(key,services.get(key)); } } /** * 模板处理 * @param config 配置项(可传入null) * @throws IOException */ public void parseWorkbook(Map<Object,Object> config) throws IOException { if(this.processor == null) throw new RuntimeException("ExcelBuilder should be supplied an instance of WorkbookProcessor!"); if(this.workbook == null){ this.processor.processWorkbook(templateWorkbook,this.resultFile,this.beans,this.services,config); this.workbook = this.openWorkbook(this.resultFile); return ; } this.processor.processWorkbook(templateWorkbook,this.tempFile,this.beans,this.services,config); HSSFWorkbook tempWorkbook = this.openWorkbook(this.tempFile); int totalSheet = tempWorkbook.getNumberOfSheets(); for (int i = 0; i < totalSheet; i++) { HSSFSheet srcSheet = tempWorkbook.getSheetAt(i); int from = srcSheet.getFirstRowNum(); if(loopStartRows!=null&&loopStartRows.length>i) from = loopStartRows[i]; mergeSheet(srcSheet, this.workbook.getSheetAt(i),tempWorkbook,this.workbook,from); } } /** * 打开一个工作簿 * @param file 工作簿文件 * @return */ private HSSFWorkbook openWorkbook(File file){ InputStream in = null; HSSFWorkbook wb = null; try { in = new FileInputStream(file); wb = new HSSFWorkbook(in); } catch (Exception e) { throw new RuntimeException("File" + file.getPath() + " not found:" + e.getMessage()); } finally { try { in.close(); } catch (Exception e) { } } return wb; } /** * 创建Excel * @return * @throws IOException */ public File create() throws IOException { FileOutputStream out = new FileOutputStream(this.resultFile); this.workbook.write(out); out.close(); if(this.deleteTemp){ if (this.tempFile.exists()) this.tempFile.delete(); } return this.resultFile; } /** * 合并工作表 * @param srcSheet 源工作表 * @param targetSheet 目的工作表 * @param from 源开始位置 */ public static void mergeSheet(HSSFSheet srcSheet,HSSFSheet targetSheet, HSSFWorkbook srcWorkbook,HSSFWorkbook targetWorkbook, int from) { mergeSheet(srcSheet, targetSheet,srcWorkbook,targetWorkbook, from, srcSheet.getLastRowNum() - from + 1); } /** * 合并工作表 * @param srcSheet 源工作表 * @param targetSheet 目的工作表 * @param from 源开始位置 * @param count 数目 */ public static void mergeSheet(HSSFSheet srcSheet, HSSFSheet targetSheet,HSSFWorkbook srcWorkbook,HSSFWorkbook targetWorkbook, int from, int count) { if (srcSheet.getLastRowNum() < from && srcSheet.getLastRowNum() - from < count) throw new IllegalArgumentException( "请检查参数!row from " + from + ",count" + count); int targetRowStart = targetSheet.getLastRowNum(); if (targetRowStart != 0) targetRowStart += 1; for (int rownum = from; rownum < from + count; rownum++) { HSSFRow fromRow = srcSheet.getRow(rownum); if (null == fromRow) return; HSSFRow targetFromRow = targetSheet.getRow(rownum);//为复制样式 HSSFRow toRow = targetSheet.createRow(targetRowStart + rownum - from); toRow.setHeight(fromRow.getHeight()); toRow.setHeightInPoints(fromRow.getHeightInPoints()); for (int i = fromRow.getFirstCellNum(); i <fromRow.getLastCellNum() && i >= 0; i++) { HSSFCell fromCell = getCell(fromRow, i); HSSFCell toCell = getCell(toRow, i); HSSFCell targetFromCell = getCell(targetFromRow,i); toCell.setCellStyle(targetFromCell.getCellStyle()); toCell.setCellType(fromCell.getCellType()); switch (fromCell.getCellType()) { case HSSFCell.CELL_TYPE_BOOLEAN: toCell.setCellValue(fromCell.getBooleanCellValue()); break; case HSSFCell.CELL_TYPE_FORMULA: toCell.setCellFormula(fromCell.getCellFormula()); break; case HSSFCell.CELL_TYPE_NUMERIC: toCell.setCellValue(fromCell.getNumericCellValue()); break; case HSSFCell.CELL_TYPE_STRING: toCell.setCellValue(fromCell.getRichStringCellValue()); break; default: } } } // 合并单元格 for (int j = 0; j < srcSheet.getNumMergedRegions(); j++) { CellRangeAddress region = srcSheet.getMergedRegion(j); if (region.getFirstRow() >= from && region.getLastRow() <= from + count) { int firstRow = region.getFirstRow() + targetRowStart-from; int lastRow = region.getLastRow() + targetRowStart-from; CellRangeAddress r = new CellRangeAddress(firstRow,lastRow,region.getFirstColumn(),region.getLastColumn()); targetSheet.addMergedRegion(r); } } } /** * * @param row 行数 * @param column 列数 * @return */ private static HSSFCell getCell(HSSFRow row, int column) { HSSFCell cell = row.getCell(column); if (cell == null) { cell = row.createCell(column); } return cell; } // resultFile public File getResultFile() { return this.resultFile; } //templateFile public File getTemplateFile() { return this.templateFile; } //tempFile public File getTempFile() { return this.tempFile; } //processor public WorkbookProcessor getProcessor() { return this.processor; } public void setProcessor(WorkbookProcessor processor) { this.processor = processor; } }
2.WorkbookProcessor接口:
package net.sf.jxls; import java.io.File; import java.io.IOException; import java.util.Map; import org.apache.poi.hssf.usermodel.HSSFWorkbook; public interface WorkbookProcessor { void processWorkbook(HSSFWorkbook templateWorkbook,File destFile,Map<String,Object> beans,Map<String,Object> services,Map<Object,Object> config) throws IOException; }
以jxls处理Excel为例(当然可以用其它可以以Excel模板为模板,以提供的数据为参数持久化工作表【曾以ExcelUtils做过实现,可是当升级至poi3.7时,ExcelUtils存在问题】),实现WorkbookProcessor接口
package net.sf.jxls; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Map; import net.sf.jxls.transformer.XLSTransformer; import org.apache.poi.hssf.usermodel.HSSFWorkbook; public class XlsExcelBuilderProcessor implements WorkbookProcessor { private XLSTransformer transformer; public XlsExcelBuilderProcessor(XLSTransformer transformer){ this.transformer = transformer; } public void processWorkbook(HSSFWorkbook templateWorkbook, File destFile, Map<String, Object> beans, Map<String, Object> services, Map<Object, Object> config) throws IOException { XLSTransformer former = this.transformer; if(config!=null&&config.get(XLSTransformer.class)!=null){ former =(XLSTransformer)config.get(XLSTransformer.class); } former.transformWorkbook(templateWorkbook, beans); FileOutputStream out = new FileOutputStream(destFile); templateWorkbook.write(out); out.flush(); out.close(); } }
如上我们的工作就算结束:编写测试
package net.sf.jxls; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import net.sf.jxls.exception.ParsePropertyException; import net.sf.jxls.transformer.XLSTransformer; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; public class ExcelBuilderTest { public static void main(String[] args) throws ParsePropertyException, InvalidFormatException, IOException { int pageSize = 5000,totalPage=4; testPage(pageSize,totalPage); } public static void testPage(int pageSize,int totalPage) throws ParsePropertyException, InvalidFormatException, IOException{ long start = System.currentTimeMillis(); String templateFileName ="E:\\demo.xls"; String destFileName="E:\\dest.xls"; ExcelBuilder builder = new ExcelBuilder(templateFileName,destFileName,new int[]{2,2}); builder.setProcessor(new XlsExcelBuilderProcessor(new XLSTransformer())); for(int i=1;i<=totalPage;i++){ List<ArticleEntity> list = new ArrayList<ArticleEntity>(); for(int j=1;j<=pageSize;j++){ ArticleEntity t = new ArticleEntity(); t.setTitle("title"+j*i); list.add(t); } Map<String,Object> beans = new HashMap<String,Object>(); beans.put("list", list); beans.put("content", "ddd"); builder.putValues(beans); builder.parseWorkbook(null); } builder.create(); System.out.println("cost "+(System.currentTimeMillis()-start)); } }
经验证,在处理数据量较少的情况下,与不分页时耗相当。在处理大数据的情况下有明显优势。
生成文件的大致效果为图:
相关推荐
1. **模板创建**:首先,你需要创建一个Excel模板文件,这个模板定义了最终生成Excel文件的布局和样式。模板中的某些单元格可以被标记为变量,这些变量会在生成过程中被Java对象的属性值替换。 2. **数据绑定**:在...
C# 用NPOI固定模版导出字符串以及图片等数据,导入npoi插件后,亲测可直接运行。
- **Excel**:导入或导出 Excel 文件。 - **Layout 布局页**:管理布局页的设计,用于复杂图表的布局。 - **Notes 记事本**:添加注释或说明文档到项目中。 - **FunctionPlot 函数绘图**:绘制数学函数图像。 #####...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
1657.5.4 处理宽度固定的文本文件 1667.5.5 追加文本数据到一个现有的表 1677.6 使用剪贴板导入数据 1677.6.1 向一个表粘贴新记录 1687.6.2 通过从剪贴板上粘贴来替换记录 1707.7 从Access表导出数据 1717.7.1 通过...
介绍如何将`GridView`控件中的数据导出为Excel文件。 - **示例102**:从Excel文件导入`GridView`控件数据。通过示例演示如何将Excel文件中的数据导入到`GridView`控件中。 - **示例103**:`GridView`控件导出Excel...
将数据导出到Excel / CSV / JSON URL 改进算法(聚合+对齐) 计划抓取频率 抓取JavaScript页面(从XHR请求获取) 数据追加(最新数据追加) 修改检索器的字段名称,列位置和模板 更改数据库体系结构(不可...
- **实现方法**: 可以使用LotusScript或Java脚本将视图导出为Excel文件,或将表单内容导出为Word文档。 #### 27. 关于Web上的检索问题 - **检索问题**: 包括全文搜索、关键字搜索等,通常通过构建索引和使用查询...