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

【Alibaba工具型技術(shù)系列】「EasyExcel技術(shù)專題」實(shí)戰(zhàn)技術(shù)針對(duì)于項(xiàng)目中常用的Excel操作指南

這篇具有很好參考價(jià)值的文章主要介紹了【Alibaba工具型技術(shù)系列】「EasyExcel技術(shù)專題」實(shí)戰(zhàn)技術(shù)針對(duì)于項(xiàng)目中常用的Excel操作指南。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

EasyExcel教程

本文使用的技術(shù)是Alibaba集團(tuán)開(kāi)源的EasyExcel技術(shù),該技術(shù)是針對(duì)Apache POI技術(shù)的封裝和優(yōu)化,主要解決了POI技術(shù)的耗內(nèi)存問(wèn)題,并且提供了較好的API使用。

  • 使用步驟繁瑣
  • 動(dòng)態(tài)寫出Excel操作非常麻煩
  • 對(duì)于新手來(lái)說(shuō),很難在短時(shí)間內(nèi)上手
  • 讀寫時(shí)需要占用較大的內(nèi)容,當(dāng)數(shù)據(jù)量大時(shí)容器發(fā)生OOM
Maven依賴
  <!-- easyexcel 依賴 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.7</version>
        </dependency>

EasyExcel API分析介紹

  • ? EasyExcel入口類,用于構(gòu)建開(kāi)始各種操作

  • ? ExcelReaderBuilder ExcelWriterBuilder 構(gòu)建出一個(gè) ReadWorkbook WriteWorkbook,可以理解成一個(gè)excel對(duì)象,一個(gè)excel只要構(gòu)建一個(gè)

  • ? ExcelReaderSheetBuilder ExcelWriterSheetBuilder 構(gòu)建出一個(gè) ReadSheet WriteSheet對(duì)象,可以理解成excel里面的一頁(yè),每一頁(yè)都要構(gòu)建一個(gè)

  • ? ReadListener在每一行讀取完畢后都會(huì)調(diào)用ReadListener來(lái)處理數(shù)據(jù)

  • ? WriteHandler在每一個(gè)操作包括創(chuàng)建單元格、創(chuàng)建表格等都會(huì)調(diào)用WriteHandler來(lái)處理數(shù)據(jù)

  • ? 所有配置都是繼承的,Workbook的配置會(huì)被Sheet繼承,所以在用EasyExcel設(shè)置參數(shù)的時(shí)候,在EasyExcel…sheet()方法之前作用域是整個(gè)sheet,之后針對(duì)單個(gè)sheet

EasyExcel 注解

  • ? ExcelProperty 指定當(dāng)前字段對(duì)應(yīng)excel中的那一列??梢愿鶕?jù)名字或者Index去匹配。當(dāng)然也可以不寫,默認(rèn)第一個(gè)字段就是index=0,以此類推。千萬(wàn)注意,要么全部不寫,要么全部用index,要么全部用名字去匹配。千萬(wàn)別三個(gè)混著用,除非你非常了解源代碼中三個(gè)混著用怎么去排序的。

  • ? ExcelIgnore 默認(rèn)所有字段都會(huì)和excel去匹配,加了這個(gè)注解會(huì)忽略該字段

  • ? DateTimeFormat 日期轉(zhuǎn)換,用String去接收excel日期格式的數(shù)據(jù)會(huì)調(diào)用這個(gè)注解。里面的value參照java.text.SimpleDateFormat

  • ? NumberFormat 數(shù)字轉(zhuǎn)換,用String去接收excel數(shù)字格式的數(shù)據(jù)會(huì)調(diào)用這個(gè)注解。里面的value參照java.text.DecimalFormat

  • ? ExcelIgnoreUnannotated 默認(rèn)不加ExcelProperty 的注解的都會(huì)參與讀寫,加了不會(huì)參與

