欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?Boot項(xiàng)目如何優(yōu)雅實(shí)現(xiàn)Excel導(dǎo)入與導(dǎo)出功能

 更新時(shí)間:2022年06月10日 16:47:40   作者:大鵬cool  
在我們平時(shí)工作中經(jīng)常會(huì)遇到要操作Excel的功能,比如導(dǎo)出個(gè)用戶(hù)信息或者訂單信息的Excel報(bào)表,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot項(xiàng)目中如何優(yōu)雅實(shí)現(xiàn)Excel導(dǎo)入與導(dǎo)出功能的相關(guān)資料,需要的朋友可以參考下

背景

Excel 導(dǎo)入與導(dǎo)出是項(xiàng)目中經(jīng)常用到的功能,在 Java 中常用 poi 實(shí)現(xiàn) Excel 的導(dǎo)入與導(dǎo)出。由于 poi 占用內(nèi)存較大,在高并發(fā)下很容易發(fā)生 OOM 或者頻繁 fullgc,阿里基于 poi 開(kāi)源了 EasyExcel 項(xiàng)目。

除了節(jié)約內(nèi)存,EasyExcel 還簡(jiǎn)化了 API,通過(guò)注解映射 Excel 單元格與對(duì)象字段之間的關(guān)系,簡(jiǎn)單的幾行代碼就能搞定復(fù)雜的導(dǎo)入導(dǎo)出功能了。

EasyExcel 問(wèn)題

看似一切美好,不過(guò)經(jīng)常做 Excel 導(dǎo)入與導(dǎo)出就會(huì)發(fā)現(xiàn),EasyExcel 還是沒(méi)那么完美的。

首先,導(dǎo)入與導(dǎo)出 Excel 本質(zhì)是上將 Excel 文件內(nèi)容與 Java 對(duì)象之間做一個(gè)映射,EasyExcel 做的只是在這兩者之間轉(zhuǎn)換。如果項(xiàng)目中的 Excel 導(dǎo)入與導(dǎo)出功能比較多,會(huì)產(chǎn)生大量的樣板式代碼,使用體驗(yàn)類(lèi)似于 JDBC。

另外,導(dǎo)入往往還伴隨著校驗(yàn),這是 EasyExcel 沒(méi)有支持的功能。如果需要校驗(yàn),要么寫(xiě)代碼手動(dòng)判斷,要么調(diào)用 Java Validation 規(guī)范 定義的 API 判斷,這又會(huì)產(chǎn)生大量樣板式代碼。

而且,當(dāng)前 spring boot 已經(jīng)成了必備的 Java 開(kāi)發(fā)框架,easyexcel 也沒(méi)有進(jìn)行整合。

分析與解決

導(dǎo)入與導(dǎo)出通常發(fā)生在 Web 環(huán)境,對(duì)于 Spring MVC 來(lái)說(shuō),可以將請(qǐng)求信息轉(zhuǎn)換為任意類(lèi)型的 contoller 方法參數(shù),將 controller 方法返回值轉(zhuǎn)換為客戶(hù)端支持的內(nèi)容。

如果能夠使用自定義的 controller 方法參數(shù)接收 Excel 文件內(nèi)容,將 controller 方法返回值轉(zhuǎn)換為 Excel 文件響應(yīng),可以直接消除 Excel 導(dǎo)入與導(dǎo)出時(shí)的樣板式代碼。

另外在將請(qǐng)求內(nèi)容轉(zhuǎn)換為 controller 方法參數(shù)時(shí)還可以加入自定義的校驗(yàn)邏輯。

由于 Excel 導(dǎo)入與導(dǎo)出樣板式代碼、校驗(yàn)問(wèn)題與具體的業(yè)務(wù)邏輯無(wú)關(guān),可以單獨(dú)抽象出來(lái),我這里在 EasyExcel 的基礎(chǔ)上封裝了一個(gè) easyexcel-spring-boot-starter 的項(xiàng)目,大大降低了 EasyExcel 上手的門(mén)檻,對(duì)用戶(hù)來(lái)說(shuō)只需要使用 EasyExcel 定義的注解提供映射關(guān)系就可以了,適用于簡(jiǎn)單場(chǎng)景的導(dǎo)入導(dǎo)出。

項(xiàng)目代碼已上傳 github easyexcel-spring-boot-starter 倉(cāng)庫(kù),點(diǎn)擊鏈接即可查閱。下面就來(lái)看看怎樣使用吧。

Spring Boot Excel 導(dǎo)入與導(dǎo)出

依賴(lài)引入

首先需要引入依賴(lài),坐標(biāo)如下。

<dependency>
    <groupId>com.zzuhkp</groupId>
    <artifactId>easyexcel-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

