使用POI生成Excel报表
先把报表模板截图贴上来

下面是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());
}
}
使用POI生成Excel报表的更多相关文章
- poi生成excel报表合并列
功能任务 poi导出excel统计报表,有合并列的. 根据结构生成层级. 目标 1输入一个linkshashmap LinkedHashMap<String, Object> fieldM ...
- ASP.NET MVC 4.0 中使用NPOI 2.2.0 按模板生成Excel报表
使用 NPOI 你就可以在没有安装 Office 或者相应环境的机器上对 WORD/EXCEL 文档进行读写.NPOI是构建在POI 3.x版本之上的,它可以在没有安装Office的情况下对Word/ ...
- java生成excel报表文件
此次简单的操作将数据从数据库导出生成excel报表以及将excel数据导入数据库 首先建立数据库的连接池: package jdbc; import java.io.FileInputStream; ...
- POI生成EXCEL文件
POI生成EXCEL文件 一.背景 根据指定格式的JSON文件生成对应的excel文件,需求如下 支持多sheet 支持单元格合并 支持插入图片 支持单元格样式可定制 需要 标题(title),表头( ...
- POI生成EXCEL,公式不自动执行的有关问题
POI生成EXCEL,公式不自动执行的问题 场景:POI读取Excel模板. 当使用POI操作Excel时,发现由POI生成的公式能够在打开Excel是被执行, 而事先手工写入Excel模板文件的公式 ...
- poi生成excel整理(设置边框/字体/颜色/加粗/居中/)
转: poi生成excel整理(设置边框/字体/颜色/加粗/居中/) 2016年12月02日 11:05:23 吃奶的牛 阅读数:34324 HSSFWorkbook wb = new HSSFW ...
- java使用poi生成excel
使用poi生成excel通常包含一下几个步骤 创建一个工作簿 创建一个sheet 创建一个Row对象 创建一个cell对象(1个row+1个cell构成一个单元格) 设置单元格内容 设置单元格样式. ...
- 使用node.js生成excel报表下载(excel-export express篇)
引言:日常工作中已经有许多应用功能块使用了nodejs作为web服务器,而生成报表下载也是我们在传统应用. java中提供了2套类库实现(jxl 和POI),.NET 作为微软的亲儿子更加不用说,各种 ...
- Java 利用 poi 生成 Excel文件的通用例子
在用java 写数据库应用的时候, 通常会生成各种报表,而这些报表可能会被导出为各种格式的文件,比如Excel文档,pdf 文档等等. 今天先做了一个生成Excel 文档的例子,主要解决以下问题: 生 ...
随机推荐
- extjs_04_grid(弹出窗口&行编辑器 CRUD数据)
1.弹出窗口(添加.删除) watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWRhbV93enM=/font/5a6L5L2T/fontsize/400/f ...
- Principle of Computing (Python)学习笔记(5) BFS Searching + Zombie Apocalypse
1 Generators Generator和list comprehension非常类似 Generators are a kind of iterator that are defined l ...
- lua 与 php 通过AES数据加密进行通讯
近期公司有款<围住神经猫>的微信小游戏火爆的不行!公司又决定开发一系列的神经猫的小游戏,于是,我被拉过来了. 后来使用cocos-2dx 开发一款小游戏,client用的是lua脚本,为了 ...
- Canvas上绘制几何图形
重要的类自定义View组件要重写View组件的onDraw(Canvase)方法,接下来是在该 Canvas上绘制大量的几何图形,点.直线.弧.圆.椭圆.文字.矩形.多边形.曲线.圆角矩形,等各种形状 ...
- google浙大招聘笔试题 师兄只能帮你到这儿了
google浙大招聘笔试题 一.单选1.80x86中,十进制数-3用16位二进制数表示为?00100002.假定符号-.*.$分别代表减法.乘法和指数运算,且 1)三个运算符优先级顺序是:-最高,*其 ...
- 将Qt 动态链接生成的exe及依赖dll打包方法
源地址:http://blog.csdn.net/ztz0223/article/details/8939341 将Qt 动态链接生成的exe及依赖dll打包方法 原文:http://www.qtcn ...
- Primefaces的fileUpload组件使用
最近在学习Primefaces(当然也是项目中需要用的).在使用其fileUpload遇到了不小的困难,现总结一下供大家及我自己今后参考使用. 1.首先是使用环境配置:正常的Primefaces开发环 ...
- 【每日一摩斯】-Troubleshooting: High CPU Utilization (164768.1) - 系列4
Jobs (CJQ0, Jn, SNPn) Job进程运行用户定义的以及系统定义的类似于batch的任务.检查Job进程占用大量CPU资源的方法,就像检查用户进程一样. 可以根据以下视图检查Job进程 ...
- C++学习之路—运算符重载(一)概念、方法及规则
(根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 1 什么是运算符重载 先来说下什么是重载吧 ...
- Delphi 能不能从Ring 3进入Ring 0
我发现了一篇发表在1999.11.29 b13版的 <令win32应用程序跳入系统层>东南大学 卢威 luwei@126.com 是用vc++嵌汇编做的, ...