使用POI生成Excel报表

先把报表模板截图贴上来

 

使用POI生成Excel报表

 

下面是POI编写的报表生成类ExcelReport.java

 

[java][/java] view plaincopyprint?

  1. package com.jadyer.report;
  2. import java.io.FileNotFoundException;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.io.OutputStream;
  6. import java.text.SimpleDateFormat;
  7. import java.util.Date;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
  11. import org.apache.poi.ss.usermodel.Cell;
  12. import org.apache.poi.ss.usermodel.CellStyle;
  13. import org.apache.poi.ss.usermodel.Row;
  14. import org.apache.poi.ss.usermodel.Sheet;
  15. import org.apache.poi.ss.usermodel.Workbook;
  16. import org.apache.poi.ss.usermodel.WorkbookFactory;
  17. /**
  18.  * 使用POI生成Excel报表
  19.  * @see 它所生成的报表是根据Excel模块文件生成的
  20.  * @see 这里要用到poi-3.9-20121203.jar和poi-ooxml-3.9-20121203.jar
  21.  * @see 另外模板文件<<ReportTemplate.xls>>下载地址为http://download.csdn.net/jadyer/xxxxxx(稍候上传)
  22.  * @create Jul 5, 2013 9:54:46 PM
  23.  * @author 玄玉<http://blog.csdn.net/jadyer>
  24.  */
  25. public enum ExcelReport {
  26.     //实现单例模式的唯一实例
  27.     INSTANCE;
  28.     /**报表模板文件的存储位置*/
  29.     private static final String REPORT_TEMPLATE_FILE_PATH = “/ReportTemplate.xls”;
  30.     /**本列开始填充序号的标识*/
  31.     private static final String SERIAL_NO = “serialNo”;
  32.     /**本行开始填充数据的标识*/
  33.     private static final String DATA_BEGIN = “dataBegin”;
  34.     /**表格采用同列样式的标识*/
  35.     private static final String USE_STYLES = “useStyles”;
  36.     /**表格样式采用的默认样式*/
  37.     private static final String DEFAULT_STYLES = “defaultStyles”;
  38.     /**初始行的下标(指的是填充数据的第一个单元格下标)*/
  39.     private int initRowIndex;
  40.     /**初始列的下标(指的是填充数据的第一个单元格下标)*/
  41.     private int initColIndex;
  42.     /**当前行的下标(指的是填充数据的当前单元格下标)*/
  43.     private int currRowIndex;
  44.     /**当前列的下标(指的是填充数据的当前单元格下标)*/
  45.     private int currColIndex;
  46.     /**最后一行的下标*/
  47.     private int lastRowIndex;
  48.     /**序号列的第一个单元格的下标*/
  49.     private int serialColIndex;
  50.     /**默认行高(指的是填充数据的第一个单元格的行高)*/
  51.     private float defaultRowHeight;
  52.     /**存放模板中所有表格样式(键为99表示表格的默认样式)*/
  53.     private Map<Integer, CellStyle> allCellStyle = new HashMap<Integer, CellStyle>();
  54.     private Row currRow;
  55.     private Sheet sheet;
  56.     private Workbook wb;
  57.     /**
  58.      * 基础数据初始化
  59.      */
  60.     private ExcelReport(){
  61.         try {
  62.             //从指定目录中读取
  63.             //wb = WorkbookFactory.create(new File(REPORT_TEMPLATE_FILE_PATH));
  64.             //从classpath中读取模板文档
  65.             wb = WorkbookFactory.create(ExcelReport.class.getResourceAsStream(REPORT_TEMPLATE_FILE_PATH));
  66.             //获取模板中的第一个Sheet
  67.             sheet = wb.getSheetAt(0);
  68.         } catch (InvalidFormatException e) {
  69.             throw new RuntimeException(“模板文件格式无效”, e);
  70.         } catch (IOException e) {
  71.             throw new RuntimeException(“模板文件不存在”, e);
  72.         }
  73.         for(Row row : sheet){
  74.             for(Cell cell : row){
  75.                 //报表模板文件default.xls中约定序号和SERIAL_NO和DATA_BEGIN都是String类型的
  76.                 if(Cell.CELL_TYPE_STRING != cell.getCellType()){
  77.                     continue;
  78.                 }
  79.                 String str = cell.getStringCellValue().trim();
  80.                 //收集默认的表格样式
  81.                 if(DEFAULT_STYLES.equals(str)){
  82.                     this.allCellStyle.put(99, cell.getCellStyle());
  83.                 }
  84.                 //收集除默认表格样式以外的所有表格样式
  85.                 if(USE_STYLES.equals(str)){
  86.                     this.allCellStyle.put(cell.getColumnIndex(), cell.getCellStyle());
  87.                 }
  88.                 //定位序号列的第一个单元格下标
  89.                 if(SERIAL_NO.equals(str)){
  90.                     this.serialColIndex = cell.getColumnIndex();
  91.                 }
  92.                 //定位开始填充数据的第一个单元格的下标
  93.                 if(DATA_BEGIN.equals(str)){
  94.                     this.initColIndex = cell.getColumnIndex();
  95.                     this.initRowIndex = row.getRowNum();
  96.                     this.currColIndex = this.initColIndex;
  97.                     this.currRowIndex = this.initRowIndex;
  98.                     this.lastRowIndex = sheet.getLastRowNum();
  99.                     this.defaultRowHeight = row.getHeightInPoints();
  100.                 }
  101.             }
  102.         }
  103.     }
  104.     /**
  105.      * 创建行
  106.      */
  107.     public void createNewRow(){
  108.         //下移行的条件有2个:当前行非初始行,且当前行没有超过最后一行
  109.         if(this.currRowIndex!=this.initRowIndex && this.lastRowIndex>this.currRowIndex){
  110.             //将指定的几行进行下移一行
  111.             sheet.shiftRows(this.currRowIndex, this.lastRowIndex, 1, true, true);
  112.             //既然下移了那么最后一行下标就也要增大了
  113.             this.lastRowIndex++;
  114.         }
  115.         //在指定的行上创建一个空行(如果此行原本有单元格和数据,那么也会被空行覆盖,且创建出来的空行是没有单元格的)
  116.         this.currRow = sheet.createRow(this.currRowIndex);
  117.         this.currRow.setHeightInPoints(this.defaultRowHeight);
  118.         this.currRowIndex++;
  119.         this.currColIndex = this.initColIndex;
  120.     }
  121.     /**
  122.      * 构造单元格(包括创建单元格和填充数据)
  123.      */
  124.     public void buildCell(String value){
  125.         Cell cell = this.currRow.createCell(this.currColIndex);
  126.         if(this.allCellStyle.containsKey(this.currColIndex)){
  127.             cell.setCellStyle(this.allCellStyle.get(this.currColIndex));
  128.         }else{
  129.             cell.setCellStyle(this.allCellStyle.get(99));
  130.         }
  131.         cell.setCellValue(value);
  132.         this.currColIndex++;
  133.     }
  134.     /**
  135.      * 插入序号
  136.      */
  137.     private void insertSerialNo(){
  138.         int index = 1;
  139.         Row row = null;
  140.         Cell cell = null;
  141.         for(int i=this.initRowIndex; i<this.currRowIndex; i++){
  142.             row = sheet.getRow(i);
  143.             cell = row.createCell(this.serialColIndex);
  144.             cell.setCellValue(index++);
  145.         }
  146.     }
  147.     /**
  148.      * 替换模板文件中的常量
  149.      */
  150.     private void replaceConstantData(){
  151.         Map<String, String> constantData = new HashMap<String, String>();
  152.         constantData.put(“title”, “优秀学生名单”);
  153.         constantData.put(“date”, new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(new Date()));
  154.         constantData.put(“developer”, “玄玉博客<http://blog.csdn.net/jadyer>”);
  155.         for(Row row : sheet){
  156.             for(Cell cell : row){
  157.                 if(Cell.CELL_TYPE_STRING != cell.getCellType()){
  158.                     continue;
  159.                 }
  160.                 String str = cell.getStringCellValue().trim();
  161.                 if(str.startsWith(“#”)){
  162.                     if(constantData.containsKey(str.substring(1))){
  163.                         cell.setCellValue(constantData.get(str.substring(1)));
  164.                     }
  165.                 }
  166.             }
  167.         }
  168.     }
  169.     /**
  170.      * 将生成的excel文件写到输出流中
  171.      * @see 适用于文件下载
  172.      */
  173.     public void writeToStream(OutputStream os){
  174.         this.insertSerialNo();
  175.         this.replaceConstantData();
  176.         try {
  177.             wb.write(os);
  178.         } catch (IOException e) {
  179.             throw new RuntimeException(“写入流失败”, e);
  180.         }
  181.     }
  182.     /**
  183.      * 将生成的excel文件写到指定的文件中
  184.      * @see 适用于硬盘保存
  185.      */
  186.     public void writeToFile(String filepath){
  187.         this.insertSerialNo();
  188.         this.replaceConstantData();
  189.         FileOutputStream fos = null;
  190.         try {
  191.             fos = new FileOutputStream(filepath);
  192.             wb.write(fos);
  193.         } catch (FileNotFoundException e) {
  194.             throw new RuntimeException(“写入的文件[” + filepath + “]不存在”, e);
  195.         } catch (IOException e) {
  196.             throw new RuntimeException(“写入数据失败”, e);
  197.         } finally {
  198.             if(null != fos){
  199.                 try {
  200.                     fos.close();
  201.                 } catch (IOException e) {
  202.                     e.printStackTrace();
  203.                 }
  204.             }
  205.         }
  206.     }
  207. }

最后是其单元测试类ExcelReportTest.java(即演示实际调用步骤)

 

 

[java][/java] view plaincopyprint?

  1. package com.jadyer.report;
  2. import java.io.File;
  3. import org.junit.Assert;
  4. import org.junit.Test;
  5. import com.jadyer.report.ExcelReport;
  6. public class ExcelReportTest {
  7.     @Test
  8.     public void testExcelReportUtil(){
  9.         ExcelReport eru = ExcelReport.INSTANCE;
  10.         eru.createNewRow();
  11.         eru.buildCell(“aa”);
  12.         eru.buildCell(“玄玉”);
  13.         eru.buildCell(“cc”);
  14.         eru.buildCell(“dd”);
  15.         eru.createNewRow();
  16.         eru.buildCell(“aa”);
  17.         eru.buildCell(“http://blog.csdn.net/jadyer”);
  18.         eru.buildCell(“cc”);
  19.         eru.buildCell(“dd”);
  20.         eru.createNewRow();
  21.         eru.buildCell(“aa”);
  22.         eru.buildCell(“蓄机而动”);
  23.         eru.buildCell(“cc”);
  24.         eru.buildCell(“dd”);
  25.         eru.writeToFile(“D:/test.xls”);
  26.         Assert.assertTrue(new File(“D:/test.xls”).exists());
  27.     }
  28. }

标签