参考博客:
http://www.oschina.net/code/snippet_565430_15074
增加了多sheet,多列的自动合并。
修改了部分过时方法和导出逻辑。
优化了标题,导出信息等
先看下效果,如果正常导出是这样子:
自动合并后是:
动态图示例:
poi导出并不是一件很麻烦的事情,只是逻辑相对复杂,要考虑到各种情况。我把代码贴上,有用得到的可以帮助一下。
导出类:
1 package com.centit.njld.commons.testexcel; 2 3 import java.io.ByteArrayOutputStream; 4 import java.text.SimpleDateFormat; 5 import java.util.Date; 6 import java.util.LinkedHashMap; 7 import java.util.List; 8 import java.util.Map.Entry; 9 import java.util.Set; 10 11 import org.apache.poi.hssf.usermodel.HSSFCell; 12 import org.apache.poi.hssf.usermodel.HSSFRow; 13 import org.apache.poi.hssf.usermodel.HSSFSheet; 14 import org.apache.poi.hssf.usermodel.HSSFWorkbook; 15 import org.apache.poi.ss.usermodel.CellStyle; 16 import org.apache.poi.ss.usermodel.Font; 17 import org.apache.poi.ss.usermodel.IndexedColors; 18 import org.apache.poi.ss.util.CellRangeAddress; 19 20 import com.centit.njld.commons.testexcel.TestExcel_Reflection; 21 22 public class TestExcel_Export { 23 24 private static HSSFWorkbook wb; 25 26 private static CellStyle titleStyle; // 标题行样式 27 private static Font titleFont; // 标题行字体 28 private static CellStyle dateStyle; // 日期行样式 29 private static Font dateFont; // 日期行字体 30 private static CellStyle headStyle; // 表头行样式 31 private static Font headFont; // 表头行字体 32 private static CellStyle contentStyle; // 内容行样式 33 private static Font contentFont; // 内容行字体 34 35 /** 36 * 导出文件 37 */ 38 public static boolean export2File(ExcelExportData setInfo, 39 String outputExcelFileName) throws Exception { 40 return TestExcel_FileUtil.write(outputExcelFileName, export2ByteArray(setInfo), 41 true, true); 42 } 43 44 /** 45 * 导出到byte数组 46 */ 47 public static byte[] export2ByteArray(ExcelExportData setInfo) 48 throws Exception { 49 return export2Stream(setInfo).toByteArray(); 50 } 51 52 /** 53 * 导出到流 54 */ 55 public static ByteArrayOutputStream export2Stream(ExcelExportData setInfo) 56 throws Exception { 57 init(); 58 59 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 60 61 Set<Entry<String, List<?>>> set = setInfo.getDataMap().entrySet(); 62 String[] sheetNames = new String[setInfo.getDataMap().size()]; 63 int sheetNameNum = 0; 64 for (Entry<String, List<?>> entry : set) { 65 sheetNames[sheetNameNum] = entry.getKey(); 66 sheetNameNum++; 67 } 68 HSSFSheet[] sheets = getSheets(setInfo.getDataMap().size(), sheetNames); 69 int sheetNum = 0; 70 int k = 0; 71 72 for (Entry<String, List<?>> entry : set) { 73 // Sheet 74 List<?> objs = entry.getValue(); 75 76 // 标题行 77 createTableTitleRow(setInfo, sheets, sheetNum); 78 79 // 日期行 80 createTableDateRow(setInfo, sheets, sheetNum); 81 82 // 表头 83 creatTableHeadRow(setInfo, sheets, sheetNum); 84 85 // 表体 86 String[] fieldNames = setInfo.getFieldNames().get(sheetNum); 87 88 int rowNum = 3; 89 for (Object obj : objs) { 90 HSSFRow contentRow = sheets[sheetNum].createRow(rowNum); 91 contentRow.setHeight((short) 300); 92 HSSFCell[] cells = getCells(contentRow, setInfo.getFieldNames().get(sheetNum).length); 93 int cellNum = 1; // 去掉一列序号,因此从1开始 94 if (fieldNames != null) { 95 for (int num = 0; num < fieldNames.length; num++) { 96 Object value = TestExcel_Reflection.invokeGetterMethod(obj,fieldNames[num]); 97 cells[cellNum].setCellValue(value == null ? "" : value.toString()); 98 cellNum++; 99 } 100 } 101 rowNum++; 102 } 103 104 k++; 105 String[] groupColumns = null; 106 if(setInfo.getGroupColumn().size()!=0){ 107 if(setInfo.getGroupColumn().size() >= k){ 108 groupColumns = setInfo.getGroupColumn().get(sheetNum); 109 } 110 } 111 112 if(groupColumns!=null){ 113 int n=0; 114 for (int i = 0; i < groupColumns.length; i++) { 115 116 String[] fieldName = setInfo.getFieldNames().get(sheetNum); 117 for (int j = 0; j < fieldName.length; j++) { 118 if(groupColumns[i].equals(fieldName[j])){ 119 j++; 120 n=j; 121 break; 122 } 123 } 124 int x = 0; 125 int y = 0; 126 int z = 3; 127 int m = objs.size(); 128 boolean flag = false; 129 Object val = null; 130 CellRangeAddress dateRange = null; 131 for (Object obj : objs) { 132 y++; 133 Object value = TestExcel_Reflection.invokeGetterMethod(obj,groupColumns[i]); 134 if(x==0){ 135 x++; 136 val=value; 137 }else if(val.toString().equals(value.toString())){ 138 x++; 139 if(m==y){ 140 dateRange = new CellRangeAddress(z, x+3, n, n); 141 sheets[sheetNum].addMergedRegion(dateRange); 142 } 143 }else{ 144 val=value; 145 if(flag){ 146 dateRange = new CellRangeAddress(z, x+3, n, n); 147 z=x+4; 148 x=x+1; 149 }else{ 150 dateRange = new CellRangeAddress(z, x+2, n, n); 151 z=x+3; 152 } 153 sheets[sheetNum].addMergedRegion(dateRange); 154 flag=true; 155 } 156 } 157 } 158 } 159 160 // CellRangeAddress dateRange = new CellRangeAddress(3, 10, 1, 1); 161 // sheets[sheetNum].addMergedRegion(dateRange); 162 // 163 // CellRangeAddress aa = new CellRangeAddress(11, 15, 1, 1); 164 // sheets[sheetNum].addMergedRegion(aa); 165 // 166 // CellRangeAddress bb = new CellRangeAddress(3, 5, 2, 2); 167 // sheets[sheetNum].addMergedRegion(bb); 168 169 // 170 // CellRangeAddress aaa = new CellRangeAddress(16, 18, 1, 1); 171 // sheets[sheetNum].addMergedRegion(aaa); 172 173 adjustColumnSize(sheets, sheetNum, fieldNames); // 自动调整列宽 174 sheetNum++; 175 } 176 wb.write(outputStream); 177 return outputStream; 178 } 179 180 /** 181 * @Description: 初始化 182 */ 183 private static void init() { 184 wb = new HSSFWorkbook(); 185 186 titleFont = wb.createFont(); 187 titleStyle = wb.createCellStyle(); 188 dateStyle = wb.createCellStyle(); 189 dateFont = wb.createFont(); 190 headStyle = wb.createCellStyle(); 191 headFont = wb.createFont(); 192 contentStyle = wb.createCellStyle(); 193 contentFont = wb.createFont(); 194 195 initTitleCellStyle(); 196 initTitleFont(); 197 initDateCellStyle(); 198 initDateFont(); 199 initHeadCellStyle(); 200 initHeadFont(); 201 initContentCellStyle(); 202 initContentFont(); 203 } 204 205 /** 206 * @Description: 自动调整列宽 207 */ 208 private static void adjustColumnSize(HSSFSheet[] sheets, int sheetNum, 209 String[] fieldNames) { 210 for (int i = 0; i < fieldNames.length + 1; i++) { 211 sheets[sheetNum].autoSizeColumn(i, true); 212 } 213 } 214 215 /** 216 * @Description: 创建标题行(需合并单元格) 217 */ 218 private static void createTableTitleRow(ExcelExportData setInfo, HSSFSheet[] sheets, int sheetNum) { 219 CellRangeAddress titleRange = new CellRangeAddress(0, 0, 0, setInfo.getFieldNames().get(sheetNum).length); 220 sheets[sheetNum].addMergedRegion(titleRange); 221 HSSFRow titleRow = sheets[sheetNum].createRow(0); 222 titleRow.setHeight((short) 800); 223 HSSFCell titleCell = titleRow.createCell(0); 224 titleCell.setCellStyle(titleStyle); 225 titleCell.setCellValue(setInfo.getTitles()[sheetNum]); 226 } 227 228 /** 229 * @Description: 创建日期行(需合并单元格) 230 */ 231 private static void createTableDateRow(ExcelExportData setInfo,HSSFSheet[] sheets, int sheetNum) { 232 CellRangeAddress dateRange = new CellRangeAddress(1, 1, 0, setInfo.getFieldNames().get(sheetNum).length); 233 sheets[sheetNum].addMergedRegion(dateRange); 234 HSSFRow dateRow = sheets[sheetNum].createRow(1); 235 dateRow.setHeight((short) 350); 236 HSSFCell dateCell = dateRow.createCell(0); 237 dateCell.setCellStyle(dateStyle); 238 dateCell.setCellValue(new SimpleDateFormat("yyyy-MM-dd").format(new Date())); 239 } 240 241 /** 242 * @Description: 创建表头行(需合并单元格) 243 */ 244 private static void creatTableHeadRow(ExcelExportData setInfo, 245 HSSFSheet[] sheets, int sheetNum) { 246 // 表头 247 HSSFRow headRow = sheets[sheetNum].createRow(2); 248 headRow.setHeight((short) 350); 249 // 序号列 250 HSSFCell snCell = headRow.createCell(0); 251 snCell.setCellStyle(headStyle); 252 snCell.setCellValue("序号"); 253 // 列头名称 254 for (int num = 1, len = setInfo.getColumnNames().get(sheetNum).length; num <= len; num++) { 255 HSSFCell headCell = headRow.createCell(num); 256 headCell.setCellStyle(headStyle); 257 headCell.setCellValue(setInfo.getColumnNames().get(sheetNum)[num - 1]); 258 } 259 } 260 261 /** 262 * @Description: 创建所有的Sheet 263 */ 264 private static HSSFSheet[] getSheets(int num, String[] names) { 265 HSSFSheet[] sheets = new HSSFSheet[num]; 266 for (int i = 0; i < num; i++) { 267 sheets[i] = wb.createSheet(names[i]); 268 } 269 return sheets; 270 } 271 272 /** 273 * @Description: 创建内容行的每一列(附加一列序号) 274 */ 275 private static HSSFCell[] getCells(HSSFRow contentRow, int num) { 276 HSSFCell[] cells = new HSSFCell[num + 1]; 277 278 for (int i = 0, len = cells.length; i < len; i++) { 279 cells[i] = contentRow.createCell(i); 280 cells[i].setCellStyle(contentStyle); 281 } 282 283 // 设置序号列值,因为出去标题行和日期行,所有-2 284 cells[0].setCellValue(contentRow.getRowNum() - 2); 285 286 return cells; 287 } 288 289 /** 290 * @Description: 初始化标题行样式 291 */ 292 private static void initTitleCellStyle() { 293 titleStyle.setAlignment(CellStyle.ALIGN_CENTER); 294 titleStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); 295 titleStyle.setFont(titleFont); 296 titleStyle.setFillBackgroundColor(IndexedColors.SKY_BLUE.getIndex()); 297 } 298 299 /** 300 * @Description: 初始化日期行样式 301 */ 302 private static void initDateCellStyle() { 303 dateStyle.setAlignment(CellStyle.ALIGN_CENTER_SELECTION); 304 dateStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); 305 dateStyle.setFont(dateFont); 306 dateStyle.setFillBackgroundColor(IndexedColors.SKY_BLUE.getIndex()); 307 } 308 309 /** 310 * @Description: 初始化表头行样式 311 */ 312 private static void initHeadCellStyle() { 313 headStyle.setAlignment(CellStyle.ALIGN_CENTER); 314 headStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); 315 headStyle.setFont(headFont); 316 headStyle.setFillBackgroundColor(IndexedColors.YELLOW.getIndex()); 317 headStyle.setBorderTop(CellStyle.BORDER_MEDIUM); 318 headStyle.setBorderBottom(CellStyle.BORDER_THIN); 319 headStyle.setBorderLeft(CellStyle.BORDER_THIN); 320 headStyle.setBorderRight(CellStyle.BORDER_THIN); 321 headStyle.setTopBorderColor(IndexedColors.BLUE.getIndex()); 322 headStyle.setBottomBorderColor(IndexedColors.BLUE.getIndex()); 323 headStyle.setLeftBorderColor(IndexedColors.BLUE.getIndex()); 324 headStyle.setRightBorderColor(IndexedColors.BLUE.getIndex()); 325 } 326 327 /** 328 * @Description: 初始化内容行样式 329 */ 330 private static void initContentCellStyle() { 331 contentStyle.setAlignment(CellStyle.ALIGN_CENTER); 332 contentStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); 333 contentStyle.setFont(contentFont); 334 contentStyle.setBorderTop(CellStyle.BORDER_THIN); 335 contentStyle.setBorderBottom(CellStyle.BORDER_THIN); 336 contentStyle.setBorderLeft(CellStyle.BORDER_THIN); 337 contentStyle.setBorderRight(CellStyle.BORDER_THIN); 338 contentStyle.setTopBorderColor(IndexedColors.BLUE.getIndex()); 339 contentStyle.setBottomBorderColor(IndexedColors.BLUE.getIndex()); 340 contentStyle.setLeftBorderColor(IndexedColors.BLUE.getIndex()); 341 contentStyle.setRightBorderColor(IndexedColors.BLUE.getIndex()); 342 contentStyle.setWrapText(true); // 字段换行 343 } 344 345 /** 346 * @Description: 初始化标题行字体 347 */ 348 private static void initTitleFont() { 349 titleFont.setFontName("华文楷体"); 350 titleFont.setFontHeightInPoints((short) 20); 351 titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD); 352 titleFont.setCharSet(Font.DEFAULT_CHARSET); 353 titleFont.setColor(IndexedColors.BLUE_GREY.getIndex()); 354 } 355 356 /** 357 * @Description: 初始化日期行字体 358 */ 359 private static void initDateFont() { 360 dateFont.setFontName("隶书"); 361 dateFont.setFontHeightInPoints((short) 10); 362 dateFont.setBoldweight(Font.BOLDWEIGHT_BOLD); 363 dateFont.setCharSet(Font.DEFAULT_CHARSET); 364 dateFont.setColor(IndexedColors.BLUE_GREY.getIndex()); 365 } 366 367 /** 368 * @Description: 初始化表头行字体 369 */ 370 private static void initHeadFont() { 371 headFont.setFontName("宋体"); 372 headFont.setFontHeightInPoints((short) 10); 373 headFont.setBoldweight(Font.BOLDWEIGHT_BOLD); 374 headFont.setCharSet(Font.DEFAULT_CHARSET); 375 headFont.setColor(IndexedColors.BLUE_GREY.getIndex()); 376 } 377 378 /** 379 * @Description: 初始化内容行字体 380 */ 381 private static void initContentFont() { 382 contentFont.setFontName("宋体"); 383 contentFont.setFontHeightInPoints((short) 10); 384 contentFont.setBoldweight(Font.BOLDWEIGHT_NORMAL); 385 contentFont.setCharSet(Font.DEFAULT_CHARSET); 386 contentFont.setColor(IndexedColors.BLUE_GREY.getIndex()); 387 } 388 389 /** 390 * Excel导出数据类 391 * @author jimmy 392 */ 393 public static class ExcelExportData { 394 395 /** 396 * 导出数据 key:String 表示每个Sheet的名称 value:List<?> 表示每个Sheet里的所有数据行 397 */ 398 private LinkedHashMap<String, List<?>> dataMap; 399 400 /** 401 * 每个Sheet里的顶部大标题 402 */ 403 private String[] titles; 404 405 /** 406 * 单个sheet里的数据列标题 407 */ 408 private List<String[]> columnNames; 409 410 /** 411 * 单个sheet里每行数据的列对应的对象属性名称 412 */ 413 private List<String[]> fieldNames; 414 415 private List<String[]> groupColumn; 416 417 public List<String[]> getFieldNames() { 418 return fieldNames; 419 } 420 421 public void setFieldNames(List<String[]> fieldNames) { 422 this.fieldNames = fieldNames; 423 } 424 425 public String[] getTitles() { 426 return titles; 427 } 428 429 public void setTitles(String[] titles) { 430 this.titles = titles; 431 } 432 433 public List<String[]> getColumnNames() { 434 return columnNames; 435 } 436 437 public void setColumnNames(List<String[]> columnNames) { 438 this.columnNames = columnNames; 439 } 440 441 public LinkedHashMap<String, List<?>> getDataMap() { 442 return dataMap; 443 } 444 445 public void setDataMap(LinkedHashMap<String, List<?>> dataMap) { 446 this.dataMap = dataMap; 447 } 448 449 public List<String[]> getGroupColumn() { 450 return groupColumn; 451 } 452 453 public void setGroupColumn(List<String[]> groupColumn) { 454 this.groupColumn = groupColumn; 455 } 456 } 457 458 }