前端JavaScript通过ajax请求下载Blob类型文件(XMLHttpRequest)

时间:2021-08-06
本文章向大家介绍前端JavaScript通过ajax请求下载Blob类型文件(XMLHttpRequest),主要包括前端JavaScript通过ajax请求下载Blob类型文件(XMLHttpRequest)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1.前端post请求导出文件

exportFile = function(params, url) {
    let xhr = new XMLHttpRequest();
    xhr.open('POST', url, true);
    xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8');
    xhr.responseType = "blob";  // 返回类型blob
    xhr.send(JSON.stringify(params));   // 发送ajax请求
    xhr.onreadystatechange = function () {
        // 监听属性xhr.readyState每次变化时会触发
        if (xhr.readyState === XMLHttpRequest.DONE) {
            // 响应已返回
            var code = decodeURI(xhr.getResponseHeader("code"));
            console.log(code);
            if (code.toString() === "0") {
                $.messager.alert('提示', "操作成功!");
                // 截取文件名,这里是后端返回了文件名+后缀,如果没有可以自己拼接
                var fileName = decodeURI(xhr.getResponseHeader("content-disposition").split(";")[1].split("=")[1]);
                console.log(fileName);
                // 将`blob`对象转化成一个可访问的`url`
                let dataUrl = window.URL.createObjectURL(new Blob([xhr.response]));
                let link = document.createElement("a");
                link.style.display = "none";
                link.href = dataUrl;
                link.setAttribute("download", fileName);
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
            } else {
                var msg = decodeURI(xhr.getResponseHeader("msg"));
                $.messager.alert('提示', msg);
            }
        }
    }
}

2.后台文件下载接口

2.1.Controller层

/**
 * 导出商品明细
 * @param req
 * @return
 */
@RequestMapping(value = "/exportGoodsRecord.json", method = RequestMethod.POST)
public void exportGoodsRecord(GoodsReq req, HttpServletResponse response, HttpSession session) throws UnsupportedEncodingException {
    try {
        req.setUserId((String) session.getAttribute(Constant.USER_SESSION_KEY));
        goodsService.exportGoodsRecord(req, response);
    } catch (Exception e) {
        log.error("导出商品明细异常", e);
        response.setHeader("code", String.valueOf(HttpStatus.SC_INTERNAL_SERVER_ERROR));
        response.setHeader("msg", URLEncoder.encode(e instanceof BusinessException ? ((BusinessException) e).getMsg() : "未知异常", StandardCharsets.UTF_8.toString()));
    }
}

2.2.Service层

@Override
public void exportGoodsRecord(GoodsReq req, HttpServletResponse response) throws IOException {
    goodsLogic.checkExistsOrElseThrows(req.getUserId(), req.getGoodsId());
    GoodsEntity entity = goodsDao.selectByPrimaryKey(req.getGoodsId());
    String fileName = String.format("%s_%s.%s", entity.getGoodsId(), System.currentTimeMillis(), "xlsx");
    String dirPath = String.format("%s/%s", ConfigUtil.getConf("fps.filepath"), LocalDate.now().format(WeDateUtils.FMT_DATE_SHORT));
    File dir = new File(dirPath);
    if (!dir.exists()) {
        dir.mkdirs();
    }
    File excelFile = new File(String.format("%s/%s", dirPath, fileName));
    goodsLogic.generateDetailFile(excelFile, entity.getGoodsId());
    FileUtil.writeResponse(excelFile, response);
}

2.3.Logic层

@Override
public void checkExistsOrElseThrows(String userId, String goodsId) {
    GoodsEntity entity = dao.selectByPrimaryKey(goodsId);
    if (entity == null) {
        throw new BusinessException("商品ID不存在");
    }
    if (StringUtils.isBlank(userId)) {
        throw new BusinessException("用户未登录");
    }
}

