国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

JAVA實(shí)現(xiàn)easyExcel批量導(dǎo)入

這篇具有很好參考價值的文章主要介紹了JAVA實(shí)現(xiàn)easyExcel批量導(dǎo)入。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

注解 類型 描述
ExcelProperty 導(dǎo)入 指定當(dāng)前字段對應(yīng)excel中的那一列。可以根據(jù)名字或者Index去匹配。當(dāng)然也可以不寫,默認(rèn)第一個字段就是index=0,以此類推。千萬注意,要么全部不寫,要么全部用index,要么全部用名字去匹配。千萬別三個混著用,除非你非常了解源代碼中三個混著用怎么去排序的。
ExcelIgnore 導(dǎo)入 默認(rèn)所有字段都會和excel去匹配,加了這個注解會忽略該字段
DateTimeFormat 導(dǎo)入 日期轉(zhuǎn)換,用String去接收excel日期格式的數(shù)據(jù)會調(diào)用這個注解。里面的value參照java.text.SimpleDateFormat
NumberFormat 導(dǎo)入 數(shù)字轉(zhuǎn)換,用String去接收excel數(shù)字格式的數(shù)據(jù)會調(diào)用這個注解。里面的value參照java.text.DecimalFormat
ExcelIgnoreUnannotated 導(dǎo)入 默認(rèn)不加ExcelProperty 的注解的都會參與讀寫,加了不會參與

導(dǎo)入方法參數(shù):ReadWorkbook,ReadSheet 都會有的參數(shù),如果為空,默認(rèn)使用上級。

  • converter 轉(zhuǎn)換器,默認(rèn)加載了很多轉(zhuǎn)換器。也可以自定義。
  • readListener 監(jiān)聽器,在讀取數(shù)據(jù)的過程中會不斷的調(diào)用監(jiān)聽器。
  • headRowNumber 需要讀的表格有幾行頭數(shù)據(jù)。默認(rèn)有一行頭,也就是認(rèn)為第二行開始起為數(shù)據(jù)。
  • headclazz二選一。讀取文件頭對應(yīng)的列表,會根據(jù)列表匹配數(shù)據(jù),建議使用class。
  • clazzhead二選一。讀取文件的頭對應(yīng)的class,也可以使用注解。如果兩個都不指定,則會讀取全部數(shù)據(jù)。
  • autoTrim 字符串、表頭等數(shù)據(jù)自動trim
  • password 讀的時候是否需要使用密碼

ReadWorkbook(理解成excel對象)參數(shù)

  • excelType 當(dāng)前excel的類型 默認(rèn)會自動判斷

  • inputStreamfile二選一。讀取文件的流,如果接收到的是流就只用,不用流建議使用file參數(shù)。因?yàn)槭褂昧?code>inputStream easyexcel會幫忙創(chuàng)建臨時文件,最終還是file

  • fileinputStream二選一。讀取文件的文件。

  • autoCloseStream 自動關(guān)閉流。

  • readCache 默認(rèn)小于5M用 內(nèi)存,超過5M會使用 EhCache,這里不建議使用這個參數(shù)。

  • useDefaultListener@since 2.1.4默認(rèn)會加入ModelBuildEventListener來幫忙轉(zhuǎn)換成傳入class的對象,設(shè)置成false后將不會協(xié)助轉(zhuǎn)換對象,自定義的監(jiān)聽器會接收到Map<Integer,CellData>對象,如果還想繼續(xù)接聽到

    class對象,請調(diào)用readListener方法,加入自定義的beforeListener、ModelBuildEventListener、 自定義afterListener即可。

ReadSheet(就是excel的一個Sheet)參數(shù)

  • sheetNo 需要讀取Sheet的編碼,建議使用這個來指定讀取哪個Sheet
  • sheetName 根據(jù)名字去匹配Sheet,excel 2003不支持根據(jù)名字去匹配

添加pom依賴

<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>easyexcel</artifactId>
   <version>2.2.6</version>
</dependency>
<!--工具類-->
<dependency>
   <groupId>cn.hutool</groupId>
   <artifactId>hutool-all</artifactId>
   <version>5.8.23</version>
</dependency>
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>fastjson</artifactId>
   <version>1.2.21</version>
</dependency>
<!--commons依賴  -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.7</version>
</dependency>

第一種:簡單導(dǎo)入

實(shí)體類

