List<ArrayList<String>> bodies = new ArrayList<ArrayList<String>>();

//  循环数据信息  准备添加到excel表格中

for(){

ArrayList<String> tmp = new ArrayList<String>();

// 姓名 
tmp.add(mapObj.get("name").toString());

bodies.add(tmp);

}

excel.buildListHeader(headers);

// 不进行合并

excel.buildListBody(bodies);

//  进行合并

List<Integer[]> indexMargeList = new ArrayList<Integer[]>();
// 元素 : 起始行,起始列,结束行,结束列   
Integer[] indexArr1 = new Integer[]{2,2,6,5};
Integer[] indexArr2 = new Integer[]{7,2,10,9};
indexMargeList.add(indexArr1) ;
indexMargeList.add(indexArr2) ;
excel.buildListBodyForMarge(bodies, indexMargeList );

// 风格设置  可以不要

class  ExcelStyle extends AbstractExcel{

public ExcelStyle () {
super();
}

public ExcelStyle (int workType) {
super(workType);
}
 
@Override
public void setStyle(int rownum, int columnnum, @SuppressWarnings("rawtypes") List dataList, Object obj,Workbook workbook, Cell cell) {

CellStyle cellStyle = workbook.createCellStyle();

//设置对齐方式
cellStyle.setAlignment(CellStyle.ALIGN_LEFT);//水平左对齐
cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);//垂直居中 
cellStyle.setBorderBottom(CellStyle.BORDER_THIN); // 下边框
cellStyle.setBorderLeft(CellStyle.BORDER_THIN);// 左边框
cellStyle.setBorderTop(CellStyle.BORDER_THIN);// 上边框
cellStyle.setBorderRight(CellStyle.BORDER_THIN);// 右边框 
cell.setCellType(Cell.CELL_TYPE_STRING);  
cellStyle.setAlignment(CellStyle.ALIGN_CENTER);// 居中  
   cellStyle.setWrapText(true);//强制使用POI样式
//式样设置到cell中:
cell.setCellStyle(cellStyle);
}

}

// 真正处理excel的类

public abstract class AbstractExcel {
    private static Logger logger = Logger.getLogger(AbstractExcel.class);

private Workbook workbook;
    private Sheet sheet;
    public final static int HSSF = 1;//03
    public final static int XSSF = 2;//07
    public final static int SXSSF = 3;//biggrid
    private int type =0;//文档类型
    
    private final static int ROW = 1;
    private final static int COLUMN = 0;
    
    //private boolean exclusion = true;
    
    private int rowMergeCount = -1;//控制行合并
    private Map<Integer,Integer> columnMergeCount = new HashMap<Integer,Integer>();//控制列合并
    
    
    private boolean startRowMerge = true;//启用行合并
    private boolean startColumnMerge = true;//启用列合并
    
    private int mergeColumnIndex = 0;//列合并起始行下标
    private int mergeColumnEndIndex = 0;//列合并终止行下标
    
    private List<Integer> mayMergeColumn = new ArrayList<Integer>();//允许合并列
    private List<Integer> mayMergeRow = new ArrayList<Integer>();//允许合并行

public AbstractExcel(){
        this.workbook = new XSSFWorkbook();
        this.sheet = workbook.createSheet();
    }
    
    public AbstractExcel(int workType){
        if(workType==HSSF){
            this.workbook = new HSSFWorkbook();
        }
        if(workType==XSSF){
            this.workbook = new XSSFWorkbook();
        }
        if(workType==SXSSF){
            this.workbook = new SXSSFWorkbook();
        }
        this.sheet = workbook.createSheet();
        type = workType;
    }
    
