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,不用去考虑系数和其他的:)

posted @ 2017-08-18 11:00  熊猫大胜  阅读(2798)  评论(0编辑  收藏  举报