【easypoi 一对多导入解决方案】

news2024/9/30 9:28:11

easypoi 一对多导入解决方案

  • 1.需求
  • 2.复现问题
    • 2.1校验时获取不到一对多中多的完整数据
    • 2.2控制台报错 Cannot add merged region B5:B7 to sheet because it overlaps with an existing merged region (B3:B5).
  • 3.如何解决
    • 第二个问题处理: Cannot add merged region B5:B7 to sheet because it overlaps with an existing merged region (B3:B5).
    • 第一个问题处理,校验时获取不到一对多中多的完整数据
  • 3 完整环境
    • 3.1 ImportController
    • 3.2 MyExcelImportService
    • 3.3 Maven 依赖
  • 4.git 完整代码

1.需求

在这里插入图片描述

  • 把如图的数据导入,
    (1)校验姓名长度不能大于 100
    (2)校验每一行次数 + 费用之和不能大于等于 10
    (3)提示哪一行报错了
  • 首先是一个一对多的导入,其次提示哪一行报错使用 ExcelImportUtil.importExcelMore().getFailWorkbook() 方法生成一个问题 excel 到服务器本地,再写一个下载失败文档的接口,让用户下载即可;
  • 但是在在导入的时候报错,Cannot add merged region B5:B7 to sheet because it overlaps with an existing merged region (B3:B5).,且在校验每一行次数 + 费用之和不能大于等于 10时只能获取第一行的数据。

2.复现问题

上代码

package com.example.myeasypoi;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelCollection;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult;
import cn.afterturn.easypoi.handler.inter.IExcelDataModel;
import cn.afterturn.easypoi.handler.inter.IExcelModel;
import cn.afterturn.easypoi.handler.inter.IExcelVerifyHandler;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.hibernate.validator.constraints.Length;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.util.Date;
import java.util.List;

@RestController
public class ImportController {
    public static void main(String[] args) throws Exception {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/study/code_source/my-easypoi/src/main/resources/ExcelExportTemplateMyNestedLoop.xlsx"));
        ImportParams importParams = new ImportParams();
        importParams.setHeadRows(2);
        importParams.setNeedVerify(true);
        importParams.setVerifyHandler(new MyVerifyHandler());
        ExcelImportResult<Object> result = ExcelImportUtil.importExcelMore(bis, MyPojo.class, importParams);
        System.out.println(result);
    }

    @Data
    public static class MyPojo extends Traffic implements IExcelDataModel, IExcelModel{
        /**
         * 行号
         */
        private int rowNum;

        /**
         * 错误消息
         */
        private String errorMsg;

        @Override
        public String getErrorMsg() {
            return errorMsg;
        }

        @Override
        public void setErrorMsg(String s) {
            this.errorMsg =s;
        }

        @Override
        public Integer getRowNum() {
            return rowNum;
        }

        @Override
        public void setRowNum(Integer rowNum) {
            this.rowNum = rowNum;
        }
    }


    public static class MyVerifyHandler implements IExcelVerifyHandler<MyPojo> {

        @Override
        public ExcelVerifyHandlerResult verifyHandler(MyPojo myPojo) {
            StringBuilder sb = new StringBuilder();
            List<TrafficDetail> shareBikes = myPojo.getShareBikes();
            List<TrafficDetail> subways = myPojo.getSubways();
            if (CollectionUtils.isNotEmpty(shareBikes)){
                shareBikes.forEach(shareBike -> {
                    if(getSum(shareBike.getNumber(),shareBike.getCost())>=10){
                        sb.append("共享单车次数和费用之和大于 10");
                    }
                });
            }
            if(CollectionUtils.isNotEmpty(subways)){
                subways.forEach(subway -> {
                    if(getSum(subway.getNumber(),subway.getCost()) >=10){
                        sb.append("地铁次数和费用之和大于 10");
                    }
                });
            }
            if(sb.length()!= 0){
                return  new ExcelVerifyHandlerResult(false,sb.toString());
            }
            return new ExcelVerifyHandlerResult(true);
        }
        private int getSum(Integer a ,Integer b){
            return (a == null ? 0 : a) + (b == null ? 0 : b);
        }
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Traffic{

        @Excel(name = "序号")
        private Integer id;
        @Excel(name = "姓名")
        @Length(max = 100,message = "姓名长度不能大于 100")
        private String name;
        @Excel(name = "日期",format = "yyyy-MM-dd")
        private Date date;
        @ExcelCollection(name = "共享单车")
        private List<TrafficDetail> shareBikes;
        @ExcelCollection(name = "地铁")
        private List<TrafficDetail> subways;
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class TrafficDetail{
        @Excel(name = "次数")
        private Integer number;
        @Excel(name = "费用")
        private Integer cost;

    }
}

2.1校验时获取不到一对多中多的完整数据

在这里插入图片描述

2.2控制台报错 Cannot add merged region B5:B7 to sheet because it overlaps with an existing merged region (B3:B5).

在这里插入图片描述
easypoi 是先校验,再获取值,所以第二个报错在我放开第一个断点后出现。

3.如何解决

第二个问题处理: Cannot add merged region B5:B7 to sheet because it overlaps with an existing merged region (B3:B5).

在这里插入图片描述

首先 ImportExcelMore 实际调用的 new ExcelImportService().importExcelByIs(inputstream, pojoClass, params, true);查看代码逻辑,是因为ExcelImportService.removeSuperfluousRows 错误
在这里插入图片描述
如何改呢,上代码,就是继承 ExcelImportService 类,重写这部分代码,然后在调研时候直接用自己写的 类;

/**
 * Copyright 2013-2015 JueYue (qrb.jueyue@gmail.com)
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.example.myeasypoi;

import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelCollectionParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelImportEntity;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult;
import cn.afterturn.easypoi.entity.BaseTypeConstants;
import cn.afterturn.easypoi.excel.imports.CellValueService;
import cn.afterturn.easypoi.excel.imports.ExcelImportService;
import cn.afterturn.easypoi.excel.imports.base.ImportBaseService;
import cn.afterturn.easypoi.excel.imports.recursive.ExcelImportForkJoinWork;
import cn.afterturn.easypoi.exception.excel.ExcelImportException;
import cn.afterturn.easypoi.exception.excel.enums.ExcelImportEnum;
import cn.afterturn.easypoi.handler.inter.IExcelDataModel;
import cn.afterturn.easypoi.handler.inter.IExcelModel;
import cn.afterturn.easypoi.util.PoiCellUtil;
import cn.afterturn.easypoi.util.PoiPublicUtil;
import cn.afterturn.easypoi.util.PoiReflectorUtil;
import cn.afterturn.easypoi.util.PoiValidationUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ForkJoinPool;

/**
 * Excel 导入服务
 *
 * @author JueYue 2014年6月26日 下午9:20:51
 */
@SuppressWarnings({"rawtypes", "unchecked", "hiding"})
public class MyExcelImportService extends ExcelImportService {

    private final static Logger LOGGER = LoggerFactory.getLogger(MyExcelImportService.class);

    private CellValueService cellValueServer;

    private boolean   verifyFail = false;
    /**
     * 异常数据styler
     */
    private CellStyle errorCellStyle;

    private List<Row> successRow;
    private List<Row> failRow;
    private List      failCollection;

    public MyExcelImportService() {
        successRow = new ArrayList<Row>();
        failRow = new ArrayList<Row>();
        failCollection = new ArrayList();
        this.cellValueServer = new CellValueService();
    }

    /***
     * 向List里面继续添加元素
     *
     * @param object
     * @param param
     * @param row
     * @param titlemap
     * @param targetId
     * @param pictures
     * @param params
     */
    public void addListContinue(Object object, ExcelCollectionParams param, Row row,
                                Map<Integer, String> titlemap, String targetId,
                                Map<String, PictureData> pictures,
                                ImportParams params, StringBuilder errorMsg) throws Exception {
        Collection collection = (Collection) PoiReflectorUtil.fromCache(object.getClass())
                .getValue(object, param.getName());
        Object entity = PoiPublicUtil.createObject(param.getType(), targetId);
        if (entity instanceof IExcelDataModel) {
            ((IExcelDataModel) entity).setRowNum(row.getRowNum());
        }
        String picId;
        // 是否需要加上这个对象
        boolean isUsed = false;
        for (int i = row.getFirstCellNum(); i < titlemap.size(); i++) {
            Cell   cell        = row.getCell(i);
            String titleString = (String) titlemap.get(i);
            if (param.getExcelParams().containsKey(titleString)) {
                if (param.getExcelParams().get(titleString).getType() == BaseTypeConstants.IMAGE_TYPE) {
                    picId = row.getRowNum() + "_" + i;
                    saveImage(entity, picId, param.getExcelParams(), titleString, pictures, params);
                } else {
                    try {
                        saveFieldValue(params, entity, cell, param.getExcelParams(), titleString, row);
                    } catch (ExcelImportException e) {
                        // 如果需要去校验就忽略,这个错误,继续执行
                        if (params.isNeedVerify() && ExcelImportEnum.GET_VALUE_ERROR.equals(e.getType())) {
                            errorMsg.append(" ").append(titleString).append(ExcelImportEnum.GET_VALUE_ERROR.getMsg());
                        }
                    }
                }
                isUsed = true;
            }
        }
        if (isUsed) {
            collection.add(entity);
        }
    }