    /**
     * 合并单元格
     */
    private void mergeCell(Sheet sheet,int firstRow,int  lastRow,int  firstCol,int  lastCol,int rorc){
        sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol));//添加合并
        int index = sheet.getNumMergedRegions();//合并列表
        if(COLUMN==rorc){
            columnMergeCount.put(firstCol+1, index-1);  // 缓存列合并下标      
        }else{
            rowMergeCount = index-1;//缓存行合并下标
        }
    }
    
    /**
     * 构建要合并的excel sheet jinp 20150129 
     * indexMargeList:坐标点集合
     * 坐标点四个参数分别是:起始行,起始列,结束行,结束列
     */
    public Sheet buildListBodyForMarge(List<ArrayList<String>> bodies,List<Integer[]> indexMargeList){
        startRowMerge = true;
        return buildListForMarge(sheet,bodies,indexMargeList);
    }
    
    /**
     * 合并单元格 jinp 20150129 
     * // 四个参数分别是:起始行,起始列,结束行,结束列
     */
    private void mergeCellForMarge(Sheet sheet,int firstRow,int  firstCol,int  lastRow,int  lastCol){
    // Region 参数 : 起始行,起始列,结束行,结束列   
        sheet.addMergedRegion(new CellRangeAddress(firstRow,firstCol,lastRow,lastCol));//添加合并
        int index = sheet.getNumMergedRegions();//合并列表
    }
    /**
     * 合并单元格  jinp 20150129 
     * // 四个参数分别是:起始行,起始列,结束行,结束列
     * 测试的时候,四个值是写死的,也可以传入另外一个参数List<List<Integer>>,多个合并的坐标 一个合并四个点坐标 
     */
    protected Sheet buildListForMarge(Sheet sheet,List<ArrayList<String>> list,List<Integer[]> indexMargeList){
    int lastRowNum = sheet.getLastRowNum();
        Row tmp = sheet.getRow(0);
        if(null != tmp){
            lastRowNum = lastRowNum + 1;
        }
        
        for(int i = 0;i<list.size();i++){
            Row row = this.createRow(sheet, i+lastRowNum);
            this.buildComplexRow(sheet,row, list,list.get(i),i);  
        }
        // 3, 2, 5, 6: 代表四个点坐标  分别是起始行,起始列,结束行,结束列,可以吧这四个值存到一个list中,
        // 多个合并的时候,可以吧这些list添加到另外一个容器中,循环容器即可
        if(indexMargeList != null && indexMargeList.size() > 0){
        for(Integer[] indexList : indexMargeList){
        // 如果坐标点小于3 是不能满足定位的  所以必须大于3 
        if(indexList != null && indexList.length > 3){
        this.mergeCellForMarge(sheet, indexList[0], indexList[1], indexList[2], indexList[3]);
        }
        }
        }
        return sheet;
    }
    
   
    
    public void mergeCell(int firstRow,int  lastRow,int  firstCol,int  lastCol){
    mergeCell(this.sheet, firstRow, lastRow, firstCol, lastCol, 0);
    }
    
    public void setCellStyle(){
        
    }
    /**
     * 删除合并(依据合并下标)
     */
    private void removeMerge(Sheet sheet,int mergeIndex){
        sheet.removeMergedRegion(mergeIndex);
        if(rowMergeCount > mergeIndex){
            rowMergeCount = rowMergeCount - 1;//重排缓存下标
        }
        reSort(columnMergeCount,mergeIndex);
    }
    /**
     * 重排缓存下标
     */
    private void reSort(Map<Integer,Integer> map,int index){
        for(int i : map.keySet()){
            if(map.get(i) > index){
                map.put(i, map.get(i)-1);
            }
        }
    }
    
    /**
     * 创建行
     * @param sheet 卡片
     * @param rownum 行号
     * @return
     */
    private Row createRow(Sheet sheet,int rownum){
        AssertUtils.notNull(sheet, "row can't be null!");
        AssertUtils.isTrue(rownum >= 0, "rownum must gt 0");
        return sheet.createRow(rownum);
    }
    
    /**
     * 创建单元格
     * @param row 行号
     * @param columnIndex 单元格列索引
     * @param type 类型
     * @return
     */
    private Cell createCell(Row row,int columnIndex,int type){
        AssertUtils.notNull(row,"row can't be null!");
        AssertUtils.isTrue( columnIndex >= 0,"columnIndex must gt 0");
        AssertUtils.isTrue((0 < type && type < 5),"type must gt 0 and lt 5");
        Cell cell = row.createCell(columnIndex, type);
        return cell;
    }
    
    //--------------对象元素构建表格---------------------
    public Sheet bulildObjectExcel(List<Object> bodies,List<Object> headers){
        int len = headers.get(0).getClass().getFields().length;
        setColMergeCount(len);
        buildObjectHeader(headers);
        buildObjectBody(bodies);
        return sheet;
    }
    
    public void setColMergeCount(int maxColNum){
        for(int i = 1; i<= maxColNum ; i++){
            columnMergeCount.put(i, -1);
        }
    }
    
    public Sheet buildObjectHeader(List<Object> headers){
        return buildObject(sheet,headers);
    }
    public Sheet buildObjectBody(List<Object> bodies){
        startRowMerge = false;
        return buildObject(sheet,bodies);
    }
    protected Sheet buildObject(Sheet sheet,List<Object> list){
        int lastRowNum = sheet.getLastRowNum();
        Row tmp = sheet.getRow(0);
        if(null != tmp){
            lastRowNum = lastRowNum + 1;
        }
        for(int i = 0;i<list.size();i++){
            Row row = this.createRow(sheet, i+lastRowNum);
            this.buildComplexRow(sheet,row, list.get(i),i,list);  
        }
        return sheet;
    }
    //------------------------------------
    
    
    //---------------构建简单workbook 表头区行列合并;数据区设定请用合并方式---------------------
    public Sheet bulildSimpleExcel(List<ArrayList<String>> bodies,List<ArrayList<String>> headers){
        setColMergeCount(headers.get(0).size());
        buildListHeader(headers);
        buildListBody(bodies);
        return sheet;
    }
    
    public Sheet buildListHeader(List<ArrayList<String>> headers){
        return buildList(sheet,headers);
    }
    public Sheet buildListBody(List<ArrayList<String>> bodies){
       startRowMerge = false;
       return buildList(sheet,bodies);
    }
    protected Sheet buildList(Sheet sheet,List<ArrayList<String>> list){
        int lastRowNum = sheet.getLastRowNum();
        Row tmp = sheet.getRow(0);
        if(null != tmp){
            lastRowNum = lastRowNum + 1;
        }
        
        for(int i = 0;i<list.size();i++){
            Row row = this.createRow(sheet, i+lastRowNum);
            this.buildComplexRow(sheet,row, list,list.get(i),i);  
        }
        
        return sheet;
    }
    //------------------------------------
    
    
    
    public abstract void setStyle(int rownum,int columnnum,List dataList,Object obj,Workbook workbook,Cell cell);//设置行样式
    
    /**
     * 
     *功能: 获取当前元素所在列中最大宽度,汉字占两个字母宽度
     *@date 2013-9-26
     * @param rownum 当前cell行
     * @param colNum 当前cell列
     * @param value 当前cell值
     * @return
     */
    private int getMaxLength(int rownum,int colNum,String value){
        int currentColLen = length(StringUtil.convertNull(value));
        if(rownum==0){
            return currentColLen;
        }else{
        if(currentColLen>=255){
        return 255;
        }else{
           Sheet sheet = workbook.getSheetAt(0);
           Row row = sheet.getRow(rownum-1);
           Cell cell = row.getCell((short)colNum);
           String cellVal = cell.getStringCellValue();
           int maxColLen = sheet.getColumnWidth(colNum)/256;
           return currentColLen>maxColLen?currentColLen:maxColLen;
        }
        }
    }
    /**
     * 获取字符串的长度,如果有中文,则每个中文字符计为2位
     *
     * @param value  指定的字符串
     *           
     * @return 字符串的长度
     */
    public int length(String value) {
        int valueLength = 2;
        String chinese = "[\u0391-\uFFE5]";
        /* 获取字段值的长度,如果含中文字符,则每个中文字符长度为2,否则为1 */
        for (int i = 0; i < value.length(); i++) {
            /* 获取一个字符 */
            String temp = value.substring(i, i + 1);
            /* 判断是否为中文字符 */
            if (temp.matches(chinese)) {
                /* 中文字符长度为2 */
                valueLength += 2;
            } else {
                /* 其他字符长度为1 */
                valueLength += 1;
            }
        }
        return valueLength;

}