不過(guò)很不幸的是目前還沒(méi)傳至中央倉(cāng)庫(kù),需要的小伙伴可自行上傳到私有倉(cāng)庫(kù)或直接把代碼嵌入自己的項(xiàng)目。

Excel 導(dǎo)入

首先看下要導(dǎo)入的 Excel 內(nèi)容吧。

為了接收 Excel 文件內(nèi)容,我們需要定義一個(gè)對(duì)應(yīng)的 Model 類(lèi)。

@Data
public class DemoData {
    @ExcelProperty(index = 0)
    private Integer integer;

    @ExcelProperty(index = 1)
    private String string;

    @ExcelProperty(index = 2)
    private Date date;
}

基本導(dǎo)入功能

然后使用 List<T> 參數(shù)接收即可。

@PostMapping("/list/obj")
public List<DemoData> listObj(@ExcelParam List<DemoData> list) {
    return list;
}

注意參數(shù)前添加了 @ExcelParam 注解,用來(lái)標(biāo)識(shí) Excel 文件參數(shù)。這樣,一個(gè)導(dǎo)入功能實(shí)現(xiàn)了,是不是很簡(jiǎn)單呢?

默認(rèn)情況下接收名稱(chēng)為 file 的表單字段作為 Excel 文件,如果不滿(mǎn)足還可以修改。

@ExcelParam(value = "file", required = true)

進(jìn)階導(dǎo)入功能

有時(shí)候,我們可能比較關(guān)心對(duì)象對(duì)應(yīng) Excel 的元數(shù)據(jù),例如這個(gè)對(duì)象是第幾行記錄產(chǎn)生的,這個(gè)對(duì)象的字段對(duì)應(yīng) Excel 第幾列,這個(gè)時(shí)候我們可以使用 ReadRows<T> 參數(shù)接收 Excel。

@PostMapping("/list/rows")
public ReadRows<DemoData> readRows(@ExcelParam ReadRows<DemoData> readRows) {
    return readRows;
}

ReadRows 使用兩個(gè)字段記錄行映射關(guān)系與列映射關(guān)系。

public class ReadRows<T> {

    private ExcelReadHeadProperty excelReadHeadProperty;

    private List<ReadRow<T>> rows;
}

ExcelReadHeadProperty 是 EasyExcel 自帶的類(lèi),表示列映射關(guān)系的元數(shù)據(jù)。ReadRow 是框架自定義的類(lèi),表示行映射關(guān)系的元數(shù)據(jù)。

看下 ReadRow 定義吧。

public class ReadRow<T> {

    // 行索引,從 0 開(kāi)始
    private final Integer rowIndex;

    // 行記錄對(duì)應(yīng)對(duì)象
    private final T data;
}

使用 ExcelReadHeadProperty 獲取字段對(duì)應(yīng)列索引的示例代碼如下。

// 對(duì)象字段名稱(chēng) -> 從 0 開(kāi)始的列索引
Map<String, Integer> fieldColumnIndexMap = readRows.getExcelReadHeadProperty().getHeadMap().values()
        .stream().collect(Collectors.toMap(Head::getFieldName, Head::getColumnIndex));

Excel 導(dǎo)出

這里對(duì) Excel 的導(dǎo)出進(jìn)行了簡(jiǎn)單的支持。將 List<T> 定義為 controller 方法返回值即可。

@ExcelResponse
@GetMapping("/list/download")
public List<DemoData> downloadList() {
    return Arrays.asList(new DemoData(1, "hello", new Date()), new DemoData(2, "excel", new Date()));
}

需要注意的是使用 @ExcelResponse 注解表示響應(yīng)內(nèi)容為 Excel 文件。默認(rèn)情況,下載的文件名稱(chēng)為 default.xlxs,寫(xiě)入到名稱(chēng)為 Sheet1 的工作表中。如果不滿(mǎn)足需求可以修改。

@ExcelResponse(fileName = "測(cè)試文件", sheetName = "工作表1")

Excel 導(dǎo)入?yún)?shù)校驗(yàn)

參數(shù)校驗(yàn)是 Excel 導(dǎo)入常用的功能,這里進(jìn)行了強(qiáng)有力的支持,使用體驗(yàn)如原生 spring boot 校驗(yàn)般順滑。

開(kāi)啟校驗(yàn)

與 spring boot 原生使用方式一樣,將 @Validated@Valid 注解添加到 @ExcelParam 參數(shù)上即可。

@PostMapping("/list/obj")
public List<DemoData> listObj(@ExcelParam @Validated List<DemoData> list) {
    return list;
}

校驗(yàn)規(guī)則定義

Bean Validation 定義校驗(yàn)規(guī)則

默認(rèn)情況下框架使用 JSR-303 Bean Validation 規(guī)范定義的校驗(yàn)注解校驗(yàn),需要手動(dòng)引入 spring-boot-starter-validation,可通過(guò)設(shè)置環(huán)境變量 easyexcel.validator.default.enable=false 關(guān)閉。

