电商商务,目前为止,做网站后台管理系统对到处数据的要求不是很高,反正自己公司内部用的嘛,能拉出来就行了,尽量简单。但是随着业务的发展,供应链系统出来了,涉及到订单,采购,库存,退款退货,财务等模块的集成。系统的生成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; } }
相关推荐
在“使用POI向Excel模板动态添加内容”时,我们通常会有一个预先设计好的Excel模板,这个模板包含了固定格式和一些占位符。我们的任务就是通过编程方式找到这些占位符,并用实际数据替换它们。这一过程可以极大地...
- 使用POI创建`Workbook`对象,然后添加`Sheet`,接着为每个实体对象创建一行数据(`Row`)并填充单元格(`Cell`)。 - 如果使用反射,可以遍历实体类的所有字段,动态生成Excel列头并设置数据。 - 将工作簿写入...
在封装POI操作Excel的过程中,反射可能被用来动态地创建对象,调用方法,或访问私有成员,这使得代码更具灵活性和可扩展性。例如,可以使用反射动态地根据Excel工作表的列名创建对应的Java对象属性,或者在不知道...
POI-excel 导出样式设计 POI(Apache POI)是一款 Java 库,用于读取和写入 Microsoft Office 文件格式,包括 Excel、Word 和 PowerPoint。POI-excel 是 POI 中处理 Excel 文件的部分,本文将介绍 POI-excel 的一些...
"基于POI的Excel多Sheet页导出导入工具类"是一个实用的Java类库,专为处理Excel文件中的多个工作表(Sheet)而设计,提供了一种高效且灵活的方式来操作Excel数据。 该工具类的核心功能包括: 1. **多Sheet页操作**...
- 图表和图像:如果需要,可以使用POI创建图表或者嵌入图片。 - 多线程:对于大规模数据,可以考虑使用多线程并行处理。 总之,Apache POI提供了一套强大的工具集,让Java开发者能够方便地与Excel文件交互。了解和...
Apache POI 是一个开源项目,专门用于处理Microsoft Office格式的文件,包括Excel、Word和PowerPoint等。在Java环境中,Apache POI 提供了API来读取、创建和修改这些文件。在这个“poi 解析excel实例”中,我们主要...
使用POI创建Excel文件时,首先需要创建`Workbook`对象。对于Excel 2003,使用`HSSFWorkbook`;对于Excel 2007,使用`XSSFWorkbook`。接着,可以创建`Sheet`对象表示工作表,再创建`Row`对象表示行,最后创建`Cell`...
3. **使用Apache POI创建Excel工作簿**:在Java代码中,导入必要的POI库,然后创建一个HSSFWorkbook对象(对于老版本的XLS格式)或XSSFWorkbook对象(对于新版本的XLSX格式)。这将是我们的Excel文件的容器。 4. **...
根据提供的文件信息,可以看出文档主要阐述了如何使用Apache POI技术解析2003-2007版本的Excel文档,并将解析后的数据导入到MySQL数据库中。文档中分别涉及到Java实体类的设计(User.java),以及数据访问层的设计...
最后,`poi-excelant-3.15-beta1.jar`是为了支持Apache Ant构建工具而设计的,它允许你在Ant脚本中直接使用POI进行Excel文件的处理。 使用POI导出Excel的基本步骤如下: 1. 创建`Workbook`对象,这代表一个Excel...
在Java开发中,Apache POI库是一个非常实用的工具,用于读取、写入和修改Microsoft Office格式的文件,特别是Excel。本篇文章主要探讨如何利用POI在Excel单元格中添加超链接,并设置字体颜色。 首先,为了使用...
- 使用POI创建一个新的Excel文件,将List数据写入工作表中。 - 设置响应头,返回生成的Excel文件供用户下载。 在实际开发中,可能还需要考虑错误处理、文件上传大小限制、并发性能等问题。以上就是关于"poi操作...
二、创建Excel模板 1. 模板设计:在Excel中创建模板,设置好需要动态填充的数据区域,如单元格样式、公式、条件格式等。 2. 保存模板:将模板文件保存为.xlsx格式,以便于POI读取。 三、使用POI读取模板并填充数据 ...
这样,我们就可以避免繁琐的Excel编程,只需关注数据和模板的设计。 在描述中提到的"读取json转为excel文件导出",这正是`jxls`的一个典型应用场景。我们通常会有一个JSON数据源,它包含我们需要导出到Excel的数据...
例如,使用Apache POI创建一个Excel文件: ```java import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.FileOutputStream; import java.io.IOException; ...
这需要先执行SQL查询,获取需要的数据集,然后使用POI创建一个新的Excel工作簿和工作表,将数据逐条写入工作表的单元格。完成后,可以将工作簿写入到响应流,供用户下载。 在实际应用中,我们还需要考虑一些其他...
2. HSSF与XSSF:在POI中,HSSF用于处理老版本的二进制XLS文件,而XSSF则专为XML结构的XLSX文件设计。这两种模型提供了类似的接口,使得代码在不同格式之间切换变得更加容易。 二、读取Excel文件 1. 创建Workbook...
这使得我们可以通过解析XML来操作Excel内容,而POI库正是为此设计的。SAX(Simple API for XML)是一种基于事件驱动的XML解析方法,它在内存中不加载整个XML文档,而是逐个处理XML事件,如开始元素、结束元素、文本...
在Android开发中,Apache POI 是一个非常实用的库,它允许程序员创建、修改和显示Microsoft Office格式的文件,如Word文档(.doc)和Excel工作簿(.xlsx或.xls)。这个工具对于需要在Android应用中处理这些文档的...