@Override
public void generateDetailFile(File excelFile, String goodsId) throws IOException {
    // 根据操作类型+卡密类型获取CardInfoTypeEnum
    GoodsEntity goodsEntity = dao.selectByPrimaryKey(goodsId);
    CardInfoTypeEnum cardInfoTypeEnum = CardInfoTypeEnum.getUniqueElseThrows(FileOperateType.EXPORT.getCode(),
            StringUtils.defaultIfEmpty(goodsEntity.getSBizType(), "JD_CARD"), TemplateVersionEnum.VERSION1.getCode());

    String sheetName = "卡券商品明细";
    int batchSize = 1000;
    int count = goodsRecordDao.selectCountByGoodsIdAndKind(goodsEntity.getGoodsId(), StringUtils.defaultIfEmpty(goodsEntity.getSBizType(), "JD_CARD"));
    Function<Integer, List<GoodsRecordCellBo>> queryFunction = i -> {
        List<GoodsRecordEntity> list = goodsRecordDao.selectListByGoodsIdAndKind(goodsEntity.getGoodsId(), StringUtils.defaultIfEmpty(goodsEntity.getSBizType(), "JD_CARD"), i * batchSize, batchSize);
        List<GoodsRecordCellBo> returnList = Lists.newArrayList();
        for (GoodsRecordEntity entity : list) {
            GoodsRecordCellBo cell = new GoodsRecordCellBo();
            BeanUtils.copyProperties(entity, cell);
            returnList.add(cell);
        }
        return returnList;
    };
    // 获取卡密类型对应的源文件模板
    Map<Integer, CellEnum> idxToCellMap = cardInfoTypeEnum.getRowCellEnumSupplier().get();
    // 在源文件模板的末尾添加状态,订单id,用户id,用户类型单元格
    idxToCellMap.put(idxToCellMap.keySet().stream().max(Integer::compareTo).orElseThrow(() -> new IllegalArgumentException("导出获取标题行异常")) + 1, CellEnum.STATE);
    idxToCellMap.put(idxToCellMap.keySet().stream().max(Integer::compareTo).orElseThrow(() -> new IllegalArgumentException("导出获取标题行异常")) + 1, CellEnum.EMS_ORDER_ID);
    idxToCellMap.put(idxToCellMap.keySet().stream().max(Integer::compareTo).orElseThrow(() -> new IllegalArgumentException("导出获取标题行异常")) + 1, CellEnum.USER_ID);
    idxToCellMap.put(idxToCellMap.keySet().stream().max(Integer::compareTo).orElseThrow(() -> new IllegalArgumentException("导出获取标题行异常")) + 1, CellEnum.USER_TYPE);
    // 获取导出模板的标题行名称、标题行字段
    String[] headName = new String[idxToCellMap.size()];
    String[] headField = new String[idxToCellMap.size()];
    idxToCellMap.values().stream().map(CellEnum::getHeaderName).collect(Collectors.toList()).toArray(headName);
    idxToCellMap.values().stream().map(CellEnum::getHeaderField).collect(Collectors.toList()).toArray(headField);
    ExcelUtil.writeExcel(excelFile, sheetName, headName, headField, count, batchSize, queryFunction);
}

2.4.FileUtil工具类

public class FileUtil {

    public static File cache(MultipartFile multipartFile, String cacheFileName) throws IOException {
        String dirPath = String.format("%s/%s", ConfigUtil.getConf("fps.filepath"), LocalDate.now().format(WeDateUtils.FMT_DATE_SHORT));
        File dir = new File(dirPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File cacheFile = new File(String.format("%s/%s", dirPath, cacheFileName));
        multipartFile.transferTo(cacheFile);
        return cacheFile;
    }

    public static String getExtensionElseThrows(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        if (StringUtils.isBlank(fileName)) {
            throw new RuntimeException("文件名为空");
        }
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }

    public static void writeResponse(File file, HttpServletResponse response) {
        OutputStream out = null;
        try {
            response.reset();
            response.setContentType("text/csv; charset=gbk");
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "gbk"));
            long fileLength = file.length();
            String length = String.valueOf(fileLength);
            response.setHeader("Content_Length", length);
            response.setHeader("code", "0");
            out = response.getOutputStream();
            out.write(FileUtils.readFileToByteArray(file));
            out.flush();
        } catch (IOException e) {
            OpLogUtil.logOpStepException("文件下载,操作结果返回", "异常", e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    OpLogUtil.logOpStepException("关闭流", "异常", e);
                }
            }
        }
    }
}

