电商商务,目前为止,做网站后台管理系统对到处数据的要求不是很高,反正自己公司内部用的嘛,能拉出来就行了,尽量简单。但是随着业务的发展,供应链系统出来了,涉及到订单,采购,库存,退款退货,财务等模块的集成。系统的生成Excel的业务越来越多,于是乎每个人都自己copy一段前人实现的代码,直接修改修改就生成一个Excel了。
这个操作方法,刚刚系统还小的时候,也没有什么关系,来回就那么点代码,可是当系统复杂了,导出的业务多了,每次代码review都看到一大段相同的代码,很不爽。于是乎写成公用类也就成为必然了。
下面是我设计生成Excel文件的设计:
一、生成一个文本Excel的抽象接口是要有如下几个方法:
package com.hqb360.common.excel;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 功能描述: 创建Excel接口
*
* @author: Zhenbin.Li
* Date: 13-11-19 Time:下午12:42
*/
public interface ExportExcelAware<T> {
/**
* 创建生成Excel文件
*
* <p>需要实现接口中的每一个方法, 接口中的方法都对应生成Excel的一个功能</p> *
* @param response HttpServletResponse
* @param exportList 输出到Excel表格list
*/
public void create(HttpServletResponse response, List<T> exportList);
/**
* 初始化Excel报表标题
*
* @return 报表标题
*/
public String initTitle();
/**
* 初始化Excel文件名称
*
* @return
*/
public String initFileName();
/**
* 初始化Excel Sheet名称
*
* @return
*/
public String initSheetName();
/**
* 获得报表列头标题
*
* 1、如果是一行列头标题,则可以通过如下代码实现:
* String[][] colTitles = { { "列1", "列2", "列3" } }
* return colTitles;
* 2、如果是二行列头标题,则可以通过如下代码实现:
* String[][] colTitles = { { "行1列1", "行1列2", null, "行1列4" },
* { null, "行2列2", "行2列3", "行2列4" }};
* return colTitles;
* 将显示的列标题实际效果为:
* <table border="1">
* <tr align="center">
* <td rowspan="2">行1列1</td>
* <td colspan="2">行1列2</td>
* <td>行1列4</td>
* </tr>
* <tr align="center">
* <td>行2列2</td>
* <td>行2列3</td>
* <td>行2列4</td>
* </tr>
* </table>
* @return 列头标题
*/
public String[][] initColTitles();
/**
* 处理Excel报表展示的数据
*
* @param exportList 输出到Excel list集合
* @return 1、列表,List(String[]);
* 2、有合并一列的数据,Map(List(String[]));
* 3、有合并两列的数据,Map(Map(List(String[])))。
*/
public Object handleBodyData(List<T> exportList);
/**
* 初始化Excel报表展示的样式
*
* @return 列表,Map(int,String );
*/
public Object initRowStyle();
/**
* 初始化Excel列宽
*
* @return 列宽
*/
public int[] initColumnWidth();
/**
* 初始化Excel报表备注信息
*
* @return 报表备注信息
*/
public String[] initRemark();
}
二、抽象实现
package com.hqb360.common.excel;
import com.google.common.collect.Maps;
import com.hqb360.common.lang.ArrayUtil;
import com.hqb360.common.lang.DateUtil;
import com.hqb360.common.lang.StringUtil;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 功能描述:创建Excel抽象实现
*
* @author: Zhenbin.Li
* Date: 13-11-19 Time:下午12:44
*/
public abstract class DefaultExportExcelAdapter<T> implements ExportExcelAware<T> {
/**
* 文件下载的header key
*/
private static final String RESOURCE_HEADER_KEY = "Content-Disposition";
/**
* 文件下载的contentType
*/
private static final String RESOURCE_CONTENT_TYPE = "application/octet-stream;charset=UTF-8";
/**
* Excel Sheet默认名称
*/
private static final String DEFAULT_SHEET_NAME = "sheet";
/**
* 生成Excel文件Session
*/
private Map<SessionKey, Object> exportSession = Maps.newHashMap();
@Override
public synchronized void create(HttpServletResponse response, List<T> exportList) {
// 初始化Session
initSession(response, exportList);
// 验证必要参数
validExportSession();
String sheetName = exportSession.get(SessionKey.SHEET_NAME) == null ?
DEFAULT_SHEET_NAME : (String) exportSession.get(SessionKey.SHEET_NAME);
ExportExcelFactory exportExcelFactory = new ExportExcelFactory(sheetName);
// 表格名称
StringBuffer titleBuffer = new StringBuffer();
titleBuffer.append(exportSession.get(SessionKey.TITLE)).append("(导出时间:")
.append(DateUtil.formatDateTime()).append(")");
//列头标题
String[][] colTitles = (String[][]) exportSession.get(SessionKey.COL_TITLES);
exportExcelFactory.setCols(colTitles[0].length);
exportExcelFactory.createCaption(titleBuffer.toString());
exportExcelFactory.createColCaption(colTitles);
Object bodyData = exportSession.get(SessionKey.BODY_DATA);
if (bodyData != null) {
Object rowColor = exportSession.get(SessionKey.ROW_COLOR);
if (rowColor == null) {
exportExcelFactory.createBody(bodyData);
} else {
exportExcelFactory.createBody(bodyData, rowColor);
}
}
if (exportSession.get(SessionKey.COLUMN_WIDTH) != null) {
int[] columnWidths = (int[]) exportSession.get(SessionKey.COLUMN_WIDTH);
if (ArrayUtil.isNotEmpty(columnWidths)) {
exportExcelFactory.setColumnWidth(columnWidths);
}
}
if (exportSession.get(SessionKey.REMARKS) != null) {
String[] remarks = (String[]) exportSession.get(SessionKey.REMARKS);
if (ArrayUtil.isEmpty(remarks)) {
exportExcelFactory.createRemarks(remarks);
}
}
String excelFileName = initFileName() + ".xls";
try {
excelFileName = new String(excelFileName.getBytes("GBK"),"ISO-8859-1");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("导出Excel业务, encode文件名称异常, excelFileName=" + excelFileName, e);
}
// 写文件
OutputStream os = null;
response.reset();
// 写入下载响应头信息
writeDownloadResHeader(excelFileName, response);
try {
os = response.getOutputStream();
exportExcelFactory.createFile(response.getOutputStream());
} catch (IOException e) {
throw new RuntimeException("导出Excel业务, 生成Excel文件异常", e);
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
}
}
}
}
/**
* Excel标题,继承时必须要实现
*
* @return
*/
@Override
public abstract String initTitle();
/**
* 获取导出Excel文件名称
*
* @return
*/
@Override
public String initFileName() {
StringBuffer fileName = new StringBuffer();
fileName.append(initTitle()).append("(").append(DateUtil.format(new Date(), "yyyyMMddHHmmss")).append(")");
return fileName.toString();
}
@Override
public String initSheetName() {
return "sheet";
}
/**
* Excel列属性值,继承时必须要实现
*
* @return
*/
@Override
public abstract String[][] initColTitles();
/**
* 必须要传入值
*
* @return
*/
@Override
public abstract Object handleBodyData(List<T> exportList);
/**
* 设置单元格样式
*
* @return
*/
@Override
public Object initRowStyle() {
return null;
}
@Override
public int[] initColumnWidth() {
return null;
}
/**
* 导出Excel有无备注信息
*
* @return
*/
@Override
public String[] initRemark() {
return null;
}
/**
* 写入下载响应头信息
* <p>声明响应类型和内容类型</p>
*
* @param fileName 文件名
* @param response HTTP响应
*/
protected static void writeDownloadResHeader(String fileName, HttpServletResponse response) {
response.addHeader(RESOURCE_HEADER_KEY, "attachment; filename=" + fileName);
response.setContentType(RESOURCE_CONTENT_TYPE);
}
/**
* Excel文件Session属性值枚举
*/
protected enum SessionKey {
RESPONSE,
BODY_DATA,
TITLE,
FILE_NAME,
COL_TITLES,
ROW_COLOR,
REMARKS,
COLUMN_WIDTH,
SHEET_NAME
}
/**
* 初始化生成Excel SessionKey
*
* @param response
* @param exportList
*/
protected void initSession(HttpServletResponse response, List exportList) {
exportSession.put(SessionKey.RESPONSE, response);
//报表数据
exportSession.put(SessionKey.BODY_DATA, handleBodyData(exportList));
// 报表标题
exportSession.put(SessionKey.TITLE, initTitle());
// 文件名称
exportSession.put(SessionKey.FILE_NAME, initFileName());
// 列名称
exportSession.put(SessionKey.COL_TITLES, initColTitles());
// 行颜色
exportSession.put(SessionKey.ROW_COLOR, initRowStyle());
// 备注
exportSession.put(SessionKey.REMARKS, initRemark());
// 列宽度
exportSession.put(SessionKey.COLUMN_WIDTH, initColumnWidth());
// Sheet名称
exportSession.put(SessionKey.SHEET_NAME, initSheetName());
}
/**
* 验证Session参数
*/
protected void validExportSession() {
if (exportSession.get(SessionKey.TITLE) == null
|| StringUtil.isBlank(String.valueOf(exportSession.get(SessionKey.TITLE)))) {
throw new RuntimeException("导出Excel业务, Excel表名称为空");
}
if (exportSession.get(SessionKey.FILE_NAME) == null
|| StringUtil.isBlank(String.valueOf(exportSession.get(SessionKey.FILE_NAME)))) {
throw new RuntimeException("导出Excel业务, Excel文件名称为空");
}
if (exportSession.get(SessionKey.COL_TITLES) == null
|| ArrayUtil.isEmpty((String[][]) exportSession.get(SessionKey.COL_TITLES))) {
throw new RuntimeException("导出Excel业务, Excel列属性名称为空");
}
}
}
三、测试实现方法,只需要实现抽象方法即可
/**
* 导出库存列表
*
* @param response
* @return
*/
@RequestMapping(value = "/invoicing/itemSkusWarehouse/exportItemSkusWarehouse.resource",
method = RequestMethod.GET)
public String exportItemSkusWarehouse(HttpServletResponse response) {
final List<ItemSkuWarehouseExportDo> list = itemSkusWarehouseQueryBiz
.findItemSkuWarehouseStatisticsForExport().getItemSkuWarehouseExportDos();
new DefaultExportExcelAdapter<ItemSkuWarehouseExportDo>() {
@Override
public String initTitle() {
return "库存列表";
}
@Override
public String[][] initColTitles() {
String[][] colTitles = {{"所属类目", "SKU ID", "SKU名称", "良品库", "申购库", "次品库", "赠品库", "寄存库", "成本价", "合计"}};
return colTitles;
}
@Override
public Object handleBodyData(List<ItemSkuWarehouseExportDo> exportList) {
List<String[]> exports = Lists.newArrayList();
if (CollectionUtil.isNotEmpty(exportList)) {
for (ItemSkuWarehouseExportDo itemSkuWarehouseExportDo : exportList) {
String[] itemSkuWarehouseExportDoArray = new String[initColTitles()[0].length];
itemSkuWarehouseExportDoArray[0] = itemSkuWarehouseExportDo.getBelongCatName();
itemSkuWarehouseExportDoArray[1] = itemSkuWarehouseExportDo.getSkuId().toString();
itemSkuWarehouseExportDoArray[2] = itemSkuWarehouseExportDo.getSkuName();
itemSkuWarehouseExportDoArray[3] = itemSkuWarehouseExportDo.getStandardWarehouse().toString();
itemSkuWarehouseExportDoArray[4] = itemSkuWarehouseExportDo.getApWarehouse().toString();
itemSkuWarehouseExportDoArray[5] = itemSkuWarehouseExportDo.getSubstandardWarehouse().toString();
itemSkuWarehouseExportDoArray[6] = itemSkuWarehouseExportDo.getDonationWarehouse().toString();
itemSkuWarehouseExportDoArray[7] = itemSkuWarehouseExportDo.getRegisterWarehouse().toString();
itemSkuWarehouseExportDoArray[8] = NumberFormatUtil.formatForIgnoreZero(itemSkuWarehouseExportDo.getCostPrice() , 5);
itemSkuWarehouseExportDoArray[9] = itemSkuWarehouseExportDo.getCountWarehouse().toString();
exports.add(itemSkuWarehouseExportDoArray);
}
}
return exports;
}
@Override
public String initSheetName() {
return "库存列表";
}
@Override
public int[] initColumnWidth() {
int[] columnWidths = {150, 100, 500, 0, 0, 0, 0, 0, 0, 0};
return columnWidths;
}
}.create(response, list);
return null;
}
四、生成Excel工厂实现
package com.hqb360.common.lang.excel;
import com.hqb360.common.lang.StringUtil;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
/**
* 功能描述:生成Excel工厂类
*
* @author: Zhenbin.Li
* Date: 13-11-17 Time:上午10:04
*/
public class ExportExcelFactory {
/** 工作薄 */
private HSSFWorkbook workbook;
/** 工作表 */
private HSSFSheet sheet;
/** 当前行数 */
private int currentRow = 0;
/** 总列数 */
private int totalCols;
/** Excel Sheet名称 */
private final String sheetName;
/**
* 默认构造方法
*/
public ExportExcelFactory(String sheetName) {
this.sheetName = sheetName;
workbook = new HSSFWorkbook();
sheet = workbook.createSheet(getSheetName());
}
/**
* 设置列宽
*
* @param columnWidth 列宽信息
*/
@SuppressWarnings("deprecation")
public void setColumnWidth(int[] columnWidth) {
for (int i = 0; i < columnWidth.length; i++) {
if (columnWidth[i] != 0) {
if (sheet.getColumnWidth((short) i) != (columnWidth[i] * 37.5)) {
sheet.setColumnWidth((short) i, (short) (columnWidth[i] * 37.5));
}
}
}
}
/**
* 设置列数
*
* @param cols 列数
*/
public void setCols(int cols) {
this.totalCols = cols;
}
/**
* 创建标题
*
* @param caption 标题
*/
public void createCaption(String caption) {
HSSFFont font = ExportExcelUtil.getFont(workbook, 10, HSSFFont.BOLDWEIGHT_BOLD, HSSFColor.BLACK.index);
HSSFCellStyle style = ExportExcelUtil.getStyle(workbook, font, HSSFCellStyle.ALIGN_CENTER);
HSSFRow row = sheet.createRow(currentRow);
ExportExcelUtil.createCell(row, 0, style, caption);
for (int i = 1; i < totalCols; i++) {
ExportExcelUtil.createCell(row, i, style, "");
}
ExportExcelUtil.mergeCol(sheet, 0, totalCols - 1, currentRow);
currentRow++;
}
/**
* 创建一行列标题
*
* @param colCaption 一行列标题
*/
public void createColCaption(String[] colCaption) {
HSSFFont font = ExportExcelUtil.getFont(workbook, 0, HSSFFont.BOLDWEIGHT_BOLD, HSSFColor.BLACK.index);
HSSFCellStyle style = ExportExcelUtil.getStyle(workbook, font, HSSFCellStyle.ALIGN_CENTER);
HSSFRow row = sheet.createRow(currentRow);
for (int i = 0; i < colCaption.length; i++) {
ExportExcelUtil.createCell(row, i, style, colCaption[i]);
}
currentRow++;
}
/**
* 创建多行列标题
*
* @param colCaption 多行列标题
*/
public void createColCaption(String[][] colCaption) {
HSSFFont font = ExportExcelUtil.getFont(workbook, 10, HSSFFont.BOLDWEIGHT_BOLD, HSSFColor.BLACK.index);
HSSFCellStyle style = ExportExcelUtil.getStyle(workbook, font, HSSFCellStyle.ALIGN_CENTER);
int[][][] spans = getSpans(colCaption);
for (int i = 0; i < colCaption.length; i++) {
HSSFRow row = sheet.createRow(currentRow);
for (int j = 0; j < colCaption[i].length; j++) {
ExportExcelUtil.createCell(row, j, style, colCaption[i][j]);
if (spans[i][j] != null) {
ExportExcelUtil
.mergeRegion(sheet, currentRow, j, currentRow + spans[i][j][0] - 1, j + spans[i][j][1] - 1);
}
}
currentRow++;
}
}
/**
* 创建EXCEL的主体数据
*
* @param data 主体数据,可支持的数据格式有:
* 1、简单列表 List(String[]);
* 2、合并一列 Map(List(String[]));
* 3、合并二列 Map(Map(List(String[]))。
*/
@SuppressWarnings("rawtypes")
public void createBody(Object data) {
int nestedCount = ExportExcelUtil.getNestedCount(data);
if (nestedCount == 0) {
createBody((List<String[]>)data);
} else if (nestedCount == 1) {
ExportExcelUtil.createOneMapBody(workbook, sheet, (Map) data, currentRow);
} else if (nestedCount == 2) {
ExportExcelUtil.createTwoMapBody(workbook, sheet, (Map) data, currentRow);
} else {
throw new IllegalArgumentException("不支持的数据格式");
}
}
/**
* 创建列表的主体数据
*
* @param list List(String[])列表数据
*/
protected void createBody(List<String[]> list) {
HSSFFont font = ExportExcelUtil.getFont(workbook, 10, HSSFFont.BOLDWEIGHT_NORMAL, HSSFColor.BLACK.index);
HSSFCellStyle style = ExportExcelUtil.getStyle(workbook, font, HSSFCellStyle.ALIGN_CENTER);
for (int index = 0; index < list.size(); index++) {
HSSFRow row = sheet.createRow(currentRow);
String[] stringArray = list.get(index);
for (int j = 0; j < stringArray.length; j++) {
ExportExcelUtil.createCell(row, j, style, stringArray[j]);
}
currentRow++;
}
}
/**
* 创建EXCEL的主体数据
*
* @param data 主体数据,可支持的数据格式有:
* 1、简单列表 List(String[]);
* 2、合并一列 Map(List(String[]));
* 3、合并二列 Map(Map(List(String[]))。
*/
@SuppressWarnings("rawtypes")
public void createBody(Object data, Object color) {
int nestedCount = ExportExcelUtil.getNestedCount(data);
if (nestedCount == 0) {
ExportExcelUtil.createBodyColor(workbook, sheet, (List) data, (Map) color, currentRow);
} else if (nestedCount == 1) {
ExportExcelUtil.createOneMapBody(workbook, sheet, (Map) data, currentRow);
} else if (nestedCount == 2) {
ExportExcelUtil.createTwoMapBody(workbook, sheet, (Map) data, currentRow);
} else {
throw new IllegalArgumentException("不支持的数据格式");
}
}
/**
* 创建备注信息
*
* @param remarks 备注信息
*/
public void createRemarks(String[] remarks) {
HSSFFont font = ExportExcelUtil.getFont(workbook, 10, HSSFFont.BOLDWEIGHT_NORMAL, HSSFColor.RED.index);
HSSFCellStyle style = ExportExcelUtil.getStyle(workbook, font, HSSFCellStyle.ALIGN_LEFT);
for (int i = 0; i < remarks.length; i++) {
HSSFRow row = sheet.createRow(currentRow);
ExportExcelUtil.createCell(row, 0, style, remarks[i]);
for (int j = 1; j < totalCols; j++) {
ExportExcelUtil.createCell(row, j, style, "");
}
ExportExcelUtil.mergeCol(sheet, 0, totalCols - 1, currentRow);
currentRow++;
}
}
/**
* 创建本地路径的EXCEL文件
*
* @param filePath EXCEL文件路径
*/
public void createFile(String filePath) {
FileOutputStream out = null;
try {
out = new FileOutputStream(filePath);
workbook.write(out);
} catch (FileNotFoundException e) {
throw new RuntimeException("无法创建文件:" + filePath);
} catch (IOException e) {
throw new RuntimeException("无法写入文件:" + filePath);
} finally {
ExportExcelUtil.closeOutputStream(out);
}
}
/**
* 把EXCEL文件写入到输出流中
*
* @param out 输出流
* @throws java.io.IOException
*/
public void createFile(OutputStream out) throws IOException {
workbook.write(out);
}
/**
* 根据多行报表标题获得一个合并的行列信息
*
* @param colTitles 列标题
* @return 报表标题合并的行列信息:第一维对应标题的行,第二维对应标题的列,
* 第三维对应标题的合并行和列,已经被合并的行或列则对应的第三维为null。
*/
public static int[][][] getSpans(String[][] colTitles) {
int[][][] spans = new int[colTitles.length][][];
for (int i = 0; i < colTitles.length; i++) {
spans[i] = new int[colTitles[i].length][];
for (int j = 0; j < colTitles[i].length; j++) {
if (colTitles[i][j] != null) {
spans[i][j] = new int[2];
spans[i][j][0] = ExportExcelUtil.getRowSpan(colTitles, i, j);
spans[i][j][1] = ExportExcelUtil.getColSpan(colTitles, i, j);
}
}
}
return spans;
}
/**
* 获取Excel Sheet名称
*
* @return
*/
public String getSheetName() {
return sheetName;
}
}
package com.hqb360.common.lang.excel;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
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.hssf.util.HSSFColor;
import org.apache.poi.hssf.util.Region;
/**
* 功能描述: ExportExcelFactory.java类抽取其方法工具类
*
* @author: Zhenbin.Li
* Date: 13-11-17 Time:上午10:20
*/
@SuppressWarnings("deprecation")
public class ExportExcelUtil {
/**
* 创建列表的主体数据
*
* @param workbook
* @param list List(String[])列表数据
* @param color
* @param sheet
* @param currentRow
*/
@SuppressWarnings("rawtypes")
protected static void createBodyColor(HSSFWorkbook workbook, HSSFSheet sheet,
List list, Map color, int currentRow) {
HSSFFont font_black = getFont(workbook, 10, HSSFFont.BOLDWEIGHT_NORMAL, HSSFColor.BLACK.index);
HSSFCellStyle style_black = getStyle(workbook, font_black, HSSFCellStyle.ALIGN_CENTER);
HSSFFont font_red = getFont(workbook, 10, HSSFFont.BOLDWEIGHT_NORMAL, HSSFColor.RED.index);
HSSFCellStyle style_red = getStyle(workbook, font_red, HSSFCellStyle.ALIGN_CENTER);
HSSFFont font_green = getFont(workbook, 10, HSSFFont.BOLDWEIGHT_NORMAL, HSSFColor.GREEN.index);
HSSFCellStyle style_green = getStyle(workbook, font_green, HSSFCellStyle.ALIGN_CENTER);
for (int index = 0; index < list.size(); index++) {
String rowColor = (String) color.get(index);
HSSFRow row = sheet.createRow(currentRow);
String[] stringArray = (String[]) list.get(index);
for (int j = 0; j < stringArray.length; j++) {
if (rowColor != null) {
if (rowColor.equals("RED")) {
createCell(row, j, style_red, stringArray[j]);
} else if (rowColor.equals("GREEN")) {
createCell(row, j, style_green, stringArray[j]);
} else {
createCell(row, j, style_black, stringArray[j]);
}
} else {
createCell(row, j, style_black, stringArray[j]);
}
}
currentRow++;
}
}
/**
* 创建合并一列的主体数据
*
* @param map Map(List(String[])) 嵌套一层的Map数据
* @param sheet
* @param currentRow
*/
@SuppressWarnings("rawtypes")
protected static void createOneMapBody(HSSFWorkbook workbook, HSSFSheet sheet, Map map, int currentRow) {
HSSFFont font = getFont(workbook, 10, HSSFFont.BOLDWEIGHT_NORMAL, HSSFColor.BLACK.index);
HSSFCellStyle style = getStyle(workbook, font, HSSFCellStyle.ALIGN_CENTER);
for (Iterator it = map.keySet().iterator(); it.hasNext(); ) {
String key = (String) it.next();
List list = (List) map.get(key);
int size = list.size();
mergeRow(sheet, currentRow, currentRow + size - 1, 0);
for (int i = 0; i < size; i++) {
HSSFRow row = sheet.createRow(currentRow);
createCell(row, 0, style, key);
String[] stringArray = (String[]) list.get(i);
for (int j = 0; j < stringArray.length; j++) {
createCell(row, j + 1, style, stringArray[j]);
}
currentRow++;
}
}
}
/**
* 创建合并二列的主体数据
*
* @param map Map(Map(List(String[]))) 嵌套二层的Map数据
* @param sheet
* @param currentRow
*/
@SuppressWarnings("rawtypes")
protected static void createTwoMapBody(HSSFWorkbook workbook, HSSFSheet sheet, Map map, int currentRow) {
HSSFFont font = getFont(workbook, 10, HSSFFont.BOLDWEIGHT_NORMAL, HSSFColor.BLACK.index);
HSSFCellStyle style = getStyle(workbook, font, HSSFCellStyle.ALIGN_CENTER);
//第一列的合并行数
int[] rowSpans = getRowSpanOfTwoMap(map);
int rowCount = 0;
for (Iterator iterator = map.keySet().iterator(); iterator.hasNext(); rowCount++) {
String key1 = (String) iterator.next();
Map map1 = (Map) map.get(key1);
mergeRow(sheet, currentRow, currentRow + rowSpans[rowCount] - 1, 0);
for (Iterator it2 = map1.keySet().iterator(); it2.hasNext(); ) {
String key2 = (String) it2.next();
List list = (List) map1.get(key2);
int size = list.size();
mergeRow(sheet, currentRow, currentRow + size - 1, 1);
for (int i = 0; i < size; i++) {
HSSFRow row = sheet.createRow(currentRow);
createCell(row, 0, style, key1);
createCell(row, 1, style, key2);
String[] stringArray = (String[]) list.get(i);
for (int j = 0; j < stringArray.length; j++) {
createCell(row, j + 2, style, stringArray[j]);
}
currentRow++;
}
}
}
}
/**
* 创建单元格
*
* @param row 行对象
* @param index 在行中创建单元格的位置,从0开始。
* @param style 单元格样式
* @param value 单元格的值
*/
protected static void createCell(HSSFRow row, int index, HSSFCellStyle style, String value) {
HSSFCell cell = row.createCell((short) index);
//cell.setEncoding(HSSFCell.ENCODING_UTF_16);
cell.setCellStyle(style);
cell.setCellValue(value);
}
/**
* 合并行
*
* @param sheet
* @param startRow 起始行(从0开始)
* @param endRow 结束行(从0开始)
* @param col 列位置(从0开始)
*/
protected static void mergeRow(HSSFSheet sheet, int startRow, int endRow, int col) {
sheet.addMergedRegion(new Region(startRow, (short) col, endRow, (short) col));
}
/**
* 合并列
*
* @param sheet
* @param startCol 起始列(从0开始)
* @param endCol 结束列(从0开始)
* @param row 行位置(从0开始)
*/
protected static void mergeCol(HSSFSheet sheet, int startCol, int endCol, int row) {
sheet.addMergedRegion(new Region(row, (short) startCol, row, (short) endCol));
}
/**
* 合并区域
*
* @param sheet
* @param startRow 起始行(从0开始)
* @param startCol 起始列(从0开始)
* @param endRow 结束行(从0开始)
* @param endCol 结束列(从0开始)
*/
protected static void mergeRegion(HSSFSheet sheet, int startRow, int startCol, int endRow, int endCol) {
sheet.addMergedRegion(new Region(startRow, (short) startCol, endRow, (short) endCol));
}
/**
* 关闭输出流
*
* @param out 输出流
*/
protected static void closeOutputStream(OutputStream out) {
if (out != null) {
try {
out.close();
} catch (IOException e) {
}
}
}
/**
* 根据字体高度和字体类型获得字体对象
*
* @param fontHeight 字体高度
* @param boldweight 字体类型
* @param color 字体颜色
* @return 字体对象
*/
protected static HSSFFont getFont(HSSFWorkbook workbook, int fontHeight, short boldweight, short color) {
HSSFFont font = workbook.createFont();
font.setFontHeightInPoints((short) fontHeight);
font.setFontName("新宋体");
font.setColor(color);
font.setBoldweight(boldweight);
return font;
}
/**
* 根据字体和对其方式获得单元格样式
*
* @param font 字体
* @param align 对其方式
* @return 单元格样式
*/
protected static HSSFCellStyle getStyle(HSSFWorkbook workbook, HSSFFont font, short align) {
HSSFCellStyle style = workbook.createCellStyle();
style.setFont(font);
//边框
style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
style.setBottomBorderColor(HSSFColor.BLACK.index);
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style.setLeftBorderColor(HSSFColor.BLACK.index);
style.setBorderRight(HSSFCellStyle.BORDER_THIN);
style.setRightBorderColor(HSSFColor.BLACK.index);
style.setBorderTop(HSSFCellStyle.BORDER_THIN);
style.setTopBorderColor(HSSFColor.BLACK.index);
//对齐方式
style.setAlignment(align);
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
return style;
}
/**
* 获得报表标题在某行某列的行跨度
*
* @param colTitles 报表列标题
* @param row 行
* @param col 列
* @return 行跨度
*/
protected static int getRowSpan(String[][] colTitles, int row, int col) {
int rowSpan = 1;
if (colTitles[row][col] != null) {
for (int i = row + 1; i < colTitles.length; i++) {
if (colTitles[i][col] == null) {
rowSpan++;
} else {
break;
}
}
}
return rowSpan;
}
/**
* 获得报表标题在某行某列的列跨度
*
* @param colTitles 报表列标题
* @param row 行
* @param col 列
* @return 列跨度
*/
protected static int getColSpan(String[][] colTitles, int row, int col) {
int colSpan = 1;
if (colTitles[row][col] != null) {
for (int i = col + 1; i < colTitles[row].length; i++) {
if (colTitles[row][i] == null) {
if (row == 0) {
colSpan++;
} else if (colTitles[row - 1][i] == null) {
colSpan++;
} else {
break;
}
} else {
break;
}
}
}
return colSpan;
}
/**
* 获得Map或List数据的嵌套层次数。
*
* @param obj Map 或 List
* @return 如果参数为null则返回-1;
* 如果参数为List则返回0;
* 如果为一层Map(Map中value为List)则返回1;
* 如果为二层Map(Map中value为Map,再深层为List,则返回2;
* ......
*/
@SuppressWarnings("rawtypes")
protected static int getNestedCount(Object obj) {
if (obj == null) {
return -1;
} else if (obj instanceof List) {
return 0;
} else if (obj instanceof Map) {
Map map = (Map) obj;
if (map.size() > 0) {
Object o = map.get(map.keySet().iterator().next());
return getNestedCount(o) + 1;
} else {
return 1;
}
}
throw new IllegalArgumentException("参数不为List或Map");
}
/**
* 获得两层嵌套Map的针对报表的第一列合并行情况
*
* @param map Map(Map(List))两层嵌套Map
* @return 对应报表的第一列合并行情况
*/
@SuppressWarnings({ "rawtypes", "unused" })
protected static int[] getRowSpanOfTwoMap(Map map) {
int[] spans = new int[map.size()];
Iterator it = map.keySet().iterator();
for (int i = 0; it.hasNext(); i++) {
Object key = it.next();
Map map2 = (Map) map.get(key);
Iterator it2 = map2.keySet().iterator();
for (int i2 = 0; it2.hasNext(); i2++) {
Object key2 = it2.next();
List list = (List) map2.get(key2);
spans[i] += list.size();
}
}
return spans;
}
}