一,前言
项目中可能经常需要导出数据报表到excel中,方便保存和备份,下面介绍使用poi进行数据导出到excel表中的方法
1,准备poi的jar包,可以在网上搜索,在官方网站或者其他技术网站下载
我使用的是3.16版的,将该jar包放入到你web-inf的lib目录下就行了
2.一个工具类的使用,可以自己查文档来写,这里直接贴代码
系统数据导出Excel 生成器
* @version 1.0
*/
package com.itheima.elec.util;
import java.io.OutputStream;
import java.util.ArrayList;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
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.hssf.util.HSSFColor;
public class ExcelFileGenerator {
private final int SPLIT_COUNT = 15; //Excel每个工作簿的行数
private ArrayList<String> fieldName = null; //excel标题数据集
private ArrayList<ArrayList<String>> fieldData = null; //excel数据内容
private HSSFWorkbook workBook = null;
/**
* 构造器
* @param fieldName 结果集的字段名
* @param data
*/
public ExcelFileGenerator(ArrayList<String> fieldName, ArrayList<ArrayList<String>> fieldData) {
this.fieldName = fieldName;
this.fieldData = fieldData;
}
/**
* 创建HSSFWorkbook对象
* @return HSSFWorkbook
*/
public HSSFWorkbook createWorkbook() {
workBook = new HSSFWorkbook();//创建一个工作薄对象
int rows = fieldData.size();//总的记录数
int sheetNum = 0; //指定sheet的页数
if (rows % SPLIT_COUNT == 0) {
sheetNum = rows / SPLIT_COUNT;
} else {
sheetNum = rows / SPLIT_COUNT + 1;
}
for (int i = 1; i <= sheetNum; i++) {//循环2个sheet的值
HSSFSheet sheet = workBook.createSheet("Page " + i);//使用workbook对象创建sheet对象
HSSFRow headRow = sheet.createRow((short) 0); //创建行,0表示第一行(本例是excel的标题)
for (int j = 0; j < fieldName.size(); j++) {//循环excel的标题
HSSFCell cell = headRow.createCell( j);//使用行对象创建列对象,0表示第1列
/**************对标题添加样式begin********************/
//设置列的宽度/
sheet.setColumnWidth(j, 6000);
HSSFCellStyle cellStyle = workBook.createCellStyle();//创建列的样式对象
HSSFFont font = workBook.createFont();//创建字体对象
//字体加粗
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
//字体颜色变红
font.setColor(HSSFColor.RED.index);
//如果font中存在设置后的字体,并放置到cellStyle对象中,此时该单元格中就具有了样式字体
cellStyle.setFont(font);
/**************对标题添加样式end********************/
//添加样式
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
if(fieldName.get(j) != null){
//将创建好的样式放置到对应的单元格中
cell.setCellStyle(cellStyle);
cell.setCellValue((String) fieldName.get(j));//为标题中的单元格设置值
}else{
cell.setCellValue("-");
}
}
//分页处理excel的数据,遍历所有的结果
for (int k = 0; k < (rows < SPLIT_COUNT ? rows : SPLIT_COUNT); k++) {
if (((i - 1) * SPLIT_COUNT + k) >= rows)//如果数据超出总的记录数的时候,就退出循环
break;
HSSFRow row = sheet.createRow((short) (k + 1));//创建1行
//分页处理,获取每页的结果集,并将数据内容放入excel单元格
ArrayList<String> rowList = (ArrayList<String>) fieldData.get((i - 1) * SPLIT_COUNT + k);
for (int n = 0; n < rowList.size(); n++) {//遍历某一行的结果
HSSFCell cell = row.createCell( n);//使用行创建列对象
if(rowList.get(n) != null){
cell.setCellValue((String) rowList.get(n).toString());
}else{
cell.setCellValue("");
}
}
}
}
return workBook;
}
public void expordExcel(OutputStream os) throws Exception {
workBook = createWorkbook();
workBook.write(os);//将excel中的数据写到输出流中,用于文件的输出
os.close();
}
}
核心方法就是expordExcel(os)这个方法,用它来生成的excel数据,并且下载
3.准备导出的核心方法,我用的是struts框架,导出作为一个功能,放在在excelExport这个action方法中了
//初始化数据,
//从数据库中查出所需的标题中文数据
ArrayList<String> fieldName = elecUserService.findFieldNameWithExcel();
//从数据库中查找所有的需要导出的数据
ArrayList<ArrayList<String>> fieldData = elecUserService.findExcelDataWithExcel(elecUser);
//使用poi进行导出到excel
ExcelFileGenerator excelFileGenerator = new ExcelFileGenerator(fieldName, fieldData);
try {
String fileName = "用户列表("+DateUtil.dateToStringWithExcel(new Date())+").xls";
fileName = new String(fileName.getBytes("gbk"),"iso-8859-1");
//设置下载的文件类型类型
response.setContentType("application/vnd.ms-excel");
//设置下载的文件头信息
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
//得到输出流
//OutputStream os = response.getOutputStream();
//使用ByteArrayOutputStream来输出,而不是response
ByteArrayOutputStream os = new ByteArrayOutputStream();
//导出
excelFileGenerator.expordExcel(os);
//将os转换成byte[]数组
byte[] buff = os.toByteArray();
//创建一个ByteArrayInputStream用来存储读取buff
ByteArrayInputStream in = new ByteArrayInputStream(buff);
//设置到下载属性的驱动
elecUser.setInputStream(in);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
解释下这两个方法findFieldNameWithExcel()和findExcelDataWithExcel(),第一个方法是从数据库中查找需要导出数据的字段名,等会作为导出后excel表的字段标题
第二个方法是从数据库查出第一个方法查出字段对应的数据内容,对于第二个方法是先通过查找第一个方法查到的字段名的对应的英文名,再将这个字段的英文名,作为sql语句需要查询的字段来查询,因为数据库中存储的字段名是英文名,下面展示下数据库表的存储
好了这样就得到了存储中文字段名的集合fieldname,和存储数据的fieldData,通过这两个字段创建了excelFileGenerator对象,这就是之前提到的工具类,这样就把
中文标题字段和数据传给了excelFileGenerator这个工具类,这个工具类通过expordExcel(os)方法中的 createWorkbook()这个方法产生一个工作簿,最后,将其写入流中
供下载使用,最后贴出图片