getPhysicalNumberOfCells获取列数不是合并前实际列数

13 篇文章 0 订阅

问题就是:有的导入复杂表头被合并的单元格有默认空字符串,有的直接不存在这个单元格

在这里插入图片描述

在这里插入图片描述
实际我需要下面这种情况
在这里插入图片描述
断点可以看到这个导入第一行合并了,被合并单元格还有默认的空字符串
在这里插入图片描述

解决办法就是在合并单元格里面判断,不是第一行第一列都设置空字符串
在这里插入图片描述

之前贴过导入复杂表头,这里再贴一边

package com.njry.modules.system.rest;


import com.njry.exception.BadRequestException;
import com.njry.modules.tools.domain.vo.HeaderCell;
import com.njry.modules.tools.domain.vo.HeaderRegion;
import com.njry.modules.system.domain.SysTest;
import com.njry.modules.system.service.SysTestService;
import com.njry.utils.SecurityUtils;
import com.njry.utils.excel.ExcelColorHelper;
import com.njry.utils.excel.HssfHelper;
import com.njry.utils.excel.XssfHelper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;

@RestController
@RequiredArgsConstructor
@Api(tags = "工具:本地存储管理")
@RequestMapping("/api/localStorageExcel")
public class testExcelController {

    private final SysTestService sysTestService;

    @PostMapping
    @ApiOperation("上传文件")
    public ResponseEntity<Object> createFile(@RequestParam String name, @RequestParam("file") MultipartFile file){
//        保存导入表头配置
        Map<String, String> mp = new HashMap<String, String>();
        int res = 1;

        try {
            if (file == null || file.isEmpty()) {
                res = -1;
            }
            HeaderCell[][] headerCells = null;
            int typeNumber = checkFile(file);
            if(typeNumber == 1){
                headerCells = readXLSX(file);
            }
            if(typeNumber == 2){
                headerCells = readXLS(file);
            }
            if(typeNumber == 0 || typeNumber == 3){
                throw new BadRequestException("上传文件格式不正确");
            }
            Map cellMap = getHtmlStr(headerCells, 1);//传1 正序
//            获取表头的后处理父子级关系
            List cellList = (List)cellMap.get("cellList");
            int rowNum = (int)cellMap.get("rowNum");

//            只有正序的时候才能这样使用
            for(int i = 0; i < cellList.size(); i++){
                HashMap<String,Object> hashMap = (HashMap)cellList.get(i);
                if(hashMap.get("rowfrom").equals(0)){
                    hashMap.put("parentLevel",null);
//                    hashMap.put("leafFlag",0);
                }else{
//                    判断不是第一行起的父级是谁
                    int rowfrom = convertObjectToInt(hashMap.get("rowfrom")) - 1;
                    int colfrom = convertObjectToInt(hashMap.get("colfrom"));
                    for (int j = 0; j < cellList.size(); j++) {
                        HashMap<String,Object> hashMapInner = (HashMap)cellList.get(j);
                        int rowfrom1 = convertObjectToInt(hashMapInner.get("rowfrom"));
                        int rowto = convertObjectToInt(hashMapInner.get("rowto"));
                        int colfrom1 = convertObjectToInt(hashMapInner.get("colfrom"));
                        int colto = convertObjectToInt(hashMapInner.get("colto"));
                        if(rowfrom >= rowfrom1 && rowfrom <= rowto && colfrom >= colfrom1 && colfrom <= colto){
                            hashMap.put("parentLevel",hashMapInner.get("headid"));
//                            hashMap.put("leafFlag",1);
                        }
                    }
                }
//                处理leafFlag是最后一行表示叶子节点
                int rowto = convertObjectToInt(hashMap.get("rowto"));
                if(rowto == rowNum - 1){
                    hashMap.put("leafFlag",1);
                }else{
                    hashMap.put("leafFlag",0);
                }
            }
            System.out.println(cellList);
            for (int k = 0; k < cellList.size(); k++) {
                HashMap<String,Object> hashMap = (HashMap)cellList.get(k);
                SysTest resources =  new SysTest();
                resources.setColfrom((Integer) hashMap.get("colfrom"));
                resources.setColto((Integer) hashMap.get("colto"));
                resources.setColspan((Integer) hashMap.get("colspan"));
                resources.setRowfrom((Integer) hashMap.get("rowfrom"));
                resources.setRowto((Integer) hashMap.get("rowto"));
                resources.setRowspan((Integer) hashMap.get("rowspan"));
//                数据库不允许title在插入的时候是null(表头传入有的是空)---修改数据表为null
                resources.setTitle((String) hashMap.get("title"));
                resources.setHeadid((String) hashMap.get("headid"));
                resources.setParentlevel((String) hashMap.get("parentLevel"));
                resources.setHeight((Float) hashMap.get("height"));
                resources.setBgColor((String) hashMap.get("bg_color"));
                resources.setFontColor((String) hashMap.get("font_color"));
                resources.setFontHeight((String) hashMap.get("font_height"));
                resources.setLeafFlag((Integer) hashMap.get("leafFlag"));
                sysTestService.create(resources);
            }
        }catch (Exception e)
            {
                throw e;
//                res = 0;
            }
            mp.put("res", res + "");
        return new ResponseEntity<>(HttpStatus.CREATED);
    }