2.5.导入导出模板枚举类

**
 * 卡密类型枚举<PK:operateType+cardType+version>
 * operateType: 0导入、1导出
 * cardType: JD_CARD京东卡、XMLY喜马拉雅、SNW水泥网、QXB启信宝
 * version: 1.0卡券导入历史模板、2.0卡券导入模板V2
 * rowCellEnumSupplier:卡密类型对应文件模板的行定义(列号->单元格类型)
 */
public enum CardInfoTypeEnum {

    IMPORT_JD_CARD("0", "京东卡1.0模板导入", "JD_CARD", "1.0", () -> {
        Map<Integer, CellEnum> jdCardHeaderPredicate = new TreeMap<>();
        // 卡号
        jdCardHeaderPredicate.put(0, CellEnum.CARD_NO);
        // 卡密
        jdCardHeaderPredicate.put(1, CellEnum.CARD_PWD);
        // 面额
        jdCardHeaderPredicate.put(2, CellEnum.FACE_VALUE);
        // 有效起始时间
        jdCardHeaderPredicate.put(3, CellEnum.START_TIME);
        // 有效结束时间
        jdCardHeaderPredicate.put(4, CellEnum.END_TIME);
        return jdCardHeaderPredicate;
    }),

    IMPORT_JD_CARD_V2("0", "京东卡2.0模板导入", "JD_CARD", "2.0", () -> {
        Map<Integer, CellEnum> jdCardV2HeaderPredicate = new TreeMap<>();
        // 卡号
        jdCardV2HeaderPredicate.put(0, CellEnum.CARD_NO);
        // 卡密
        jdCardV2HeaderPredicate.put(1, CellEnum.CARD_PWD);
        // 有效起始时间
        jdCardV2HeaderPredicate.put(2, CellEnum.START_TIME);
        // 有效结束时间
        jdCardV2HeaderPredicate.put(3, CellEnum.END_TIME);
        return jdCardV2HeaderPredicate;
    }),

    IMPORT_XMLY_V2("0", "喜马拉雅2.0模板导入", "XMLY", "2.0", () -> {
        Map<Integer, CellEnum> xmlyCardV2HeaderPredicate = new TreeMap<>();
        // 卡号
        xmlyCardV2HeaderPredicate.put(0, CellEnum.CARD_NO);
        // 卡密
        xmlyCardV2HeaderPredicate.put(1, CellEnum.CARD_PWD);
        // 有效起始时间
        xmlyCardV2HeaderPredicate.put(2, CellEnum.START_TIME);
        // 有效结束时间
        xmlyCardV2HeaderPredicate.put(3, CellEnum.END_TIME);
        return xmlyCardV2HeaderPredicate;
    }),

    IMPORT_SNW_V2("0", "水泥网2.0模板导入", "SNW", "2.0", () -> {
        Map<Integer, CellEnum> snwCardV2HeaderPredicate = new TreeMap<>();
        // 卡号
        snwCardV2HeaderPredicate.put(0, CellEnum.CARD_NO);
        // 卡密
        snwCardV2HeaderPredicate.put(1, CellEnum.CARD_PWD);
        // 有效起始时间
        snwCardV2HeaderPredicate.put(2, CellEnum.START_TIME);
        // 有效结束时间
        snwCardV2HeaderPredicate.put(3, CellEnum.END_TIME);
        return snwCardV2HeaderPredicate;
    }),