package com.example.mybatismysql8demo.excel;

import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

import java.math.BigDecimal;

@Data
//忽視無注解的字段
@ExcelIgnoreUnannotated
public class GoodsImportExcel {

    /**
     * 用名字去匹配,這里需要注意,如果名字重復(fù),會導(dǎo)致只有一個字段讀取到數(shù)據(jù)
     */
    @ExcelProperty(value = {"商品信息","商品名稱"},index = 0)
    public String goodsName;

    @ExcelProperty(value = {"商品信息","商品價格"},index = 1)
    public BigDecimal price;

    @ExcelProperty(value = {"商品信息","商品數(shù)量"},index = 2)
    public Integer num;
    
}

監(jiān)聽器

package com.example.mybatismysql8demo.handler;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.mybatismysql8demo.excel.GoodsImportExcel;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;

import java.util.List;
import java.util.function.Consumer;

/**
 * 讀取excel數(shù)據(jù)
 */
public class DemoDataListener extends AnalysisEventListener<GoodsImportExcel> {

    /**臨時存儲正常數(shù)據(jù)集合,最大存儲100*/
    private List<GoodsImportExcel> successDataList = Lists.newArrayListWithExpectedSize(100);

    /**自定義消費(fèi)者函數(shù)接口用于自定義監(jiān)聽器中數(shù)據(jù)組裝*/
    private final Consumer<List<GoodsImportExcel>> successConsumer;

    public DemoDataListener(Consumer<List<GoodsImportExcel>> successConsumer) {
        this.successConsumer = successConsumer;
    }

    @Override
    public void invoke(GoodsImportExcel goodsImportExcel, AnalysisContext analysisContext) {
        successDataList.add(goodsImportExcel);
        System.out.println("數(shù)據(jù):"+goodsImportExcel);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        if (CollectionUtils.isNotEmpty(successDataList)) {
            successConsumer.accept(successDataList);
        }
    }
}

執(zhí)行方法

package com.example.mybatismysql8demo.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSONObject;
import com.example.mybatismysql8demo.excel.GoodsImportExcel;
import com.example.mybatismysql8demo.handler.DemoDataListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;


@Slf4j
@RestController
public class EasyExcelController {