通用參數(shù)

  • ? ReadWorkbook,ReadSheet 都會(huì)有的參數(shù),如果為空,默認(rèn)使用上級(jí)。

  • ? converter 轉(zhuǎn)換器,默認(rèn)加載了很多轉(zhuǎn)換器。也可以自定義。

  • ? readListener 監(jiān)聽(tīng)器,在讀取數(shù)據(jù)的過(guò)程中會(huì)不斷的調(diào)用監(jiān)聽(tīng)器。

  • ? headRowNumber 需要讀的表格有幾行頭數(shù)據(jù)。默認(rèn)有一行頭,也就是認(rèn)為第二行開(kāi)始起為數(shù)據(jù)。

  • ? head 與clazz二選一。讀取文件頭對(duì)應(yīng)的列表,會(huì)根據(jù)列表匹配數(shù)據(jù),建議使用class。

  • ? clazz 與head二選一。讀取文件的頭對(duì)應(yīng)的class,也可以使用注解。如果兩個(gè)都不指定,則會(huì)讀取全部數(shù)據(jù)。

  • ? autoTrim 字符串、表頭等數(shù)據(jù)自動(dòng)trim

  • ? password 讀的時(shí)候是否需要使用密碼

ReadWorkbook(理解成excel對(duì)象)參數(shù)
  • ? excelType 當(dāng)前excel的類型 默認(rèn)會(huì)自動(dòng)判斷

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

  • ? file 與inputStream二選一。讀取文件的文件。

  • ? autoCloseStream 自動(dòng)關(guān)閉流。

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

ReadSheet(就是excel的一個(gè)Sheet)參數(shù)
  • ? sheetNo 需要讀取Sheet的編碼,建議使用這個(gè)來(lái)指定讀取哪個(gè)Sheet

  • ? sheetName 根據(jù)名字去匹配Sheet,excel 2003不支持根據(jù)名字去匹配

注解
  • ? ExcelProperty index 指定寫到第幾列,默認(rèn)根據(jù)成員變量排序。value指定寫入的名稱,默認(rèn)成員變量的名字,多個(gè)value可以參照快速開(kāi)始中的復(fù)雜頭

  • ? ExcelIgnore 默認(rèn)所有字段都會(huì)寫入excel,這個(gè)注解會(huì)忽略這個(gè)字段

  • ? DateTimeFormat 日期轉(zhuǎn)換,將Date寫到excel會(huì)調(diào)用這個(gè)注解。里面的value參照java.text.SimpleDateFormat

  • ? NumberFormat 數(shù)字轉(zhuǎn)換,用Number寫excel會(huì)調(diào)用這個(gè)注解。里面的value參照java.text.DecimalFormat

  • ? ExcelIgnoreUnannotated 默認(rèn)不加ExcelProperty 的注解的都會(huì)參與讀寫,加了不會(huì)參與

參數(shù)
通用參數(shù)
  • ? WriteWorkbook,WriteSheet ,WriteTable都會(huì)有的參數(shù),如果為空,默認(rèn)使用上級(jí)。

  • ? converter 轉(zhuǎn)換器,默認(rèn)加載了很多轉(zhuǎn)換器。也可以自定義。

  • ? writeHandler 寫的處理器。可以實(shí)現(xiàn)WorkbookWriteHandler,SheetWriteHandler,RowWriteHandler,CellWriteHandler,在寫入excel的不同階段會(huì)調(diào)用

  • ? relativeHeadRowIndex 距離多少行后開(kāi)始。也就是開(kāi)頭空幾行

  • ? needHead 是否導(dǎo)出頭

  • ? head 與clazz二選一。寫入文件的頭列表,建議使用class。

  • ? clazz 與head二選一。寫入文件的頭對(duì)應(yīng)的class,也可以使用注解。

  • ? autoTrim 字符串、表頭等數(shù)據(jù)自動(dòng)trim

WriteWorkbook(理解成excel對(duì)象)參數(shù)
  • ? excelType 當(dāng)前excel的類型 默認(rèn)xlsx

  • ? outputStream 與file二選一。寫入文件的流

  • ? file 與outputStream二選一。寫入的文件

  • ? templateInputStream 模板的文件流

  • ? templateFile 模板文件

  • ? autoCloseStream 自動(dòng)關(guān)閉流。

  • ? password 寫的時(shí)候是否需要使用密碼

  • ? useDefaultStyle 寫的時(shí)候是否是使用默認(rèn)頭

WriteSheet(就是excel的一個(gè)Sheet)參數(shù)
  • ? sheetNo 需要寫入的編碼。默認(rèn)0

  • ? sheetName 需要些的Sheet名稱,默認(rèn)同sheetNo