    public int convertObjectToInt(Object obj) {
        if (obj instanceof String) {
            return Integer.parseInt((String) obj);
        } else if (obj instanceof Integer) {
            return (Integer) obj;
        } else {
            throw new IllegalArgumentException("Object cannot be converted to int");
        }
    }

    public HeaderCell[][] readXLS(MultipartFile file){
        Workbook wb = null;
        try
        {
            wb = new HSSFWorkbook(file.getInputStream());
        }
        catch (Exception ex)
        {
        }
        Sheet sheet = wb.getSheetAt(0);
        return excelToHtml(sheet,wb,1);
    }

    public HeaderCell[][] readXLSX(MultipartFile file){
        Workbook wb = null;
        try
        {
            wb = new XSSFWorkbook(file.getInputStream());
        }
        catch (Exception ex)
        {
        }
        Sheet sheet = wb.getSheetAt(0);
        return excelToHtml(sheet,wb,2);
    }

    /**
     * 判断File文件的类型
     * @param file 传入的文件
     * @return 0-文件为空,1-XLSX文件,2-XLS文件,3-其他文件
     */
    public int checkFile(MultipartFile file) {
        if (file == null) {
            return 0;
        }
        String filename = file.getOriginalFilename();
        String fileSuffix= filename.substring(filename.lastIndexOf("."));
        if (fileSuffix.endsWith("xlsx")) {
            return 1;
        }
        if (fileSuffix.endsWith("xls")) {
            return 2;
        }
        return 3;
    }

    /**
     * Convert byte[] to hex string.这里我们可以将byte转换成int,然后利用Integer.toHexString(int)
     *来转换成16进制字符串。
     * @param src 传入的rbg
     * @return @return hex string
     */
    public static String bytesToHexString(byte[] src){
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }


