最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot導(dǎo)出Excel的四種實(shí)現(xiàn)方式

 更新時(shí)間:2024年01月29日 11:42:23   作者:雷襲月啟  
近期接到了一個(gè)小需求,要將系統(tǒng)中的數(shù)據(jù)導(dǎo)出為Excel,且能將Excel數(shù)據(jù)導(dǎo)入到系統(tǒng),對(duì)于大多數(shù)研發(fā)人員來(lái)說(shuō),這算是一個(gè)最基本的操作了,本文就給大家總結(jié)一下SpringBoot導(dǎo)出Excel的四種實(shí)現(xiàn)方式,需要的朋友可以參考下

背景

近期接到了一個(gè)小需求,要將系統(tǒng)中的數(shù)據(jù)導(dǎo)出為Excel,且能將Excel數(shù)據(jù)導(dǎo)入到系統(tǒng)。對(duì)于大多數(shù)研發(fā)人員來(lái)說(shuō),這算是一個(gè)最基本的操作了。但是……我居然有點(diǎn)方!

好多年沒(méi)有實(shí)操這種基礎(chǔ)的功能了。我對(duì)于excel導(dǎo)入導(dǎo)出的印象還停留在才入行時(shí)的工作經(jīng)歷。配模板,建對(duì)應(yīng)的實(shí)體類(lèi),寫(xiě)輸入輸出流…代碼繁瑣而低效,且不能很好的支持Excel中的格式調(diào)整、行列合并等各種復(fù)雜操作,每次回想起這些,我都會(huì)有一種深深的無(wú)力感 。然,研發(fā)技術(shù)的更新?lián)Q代堪稱(chēng)日新月異。這么多年過(guò)去了,也該有更優(yōu)雅的方式實(shí)現(xiàn)這些功能了吧!我翻了下自己這些年積累下來(lái)的屎山代碼,也參考了公司幾位大佬的手段,將現(xiàn)有項(xiàng)目中實(shí)現(xiàn)的Excel導(dǎo)入導(dǎo)出方案整理之后,居然發(fā)現(xiàn),一個(gè)小小的公司里竟有如此多的臥龍鳳雛,連這種基操都能鼓搗出三種以上的方法來(lái)。

方法一:來(lái)自胡大佬的饋贈(zèng) 

第一種方法來(lái)自于胡大佬的推薦,大佬說(shuō)這方法也不是他原創(chuàng)的,而是早年他自某個(gè)項(xiàng)目中偶然覓得,奉為圭臬,忍不住收藏下來(lái)(說(shuō)白了就是從別的項(xiàng)目里COPY的),該方法通過(guò)自研的一套Excel注解,在實(shí)體類(lèi)上添加注解,然后用一套工具類(lèi)(見(jiàn)源碼中com.leixi.excel.util.excelOne)實(shí)現(xiàn)實(shí)體類(lèi)列表的導(dǎo)出。優(yōu)點(diǎn)是不用建模板,調(diào)用簡(jiǎn)單,缺點(diǎn)是遷移麻煩。有好幾個(gè)配套的文件如注解,工具類(lèi)等,想要在別的項(xiàng)目中使用,就涉及到文件的拷貝。老實(shí)說(shuō),不太優(yōu)雅,而且更可惜的是,這些方法里居然沒(méi)有封裝導(dǎo)出方法。下面給出實(shí)體類(lèi)創(chuàng)建,方法調(diào)用的代碼,供各位參考(相關(guān)源碼會(huì)在文中提供)

//引入依賴
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.12</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.3.0</version>
        </dependency>
//controller方法,不得不說(shuō),調(diào)用起來(lái)是真的方便
    @PostMapping(value = "/exportData")
    public ResponseEntity<byte[]> exportData(String fileName) {
        List<ExcelOneDto> list = CommonUtil.buildDemoExcel(ExcelOneDto.class);
        Workbook workbook = new DefaultWriteHandler<ExcelOneDto>().write("sheet名稱(chēng)",list, ExcelOneDto.class);
        return CommonUtil.exportWorkbook(workbook, fileName);
    }
 
 //實(shí)體類(lèi)