private Cell buildCell(Row row,int rownum,int columnnum,String value,List dataList,Object obj){
        Cell cell = this.createCell(row, columnnum, Cell.CELL_TYPE_STRING);//创建单元格
        cell.setCellValue(null==value?"":value);//单元格赋值
        
        
        setStyle(rownum,columnnum,dataList,obj,workbook,cell);
        
        int maxLenth = getMaxLength(row.getRowNum(),columnnum,value);
        sheet.setColumnWidth(columnnum, maxLenth*256);
        return cell;
    }
    
    /**
     * 合并构建(指定合并)
     * 合并顺序:先:行合并;再列合并。
     * 列合并前校验:解决(四个方块区域合并冲突)
     */
    private void buildMerge(Sheet sheet){
        int rownum = sheet.getLastRowNum();
        int columnnum =sheet.getRow(rownum).getLastCellNum()-1;
        String value = sheet.getRow(rownum).getCell(columnnum).getStringCellValue();
        if(mayMergeRow.contains(rownum) && (columnnum > 0)){//行 合并。startRowMerge:启用行合并;columnnum:列号 要大于0 从第二列开始行合并
            int rowBegin = getRowFirstMergeIndex(value,sheet.getRow(rownum),columnnum);//开始合并的 列索引下标。
            if(rowBegin >= 0){//参与合并的下标位置判断。0:边界位置;-1 不允许合并
                if(checkRowMergeRegion(rowMergeCount)){//状态校验。checkRowMergeRegion: 判断上一个单元格是否是合并单元格
                    if(rowBegin!=0){
                        this.removeMerge(sheet,rowMergeCount);//删除合并                        
                    }else{
                        if(columnnum!=1){
                            this.removeMerge(sheet,rowMergeCount);//删除合并
                        }
                    }
                    
                }
                this.mergeCell(sheet, rownum, rownum, rowBegin, columnnum,ROW);//合并单元格
            }else{
                rowMergeCount = -1;
            }
            
        }
        // 逻辑同上
        if((rownum > 0) && mayMergeColumn.contains(columnnum)){//TODO 待处理四格子冲突
            
            int columnBegin = getColumnFirstMergeIndex(value,sheet,rownum,columnnum);
            if(columnBegin >= mergeColumnIndex){
                if(checkColumnMergeRegion(columnnum+1) ){//
                    this.removeMerge(sheet, columnMergeCount.get(columnnum+1));
                }
                this.mergeCell(sheet, columnBegin, rownum, columnnum, columnnum,COLUMN);
            }else{
        columnMergeCount.put(columnnum+1, -1);
        }
        }
    }