    /**
     * 获取key的值,针对不同类型获取不同的值
     *
     * @author JueYue 2013-11-21
     */
    private String getKeyValue(Cell cell) {
        Object obj = PoiCellUtil.getCellValue(cell);
        return obj == null ? null : obj.toString().trim();
    }

    /**
     * 获取保存的真实路径
     */
    private String getSaveUrl(ExcelImportEntity excelImportEntity, Object object) throws Exception {
        String url = "";
        if (ExcelImportEntity.IMG_SAVE_PATH.equals(excelImportEntity.getSaveUrl())) {
            if (excelImportEntity.getMethods() != null
                    && excelImportEntity.getMethods().size() > 0) {
                object = getFieldBySomeMethod(excelImportEntity.getMethods(), object);
            }
            url = object.getClass().getName()
                    .split("\\.")[object.getClass().getName().split("\\.").length - 1];
            return excelImportEntity.getSaveUrl() + File.separator + url;
        }
        return excelImportEntity.getSaveUrl();
    }

    private <T> List<T> importExcel(Collection<T> result, Sheet sheet, Class<?> pojoClass,
                                    ImportParams params,
                                    Map<String, PictureData> pictures) throws Exception {
        List                           collection      = new ArrayList();
        Map<String, ExcelImportEntity> excelParams     = new HashMap<>();
        List<ExcelCollectionParams>    excelCollection = new ArrayList<>();
        String                         targetId        = null;
        i18nHandler = params.getI18nHandler();
        boolean isMap = Map.class.equals(pojoClass);
        if (!isMap) {
            Field[]     fileds  = PoiPublicUtil.getClassFields(pojoClass);
            ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class);
            if (etarget != null) {
                targetId = etarget.value();
            }
            getAllExcelField(targetId, fileds, excelParams, excelCollection, pojoClass, null, null);
        }
        Iterator<Row> rows = sheet.rowIterator();
        for (int j = 0; j < params.getTitleRows(); j++) {
            rows.next();
        }
        Map<Integer, String> titlemap = getTitleMap(rows, params, excelCollection, excelParams);
        checkIsValidTemplate(titlemap, excelParams, params, excelCollection);
        Row    row     = null;
        Object object  = null;
        String picId;
        int    readRow = 1;
        //跳过无效行
        for (int i = 0; i < params.getStartRows(); i++) {
            rows.next();
        }
        //判断index 和集合,集合情况默认为第一列
        if (excelCollection.size() > 0 && params.getKeyIndex() == null) {
            params.setKeyIndex(0);
        }
        int          endRow       = sheet.getLastRowNum() - params.getLastOfInvalidRow();
        if (params.getReadRows() > 0) {
            endRow = Math.min(params.getReadRows(), endRow);
        }
        if (params.isConcurrentTask()) {
            ForkJoinPool forkJoinPool = new ForkJoinPool();
            ExcelImportForkJoinWork task           = new ExcelImportForkJoinWork(params.getStartRows() + params.getHeadRows() + params.getTitleRows(), endRow, sheet, params, pojoClass, this, targetId, titlemap, excelParams);
            ExcelImportResult       forkJoinResult = forkJoinPool.invoke(task);
            collection = forkJoinResult.getList();
            failCollection = forkJoinResult.getFailList();
        } else {
            StringBuilder errorMsg;
            while (rows.hasNext()) {
                row = rows.next();
                // Fix 如果row为无效行时候跳出
                if (row.getRowNum() > endRow) {
                    break;
                }
                /* 如果当前行的单元格都是无效的,那就继续下一行 */
                if (row.getLastCellNum()<0) {
                    continue;
                }
                if(isMap && object != null) {
                    ((Map) object).put("excelRowNum", row.getRowNum());
                }
                errorMsg = new StringBuilder();
                // 判断是集合元素还是不是集合元素,如果是就继续加入这个集合,不是就创建新的对象
                // keyIndex 如果为空就不处理,仍然处理这一行
                if (params.getKeyIndex() != null
                        && (row.getCell(params.getKeyIndex()) == null
                        || StringUtils.isEmpty(getKeyValue(row.getCell(params.getKeyIndex()))))
                        && object != null) {
                    for (ExcelCollectionParams param : excelCollection) {
                        addListContinue(object, param, row, titlemap, targetId, pictures, params, errorMsg);
                    }
                } else {
                    object = PoiPublicUtil.createObject(pojoClass, targetId);
                    try {
                        Set<Integer> keys = titlemap.keySet();
                        for (Integer cn : keys) {
                            Cell   cell        = row.getCell(cn);
                            String titleString = (String) titlemap.get(cn);
                            if (excelParams.containsKey(titleString) || isMap) {
                                if (excelParams.get(titleString) != null
                                        && excelParams.get(titleString).getType() == BaseTypeConstants.IMAGE_TYPE) {
                                    picId = row.getRowNum() + "_" + cn;
                                    saveImage(object, picId, excelParams, titleString, pictures,
                                            params);
                                } else {
                                    try {
                                        saveFieldValue(params, object, cell, excelParams, titleString, row);
                                    } catch (ExcelImportException e) {
                                        // 如果需要去校验就忽略,这个错误,继续执行
                                        if (params.isNeedVerify() && ExcelImportEnum.GET_VALUE_ERROR.equals(e.getType())) {
                                            errorMsg.append(" ").append(titleString).append(ExcelImportEnum.GET_VALUE_ERROR.getMsg());
                                        }
                                    }
                                }
                            }
                        }
                        //for (int i = row.getFirstCellNum(), le = titlemap.size(); i < le; i++) {

                        //}
                        if (object instanceof IExcelDataModel) {
                            ((IExcelDataModel) object).setRowNum(row.getRowNum());
                        }
                        for (ExcelCollectionParams param : excelCollection) {
                            addListContinue(object, param, row, titlemap, targetId, pictures, params, errorMsg);
                        }
                        if (verifyingDataValidity(object, row, params, isMap, errorMsg)) {
                            collection.add(object);
                        } else {
                            failCollection.add(object);
                        }
                    } catch (ExcelImportException e) {
                        LOGGER.error("excel import error , row num:{},obj:{}", readRow, ReflectionToStringBuilder.toString(object));
                        if (!e.getType().equals(ExcelImportEnum.VERIFY_ERROR)) {
                            throw new ExcelImportException(e.getType(), e);
                        }
                    } catch (Exception e) {
                        LOGGER.error("excel import error , row num:{},obj:{}", readRow, ReflectionToStringBuilder.toString(object));
                        throw new RuntimeException(e);
                    }
                }
                readRow++;
            }
        }
        return collection;
    }

