先把报表模板截图贴上来
下面是POI编写的报表生成类ExcelReport.java
package com.jadyer.report; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; 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; /** * 使用POI生成Excel报表 * @see 它所生成的报表是根据Excel模块文件生成的 * @see 这里要用到poi-3.9-20121203.jar和poi-ooxml-3.9-20121203.jar * @see 另外模板文件<<ReportTemplate.xls>>下载地址为http://download.csdn.net/detail/jadyer/5736263 * @create Jul 5, 2013 9:54:46 PM * @author 玄玉<http://blog.csdn.net/jadyer> */ public enum ExcelReport { //实现单例模式的唯一实例 INSTANCE; /**报表模板文件的存储位置*/ private static final String REPORT_TEMPLATE_FILE_PATH = "/ReportTemplate.xls"; /**本列开始填充序号的标识*/ private static final String SERIAL_NO = "serialNo"; /**本行开始填充数据的标识*/ private static final String DATA_BEGIN = "dataBegin"; /**表格采用同列样式的标识*/ private static final String USE_STYLES = "useStyles"; /**表格样式采用的默认样式*/ private static final String DEFAULT_STYLES = "defaultStyles"; /**初始行的下标(指的是填充数据的第一个单元格下标)*/ private int initRowIndex; /**初始列的下标(指的是填充数据的第一个单元格下标)*/ private int initColIndex; /**当前行的下标(指的是填充数据的当前单元格下标)*/ private int currRowIndex; /**当前列的下标(指的是填充数据的当前单元格下标)*/ private int currColIndex; /**最后一行的下标*/ private int lastRowIndex; /**序号列的第一个单元格的下标*/ private int serialColIndex; /**默认行高(指的是填充数据的第一个单元格的行高)*/ private float defaultRowHeight; /**存放模板中所有表格样式(键为99表示表格的默认样式)*/ private Map<Integer, CellStyle> allCellStyle = new HashMap<Integer, CellStyle>(); private Row currRow; private Sheet sheet; private Workbook wb; /** * 基础数据初始化 */ private ExcelReport(){ try { //从指定目录中读取 //wb = WorkbookFactory.create(new File(REPORT_TEMPLATE_FILE_PATH)); //从classpath中读取模板文档 wb = WorkbookFactory.create(ExcelReport.class.getResourceAsStream(REPORT_TEMPLATE_FILE_PATH)); //获取模板中的第一个Sheet sheet = wb.getSheetAt(0); } catch (InvalidFormatException e) { throw new RuntimeException("模板文件格式无效", e); } catch (IOException e) { throw new RuntimeException("模板文件不存在", e); } for(Row row : sheet){ for(Cell cell : row){ //报表模板文件default.xls中约定序号和SERIAL_NO和DATA_BEGIN都是String类型的 if(Cell.CELL_TYPE_STRING != cell.getCellType()){ continue; } String str = cell.getStringCellValue().trim(); //收集默认的表格样式 if(DEFAULT_STYLES.equals(str)){ this.allCellStyle.put(99, cell.getCellStyle()); } //收集除默认表格样式以外的所有表格样式 if(USE_STYLES.equals(str)){ this.allCellStyle.put(cell.getColumnIndex(), cell.getCellStyle()); } //定位序号列的第一个单元格下标 if(SERIAL_NO.equals(str)){ this.serialColIndex = cell.getColumnIndex(); } //定位开始填充数据的第一个单元格的下标 if(DATA_BEGIN.equals(str)){ this.initColIndex = cell.getColumnIndex(); this.initRowIndex = row.getRowNum(); this.currColIndex = this.initColIndex; this.currRowIndex = this.initRowIndex; this.lastRowIndex = sheet.getLastRowNum(); this.defaultRowHeight = row.getHeightInPoints(); } } } } /** * 创建行 */ public void createNewRow(){ //下移行的条件有2个:当前行非初始行,且当前行没有超过最后一行 if(this.currRowIndex!=this.initRowIndex && this.lastRowIndex>this.currRowIndex){ //将指定的几行进行下移一行 sheet.shiftRows(this.currRowIndex, this.lastRowIndex, 1, true, true); //既然下移了那么最后一行下标就也要增大了 this.lastRowIndex++; } //在指定的行上创建一个空行(如果此行原本有单元格和数据,那么也会被空行覆盖,且创建出来的空行是没有单元格的) this.currRow = sheet.createRow(this.currRowIndex); this.currRow.setHeightInPoints(this.defaultRowHeight); this.currRowIndex++; this.currColIndex = this.initColIndex; } /** * 构造单元格(包括创建单元格和填充数据) */ public void buildCell(String value){ Cell cell = this.currRow.createCell(this.currColIndex); if(this.allCellStyle.containsKey(this.currColIndex)){ cell.setCellStyle(this.allCellStyle.get(this.currColIndex)); }else{ cell.setCellStyle(this.allCellStyle.get(99)); } cell.setCellValue(value); this.currColIndex++; } /** * 插入序号 */ private void insertSerialNo(){ int index = 1; Row row = null; Cell cell = null; for(int i=this.initRowIndex; i<this.currRowIndex; i++){ row = sheet.getRow(i); cell = row.createCell(this.serialColIndex); cell.setCellValue(index++); } } /** * 替换模板文件中的常量 */ private void replaceConstantData(){ Map<String, String> constantData = new HashMap<String, String>(); constantData.put("title", "优秀学生名单"); constantData.put("date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); constantData.put("developer", "玄玉博客<http://blog.csdn.net/jadyer>"); for(Row row : sheet){ for(Cell cell : row){ if(Cell.CELL_TYPE_STRING != cell.getCellType()){ continue; } String str = cell.getStringCellValue().trim(); if(str.startsWith("#")){ if(constantData.containsKey(str.substring(1))){ cell.setCellValue(constantData.get(str.substring(1))); } } } } } /** * 将生成的excel文件写到输出流中 * @see 适用于文件下载 */ public void writeToStream(OutputStream os){ this.insertSerialNo(); this.replaceConstantData(); try { wb.write(os); } catch (IOException e) { throw new RuntimeException("写入流失败", e); } } /** * 将生成的excel文件写到指定的文件中 * @see 适用于硬盘保存 */ public void writeToFile(String filepath){ this.insertSerialNo(); this.replaceConstantData(); FileOutputStream fos = null; try { fos = new FileOutputStream(filepath); wb.write(fos); } catch (FileNotFoundException e) { throw new RuntimeException("写入的文件[" + filepath + "]不存在", e); } catch (IOException e) { throw new RuntimeException("写入数据失败", e); } finally { if(null != fos){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
最后是其单元测试类ExcelReportTest.java(即演示实际调用步骤)
package com.jadyer.report; import java.io.File; import org.junit.Assert; import org.junit.Test; import com.jadyer.report.ExcelReport; public class ExcelReportTest { @Test public void testExcelReportUtil(){ ExcelReport eru = ExcelReport.INSTANCE; eru.createNewRow(); eru.buildCell("aa"); eru.buildCell("玄玉"); eru.buildCell("cc"); eru.buildCell("dd"); eru.createNewRow(); eru.buildCell("aa"); eru.buildCell("http://blog.csdn.net/jadyer"); eru.buildCell("cc"); eru.buildCell("dd"); eru.createNewRow(); eru.buildCell("aa"); eru.buildCell("蓄机而动"); eru.buildCell("cc"); eru.buildCell("dd"); eru.writeToFile("D:/test.xls"); Assert.assertTrue(new File("D:/test.xls").exists()); } }