java–poi生成excel动态合并内容相同的行+水平垂直居中+大标题 浏览器直接下载
转自https://blog.csdn.net/qq_33142257/article/details/64929145#commentBox
public static String createExcel(String[] title, Map<String/*sheet名*/, List<Map<String/*对应title的值*/, Object>>> maps, int[] mergeIndex,HttpServletResponse response){
if (title.length==0){
return null;
}
/*初始化excel模板*/
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = null;
int n = 0;
/*循环sheet页*/
for(Map.Entry<String, List<Map<String/*对应title的值*/, Object>>> entry : maps.entrySet()){
/*实例化sheet对象并且设置sheet名称,book对象*/
try {
sheet = workbook.createSheet();
workbook.setSheetName(n, entry.getKey());
workbook.setSelectedTab(0);
}catch (Exception e){
e.printStackTrace();
}
/*初始化head,填值标题行(第一行)*/
//设置字体
HSSFFont font = workbook.createFont();
font.setFontHeightInPoints((short) 20); //字体高度
font.setColor(HSSFFont.COLOR_NORMAL); //字体颜色
font.setFontName("黑体"); //字体
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); //宽度
font.setItalic(false); //是否使用斜体
//设置单元格类型
HSSFCellStyle cellStyle0 = workbook.createCellStyle();
cellStyle0.setFont(font);
cellStyle0.setAlignment(HSSFCellStyle.ALIGN_CENTER); //水平布局:居中
cellStyle0.setWrapText(true);//自动换行
//创建第一行
HSSFRow row0 = sheet.createRow(0);
HSSFCell cell_0 = row0.createCell(0, HSSFCell.CELL_TYPE_STRING);
cell_0.setCellValue("隐患排查标准");//标题名称
cell_0.setCellStyle(cellStyle0);
sheet.addMergedRegion(new CellRangeAddress(0,0,0,15));//合并单元格(起始行,截止行,起始列,截止列)
/*初始化head,填值标题行(第二行)*/
HSSFCellStyle cellStyle1 = workbook.createCellStyle();
cellStyle1.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//垂直居中
cellStyle1.setAlignment(HSSFCellStyle.ALIGN_CENTER); //水平布局:居中
cellStyle1.setWrapText(true);//自动换行
HSSFRow row1 = sheet.createRow(1);
for(int i = 0; i<title.length; i++){
if (i==0) {//设置单元格宽度
sheet.setColumnWidth(i, "5897845697f84b3bacdf61883be841ad".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 cell_1 = row1.createCell(i, HSSFCell.CELL_TYPE_STRING);
cell_1.setCellValue(title[i]);
cell_1.setCellStyle(cellStyle1);
}
/*得到当前sheet下的数据集合*/
List<Map<String/*对应title的值*/, Object>> list = entry.getValue();
/*遍历该数据集合*/
List<PoiModel> poiModels = new ArrayList<PoiModel>();
if(null!=workbook){
Iterator iterator = list.iterator();
int index = 2;/*这里1是从excel的第三行开始,第一二行已经塞入标题了*/
while (iterator.hasNext()){
HSSFRow row = sheet.createRow(index);
/*取得当前这行的map,该map中以key,value的形式存着这一行值*/
Map<String, Object> map = (Map<String, Object>)iterator.next();
/*循环列数,给当前行塞值*/
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){
/*记录第三行的开始行和开始列*/
PoiModel poiModel = new PoiModel();
poiModel.setOldContent(map.get(title[i]).toString());
poiModel.setContent(map.get(title[i]).toString());
poiModel.setRowIndex(2);
poiModel.setCellIndex(i);
poiModels.add(poiModel);
break;
}else if(i > 0 && mergeIndex[j] == i){/*这边i>0也是因为第一列已经是最前一列了,只能从第二列开始*/
/*当前同一列的内容与上一行同一列不同时,把那以上的合并, 或者在当前元素一样的情况下,前一列的元素并不一样,这种情况也合并*/
/*如果不需要考虑当前行与上一行内容相同,但是它们的前一列内容不一样则不合并的情况,把下面条件中||poiModels.get(i).getContent().equals(map.get(title[i])) && !poiModels.get(i - 1).getOldContent().equals(map.get(title[i-1]))去掉就行*/
if(!poiModels.get(i).getContent().equals(map.get(title[i]).toString()) || poiModels.get(i).getContent().equals(map.get(title[i]).toString()) && !poiModels.get(i - 1).getOldContent().equals(map.get(title[i-1]).toString())){
/*当前行的当前列与上一行的当前列的内容不一致时,则把当前行以上的合并*/
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);
}
}
/*处理第一列的情况*/
if(mergeIndex[j] == i && i == 0 && !poiModels.get(i).getContent().equals(map.get(title[i]).toString())){
/*当前行的当前列与上一行的当前列的内容不一致时,则把当前行以上的合并*/
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);
}
/*最后一行没有后续的行与之比较,所以当到最后一行时则直接合并对应列的相同内容*/
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, HSSFCell.CELL_TYPE_STRING);
cell.setCellValue(map.get(title[i]).toString());
cell.setCellStyle(cellStyle1);
/*在每一个单元格处理完成后,把这个单元格内容设置为old内容*/
poiModels.get(i).setOldContent(old);
}
index++;
}
}
n++;
}
try {
response.setHeader("Content-Disposition","attachment;filename="+URLEncoder.encode("隐患排查标准","utf-8")+".xls");//直接从浏览器下载
OutputStream os = response.getOutputStream();
workbook.write(os);
os.close();
} catch (Exception e) {
e.printStackTrace();
}
return "成功";
}
public static void main(String args[]){
/*此处标题的数组则对应excel的标题*/
String[] title = {"编号","排查项目","排查内容","排查依据","排查方式","可能造成的事故","可能造成的后果","隐患等级","隐患类型","隐患类别","隐患内容","隐患内容说明","责任单位","责任人","排查地点","排查时间"};
Map<String/*此处的key为每个sheet的名称,一个excel中可能有多个sheet页*/, List<Map<String/*此处key对应每一列的标题*/, Object>>/*该list为每个sheet页的数据*/> maps = new HashMap<String, List<Map<String,Object>>>();
maps.put("隐患排查标准", list);//key:sheet页名称 value:数据库查出的数据集合List<Map<String,Object>>
int[] intArr = new int[]{0,1};//需要合并的列
String result = createExcel(title, maps, intArr,response);
System.out.println(result);
}