    /**
     * 校验数据合法性
     */
    public boolean verifyingDataValidity(Object object, Row row, ImportParams params,
                                         boolean isMap, StringBuilder fieldErrorMsg) {
        boolean isAdd = true;
        Cell    cell  = null;
        if (params.isNeedVerify()) {
            String errorMsg = PoiValidationUtil.validation(object, params.getVerifyGroup());
            if (StringUtils.isNotEmpty(errorMsg)) {
                cell = row.createCell(row.getLastCellNum());
                cell.setCellValue(errorMsg);
                if (object instanceof IExcelModel) {
                    IExcelModel model = (IExcelModel) object;
                    model.setErrorMsg(errorMsg);
                }
                isAdd = false;
                verifyFail = true;
            }
        }
        if (params.getVerifyHandler() != null) {
            ExcelVerifyHandlerResult result = params.getVerifyHandler().verifyHandler(object);
            if (!result.isSuccess()) {
                if (cell == null) {
                    cell = row.createCell(row.getLastCellNum());
                }
                cell.setCellValue((StringUtils.isNoneBlank(cell.getStringCellValue())
                        ? cell.getStringCellValue() + "," : "") + result.getMsg());
                if (object instanceof IExcelModel) {
                    IExcelModel model = (IExcelModel) object;
                    model.setErrorMsg((StringUtils.isNoneBlank(model.getErrorMsg())
                            ? model.getErrorMsg() + "," : "") + result.getMsg());
                }
                isAdd = false;
                verifyFail = true;
            }
        }
        if ((params.isNeedVerify() || params.getVerifyHandler() != null) && fieldErrorMsg.length() > 0) {
            if (object instanceof IExcelModel) {
                IExcelModel model = (IExcelModel) object;
                model.setErrorMsg((StringUtils.isNoneBlank(model.getErrorMsg())
                        ? model.getErrorMsg() + "," : "") + fieldErrorMsg.toString());
            }
            if (cell == null) {
                cell = row.createCell(row.getLastCellNum());
            }
            cell.setCellValue((StringUtils.isNoneBlank(cell.getStringCellValue())
                    ? cell.getStringCellValue() + "," : "") + fieldErrorMsg.toString());
            isAdd = false;
            verifyFail = true;
        }
        if (cell != null) {
            cell.setCellStyle(errorCellStyle);
            failRow.add(row);
            if(isMap) {
                ((Map) object).put("excelErrorMsg", cell.getStringCellValue());
            }
        } else {
            successRow.add(row);
        }
        return isAdd;
    }

    /**
     * 获取表格字段列名对应信息
     */
    private Map<Integer, String> getTitleMap(Iterator<Row> rows, ImportParams params,
                                             List<ExcelCollectionParams> excelCollection,
                                             Map<String, ExcelImportEntity> excelParams) {
        Map<Integer, String>  titlemap         = new LinkedHashMap<Integer, String>();
        Iterator<Cell>        cellTitle;
        String                collectionName   = null;
        ExcelCollectionParams collectionParams = null;
        Row                   row              = null;
        for (int j = 0; j < params.getHeadRows(); j++) {
            row = rows.next();
            if (row == null) {
                continue;
            }
            cellTitle = row.cellIterator();
            while (cellTitle.hasNext()) {
                Cell   cell  = cellTitle.next();
                String value = getKeyValue(cell);
                value = value.replace("\n", "");
                int i = cell.getColumnIndex();
                //用以支持重名导入
                if (StringUtils.isNotEmpty(value)) {
                    if (titlemap.containsKey(i)) {
                        collectionName = titlemap.get(i);
                        collectionParams = getCollectionParams(excelCollection, collectionName);
                        titlemap.put(i, collectionName + "_" + value);
                    } else if (StringUtils.isNotEmpty(collectionName) && collectionParams != null
                            && collectionParams.getExcelParams()
                            .containsKey(collectionName + "_" + value)) {
                        titlemap.put(i, collectionName + "_" + value);
                    } else {
                        collectionName = null;
                        collectionParams = null;
                    }
                    if (StringUtils.isEmpty(collectionName)) {
                        titlemap.put(i, value);
                    }
                }
            }
        }

        // 处理指定列的情况
        Set<String> keys = excelParams.keySet();
        for (String key : keys) {
            if (key.startsWith("FIXED_")) {
                String[] arr = key.split("_");
                titlemap.put(Integer.parseInt(arr[1]), key);
            }
        }
        return titlemap;
    }

    /**
     * 获取这个名称对应的集合信息
     */
    private ExcelCollectionParams getCollectionParams(List<ExcelCollectionParams> excelCollection,
                                                      String collectionName) {
        for (ExcelCollectionParams excelCollectionParams : excelCollection) {
            if (collectionName.equals(excelCollectionParams.getExcelName())) {
                return excelCollectionParams;
            }
        }
        return null;
    }

    /**
     * Excel 导入 field 字段类型 Integer,Long,Double,Date,String,Boolean
     */
    public ExcelImportResult importExcelByIs(InputStream inputstream, Class<?> pojoClass,
                                             ImportParams params, boolean needMore) throws Exception {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Excel import start ,class is {}", pojoClass);
        }
        List<T>               result = new ArrayList<T>();
        ByteArrayOutputStream baos   = new ByteArrayOutputStream();
        ExcelImportResult     importResult;
        try {
            byte[] buffer = new byte[1024];
            int    len;
            while ((len = inputstream.read(buffer)) > -1) {
                baos.write(buffer, 0, len);
            }
            baos.flush();

            InputStream userIs = new ByteArrayInputStream(baos.toByteArray());
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Excel clone success");
            }
            Workbook book = WorkbookFactory.create(userIs);