@Data
public class ExcelOneDto {
    @ExcelCell(priority = "A", cellTitle = "編號(hào)")
    private Integer code;
 
    @ExcelCell(priority = "B", cellTitle = "名稱(chēng)")
    private String name;
 
 
    @ExcelCell(priority = "C", cellTitle = "詳情")
    private String desc;
 
    @ExcelCell(priority = "D", cellTitle = "備注")
    private String remark;
}

這是導(dǎo)出的測(cè)試結(jié)果:

方法二:ExcelImportUtil工具類(lèi)

第二種方法是我從現(xiàn)有項(xiàng)目中找到的,通過(guò)使用ExcelImportUtil的importExcel和exportExcel實(shí)現(xiàn)數(shù)據(jù)的導(dǎo)入導(dǎo)出。大概是同事抄得不夠高明,初次看到這個(gè)方法時(shí),我覺(jué)得蠻臃腫的,但是在經(jīng)過(guò)遷移和封裝后,代碼量減了不少,用起來(lái)還挺方便,而且該方法還支持Excel導(dǎo)出,以及嵌套的實(shí)體導(dǎo)出,可以說(shuō)是十分高明了。該方法的優(yōu)點(diǎn):不用excel模板,導(dǎo)出導(dǎo)出方便。缺點(diǎn)是封裝的不夠好。研發(fā)人員使用時(shí)需要對(duì)ExcelImportUtil進(jìn)行一定的加工。下面是我封裝后的代碼:

//maven依賴
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.3.0</version>
        </dependency>
//control類(lèi)的導(dǎo)入導(dǎo)出
 
    @PostMapping(value = "/importData")
    public Object importManageData(@RequestPart("file") MultipartFile file) throws Exception {
        return CommonUtil.getExcelDataFromFile(file, ExcelTwoDto.class, 1,2);
    }
 
    @PostMapping(value = "/exportData")
    public ResponseEntity<byte[]> exportData(@RequestParam("fileName") String fileName){
        List<ExcelTwoDto> list  = CommonUtil.buildDemoExcel(ExcelTwoDto.class);
        List<Map<String, Object>> exportView = CommonUtil.buildExportView("測(cè)試Title", "測(cè)試Sheet",list);
        Workbook workbook = ExcelExportUtil.exportExcel(exportView, ExcelType.XSSF);
        ExcelStyleUtil.addNotExistCell(workbook, 0, 3);
        return CommonUtil.exportWorkbook(workbook, fileName);
    }
    
//實(shí)體類(lèi) 
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExcelTwoDto {
 
    @Excel(name = "第一列" ,fixedIndex = 0, orderNum = "0")
    private String codeOne;
    @Excel(name = "第二列" ,fixedIndex = 1, orderNum = "1", width = 50)
    private String codeTwo;
    @ExcelCollection(name = "第三列" , orderNum = "2")
    private List<ExcelChildDto> codeThree;
 
    @Excel(name = "第四列" ,fixedIndex = 4, orderNum = "4", width = 50)
    private String codeFour;
    @Excel(name = "第五列" ,fixedIndex = 5, orderNum = "5")
    private String codeFive;
    @Excel(name = "第六列A", groupName = "第六列匯總" ,fixedIndex = 6, orderNum = "6")
    private String codeThreeOne;
    @Excel(name = "第六列B", groupName = "第六列匯總" ,fixedIndex = 7, orderNum = "7")
    private String codeThreeTwo;
    @Excel(name = "第六列C", groupName = "第六列匯總" ,fixedIndex = 8, orderNum = "8")
    private String codeThreeThree;
}
 
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExcelChildDto {
    @Excel(name = "編碼" ,fixedIndex = 0, orderNum = "0")
    private String code;
    @Excel(name = "名稱(chēng)" ,fixedIndex = 1, orderNum = "1", width = 50)
    private String name;
}

導(dǎo)出測(cè)試結(jié)果:

方法三:Excel模板導(dǎo)出