    /**
     * @description 解析表头
     * @author 
     * @param sheet
     * @param wb
     * @param type 1是 HSSFWorkbook 2 是XSSFWorkbook
     * @return
     */
    @SuppressWarnings({"deprecation", "unchecked", "static-access"})
    public HeaderCell[][] excelToHtml(Sheet sheet, Workbook wb,int type)
    {
        //开始解析excel
        HssfHelper hssfHelper = null;
        XssfHelper xssfHelper = null;
        if(type == 1){
            hssfHelper= new HssfHelper();
        }
        if(type == 2){
            xssfHelper = new XssfHelper();
        }
        ExcelColorHelper colorHelper = new ExcelColorHelper();
        Font headFont;
        CellStyle headStyle;


        //获取Sheet中的合并单元格信息(为下文HeaderCell下属性判断使用)
        HeaderRegion[] headerRegions = new HeaderRegion[sheet.getNumMergedRegions()];
        for(int k = 0; k < sheet.getNumMergedRegions(); k++)
        {
            HeaderRegion headerRegion = null;
            CellRangeAddress region = sheet.getMergedRegion(k);
            headerRegion = new HeaderRegion();
            int firstRow = region.getFirstRow();
            int lastRow = region.getLastRow();
            int firstColumn = region.getFirstColumn();
            int lastColumn = region.getLastColumn();
            headerRegion.setTargetRowFrom(firstRow);
            headerRegion.setTargetRowTo(lastRow);
            headerRegion.setTargetColumnFrom(firstColumn);
            headerRegion.setTargetColumnTo(lastColumn);
            if(type == 1){
                HSSFCell cell = (HSSFCell)sheet.getRow(firstRow).getCell(firstColumn);
                headerRegion.setText(hssfHelper.getCellStringValue(cell));
            }
            if(type == 2){
                XSSFCell cell = (XSSFCell)sheet.getRow(firstRow).getCell(firstColumn);
                headerRegion.setText(xssfHelper.getCellStringValue(cell));
            }
            headerRegion.setColLength(1 + (lastColumn - firstColumn));
            headerRegion.setRowLength(1 + (lastRow - firstRow));
//            当前合并单元的合并的列数
//            int numberOfCells = region.getNumberOfCells();
//            System.out.println(numberOfCells);
//            合并单元格,被合并单元格没数据设置成默认空字符----getPhysicalNumberOfCells获取不到存在合并行(合并前的)实际列数
            for (int i = firstRow; i <= lastRow; i++) {
                for (int j = firstColumn; j <= lastColumn; j++) {
//                    除去第一行一列默认有值,其余全部设置为空字符串
                    if(i == firstRow && j == firstColumn){
//                        第一行第一列啥也不处理
                    }else{
//                        被合并但是有数据默认空字符串不处理
                        Cell cell = sheet.getRow(i).getCell(j);
                        if(cell == null){
                            cell = sheet.getRow(i).createCell(j);
                            cell.setCellValue(""); // 设置单元格为空字符串
                        }
                    }
                }
            }
            headerRegions[k] = headerRegion;
        }

        //获取Sheet中的单元格信息
        int rowNum = sheet.getPhysicalNumberOfRows();
//        获取第一行,得到第一行有多少列,就是excel有多少列(有的第一行合并后,获取是合并的列数,不是合并前实际列数)
        Row rowFirst = sheet.getRow(0);
        int cellNum = rowFirst.getPhysicalNumberOfCells();

//        short firstCellNum = rowFirst.getFirstCellNum();
//        System.out.println(firstCellNum);
//        short lastCellNum = rowFirst.getLastCellNum();
//        System.out.println(lastCellNum);
        HeaderCell[][] headerCells = new HeaderCell[rowNum][cellNum];
        Iterator iter = sheet.rowIterator();
        for(int i = 0; iter.hasNext(); i++)
        {
            HeaderCell headerCell = null;
            if(type == 1){
                HSSFRow row = (HSSFRow) iter.next();
//            获取每一行高度
                float heightInPoints = row.getHeightInPoints();
//            获取每一行有多少列 physical物理的
                int cellNums = row.getPhysicalNumberOfCells();

                for(int j = 0; j < cellNums; j++)
                {
                    headerCell = new HeaderCell();
//                获取到每一行下每一列
                    HSSFCell cell = row.getCell((short) j);
                    headStyle = cell.getCellStyle();
                    headFont = wb.getFontAt(cell.getCellStyle().getFontIndex());//得到单元格的字体
                    headerCell.setRowIndex(i);
                    headerCell.setColIndex(j);
                    headerCell.setText(hssfHelper.getCellStringValue(cell));
                    headerCell.setHeight(heightInPoints);
                    headerCell.setWidth(sheet.getColumnWidth((short) j) / 32);


                    HSSFCellStyle cellStyle = cell.getCellStyle();
                    HSSFColor fillForegroundColorColor1 = cellStyle.getFillForegroundColorColor();
                    String foregroundColorHexString = fillForegroundColorColor1.getHexString();
                    HSSFFont font = cellStyle.getFont(wb);
                    HSSFWorkbook tempTransport = (HSSFWorkbook) wb;
                    HSSFColor hssfColor = font.getHSSFColor(tempTransport);
                    if(hssfColor == null){
                        String colorHexString = "#000000";
                        headerCell.setFontColor(colorHexString);
                    }else{
                        String colorHexString = hssfColor.getHexString();
                        headerCell.setFontColor(colorHexString);
                    }
                    headerCell.setBgcolor(foregroundColorHexString);

                    headerCell.setFontHeight(String.valueOf(headFont.getFontHeight()/20));

                    boolean hasRegion = false;
                    for(int k = 0; k < headerRegions.length; k++)
                    {
//                    判断当前cell是否属于合并单元格 i 在合并单元格之内 同时 j 在合并单元格内(上文headerRegions使用)
                        if(i >= headerRegions[k].getTargetRowFrom() && i <= headerRegions[k].getTargetRowTo()
                                && j >= headerRegions[k].getTargetColumnFrom() && j <= headerRegions[k].getTargetColumnTo())
                        {
                            headerCell.setHeaderRegion(headerRegions[k]);
                            hasRegion = true;
                        }
                    }

                    if(!hasRegion)
                    {
                        HeaderRegion headerRegion2 = new HeaderRegion();
                        headerRegion2.setTargetRowFrom(i);
                        headerRegion2.setTargetRowTo(i);
                        headerRegion2.setTargetColumnFrom(j);
                        headerRegion2.setTargetColumnTo(j);
                        HSSFCell cell1 = (HSSFCell)sheet.getRow(i).getCell((short) j);
                        headerRegion2.setText(hssfHelper.getCellStringValue(cell1));
                        headerRegion2.setColLength(1);
                        headerRegion2.setRowLength(1);
                        headerCell.setHeaderRegion(headerRegion2);
                    }
//                通过!hasRegion将没有合并的单元格都也有headerRegion,就是自己本身,本身的话下面设置两个变量都是true
//                合并区域的开始行i 和开始列 j 是否是当前单元格的开始行和列
                    headerCell.setAscDisplay((i == headerCell.getHeaderRegion().getTargetRowFrom() && j == headerCell.getHeaderRegion().getTargetColumnFrom()) ? true : false);
//                合并区域的结束行i 和开始列 j 是否是当前单元格的开始行和列
                    headerCell.setDescDisplay((i == headerCell.getHeaderRegion().getTargetRowTo() && j == headerCell.getHeaderRegion().getTargetColumnFrom()) ? true : false);
                    headerCells[i][j] = headerCell;
                }
            }
            if(type == 2){
                XSSFRow row = (XSSFRow) iter.next();
//            获取每一行高度
                float heightInPoints = row.getHeightInPoints();
//            获取每一行有多少列 physical物理的
                int cellNums = row.getPhysicalNumberOfCells();

                for(int j = 0; j < cellNums; j++)
                {
                    headerCell = new HeaderCell();
//                获取到每一行下每一列
                    XSSFCell cell = row.getCell(j);
                    headFont = wb.getFontAt(cell.getCellStyle().getFontIndex());//得到单元格的字体
                    headerCell.setRowIndex(i);
                    headerCell.setColIndex(j);
                    headerCell.setText(xssfHelper.getCellStringValue(cell));
                    headerCell.setHeight(heightInPoints);
                    headerCell.setWidth(sheet.getColumnWidth((short) j) / 32);


                    XSSFCellStyle cellStyle = cell.getCellStyle();
                    XSSFColor fillForegroundColorColor = cellStyle.getFillForegroundColorColor();
                    if(fillForegroundColorColor == null){
                        String foregroundColorHexString = "#ffffff";
                        headerCell.setBgcolor(foregroundColorHexString);
                    }else{
                        byte[] argb = fillForegroundColorColor.getARGB();
                        String tempString = bytesToHexString(argb);
                        headerCell.setBgcolor(tempString);
                    }
                    XSSFFont font = cellStyle.getFont();
                    XSSFColor xssfColor = font.getXSSFColor();
                    if(xssfColor == null){
                        String colorHexString = "#000000";
                        headerCell.setFontColor(colorHexString);
                    }else{
                        byte[] argb = xssfColor.getARGB();
                        String tempString = bytesToHexString(argb);
                        headerCell.setFontColor(tempString);
                    }

                    headerCell.setFontHeight(String.valueOf(headFont.getFontHeight()/20));

                    boolean hasRegion = false;
                    for(int k = 0; k < headerRegions.length; k++)
                    {
//                    判断当前cell是否属于合并单元格 i 在合并单元格之内 同时 j 在合并单元格内(上文headerRegions使用)
                        if(i >= headerRegions[k].getTargetRowFrom() && i <= headerRegions[k].getTargetRowTo()
                                && j >= headerRegions[k].getTargetColumnFrom() && j <= headerRegions[k].getTargetColumnTo())
                        {
                            headerCell.setHeaderRegion(headerRegions[k]);
                            hasRegion = true;
                        }
                    }

                    if(!hasRegion)
                    {
                        HeaderRegion headerRegion2 = new HeaderRegion();
                        headerRegion2.setTargetRowFrom(i);
                        headerRegion2.setTargetRowTo(i);
                        headerRegion2.setTargetColumnFrom(j);
                        headerRegion2.setTargetColumnTo(j);
                        XSSFCell cell1 = (XSSFCell)sheet.getRow(i).getCell((short) j);
                        headerRegion2.setText(xssfHelper.getCellStringValue(cell1));
                        headerRegion2.setColLength(1);
                        headerRegion2.setRowLength(1);
                        headerCell.setHeaderRegion(headerRegion2);
                    }
//                通过!hasRegion将没有合并的单元格都也有headerRegion,就是自己本身,本身的话下面设置两个变量都是true
//                合并区域的开始行i 和开始列 j 是否是当前单元格的开始行和列
                    headerCell.setAscDisplay((i == headerCell.getHeaderRegion().getTargetRowFrom() && j == headerCell.getHeaderRegion().getTargetColumnFrom()) ? true : false);
//                合并区域的结束行i 和开始列 j 是否是当前单元格的开始行和列
                    headerCell.setDescDisplay((i == headerCell.getHeaderRegion().getTargetRowTo() && j == headerCell.getHeaderRegion().getTargetColumnFrom()) ? true : false);
                    headerCells[i][j] = headerCell;
                }
            }
        }
        return headerCells;
    }