            boolean isXSSFWorkbook = !(book instanceof HSSFWorkbook);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Workbook create success");
            }
            importResult = new ExcelImportResult();
            createErrorCellStyle(book);
            Map<String, PictureData> pictures;
            for (int i = params.getStartSheetIndex(); i < params.getStartSheetIndex()
                    + params.getSheetNum(); i++) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(" start to read excel by is ,startTime is {}", new Date());
                }
                if (isXSSFWorkbook) {
                    pictures = PoiPublicUtil.getSheetPictrues07((XSSFSheet) book.getSheetAt(i),
                            (XSSFWorkbook) book);
                } else {
                    pictures = PoiPublicUtil.getSheetPictrues03((HSSFSheet) book.getSheetAt(i),
                            (HSSFWorkbook) book);
                }
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(" end to read excel by is ,endTime is {}", new Date());
                }
                result.addAll(importExcel(result, book.getSheetAt(i), pojoClass, params, pictures));
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(" end to read excel list by sheet ,endTime is {}", new Date());
                }
                if (params.isReadSingleCell()) {
                    readSingleCell(importResult, book.getSheetAt(i), params);
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug(" read Key-Value ,endTime is {}", System.currentTimeMillis());
                    }
                }
            }
            if (params.isNeedSave()) {
                saveThisExcel(params, pojoClass, isXSSFWorkbook, book);
            }
            importResult.setList(result);
            if (needMore) {
                InputStream successIs = new ByteArrayInputStream(baos.toByteArray());
                try {
                    Workbook successBook = WorkbookFactory.create(successIs);
                    if (params.isVerifyFileSplit()){
                        importResult.setWorkbook(removeSuperfluousRows(successBook, failRow, params));
                        importResult.setFailWorkbook(removeSuperfluousRows(book, successRow, params));
                    } else {
                        importResult.setWorkbook(book);
                    }
                    importResult.setFailList(failCollection);
                    importResult.setVerifyFail(verifyFail);
                } finally {
                    successIs.close();
                }
            }
        } finally {
            IOUtils.closeQuietly(baos);
        }

        return importResult;
    }

    private Workbook removeSuperfluousRows(Workbook book, List<Row> rowList, ImportParams params) {
        for (int i = params.getStartSheetIndex(); i < params.getStartSheetIndex()
                + params.getSheetNum(); i++) {
            for (int j = rowList.size() - 1; j >= 0; j--) {
                if (rowList.get(j).getRowNum() < rowList.get(j).getSheet().getLastRowNum()) {
                    book.getSheetAt(i).shiftRows(rowList.get(j).getRowNum() + 1, rowList.get(j).getSheet().getLastRowNum(), 1);
                } else if (rowList.get(j).getRowNum() == rowList.get(j).getSheet().getLastRowNum()) {
                    book.getSheetAt(i).createRow(rowList.get(j).getRowNum() + 1);
                    book.getSheetAt(i).shiftRows(rowList.get(j).getRowNum() + 1, rowList.get(j).getSheet().getLastRowNum() + 1, 1);
                }
            }
        }
        return book;
    }

    /**
     * 按照键值对的方式取得Excel里面的数据
     */
    private void readSingleCell(ExcelImportResult result, Sheet sheet, ImportParams params) {
        if (result.getMap() == null) {
            result.setMap(new HashMap<String, Object>());
        }
        for (int i = 0; i < params.getTitleRows() + params.getHeadRows() + params.getStartRows(); i++) {
            getSingleCellValueForRow(result, sheet.getRow(i), params);
        }

        for (int i = sheet.getLastRowNum() - params.getLastOfInvalidRow(); i < sheet.getLastRowNum(); i++) {
            getSingleCellValueForRow(result, sheet.getRow(i), params);

        }
    }

    private void getSingleCellValueForRow(ExcelImportResult result, Row row, ImportParams params) {
        for (int j = row.getFirstCellNum(), le = row.getLastCellNum(); j < le; j++) {
            String text = PoiCellUtil.getCellValue(row.getCell(j));
            if (StringUtils.isNoneBlank(text) && text.endsWith(params.getKeyMark())) {
                if (result.getMap().containsKey(text)) {
                    if (result.getMap().get(text) instanceof String) {
                        List<String> list = new ArrayList<String>();
                        list.add((String) result.getMap().get(text));
                        result.getMap().put(text, list);
                    }
                    ((List) result.getMap().get(text)).add(PoiCellUtil.getCellValue(row.getCell(++j)));
                } else {
                    result.getMap().put(text, PoiCellUtil.getCellValue(row.getCell(++j)));
                }

            }

        }
    }

    /**
     * 检查是不是合法的模板
     */
    private void checkIsValidTemplate(Map<Integer, String> titlemap,
                                      Map<String, ExcelImportEntity> excelParams,
                                      ImportParams params,
                                      List<ExcelCollectionParams> excelCollection) {

        if (params.getImportFields() != null) {
            // 同时校验列顺序
            if (params.isNeedCheckOrder()) {

                if (params.getImportFields().length != titlemap.size()) {
                    LOGGER.error("excel列顺序不一致");
                    throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                }
                int i = 0;
                for (String title : titlemap.values()) {
                    if (!StringUtils.equals(title, params.getImportFields()[i++])) {
                        LOGGER.error("excel列顺序不一致");
                        throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                    }
                }
            } else {
                for (int i = 0, le = params.getImportFields().length; i < le; i++) {
                    if (!titlemap.containsValue(params.getImportFields()[i])) {
                        throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                    }
                }
            }
        } else {
            Collection<ExcelImportEntity> collection = excelParams.values();
            for (ExcelImportEntity excelImportEntity : collection) {
                if (excelImportEntity.isImportField()
                        && !titlemap.containsValue(excelImportEntity.getName())) {
                    LOGGER.error(excelImportEntity.getName() + "必须有,但是没找到");
                    throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                }
            }

            for (int i = 0, le = excelCollection.size(); i < le; i++) {
                ExcelCollectionParams collectionparams = excelCollection.get(i);
                collection = collectionparams.getExcelParams().values();
                for (ExcelImportEntity excelImportEntity : collection) {
                    if (excelImportEntity.isImportField() && !titlemap.containsValue(
                            collectionparams.getExcelName() + "_" + excelImportEntity.getName())) {
                        throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                    }
                }
            }
        }
    }

    /**
     * 保存字段值(获取值,校验值,追加错误信息)
     */
    public void saveFieldValue(ImportParams params, Object object, Cell cell,
                               Map<String, ExcelImportEntity> excelParams, String titleString,
                               Row row) throws Exception {
        Object value = cellValueServer.getValue(params.getDataHandler(), object, cell, excelParams,
                titleString, params.getDictHandler());
        if (object instanceof Map) {
            if (params.getDataHandler() != null) {
                params.getDataHandler().setMapValue((Map) object, titleString, value);
            } else {
                ((Map) object).put(titleString, value);
            }
        } else {
            setValues(excelParams.get(titleString), object, value);
        }
    }

    /**
     * @param object
     * @param picId
     * @param excelParams
     * @param titleString
     * @param pictures
     * @param params
     * @throws Exception
     */
    private void saveImage(Object object, String picId, Map<String, ExcelImportEntity> excelParams,
                           String titleString, Map<String, PictureData> pictures,
                           ImportParams params) throws Exception {
        if (pictures == null) {
            return;
        }
        PictureData image = pictures.get(picId);
        if (image == null) {
            return;
        }
        byte[] data     = image.getData();
        String fileName = "pic" + Math.round(Math.random() * 100000000000L);
        fileName += "." + PoiPublicUtil.getFileExtendName(data);
        if (excelParams.get(titleString).getSaveType() == 1) {
            String path     = getSaveUrl(excelParams.get(titleString), object);
            File   savefile = new File(path);
            if (!savefile.exists()) {
                savefile.mkdirs();
            }
            savefile = new File(path + File.separator + fileName);
            FileOutputStream fos = new FileOutputStream(savefile);
            try {
                fos.write(data);
            } finally {
                IOUtils.closeQuietly(fos);
            }
            setValues(excelParams.get(titleString), object,
                    getSaveUrl(excelParams.get(titleString), object) + File.separator + fileName);
        } else {
            setValues(excelParams.get(titleString), object, data);
        }
    }

    private void createErrorCellStyle(Workbook workbook) {
        errorCellStyle = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setColor(Font.COLOR_RED);
        errorCellStyle.setFont(font);
    }

}

在这里插入图片描述
在这里插入图片描述

第一个问题处理,校验时获取不到一对多中多的完整数据

  • 当我把 第二个问题处理后,第一个问题在校验的时候还是只能获取一对多的第一个,实在没找到源码,也不想找了,就用一个笨方法处理了,就是把读入的流分成两份,一份用 ExcelImportUtil.importExcel() 不校验获取所有数据,一份用 ExcelImportUtil.importExcelMore() 处理,在设置校验类时,用构造方法的方式放入 ExcelImportUtil.importExcel() 的返回值到校验类中。
  • 这样技能够校验了,也能过获取完整的数据了。
    在这里插入图片描述

3 完整环境

3.1 ImportController

package com.example.myeasypoi;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelCollection;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult;
import cn.afterturn.easypoi.handler.inter.IExcelDataModel;
import cn.afterturn.easypoi.handler.inter.IExcelModel;
import cn.afterturn.easypoi.handler.inter.IExcelVerifyHandler;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.Length;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@RestController
public class ImportController {
    public static void main(String[] args) throws Exception {

        BufferedInputStream bis1 = new BufferedInputStream(new FileInputStream("D:/study/code_source/my-easypoi/src/main/resources/ExcelExportTemplateMyNestedLoop.xlsx"));
        BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream("D:/study/code_source/my-easypoi/src/main/resources/ExcelExportTemplateMyNestedLoop.xlsx"));
        //第一份文件,不校验
        ImportParams importParams1 = new ImportParams();
        importParams1.setHeadRows(2);
        List<MyPojo> firstMyPojoList = ExcelImportUtil.importExcel(bis1, MyPojo.class, importParams1);
        Map<Integer, MyPojo> idMyPojoMap = firstMyPojoList.stream().collect(Collectors.toMap(MyPojo::getId, e -> e));

