java根据xml配置文件导出excel通用方法

时间:2021-04-23 17:17:50

  java web项目中时常会用到导出功能,而导出excel几乎是每个项目必备的功能之一。针对形形色色的导出方法及个人平时的工作经验,特将导出excel方法整理成通用的方法,根据xml配置来实现特定的导出。

  此方法基于struts2框架实现,先看struts.xml配置文件中的配置方法:

 <action name="exportExcel" class="exportExcelAction">
<result name="download" type="stream">
<param name="contentType">application/vnd.ms-excel</param>
<param name="contentDisposition">attachment;filename="${excelName}"</param>
<param name="inputName">excelStream</param>
</result>
</action>

  1、excelName对应bean中的excelName属性,为导出文件名称;

  2、excelStream对应bean中导出数据流,即导出方法返回的数据流。

  接着是导出配置文件:excel.xml,需要导出的列表按照规则配置在此xml文件中即可:

 <?xml version="1.0" encoding="utf-8"?>
<excel>
<element title="检测库信息表" class="com.model.CheckRecord">
<property name="xmmc" display_name="项目名称"></property>
<property name="sampleNo" display_name="样品编号"></property>
<property name="detectTime" display_name="检测日期"></property>
<property name="jcbh" display_name="检测板号"></property>
<property name="ypmc" display_name="样品名称"></property>
<property name="yplx" display_name="样品类型"></property>
<property name="ypcd" display_name="样品产地"></property>
<property name="resultType" display_name="检测类型"></property>
<property name="resultValue" display_name="检测结果"></property>
<property name="resultDetect" display_name="检测读数值"></property>
<property name="resultTip" display_name="检测提示"></property>
<property name="submitStaff" display_name="送检人员"></property>
<property name="submitTime" display_name="送检时间"></property>
</element>
</excel>

  excel节点为根节点,element节点即为需要导出的列表节点,class属性用来唯一区别不同的导出列表,即根据class属性查找需要导出的列表属性集合,title属性当然是导出excel表格的标题咯。

  property节点是需要导出的字段,name属性和javabean中属性一一对应,display_name是excel表格所对应的显示名称。

  不同的导出列表只需要按照上面的实例配置多个element即可,切记class属性要唯一哦。

  接下来就是导出excel工具类啦,先看代码:

 package excel.util;

 /**
* 导出excel工具类
* @author BaiFL
*/
public class ExportExcelUtil { /**标题**/
private String title; private InputStream inputStream = null; private ByteArrayOutputStream outputStream = null; private HSSFWorkbook workbook; private HSSFSheet sheet; /**表格行**/
private HSSFRow row; /**单元格**/
private HSSFCell cell; /**字体**/
private HSSFFont font; /**单元格样式**/
private HSSFCellStyle cellStyle; /**
* 字段及字段注释
* key:字段名
* value:字段注释
*/
private Map<String, String> propertyMap = new HashMap<String, String>(); /**
* 导出excel
* @param className 完整类名
* @param list 导出结果集
*/
public InputStream export(String className, List<?> list){ //初始化
this.instance(className); //设置字体
font = workbook.createFont();
font.setFontName("宋体");
font.setFontHeightInPoints((short) 12); //设置单元格类型
cellStyle = workbook.createCellStyle();
cellStyle.setFont(font);
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); //创建第一行title
row = sheet.createRow(0);
this.setCellValue(0, title);
//合并单元格:0行~0行,0列~propertyMap.size() - 1列
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, propertyMap.size() - 1)); //创建第二行标题行
row = sheet.createRow(1);
int i = 0;
//遍历propertyMap
for(String key : propertyMap.keySet()){
//创建单元格
this.setCellValue(i, propertyMap.get(key));
i++;
} //遍历数据集合
for(int j = 0; j < list.size(); j++) {
Object object = list.get(j);
//创建数据行,从第三行开始
row = sheet.createRow(j + 2);
int k = 0;
for(String key : propertyMap.keySet()){
Field f;
String value;
try {
f = object.getClass().getDeclaredField(key);
//设置私有字段的可访问性
f.setAccessible(true);
//获取字段get方法
value = String.valueOf(f.get(object));
//设置单元格
this.setCellValue(k, value);
k++;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
try {
outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
byte[] content = outputStream.toByteArray();
inputStream = new ByteArrayInputStream(content);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
if(outputStream != null){
outputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return inputStream;
} /**
* 初始化
* @param className 完整类名
* 根据className获取excel.xml文件对应element属性集合
*/
@SuppressWarnings("unchecked")
private void instance(String className){
//加载配置文件
inputStream = ExportExcelUtil.class.
getResourceAsStream("/resources/exportExcel/excel.xml"); this.workbook = new HSSFWorkbook();
this.sheet = workbook.createSheet(); SAXReader reader = new SAXReader(); Document document = null;
try {
document = reader.read(inputStream);
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //获取根节点
Element excel = document.getRootElement(); //获取element集合
List<Element> elementList = excel.elements("element");
//根据class属性获取对应导出字段属性集合
for(Element element : elementList){
if(className.equals(element.attributeValue("class"))){
title = element.attributeValue("title");
//element下所有property集合
List<Element> childList = element.elements();
for(Element child : childList){
propertyMap.put(child.attributeValue("name"),
child.attributeValue("display_name"));
}
}
}
} /**
* 设置单元格
* @param index
* @param value
*/
private void setCellValue(int index, String value){
//创建单元格,设置单元格属性为文本类型
cell = row.createCell(index, HSSFCell.CELL_TYPE_STRING);
cell.setCellStyle(cellStyle);
cell.setCellValue(value);
//设置第index列宽为自动
sheet.autoSizeColumn(index);
} }
   方法export(String className, List<?> list)即导出excel通用方法,参数1:className对应导出配置文件excel.xml文件中element节点的class属 性,为完整类名;参数2:list即需要导出的数据,该list为对象集合,非数组集合。

  下面就是action中如何用啦,前面所有工作做好以后action中只需要很少的代码调用就可以啦,先看代码:
     /**
* exportExcel
* @return
*/
public String exportExcel() {
//获取数据条数
int count = recordService.count(checkRecord);
//分页
Page page = listForm.getPageObj(count);
if(StringUtils.blank(page.getOrderBy())){
//默认按检测时间倒序排序
page.setOrderBy("detectTime");
page.setOrder("desc");
}
//导出excel
if(Constant.EXPORT.equals(export)){
page.setPage(0);
page.setPageSize(exportSize !=0 && exportSize < count ? exportSize : (count < 65535 ? count : 65535));
List<CheckRecord> list = recordService.find(checkRecord, page);
excelStream = excel.export(CheckRecord.class.getName(), list);
return "download";  
}else{
List<CheckRecord> list = recordService.find(checkRecord, page);
httpServletRequest.setAttribute("List", list);
httpServletRequest.setAttribute("Page", page);
return "list";
}
}

  这是普通的页面列表数据展示代码,当属性export值为Constant.EXPORT("export")时,执行导出excel操作,导出数据范围为exportSize~65535;

  action中还必须有excelStream、excelName两个属性,分别和struts中的属性一一对应。

  /**导出excel数据流对应struts中的stream**/
  protected InputStream excelStream;

  /**excel文件名**/
  protected String excelName;

  getter/setter方法这里就不写了,action中可一定要写哦。

  至此,整个导出功能全部实现,赶紧试试吧

  下面的代码无需配置struts,直接导出并下载:

 package com.jeecms.common.util;

 import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; 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.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.ss.util.CellRangeAddress;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader; /**
* 导出excel工具类
* @author BaiFL
*/
public class ExportExcelUtil { /**标题**/
private String title; private InputStream inputStream = null; private OutputStream os = null; private HSSFWorkbook workbook; private HSSFSheet sheet; /**表格行**/
private HSSFRow row; /**单元格**/
private HSSFCell cell; /**字体**/
private HSSFFont font; /**单元格样式**/
private HSSFCellStyle cellStyle; /**
* 字段及字段注释
* key:字段名
* value:字段注释
*/
private Map<String, String> propertyMap = new LinkedHashMap<String, String>(); /**
* 导出excel
* @param className 完整类名
* @param list 导出结果集
* @param response
*/
public void export(String className, List<?> list, HttpServletResponse response){ //初始化
this.instance(className); response.reset(); response.setCharacterEncoding("UTF-8");
response.setContentType("application/vnd.ms-excel");
String fileName = null;
try {
fileName = new String(title.getBytes("GBK"), "ISO-8859-1");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
response.setHeader("Content-Disposition", "filename=" + fileName + DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss")+ ".xls"); //设置字体
font = workbook.createFont();
font.setFontName("宋体");
font.setFontHeightInPoints((short) 12); //设置单元格类型
cellStyle = workbook.createCellStyle();
cellStyle.setFont(font);
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); //创建第一行title
row = sheet.createRow(0);
this.setCellValue(0, title);
//合并单元格:0行~0行,0列~propertyMap.size() - 1列
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, propertyMap.size() - 1)); //创建第二行标题行
row = sheet.createRow(1);
int i = 0;
//遍历propertyMap
for(String key : propertyMap.keySet()){
//创建单元格
this.setCellValue(i, propertyMap.get(key));
i++;
}
//遍历数据集合
for(int j = 0; j < list.size(); j++) {
Object object = list.get(j);
//创建数据行,从第三行开始
row = sheet.createRow(j + 2);
int k = 0;
for(String key : propertyMap.keySet()){
if(key.indexOf(".") > 0){ //关联对象中的私有属性
String[] keyArr = key.split("\\.");
Field field;
Object obj = object;
for(int t = 0; t < keyArr.length; t++){
if(t + 1 == keyArr.length){ //获取私有字段值
try {
field = obj.getClass().getDeclaredField(keyArr[t]);
//设置私有字段的可访问性
field.setAccessible(true);
//获取字段get方法
Object value = field.get(obj);
//设置单元格
this.setCellValue(k, (value == null ? "" : String.valueOf(value)));
k++;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}else{ //获取关联对象
try {
field = obj.getClass().getDeclaredField(keyArr[t]);
//设置私有字段的可访问性
field.setAccessible(true);
//获取字段get方法
obj = field.get(obj);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}else{ //不包含关联对象的私有属性
try {
Field f = object.getClass().getDeclaredField(key);
//设置私有字段的可访问性
f.setAccessible(true);
//获取字段get方法
Object value = f.get(object);
//设置单元格
this.setCellValue(k, (value == null ? "" : String.valueOf(value)));
k++;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
try {
os = response.getOutputStream();
workbook.write(os);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
if(os != null){
os.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
} /**
* 初始化
* @param className 完整类名
* 根据className获取excel.xml文件对应element属性集合
*/
@SuppressWarnings("unchecked")
private void instance(String className){
//加载配置文件
inputStream = ExportExcelUtil.class.getResourceAsStream("/resources/exportExcel/excel.xml"); SAXReader reader = new SAXReader(); Document document = null;
try {
document = reader.read(inputStream);
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //获取根节点
Element excel = document.getRootElement(); //获取element集合
List<Element> elementList = excel.elements("element");
//根据class属性获取对应导出字段属性集合
for(Element element : elementList){
if(className.equals(element.attributeValue("class"))){
title = element.attributeValue("title");
//element下所有property集合
List<Element> childList = element.elements();
for(Element child : childList){
propertyMap.put(child.attributeValue("name"), child.attributeValue("display_name"));
}
}
} this.workbook = new HSSFWorkbook();
this.sheet = workbook.createSheet(title);
} /**
* 设置单元格
* @param index
* @param value
*/
private void setCellValue(int index, String value){
//创建单元格,设置单元格属性为文本类型
cell = row.createCell(index, HSSFCell.CELL_TYPE_STRING);
cell.setCellStyle(cellStyle);
cell.setCellValue(value);
//设置第index列宽为自动
sheet.autoSizeColumn(index);
} }

action中使用方法:

     /**
* 导出
* @param queryValue
* @param pageNo
* @param request
* @param response
* @param model
*/
@RequestMapping(value = "/addresslist/export.do")
public void export(String queryValue, Integer pageNo,
HttpServletRequest request, HttpServletResponse response, ModelMap model) {
List<CmsUser> list = manager.getExcelList(CmsUtils.getSiteId(request), queryValue);
ExportExcelUtil excel = new ExportExcelUtil();
excel.export(CmsUser.class.getName(), list, response);
log.info("通讯录导出成功!");
}