    IMPORT_QXB_V2("0", "启信宝2.0模板导入", "QXB", "2.0", () -> {
        Map<Integer, CellEnum> qxbCardV2HeaderPredicate = new TreeMap<>();
        // 卡号
        qxbCardV2HeaderPredicate.put(0, CellEnum.CARD_NO);
        // 卡密
        qxbCardV2HeaderPredicate.put(1, CellEnum.CARD_PWD);
        // 有效起始时间
        qxbCardV2HeaderPredicate.put(2, CellEnum.START_TIME);
        // 有效结束时间
        qxbCardV2HeaderPredicate.put(3, CellEnum.END_TIME);
        return qxbCardV2HeaderPredicate;
    }),

    EXPORT_JD_CARD("1", "京东卡明细导出", "JD_CARD", "1.0", () -> {
        Map<Integer, CellEnum> exJdCardHeaderPredicate = new TreeMap<>();
        // 卡号
        exJdCardHeaderPredicate.put(0, CellEnum.CARD_NO);
        // 有效起始时间
        exJdCardHeaderPredicate.put(1, CellEnum.START_TIME);
        // 有效结束时间
        exJdCardHeaderPredicate.put(2, CellEnum.END_TIME);
        return exJdCardHeaderPredicate;
    }),

    EXPORT_XMLY("1", "喜马拉雅明细导出", "XMLY", "1.0", () -> {
        Map<Integer, CellEnum> exXmlyCardHeaderPredicate = new TreeMap<>();
        // 卡号
        exXmlyCardHeaderPredicate.put(0, CellEnum.CARD_NO);
        // 有效起始时间
        exXmlyCardHeaderPredicate.put(1, CellEnum.START_TIME);
        // 有效结束时间
        exXmlyCardHeaderPredicate.put(2, CellEnum.END_TIME);
        return exXmlyCardHeaderPredicate;
    }),

    EXPORT_SNW("1", "水泥网明细导出", "SNW", "1.0", () -> {
        Map<Integer, CellEnum> exSnwCardHeaderPredicate = new TreeMap<>();
        // 卡号
        exSnwCardHeaderPredicate.put(0, CellEnum.CARD_NO);
        // 有效起始时间
        exSnwCardHeaderPredicate.put(1, CellEnum.START_TIME);
        // 有效结束时间
        exSnwCardHeaderPredicate.put(2, CellEnum.END_TIME);
        return exSnwCardHeaderPredicate;
    }),

    EXPORT_QXB("1", "启信宝明细导出", "QXB", "1.0", () -> {
        Map<Integer, CellEnum> exQxbCardHeaderPredicate = new TreeMap<>();
        // 卡号
        exQxbCardHeaderPredicate.put(0, CellEnum.CARD_NO);
        // 有效起始时间
        exQxbCardHeaderPredicate.put(1, CellEnum.START_TIME);
        // 有效结束时间
        exQxbCardHeaderPredicate.put(2, CellEnum.END_TIME);
        return exQxbCardHeaderPredicate;
    });

    private String operateType;
    private String cardTypeDesc;
    private String cardType;
    private String version;
    private Supplier<Map<Integer, CellEnum>> rowCellEnumSupplier;

    public static CardInfoTypeEnum getUniqueElseThrows(String operateType, String cardType, String version) {
        return Arrays.stream(values())
                .filter(e -> e.getOperateType().equals(operateType) && e.getCardType().equals(cardType) && e.getVersion().equals(version))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException(String.format("卡券产品%s未找到模板类型%s", cardType, version)));
    }

    public static String getCardInfoDescDefaultBlank(String operateType, String cardType, String version) {
        Optional<CardInfoTypeEnum> optional = Arrays.stream(values())
                .filter(e -> e.getOperateType().equals(operateType) && e.getCardType().equals(cardType) && e.getVersion().equals(version))
                .findFirst();
        if (optional.isPresent()) {
            return optional.get().getCardTypeDesc();
        }
        return StringUtils.EMPTY;
    }

    CardInfoTypeEnum(String cardTypeDesc, String cardType, String version, Supplier<Map<Integer, CellEnum>> rowCellEnumSupplier) {
        this.cardTypeDesc = cardTypeDesc;
        this.cardType = cardType;
        this.version = version;
        this.rowCellEnumSupplier = rowCellEnumSupplier;
    }

    CardInfoTypeEnum(String operateType, String cardTypeDesc, String cardType, String version, Supplier<Map<Integer, CellEnum>> rowCellEnumSupplier) {
        this.operateType = operateType;
        this.cardTypeDesc = cardTypeDesc;
        this.cardType = cardType;
        this.version = version;
        this.rowCellEnumSupplier = rowCellEnumSupplier;
    }

    public String getOperateType() {
        return operateType;
    }

    public String getCardTypeDesc() {
        return cardTypeDesc;
    }

    public String getCardType() {
        return cardType;
    }

    public String getVersion() {
        return version;
    }

    public Supplier<Map<Integer, CellEnum>> getRowCellEnumSupplier() {
        return rowCellEnumSupplier;
    }
}