        ImportParams importParams2 = new ImportParams();
        importParams2.setHeadRows(2);
        importParams2.setNeedVerify(true);
        importParams2.setVerifyHandler(new MyVerifyHandler(idMyPojoMap));
//        ExcelImportResult<Object> result = ExcelImportUtil.importExcelMore(bis, MyPojo.class, importParams);
        ExcelImportResult<MyPojo> result = new MyExcelImportService().importExcelByIs(bis2, MyPojo.class, importParams2,true);
        List<MyPojo> failList = result.getFailList();
        System.out.println(failList);
    }

    @Data
    public static class MyPojo extends Traffic implements IExcelDataModel, IExcelModel{
        /**
         * 行号
         */
        private int rowNum;

        /**
         * 错误消息
         */
        private String errorMsg;

        @Override
        public String getErrorMsg() {
            return errorMsg;
        }

        @Override
        public void setErrorMsg(String s) {
            this.errorMsg =s;
        }

        @Override
        public Integer getRowNum() {
            return rowNum;
        }

        @Override
        public void setRowNum(Integer rowNum) {
            this.rowNum = rowNum;
        }
    }


    public static class MyVerifyHandler implements IExcelVerifyHandler<MyPojo> {
        Map<Integer,MyPojo> idMyPojoMap;
        public MyVerifyHandler(Map<Integer, MyPojo> idMyPojoMap) {
            this.idMyPojoMap = idMyPojoMap;
        }

        @Override
        public ExcelVerifyHandlerResult verifyHandler(MyPojo myPojo) {
            myPojo = idMyPojoMap.get(myPojo.getId());
            StringBuilder sb = new StringBuilder();

            //校验
            String name = myPojo.getName();
            if(StringUtils.isNotEmpty(name) && name.length() > 100){
                sb.append("姓名长度不能超过 100");
            }
            List<TrafficDetail> shareBikes = myPojo.getShareBikes();
            List<TrafficDetail> subways = myPojo.getSubways();
            if (CollectionUtils.isNotEmpty(shareBikes)){
                shareBikes.forEach(shareBike -> {
                    if(getSum(shareBike.getNumber(),shareBike.getCost())>=10){
                        sb.append("共享单车次数和费用之和大于 10");
                    }
                });
            }
            if(CollectionUtils.isNotEmpty(subways)){
                subways.forEach(subway -> {
                    if(getSum(subway.getNumber(),subway.getCost()) >=10){
                        sb.append("地铁次数和费用之和大于 10");
                    }
                });
            }
            ExcelVerifyHandlerResult excelVerifyHandlerResult;
            if(sb.length()!= 0){
                excelVerifyHandlerResult= new ExcelVerifyHandlerResult(false,sb.toString());
            }else {

                excelVerifyHandlerResult= new ExcelVerifyHandlerResult(true);
            }
            return excelVerifyHandlerResult;
        }
        private int getSum(Integer a ,Integer b){
            return (a == null ? 0 : a) + (b == null ? 0 : b);
        }
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Traffic{

        @Excel(name = "序号")
        private Integer id;
        @Excel(name = "姓名")
        @Length(max = 100,message = "姓名长度不能大于 100")
        private String name;
        @Excel(name = "日期",format = "yyyy-MM-dd")
        private Date date;
        @ExcelCollection(name = "共享单车")
        private List<TrafficDetail> shareBikes;
        @ExcelCollection(name = "地铁")
        private List<TrafficDetail> subways;
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class TrafficDetail{
        @Excel(name = "次数")
        private Integer number;
        @Excel(name = "费用")
        private Integer cost;

    }
}

3.2 MyExcelImportService

/**
 * Copyright 2013-2015 JueYue (qrb.jueyue@gmail.com)
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.example.myeasypoi;

import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelCollectionParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelImportEntity;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult;
import cn.afterturn.easypoi.entity.BaseTypeConstants;
import cn.afterturn.easypoi.excel.imports.CellValueService;
import cn.afterturn.easypoi.excel.imports.ExcelImportService;
import cn.afterturn.easypoi.excel.imports.base.ImportBaseService;
import cn.afterturn.easypoi.excel.imports.recursive.ExcelImportForkJoinWork;
import cn.afterturn.easypoi.exception.excel.ExcelImportException;
import cn.afterturn.easypoi.exception.excel.enums.ExcelImportEnum;
import cn.afterturn.easypoi.handler.inter.IExcelDataModel;
import cn.afterturn.easypoi.handler.inter.IExcelModel;
import cn.afterturn.easypoi.util.PoiCellUtil;
import cn.afterturn.easypoi.util.PoiPublicUtil;
import cn.afterturn.easypoi.util.PoiReflectorUtil;
import cn.afterturn.easypoi.util.PoiValidationUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ForkJoinPool;

/**
 * Excel 导入服务
 *
 * @author JueYue 2014年6月26日 下午9:20:51
 */
@SuppressWarnings({"rawtypes", "unchecked", "hiding"})
public class MyExcelImportService extends ExcelImportService {

    private final static Logger LOGGER = LoggerFactory.getLogger(MyExcelImportService.class);

    private CellValueService cellValueServer;

    private boolean   verifyFail = false;
    /**
     * 异常数据styler
     */
    private CellStyle errorCellStyle;

    private List<Row> successRow;
    private List<Row> failRow;
    private List      failCollection;

    public MyExcelImportService() {
        successRow = new ArrayList<Row>();
        failRow = new ArrayList<Row>();
        failCollection = new ArrayList();
        this.cellValueServer = new CellValueService();
    }

    /***
     * 向List里面继续添加元素
     *
     * @param object
     * @param param
     * @param row
     * @param titlemap
     * @param targetId
     * @param pictures
     * @param params
     */
    public void addListContinue(Object object, ExcelCollectionParams param, Row row,
                                Map<Integer, String> titlemap, String targetId,
                                Map<String, PictureData> pictures,
                                ImportParams params, StringBuilder errorMsg) throws Exception {
        Collection collection = (Collection) PoiReflectorUtil.fromCache(object.getClass())
                .getValue(object, param.getName());
        Object entity = PoiPublicUtil.createObject(param.getType(), targetId);
        if (entity instanceof IExcelDataModel) {
            ((IExcelDataModel) entity).setRowNum(row.getRowNum());
        }
        String picId;
        // 是否需要加上这个对象
        boolean isUsed = false;
        for (int i = row.getFirstCellNum(); i < titlemap.size(); i++) {
            Cell   cell        = row.getCell(i);
            String titleString = (String) titlemap.get(i);
            if (param.getExcelParams().containsKey(titleString)) {
                if (param.getExcelParams().get(titleString).getType() == BaseTypeConstants.IMAGE_TYPE) {
                    picId = row.getRowNum() + "_" + i;
                    saveImage(entity, picId, param.getExcelParams(), titleString, pictures, params);
                } else {
                    try {
                        saveFieldValue(params, entity, cell, param.getExcelParams(), titleString, row);
                    } catch (ExcelImportException e) {
                        // 如果需要去校验就忽略,这个错误,继续执行
                        if (params.isNeedVerify() && ExcelImportEnum.GET_VALUE_ERROR.equals(e.getType())) {
                            errorMsg.append(" ").append(titleString).append(ExcelImportEnum.GET_VALUE_ERROR.getMsg());
                        }
                    }
                }
                isUsed = true;
            }
        }
        if (isUsed) {
            collection.add(entity);
        }
    }

    /**
     * 获取key的值,针对不同类型获取不同的值
     *
     * @author JueYue 2013-11-21
     */
    private String getKeyValue(Cell cell) {
        Object obj = PoiCellUtil.getCellValue(cell);
        return obj == null ? null : obj.toString().trim();
    }

    /**
     * 获取保存的真实路径
     */
    private String getSaveUrl(ExcelImportEntity excelImportEntity, Object object) throws Exception {
        String url = "";
        if (ExcelImportEntity.IMG_SAVE_PATH.equals(excelImportEntity.getSaveUrl())) {
            if (excelImportEntity.getMethods() != null
                    && excelImportEntity.getMethods().size() > 0) {
                object = getFieldBySomeMethod(excelImportEntity.getMethods(), object);
            }
            url = object.getClass().getName()
                    .split("\\.")[object.getClass().getName().split("\\.").length - 1];
            return excelImportEntity.getSaveUrl() + File.separator + url;
        }
        return excelImportEntity.getSaveUrl();
    }

    private <T> List<T> importExcel(Collection<T> result, Sheet sheet, Class<?> pojoClass,
                                    ImportParams params,
                                    Map<String, PictureData> pictures) throws Exception {
        List                           collection      = new ArrayList();
        Map<String, ExcelImportEntity> excelParams     = new HashMap<>();
        List<ExcelCollectionParams>    excelCollection = new ArrayList<>();
        String                         targetId        = null;
        i18nHandler = params.getI18nHandler();
        boolean isMap = Map.class.equals(pojoClass);
        if (!isMap) {
            Field[]     fileds  = PoiPublicUtil.getClassFields(pojoClass);
            ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class);
            if (etarget != null) {
                targetId = etarget.value();
            }
            getAllExcelField(targetId, fileds, excelParams, excelCollection, pojoClass, null, null);
        }
        Iterator<Row> rows = sheet.rowIterator();
        for (int j = 0; j < params.getTitleRows(); j++) {
            rows.next();
        }
        Map<Integer, String> titlemap = getTitleMap(rows, params, excelCollection, excelParams);
        checkIsValidTemplate(titlemap, excelParams, params, excelCollection);
        Row    row     = null;
        Object object  = null;
        String picId;
        int    readRow = 1;
        //跳过无效行
        for (int i = 0; i < params.getStartRows(); i++) {
            rows.next();
        }
        //判断index 和集合,集合情况默认为第一列
        if (excelCollection.size() > 0 && params.getKeyIndex() == null) {
            params.setKeyIndex(0);
        }
        int          endRow       = sheet.getLastRowNum() - params.getLastOfInvalidRow();
        if (params.getReadRows() > 0) {
            endRow = Math.min(params.getReadRows(), endRow);
        }
        if (params.isConcurrentTask()) {
            ForkJoinPool forkJoinPool = new ForkJoinPool();
            ExcelImportForkJoinWork task           = new ExcelImportForkJoinWork(params.getStartRows() + params.getHeadRows() + params.getTitleRows(), endRow, sheet, params, pojoClass, this, targetId, titlemap, excelParams);
            ExcelImportResult       forkJoinResult = forkJoinPool.invoke(task);
            collection = forkJoinResult.getList();
            failCollection = forkJoinResult.getFailList();
        } else {
            StringBuilder errorMsg;
            while (rows.hasNext()) {
                row = rows.next();
                // Fix 如果row为无效行时候跳出
                if (row.getRowNum() > endRow) {
                    break;
                }
                /* 如果当前行的单元格都是无效的,那就继续下一行 */
                if (row.getLastCellNum()<0) {
                    continue;
                }
                if(isMap && object != null) {
                    ((Map) object).put("excelRowNum", row.getRowNum());
                }
                errorMsg = new StringBuilder();
                // 判断是集合元素还是不是集合元素,如果是就继续加入这个集合,不是就创建新的对象
                // keyIndex 如果为空就不处理,仍然处理这一行
                if (params.getKeyIndex() != null
                        && (row.getCell(params.getKeyIndex()) == null
                        || StringUtils.isEmpty(getKeyValue(row.getCell(params.getKeyIndex()))))
                        && object != null) {
                    for (ExcelCollectionParams param : excelCollection) {
                        addListContinue(object, param, row, titlemap, targetId, pictures, params, errorMsg);
                    }
                } else {
                    object = PoiPublicUtil.createObject(pojoClass, targetId);
                    try {
                        Set<Integer> keys = titlemap.keySet();
                        for (Integer cn : keys) {
                            Cell   cell        = row.getCell(cn);
                            String titleString = (String) titlemap.get(cn);
                            if (excelParams.containsKey(titleString) || isMap) {
                                if (excelParams.get(titleString) != null
                                        && excelParams.get(titleString).getType() == BaseTypeConstants.IMAGE_TYPE) {
                                    picId = row.getRowNum() + "_" + cn;
                                    saveImage(object, picId, excelParams, titleString, pictures,
                                            params);
                                } else {
                                    try {
                                        saveFieldValue(params, object, cell, excelParams, titleString, row);
                                    } catch (ExcelImportException e) {
                                        // 如果需要去校验就忽略,这个错误,继续执行
                                        if (params.isNeedVerify() && ExcelImportEnum.GET_VALUE_ERROR.equals(e.getType())) {
                                            errorMsg.append(" ").append(titleString).append(ExcelImportEnum.GET_VALUE_ERROR.getMsg());
                                        }
                                    }
                                }
                            }
                        }
                        //for (int i = row.getFirstCellNum(), le = titlemap.size(); i < le; i++) {

                        //}
                        if (object instanceof IExcelDataModel) {
                            ((IExcelDataModel) object).setRowNum(row.getRowNum());
                        }
                        for (ExcelCollectionParams param : excelCollection) {
                            addListContinue(object, param, row, titlemap, targetId, pictures, params, errorMsg);
                        }
                        if (verifyingDataValidity(object, row, params, isMap, errorMsg)) {
                            collection.add(object);
                        } else {
                            failCollection.add(object);
                        }
                    } catch (ExcelImportException e) {
                        LOGGER.error("excel import error , row num:{},obj:{}", readRow, ReflectionToStringBuilder.toString(object));
                        if (!e.getType().equals(ExcelImportEnum.VERIFY_ERROR)) {
                            throw new ExcelImportException(e.getType(), e);
                        }
                    } catch (Exception e) {
                        LOGGER.error("excel import error , row num:{},obj:{}", readRow, ReflectionToStringBuilder.toString(object));
                        throw new RuntimeException(e);
                    }
                }
                readRow++;
            }
        }
        return collection;
    }

    /**
     * 校验数据合法性
     */
    public boolean verifyingDataValidity(Object object, Row row, ImportParams params,
                                         boolean isMap, StringBuilder fieldErrorMsg) {
        boolean isAdd = true;
        Cell    cell  = null;
        if (params.isNeedVerify()) {
            String errorMsg = PoiValidationUtil.validation(object, params.getVerifyGroup());
            if (StringUtils.isNotEmpty(errorMsg)) {
                cell = row.createCell(row.getLastCellNum());
                cell.setCellValue(errorMsg);
                if (object instanceof IExcelModel) {
                    IExcelModel model = (IExcelModel) object;
                    model.setErrorMsg(errorMsg);
                }
                isAdd = false;
                verifyFail = true;
            }
        }
        if (params.getVerifyHandler() != null) {
            ExcelVerifyHandlerResult result = params.getVerifyHandler().verifyHandler(object);
            if (!result.isSuccess()) {
                if (cell == null) {
                    cell = row.createCell(row.getLastCellNum());
                }
                cell.setCellValue((StringUtils.isNoneBlank(cell.getStringCellValue())
                        ? cell.getStringCellValue() + "," : "") + result.getMsg());
                if (object instanceof IExcelModel) {
                    IExcelModel model = (IExcelModel) object;
                    model.setErrorMsg((StringUtils.isNoneBlank(model.getErrorMsg())
                            ? model.getErrorMsg() + "," : "") + result.getMsg());
                }
                isAdd = false;
                verifyFail = true;
            }
        }
        if ((params.isNeedVerify() || params.getVerifyHandler() != null) && fieldErrorMsg.length() > 0) {
            if (object instanceof IExcelModel) {
                IExcelModel model = (IExcelModel) object;
                model.setErrorMsg((StringUtils.isNoneBlank(model.getErrorMsg())
                        ? model.getErrorMsg() + "," : "") + fieldErrorMsg.toString());
            }
            if (cell == null) {
                cell = row.createCell(row.getLastCellNum());
            }
            cell.setCellValue((StringUtils.isNoneBlank(cell.getStringCellValue())
                    ? cell.getStringCellValue() + "," : "") + fieldErrorMsg.toString());
            isAdd = false;
            verifyFail = true;
        }
        if (cell != null) {
            cell.setCellStyle(errorCellStyle);
            failRow.add(row);
            if(isMap) {
                ((Map) object).put("excelErrorMsg", cell.getStringCellValue());
            }
        } else {
            successRow.add(row);
        }
        return isAdd;
    }

    /**
     * 获取表格字段列名对应信息
     */
    private Map<Integer, String> getTitleMap(Iterator<Row> rows, ImportParams params,
                                             List<ExcelCollectionParams> excelCollection,
                                             Map<String, ExcelImportEntity> excelParams) {
        Map<Integer, String>  titlemap         = new LinkedHashMap<Integer, String>();
        Iterator<Cell>        cellTitle;
        String                collectionName   = null;
        ExcelCollectionParams collectionParams = null;
        Row                   row              = null;
        for (int j = 0; j < params.getHeadRows(); j++) {
            row = rows.next();
            if (row == null) {
                continue;
            }
            cellTitle = row.cellIterator();
            while (cellTitle.hasNext()) {
                Cell   cell  = cellTitle.next();
                String value = getKeyValue(cell);
                value = value.replace("\n", "");
                int i = cell.getColumnIndex();
                //用以支持重名导入
                if (StringUtils.isNotEmpty(value)) {
                    if (titlemap.containsKey(i)) {
                        collectionName = titlemap.get(i);
                        collectionParams = getCollectionParams(excelCollection, collectionName);
                        titlemap.put(i, collectionName + "_" + value);
                    } else if (StringUtils.isNotEmpty(collectionName) && collectionParams != null
                            && collectionParams.getExcelParams()
                            .containsKey(collectionName + "_" + value)) {
                        titlemap.put(i, collectionName + "_" + value);
                    } else {
                        collectionName = null;
                        collectionParams = null;
                    }
                    if (StringUtils.isEmpty(collectionName)) {
                        titlemap.put(i, value);
                    }
                }
            }
        }

        // 处理指定列的情况
        Set<String> keys = excelParams.keySet();
        for (String key : keys) {
            if (key.startsWith("FIXED_")) {
                String[] arr = key.split("_");
                titlemap.put(Integer.parseInt(arr[1]), key);
            }
        }
        return titlemap;
    }

    /**
     * 获取这个名称对应的集合信息
     */
    private ExcelCollectionParams getCollectionParams(List<ExcelCollectionParams> excelCollection,
                                                      String collectionName) {
        for (ExcelCollectionParams excelCollectionParams : excelCollection) {
            if (collectionName.equals(excelCollectionParams.getExcelName())) {
                return excelCollectionParams;
            }
        }
        return null;
    }

    /**
     * Excel 导入 field 字段类型 Integer,Long,Double,Date,String,Boolean
     */
    public ExcelImportResult importExcelByIs(InputStream inputstream, Class<?> pojoClass,
                                             ImportParams params, boolean needMore) throws Exception {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Excel import start ,class is {}", pojoClass);
        }
        List<T>               result = new ArrayList<T>();
        ByteArrayOutputStream baos   = new ByteArrayOutputStream();
        ExcelImportResult     importResult;
        try {
            byte[] buffer = new byte[1024];
            int    len;
            while ((len = inputstream.read(buffer)) > -1) {
                baos.write(buffer, 0, len);
            }
            baos.flush();

            InputStream userIs = new ByteArrayInputStream(baos.toByteArray());
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Excel clone success");
            }
            Workbook book = WorkbookFactory.create(userIs);

            boolean isXSSFWorkbook = !(book instanceof HSSFWorkbook);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Workbook create success");
            }
            importResult = new ExcelImportResult();
            createErrorCellStyle(book);
            Map<String, PictureData> pictures;
            for (int i = params.getStartSheetIndex(); i < params.getStartSheetIndex()
                    + params.getSheetNum(); i++) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(" start to read excel by is ,startTime is {}", new Date());
                }
                if (isXSSFWorkbook) {
                    pictures = PoiPublicUtil.getSheetPictrues07((XSSFSheet) book.getSheetAt(i),
                            (XSSFWorkbook) book);
                } else {
                    pictures = PoiPublicUtil.getSheetPictrues03((HSSFSheet) book.getSheetAt(i),
                            (HSSFWorkbook) book);
                }
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(" end to read excel by is ,endTime is {}", new Date());
                }
                result.addAll(importExcel(result, book.getSheetAt(i), pojoClass, params, pictures));
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(" end to read excel list by sheet ,endTime is {}", new Date());
                }
                if (params.isReadSingleCell()) {
                    readSingleCell(importResult, book.getSheetAt(i), params);
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug(" read Key-Value ,endTime is {}", System.currentTimeMillis());
                    }
                }
            }
            if (params.isNeedSave()) {
                saveThisExcel(params, pojoClass, isXSSFWorkbook, book);
            }
            importResult.setList(result);
            if (needMore) {
                InputStream successIs = new ByteArrayInputStream(baos.toByteArray());
                try {
                    Workbook successBook = WorkbookFactory.create(successIs);
                    if (params.isVerifyFileSplit()){
                        importResult.setWorkbook(removeSuperfluousRows(successBook, failRow, params));
                        importResult.setFailWorkbook(removeSuperfluousRows(book, successRow, params));
                    } else {
                        importResult.setWorkbook(book);
                    }
                    importResult.setFailList(failCollection);
                    importResult.setVerifyFail(verifyFail);
                } finally {
                    successIs.close();
                }
            }
        } finally {
            IOUtils.closeQuietly(baos);
        }

        return importResult;
    }

    private Workbook removeSuperfluousRows(Workbook book, List<Row> rowList, ImportParams params) {
        for (int i = params.getStartSheetIndex(); i < params.getStartSheetIndex()
                + params.getSheetNum(); i++) {
            for (int j = rowList.size() - 1; j >= 0; j--) {
                if (rowList.get(j).getRowNum() < rowList.get(j).getSheet().getLastRowNum()) {
                    book.getSheetAt(i).shiftRows(rowList.get(j).getRowNum() + 1, rowList.get(j).getSheet().getLastRowNum(), 1);
                } else if (rowList.get(j).getRowNum() == rowList.get(j).getSheet().getLastRowNum()) {
                    book.getSheetAt(i).createRow(rowList.get(j).getRowNum() + 1);
                    book.getSheetAt(i).shiftRows(rowList.get(j).getRowNum() + 1, rowList.get(j).getSheet().getLastRowNum() + 1, 1);
                }
            }
        }
        return book;
    }

    /**
     * 按照键值对的方式取得Excel里面的数据
     */
    private void readSingleCell(ExcelImportResult result, Sheet sheet, ImportParams params) {
        if (result.getMap() == null) {
            result.setMap(new HashMap<String, Object>());
        }
        for (int i = 0; i < params.getTitleRows() + params.getHeadRows() + params.getStartRows(); i++) {
            getSingleCellValueForRow(result, sheet.getRow(i), params);
        }

        for (int i = sheet.getLastRowNum() - params.getLastOfInvalidRow(); i < sheet.getLastRowNum(); i++) {
            getSingleCellValueForRow(result, sheet.getRow(i), params);

        }
    }

    private void getSingleCellValueForRow(ExcelImportResult result, Row row, ImportParams params) {
        for (int j = row.getFirstCellNum(), le = row.getLastCellNum(); j < le; j++) {
            String text = PoiCellUtil.getCellValue(row.getCell(j));
            if (StringUtils.isNoneBlank(text) && text.endsWith(params.getKeyMark())) {
                if (result.getMap().containsKey(text)) {
                    if (result.getMap().get(text) instanceof String) {
                        List<String> list = new ArrayList<String>();
                        list.add((String) result.getMap().get(text));
                        result.getMap().put(text, list);
                    }
                    ((List) result.getMap().get(text)).add(PoiCellUtil.getCellValue(row.getCell(++j)));
                } else {
                    result.getMap().put(text, PoiCellUtil.getCellValue(row.getCell(++j)));
                }

            }

        }
    }

    /**
     * 检查是不是合法的模板
     */
    private void checkIsValidTemplate(Map<Integer, String> titlemap,
                                      Map<String, ExcelImportEntity> excelParams,
                                      ImportParams params,
                                      List<ExcelCollectionParams> excelCollection) {

        if (params.getImportFields() != null) {
            // 同时校验列顺序
            if (params.isNeedCheckOrder()) {

                if (params.getImportFields().length != titlemap.size()) {
                    LOGGER.error("excel列顺序不一致");
                    throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                }
                int i = 0;
                for (String title : titlemap.values()) {
                    if (!StringUtils.equals(title, params.getImportFields()[i++])) {
                        LOGGER.error("excel列顺序不一致");
                        throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                    }
                }
            } else {
                for (int i = 0, le = params.getImportFields().length; i < le; i++) {
                    if (!titlemap.containsValue(params.getImportFields()[i])) {
                        throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                    }
                }
            }
        } else {
            Collection<ExcelImportEntity> collection = excelParams.values();
            for (ExcelImportEntity excelImportEntity : collection) {
                if (excelImportEntity.isImportField()
                        && !titlemap.containsValue(excelImportEntity.getName())) {
                    LOGGER.error(excelImportEntity.getName() + "必须有,但是没找到");
                    throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                }
            }

            for (int i = 0, le = excelCollection.size(); i < le; i++) {
                ExcelCollectionParams collectionparams = excelCollection.get(i);
                collection = collectionparams.getExcelParams().values();
                for (ExcelImportEntity excelImportEntity : collection) {
                    if (excelImportEntity.isImportField() && !titlemap.containsValue(
                            collectionparams.getExcelName() + "_" + excelImportEntity.getName())) {
                        throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                    }
                }
            }
        }
    }

    /**
     * 保存字段值(获取值,校验值,追加错误信息)
     */
    public void saveFieldValue(ImportParams params, Object object, Cell cell,
                               Map<String, ExcelImportEntity> excelParams, String titleString,
                               Row row) throws Exception {
        Object value = cellValueServer.getValue(params.getDataHandler(), object, cell, excelParams,
                titleString, params.getDictHandler());
        if (object instanceof Map) {
            if (params.getDataHandler() != null) {
                params.getDataHandler().setMapValue((Map) object, titleString, value);
            } else {
                ((Map) object).put(titleString, value);
            }
        } else {
            setValues(excelParams.get(titleString), object, value);
        }
    }

    /**
     * @param object
     * @param picId
     * @param excelParams
     * @param titleString
     * @param pictures
     * @param params
     * @throws Exception
     */
    private void saveImage(Object object, String picId, Map<String, ExcelImportEntity> excelParams,
                           String titleString, Map<String, PictureData> pictures,
                           ImportParams params) throws Exception {
        if (pictures == null) {
            return;
        }
        PictureData image = pictures.get(picId);
        if (image == null) {
            return;
        }
        byte[] data     = image.getData();
        String fileName = "pic" + Math.round(Math.random() * 100000000000L);
        fileName += "." + PoiPublicUtil.getFileExtendName(data);
        if (excelParams.get(titleString).getSaveType() == 1) {
            String path     = getSaveUrl(excelParams.get(titleString), object);
            File   savefile = new File(path);
            if (!savefile.exists()) {
                savefile.mkdirs();
            }
            savefile = new File(path + File.separator + fileName);
            FileOutputStream fos = new FileOutputStream(savefile);
            try {
                fos.write(data);
            } finally {
                IOUtils.closeQuietly(fos);
            }
            setValues(excelParams.get(titleString), object,
                    getSaveUrl(excelParams.get(titleString), object) + File.separator + fileName);
        } else {
            setValues(excelParams.get(titleString), object, data);
        }
    }

    private void createErrorCellStyle(Workbook workbook) {
        errorCellStyle = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setColor(Font.COLOR_RED);
        errorCellStyle.setFont(font);
    }

}