@Data
public class DemoData {
    @NotNull(message = "參數(shù)不能為空")
    private Integer integer;

    private String string;

    private Date date;
}

另外還可以自定義注解對(duì)對(duì)象校驗(yàn)。

... 省略其他元注解
@Constraint(validatedBy = {DemoDataValid.DemoDataValidator.class})
public @interface DemoDataValid {
		... 省略注解屬性
		
    class DemoDataValidator implements ConstraintValidator<DemoDataValid, DemoData> {

        @Override
        public boolean isValid(DemoData value, ConstraintValidatorContext context) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("測(cè)試對(duì)象校驗(yàn)").addConstraintViolation();
            return false;
        }
    }
}
@DemoDataValid
public class DemoData {
    ... 省略屬性
}

ExcelValidator 接口定義校驗(yàn)規(guī)則

Bean Validation 注解只能校驗(yàn)單個(gè)字段或?qū)ο?,如果需要?duì)所有的對(duì)象進(jìn)行校驗(yàn),可以實(shí)現(xiàn)框架定義的 ExcelValidator 接口,然后將實(shí)現(xiàn)定義為 Spring Bean。

這個(gè)接口定義如下。

public interface ExcelValidator<T> {
    ExcelValidErrors validate(ReadRows<T> readRows);
}

ExcelValidErrors 用于接收校驗(yàn)的錯(cuò)誤信息,分別使用接口 ExcelValidObjectErrorExcelValidFieldError 接口定義行錯(cuò)誤信息和單元格錯(cuò)誤信息。

public class ExcelValidErrors {
	// 行錯(cuò)誤信息或單元格錯(cuò)誤信息列表
    private final List<ExcelValidObjectError> errors;
}

public interface ExcelValidObjectError {
    // 獲取行號(hào),從 1 開(kāi)始
    Integer getRow();

    // 獲取錯(cuò)誤消息
    String getMessage();
}

public interface ExcelValidFieldError extends ExcelValidObjectError {
    // 獲取列,從 1 開(kāi)始
    Integer getColumn();
}

例如,如果需要對(duì)所有的 DemoData 校驗(yàn) integer 字段的值不能重復(fù),可以使用如下的代碼。

@Component
public class CustomExcelValidator implements ExcelValidator<DemoData> {
    @Override
    public ExcelValidErrors validate(ReadRows<DemoData> readRows) {
        ExcelValidErrors errors = new ExcelValidErrors();

        Map<Integer, List<ReadRow<DemoData>>> group = readRows.getRows().stream()
                .collect(Collectors.groupingBy(item -> item.getData().getInteger()));

        for (Map.Entry<Integer, List<ReadRow<DemoData>>> entry : group.entrySet()) {
            if (entry.getValue().size() > 1) {
                for (ReadRow<DemoData> readRow : entry.getValue()) {
                    errors.addError(new DefaultExcelObjectError(readRow.getRowIndex() + 1, "參數(shù)重復(fù)"));
                }
            }
        }
        return errors;
    }
}

校驗(yàn)結(jié)果接收

與 Spring MVC 設(shè)計(jì)類(lèi)似,這里也提供了兩種接收校驗(yàn)結(jié)果的方式。

異常捕獲接收校驗(yàn)結(jié)果

開(kāi)啟校驗(yàn)后,如果校驗(yàn)結(jié)果中包含錯(cuò)誤,會(huì)將錯(cuò)誤信息封裝到 ExcelValidException,并拋出異常,可以通過(guò)全局異常捕獲的方式收集錯(cuò)誤信息。

@RestControllerAdvice
public class GlobalExceptionControllerAdvice {
    @ExceptionHandler(ExcelValidException.class)
    public String handleException(ExcelValidException e) {
        ExcelValidErrors errors = e.getErrors();
        return JSON.toJSONString(errors);
    }
}

controller 方法參數(shù)接收校驗(yàn)結(jié)果

如果不想通過(guò)異常捕獲的方式接收校驗(yàn)的錯(cuò)誤信息,還可以將錯(cuò)誤信息添加到 @ExcelParam 參數(shù)的后面,示例代碼如下。

@PostMapping("/list/obj")
public List<DemoData> listObj(@ExcelParam @Validated List<DemoData> list, ExcelValidErrors errors) {
    if (errors.hasErrors()) {
        String messages = errors.getAllErrors().stream().map(ExcelValidObjectError::getMessage).collect(Collectors.joining(" | "));
        throw new RuntimeException("發(fā)現(xiàn)異常:" + messages);
    }
    return list;
}

總結(jié)