2.6.单元格枚举类

/**
 * 单元格枚举
 * headerName:单元格所属标题列名
 * headerField:单元格所属列映射POJO字段
 * cellPredicate:单元格内容检查规则
 * copyPropsConsumer:单元格转DTO实体
 * Create by v_wbqsliu on 2021/8/2
 */
public enum CellEnum {

    CARD_NO("卡号", "cardNo", ExcelUtil.cellStrNotBlank(), (cell, object) -> {
        CardInfoDto dto = (CardInfoDto) object;
        dto.setCardNo(ExcelUtil.parseStr(cell, null));
    }),

    CARD_PWD("卡密", "cardPwd", ExcelUtil.cellStrNotBlank(), (cell, object) -> {
        CardInfoDto dto = (CardInfoDto) object;
        dto.setCardPwd(ExcelUtil.parseStr(cell, null));
    }),

    FACE_VALUE("面额", "faceValue", ExcelUtil.cellPositiveDouble(), (cell, object) -> {
        CardInfoDto dto = (CardInfoDto) object;
        dto.setFaceValue(ExcelUtil.parseStr(cell, null));
    }),

    START_TIME("有效起始时间", "startTime", e -> true, (cell, object) -> {
        CardInfoDto dto = (CardInfoDto) object;
        dto.setStartTime(ExcelUtil.parseStr(cell, null));
    }),

    END_TIME("有效结束时间", "endTime", e -> true, (cell, object) -> {
        CardInfoDto dto = (CardInfoDto) object;
        dto.setEndTime(ExcelUtil.parseStr(cell, null));
    }),

    STATE("状态", "state", e -> true, (cell, object) -> {
    }),

    EMS_ORDER_ID("订单ID", "emsOrderId", e -> true, (cell, object) -> {
    }),

    USER_ID("用户ID", "userId", e -> true, (cell, object) -> {
    }),

    USER_TYPE("用户类型", "userType", e -> true, (cell, object) -> {
    });

    private String headerName;
    private String headerField;
    private Predicate<Cell> cellPredicate;
    private BiConsumer<Cell, Object> copyPropsConsumer;

    CellEnum(String headerName, String headerField, Predicate<Cell> cellPredicate, BiConsumer<Cell, Object> copyPropsConsumer) {
        this.headerName = headerName;
        this.headerField = headerField;
        this.cellPredicate = cellPredicate;
        this.copyPropsConsumer = copyPropsConsumer;
    }

    public String getHeaderName() {
        return headerName;
    }

    public String getHeaderField() {
        return headerField;
    }

    public Predicate<Cell> getCellPredicate() {
        return cellPredicate;
    }

    public BiConsumer<Cell, Object> getCopyPropsConsumer() {
        return copyPropsConsumer;
    }
}

附:ExcelUtil工具类

1.集成了Excel文件的读取和写入、内容解析和检查相关操作

public class ExcelUtil {

    private static final String XLS = "xls";
    private static final String XLSX = "xlsx";
    public static final String PATTERN_ZERO_DIGIT = "0";
    public static final int MAX_ROWS_LENGTH = 60000;