第三種方案是我從之前的屎山代碼中翻出來(lái)的,通過(guò)excel模板來(lái)實(shí)現(xiàn)的方法,現(xiàn)在基本已經(jīng)廢棄了,之所以放在這里是為了做一個(gè)參照,讓大家看看不同的實(shí)現(xiàn)方法的區(qū)別。這種方式通過(guò)創(chuàng)建一個(gè)Excel模板和對(duì)應(yīng)模板的實(shí)體類(lèi)來(lái)實(shí)現(xiàn)文件導(dǎo)出,優(yōu)點(diǎn)是實(shí)體類(lèi)里不需要加注解了,而且在excel里可以設(shè)計(jì)一些style和格式,缺點(diǎn)是配置excelTemplate太麻煩了。配置繁瑣,且過(guò)程中如出現(xiàn)參數(shù)名錯(cuò)誤,符號(hào)錯(cuò)誤等 ,調(diào)試起來(lái)很不方便,如果要增減字段,實(shí)體類(lèi)和excel都得調(diào)整。下面給出編寫(xiě)的代碼:

// controller方法
    @PostMapping(value = "/exportData")
    public ResponseEntity<byte[]> exportData(@RequestParam("fileName") String fileName) {
        TemplateExportParams params = new TemplateExportParams("templates/template.xlsx");
        params.setScanAllsheet(true);
        Map<String, Object> dataMap = new HashMap<>();
        List<ExcelThreeDto> list  = CommonUtil.buildDemoExcel(ExcelThreeDto.class);
        dataMap.put("titleName", "標(biāo)題名稱(chēng)");
        dataMap.put("desc", "備注名稱(chēng)");
        dataMap.put("dataList", list);
        Workbook workbook = ExcelExportUtil.exportExcel(params, dataMap);
        ExcelStyleUtil.setAutoHeight(workbook, 0, 4);
        return CommonUtil.exportWorkbook(workbook, fileName);
    }
    
//實(shí)體類(lèi)
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class ExcelThreeDto {
        private Integer code;
        private String name;
        private String desc;
        private String remark;
    }

Excel模板的配置

導(dǎo)出的結(jié)果:

由于年代久遠(yuǎn),我沒(méi)能找到對(duì)應(yīng)的模板導(dǎo)入的方法,于是在網(wǎng)上搜索了相關(guān)資料,編寫(xiě)了一個(gè)較通用的文件導(dǎo)入方法:

//maven依賴
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.3.0</version>
        </dependency>
  /**
     * excel 導(dǎo)入
     */
    @PostMapping("/importData")
    public Object upload(@RequestParam(name = "file") MultipartFile file) {
        return CommonUtil.importExcel(file, 3, ExcelThreeDto.class);
    }
 
    /**
     * 通用的excel導(dǎo)入的方法
     *
     * @param file 導(dǎo)入文件
     * @param startRow 第幾行開(kāi)始讀數(shù)據(jù)
     * @param clazz 導(dǎo)入后轉(zhuǎn)成的實(shí)體類(lèi)
     * @return
     * @param <T> 
     */
    @SneakyThrows
    public static <T> List<T> importExcel(MultipartFile file, Integer startRow, Class<T> clazz) {
        Workbook wb = new XSSFWorkbook(file.getInputStream());
        //1.2.獲取Sheet
        Sheet sheet = wb.getSheetAt(0);
        List<T> list = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        for (int rowNum = startRow; rowNum <= sheet.getLastRowNum(); rowNum++) {
            //根據(jù)索引獲取每一個(gè)行
            Row row = sheet.getRow(rowNum);
            T obj = clazz.newInstance();
            for (int cellNum = 0; cellNum < row.getLastCellNum() && cellNum< fields.length; cellNum++) {
                Cell cell = row.getCell(cellNum);
                Object value = CommonUtil.getCellValue(cell);
                Field field = fields[cellNum];
                field.setAccessible(true);
                // 注意,這里是為了演示,只分析了Integer和String的寫(xiě)法,實(shí)際上要根據(jù)Field數(shù)據(jù)的枚舉分類(lèi)處理
                if (field.getType().equals(Integer.class) && value != null) {
                    field.set(obj, new Double(value.toString()).intValue());
                } else {
                    field.set(obj, value);
                }
            }
            list.add(obj);
        }
        return list;
    }

