poi创建excel复杂表头
最近遇到一个导出,excel的表头很复杂,想了想,为了避免重复造轮子,我就自己写了个类处理poi来建表,为了方便,花了两天来写来测试。
遇到的excel头是这样的
本来没打算不封装起来的,可是发现不封装更难写:(,这好耐着性子想出来。
这是我用自己的类封装写的,效果是这样的,因为公司开发都是用开发云写的,代码拿不出来,自己再手敲一遍,样式的就没那么细致写了。
git@github.com:chaospand/chaos.git
这是项目的github地址,里面有个poiDeal的maven项目,拿出来在eclipse上面导入就可以跑了,里面还有一个App的测试,可以直接看到运行效果,需要用的话不妨拿去试试。
package cn.chaos.poiDeal;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
/**
* 用于建立复杂的表头(这是我暂时用到的地方),用法
* POIexcelMake make = new POIexcelMake('excel表名');
* make.creatRow();
* make.createCell();
* make.createCell(with,height); //这里的with和height是excel单元格合并别的单元格的个数
*
* @author chaospanda
*
*/
public class POIexcelMake {
private String name;
private HSSFWorkbook hssfWorkbook;
private HSSFSheet sheet;
private Row crruentRow;//当前操作的行
private int columnPosi;//当前行位置
private int rowPosi;//当前列位置
private int rowSize;//行的数量
private int columnSize;//列的数量
/**
* 这个map的第一个参数是行,第二个参数是是列中被占用了的位置,类似电影院买票时,有些被买了,有些没被买,用这个标记出来
*/
private Map<Integer,Map<Integer,Integer>> excelMap;
private HSSFCellStyle style;
public POIexcelMake(String name) {
this.name = name;
columnPosi = 0;
rowPosi = 0;
rowSize = 0;
columnSize = 0;
this.hssfWorkbook = new HSSFWorkbook();
this.sheet = this.hssfWorkbook.createSheet();
this.excelMap = new HashMap();
this.style = hssfWorkbook.createCellStyle();
style.setAlignment(CellStyle.ALIGN_CENTER);
}
/**
* 创建一行,也表示当前操作的行
* @return
*/
public Row createRow(){
Row row = sheet.createRow(rowSize);
this.crruentRow = row;
rowPosi = rowSize; //当前行位置设为创建的行
columnPosi = 0;
/**
* 在这里,通过excelMap进行过滤,确认当前的行的列的位置,因为我为了方便,先设置最大值是100
*/
if(excelMap.containsKey(rowPosi)){
Map<Integer, Integer> map = excelMap.get(rowPosi);
for(int i=0;i<100;i++){
if(!map.containsKey(i)){
columnPosi = i;
break;
}
}
}
columnSize = 0;
rowSize++;
return row;
}
/**
* 创建一个长宽为1的cell
* @return
*/
public Cell createCell(){
if(this.crruentRow==null)
throw new RuntimeException("please create row first,there is no row for you to create cell");
Cell cell = createCell(columnPosi);
columnPosiForWard();
columnSize++;
return cell;
}
/**
* 创建一个指定大小的cell
* @param width
* @param height
* @return
*/
public Cell createCell(int width,int height){
int lastRow = rowPosi + height -1;
int lastCol = columnPosi + width -1;
sheet.addMergedRegion(new CellRangeAddress(rowPosi,lastRow, columnPosi, lastCol));
dealMap(width,height);
Cell cell = createCell(columnPosi);
columnPosi =lastCol;
columnPosiForWard();
columnSize++;
return cell;
}
private void dealMap(int width, int height) {
// TODO Auto-generated method stub
Integer perRowPosi = rowPosi;//获得当前行
Integer perColumnPosi = columnPosi;//获得当前行的列位置
for(int i=0;i<height-1;i++){
perRowPosi++;//获得下一行
if(!excelMap.containsKey(perRowPosi)){
excelMap.put(perRowPosi, new HashMap<Integer,Integer>());
}
Map<Integer, Integer> rowMap = excelMap.get(perRowPosi);
for(int j=0;j<width;j++){
Integer col = perColumnPosi+j;
if(!rowMap.containsKey(col)){
rowMap.put(col, col);
}
}
}
}
public HSSFWorkbook getHssfWorkbook() {
return hssfWorkbook;
}
private Cell createCell(int position){
Cell cell = crruentRow.createCell(position);
cell.setCellStyle(style);
return cell;
}
private void columnPosiForWard(){
columnPosi++;
//如果包含当前行,获得该行,判断当前位置是否有被使用,如果往前移一格继续判断
if(excelMap.containsKey(rowPosi)){
Map<Integer, Integer> map = excelMap.get(rowPosi);
if(map!=null){
while(map.containsKey(columnPosi)){
columnPosi++;
}
}
}
}
}
上面就是代码,里面有个最重要的就是excelmap,用来查询哪些cell格子是已经被用了,自动跳过这些格子。这个创建的思想是这样的:基于你要创建多大的格子,创建的时候会在能创建
且没被使用的格子里创建你要的cell,不用去考虑系数和其他的:)