最近项目中要将数据导出到Excel,没做过,在网上搜了些资料,简单实现了这个功能。项目环境是spring+struts+mybatis。我将功能放在了action里,在页面使用表单提交到后台,如果有需要,可以传递一些参数供查询数据库使用,在action里调用业务层方法查询封装数据。
对于大数据量的导出,没有经过测试,我也是初次使用POI,还没有深入研究,这里仅供参考。
先看实现效果
简单表格如下
复杂表格如下
下面看代码。如果表格简单,表头只有一行的话,可以使用下面的工具类,封装好数据,直接调用即可导出到excel。
package org.wusq.ssx.component.poi;
import java.io.OutputStream;
import java.util.LinkedHashMap;
import java.util.List;
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.HSSFRichTextString;
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;
/**
* 导出EXCEL工具类,适用于单行表头的表格
* @author wusq
* @since 2011-06-20
*/
public class ExportExcelUtils {
/**
* 导出Excel的方法
* @param title excel中的sheet名称
* @param headers 表头
* @param columns 表头对应的数据库中的列名
* @param result 结果集
* @param out 输出流
* @param pattern 时间格式
* @throws Exception
*/
public static void exportExcel(String title, String[] headers, String[] columns, List<LinkedHashMap<String, Object>> result, OutputStream out, String pattern) throws Exception{
// 声明一个工作薄
HSSFWorkbook workbook = new HSSFWorkbook();
// 生成一个表格
HSSFSheet sheet = workbook.createSheet(title);
// 设置表格默认列宽度为20个字节
sheet.setDefaultColumnWidth(20);
// 生成一个样式
HSSFCellStyle style = workbook.createCellStyle();
// 设置这些样式
style.setFillForegroundColor(HSSFColor.GOLD.index);
style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style.setBorderRight(HSSFCellStyle.BORDER_THIN);
style.setBorderTop(HSSFCellStyle.BORDER_THIN);
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
// 生成一个字体
HSSFFont font = workbook.createFont();
font.setColor(HSSFColor.VIOLET.index);
//font.setFontHeightInPoints((short) 12);
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
// 把字体应用到当前的样式
style.setFont(font);
// 指定当单元格内容显示不下时自动换行
style.setWrapText(true);
/*
以下可以用于设置导出的数据的样式
// 生成并设置另一个样式
HSSFCellStyle style2 = workbook.createCellStyle();
style2.setFillForegroundColor(HSSFColor.LIGHT_YELLOW.index);
style2.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
style2.setBorderBottom(HSSFCellStyle.BORDER_THIN);
style2.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style2.setBorderRight(HSSFCellStyle.BORDER_THIN);
style2.setBorderTop(HSSFCellStyle.BORDER_THIN);
style2.setAlignment(HSSFCellStyle.ALIGN_CENTER);
style2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 生成另一个字体
HSSFFont font2 = workbook.createFont();
font2.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
// 把字体应用到当前的样式
style2.setFont(font2);
// 声明一个画图的顶级管理器
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
// 定义注释的大小和位置,详见文档
HSSFComment comment = patriarch.createComment(new HSSFClientAnchor(0, 0, 0, 0, (short) 4, 2, (short) 6, 5));
// 设置注释内容
comment.setString(new HSSFRichTextString("可以在POI中添加注释!"));
// 设置注释作者,当鼠标移动到单元格上是可以在状态栏中看到该内容.
comment.setAuthor("leno");*/
// 产生表格标题行
HSSFRow row = sheet.createRow(0);
for (int i = 0; i < headers.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellStyle(style);
HSSFRichTextString text = new HSSFRichTextString(headers[i]);
cell.setCellValue(text);
}
// 遍历集合数据,产生数据行
if(result != null){
int index = 1;
for(LinkedHashMap<String, Object> m:result){
row = sheet.createRow(index);
int cellIndex = 0;
for(String s:columns){
HSSFCell cell = row.createCell(cellIndex);
//cell.setCellStyle(style2);
HSSFRichTextString richString = new HSSFRichTextString(m.get(s) == null ? "" : m.get(s).toString());
//HSSFFont font3 = workbook.createFont();
//font3.setColor(HSSFColor.BLUE.index);
//richString.applyFont(font3);
cell.setCellValue(richString);
cellIndex++;
}
index++;
}
}
workbook.write(out);
}
}
测试类继承ActionSupport。如果表头比较复杂,有多行,则需单独处理,见测试类的moreHead()方法。
package org.wusq.ssx.component.poi;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
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;
import org.apache.poi.hssf.util.Region;
import org.apache.struts2.ServletActionContext;
import org.springframework.stereotype.Controller;
import com.opensymphony.xwork2.ActionSupport;
@Controller
public class ExportExcelAction extends ActionSupport{
private static final long serialVersionUID = 2165773254718823136L;
/**
* 测试单行表头的表格
* @return
*/
public String oneHead(){
try {
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("octets/stream");
response.addHeader("Content-Disposition","attachment;filename=test.xls");
OutputStream out = response.getOutputStream();
//此处为模拟数据,实际应用从数据库中查出
List<LinkedHashMap<String, Object>> result = new ArrayList<LinkedHashMap<String, Object>>();
LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
map.put("ID", "1");
map.put("USER", "wusq");
map.put("PASS", "000000");
result.add(map);
String[] headers = {"ID", "用户名", "密码"};
String[] columns = {"ID", "USER", "PASS"};
ExportExcelUtils.exportExcel("用户表", headers, columns, result, out, "");
out.close();
} catch (Exception e) {
//e.printStackTrace();
}
return null;
}
/**
* 测试多行表头
* @return
*/
public String moreHead(){
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("octets/stream");
response.addHeader("Content-Disposition","attachment;filename=test.xls");
OutputStream out = null;
HSSFWorkbook workbook = new HSSFWorkbook();
try {
out = response.getOutputStream();
HSSFSheet sheet = workbook.createSheet();
List<String> jsdj = new ArrayList<String>();
jsdj.add("一级");
jsdj.add("二级");
List<String> xzdj = new ArrayList<String>();
xzdj.add("国道");
xzdj.add("省道");
int number = 2 + jsdj.size() + xzdj.size();
// 给工作表列定义列宽(实际应用自己更改列数)
for (int i = 0; i < number; i++) {
sheet.setColumnWidth(i, 3000);
}
// 创建单元格样式
HSSFCellStyle cellStyle = workbook.createCellStyle();
// 指定单元格居中对齐
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
// 指定单元格垂直居中对齐
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 指定当单元格内容显示不下时自动换行
cellStyle.setWrapText(true);
cellStyle.setFillForegroundColor(HSSFColor.GOLD.index);
// 设置列头
HSSFRow row0 = sheet.createRow(0);
HSSFCell cell0 = row0.createCell(0);
cell0.setCellStyle(cellStyle);
cell0.setCellValue(new HSSFRichTextString("所属年份"));
HSSFCell cell1 = row0.createCell(1);
cell1.setCellStyle(cellStyle);
cell1.setCellValue(new HSSFRichTextString("隐患公里"));
HSSFCell cell2 = row0.createCell(2);
cell2.setCellStyle(cellStyle);
cell2.setCellValue(new HSSFRichTextString("技术等级"));
HSSFCell cell3 = row0.createCell(2 + jsdj.size());
cell3.setCellStyle(cellStyle);
cell3.setCellValue(new HSSFRichTextString("行政等级"));
HSSFRow row1 = sheet.createRow(1);
HSSFCell row1Cell = null;
int m = 0;
int n = 0;
for(int i = 2; i < 2 + jsdj.size() + xzdj.size(); i++){
if(i < 2 + jsdj.size()){
row1Cell = row1.createCell(i);
row1Cell.setCellStyle(cellStyle);
row1Cell.setCellValue(new HSSFRichTextString(jsdj.get(m)));
m++;
}else{
row1Cell = row1.createCell(i);
row1Cell.setCellStyle(cellStyle);
row1Cell.setCellValue(new HSSFRichTextString(xzdj.get(n)));
n++;
}
}
//合并第一行到第二行的第一列
sheet.addMergedRegion(new Region(0, (short) 0, 1, (short) 0));
//合并第一行到第二行的第二列
sheet.addMergedRegion(new Region(0, (short) 1, 1, (short) 1));
// 合并第一行的第三列到第指定的列
int a = 1 + jsdj.size();
sheet.addMergedRegion(new Region(0, (short) 2, 0, (short) a));
int b = 1 + jsdj.size() + xzdj.size();
sheet.addMergedRegion(new Region(0, (short) (a + 1), 0, (short) b));
//此处为模拟数据,实际应用从数据库中查出
List<LinkedHashMap<String, Object>> result = new ArrayList<LinkedHashMap<String, Object>>();
LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
map.put("SSNF", "2011");
map.put("YHGL", "100");
map.put("YJ", "10");
map.put("EJ", "20");
map.put("GD", "30");
map.put("SD", "40");
result.add(map);
HSSFRow row = null;
HSSFCell rowCell = null;
for(int i = 0; i < result.size(); i++ ){
LinkedHashMap<String, Object> lhm = result.get(i);
row = sheet.createRow(i + 2);
rowCell = row.createCell(0);
rowCell.setCellValue(new HSSFRichTextString(lhm.get("SSNF").toString()));
rowCell = row.createCell(1);
rowCell.setCellValue(new HSSFRichTextString(lhm.get("YHGL").toString()));
rowCell = row.createCell(2);
rowCell.setCellValue(new HSSFRichTextString(lhm.get("YJ").toString()));
rowCell = row.createCell(3);
rowCell.setCellValue(new HSSFRichTextString(lhm.get("EJ").toString()));
rowCell = row.createCell(4);
rowCell.setCellValue(new HSSFRichTextString(lhm.get("GD").toString()));
rowCell = row.createCell(5);
rowCell.setCellValue(new HSSFRichTextString(lhm.get("SD").toString()));
}
} catch (Exception e) {
e.printStackTrace();
}
try {
workbook.write(out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
<body>
测试导出到excel功能(单行表头) <br>
<form id="form1" name="form1" action="oneHead.do" method="post">
<input type="submit" name="submit" value="导出到Excel">
</form>
测试导出到excel功能(复杂表头) <br>
<form id="form2" name="form2" action="moreHead.do" method="post">
<input type="submit" name="submit" value="导出到Excel">
</form>
</body>
注意配置好struts2的跳转路径,一般不需要设置跳转页面。
<struts>
<package name="poi" namespace="/" extends="struts-default">
<action name="oneHead" class="exportExcelAction" method="oneHead">
</action>
<action name="moreHead" class="exportExcelAction" method="moreHead">
</action>
</package>
</struts>
异常处理可能不太合理,如果后台程序出现异常,对于简单表格,将导出一个空的excel文件,对于复杂表格,只导出了表头。
POI的jar包可以去官网下载,我用的3.7版本,引入poi-3.7-20101029.jar即可。
本文原先发表于本人的另一博客,后弃之不用,特转移到新博客来。