    /**
     * @description 拼接表头样式(报表表头导入)
     * @author 
     * @param headerCells
     * @param flag
     * @return
     */
    @SuppressWarnings("unchecked")
    public Map getHtmlStr(HeaderCell[][] headerCells, int flag) {

        if(headerCells == null || headerCells.length == 0) {
            return null;
        }
        Map map = new HashMap();
        int rowNum = headerCells.length;
        int cellNum = headerCells[0].length;
        String htmlStr = "";
        String cellStr = "";
        List cellList = new ArrayList();
        int width = 0;
        Map cellMap = null;
        int i = 0;
        boolean bool = i < rowNum;
        if(flag == -1)
        {
            i = rowNum - 1;
            bool = i >= 0;
        }
        while(bool)
        {
            for(int j = 0; j < cellNum; j++)
            {
//                通过是否是正序(合并单元格开始行,限制列仅为开始)或者倒序,可以排除合并中不是开始的单元格(不必要的循环)
                boolean bool_tem = flag == -1 ? headerCells[i][j].isDescDisplay(): headerCells[i][j].isAscDisplay();
                if(bool_tem)
                {
                    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
                    cellMap = new HashMap();
                    cellMap.put("title", headerCells[i][j].getText());                                  //标题
                    cellMap.put("headid", uuid);                                                        //唯一id
                    cellMap.put("rowfrom", headerCells[i][j].getHeaderRegion().getTargetRowFrom());     //起始行
                    cellMap.put("colfrom", headerCells[i][j].getHeaderRegion().getTargetColumnFrom());  //起始列
                    cellMap.put("rowto", headerCells[i][j].getHeaderRegion().getTargetRowTo());         //目标行
                    cellMap.put("colto", headerCells[i][j].getHeaderRegion().getTargetColumnTo());      //目标列
                    cellMap.put("colspan", headerCells[i][j].getHeaderRegion().getColLength());         //合并列
                    cellMap.put("rowspan", headerCells[i][j].getHeaderRegion().getRowLength());         //合并行
                    cellMap.put("width", headerCells[i][j].getWidth());         //宽度
                    cellMap.put("height", headerCells[i][j].getHeight());         //高度
                    cellMap.put("bg_color", headerCells[i][j].getBgcolor());         //背景色
                    cellMap.put("font_color", headerCells[i][j].getFontColor());         //字体颜色
                    cellMap.put("font_height", headerCells[i][j].getFontHeight());         //字体大小
                    cellList.add(cellMap);

/*//                    不是倒数第一和第二行循环
//                    添加随机id,方便后面建立父子级关系
                    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
                    if((i != rowNum - 2) && (i != rowNum - 1))
                    {
                        cellMap = new HashMap();
                        cellMap.put("title", headerCells[i][j].getText());                                  //标题
                        cellMap.put("headid", uuid);                                                        //唯一id
                        cellMap.put("rowfrom", headerCells[i][j].getHeaderRegion().getTargetRowFrom());     //起始行
                        cellMap.put("colfrom", headerCells[i][j].getHeaderRegion().getTargetColumnFrom());  //起始列
                        cellMap.put("rowto", headerCells[i][j].getHeaderRegion().getTargetRowTo());         //目标行
                        cellMap.put("colto", headerCells[i][j].getHeaderRegion().getTargetColumnTo());      //目标列
                        cellMap.put("colspan", headerCells[i][j].getHeaderRegion().getColLength());         //合并列
                        cellMap.put("rowspan", headerCells[i][j].getHeaderRegion().getRowLength());         //合并行
                        cellMap.put("width", headerCells[i][j].getWidth());         //宽度
                        cellMap.put("height", headerCells[i][j].getHeight());         //高度
                        cellMap.put("bg_color", headerCells[i][j].getBgcolor());         //背景色
                        cellMap.put("font_color", headerCells[i][j].getFontColor());         //字体颜色
                        cellMap.put("font_height", headerCells[i][j].getFontHeight());         //字体大小
                        cellList.add(cellMap);
                    }
                    if(i == rowNum - 2) //标题对应英文字段(总行数rowNum不变,i变化,总函数减去2就是倒数第二行)
                    {
                        htmlStr +=  "#" + headerCells[i][j].getHeaderRegion().getText() + ">>" + j;
                        width += new Float(headerCells[i][j].getWidth()).intValue() + 20;
                    }
                    else if(i == rowNum - 1)  //英文字段类型
                    {
                        cellStr += "#" + headerCells[i][j].getHeaderRegion().getText() + ">>" + j;
                    }*/
                }
            }
            if(flag == -1)
            {
                i--;
                bool = i >= 0;
            }
            else
            {
                i++;
                bool = i < rowNum;
            }
        }
//        map.put("htmlStr", htmlStr.substring(1));
//        map.put("cellStr", cellStr.substring(1));
        map.put("cellList", cellList);
        map.put("rowNum", rowNum);
//        map.put("width", width);
        return map;
    }
}

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值