/**
     * 构建自动合并的行列
     * @param row
     * @param list
     * @return
     */
    private Row buildComplexRow(Sheet sheet,Row row,List dataList,List<String> list,int rownum){
        for(int i = 0;i<list.size();i++){
            String value = list.get(i);
            Cell cell = buildCell(row, rownum, i, value,dataList,list);//先创建
            buildMerge(sheet);
        }
        return row;
    }
    
    /**
     * 反射调用get方法取值
     */
    private Row buildComplexRow(Sheet sheet,Row row,Object obj,int rownum,List dataList){
        Class clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for(int i = 0;i<fields.length;i++){
            String name = fields[i].getName();
            Object objValue = null;
            try {
                objValue = ReflectionUtils.invokeGetterMethod(obj, name);
            }catch(Exception e){
                logger.error(e.getMessage(), e);
                throw new ExcelException(e);
            }
            String value = String.valueOf(objValue);
            Cell cell = buildCell(row, rownum, i, value,dataList,obj);//先创建
            buildMerge(sheet);//后合并
        }
        return row;
    }
    
    
    /**
     * 列合并 状态 校验
     */
    private boolean checkColumnMergeRegion(int preColumn){
        //TODO 
        return (-1 != columnMergeCount.get(preColumn)); 
    }
    /**
     * 行合并 状态 校验
     */
    private boolean checkRowMergeRegion(int status){
        return (-1 != status);
    }
    
    /**
     * 查找开始合并index
     * @param value 填充值
     * @param row 行号
     * @param rowCellIndex 行cell index
     * @return 合并起始位置
     */
    private int getRowFirstMergeIndex(String value,Row row ,int rowCellIndex){
    int beginMergeIndex = -1;
        if(rowCellIndex > 0 && checkRowMergeRegion(rowCellIndex) && value.equals(row.getCell(rowCellIndex-1).getStringCellValue().trim())){
        int formerIndex = getRowFirstMergeIndex(value,row,rowCellIndex-1);
        if(formerIndex==-1){
        beginMergeIndex = rowCellIndex-1;
        }else{
        beginMergeIndex = formerIndex;
        }
        }
        return beginMergeIndex;
    }
    
    private int getColumnFirstMergeIndex(String value,Sheet sheet,int rowNum,int columnNum){
    int beginMergeIndex = -1;
        if(rowNum > mergeColumnEndIndex && null!=sheet.getRow(rowNum-1).getCell(columnNum) && value.equals(sheet.getRow(rowNum-1).getCell(columnNum).getStringCellValue())){
        int formerIndex = getColumnFirstMergeIndex(value,sheet,rowNum-1,columnNum);
        if(formerIndex == -1){
        beginMergeIndex = rowNum-1;
        }else{
        beginMergeIndex = formerIndex;
        }
        }
       return beginMergeIndex;
    }
    /**
     * 通过流输出至本地excel表中
     * @param excelname 文档名称
     * @param filedir  输出目录(暂时未使用)
     * @throws Exception
     */
    public void exportToExcel(String excelname, HttpServletResponse response, String filedir)throws Exception {
        if(type==0){//如果未传递文档参数,则默认为07版本excel
            this.type=XSSF;
        }
        String extension = this.type==1?".xls":".xlsx";
        BufferedOutputStream bos = null;
        OutputStream os = null;
        try {
            os = response.getOutputStream();
            bos = new BufferedOutputStream(os);
            response.setHeader("Content-disposition", "attachment;filename=\""
                    + (new String(excelname.getBytes("GB2312"),"ISO8859-1")+extension + "\""));
            
            this.workbook.write(bos);
            bos.flush();
        } catch (Exception e) {
            logger.error(e.getMessage());
        }finally{
            if(os!=null) os.close();
            if(bos!=null) bos.close();
        }
    }
    
    /**
     * 设置可以合并列
     */
    public void setMayMergeColumn(List<Integer> mayMergeColumn) {
        this.mayMergeColumn = mayMergeColumn;
    }
    
    public Workbook getWorkbook() {
        return workbook;
    }