3.3 Maven 依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-spring-boot-starter</artifactId>
            <version>4.4.0</version>
        </dependency>
        <!-- 建议只用start -->
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.4.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-web</artifactId>
            <version>4.4.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-annotation</artifactId>
            <version>4.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator-annotation-processor</artifactId>
            <version>5.2.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.el</artifactId>
            <version>2.2.4</version>
        </dependency>

4.git 完整代码

防止复现不了我说的情况,git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2179276.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

tr命令:替换文本中的字符

一、命令简介 ​tr​ 命令用于转换或删除文件中的字符。它可以从标准输入中读取数据&#xff0c;对数据进行字符替换、删除或压缩&#xff0c;并将结果输出到标准输出。 ‍ 二、命令参数 格式 tr [选项] [集合1] [集合2]选项和参数 ​ ​-c​​: 指定 集合 1 的补集。​ …

Vulhub zico 2靶机详解

项目地址 https://download.vulnhub.com/zico/zico2.ova实验过程 将下载好的靶机导入到VMware中&#xff0c;设置网络模式为NAT模式&#xff0c;然后开启靶机虚拟机 使用nmap进行主机发现&#xff0c;获取靶机IP地址 nmap 192.168.47.1-254根据对比可知Zico 2的一个ip地址为…

以太网交换安全:MAC地址表安全