WriteTable(就把excel的一個(gè)Sheet,一塊區(qū)域看一個(gè)table)參數(shù)
  • ? tableNo 需要寫入的編碼。默認(rèn)0
EasyExcel用法指南
簡(jiǎn)單的讀取excel文件
public void read() {
    String fileName = "demo.xlsx";
    // 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheet 文件流會(huì)自動(dòng)關(guān)閉
    // 參數(shù)一:讀取的excel文件路徑
    // 參數(shù)二:讀取sheet的一行,將參數(shù)封裝在DemoData實(shí)體類中
    // 參數(shù)三:讀取每一行的時(shí)候會(huì)執(zhí)行DemoDataListener監(jiān)聽(tīng)器
    EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
}
簡(jiǎn)單的寫入excel文件
@Test
public void simpleWrite() {
    String fileName = "demo.xlsx";
    // 這里 需要指定寫用哪個(gè)class去讀,然后寫到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉
    // 如果這里想使用03 則 傳入excelType參數(shù)即可
    // 參數(shù)一:寫入excel文件路徑
    // 參數(shù)二:寫入的數(shù)據(jù)類型是DemoData
    // data()方法是寫入的數(shù)據(jù),結(jié)果是List<DemoData>集合
    EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
}
Web上傳與下載
/**
	excel文件的下載
*/
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
    response.setContentType("application/vnd.ms-excel");
    response.setCharacterEncoding("utf-8");
    response.setHeader("Content-disposition", "attachment;filename=demo.xlsx");
    EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
}

/**
	excel文件的上傳
*/
@PostMapping("upload")
@ResponseBody
public String upload(MultipartFile file) throws IOException {
    EasyExcel.read(file.getInputStream(), DemoData.class, new DemoDataListener()).sheet().doRead();
    return "success";
}
詳解讀取Excel
對(duì)象模型
// 如果沒(méi)有特殊說(shuō)明,下面的案例將默認(rèn)使用這個(gè)實(shí)體類
public class DemoData {
    /**
     * 強(qiáng)制讀取第三個(gè) 這里不建議 index 和 name 同時(shí)用,要么一個(gè)對(duì)象只用index,要么一個(gè)對(duì)象只用name去匹配
     */
    @ExcelProperty(index = 2)
	//我想接收百分比的數(shù)字
	@NumberFormat("#.##%")
	@ExcelProperty(value="浮點(diǎn)數(shù)標(biāo)題", converter = CustomStringConverter.class)
    private Double doubleData;
    /**
     * 用名字去匹配,這里需要注意,如果名字重復(fù),會(huì)導(dǎo)致只有一個(gè)字段讀取到數(shù)據(jù)
     */
	@ExcelProperty(value="字符串標(biāo)題", converter = CustomStringConverter.class)
	// converter屬性定義自己的字符串轉(zhuǎn)換器
    private String string;
	
	@DateTimeFormat("yyyy年MM月dd日 HH時(shí)mm分ss秒")
    @ExcelProperty("日期標(biāo)題")
	//這里用string 去接日期才能格式化
    private Date date;
}
監(jiān)聽(tīng)器
// 如果沒(méi)有特殊說(shuō)明,下面的案例將默認(rèn)使用這個(gè)監(jiān)聽(tīng)器
public class DemoDataListener extends AnalysisEventListener<DemoData> {

    List<DemoData> list = new ArrayList<DemoData>();
    /**
     * 如果使用了spring,請(qǐng)使用這個(gè)構(gòu)造方法。每次創(chuàng)建Listener的時(shí)候需要把spring管理的類傳進(jìn)來(lái)
     */
    public DemoDataListener() {}
    /**
     * 這個(gè)每一條數(shù)據(jù)解析都會(huì)來(lái)調(diào)用
     *
     * @param data
     * @param context
     */
    @Override
    public void invoke(DemoData data, AnalysisContext context) {
        System.out.println("解析到一條數(shù)據(jù):{}", JSON.toJSONString(data));
        list.add(data);
    }

