案例 导出excel美化合并单元格

有时感觉客户给的导出模板比较复杂既有合并单元格还有不规则的分类配置,其实都是为了导出excel后可以很直观的浏览数据,得到反馈;从这点出发,开发出来的功能客户用起来才会觉得好用。为了方便以后Ctrl C and Ctrl V,在这里和童鞋们分享两种相似的合并单元格的方法;

一、固定列名+变动有规律的列名

    /**
     * 导出excel到浏览器,美化合并单元格
     * @param titles 表头,合并单元格时取左上角第一个的值
     * [序号, 生产系, 部品番号, 上月滞后, , 12月1日-白班A, , , 12月1日-夜班B, , , 12月2日-白班A, , , 12月2日-夜班B, , , 12月3日-白班A, , , 12月3日-夜班B, , , 12月4日-白班A, , , 12月4日-夜班B, , , 12月5日-白班A, , , 12月5日-夜班B, , , 12月6日-白班A, , , 12月6日-夜班B, , , 12月7日-白班A, , , 12月7日-夜班B, , , 12月8日-白班A, , , 12月8日-夜班B, , , 12月9日-白班A, , , 12月9日-夜班B, , , 12月10日-白班A, , , 12月10日-夜班B, , , 12月11日-白班A, , , 12月11日-夜班B, , , 12月12日-白班A, , , 12月12日-夜班B, , , 12月13日-白班A, , , 12月13日-夜班B, , , 12月14日-白班A, , , 12月14日-夜班B, , , 12月15日-白班A, , , 12月15日-夜班B, , , 12月16日-白班A, , , 12月16日-夜班B, , , 12月17日-白班A, , , 12月17日-夜班B, , , 12月18日-白班A, , , 12月18日-夜班B, , , 12月19日-白班A, , , 12月19日-夜班B, , , 12月20日-白班A, , , 12月20日-夜班B, , , 12月21日-白班A, , , 12月21日-夜班B, , , 12月22日-白班A, , , 12月22日-夜班B, , , 12月23日-白班A, , , 12月23日-夜班B, , , 12月24日-白班A, , , 12月24日-夜班B, , , 12月25日-白班A, , , 12月25日-夜班B, , , 12月26日-白班A, , , 12月26日-夜班B, , , 12月27日-白班A, , , 12月27日-夜班B, , , 12月28日-白班A, , , 12月28日-夜班B, , , 12月29日-白班A, , , 12月29日-夜班B, , , 12月30日-白班A, , , 12月30日-夜班B, , , 12月31日-白班A, , , 12月31日-夜班B, ]
     * [, , , , 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异, 计划, 实绩, 差异]
     * @param datas 列表数据
     * @param response 响应体
     * @param sheetName 导出表名
     */
    private void getMergeExcel(List<String[]> titles, List<String[]> datas, HttpServletResponse response, String sheetName){
        ByteArrayOutputStream bout = null;
        SXSSFWorkbook xssfWorkbook;
        try{
            Row row = null;
            Cell cell = null;
            CellRangeAddress cellRangeAddress = null;
            xssfWorkbook = new SXSSFWorkbook();
            Sheet sheet = xssfWorkbook.createSheet(sheetName);
            
            // 水平居中
            XSSFCellStyle alignStyle = (XSSFCellStyle) xssfWorkbook.createCellStyle();
            alignStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
            // 垂直居中
            XSSFCellStyle verticalStyle = (XSSFCellStyle) xssfWorkbook.createCellStyle();
            verticalStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
            // 水平垂直居中
            XSSFCellStyle horizontalVerticalStyle = (XSSFCellStyle) xssfWorkbook.createCellStyle();
            horizontalVerticalStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
            horizontalVerticalStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
            
            // 拼接表头
            for (int i = 0; i < titles.size(); i++) {
                row = sheet.createRow(i);
                if(i == 0){
                    // 合并表头个数 + 固定列名个数
                    int length = (titles.get(i).length - 4) / 3 + 4;
                    // 第一行,序号、生产系、部品番号、上月滞后、日期
                    for (int j = 0; j < length; j ++) {
                        if(j < 4){
                            // 0~3,固定表头的索引
                            cellRangeAddress = new CellRangeAddress(0, 1, j, j);
                            sheet.addMergedRegion(cellRangeAddress);
                            cell = row.createCell(j);
                            cell.setCellStyle(horizontalVerticalStyle);
                            cell.setCellValue(titles.get(i)[j]);
                            continue;
                        }
                        
                        // 需要合并的单元格
                        // 指定合并的范围,开始行,结束行,开始列,结束列
                        cellRangeAddress = new CellRangeAddress(0, 0, j + 2 * (j - 4), j + 2 * (j - 3));
                        // 将合并单元格加入表中
                        sheet.addMergedRegion(cellRangeAddress);
                        cell = row.createCell(j + 2 * (j - 4));
                        // 指定合并单元格内容居中样式
                        cell.setCellStyle(alignStyle);
//                        cell.setCellValue("5月5日-白班A");
                        // 为合并单元格赋值
                        cell.setCellValue(titles.get(i)[3 * (j - 2) - 1]);
                    }
                }else{
                    int length = titles.get(i).length;
                    // 第二行、计划、实绩、差异
                    for (int j = 0; j < length; j ++) {
                        if(j < 4){
                            // 跳过固定表头的索引
                            continue;
                        }
                        
                        // 4~end,非固定表头的索引
                        cell = row.createCell(j);
                        cell.setCellType(Cell.CELL_TYPE_STRING);
                        cell.setCellValue(titles.get(i)[j]);
                    }
                }
            }
            for (int i = 0; i < datas.size(); i++) {
                row = sheet.createRow(i+2);
                String[] rows = datas.get(i);
                for (int j = 0; j < rows.length; j++) {
                    cell = row.createCell(j);
                     cell.setCellType(Cell.CELL_TYPE_STRING);
                     cell.setCellValue(rows[j]);
                }
            }
            String title = new String(sheetName.getBytes("utf-8"), "ISO-8859-1");
            response.setHeader("content-disposition", "attachment;filename=" + title + ".xlsx");
            response.flushBuffer();
            xssfWorkbook.write(response.getOutputStream());
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(bout!=null){
                try {
                    bout.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

导出excel格式参考:

二、固定列名+变动无规律的列名

    /**
     * 导出excel到浏览器,美化合并单元格
     * @param titles 表头,合并单元格时取左上角第一个的值 
     * [序号, 日期, 班次, 生产系, 部品, 正常停止, 正常停止, 正常停止, 正常停止, 正常停止, 正常停止, 正常停止, 品质, 品质, 品质, 品质, 技改, 技改, 技改, 技改, 组装, 组装, 组装, 组装, 保全, 保全, 保全, 保全, 保全, 保全, 保全, 保全, 保全, 保全, 保全, 物流, 物流, 物流, 物流, 物流, 物流, 冲压, 冲压, 其他, 其他, 其他, 其他, 其他, 其他]
     * [, , , , , 剥离、压力测试, 电极研磨, 电极更换, 焊丝更换, 贴标签, 段取, 点检, 品质异常判定, 单品、KD来料不良, 焊点不良.co2焊道不良.压力值不足, 品质不良调查/改善, 夹具精度不良.调整, 夹具气路异常(气缸.气管.接头等气路元件损坏), 夹具机械异常(定位销.导向块等易耗类故障), 涂胶机/遮断器/刻印机,机械异常, 平衡器异常及机械类故障, 电极.定位芯.研磨刀更换异常更换, 握杆、电极杆、电极异常更换, 水、气管破损更换, 夹具线路.感应器故障.磁性开关损坏, 悬挂式点焊机.固定焊故障, co2焊机故障.DCE焊机故障, 机器人.自动打点机故障, 螺母(栓)输送机故障, 螺母(栓)机焊接异常, 研磨机电路故障, 涂胶机/遮断器异常, 刻印机线路故障.光栅异常, co2机器人研磨.喷油故障, 刻印机电路.程序故障.电磁阀损坏, 缺辅材, 缺单品, 缺KD, 单/成品待叉车, 缺胶箱.容器不良, 纳入异常, 缺单品, 产品不良, 生理现象, 作业指导, 停电, 停水, 停气, 其他]
     * @param titleMap 可变动的列名及其列的个数
     * {正常停止=[剥离、压力测试, 电极研磨, 电极更换, 焊丝更换, 贴标签, 段取, 点检], 品质=[品质异常判定, 单品、KD来料不良, 焊点不良.co2焊道不良.压力值不足, 品质不良调查/改善], 技改=[夹具精度不良.调整, 夹具气路异常(气缸.气管.接头等气路元件损坏), 夹具机械异常(定位销.导向块等易耗类故障), 涂胶机/遮断器/刻印机,机械异常], 组装=[平衡器异常及机械类故障, 电极.定位芯.研磨刀更换异常更换, 握杆、电极杆、电极异常更换, 水、气管破损更换], 保全=[夹具线路.感应器故障.磁性开关损坏, 悬挂式点焊机.固定焊故障, co2焊机故障.DCE焊机故障, 机器人.自动打点机故障, 螺母(栓)输送机故障, 螺母(栓)机焊接异常, 研磨机电路故障, 涂胶机/遮断器异常, 刻印机线路故障.光栅异常, co2机器人研磨.喷油故障, 刻印机电路.程序故障.电磁阀损坏], 物流=[缺辅材, 缺单品, 缺KD, 单/成品待叉车, 缺胶箱.容器不良, 纳入异常], 冲压=[缺单品, 产品不良], 其他=[生理现象, 作业指导, 停电, 停水, 停气, 其他]}
     * @param datas 列表数据
     * @param response 响应体
     * @param sheetName 导出表名
     */
    private void getMergeExcel(List<String[]> titles, LinkedHashMap<String, List<String>> titleMap, List<String[]> datas, HttpServletResponse response, String sheetName){
        ByteArrayOutputStream bout = null;
        SXSSFWorkbook xssfWorkbook;
        try{
            Row row = null;
            Cell cell = null;
            CellRangeAddress cellRangeAddress = null;
            xssfWorkbook = new SXSSFWorkbook();
            Sheet sheet = xssfWorkbook.createSheet(sheetName);
            
            // 水平居中
            XSSFCellStyle alignStyle = (XSSFCellStyle) xssfWorkbook.createCellStyle();
            alignStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
            // 垂直居中
            XSSFCellStyle verticalStyle = (XSSFCellStyle) xssfWorkbook.createCellStyle();
            verticalStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
            // 水平垂直居中
            XSSFCellStyle horizontalVerticalStyle = (XSSFCellStyle) xssfWorkbook.createCellStyle();
            horizontalVerticalStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
            horizontalVerticalStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
            
            // 拼接表头
            for (int i = 0; i < titles.size(); i++) {
                row = sheet.createRow(i);
                if(i == 0){
                    // 合并表头个数 + 固定列名个数
                    String[] title0 = titles.get(i);
                    int length = title0.length;
                    
                    // 第一行,序号、日期、班次、生产系、部品
                    for (int j = 0; j < length;) {
                        if(j < 5){
                            // 0~4,固定表头的索引
                            cellRangeAddress = new CellRangeAddress(0, 1, j, j);
                            sheet.addMergedRegion(cellRangeAddress);
                            cell = row.createCell(j);
                            cell.setCellStyle(horizontalVerticalStyle);
                            cell.setCellValue(title0[j]);
                            j ++;
                            continue;
                        }
                        
                        // 需要合并的单元格
                        int mergeNum = titleMap.get(title0[j]).size();
                        // 指定合并的范围,开始行,结束行,开始列,结束列
                        cellRangeAddress = new CellRangeAddress(0, 0, j, j + mergeNum - 1);
                        // 将合并单元格加入表中
                        sheet.addMergedRegion(cellRangeAddress);
                        cell = row.createCell(j);
                        // 指定合并单元格内容居中样式
                        cell.setCellStyle(alignStyle);
                        // 为合并单元格赋值
                        cell.setCellValue(title0[j]);
                        // 指定下一个动态列名的索引位置
                        j += mergeNum;
                    }
                }else if(i == 1){
                    String[] title1 = titles.get(1);
                    int length = title1.length;
                    // 第二行、计划、实绩、差异
                    for (int j = 0; j < length; j ++) {
                        if(j < 5){
                            // 跳过固定表头的索引
                            continue;
                        }
                        
                        // 5~end,非固定表头的索引
                        cell = row.createCell(j);
                        cell.setCellType(Cell.CELL_TYPE_STRING);
                        cell.setCellValue(title1[j]);
                    }
                }
            }
            for (int i = 0; i < datas.size(); i++) {
                row = sheet.createRow(i+2);
                String[] rows = datas.get(i);
                for (int j = 0; j < rows.length; j++) {
                    cell = row.createCell(j);
                     cell.setCellType(Cell.CELL_TYPE_STRING);
                     cell.setCellValue(rows[j]);
                }
            }
            String title = new String(sheetName.getBytes("utf-8"), "ISO-8859-1");
            response.setHeader("content-disposition", "attachment;filename=" + title + ".xlsx");
            response.flushBuffer();
            xssfWorkbook.write(response.getOutputStream());
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(bout!=null){
                try {
                    bout.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

导出excel格式参考:

 

posted @ 2020-12-04 11:59  王晓鸣  阅读(428)  评论(1)    收藏  举报