一、MAC地址表安全 MAC地址表安全是网络安全中的一个重要方面&#xff0c;它涉及到网络设备的MAC地址表的管理和保护。以下是对MAC地址表安全的详细介绍&#xff1a; &#xff08;1&#xff09;基本概念 定义&#xff1a;MAC地址表是网络设备&#xff08;如交换机&#xff0…

群晖安装Audiobookshelf(有声书)

一、Audiobookshelf是什么&#xff1f; Audiobookshelf是一款自托管的有声读物和播客服务器&#xff0c;用于管理和播放您的有声读物。为用户提供便捷、个性化的音频书籍管理与播放体验 支持网页端、安卓端、IOS端三端同步,支持对有声书进行不同分类。 二、安装教程 通过群晖…

【C语言进阶】一次解决字符串输入问题——为什么输入这么容易奔溃?

文章一览 写在前面一、scanf、getchar与gets函数的爱恨情仇1.1 scanf函数1.1.1 %c输入单个字符2. %s 输入字符串1.1.3 %d输入数字 1.2 getchar函数1.3 gets函数 二、不同输入情况下的使用三、回顾C语言的输入函数总结 写在前面 在之前的文章中&#xff0c;笔者详细介绍了scanf函…

基于Springboot+Vue的课程教学平台的设计与实现系统(含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 这个系…

Arm Linux 交叉编译openssl 1.1.1

一、openssl 源码下载 OpenSSL的官方网站或源代码仓库下载最新或指定版本的OpenSSL源代码。 官网地址&#xff1a; https://openssl-library.org/source/index.html 旧版本下载&#xff1a; https://openssl-library.org/source/old/index.html 这里以 1.1.1 为例 国内git…

网线最短不能短于1米?

大家都知道网线最长不能长于100米&#xff0c;但你有没有听说过“网线最短不能短于1米”这个说法呢&#xff1f;也有的朋友说不能低于0.6米。 有的网友说“‌‌网线最短1米的说法是真的。‌ 短于1米的网线电阻几乎为零&#xff0c;设备可能无法识别&#xff0c;因此在实际应用中…

Android 安卓内存安全漏洞数量大幅下降的原因

谷歌决定使用内存安全的编程语言 Rust 向 Android 代码库中写入新代码&#xff0c;尽管旧代码&#xff08;用 C/C 编写&#xff09;没有被重写&#xff0c;但内存安全漏洞却大幅减少。 Android 代码库中每年发现的内存安全漏洞数量&#xff08;来源&#xff1a;谷歌&#xff09…

【前端开发入门】html快速入门

目录 引言html基础模板内容html文档流html 标签块级元素行内元素功能性元素标签嵌套 html编码习惯总结 引言 本系列教程旨在帮助一些零基础的玩家快速上手前端开发。基于我自学的经验会删减部分使用频率不高的内容&#xff0c;并不代表这部分内容不重要&#xff0c;只是对于初学…

一站式大语言模型API调用:快速上手教程

智匠MindCraft是一个强大的AI工具及开发平台&#xff0c;支持多种大语言模型和多模态AI模型。本文将详细介绍如何通过API调用智匠MindCraft中的大语言模型&#xff0c;帮助开发者快速上手。 注册与登录 访问智匠MindCraft官网&#xff0c;注册并登录账号。 进入开发者平台&…

86、Python之鸭子类型:即便行为大于类型,还是要聊一下类型转换

引言 我们的最近几篇文章一直在聊的是鸭子类型&#xff0c;以及支撑鸭子类型相关的魔术方法的内容。其实&#xff0c;鸭子类型的本质在于“行为大于类型”。但是&#xff0c;并不是说类型不重要&#xff0c;只是在特定领域中&#xff0c;行为本身高于类型形式&#xff0c;或者…

爬虫及数据可视化——运用Hadoop和MongoDB数据进行分析

作品详情  运用Hadoop和MongoDB对得分能力数据进行分析&#xff1b;  运用python进行机器学习的模型调理&#xff0c;利用Pytorch框架对爬取的评论进行情感分析预测&#xff1b;  利用python和MySQL对网站的数据进行爬取、数据清洗及可视化。

Chainlit集成LlamaIndex实现知识库高级检索(组合对象检索)

检索原理 对象组合索引的原理 是利用IndexNode索引节点&#xff0c;将两个不同类型的检索器作为节点对象&#xff0c;使用 SummaryIndex &#xff08;它可以用来构建一个包含多个索引节点的索引结构。这种索引通常用于从多个不同的数据源或索引方法中汇总信息&#xff0c;并能…

零工市场小程序如何提高找兼职的效率?

越来越多的人们会选择成为自由职业者&#xff0c;或者在空暇时兼职来获取酬劳&#xff0c;那么传统的找兼职方式&#xff0c;如&#xff1a;中介公司、招聘广告等。 如今大家的生活都已经进入了“快节奏”&#xff0c;零工市场小程序针对这样的问题而提出了解决方案&#xff0…

python Scrapy 框架 demo

文章目录 前言python Scrapy 框架 demo1. 安装2. 百度热搜爬取demo2.1. 初始化项目2.2. 修改 items.pyitems.py2.3. 创建 spiders/baidu_spider.py2.4. 修改 pipelines.py2.5. 修改 settings.py 3. settings.py 相关配置说明4. 启动爬虫测试 前言 如果您觉得有用的话&#xff0…

python+requests接口测试

pythonrequest 一、调用的方法 requests是一个第三方库 &#xff08;1&#xff09; a、下载地方库pip install requests b、pycaharm中下载 &#xff08;2&#xff09;导入requests库 &#xff08;3&#xff09;requests中的三种调用方法 第一种&#xff1a; requests.…

算法训练营打卡Day18

目录 二叉搜索树的最小绝对差二叉搜索树中的众数二叉树的最近公共祖先额外练手题目 题目1、二叉搜索树的最小绝对差 力扣题目链接(opens new window) 给你一棵所有节点为非负值的二叉搜索树&#xff0c;请你计算树中任意两节点的差的绝对值的最小值。 示例&#xff1a; 思…

时间复杂度及空间复杂度(简略)

目录 时间复杂度空间复杂度 时间复杂度 计算时间复杂度时&#xff0c;我们只需计算大致执行次数&#xff0c;再用大O的渐进表示法就可以了 常见的复杂度为O(N),O(1),O(N^2)的几个情况这里就不提了&#xff0c;下面是几个相对来说需要分析的算法 算法1&#xff1a; // 计算str…

【Python报错已解决】TypeError: ‘int‘ object is not subscriptable

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…