導(dǎo)入的結(jié)果還是蠻令人滿意的:

方法四:easyexcel

以上這些都是我從以往的項(xiàng)目中見(jiàn)識(shí)到的Excel導(dǎo)入導(dǎo)出方法,那么,時(shí)下流行的方式是什么樣的呢?網(wǎng)上搜索資料得知,現(xiàn)在使用頻率較高的是用easyexcel實(shí)現(xiàn)的。經(jīng)過(guò)一番了解,我將easyexcel的實(shí)現(xiàn)方式也列出來(lái)作為參考。該方法的優(yōu)點(diǎn)是使用方便,功能強(qiáng)大!本文中我只實(shí)現(xiàn)了最簡(jiǎn)單的導(dǎo)入導(dǎo)出,easyexcel還支持很多如嵌套導(dǎo)入,合并行列等高級(jí)操作

//引入maven依賴
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.1.3</version>
        </dependency>
//controller:
    @PostMapping(value = "/exportData")
    public void exportData(String fileName, HttpServletResponse response) {
        try {
            this.setExcelResponseProp(response, fileName);
            List<ExcelFourDto> list = CommonUtil.buildDemoExcel(ExcelFourDto.class);;
            EasyExcel.write(response.getOutputStream())
                    .head(ExcelFourDto.class)
                    .excelType(ExcelTypeEnum.XLSX)
                    .sheet(fileName)
                    .doWrite(list);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
 
    @PostMapping("/importData")
    @SneakyThrows
    public Object importUserExcel(@RequestPart("file") MultipartFile file) {
            List<ExcelFourDto> list = EasyExcel.read(file.getInputStream())
                    .head(ExcelFourDto.class).sheet().doReadSync();
            return list;
    }
    
    /**
     * 設(shè)置響應(yīng)結(jié)果
     *
     * @param response    響應(yīng)結(jié)果對(duì)象
     * @param rawFileName 文件名
     * @throws UnsupportedEncodingException 不支持編碼異常
     */
    private void setExcelResponseProp(HttpServletResponse response, String rawFileName) throws UnsupportedEncodingException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode(rawFileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
    } 
 
// 實(shí)體類(lèi)
@Data
public class ExcelFourDto {
    @ExcelProperty("編號(hào)")
    @ColumnWidth(20)
    private Integer code;
 
    @ExcelProperty("名稱(chēng)")
    @ColumnWidth(20)
    private String name;
 
    @ExcelProperty("詳情")
    @ColumnWidth(20)
    private String desc;
 
    @ExcelProperty("備注")
    @ColumnWidth(20)
    private String remark;
}

以下是測(cè)試結(jié)果:

原以為胡大佬的方法已經(jīng)是別開(kāi)生面了,但是對(duì)比起來(lái),仍然是落伍了很多(希望胡大佬不要看到這篇博客)。時(shí)代真是進(jìn)步的飛快,對(duì)于程序員來(lái)說(shuō),這種變遷顯得尤為明顯。它就像一根鞭子,不斷的抽打著碼農(nóng)們,稍有懈怠就會(huì)被這洪流所淹沒(méi)…

 (文中附上四種方式的源碼,僅用于學(xué)習(xí)和參考!)

以上就是SpringBoot導(dǎo)出Excel的四種實(shí)現(xiàn)方式的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot導(dǎo)出Excel的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解Java中Stream流的用法和原理

    詳解Java中Stream流的用法和原理

    最近編碼的時(shí)候用到了Stream這個(gè)東西,以前也用過(guò),但是對(duì)它沒(méi)有一個(gè)系統(tǒng)的認(rèn)知,在好奇心的驅(qū)動(dòng)下還是決定花一些時(shí)間去系統(tǒng)地學(xué)一學(xué),不了解Stream的同學(xué)可以看看本文,對(duì)大家的學(xué)習(xí)和工作有一定的幫助
    2023-10-10
  • IDEA快速搭建spring?boot項(xiàng)目教程(Spring?initializr)

    IDEA快速搭建spring?boot項(xiàng)目教程(Spring?initializr)

    這篇文章主要介紹了IDEA快速搭建spring?boot項(xiàng)目教程(Spring?initializr),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • java開(kāi)源調(diào)度如何給xxljob加k8s執(zhí)行器

    java開(kāi)源調(diào)度如何給xxljob加k8s執(zhí)行器

    這篇文章主要介紹了java開(kāi)源調(diào)度如何給xxljob加一個(gè)k8s執(zhí)行器,?xxljob?在設(shè)計(jì)上,抽象出了執(zhí)行器的接口,所以實(shí)現(xiàn)一個(gè)語(yǔ)言的執(zhí)行器并不復(fù)雜,這里主要探索下,如何利用k8s的pod?的能力,使用?xxljob?調(diào)度?pod?運(yùn)行,實(shí)現(xiàn)一個(gè)通用的和語(yǔ)言無(wú)關(guān)的執(zhí)行器
    2022-02-02
  • SpringBoot配置actuator的代碼

    SpringBoot配置actuator的代碼

    這篇文章主要介紹了SpringBoot配置actuator,這里大家需要注意可以監(jiān)控SpringBoot?中的?Tomcat?性能數(shù)據(jù),?以日志形式定期輸出監(jiān)控?cái)?shù)據(jù),?只需要配置一個(gè)Bean,需要的朋友可以參考下
    2022-03-03
  • SpringBoot中@Configuration和@Bean和@Component相同點(diǎn)詳解

    SpringBoot中@Configuration和@Bean和@Component相同點(diǎn)詳解

    這篇文章主要介紹了SpringBoot中@Configuration和@Bean和@Component相同點(diǎn)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Spring?InitializingBean的使用方式

    Spring?InitializingBean的使用方式

    InitializingBean是Spring框架中的一個(gè)生命周期接口,用于在Bean的屬性設(shè)置完成后執(zhí)行自定義的初始化邏輯,本文給大家介紹spring?InitializingBean的使用方式,感興趣的朋友小編一起看看吧
    2026-01-01
  • 如何重寫(xiě)hashcode和equals方法

    如何重寫(xiě)hashcode和equals方法

    這篇文章主要介紹了如何重寫(xiě)hashcode和equals方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java實(shí)現(xiàn)Word/Pdf/TXT轉(zhuǎn)html的示例

    Java實(shí)現(xiàn)Word/Pdf/TXT轉(zhuǎn)html的示例

    這篇文章主要介紹了Java實(shí)現(xiàn)Word/Pdf/TXT轉(zhuǎn)html的示例,幫助大家方便的進(jìn)行文件格式轉(zhuǎn)換,完成需求,感興趣的朋友可以了解下
    2020-11-11
  • Spring如何解決單例bean線程不安全的問(wèn)題

    Spring如何解決單例bean線程不安全的問(wèn)題

    這篇文章主要介紹了Spring如何解決單例bean線程不安全的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • SSM項(xiàng)目中配置LOG4J日志的方法

    SSM項(xiàng)目中配置LOG4J日志的方法

    本篇文章主要介紹了SSM項(xiàng)目中配置LOG4J日志的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09

最新評(píng)論

新乡县| 察哈| 定兴县| 大冶市| 阿巴嘎旗| 环江| 吴桥县| 尖扎县| 开封县| 财经| 高青县| 申扎县| 长沙市| 西和县| 宣城市| 余干县| 拜城县| 武强县| 博乐市| 兴山县| 高陵县| 海淀区| 黔西县| 鹤壁市| 兰考县| 济南市| 新源县| 明光市| 淮安市| 彰武县| 常宁市| 太保市| 抚顺县| 阳原县| 潜江市| 阳高县| 正安县| 汝南县| 扶余县| 凉城县| 浏阳市|