    /**
     * 所有數(shù)據(jù)解析完成了 都會(huì)來(lái)調(diào)用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        System.out.println(JSON.toJSONString(list));
    }
}
代碼
@Test
public void simpleRead() {
    // 寫法1:
    String fileName = "demo.xlsx";
    // 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheet 文件流會(huì)自動(dòng)關(guān)閉
    EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
    // 寫法2:
    fileName = "demo.xlsx";
    ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build();
    ReadSheet readSheet = EasyExcel.readSheet(0).build();
    excelReader.read(readSheet);
    // 這里千萬(wàn)別忘記關(guān)閉,讀的時(shí)候會(huì)創(chuàng)建臨時(shí)文件,到時(shí)磁盤會(huì)崩的
    excelReader.finish();
}
讀取多個(gè)sheet
@Test
public void repeatedRead() {
    String fileName = "demo.xlsx";
    // 讀取全部sheet
    // 這里需要注意 DemoDataListener的doAfterAllAnalysed 會(huì)在每個(gè)sheet讀取完畢后調(diào)用一次。然后所有sheet都會(huì)往同一個(gè)DemoDataListener里面寫
    EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).doReadAll();
    // 讀取部分sheet
    fileName = "demo.xlsx";
    ExcelReader excelReader = EasyExcel.read(fileName).build();
    // 這里為了簡(jiǎn)單 所以注冊(cè)了 同樣的head 和Listener 自己使用功能必須不同的Listener
    // readSheet參數(shù)設(shè)置讀取sheet的序號(hào)
    ReadSheet readSheet1 =
        EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
    ReadSheet readSheet2 =
        EasyExcel.readSheet(1).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
    // 這里注意 一定要把sheet1 sheet2 一起傳進(jìn)去,不然有個(gè)問(wèn)題就是03版的excel 會(huì)讀取多次,浪費(fèi)性能
    excelReader.read(readSheet1, readSheet2);
    // 這里千萬(wàn)別忘記關(guān)閉,讀的時(shí)候會(huì)創(chuàng)建臨時(shí)文件,到時(shí)磁盤會(huì)崩的
    excelReader.finish();
}
自定義格式轉(zhuǎn)換
public class CustomStringStringConverter implements Converter<String> {
    
	@Override
    public Class supportJavaTypeKey() {
        return String.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 這里讀的時(shí)候會(huì)調(diào)用
     *
     * @param cellData
     *            NotNull
     * @param contentProperty
     *            Nullable
     * @param globalConfiguration
     *            NotNull
     * @return
     */
    @Override
    public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
        GlobalConfiguration globalConfiguration) {
        return "自定義:" + cellData.getStringValue();
    }

    /**
     * 這里是寫的時(shí)候會(huì)調(diào)用 不用管
     *
     * @param value
     *            NotNull
     * @param contentProperty
     *            Nullable
     * @param globalConfiguration
     *            NotNull
     * @return
     */
    @Override
    public CellData convertToExcelData(String value, ExcelContentProperty contentProperty,
        GlobalConfiguration globalConfiguration) {
        return new CellData(value);
    }
}
多行頭
@Test
public void complexHeaderRead() {
    String fileName = "demo.xlsx";
    // 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheet 
    EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet()
        // 這里可以設(shè)置1,因?yàn)轭^就是一行。如果多行頭,可以設(shè)置其他值。不傳入默認(rèn)1行
        .headRowNumber(1).doRead();
}
讀取表頭數(shù)據(jù)

覆蓋監(jiān)聽(tīng)器invokeHeadMap方法

/**
 * 這里會(huì)一行行的返回頭
 * 監(jiān)聽(tīng)器只需要重寫這個(gè)方法就可以讀取到頭信息
 * @param headMap
 * @param context
 */
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
    LOGGER.info("解析到一條頭數(shù)據(jù):{}", JSON.toJSONString(headMap));
}

異常處理

覆蓋監(jiān)聽(tīng)器onException方法