public Sheet getSheet() {
        return sheet;
    }

public List<Integer> getMayMergeRow() {
        return mayMergeRow;
    }

public void setMayMergeRow(List<Integer> mayMergeRow) {
        this.mayMergeRow = mayMergeRow;
    }

public int getMergeColumnIndex() {
return mergeColumnIndex;
}

public void setMergeColumnIndex(int mergeColumnIndex) {
this.mergeColumnIndex = mergeColumnIndex;
}

public int getMergeColumnEndIndex() {
return mergeColumnEndIndex;
}

public void setMergeColumnEndIndex(int mergeColumnEndIndex) {
this.mergeColumnEndIndex = mergeColumnEndIndex;
}

}

excel 合并行列单元格相关推荐

  1. python使用openpyxl excel 合并拆分单元格

    再次编辑中,这次是在使用删除列的时候发现,合并单元格会出现漏删除情况,才想到用拆分单元格,没想到unmerge_cells(),worksheet.merged_cells返回的合并单元格对象居然不能 ...

  2. Aspose.cells导出Excel合并行单元格(Datatable)

    //前台ajax返回成功的数据 $.ajax({             url: "地址?r=" + Math.random,             type: "p ...

  3. python openpyxl合并单元格_python使用openpyxl excel 合并拆分单元格

    再次编辑中,这次是在使用删除列的时候发现,合并单元格会出现漏删除情况,才想到用拆分单元格,没想到unmerge_cells(),worksheet.merged_cells返回的合并单元格对象居然不能 ...

  4. Latex 制作斜线表头、合并行列单元格

    这篇文章主要给出一些 Latex 制作斜线表头.合并行单元格与合并列单元格的 demo 演示 latex:制作斜线表头 \begin{tabular}{|l|ccc|} \hline \diagbox ...

  5. 利用xlwt写excel并进行单元格的合并

    1.写入行列值 import xlwt # 创建一个workbook 设置编码 workbook = xlwt.Workbook(encoding='utf-8') # 创建一个worksheet w ...

  6. thinkphp导出到excel,合并拆分单元格!

    导出到excel合并拆解单元格操作(奇怪操作) 接到需求做一个奇怪的产品表格,时间紧任务重,开始演示,目的以下样式 目标确定开始操作! 首先数据格式为图中,我们需要先分析出这应该是一条数据但是需要合并 ...

  7. html导出excel合并单元格,JS导出EXCEL,动态设置单元格格式,合并单元格(横向或纵向)等操作...

    参考链接: https://blog.csdn.net/weixin_33724046/article/details/89611397 https://www.cnblogs.com/lvsk/p/ ...

  8. jQuery仿excel表格实现单元格拆分合并功能

    用html的table来布局,定制html模板,调用pd4ml生成要打印的pdf,为了方便添加了一个合并拆分单元格的方法,合并单元格来源于网络,但是有问题自己进行了修改. 网上合并单元格源码如下: & ...

  9. 雅客EXCEL (3)-合并取消单元格、平均值、添加序号

    文章目录 0.引言 1.合并单元格和取消单元格(定位查找法) 2.求平均值函数average 3. 添加序号 0.引言 本文是微商视频<雅客EXCEL>的视频笔记,通过199元购买的,如需 ...

