无事,正好有点想法,就顺手组装了一个动态导出excel的组件
主要是利用阿帕奇的poi组件。
在需要导出到excel的实体类型对象上加入自定义注解。
注解类源码:
package com.gome.meidian.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @ClassName: ColumnTitle
* @Description: 导出时对vo每个字段列名的标识 无注解的字段不导出
* @author li
* @date 2018年1月15日 上午10:28:08
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcelColumn {
/**
* @Title: title
* @return
* @Description: 表头列名 必填
*/
public String title();
/**
* @Title: width
* @return
* @Description: 列宽 默认15
*/
public short width() default 15;
public enum Alignment {
LEFT(0x1), CENTER(0x2), RIGHT(0x3);
private int value;
private Alignment(int value) {
this.value = value;
}
public int getValue() {
return value;
}
};
/**
* @Title: alignment
* @return
* @Description: 文字样式 默认居中(Alignment.CENTER)
*/
public Alignment alignment() default Alignment.CENTER;
/**
* @Title: boder
* @return
* @Description: 单元格是否需要边框 环绕包围 默认false
*/
public boolean boder() default false;
public enum StyleColor {
WHITE(0x9), BLACK(0x8), BLUE(0xc), RED(0xa), YELLOW(0xd);
private int value;
private StyleColor(int value) {
this.value = value;
}
public int getValue() {
return value;
}
};
/**
* @Title: styleColor
* @return
* @Description: 单元格背景色 默认白色
*/
public StyleColor styleColor() default StyleColor.WHITE;
public enum FontColor {
BLACK(0x8), BLUE(0xc), RED(0xa), YELLOW(0xd);
private int value;
private FontColor(int value) {
this.value = value;
}
public int getValue() {
return value;
}
};
/**
* @Title: fontColor
* @return
* @Description: 文字颜色 默认黑色(FontColor.BLACK) 暂支持 BLACK BLUE RED YELLO
*/
public FontColor fontColor() default FontColor.BLACK;
/**
* @Title: fontSize
* @return
* @Description: 字号大小 默认12
*/
public short fontSize() default 12;
/**
* @Title: fontName
* @return
* @Description: 字体 默认微软雅黑
*/
public String fontName() default "微软雅黑";
}
实体类除了表头必填,还实现了 列宽 单元格背景色 环绕边框 字体位置 字体 字号 颜色 等可以动态配置。
导出工具类:反射获取泛型类,接受注解值,动态导出。
接收参数为map<String,Collection<T>> ,一个key对应一个sheet页面 实现多sheet输出。
源码:
package com.gome.meidian.tool;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
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;
import org.springframework.stereotype.Component;
import com.gome.meidian.annotation.ExcelColumn;
import com.gome.meidian.annotation.ExcelColumn.Alignment;
/**
* @ClassName: ExcelUtil
* @Description: 导出excel通用工具类
* @author li
* @date 2018年4月3日 下午5:48:37
* @param <T>
*/
@Component
public class ExcelUtil<T> {
/**
* @Title: exportExcel
* @param dataMap
* map key为sheet value为sheet内的数据集合
* @param out
* @throws IOException
* @Description: 使用默认字体导出excel
*/
public void exportExcel(Map<String, Collection<T>> dataMap, OutputStream out) throws IOException {
HSSFWorkbook workbook = new HSSFWorkbook();
for (String sheetName : dataMap.keySet()) {
HSSFSheet sheet = workbook.createSheet(sheetName);
creatSheet(workbook, sheet, dataMap.get(sheetName));
}
try {
workbook.write(out);
// 自行处理out 例:out.flush(); out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @Title: creatSheet
* @param workbook
* @param sheet
* @param dataSet
* 单页的数据集合
* @param fontName
* 全局字体设置
* @throws IOException
* @Description: 创建页数单位
*/
private void creatSheet(HSSFWorkbook workbook, HSSFSheet sheet, Collection<T> dataSet)
throws IOException {
if (null == dataSet || dataSet.size() == 0) {
return;
}
// 列名集合
List<String> headers = new ArrayList<String>();
// 列宽
List<Short> columnWidth = new ArrayList<Short>();
// 内文样式位置
List<Integer> alignList = new ArrayList<Integer>();
// 是否需要边框
List<Boolean> boderList = new ArrayList<Boolean>();
// 字体颜色集合
List<Integer> fontColorList = new ArrayList<Integer>();
// 字体集合
List<String> fontNameList = new ArrayList<String>();
// 字号集合
List<Short> fontSizeList = new ArrayList<Short>();
// 单元格背景色
List<Integer> styleColorList = new ArrayList<Integer>();
//存放有注解的字段 也就是需要导出的字段 无注解字段排除
Field[] excelFileds = new Field[] {};
T t = (T) dataSet.toArray()[0];
Annotation annotation = null;
Field[] fields = t.getClass().getDeclaredFields();int j=0;
for (short i = 0; i < fields.length; i++) {
Field field = fields[i];
annotation = field.getAnnotation(ExcelColumn.class);
if (null == annotation) {
continue;
} else {
excelFileds[j] = field;
ExcelColumn excelColumn = (ExcelColumn) annotation;
headers.add(excelColumn.title());
columnWidth.add(excelColumn.width());
alignList.add(excelColumn.alignment().getValue());
boderList.add(excelColumn.boder());
fontColorList.add(excelColumn.fontColor().getValue());
fontNameList.add(excelColumn.fontName());
fontSizeList.add(excelColumn.fontSize());
styleColorList.add(excelColumn.styleColor().getValue());j++;
}
}
// 循环设置列宽
for (int i = 0; i < columnWidth.size(); i++) {
sheet.setColumnWidth(i, columnWidth.get(i) * 256);
}
// 产生表格标题行
HSSFRow row = sheet.createRow(0);
for (int i = 0; i < headers.size(); i++) {
HSSFCell cell = row.createCell(i);
setCellStyle(workbook, cell, alignList.get(i), boderList.get(i),styleColorList.get(i), fontColorList.get(i), fontNameList.get(i),fontSizeList.get(i),true);
HSSFRichTextString text = new HSSFRichTextString(headers.get(i));
cell.setCellValue(text);
}
// 遍历集合数据,产生数据行
Iterator<T> it = dataSet.iterator();
int index = 0;
while (it.hasNext()) {
index++;
row = sheet.createRow(index);
t = (T) it.next();
// 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值
for (int i = 0; i < excelFileds.length; i++) {
HSSFCell cell = row.createCell(i);
setCellStyle(workbook, cell, alignList.get(i), boderList.get(i),styleColorList.get(i), fontColorList.get(i), fontNameList.get(i),fontSizeList.get(i),false);
String fieldName = excelFileds[i].getName();
String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
try {
Method getMethod = t.getClass().getMethod(getMethodName, new Class[] {});
Object value = getMethod.invoke(t, new Object[] {});
String textValue = value.toString();
if (textValue != null) {
HSSFRichTextString richString = new HSSFRichTextString(textValue);
cell.setCellValue(richString);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* @Title: setCellStyle
* @param workbook
* @param cell 要配置的单元格
* @param alignment 单元格内文样式
* @param needBoder 否需要环绕边框
* @param sytleColor 单元格背景色
* @param fontColor 文字颜色
* @param fontName 字体
* @param fontSize 字号
* @param isBold 表头是否加粗
* @Description: 设置单元格以及字体的整体样式
*/
private void setCellStyle(HSSFWorkbook workbook, HSSFCell cell, int alignment, Boolean needBoder, int sytleColor,int fontColor,
String fontName,short fontSize,boolean isBold) {
// 生成一个通用样式 默认背景为白色
HSSFCellStyle style = workbook.createCellStyle();
style.setFillForegroundColor((short)sytleColor);
// 单元格内容样式
style.setAlignment((short) alignment);
// 单元格是否需要边框
if (needBoder) {
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);
}
// 生成一个字体 默认字体微软雅黑
HSSFFont font = workbook.createFont();
font.setFontName(fontName);
font.setColor((short) fontColor);
// 设置字体大小
font.setFontHeightInPoints(fontSize);
// 字体是否加粗
if (isBold) {
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
}
// 把字体应用到当前的样式
style.setFont(font);
cell.setCellStyle(style);
}
}
自己实现下载流的设置 关闭 。
public static void setRepensehead(HttpServletRequest request, HttpServletResponse response, String filename)
throws Exception {
String agent = request.getHeader("USER-AGENT").toLowerCase();
response.setContentType("application/vnd.ms-excel");
if (agent.contains("firefox")) {
response.setCharacterEncoding("utf-8");
response.setHeader("content-disposition",
"attachment;filename=" + new String(filename.getBytes(), "ISO8859-1") + ".xls");
} else {
response.setHeader("content-disposition", "attachment;filename=" + filename + ".xls");
}
}