    public static Set<String> workbookWrongIdxs(File localFile, Map<Integer, CellEnum> cellPredicateMap) throws IOException {
        return ExcelUtil.traverse(localFile, (Function<Workbook, Set<String>>) workbook -> wrongSheetRows(workbook, row -> row != null && row.getRowNum() == 0, row -> hasError(row, cellPredicateMap)));
    }

    public static boolean workbookSeekTitle(File localFile, String title) throws IOException {
        return ExcelUtil.traverse(localFile, (Function<Workbook, Boolean>) workbook -> hasCertainTitle(workbook, cell -> StringUtils.equals(title, parseStr(cell, null))));
    }

    public static <T> T traverse(File excelFile, Function<Workbook, T> function)
            throws IOException {
        Workbook workbook = null;
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(excelFile);
            workbook = getWorkbook(inputStream, excelFile);
            return function.apply(workbook);
        } finally {
            try {
                if (null != workbook) {
                    workbook.close();
                }
                if (null != inputStream) {
                    inputStream.close();
                }
            } catch (Exception e) {
                OpLogUtil.logOpStepException("关闭流", "异常", e);
            }
        }
    }

    public static boolean traverse(File excelFile, Consumer<Workbook> consumer) throws IOException {
        Workbook workbook = null;
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(excelFile);
            workbook = getWorkbook(excelFile);
            consumer.accept(workbook);
            workbook.write(outputStream);
            return true;
        } finally {
            try {
                if (null != workbook) {
                    workbook.close();
                }
                if (null != outputStream) {
                    outputStream.close();
                }
            } catch (Exception e) {
                OpLogUtil.logOpStepException("关闭流", "异常", e);
            }
        }
    }

    public static <T> boolean writeExcel(File excelFile, String sheetName, String[] headName, String[] headKey, int count,
                                         int batchSize, Function<Integer, List<T>> queryFunction) throws IOException {
        return ExcelUtil.traverse(excelFile, workbook -> {
            // 生成表头
            generateExcelTitle(workbook, sheetName, headName, headKey, count);
            // 生成数据
            int times = count / batchSize + 1;// 需要写入次数
            for (int i = 0; i < times; i++) {
                // 从sheetName页第batchSize*i+1追加写入数据
                int startRow = batchSize * i + 1;
                List<T> dataList = queryFunction.apply(i);
                generateExcelData(workbook, sheetName, headKey, dataList, startRow);
            }
        });
    }

    public static void generateExcelTitle(Workbook workbook, String sheetName, String[] headName, String[] headKey, int count) {
        if (count <= 0) {
            throw new BusinessException("数据为空,无需生成");
        }
        if (headName.length == 0 || headKey.length == 0) {
            throw new BusinessException("表头为空,无需生成");
        }
        if (headName.length != headKey.length) {
            throw new BusinessException("表头数与要求生成数不一致");
        }
        writeSheetRows(workbook, sheetName, Collections.singletonList(Arrays.asList(headName)), 0);
    }

    public static void generateExcelData(Workbook workbook, String sheetName, String[] headKey, List dataList, int startRow) {
        List<List<Object>> dataObjList = new ArrayList<>();
        try {
            Iterator iterator = dataList.listIterator();
            while (iterator.hasNext()) {
                List<Object> data = new ArrayList<>();
                Object obj = iterator.next();
                Field[] fields = obj.getClass().getDeclaredFields();
                for (int j = 0; j < headKey.length; j++) {
                    for (int i = 0; i < fields.length; i++) {
                        if (fields[i].getName().equals(headKey[j])) {
                            fields[i].setAccessible(true);
                            if (fields[i].get(obj) == null) {
                                data.add("");
                                break;
                            }
                            data.add(fields[i].get(obj).toString());
                            break;
                        }
                    }
                }
                dataObjList.add(data);
            }
        } catch (Exception e) {
            OpLogUtil.logOpStepException("Excel数据转换", "异常", e);
        }
        writeSheetRows(workbook, sheetName, dataObjList, startRow);
    }


    private static void writeRow(List<Object> rowObj, Row row) {
        for (int i = 0; i < rowObj.size(); i++) {
            row.createCell((short) i).setCellValue(rowObj.get(i).toString());
        }
    }

    /**
     * 由于xls表格页有最大长度的限制(65535),因此每6w条数据分成一页
     *
     * 说明:startRow(开始行号)必须大于等于currRows(当前sheet页已有数据行数),否则,
     * 条件i + currRows >= MAX_ROWS_LENGTH 一直满足,递归方法进入死循环,导致 StackOverflowError
     *
     * @param workbook    工作簿
     * @param sheetName   sheet名称
     * @param dataObjList 待处理数据
     * @param startRow    开始行号
     */
    private static void writeSheetRows(Workbook workbook, String sheetName, List<List<Object>> dataObjList, int startRow) {
        String newSheetName = startRow < MAX_ROWS_LENGTH ? sheetName : sheetName + startRow / MAX_ROWS_LENGTH;
        Sheet sheet = workbook.getSheet(newSheetName);
        if (sheet == null) {
            sheet = workbook.createSheet(newSheetName);
            sheet.setDefaultColumnWidth(20);
            sheet.setDefaultRowHeight((short) (2 * 256));
        }
        int currRows = sheet.getPhysicalNumberOfRows();
        for (int i = 0; i < dataObjList.size(); i++) {
            if (i + currRows >= MAX_ROWS_LENGTH) {
                writeSheetRows(workbook, sheetName,
                        new ArrayList(dataObjList.subList(i, dataObjList.size())), i + startRow);
                break;
            }
            List<Object> rowObj = dataObjList.get(i);
            Row row = sheet.createRow(i + currRows);
            ExcelUtil.writeRow(rowObj, row);
        }
    }

    public static <T> List<T> parseWorkbookData(Workbook workbook, Predicate<Row> shouldSkip, Function<Row, T> rowTransform) {
        List<T> list = new ArrayList<>();
        for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
            // 获取sheet
            Sheet sheet = workbook.getSheetAt(sheetNum);
            if (sheet == null) {
                continue;
            }
            // 遍历行
            int firstRow = sheet.getFirstRowNum();
            int endRow = sheet.getPhysicalNumberOfRows();
            for (int rowNum = firstRow; rowNum < endRow; rowNum++) {
                Row row = sheet.getRow(rowNum);
                if (row == null || shouldSkip.test(row)) {
                    continue;
                }
                list.add(rowTransform.apply(row));
            }
        }
        return list;
    }

    public static Predicate<Cell> cellStrNotBlank() {
        return cell -> {
            String str = ExcelUtil.cellToString(cell, ExcelUtil.PATTERN_ZERO_DIGIT);
            return StringUtils.isNotBlank(str);
        };
    }

    public static Predicate<Cell> cellPositiveDouble() {
        return cell -> {
            String str = ExcelUtil.cellToString(cell, null);
            return StringUtils.isNotBlank(str) && Double.parseDouble(str) > 0;
        };
    }

    public static String parseStr(Cell cell) {
        return ExcelUtil.cellToString(cell, ExcelUtil.PATTERN_ZERO_DIGIT);
    }

    public static String parseStr(Cell cell, String decimalFormatPattern) {
        return ExcelUtil.cellToString(cell, decimalFormatPattern);
    }

    private static String cellToString(Cell cell, String decimalFormatPattern) {
        if (cell == null) {
            return null;
        }

        String returnValue = null;
        switch (cell.getCellType()) {
            case NUMERIC:
                Double doubleValue = cell.getNumericCellValue();
                if (StringUtils.isBlank(decimalFormatPattern)) {
                    return String.valueOf(doubleValue);
                }
                DecimalFormat df = new DecimalFormat(decimalFormatPattern);
                returnValue = df.format(doubleValue);
                break;
            case STRING:
                returnValue = cell.getStringCellValue();
                break;
            case BOOLEAN:
                boolean booleanValue = cell.getBooleanCellValue();
                returnValue = Boolean.toString(booleanValue);
                break;
            case FORMULA:
                returnValue = cell.getCellFormula();
                break;
            default:
                break;
        }
        return returnValue;
    }

    private static Workbook getWorkbook(InputStream inputStream, File excelFile) throws IOException {
        String extension = excelFile.getAbsolutePath().substring(excelFile.getAbsolutePath().lastIndexOf(".") + 1);
        switch (extension) {
            case XLS:
                return new HSSFWorkbook(inputStream);
            case XLSX:
                return new XSSFWorkbook(inputStream);
            default:
                throw new IllegalArgumentException(String.format("%s|%s", "EXCEL文件扩展名有误", extension));
        }
    }

    private static Workbook getWorkbook(File excelFile) {
        String extension = excelFile.getAbsolutePath().substring(excelFile.getAbsolutePath().lastIndexOf(".") + 1);
        switch (extension) {
            case XLS:
                return new HSSFWorkbook();
            case XLSX:
                return new XSSFWorkbook();
            default:
                throw new IllegalArgumentException(String.format("%s|%s", "EXCEL文件扩展名有误", extension));
        }
    }

    private static boolean hasCertainTitle(Workbook workbook, Predicate<Cell> hasCertain) {
        for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
            // 获取sheet
            Sheet sheet = workbook.getSheetAt(sheetNum);
            if (sheet == null) {
                continue;
            }
            // 获取表头
            Row row = sheet.getRow(0);
            if (row != null) {
                Cell cell = null;
                int cellIdx = 0;
                Iterator<Cell> iterator = row.cellIterator();
                while (iterator.hasNext()) {
                    cell = iterator.next();
                    if (hasCertain.test(cell)) {
                        return true;
                    }
                    cellIdx++;
                }
            }
        }
        return false;
    }

    private static Set<String> wrongSheetRows(Workbook workbook, Predicate<Row> shouldSkip, Predicate<Row> hasError) {
        Set<String> errorSheetRow = new HashSet<>();
        for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
            // 获取sheet
            Sheet sheet = workbook.getSheetAt(sheetNum);
            if (sheet == null) {
                continue;
            }
            // 遍历行
            int firstRow = sheet.getFirstRowNum();
            int endRow = sheet.getPhysicalNumberOfRows();
            for (int rowNum = firstRow; rowNum < endRow; rowNum++) {
                Row row = sheet.getRow(rowNum);
                if (shouldSkip.test(row)) {
                    continue;
                }
                if (hasError.test(row)) {
                    errorSheetRow.add(String.format("sheet%s_row%s:%s", sheetNum, rowNum, ExcelUtil.rowContent(row)));
                }
            }
        }
        return errorSheetRow;
    }

    private static String rowContent(Row row) {
        StringBuilder sb = new StringBuilder();
        row.forEach(cell -> sb.append(cellToString(cell, null)).append("|"));
        return sb.toString();
    }

    public static boolean hasError(Row row, Map<Integer/*cellIdx*/, CellEnum> cellPredicateMap) {
        Cell cell = null;
        try {
            int cellIdx = 0;
            Iterator<Cell> iterator = row.cellIterator();
            while (iterator.hasNext()) {
                cell = iterator.next();
                if (!cellPredicateMap.get(cellIdx).getCellPredicate().test(cell)) {
                    return true;
                }
                cellIdx++;
            }
        } catch (Exception e) {
            OpLogUtil.logOpStepException("Excel行Cell检查", "异常", e, cell);
            return true;
        }
        return false;
    }
}

2.ExcelUtil工具类使用说明

Excel工具类的相关使用说明,请参考链接:Java生成并下载Excel文件-工具类

本文来自博客园,作者:冰枫丶,转载请注明原文链接:https://www.cnblogs.com/yydscn/p/15108059.html

原文地址:https://www.cnblogs.com/yydscn/p/15108059.html