/**
* 監(jiān)聽(tīng)器實(shí)現(xiàn)這個(gè)方法就可以在讀取數(shù)據(jù)的時(shí)候獲取到異常信息
*/
@Override
public void onException(Exception exception, AnalysisContext context) {
    LOGGER.error("解析失敗,但是繼續(xù)解析下一行:{}", exception.getMessage());
    // 如果是某一個(gè)單元格的轉(zhuǎn)換異常 能獲取到具體行號(hào)
    // 如果要獲取頭的信息 配合invokeHeadMap使用
    if (exception instanceof ExcelDataConvertException) {
        ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
        LOGGER.error("第{}行,第{}列解析異常", excelDataConvertException.getRowIndex(),
            excelDataConvertException.getColumnIndex());
    }
}
導(dǎo)出指定的列
@Test
public void excludeOrIncludeWrite() {
	
    String fileName = "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";
    // 忽略 date 不導(dǎo)出
    Set<String> excludeColumnFiledNames = new HashSet<String>();
    excludeColumnFiledNames.add("date");
    // 這里 需要指定寫用哪個(gè)class去寫,然后寫到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉
    EasyExcel.write(fileName, DemoData.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("忽略date")
        .doWrite(data());
    fileName = "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";
    // 根據(jù)用戶傳入字段 假設(shè)我們只要導(dǎo)出 date
    Set<String> includeColumnFiledNames = new HashSet<String>();
    includeColumnFiledNames.add("date");
    // 這里 需要指定寫用哪個(gè)class去寫,然后寫到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉
    EasyExcel.write(fileName, DemoData.class).includeColumnFiledNames(includeColumnFiledNames).sheet("導(dǎo)出date")
        .doWrite(data());
}
調(diào)整指定列順序
public class IndexData {
    /**
    * 導(dǎo)出的excel第二列和第四列將空置
    */
    @ExcelProperty(value = "字符串標(biāo)題", index = 0)
    private String string;
    @ExcelProperty(value = "日期標(biāo)題", index = 2)
    private Date date;
    @ExcelProperty(value = "浮點(diǎn)數(shù)標(biāo)題", index = 4)
    private Double doubleData;
}

復(fù)雜頭寫入
public class ComplexHeadData {
    /**
    * 主標(biāo)題 將整合為一個(gè)單元格效果如下:
    * —————————————————————————
    * |          主標(biāo)題        |
    * —————————————————————————
    * |字符串標(biāo)題|日期標(biāo)題|數(shù)字標(biāo)題|
    * —————————————————————————
    */
    @ExcelProperty({"主標(biāo)題", "字符串標(biāo)題"})
    private String string;
    @ExcelProperty({"主標(biāo)題", "日期標(biāo)題"})
    private Date date;
    @ExcelProperty({"主標(biāo)題", "數(shù)字標(biāo)題"})
    private Double doubleData;
}

前面屬于主標(biāo)題,后面屬于副標(biāo)題

圖片導(dǎo)出
@Data
@ContentRowHeight(200)
@ColumnWidth(200 / 8)
public class ImageData {
    // 圖片導(dǎo)出方式有5種
    private File file;
    private InputStream inputStream;
    /**
     * 如果string類型 必須指定轉(zhuǎn)換器,string默認(rèn)轉(zhuǎn)換成string,該轉(zhuǎn)換器是官方支持的
     */
    @ExcelProperty(converter = StringImageConverter.class)
    private String string;
    private byte[] byteArray;
    /**
     * 根據(jù)url導(dǎo)出 版本2.1.1才支持該種模式
     */
    private URL url;
}

 @Test
public void imageWrite() throws Exception {
    String fileName = "imageWrite" + System.currentTimeMillis() + ".xlsx";
    // 如果使用流 記得關(guān)閉
    InputStream inputStream = null;
    try {
        List<ImageData> list = new ArrayList<ImageData>();
        ImageData imageData = new ImageData();
        list.add(imageData);
        String imagePath = "converter" + File.separator + "img.jpg";
        // 放入五種類型的圖片 根據(jù)實(shí)際使用只要選一種即可
        imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath)));
        imageData.setFile(new File(imagePath));
        imageData.setString(imagePath);
        inputStream = FileUtils.openInputStream(new File(imagePath));
        imageData.setInputStream(inputStream);
        imageData.setUrl(new URL(
            "https://raw.githubusercontent.com/alibaba/easyexcel/master/src/test/resources/converter/img.jpg"));
        EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list);
    } finally {
        if (inputStream != null) {
            inputStream.close();
        }
    }
}

列寬、行高
@Data
@ContentRowHeight(10)
@HeadRowHeight(20)
@ColumnWidth(25)
public class WidthAndHeightData {
    @ExcelProperty("字符串標(biāo)題")
    private String string;
    @ExcelProperty("日期標(biāo)題")
    private Date date;
    /**
     * 寬度為50,覆蓋上面的寬度25
     */
    @ColumnWidth(50)
    @ExcelProperty("數(shù)字標(biāo)題")
    private Double doubleData;
}
  • @HeadRowHeight(value = 35) // 表頭行高
  • @ContentRowHeight(value = 25) // 內(nèi)容行高
  • @ColumnWidth(value = 50) // 列寬

