poi导出动态行动态列_excel工具类 java–poi 生成excel动态合并内容相同的行+水平垂直居中+大标题 浏览器直接下载...

这是一个Java使用Apache POI库动态合并Excel内容的工具类,支持水平垂直居中和大标题,允许在浏览器中直接下载。通过传入标题、数据Map、合并列索引、文件名和Http响应头来创建Excel。
摘要由CSDN通过智能技术生成

import lombok.Builder;

import lombok.Data;

import org.apache.poi.hssf.usermodel.*;

import org.apache.poi.ss.usermodel.CellType;

import org.apache.poi.ss.usermodel.HorizontalAlignment;

import org.apache.poi.ss.usermodel.VerticalAlignment;

import org.apache.poi.ss.usermodel.Workbook;

import org.apache.poi.ss.util.CellRangeAddress;

import javax.servlet.http.HttpServletResponse;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.OutputStream;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

/**

* @description: java–poi生成excel动态合并内容相同的行+水平垂直居中+大标题 浏览器直接下载

* @author: Dai Yuanchuan

* @create: 2019-03-24 14:38

**/

public class ExcelUtil {

/**

* 工具类主入口

*

* @param title excel 头

* @param maps Map>>

* @param mergeIndex 需要合并的列的下标组成的int数组

* @param fileName 文件名

* @param response 响应头

* @return

*/

public static void createExcel(String[] title, Map>> maps,

int[] mergeIndex, String fileName, HttpServletResponse response) {

// 初始化excel模板

HSSFWorkbook workbook = new HSSFWorkbook();

HSSFSheet sheet = null;

int n = 0;

/**

* 循环sheet页

* List>>

*/

for (Map.Entry>> entry : maps.entrySet()) {

// 实例化sheet对象并且设置sheet名称,book对象

try {

sheet = workbook.createSheet();

workbook.setSelectedTab(0);

} catch (Exception e) {

e.printStackTrace();

}

// 初始化头部

HSSFCellStyle cellStyle1 = initExcelHead(sheet, workbook, n, entry, fileName, title);

// 得到当前sheet下的数据集合 List>

List> list = entry.getValue();

// 遍历该数据集合

List poiModels = new ArrayList<>();

if (null != workbook) {

Iterator iterator = list.iterator();

// 这里1是从excel的第三行开始,第一二行已经塞入标题了

int index = 2;

while (iterator.hasNext()) {

HSSFRow row = sheet.createRow(index);

// 设置单元格的高

row.setHeightInPoints(43);

// 取得当前这行的map,该map中以key,value的形式存着这一行值

Map map = (Map) iterator.next();

// 循环列数,给当前行塞值

currentRowAssignment(title, index, poiModels, mergeIndex, map, sheet, cellStyle1, row, list);

index++;

}

}

n++;

}

//直接从浏览器下载

setExportHTTPResponse(workbook, fileName, response);

}

/**

* 合并单元格

*

* @param poiModels

* @param i

* @param index

* @param sheet

* @param map

* @param title

*/

private static void merge(List poiModels, int i, int index,

HSSFSheet sheet, Map map, String[] title) {

/**

* 当前行的当前列与上一行的当前列的内容不一致时,则把当前行以上的合并

* 参数1: 从第二行开始,

* 参数2: 到第几行,

* 参数3: 从某一列开始,

* 参数4: 到第几列

*/

CellRangeAddress cra = new CellRangeAddress(poiModels.get(i).getRowIndex(), index - 1,

poiModels.get(i).getCellIndex(), poiModels.get(i).getCellIndex());

//在sheet里增加合并单元格

sheet.addMergedRegion(cra);

/*重新记录该列的内容为当前内容,行标记改为当前行标记*/

poiModels.get(i).setContent(map.get(title[i]).toString());

poiModels.get(i).setRowIndex(index);

poiModels.get(i).setCellIndex(i);

}

/**

* 设置导出的HTTP响应头

*

* @param workbook 最终需要导出的excel数据

* @param fileName 导出的文件名

* @param response 导出的响应头

*/

private static void setExportHTTPResponse(Workbook workbook, String fileName, HttpServletResponse response) {

if (workbook != null) {

ByteArrayOutputStream byteArrayOutputStream = null;

try {

byteArrayOutputStream = new ByteArrayOutputStream();

workbook.write(byteArrayOutputStream);

String suffix = ".xls";

response.setContentType("application/vnd.ms-excel;charset=utf-8");

response.setHeader("Content-Disposition",

"attachment;filename=" + new String((fileName + suffix).getBytes(), "iso-8859-1"));

OutputStream outputStream = response.getOutputStream();

outputStream.write(byteArrayOutputStream.toByteArray());

outputStream.close();

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if (byteArrayOutputStream != null) {

byteArrayOutputStream.close();

}

} catch (IOException e) {

e.printStackTrace();

}

try {

workbook.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

/**

* 设置excel 头部的字体

*

* @param workbook 需要设置的工作部实体

* @return 返回一个 HSSFFont

*/

private static HSSFFont setExcelHeaderFont(HSSFWorkbook workbook) {

// 初始化head,填值标题行(第一行) 设置字体

HSSFFont font = workbook.createFont();

//字体高度

font.setFontHeightInPoints((short) 20);

//字体颜色

font.setColor(HSSFFont.COLOR_NORMAL);

//字体

font.setFontName("黑体");

//宽度

font.setBold(true);

font.setFontHeightInPoints((short) 13);

//是否使用斜体

font.setItalic(false);

return font;

}

/**

* 设置单元格基本的 水平居中 自动换行 字体

*

* @param workbook 需要设置的工作簿实体

* @return 返回一个 HSSFCellStyle

*/

private static HSSFCellStyle setHSSFCellStyle(HSSFWorkbook workbook) {

// 设置单元格类型

HSSFCellStyle cellStyle0 = workbook.createCellStyle();

// 水平布局:居中

cellStyle0.setAlignment(HorizontalAlignment.CENTER);

// 自动换行

cellStyle0.setWrapText(true);

return cellStyle0;

}

/**

* 创建excel第一行

*

* @param sheet

* @param fileName 文件名

* @param cellStyle 样式

* @param title 头部

*/

private static void createExcelFirstLine(HSSFSheet sheet, String fileName, HSSFCellStyle cellStyle, String[] title) {

// 创建第一行

HSSFRow row0 = sheet.createRow(0);

HSSFCell cell0 = row0.createCell(0, CellType.STRING);

// 标题名称

cell0.setCellValue(fileName);

cell0.setCellStyle(cellStyle);

// 合并单元格(起始行,截止行,起始列,截止列)

sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, title.length));

}

/**

* 创建excel头部

*

* @param sheet

* @param title 头部数组

* @param cellStyle 头部样式

*/

private static void createExcelHeader(HSSFSheet sheet, String[] title, HSSFCellStyle cellStyle) {

HSSFRow row1 = sheet.createRow(1);

for (int i = 0; i < title.length; i++) {

//设置单元格宽度

if (i == 0) {

sheet.setColumnWidth(i, "5897845697f84b3bf6acd1883be841ad".getBytes().length * 1 * 256);

} else if (i == 3) {

sheet.setColumnWidth(i, title[i].getBytes().length * 4 * 256);

} else {

sheet.setColumnWidth(i, title[i].getBytes().length * 2 * 256);

}

// 创建单元格,指定类型

HSSFCell cell1 = row1.createCell(i, CellType.STRING);

cell1.setCellValue(title[i]);

cell1.setCellStyle(cellStyle);

}

}

/**

* 初始化Excel头部信息 包含第一行 、 第二行

*

* @param sheet

* @param workbook 需要设置的工作簿实体

* @param n

* @param entry

* @param fileName 文件名

* @param title 头部

* @return 返回一个 HSSFCellStyle

*/

private static HSSFCellStyle initExcelHead(HSSFSheet sheet, HSSFWorkbook workbook, int n,

Map.Entry>> entry, String fileName, String[] title) {

// 初始化head,填值标题行(第一行) 设置字体

HSSFFont font = setExcelHeaderFont(workbook);

// 设置第一行 第二行 单元格的类型

HSSFCellStyle cellStyle0 = setHSSFCellStyle(workbook);

// 设置字体

cellStyle0.setFont(font);

// 创建第一行

createExcelFirstLine(sheet, fileName, cellStyle0, title);

// 垂直居中

cellStyle0.setVerticalAlignment(VerticalAlignment.CENTER);

// 创建excel表格头部

createExcelHeader(sheet, title, cellStyle0);

// 设置其他的 单元格类型

HSSFCellStyle cellStyle1 = setHSSFCellStyle(workbook);

// 垂直居中

cellStyle1.setVerticalAlignment(VerticalAlignment.CENTER);

return cellStyle1;

}

/**

* 循环列数 给当前行赋值

*

* @param title excel 头

* @param index 行数标识

* @param poiModels 当前行的数据集合

* @param mergeIndex 需要合并的列的下标组成的int数组

* @param map 取得当前这行的map,该map中以key,value的形式存着这一行值

* @param sheet

* @param cellStyle 单元格的样式

* @param row 创建的单元格的行的实体

* @param list 得到当前sheet下的数据集合 List>

*/

private static void currentRowAssignment(String[] title, int index, List poiModels, int[] mergeIndex,

Map map, HSSFSheet sheet, HSSFCellStyle cellStyle,

HSSFRow row, List> list) {

for (int i = 0; i < title.length; i++) {

String old = "";

// old存的是上一行统一位置的单元的值,第一行是最上一行了,所以从第二行开始记

if (index > 2) {

old = poiModels.get(i) == null ? "" : poiModels.get(i).getContent();

}

// 循环需要合并的列

for (int j = 0; j < mergeIndex.length; j++) {

if (index == 2) {

// 记录第三行的开始行和开始列

Object value = map.get(title[i]);

poiModels.add(PoiModel.builder()

.oldContent(value == null ? "" : value.toString())

.content(value == null ? "" : value.toString())

.rowIndex(2)

.cellIndex(i)

.build());

break;

// 这边i>0也是因为第一列已经是最前一列了,只能从第二列开始

} else if (i > 0 && mergeIndex[j] == i) {

/**

* 当前同一列的内容与上一行同一列不同时,把那以上的合并,

* 或者在当前元素一样的情况下,前一列的元素并不一样,这种情况也合并

* 如果不需要考虑当前行与上一行内容相同,但是它们的前一列内容不一样则不合并的情况,把下面条件中(rowSameContent && colSameContent)去掉就行

*/

// 当前行 的内容 与 上一行 的内容 是否相同

boolean rowSameContent = poiModels.get(i).getContent().equals(map.get(title[i]).toString());

// 当前列 的内容 与 前一列 的内容 是否不同

boolean colSameContent = !poiModels.get(i - 1).getOldContent().equals(map.get(title[i - 1]).toString());

// 最终的判断结果

boolean finalResult = !rowSameContent || (rowSameContent && colSameContent);

if (finalResult) {

merge(poiModels, i, index, sheet, map, title);

}

}

// 处理第一列的情况

if (mergeIndex[j] == i && i == 0 && !poiModels.get(i).getContent().equals(map.get(title[i]).toString())) {

// 当前行的当前列与上一行的当前列的内容不一致时,则把当前行以上的合并

merge(poiModels, i, index, sheet, map, title);

}

// 最后一行没有后续的行与之比较,所以当到最后一行时则直接合并对应列的相同内容

if (mergeIndex[j] == i && index == list.size() + 1) {

CellRangeAddress cra = new CellRangeAddress(poiModels.get(i).getRowIndex(),

index, poiModels.get(i).getCellIndex(), poiModels.get(i).getCellIndex());

//在sheet里增加合并单元格

sheet.addMergedRegion(cra);

}

}

HSSFCell cell = row.createCell(i, CellType.STRING);

Object value = map.get(title[i]);

cell.setCellValue(value == null ? "" : value.toString());

cell.setCellStyle(cellStyle);

// 在每一个单元格处理完成后,把这个单元格内容设置为old内容

poiModels.get(i).setOldContent(old);

}

}

public static void main(String args[]){

String[] headers = {

"id",

"产品名称",

"产品名称id",

"客户名称",

"客户名称id",

"条形码号"

};

/**

* 此处 Map 的 key 为每个sheet的名称,一个excel中可能有多个sheet页

* 此处 Map 中的 value List 中的 Map 的key 对应每一列的标题

* 此处 Map 中的 value list 为每个 sheet 页的数据

* 此处 HashMap 初始化时 使用默认大小 16

*/

Map>> maps = new HashMap<>(16);

//key:sheet页名称 value:数据库查出的数据集合List>

maps.put("id", list);

//需要合并的列

int[] intArr = new int[]{0,1};

ExcelUtil.createExcel(excel的头部, maps, intArr,文件名,响应头);

}

}

@Builder

@Data

class PoiModel {

private String content;

private String oldContent;

private int rowIndex;

private int cellIndex;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值