最新文章

  1. SET-UID程序漏洞实验
  2. 锋利的JQuery学习笔记01
  3. Linux2.6内核驱动与2.4的区别 .
  4. jar 工程我怎么在网页上url访问某一个方法_Java高级编程之URL处理
  5. 腾讯、阿里、百度...大厂招聘火热中,测试员如何才能入大厂?
  6. Android开发文档
  7. bootstrap-table 树形结构
  8. 3.7 TextRNN—TextRCNN—TextAttentionRNN—HAN—FastText—代码
  9. 树形DP+二分(Information Disturbing HDU3586)
  10. Makefile详解(六)
  11. PyMuPDF 拼版(一)
  12. P2P网络NAT穿透原理(打洞方案)
  13. NVIDIA、CUDA与CPU参数、计算能力对比学习
  14. 【刘文彬】【源码解读】EOS测试插件:txn_test_gen_plugin.cpp
  15. Java 编写捕鱼达人游戏 窗体程序 完整源码
  16. UI设计学习路线是什么?
  17. html+js+canvas实现画板涂画功能和vue+canvas实现画板涂画功能
  18. 人工智能的知识图,人工智能学习路线
  19. 【ZDNS分享】广电行业(四)DHCP解决方案
  20. 八段锦:让 IT 人士受益一生的运动救生圈

热门文章

  1. 浅谈350M警用集群对讲机的使用与维护
  2. R语言学习笔记(1)——cut函数
  3. 第1章 电路元件和电路定律
  4. PubSub Websocket实时通信 - GoEasy在小程序中的使用
  5. RN Deep Linking for iOS
  6. 【OpenCV 4开发详解】图像模板匹配
  7. 数据一致性比对(番外)
  8. 操作系统第五章——输入输出管理(上)
  9. PPT之对人脸模糊处理
  10. hydra暴力破解工具