经常会遇到给用户提供数据下载的场景,将相关数据导出为Excel,因此对此进行了相关工具方法的封装:
pom:
org.apache.poi
poi-ooxml
3.9
Controller层调用:
@GetMapping("download")
public void downloadAnnualBudget(@RequestParam("businessYear") Integer year,
@RequestParam(value = "version", required = false) Integer version,
HttpServletResponse httpResponse) {
// 获取待下载数据
List dataset = annualBudgetService.getBudget(year, version);
String[] headers = {"资源类型", "单价", "折扣", "预算量", 计费量"};
download(annualBudgetDownLoadBos, headers, httpResponse);
}
工具类封装:
public class ExportExcelUtils {
private static final Logger logger = LoggerFactory.getLogger(ExportExcelUtils.class);
/**
* 导出无头部标题行Excel, 时间格式默认:yyyy-MM-dd hh:mm:ss
* @param workbook
* @param title
* @param dataset
*/
public static void exportExcel(XSSFWorkbook workbook, String title, Collection dataset) {
exportExcel2007(workbook,title, null, dataset);
}
/**
* 导出带头部标题行Excel, 时间格式默认:yyyy-MM-dd hh:mm:ss
* @param workbook
* @param title
* @param headers
* @param dataset
*/
public static void exportExcel(XSSFWorkbook workbook, String title, String[] headers, Collection dataset) {
exportExcel2007(workbook,title, headers, dataset);
}
/**
* 通用Excel导出方法,利用反射机制遍历对象的所有字段,将数据写入Excel文件中, 此版本生成2007以上版本的文件 (文件后缀:xlsx)
* 如果有时间数据,设定输出格式。默认为"yyyy-MM-dd hh:mm:ss"
* @param workbook 工作薄
* @param title 表格标题名
* @param headers 表格头部标题集合
* @param dataset 需要显示的数据集合,集合中一定要放置符合JavaBean风格的类的对象。此方法支持的JavaBean属性的数据类型有基本数据类型及String, Date
*/
public static void exportExcel2007(XSSFWorkbook workbook, String title, String[] headers, Collection dataset) {
// 在工作薄中创建一工作表
XSSFSheet sheet = workbook.createSheet(title);
// 设置表格默认列宽度为15个字节
sheet.setDefaultColumnWidth(20);
// 生成标题样式
XSSFCellStyle headerStyle = getHeaderStyle(workbook);
// 生成正文样式
XSSFCellStyle textStyle = getTextStyle(workbook);
// 产生表格标题行 1.在指定的索引处创建一行 2.设置单元格样式并赋值
XSSFRow row = sheet.createRow(0);
XSSFCell cellHeader;
for (int i = 0; i < headers.length; i++) {
// 在指定的索引处创建一列(单元格)
cellHeader = row.createCell(i);
cellHeader.setCellStyle(headerStyle);
// 在单元格输入内容
cellHeader.setCellValue(new XSSFRichTextString(headers[i]));
}
// 产生正文行数据, 通过反射获取数据
Iterator iterator = dataset.iterator();
int index = 0;
T obj;
// T类的所有字段
Field[] fields;
Field field;
// 字段名
String fieldName;
// 获取字段的方法名 getXXX
String getMethodName;
// 字段具体值
Object value;
XSSFCell cell;
Class objClass;
Method getMethod;
String textValue;
StringBuilder sb = new StringBuilder();
while (iterator.hasNext()) {
index++;
row = sheet.createRow(index);
obj = (T) iterator.next();
fields = obj.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
cell = row.createCell(i);
cell.setCellStyle(textStyle);
field = fields[i];
fieldName = field.getName();
getMethodName = sb.append("get").append(fieldName.substring(0, 1).toUpperCase()).append(fieldName.substring(1)).toString();
try {
objClass = obj.getClass();
getMethod = objClass.getMethod(getMethodName, new Class[]{});
value = getMethod.invoke(obj, new Object[]{});
// 强制类型转换,写入cell
if (value instanceof Integer) {
cell.setCellValue((Integer) value);
} else if (value instanceof Float) {
cell.setCellValue((Float) value);
} else if (value instanceof Double) {
cell.setCellValue((Double) value);
} else if (value instanceof Long) {
cell.setCellValue((Long) value);
} else if (value instanceof BigDecimal) {
cell.setCellValue(((BigDecimal) value).doubleValue());
} else if (value instanceof Date) {
textValue = TimeUtils.formatDateTime((Date) value);
cell.setCellValue(textValue);
} else {
// 其它数据类型都当作字符串简单处理
if (value != null) {
textValue = value.toString();
cell.setCellValue(textValue);
}
}
} catch (SecurityException e) {
logger.error(e.getMessage());
} catch (NoSuchMethodException e) {
logger.error(e.getMessage());
} catch (IllegalArgumentException e) {
logger.error(e.getMessage());
} catch (IllegalAccessException e) {
logger.error(e.getMessage());
} catch (InvocationTargetException e) {
logger.error(e.getMessage());
} finally {
// 清理资源
sb.delete(0, sb.length());
}
}
}
}
/**
* 获取header样式
* @param workbook
* @return
*/
public static XSSFCellStyle getHeaderStyle(XSSFWorkbook workbook) {
XSSFCellStyle style = workbook.createCellStyle();
// 设置这些样式
style.setFillForegroundColor(new XSSFColor(java.awt.Color.gray));
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.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
font.setFontName("宋体");
font.setColor(new XSSFColor(java.awt.Color.BLACK));
font.setFontHeightInPoints((short) 11);
// 把字体应用到当前的样式
style.setFont(font);
return style;
}
/**
* 获取正文样式
* @param workbook
* @return
*/
public static XSSFCellStyle getTextStyle(XSSFWorkbook workbook) {
XSSFCellStyle style = workbook.createCellStyle();
style.setFillForegroundColor(new XSSFColor(java.awt.Color.WHITE));
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);
style.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
XSSFFont font = workbook.createFont();
font.setBoldweight(XSSFFont.BOLDWEIGHT_NORMAL);
style.setFont(font);
return style;
}
/**
* 文件写入HttpServletResponse
* @param dataset 待生成Excel的数据
* @param headers Excel标题栏
* @param httpResponse http响应
* @param
*/
public static void download(List dataset, String[] headers, HttpServletResponse httpResponse) {
XSSFWorkbook workbook = new XSSFWorkbook();
try {
// 清空输出流
httpResponse.reset();
// 设定输出文件头,该方法有两个参数,分别表示应答头的名字和值。
httpResponse.setHeader("Content-disposition", "attachment; filename=" + "test"+ TimeUtils.formatDateTime(new Date()) + ".xls");
httpResponse.setContentType("application/msexcel");
OutputStream outputStream = httpResponse.getOutputStream();
exportExcel(workbook, "数据明细", headers, dataset);
workbook.write(outputStream);
} catch (IOException e) {
logger.error("获取明细失败: " + e.getMessage());
}
}
}