最近在Struts2+Spring+Mybatis整合的项目的开发工作中呢,遇到一个需要优化数据导出的功能的需求,原来的导出功能是通过jsp模板做的,发现只能导出Excel2003(.xls),并且导出到Excel中的样式也有所改变。因为Excel2003的有行数限制,超过相应行数后数据不显示。所以需要优化下导出功能,我就在寻找通用的导出工具类。但是发现我Dao层查询的数据都是封装在List中的,而网上提供的工具类都是直接接收List的。所以我做了下调整,能够支持两种数据集合的操作,话不多说,以下是实现过程:
package cn.voole.util;
import java.awt.Color;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ExportExcelUtil {
private Log logger = LogFactory.getLog(ExportExcelUtil.class);
/**
*
* @param title
* 表格标题名
* @param headers
* 表格属性列名数组 (第一行标题)
* @param Col
* 需要显示的表格属性列名数组 如果是javabean 必须和字段名字一直 如果为Map 必须为Map的key名字对应
* @param list
* 需要显示的数据集合,集合泛型支持两种,1:符合javabean风格的类的对象 2:Map类型。此方法支持的
* javabean属性的数据类型有基本数据类型及String,Date,byte[](图片数据)
* @param pattern
* 如果有时间数据,设定输出格式。默认为"yyy-MM-dd"
*/
public XSSFWorkbook exportExcel(String title, String[] headers,String[] Col,List list, String pattern) {
if(pattern == null || pattern.equals("")) pattern = "yyy-MM-dd";
XSSFWorkbook workbook = new XSSFWorkbook();
// 生成一个表格
XSSFSheet sheet = workbook.createSheet(title);
// 设置表格默认列宽度为15个字节
sheet.setDefaultColumnWidth(30);
// 生成一个样式
XSSFCellStyle style = workbook.createCellStyle();
// 设置这些样式
style.setFillForegroundColor(new XSSFColor(Color.BLUE));
style.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
style.setBorderBottom(XSSFCellStyle.BORDER_THIN);
style.setBorderLeft(XSSFCellStyle.BORDER_THIN);
style.setBorderRight(XSSFCellStyle.BORDER_THIN);
style.setBorderTop(XSSFCellStyle.BORDER_THIN);
style.setAlignment(XSSFCellStyle.ALIGN_CENTER);
// 生成一个字体
XSSFFont font = workbook.createFont();
font.setColor(new XSSFColor(Color.YELLOW));
font.setFontHeightInPoints((short) 12);
font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
// 把字体应用到当前的样式
style.setFont(font);
// 生成并设置另一个样式
XSSFCellStyle style2 = workbook.createCellStyle();
style2.setFillForegroundColor(new XSSFColor(Color.WHITE));
style2.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
style2.setBorderBottom(XSSFCellStyle.BORDER_THIN);
style2.setBorderLeft(XSSFCellStyle.BORDER_THIN);
style2.setBorderRight(XSSFCellStyle.BORDER_THIN);
style2.setBorderTop(XSSFCellStyle.BORDER_THIN);
style2.setAlignment(XSSFCellStyle.ALIGN_CENTER);
style2.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
// 生成另一个字体
XSSFFont font2 = workbook.createFont();
font2.setBoldweight(XSSFFont.BOLDWEIGHT_NORMAL);
// 把字体应用到当前的样式
style2.setFont(font2);
// 声明一个画图的顶级管理器
XSSFDrawing patriarch = sheet.createDrawingPatriarch();
// 产生表格标题行
XSSFRow row = sheet.createRow(0);
int Cell = 0;
for (short i = 0; i < headers.length; i++) {
XSSFCell cell = row.createCell(Cell);
cell.setCellStyle(style);
XSSFRichTextString text = new XSSFRichTextString(headers[i]);
cell.setCellValue(text);
Cell ++ ;
}
// 遍历集合数据,产生数据行
Iterator it = (Iterator) list.iterator();
int index = 0;
while (it.hasNext()) {
index++;
row = sheet.createRow(index);
T t = (T) it.next();
String[] fields = Col;
Cell = 0;
for (short i = 0; i < fields.length; i++) {
String fieldName = fields[i];
XSSFCell cell = row.createCell(Cell);
cell.setCellStyle(style2);
try {
Object value = "";
Class tCls = null;
Map map = null;
if(t instanceof Map){
map = (Map)t;
value = map.get(fieldName);
} else {
String getMethodName = "get"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
tCls = t.getClass();
Method getMethod = tCls.getMethod(getMethodName,new Class[] {});
value = getMethod.invoke(t, new Object[] {});
}
if(value == null ) value = "";
// 判断值的类型后进行强制类型转换
String textValue = null;
if (value instanceof Date) {
Date date = (Date) value;
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
textValue = sdf.format(date);
} else if (value instanceof byte[]) {
// 有图片时,设置行高为60px;
row.setHeightInPoints(60);
// 设置图片所在列宽度为80px,注意这里单位的一个换算
sheet.setColumnWidth(Cell, (short) (35.7 * 80));
// sheet.autoSizeColumn(i);
byte[] bsValue = (byte[]) value;
XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0,
1023, 255, (short) 6, index, (short) 6, index);
anchor.setAnchorType(2);
patriarch.createPicture(anchor, workbook.addPicture(
bsValue, XSSFWorkbook.PICTURE_TYPE_JPEG));
} else {
// 其它数据类型都当作字符串简单处理
textValue = value.toString();
}
// 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成
if (textValue != null) {
Pattern p = Pattern.compile("^//d+(//.//d+)?$");
Matcher matcher = p.matcher(textValue);
if (matcher.matches()) {
// 是数字当作double处理
cell.setCellValue(Double.parseDouble(textValue));
} else {
XSSFRichTextString richString = new XSSFRichTextString(
textValue);
XSSFFont font3 = workbook.createFont();
font3.setColor(new XSSFColor(Color.BLUE));
richString.applyFont(font3);
cell.setCellValue(richString);
}
}
Cell ++ ;
} catch (Exception e) {
e.printStackTrace();
}
}
}
return workbook;
}
}
页面中表头中的所有列名作为导出Excel没列的列名,从数据库查出封装到List的Map中的key值其实就是数据库中的字段名。当然也可以根据导出的需要自行封装。总之这个key值要传入工具类中,用来通过key值获取map中的数据写入到Excel的每一列中。
/**
*
* @Title: exportExcel
* @Description: 数据字典导出
* @param: @return
* @return: String
* @throws
*/
public String exportExcel(){
OutputStream ouputStream = null;
try {
HttpServletResponse response = ServletActionContext.getResponse();
HttpServletRequest request = ServletActionContext.getRequest();
//导出数据每列的列明
String[] headers = { "字典数据名称", "字典数据代码", "建档人员", "建档日期", "更新人员", "更新日期","备注"};
//在List
String[] Col = { "VC2ITEMNAME", "VC2ITEMCODE", "CREATEPERSON", "DATCREATE", "UPDATEPERSON", "DATUPDATE" ,"VC2DESC"};
//获取结果集
List> resultList =itemListService.exportExcel(itemList);
ExportExcelUtil> ex = new ExportExcelUtil>();
XSSFWorkbook workbook = ex.exportExcel("sheet1",headers,Col,resultList,null);
Date date = new Date();
SimpleDateFormat sd = new SimpleDateFormat("yyyyMMdd");
String dt = sd.format(date);
//导出的文件名
String filename = "数据字典导出"+dt+".xlsx";
//文件名编码
filename = encodeFileName(request, filename);
//设置响应头
response.setHeader("Content-Disposition", "attachment;filename=" + filename);
ouputStream = response.getOutputStream();
workbook.write(ouputStream);
ouputStream.flush();
ouputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
*
* @Title: encodeFileName
* @Description: 导出文件名编码设置
* @param: @param request
* @param: @param fileName
* @param: @return
* @param: @throws UnsupportedEncodingException
* @return: String
* @throws
*/
public static String encodeFileName(HttpServletRequest request, String fileName) throws UnsupportedEncodingException {
String agent = request.getHeader("USER-AGENT");
if (null != agent && -1 != agent.indexOf("MSIE")) {
return URLEncoder.encode(fileName, "UTF-8");
} else if (null != agent && -1 != agent.indexOf("Mozilla")) {
return "=?UTF-8?B?"+ (new String(Base64.encodeBase64(fileName.getBytes("UTF-8")))) + "?=";
} else {
return fileName;
}
}
/**
*
* Title: exportExcel
* Description: 查询所需要导出的数据并封装到List>中
* @param itemList
* @return
* @see cn.voole.service.ItemListService#exportExcel(cn.voole.model.ItemList)
*/
public List> exportExcel(ItemList itemList) {
try{
return itemListDao.exportExcel(itemList);
}catch(Exception e){
logger.error(e.getMessage());
}
return null;
}
package cn.voole.dao;
import java.util.HashMap;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import cn.voole.model.ItemList;
public interface ItemListDao {
/**
*
* @Title: exportExcel
* @Description: 查询需要导出的数据
* @param: @param itemList
* @param: @return
* @return: List>
* @throws
*/
public List> exportExcel(ItemList itemList);
}
<select id="exportExcel" parameterType="ItemList" resultType="hashmap">
select numItemList,
vc2ItemCode,
vc2ItemName,
numCreatePerson,
to_char(datCreate,'yyyy-MM-dd hh24:mi:ss') datCreate,
numUpdatePerson,
to_char(datUpdate,'yyyy-MM-dd hh24:mi:ss') datUpdate,
vc2Desc
from T_ITEMLIST
<if test="vc2Desc==1">
<where>
<if test="enterCondition!=null and enterCondition!='' and condition!=null and condition!=''">
<if test="enterCondition=='itemName'">
and vc2ItemName like '%'||#{condition}||'%'
if>
<if test="enterCondition=='itemCode'">
and vc2ItemCode like '%'||#{condition}||'%'
if>
<if test="enterCondition=='createPerson'">
and numCreatePerson like '%'||#{condition}||'%'
if>
<if test="enterCondition=='updatePerson'">
and numUpdatePerson like '%'||#{condition}||'%'
if>
if>
<if test="dateCondition!=null and dateCondition!=''">
<if test="dateCondition=='createDate'">
<if test="beginTime!=null and beginTime!='' and (endTime==null or endTime=='')">
= to_date(#{beginTime},'yyyy-MM-dd')]]>
if>
<if test="(beginTime==null or beginTime=='') and endTime!=null and endTime!=''">
if>
<if test="beginTime!=null and beginTime!='' and endTime!=null and endTime!=''">
and a.datCreate between to_date(#{beginTime},'yyyy-MM-dd') and to_date(#{endTime},'yyyy-MM-dd')
if>
if>
<if test="dateCondition=='updateDate'">
<if test="beginTime!=null and beginTime!='' and (endTime==null or endTime=='')">
= to_date(#{beginTime},'yyyy-MM-dd')]]>
if>
<if test="(beginTime==null or beginTime=='') and endTime!=null and endTime!=''">
if>
<if test="beginTime!=null and beginTime!='' and endTime!=null and endTime!=''">
and a.datUpdate between to_date(#{beginTime},'yyyy-MM-dd') and to_date(#{endTime},'yyyy-MM-dd')
if>
if>
if>
where>
if>
ORDER BY NLSSORT(vc2ItemName, 'NLS_SORT=SCHINESE_PINYIN_M')
select>
总结:
以上是我针对我项目中的需求编写的代码,实现了这一个功能,其他的导出只需要根据这个套路进行修改,剩下的就是体力活了,第一次写博客,没有经验,希望大家批评指正。
参考博客:
Java poi Excel 通用导出