import java.io.Serializable; /** * POI Excel報表導出,列合並實體<br> * * @author WQ * */ public class PoiModel implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String content; private String oldContent; private int rowIndex; private int cellIndex; public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getOldContent() { return oldContent; } public void setOldContent(String oldContent) { this.oldContent = oldContent; } public int getRowIndex() { return rowIndex; } public void setRowIndex(int rowIndex) { this.rowIndex = rowIndex; } public int getCellIndex() { return cellIndex; } public void setCellIndex(int cellIndex) { this.cellIndex = cellIndex; } public PoiModel() { } public PoiModel(String content, String oldContent, int rowIndex, int cellIndex) { this.content = content; this.oldContent = oldContent; this.rowIndex = rowIndex; this.cellIndex = cellIndex; } @Override public String toString() { return "PoiModel [content=" + content + ", oldContent=" + oldContent + ", rowIndex=" + rowIndex + ", cellIndex=" + cellIndex + "]"; } }
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class Demo { /** * @param title 標題集合 tilte的長度應該與list中的model的屬性個數一致 * @param maps 內容集合 * @param mergeIndex 合並單元格的列 */ public static String createExcel(String[] title, Map<String, List<Map<String, String>>> maps, int[] mergeIndex){ if (title.length==0){ return null; } /*初始化excel模板*/ Workbook workbook = new XSSFWorkbook(); Sheet sheet = null; int n = 0; for(Map.Entry<String, List<Map<String, String>>> entry : maps.entrySet()){ try { sheet = workbook.createSheet(); workbook.setSheetName(n, entry.getKey()); workbook.setSelectedTab(0); }catch (Exception e){ e.printStackTrace(); } /*初始化head,填值標題行(第一行)*/ Row row0 = sheet.createRow(0); for(int i = 0; i<title.length; i++){ /*創建單元格,指定類型*/ Cell cell_1 = row0.createCell(i, Cell.CELL_TYPE_STRING); cell_1.setCellValue(title[i]); } /*得到當前sheet下的數據集合*/ List<Map<String, String>> list = entry.getValue(); /*遍歷該數據集合*/ List<PoiModel> poiModels = new ArrayList(); if(null!=workbook){ Iterator iterator = list.iterator(); int index = 1; while (iterator.hasNext()){ Row row = sheet.createRow(index); /*取得當前這行的map,該map中以key,value的形式存着這一行值*/ Map<String, String> map = (Map<String, String>)iterator.next(); /*循環列數,給當前行塞值*/ for(int i = 0; i<title.length; i++){ String old = ""; /*old存的是上一行統一位置的單元的值,第一行是最上一行了,所以從第二行開始記*/ if(index > 1){ old = poiModels.get(i)==null?"":poiModels.get(i).getContent(); } /*循環需要合並的列*/ for(int j = 0; j < mergeIndex.length; j++){ if(index == 1){ /*記錄第一行的開始行和開始列*/ PoiModel poiModel = new PoiModel(); poiModel.setOldContent(map.get(title[i])); poiModel.setContent(map.get(title[i])); poiModel.setRowIndex(1); 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])) || poiModels.get(i).getContent().equals(map.get(title[i]))
&& !poiModels.get(i - 1).getOldContent().equals(map.get(title[i-1]))){ /*當前行的當前列與上一行的當前列的內容不一致時,則把當前行以上的合並*/ 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])); 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]))){ /*當前行的當前列與上一行的當前列的內容不一致時,則把當前行以上的合並*/ 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])); poiModels.get(i).setRowIndex(index); poiModels.get(i).setCellIndex(i); } /*最后一行沒有后續的行與之比較,所有當到最后一行時則直接合並對應列的相同內容*/ if(mergeIndex[j] == i && index == list.size()){ CellRangeAddress cra=new CellRangeAddress(poiModels.get(i).getRowIndex(), index, poiModels.get(i).getCellIndex(), poiModels.get(i).getCellIndex()); //在sheet里增加合並單元格 sheet.addMergedRegion(cra); } } Cell cell = row.createCell(i, Cell.CELL_TYPE_STRING); cell.setCellValue(map.get(title[i])); /*在每一個單元格處理完成后,把這個單元格內容設置為old內容*/ poiModels.get(i).setOldContent(old); } index++; } } n++; } /*生成臨時文件*/ FileOutputStream out = null; String localPath = null; File tempFile = null; String fileName = String.valueOf(new Date().getTime()/1000); try { tempFile = File.createTempFile(fileName, ".xlsx"); localPath = tempFile.getAbsolutePath(); out = new FileOutputStream(localPath); workbook.write(out); }catch (IOException e){ e.printStackTrace(); }finally { try { out.flush(); out.close(); }catch (IOException e){ e.printStackTrace(); } } return localPath; } public static void main(String[] args) throws IOException{ /*此處標題的數組則對應excel的標題*/ String[] title = {"id","標題","描述","負責人","開始時間"}; List<Map<String, String>> list = new ArrayList(); /*這邊是制造一些數據,注意每個list中map的key要和標題數組中的元素一致*/ for(int i = 0; i<10; i++){ HashMap<String, String> map = new HashMap(); if(i > 5){ if(i<7){ map.put("id","333"); map.put("標題","mmmm"); }else { map.put("id","333"); map.put("標題","aaaaa"); } }else if (i >3){ map.put("id","222"); map.put("標題","哈哈哈哈"); }else if (i>1 && i<3){ map.put("id","222"); map.put("標題","hhhhhhhh"); }else { map.put("id","222"); map.put("標題","bbbb"); } map.put("描述","sssssss"); map.put("負責人","vvvvv"); map.put("開始時間","2017-02-27 11:20:26"); list.add(map); } Map<String, List<Map<String, String>>> map = new HashMap(); map.put("測試合並數據", list); System.out.println(createExcel(title, map, new int[]{0,1,2})); } }
思路:
后來就通過建一個單元格對象,屬性有單元格內容,與單元格同一列的上一行內容,起始行,起始列,就這四個屬性
生成的文件效果(兩種情況的):