此外還有,自適應(yīng)寬度,但是這個(gè)不是特別精確

@Test
void contextLoads() {
    EasyExcel.write("自適應(yīng).xlsx", Student.class)
        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
        .sheet()
        .doWrite(getData());
}
動(dòng)態(tài)表頭
@Test
public void dynamicHeadWrite() {
    String fileName = "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx";
    EasyExcel.write(fileName)
        // 這里放入動(dòng)態(tài)頭
        .head(head()).sheet("模板")
        // 當(dāng)然這里數(shù)據(jù)也可以用 List<List<String>> 去傳入
        .doWrite(data());
}
// 動(dòng)態(tài)表頭的數(shù)據(jù)格式List<List<String>>
private List<List<String>> head() {
    List<List<String>> list = new ArrayList<List<String>>();
    List<String> head0 = new ArrayList<String>();
    head0.add("字符串" + System.currentTimeMillis());
    List<String> head1 = new ArrayList<String>();
    head1.add("數(shù)字" + System.currentTimeMillis());
    List<String> head2 = new ArrayList<String>();
    head2.add("日期" + System.currentTimeMillis());
    list.add(head0);
    list.add(head1);
    list.add(head2);
    return list;
}
合并單元格
 @Test
 public void mergeWrite() {
     String fileName = "mergeWrite" + System.currentTimeMillis() + ".xlsx";
     LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0);
     EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("合并單元格")
         .doWrite(data());
 }
  • 每隔2行會(huì)合并 把eachColumn 設(shè)置成 3 也就是我們數(shù)據(jù)的長(zhǎng)度,所以就第一列會(huì)合并。當(dāng)然其他合并策略也可以自己寫

  • 這里 需要指定寫用哪個(gè)class去寫,然后寫到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉

web數(shù)據(jù)寫出
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
    response.setContentType("application/vnd.ms-excel");
    response.setCharacterEncoding("utf-8");
    // 這里URLEncoder.encode可以防止中文亂碼 當(dāng)然和easyexcel沒(méi)有關(guān)系
    String fileName = URLEncoder.encode("數(shù)據(jù)寫出", "UTF-8");
    response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
    EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
}
模板格式導(dǎo)出

如果需要橫向填充只需要模板設(shè)置好就可以。

簡(jiǎn)單的Excel模板

【Alibaba工具型技術(shù)系列】「EasyExcel技術(shù)專題」實(shí)戰(zhàn)技術(shù)針對(duì)于項(xiàng)目中常用的Excel操作指南,深入淺出Java原理及實(shí)戰(zhàn),實(shí)戰(zhàn)指南之分布式/微服務(wù),底層服務(wù)/編程功底系列,excel,java,alibaba

public class FillData {
    private String name;
    private double number;
    // getting setting
}
實(shí)現(xiàn)模板填充
@Test
public void simpleFill() {
    String templateFileName = "simple.xlsx";

    // 方案1 根據(jù)對(duì)象填充
    String fileName = System.currentTimeMillis() + ".xlsx";
    // 這里 會(huì)填充到第一個(gè)sheet, 然后文件流會(huì)自動(dòng)關(guān)閉
    FillData fillData = new FillData();
    fillData.setName("知春秋");
    fillData.setNumber(25);
    EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(fillData);

    // 方案2 根據(jù)Map填充
    fileName = System.currentTimeMillis() + ".xlsx";
    // 這里 會(huì)填充到第一個(gè)sheet, 然后文件流會(huì)自動(dòng)關(guān)閉
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("name", "知春秋");
    map.put("number", 25);
    EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(map);
}
  • 模板注意 用{} 來(lái)表示你要用的變量 如果本來(lái)就有"{“,”}" 特殊字符 用"{“,”}"代替
復(fù)雜的填充

使用List集合的方法批量寫入數(shù)據(jù),點(diǎn)表示該參數(shù)是集合