    @PostMapping("/easyExcelImport")
    public void importExcel(MultipartFile file,Integer type) {
        if (!file.isEmpty()) {
            //文件名稱
            int begin = Objects.requireNonNull(file.getOriginalFilename()).indexOf(".");
            //文件名稱長度
            int last = file.getOriginalFilename().length();
            //判斷文件格式是否正確
            String fileName = file.getOriginalFilename().substring(begin, last);
            if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
                throw new IllegalArgumentException("上傳文件格式錯誤");
            }
        } else {
            throw new IllegalArgumentException("文件不能為空");
        }
        try (InputStream inputStream = file.getInputStream()) {
            if (type == 1){
                simpleRead(inputStream);
            }else if (type == 2){
                synchronousRead(inputStream);
            }else {
                repeatedRead(inputStream);
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    /**
     * 最簡單的讀的監(jiān)聽器
     */
    public void simpleRead(InputStream inputStream){
        //獲取正確數(shù)據(jù)
        ArrayList<GoodsImportExcel> successArrayList = new ArrayList<>();
        EasyExcel.read(inputStream)
                .head(GoodsImportExcel.class)
                .registerReadListener(new DemoDataListener(
                        // 監(jiān)聽器中doAfterAllAnalysed執(zhí)行此方法;所有讀取完成之后處理邏輯
                        successArrayList::addAll))
                // 設(shè)置sheet,默認(rèn)讀取第一個
                .sheet()
                // 設(shè)置標(biāo)題(字段列表)所在行數(shù)
                .headRowNumber(2)
                .doReadSync();
        System.out.println(successArrayList);
    }

    /**
     * 同步的返回,不推薦使用,如果數(shù)據(jù)量大會把數(shù)據(jù)放到內(nèi)存里面
     */
    public void synchronousRead(InputStream inputStream){
        // 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet 同步讀取會自動finish
        List<GoodsImportExcel> batchGoodsImportModels = EasyExcel.read(inputStream)
                .head(GoodsImportExcel.class)
                // 設(shè)置sheet,默認(rèn)讀取第一個
                .sheet()
                // 設(shè)置標(biāo)題(字段列表)所在行數(shù)
                .headRowNumber(2)
                .doReadSync();
        System.out.println(JSONObject.toJSONString(batchGoodsImportModels));
    }

    /**
     * 讀取多個sheet
     */
    public void repeatedRead(InputStream inputStream){
        ArrayList<GoodsImportExcel> successArrayList = new ArrayList<>();
        //使用模型來讀取Excel(多個sheet)
        ExcelReader reader = EasyExcel.read(inputStream).build();
        //多個sheet
        List<ReadSheet> sheetList = new ArrayList<>();
        for (int i = 0; i < reader.getSheets().size(); i++){
            // 這里為了簡單,所以注冊了同樣的head 和Listener 自己使用功能必須不同的Listener
            ReadSheet readSheet = EasyExcel.readSheet(i)
                    .head(GoodsImportExcel.class)
                    .registerReadListener(new DemoDataListener(successArrayList::addAll))
                    // 設(shè)置標(biāo)題(字段列表)所在行數(shù)
                    .headRowNumber(2)
                    .build();
            sheetList.add(readSheet);
        }
        // 這里注意 一定要把sheet1 sheet2 一起傳進(jìn)去,不然有個問題就是03版的excel 會讀取多次,浪費(fèi)性能
        reader.read(sheetList);
        // 這里千萬別忘記關(guān)閉,讀的時候會創(chuàng)建臨時文件,到時磁盤會崩的
        reader.finish();
        System.out.println(successArrayList);
    }
    
}

結(jié)果打印
數(shù)據(jù):GoodsImportExcel(goodsName=蘋果, price=10, num=11)
數(shù)據(jù):GoodsImportExcel(goodsName=香蕉, price=8, num=12)
數(shù)據(jù):GoodsImportExcel(goodsName=梨子, price=11.0, num=30)
數(shù)據(jù):GoodsImportExcel(goodsName=葡萄, price=20.0, num=40)
[GoodsImportExcel(goodsName=蘋果, price=10, num=11), GoodsImportExcel(goodsName=香蕉, price=8, num=12), GoodsImportExcel(goodsName=梨子, price=11.0, num=30), GoodsImportExcel(goodsName=葡萄, price=20.0, num=40)]

導(dǎo)入模版
JAVA實(shí)現(xiàn)easyExcel批量導(dǎo)入,項(xiàng)目技術(shù)框架,java,后端,excel
JAVA實(shí)現(xiàn)easyExcel批量導(dǎo)入,項(xiàng)目技術(shù)框架,java,后端,excel

第二種:數(shù)據(jù)校驗(yàn)

自定義注解

package com.example.mybatismysql8demo.config;

import java.lang.annotation.*;


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface LengthValid {

    int length() default 0;

    String msg() default "";

    int cell() default 0;
}

實(shí)體類

package com.example.mybatismysql8demo.excel;

import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.example.mybatismysql8demo.config.LengthValid;
import lombok.Data;

import java.math.BigDecimal;

@Data
//忽視無注解的字段
@ExcelIgnoreUnannotated
public class GoodsImportExcel {

    /**
     * 用名字去匹配,這里需要注意,如果名字重復(fù),會導(dǎo)致只有一個字段讀取到數(shù)據(jù)
     */
    @LengthValid(length =  5,msg = "商品名稱長度超出5個字符串!",cell = 1)
    @ExcelProperty(value = {"商品信息","商品名稱"},index = 0)
    public String goodsName;

    @ExcelProperty(value = {"商品信息","商品價格"},index = 1)
    public BigDecimal price;

    @ExcelProperty(value = {"商品信息","商品數(shù)量"},index = 2)
    public Integer num;

    private String errorMsg;
}

監(jiān)聽器

package com.example.mybatismysql8demo.handler;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.api.Assert;
import com.example.mybatismysql8demo.config.LengthValid;
import com.example.mybatismysql8demo.excel.GoodsImportExcel;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
 * 讀取excel數(shù)據(jù)
 */
@Slf4j
public class DemoDataListener extends AnalysisEventListener<GoodsImportExcel> {

    /**單次處理上限100條記錄*/
    private static final int BATCH_COUNT = 100;

    /**臨時存儲正常數(shù)據(jù)集合*/
    private List<GoodsImportExcel> successDataList = Lists.newArrayListWithExpectedSize(BATCH_COUNT);

    /**臨時存錯誤儲數(shù)據(jù)集合*/
    private List<GoodsImportExcel> errorDataList = Lists.newArrayListWithExpectedSize(BATCH_COUNT);

    /**自定義消費(fèi)者函數(shù)接口用于自定義監(jiān)聽器中數(shù)據(jù)組裝*/
    private final Consumer<List<GoodsImportExcel>> successConsumer;

    private final Consumer<List<GoodsImportExcel>> errorConsumer;

    public DemoDataListener(Consumer<List<GoodsImportExcel>> successConsumer, Consumer<List<GoodsImportExcel>> errorConsumer) {
        this.successConsumer = successConsumer;
        this.errorConsumer = errorConsumer;
    }

    /**手機(jī)號格式異常日志處理*/
    @Override
    public void onException(Exception exception, AnalysisContext context) {
        log.error("異常信息:{}", exception.getMessage());
        // 如果是某一個單元格的轉(zhuǎn)換異常 能獲取到具體行號,如果要獲取頭的信息 配合invokeHeadMap使用
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
            log.error("第{}行,第{}列解析異常,數(shù)據(jù)為:{}", excelDataConvertException.getRowIndex(), excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData());
        }else if (exception instanceof IllegalArgumentException){
            throw new IllegalArgumentException(exception.getMessage());
        }
    }

    /**
     * 在這里進(jìn)行模板的判斷
     * @param headMap 存放著導(dǎo)入表格的表頭,鍵是索引,值是名稱
     * @param context
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        //只校驗(yàn)第三行表頭是否正確
        Integer rowNum = context.getCurrentRowNum();
        if (rowNum == 2) {
            // 獲取數(shù)據(jù)實(shí)體的字段列表
            Field[] fields = GoodsImportExcel.class.getDeclaredFields();
            // 遍歷字段進(jìn)行判斷
            for (Field field : fields) {
                // 獲取當(dāng)前字段上的ExcelProperty注解信息
                ExcelProperty fieldAnnotation = field.getAnnotation(ExcelProperty.class);
                // 判斷當(dāng)前字段上是否存在ExcelProperty注解
                if (fieldAnnotation != null) {
                    String value = fieldAnnotation.value()[1];
                    // 存在ExcelProperty注解則根據(jù)注解的value值到表格中對比是否存在對應(yīng)的表頭
                    if(!headMap.containsValue(value)){
                        // 如果表格不包含模版類字段中的表頭,則拋出異常不再往下執(zhí)行
                        throw new RuntimeException("模板錯誤,請檢查導(dǎo)入模板");
                    }
                }
            }
        }
    }


    /**每行讀取監(jiān)聽觸發(fā)邏輯*/
    @SneakyThrows
    @Override
    public void invoke(GoodsImportExcel goodsImportExcel, AnalysisContext analysisContext) {
        //獲取總行數(shù)
        Integer rowNumber = analysisContext.readSheetHolder().getApproximateTotalRowNumber();
        //行數(shù)
        int row = analysisContext.readRowHolder().getRowIndex();
        log.info("第" + row + "行數(shù)據(jù)進(jìn)行處理");
        // 手機(jī)號格式校驗(yàn)
        validParam(goodsImportExcel,row);
        //正常數(shù)據(jù)
        successDataList.add(goodsImportExcel);
        // 按照指定條數(shù)對導(dǎo)入數(shù)據(jù)進(jìn)行分批處理
        if (successDataList.size() >= BATCH_COUNT) {
            successConsumer.accept(successDataList);
            successDataList = Lists.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    private void validParam(GoodsImportExcel goodsImportExcel, int row) throws IllegalAccessException {
        // 參數(shù)校驗(yàn)
        Field[] fields = goodsImportExcel.getClass().getDeclaredFields();
        for (Field field : fields) {
            //設(shè)置可訪問
            field.setAccessible(true);
            //判斷字段是否添加校驗(yàn)
            boolean valid = field.isAnnotationPresent(LengthValid.class);
            if (valid) {
                //獲取注解信息
                LengthValid annotation = field.getAnnotation(LengthValid.class);
                //行數(shù)列數(shù)
                String msg = "第" + row + "行的第" + annotation.cell() + "列:";
                //值
                String value = (String) field.get(goodsImportExcel);
                if(value.length() > annotation.length()){
                    //錯誤信息
                    goodsImportExcel.setErrorMsg(msg + annotation.msg());
                    //錯誤數(shù)據(jù)
                    errorDataList.add(goodsImportExcel);
                    // 按照指定條數(shù)對導(dǎo)入數(shù)據(jù)進(jìn)行分批處理
                    if (errorDataList.size() >= BATCH_COUNT) {
                        errorConsumer.accept(errorDataList);
                        errorDataList = Lists.newArrayListWithExpectedSize(BATCH_COUNT);
                    }
                    throw new RuntimeException(msg + annotation.msg());
                }
            }
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        if (CollectionUtils.isNotEmpty(successDataList)) {
            successConsumer.accept(successDataList);
        }
        if (CollectionUtils.isNotEmpty(errorDataList)) {
            errorConsumer.accept(errorDataList);
        }
    }

    /**
     * 額外信息(批注、超鏈接、合并單元格信息讀取)
     */
    @Override
    public void extra(CellExtra extra, AnalysisContext context) {
        log.info("讀取到了一條額外信息:{}", JSONObject.toJSONString(extra));
        switch (extra.getType()) {
            case COMMENT:
                log.info("額外信息是批注,在rowIndex:{},columnIndex;{},內(nèi)容是:{}", extra.getRowIndex(), extra.getColumnIndex(), extra.getText());
                break;
            case HYPERLINK:
                if ("Sheet1!A1".equals(extra.getText())) {
                    log.info("額外信息是超鏈接,在rowIndex:{},columnIndex;{},內(nèi)容是:{}", extra.getRowIndex(), extra.getColumnIndex(), extra.getText());
                } else if ("Sheet2!A1".equals(extra.getText())) {
                    log.info("額外信息是超鏈接,而且覆蓋了一個區(qū)間,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}," + "內(nèi)容是:{}",
                            extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
                            extra.getLastColumnIndex(), extra.getText());
                } else {
                    Assert.fail("Unknown hyperlink!");
                }
                break;
            case MERGE:
                log.info("額外信息是超鏈接,而且覆蓋了一個區(qū)間,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}",
                        extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
                        extra.getLastColumnIndex());
                break;
            default:
        }
    }

    /**
     *監(jiān)聽器的hasNext()方法時沒有注意到默認(rèn)返回的是false,導(dǎo)致一進(jìn)監(jiān)聽器就判斷已經(jīng)沒有下一條記錄,直接跳出監(jiān)聽器,然后導(dǎo)入就完成,也不會報錯,改成返回true即可解決
     */
    @Override
    public boolean hasNext(AnalysisContext analysisContext) {
        return true;
    }
}

執(zhí)行方法

package com.example.mybatismysql8demo.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSONObject;
import com.example.mybatismysql8demo.excel.GoodsImportExcel;
import com.example.mybatismysql8demo.handler.DemoDataListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;


@Slf4j
@RestController
public class EasyExcelController {

    @PostMapping("/easyExcelImport")
    public void importExcel(MultipartFile file,Integer type) {
        if (!file.isEmpty()) {
            //文件名稱
            int begin = Objects.requireNonNull(file.getOriginalFilename()).indexOf(".");
            //文件名稱長度
            int last = file.getOriginalFilename().length();
            //判斷文件格式是否正確
            String fileName = file.getOriginalFilename().substring(begin, last);
            if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
                throw new IllegalArgumentException("上傳文件格式錯誤");
            }
        } else {
            throw new IllegalArgumentException("文件不能為空");
        }
        try (InputStream inputStream = file.getInputStream()) {
            if (type == 1){
                simpleRead(inputStream);
            }else if (type == 2){
                synchronousRead(inputStream);
            }else {
                repeatedRead(inputStream);
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    /**
     * 最簡單的讀的監(jiān)聽器
     */
    public void simpleRead(InputStream inputStream){
        //獲取正確數(shù)據(jù)
        ArrayList<GoodsImportExcel> successArrayList = new ArrayList<>();
        //獲取錯誤數(shù)據(jù)
        ArrayList<GoodsImportExcel> errorArrayList = new ArrayList<>();
        EasyExcel.read(inputStream)
                .head(GoodsImportExcel.class)
                .registerReadListener(new DemoDataListener(
                        // 監(jiān)聽器中doAfterAllAnalysed執(zhí)行此方法;所有讀取完成之后處理邏輯
                        successArrayList::addAll, errorArrayList::addAll))
                // 設(shè)置sheet,默認(rèn)讀取第一個
                .sheet()
                // 設(shè)置標(biāo)題(字段列表)所在行數(shù)
                .headRowNumber(2)
                .doReadSync();
        System.out.println(successArrayList);
        System.out.println(errorArrayList);
    }

    /**
     * 同步的返回,不推薦使用,如果數(shù)據(jù)量大會把數(shù)據(jù)放到內(nèi)存里面
     */
    public void synchronousRead(InputStream inputStream){
        // 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet 同步讀取會自動finish
        List<GoodsImportExcel> batchGoodsImportModels = EasyExcel.read(inputStream)
                .head(GoodsImportExcel.class)
                // 設(shè)置sheet,默認(rèn)讀取第一個
                .sheet()
                // 設(shè)置標(biāo)題(字段列表)所在行數(shù)
                .headRowNumber(2)
                .doReadSync();
        System.out.println(JSONObject.toJSONString(batchGoodsImportModels));
    }

    /**
     * 讀取多個sheet
     */
    public void repeatedRead(InputStream inputStream){
        ArrayList<GoodsImportExcel> successArrayList = new ArrayList<>();
        //獲取錯誤數(shù)據(jù)
        ArrayList<GoodsImportExcel> errorArrayList = new ArrayList<>();
        //使用模型來讀取Excel(多個sheet)
        ExcelReader reader = EasyExcel.read(inputStream).build();
        //多個sheet
        List<ReadSheet> sheetList = new ArrayList<>();
        for (int i = 0; i < reader.getSheets().size(); i++){
            // 這里為了簡單,所以注冊了同樣的head 和Listener 自己使用功能必須不同的Listener
            ReadSheet readSheet = EasyExcel.readSheet(i)
                    .head(GoodsImportExcel.class)
                    .registerReadListener(new DemoDataListener(successArrayList::addAll, errorArrayList::addAll))
                    // 設(shè)置標(biāo)題(字段列表)所在行數(shù)
                    .headRowNumber(2)
                    .build();
            sheetList.add(readSheet);
        }
        // 這里注意 一定要把sheet1 sheet2 一起傳進(jìn)去,不然有個問題就是03版的excel 會讀取多次,浪費(fèi)性能
        reader.read(sheetList);
        // 這里千萬別忘記關(guān)閉,讀的時候會創(chuàng)建臨時文件,到時磁盤會崩的
        reader.finish();
        System.out.println(successArrayList);
        System.out.println(errorArrayList);
    }
}

結(jié)果打印
[GoodsImportExcel(goodsName=蘋果, price=10, num=11, errorMsg=null), GoodsImportExcel(goodsName=香蕉, price=8, num=12, errorMsg=null), GoodsImportExcel(goodsName=葡萄, price=20.0, num=40, errorMsg=null)]
[GoodsImportExcel(goodsName=梨子1111, price=11.0, num=30, errorMsg=2行的第1:商品名稱長度超出5個字符串!)]

導(dǎo)入模版
JAVA實(shí)現(xiàn)easyExcel批量導(dǎo)入,項(xiàng)目技術(shù)框架,java,后端,excel

第三種:讀取存在合并

監(jiān)聽器

package com.example.mybatismysql8demo.handler;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;



/**
 * Excel模板的讀取監(jiān)聽類
 * @author gd
 */
public class ImportExcelListener<T> extends AnalysisEventListener<T> {

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

    /**
     * 解析的數(shù)據(jù)
     */
    private final List<T> list = new ArrayList<>();

    /**
     * 正文起始行
     */
    private final Integer headRowNumber;

    /**
     * 合并單元格
     */
    private final List<CellExtra> extraMergeInfoList = new ArrayList<>();


    public ImportExcelListener(Integer headRowNumber) {
        this.headRowNumber = headRowNumber;
    }

    /**
     * 這個每一條數(shù)據(jù)解析都會來調(diào)用
     */
    @Override
    public void invoke(T data, AnalysisContext context) {
        LOGGER.info("數(shù)據(jù)處理: " + JSON.toJSONString(data));
        list.add(data);
    }

    /**
     * 所有數(shù)據(jù)解析完成了 都會來調(diào)用
     * @param context context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        LOGGER.info("所有數(shù)據(jù)解析完成!");
    }


    /**
     * 返回解析出來的List
     */
    public List<T> getData() {
        return list;
    }


    /**
     * 讀取額外信息:合并單元格
     */
    @Override
    public void extra(CellExtra extra, AnalysisContext context) {
        LOGGER.info("讀取到了一條額外信息:{}", JSON.toJSONString(extra));
        switch (extra.getType()) {
            case COMMENT:
                LOGGER.info("額外信息是批注,在rowIndex:{},columnIndex;{},內(nèi)容是:{}", extra.getRowIndex(), extra.getColumnIndex(), extra.getText());
                break;
            case MERGE: {
                LOGGER.info(
                        "額外信息是合并單元格,而且覆蓋了一個區(qū)間,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}",
                        extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(), extra.getLastColumnIndex());
                if (extra.getRowIndex() >= headRowNumber) {
                    extraMergeInfoList.add(extra);
                }
                break;
            }
            default:
        }
    }

    /**
     * 返回解析出來的合并單元格List
     */
    public List<CellExtra> getExtraMergeInfoList() {
        return extraMergeInfoList;
    }
}

合并數(shù)據(jù)處理工具類

package com.example.mybatismysql8demo.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.util.CollectionUtils;
import com.example.mybatismysql8demo.config.LengthValid;
import com.example.mybatismysql8demo.excel.GoodsImportExcel;
import com.example.mybatismysql8demo.handler.ImportExcelListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.List;

public class ImportExcelMergeUtil<T> {

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

    /**
     * 返回解析后的List
     *
     * @param: fileName 文件名
     * @param: clazz Excel對應(yīng)屬性名
     * @param: sheetNo 要解析的sheet
     * @param: headRowNumber 正文起始行
     * @return java.util.List<T> 解析后的List
     */
    public void getList(InputStream inputStream, Class<GoodsImportExcel> clazz, Integer sheetNo, Integer headRowNumber,List<T> successList,List<T> errorList) {
        ImportExcelListener<T> listener = new ImportExcelListener<>(headRowNumber);
        try {
            EasyExcel.read(inputStream, clazz, listener).extraRead(CellExtraTypeEnum.MERGE).sheet(sheetNo).headRowNumber(headRowNumber).doRead();
        } catch (Exception e) {
            LOGGER.error(e.getMessage());
        }
        List<CellExtra> extraMergeInfoList = listener.getExtraMergeInfoList();
        //解析數(shù)據(jù)
        List<T> list;
        if (CollectionUtils.isEmpty(extraMergeInfoList)) {
            list = (listener.getData());
        }else {
            list = explainMergeData(listener.getData(), extraMergeInfoList, headRowNumber);
        }
        //數(shù)據(jù)處理
        for (T v : list) {
            if(validParam(v)){
                errorList.add(v);
            }else {
                successList.add(v);
            }
        }
    }

    private Boolean validParam(T object){
        // 參數(shù)校驗(yàn)
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            //設(shè)置可訪問
            field.setAccessible(true);
            //判斷字段是否添加校驗(yàn)
            boolean valid = field.isAnnotationPresent(LengthValid.class);
            if (valid) {
                try {
                    //獲取注解信息
                    LengthValid annotation = field.getAnnotation(LengthValid.class);
                    //值
                    String value = (String) field.get(object);
                    if(value.length() > annotation.length()){
                        //錯誤信息(需要設(shè)置字段為public)
                        Field errorMsg = object.getClass().getField("errorMsg");
                        if (errorMsg.get(object) == null){
                            errorMsg.set(object, annotation.msg());
                        }else {
                            errorMsg.set(object,errorMsg.get(object) + "," + annotation.msg());
                        }
                        return true;
                    }
                } catch (IllegalAccessException | NoSuchFieldException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 處理合并單元格
     * @param data               解析數(shù)據(jù)
     * @param extraMergeInfoList 合并單元格信息
     * @param headRowNumber      起始行
     * @return 填充好的解析數(shù)據(jù)
     */
    private List<T> explainMergeData(List<T> data, List<CellExtra> extraMergeInfoList, Integer headRowNumber) {
        //循環(huán)所有合并單元格信息
        extraMergeInfoList.forEach(cellExtra -> {
            int firstRowIndex = cellExtra.getFirstRowIndex() - headRowNumber;
            int lastRowIndex = cellExtra.getLastRowIndex() - headRowNumber;
            int firstColumnIndex = cellExtra.getFirstColumnIndex();
            int lastColumnIndex = cellExtra.getLastColumnIndex();
            //獲取初始值
            Object initValue = getInitValueFromList(firstRowIndex, firstColumnIndex, data);
            //設(shè)置值
            for (int i = firstRowIndex; i <= lastRowIndex; i++) {
                for (int j = firstColumnIndex; j <= lastColumnIndex; j++) {
                    setInitValueToList(initValue, i, j, data);
                }
            }
        });
        return data;
    }

    /**
     * 設(shè)置合并單元格的值
     *
     * @param filedValue  值
     * @param rowIndex    行
     * @param columnIndex 列
     * @param data        解析數(shù)據(jù)
     */
    private void setInitValueToList(Object filedValue, Integer rowIndex, Integer columnIndex, List<T> data) {
        T object = data.get(rowIndex);
        for (Field field : object.getClass().getDeclaredFields()) {
            //提升反射性能,關(guān)閉安全檢查
            field.setAccessible(true);
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            if (annotation != null) {
                if (annotation.index() == columnIndex) {
                    try {
                        field.set(object, filedValue);
                        break;
                    } catch (IllegalAccessException e) {
                        LOGGER.error("設(shè)置合并單元格的值異常:"+e.getMessage());
                    }
                }
            }
        }
    }


    /**
     * 獲取合并單元格的初始值
     * rowIndex對應(yīng)list的索引
     * columnIndex對應(yīng)實(shí)體內(nèi)的字段
     * @param firstRowIndex    起始行
     * @param firstColumnIndex 起始列
     * @param data             列數(shù)據(jù)
     * @return 初始值
     */
    private Object getInitValueFromList(Integer firstRowIndex, Integer firstColumnIndex, List<T> data) {
        Object filedValue = null;
        T object = data.get(firstRowIndex);
        for (Field field : object.getClass().getDeclaredFields()) {
            //提升反射性能,關(guān)閉安全檢查
            field.setAccessible(true);
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            if (annotation != null) {
                if (annotation.index() == firstColumnIndex) {
                    try {
                        filedValue = field.get(object);
                        break;
                    } catch (IllegalAccessException e) {
                        LOGGER.error("獲取合并單元格的初始值異常:"+e.getMessage());
                    }
                }
            }
        }
        return filedValue;
    }
}

執(zhí)行方法

package com.example.mybatismysql8demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.mybatismysql8demo.excel.GoodsImportExcel;
import com.example.mybatismysql8demo.utils.ImportExcelMergeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;


@Slf4j
@RestController
public class EasyExcelController {

    @PostMapping("/easyExcelImport")
    public void importExcel(MultipartFile file) {
        if (!file.isEmpty()) {
            //文件名稱
            int begin = Objects.requireNonNull(file.getOriginalFilename()).indexOf(".");
            //文件名稱長度
            int last = file.getOriginalFilename().length();
            //判斷文件格式是否正確
            String fileName = file.getOriginalFilename().substring(begin, last);
            if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
                throw new IllegalArgumentException("上傳文件格式錯誤");
            }
        } else {
            throw new IllegalArgumentException("文件不能為空");
        }
        ImportExcelMergeUtil<GoodsImportExcel> helper = new ImportExcelMergeUtil<>();
        List<GoodsImportExcel> successList = new ArrayList<>();
        List<GoodsImportExcel> errorList = new ArrayList<>();
        try {
            helper.getList(file.getInputStream(), GoodsImportExcel.class,0,2,successList,errorList);
            System.out.println("正確數(shù)據(jù):"+successList);
            System.out.println("錯誤數(shù)據(jù):"+errorList);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

結(jié)果打印
正確數(shù)據(jù):[GoodsImportExcel(goodsName=香蕉, price=8, num=12, errorMsg=null)]
錯誤數(shù)據(jù):[GoodsImportExcel(goodsName=蘋果11111, price=10, num=11, errorMsg=商品名稱長度超出5個字符串!), GoodsImportExcel(goodsName=蘋果11111, price=9.0, num=20, errorMsg=商品名稱長度超出5個字符串!)]

導(dǎo)入模版
JAVA實(shí)現(xiàn)easyExcel批量導(dǎo)入,項(xiàng)目技術(shù)框架,java,后端,excel文章來源地址http://www.zghlxwxcb.cn/news/detail-859882.html

到了這里,關(guān)于JAVA實(shí)現(xiàn)easyExcel批量導(dǎo)入的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包