easyexcel-spring-boot-starter 綜合應(yīng)用了前面文章介紹的各種 Spring 知識(shí),代碼量并不大,對(duì)實(shí)現(xiàn)感興趣的小伙伴可自行查閱代碼。由于這個(gè)框架是把 Excel 中所有的行數(shù)據(jù)收集到內(nèi)存,因此只適合一些比較簡(jiǎn)單的場(chǎng)景。

到此這篇關(guān)于Spring Boot項(xiàng)目如何優(yōu)雅實(shí)現(xiàn)Excel導(dǎo)入與導(dǎo)出功能的文章就介紹到這了,更多相關(guān)SpringBoot實(shí)現(xiàn)Excel導(dǎo)入導(dǎo)出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringCloudAlibaba分布式組件詳解

    SpringCloudAlibaba分布式組件詳解

    這篇文章主要介紹了簡(jiǎn)單了解Spring Cloud Alibaba分布式組件相關(guān)知識(shí),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-08-08
  • Springboot使用RestTemplate調(diào)用第三方接口的操作代碼

    Springboot使用RestTemplate調(diào)用第三方接口的操作代碼

    這篇文章主要介紹了Springboot使用RestTemplate調(diào)用第三方接口,我只演示了最常使用的請(qǐng)求方式get、post的簡(jiǎn)單使用方法,當(dāng)然RestTemplate的功能還有很多,感興趣的朋友可以參考RestTemplate源碼
    2022-12-12
  • SpringBoot中如何啟動(dòng)Tomcat流程

    SpringBoot中如何啟動(dòng)Tomcat流程

    這篇文章主要介紹了SpringBoot中如何啟動(dòng)Tomcat流程,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-05-05
  • Java輕量級(jí)權(quán)限認(rèn)證框架Sa-Token的使用

    Java輕量級(jí)權(quán)限認(rèn)證框架Sa-Token的使用

    Sa-Token是一個(gè)輕量級(jí)Java權(quán)限認(rèn)證框架,本文就詳細(xì)的來(lái)介紹一下Java輕量級(jí)權(quán)限認(rèn)證框架Sa-Token的使用,主要解決:登錄認(rèn)證、權(quán)限認(rèn)證、Session會(huì)話(huà)、單點(diǎn)登錄、OAuth2.0、微服務(wù)網(wǎng)關(guān)鑒權(quán)等,感興趣的可以了解一下
    2022-03-03
  • Java+Swing實(shí)現(xiàn)醫(yī)院管理系統(tǒng)的完整代碼

    Java+Swing實(shí)現(xiàn)醫(yī)院管理系統(tǒng)的完整代碼

    這篇文章主要介紹了Java+Swing實(shí)現(xiàn)醫(yī)院管理系統(tǒng)的完整代碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-05-05
  • 在Java中如何決定使用 HashMap 還是 TreeMap

    在Java中如何決定使用 HashMap 還是 TreeMap

    這篇文章主要介紹了在Java中如何決定使用 HashMap 還是 TreeMap,很多朋友對(duì)這樣的問(wèn)題很迷茫,下面小編給大家?guī)?lái)一篇文章幫助大家了解,需要的朋友可以參考下
    2019-10-10
  • Java中的ReentrantLock解讀

    Java中的ReentrantLock解讀

    這篇文章主要介紹了Java中的ReentrantLock解讀,ReentantLock是java中重入鎖的實(shí)現(xiàn),一次只能有一個(gè)線(xiàn)程來(lái)持有鎖,包含三個(gè)內(nèi)部類(lèi),Sync、NonFairSync、FairSync,需要的朋友可以參考下
    2023-09-09
  • Java中從JSON轉(zhuǎn)Java實(shí)體的多種方法詳解

    Java中從JSON轉(zhuǎn)Java實(shí)體的多種方法詳解

    在現(xiàn)在的日常開(kāi)發(fā)中不管前端還是后端,JSON 格式的數(shù)據(jù)是用得比較多的,甚至可以說(shuō)無(wú)處不在,這篇文章主要給大家介紹了關(guān)于Java中從JSON轉(zhuǎn)Java實(shí)體的多種方法,需要的朋友可以參考下
    2023-12-12
  • java二維數(shù)組遍歷的2種代碼

    java二維數(shù)組遍歷的2種代碼

    這篇文章主要介紹了java二維數(shù)組遍歷的2種代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之養(yǎng)老院管理系統(tǒng)的實(shí)現(xiàn)

    Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之養(yǎng)老院管理系統(tǒng)的實(shí)現(xiàn)

    讀萬(wàn)卷書(shū)不如行萬(wàn)里路,只學(xué)書(shū)上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SSM+JSP+Easyui+maven+mysql實(shí)現(xiàn)一個(gè)養(yǎng)老院管理系統(tǒng),大家可以在過(guò)程中查缺補(bǔ)漏,提升水平
    2022-03-03

最新評(píng)論