@Test
public void complexFill() {
    String templateFileName = "complex.xlsx";
    String fileName = System.currentTimeMillis() + ".xlsx";
    ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build();
    WriteSheet writeSheet = EasyExcel.writerSheet().build();
    // 如果數(shù)據(jù)量大 list不是最后一行 參照下一個(gè)
    FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
    excelWriter.fill(data(), fillConfig, writeSheet);
    excelWriter.fill(data(), fillConfig, writeSheet);
    // 其他參數(shù)可以使用Map封裝
    Map<String, Object> map = new HashMap<String, Object>();
    excelWriter.fill(map, writeSheet);
    excelWriter.finish();
}
  • 模板注意 用{} 來(lái)表示你要用的變量 如果本來(lái)就有"{“,”}" 特殊字符 用"{“,”}"代替

  • // {} 代表普通變量 {.} 代表是list的變量
    
  • // 這里注意 入?yún)⒂昧薴orceNewRow 代表在寫入list的時(shí)候不管list下面有沒(méi)有空行 都會(huì)創(chuàng)建一行,然后下面的數(shù)據(jù)往后移動(dòng)。默認(rèn) 是false,會(huì)直接使用下一行,如果沒(méi)有則創(chuàng)建。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-804195.html

  • // forceNewRow 如果設(shè)置了true,有個(gè)缺點(diǎn) 就是他會(huì)把所有的數(shù)據(jù)都放到內(nèi)存了,所以慎用
    
  • // 簡(jiǎn)單的說(shuō) 如果你的模板有l(wèi)ist,且list不是最后一行,下面還有數(shù)據(jù)需要填充 就必須設(shè)置 forceNewRow=true 但是這個(gè)就會(huì)把所有數(shù)據(jù)放到內(nèi)存 會(huì)很耗內(nèi)存
    

總結(jié)一個(gè)工具類


public class ExcelUtil {
    /**
     * 寫出一個(gè) excel 文件到本地
     * <br />
     * 將類型所有加了 @ExcelProperty 注解的屬性全部寫出
     *
     * @param fileName  文件名 不要后綴
     * @param sheetName sheet名
     * @param data      寫出的數(shù)據(jù)
     * @param clazz     要寫出數(shù)據(jù)類的Class類型對(duì)象
     * @param <T>       寫出的數(shù)據(jù)類型
     */
    public static <T> void writeExcel(String fileName, String sheetName, List<T> data, Class<T> clazz) {
        writeExcel(null, fileName, sheetName, data, clazz);
    }


    /**
     * 按照指定的屬性名進(jìn)行寫出 一個(gè) excel
     *
     * @param attrName  指定的屬性名 必須與數(shù)據(jù)類型的屬性名一致
     * @param fileName  文件名 不要后綴
     * @param sheetName sheet名
     * @param data      要寫出的數(shù)據(jù)
     * @param clazz     要寫出數(shù)據(jù)類的Class類型對(duì)象
     * @param <T>       要寫出的數(shù)據(jù)類型
     */
    public static <T> void writeExcel(Set<String> attrName, String fileName, String sheetName, List<T> data, Class<T> clazz) {
        fileName = StringUtils.isBlank(fileName) ? "學(xué)生管理系統(tǒng)" : fileName;
        sheetName = StringUtils.isBlank(sheetName) ? "sheet0" : sheetName;

        try(FileOutputStream fos = new FileOutputStream(fileName)) {
            write(fos,attrName,sheetName,data,clazz);
        } catch (Exception exception) {
            exception.printStackTrace();
         
        }


    }

    /**
     * 讀取 指定格式的 excel文檔
     *
     * @param fileName 文件名
     * @param clazz    數(shù)據(jù)類型的class對(duì)象
     * @param <T>      數(shù)據(jù)類型
     * @return
     */
    public static <T> List<T> readExcel(String fileName, Class<T> clazz) {
        
        return readExcel(fileName, clazz, null);
    }

    /**
     * 取 指定格式的 excel文檔
     * 注意一旦傳入自定義監(jiān)聽(tīng)器,則返回的list為空,數(shù)據(jù)需要在自定義監(jiān)聽(tīng)器里面獲取
     *
     * @param fileName     文件名
     * @param clazz        數(shù)據(jù)類型的class對(duì)象
     * @param readListener 自定義監(jiān)聽(tīng)器
     * @param <T>          數(shù)據(jù)類型
     * @return
     */
    public static <T> List<T> readExcel(String fileName, Class<T> clazz, ReadListener<T> readListener) {
  

        try(FileInputStream fis = new FileInputStream(fileName)) {
            return read(fis,clazz,readListener);
        } catch (Exception exception) {
            exception.printStackTrace();
        
        }
    }


    /**
     * 導(dǎo)出  一個(gè) excel
     *         導(dǎo)出excel所有數(shù)據(jù)
     * @param response
     * @param fileName  件名 最好為英文,不要后綴名
     * @param sheetName sheet名
     * @param data      要寫出的數(shù)據(jù)
     * @param clazz     要寫出數(shù)據(jù)類的Class類型對(duì)象
     * @param <T>       要寫出的數(shù)據(jù)類型
     */
    public static <T> void export(HttpServletResponse response, String fileName, String sheetName, List<T> data, Class<T> clazz) {
        export(response, null, fileName, sheetName, data, clazz);
    }

    /**
     * 按照指定的屬性名進(jìn)行寫出 一個(gè) excel
     *
     * @param response
     * @param attrName  指定的屬性名 必須與數(shù)據(jù)類型的屬性名一致
     * @param fileName  文件名 最好為英文,不要后綴名
     * @param sheetName sheet名
     * @param data      要寫出的數(shù)據(jù)
     * @param clazz     要寫出數(shù)據(jù)類的Class類型對(duì)象
     * @param <T>       要寫出的數(shù)據(jù)類型
     */
    public static <T> void export(HttpServletResponse response, Set<String> attrName, String fileName, String sheetName, List<T> data, Class<T> clazz) {
      
        fileName = StringUtils.isBlank(fileName) ? "student-system-manager" : fileName;
        sheetName = StringUtils.isBlank(sheetName) ? "sheet0" : sheetName;

        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        response.addHeader("Content-disposition", "attachment;filename=" + fileName + ExcelTypeEnum.XLSX.getValue());

        try(OutputStream os = response.getOutputStream()) {
            write(os,attrName,sheetName,data,clazz);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 接收一個(gè)excel文件,并且進(jìn)行解析
     *  注意一旦傳入自定義監(jiān)聽(tīng)器,則返回的list為空,數(shù)據(jù)需要在自定義監(jiān)聽(tīng)器里面獲取
     * @param multipartFile excel文件
     * @param clazz 數(shù)據(jù)類型的class對(duì)象
     * @param readListener 監(jiān)聽(tīng)器
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(MultipartFile multipartFile,Class<T> clazz,ReadListener<T> readListener) {
  
  
        try(InputStream inputStream = multipartFile.getInputStream()) {
            return read(inputStream,clazz,readListener);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    private static <T> void write(OutputStream os, Set<String> attrName, String sheetName, List<T> data, Class<T> clazz) {
        ExcelWriterBuilder write = EasyExcel.write(os, clazz);
        // 如果沒(méi)有指定要寫出那些屬性數(shù)據(jù),則寫出全部
        if (!CollectionUtils.isEmpty(attrName)) {
            write.includeColumnFiledNames(attrName);
        }
        write.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet(sheetName).doWrite(data);
    }


    private static <T> List<T> read(InputStream in,Class<T> clazz, ReadListener<T> readListener) {
        List<T> list = new ArrayList<>();

        Optional<ReadListener> optional = Optional.ofNullable(readListener);

        EasyExcel.read(in, clazz, optional.orElse(new AnalysisEventListener<T>() {

            @Override
            public void invoke(T data, AnalysisContext context) {
                list.add(data);
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                  System.out.println("解析完成")}
        })).sheet().doRead();

        return list;
    }
}

參考資料

  • https://github.com/alibaba/easyexcel/blob/master/docs/API.md 官方api
  • https://github.com/alibaba/easyexcel easyexcel github 地址
  • https://blog.csdn.net/sinat_32366329/article/details/103109058 easyexcel總結(jié)
  • https://alibaba-easyexcel.github.io/index.html 官方示例

到了這里,關(guān)于【Alibaba工具型技術(shù)系列】「EasyExcel技術(shù)專題」實(shí)戰(zhàn)技術(shù)針對(duì)于項(xiàng)目中常用的Excel操作指南的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包