SpringBoot は EasyExcel を統合して、複雑な Excel テーブルのインポートおよびエクスポート機能を実装します

バックエンド管理システムの開発では、現在のテーブル データをエクスポートする機能がよくありますが、一部のフロントエンド テーブル コンポーネントではこれを直接実行できますが、柔軟性が十分ではありません。フロントエンドで取得したデータは常に処理されるため、元のデータを取得したい場合はバックエンドで処理する必要があります。また、Excelのインポートも多く、データ処理も面倒ですが、Apache POIなどの一般的なツールキットを利用することで簡略化できますが、作成するクラスが多すぎるなどの欠点もあります。 。

では、Apache POI パッケージを使用する以外に、他のオプションはあるのでしょうか? もちろんです! ここでは、非常にシンプルで使いやすいオープンソース コンポーネントをお勧めします。Alibaba EasyExcel

まず、公式ウェブサイトのアドレスを公開し、スター登録を歓迎します (現在 24,000 人):https://alibaba-easyexcel.github.io/docs/current/

EasyExcel は、Java に基づいて Excel を読み書きするためのシンプルでメモリを節約するオープン ソース プロジェクトです。メモリを可能な限り節約しながら、100M Excel の読み書きをサポートします。

64M メモリは 75M (46W 行と 25 列) Excel (バージョン 3.0.2+) を 20 秒で読み取ります

Alibaba EasyExcel のコア クラスはEasyExcelクラスです。

  
     * 最简单的读
     * <p>1. 创建excel对应的实体对象 参照{@link DemoData}
     * <p>2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
     * <p>3. 直接读即可
     */
    @Test
    public void simpleRead() {
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        
        EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
    }

     * 最简单的写
     * <p>1. 创建excel对应的实体对象 参照{@link com.alibaba.easyexcel.test.demo.write.DemoData}
     * <p>2. 直接写即可
     */
    @Test
    public void simpleWrite() {
        String fileName = TestFileUtil.getPath() + "write" + System.currentTimeMillis() + ".xlsx";
        
        
        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
    }

1. プロジェクトの基本情報

(1) プロジェクトの構成

(2)pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath/> 
    </parent>
    <groupId>com.example</groupId>
    <artifactId>SpringBoot-easyexcel</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringBoot-easyexcel</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>

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

        
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.1.1</version>
        </dependency>

        
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>

        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>


2. ファイルのエクスポート

まずは効果を見せてみましょう。

(1) 単一シートとヘッダー結合

(2) 複数シートをエクスポートする

以下はエクスポート関連のクラスコードです。

エクスポートコントローラー.java

package com.example.springbooteasyexcel.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.example.springbooteasyexcel.data.Mock;
import com.example.springbooteasyexcel.sheet.CitySheet;
import com.example.springbooteasyexcel.sheet.CompanySheet;
import com.example.springbooteasyexcel.sheet.UserSheet;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;

@RestController
@RequestMapping("/export")
public class ExportController {

    
     * @param response
     * @url <a>http://localhost:8080/export/test1</a>
     * 在Excel中写入单个sheet
     */
    @RequestMapping("/test1")
    public void test1(HttpServletResponse response) {
        
        try {
            
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            
            response.setCharacterEncoding("utf-8");
            
            String fileName = URLEncoder.encode("用户信息表", "UTF-8").replaceAll("\\+", "%20");
            
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            
            EasyExcel.write(response.getOutputStream(), UserSheet.class).inMemory(true).sheet("用户信息表").doWrite(Mock.userList());
        } catch (IOException e) {
            throw new RuntimeException("数据或文件损坏,无法下载");
        }
    }

    
     * 在Excel中写入多个sheet
     *
     * @url <a>http://localhost:8080/export/test2</a>
     */
    @RequestMapping("/test2")
    public void test2(HttpServletResponse response) throws Exception {
        
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        
        response.setCharacterEncoding("utf-8");
        
        String fileName = URLEncoder.encode("信息表", "UTF-8").replaceAll("\\+", "%20");
        
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        
        try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).inMemory(true).build()) {
            
            WriteSheet userInfoSheet = EasyExcel.writerSheet(0, "用户信息表").head(UserSheet.class).build();
            excelWriter.write(Mock.userList(), userInfoSheet);
            
            WriteSheet cityInfoSheet = EasyExcel.writerSheet(1, "城市信息表").head(CitySheet.class).build();
            excelWriter.write(Mock.cityList(), cityInfoSheet);
            
            WriteSheet companyInfoSheet = EasyExcel.writerSheet(2, "公司信息表").head(CompanySheet.class).build();
            excelWriter.write(Mock.companyList(), companyInfoSheet);
        }
    }
}

モック.java

以下のデータはインターネットから取得したものです。侵害がある場合は、削除するようご連絡ください。

package com.example.springbooteasyexcel.data;


import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.data.RichTextStringData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.example.springbooteasyexcel.sheet.CitySheet;
import com.example.springbooteasyexcel.sheet.CompanySheet;
import com.example.springbooteasyexcel.sheet.UserSheet;
import org.apache.poi.ss.usermodel.IndexedColors;

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

public class Mock {

    public static List<UserSheet> userList() {
        List<UserSheet> list = new ArrayList<>(10);
        list.add(UserSheet.builder().userId(001L).userName("张三").userPhone("11112223123").userEmail("[email protected]").userAddress("北京朝阳区").gender(buildCellData("男")).registerTime(Calendar.getInstance().getTime()).build());
        list.add(UserSheet.builder().userId(002L).userName("李四").userPhone("11112223123").userEmail("[email protected]").userAddress("南京玄武门").gender(buildCellData("女")).registerTime(Calendar.getInstance().getTime()).build());
        list.add(UserSheet.builder().userId(003L).userName("王五").userPhone("11112223123").userEmail("[email protected]").userAddress("杭州未来科技城").gender(buildCellData("男")).registerTime(Calendar.getInstance().getTime()).build());
        list.add(UserSheet.builder().userId(004L).userName("赵六").userPhone("11112223123").userEmail("[email protected]").userAddress("上海徐家汇").gender(buildCellData("女")).registerTime(Calendar.getInstance().getTime()).build());
        return list;
    }

    private static WriteCellData<String> buildCellData(String gender) {
        
        WriteCellData<String> cellData = new WriteCellData<>();
        
        cellData.setType(CellDataTypeEnum.RICH_TEXT_STRING);
        
        RichTextStringData richTextStringData = new RichTextStringData();
        cellData.setRichTextStringDataValue(richTextStringData);
        richTextStringData.setTextString(gender);
        WriteFont writeFont = new WriteFont();
        if ("男".equalsIgnoreCase(gender)) {
         
            writeFont.setColor(IndexedColors.RED.getIndex());
        } else if ("女".equalsIgnoreCase(gender)) {
         
            writeFont.setColor(IndexedColors.GREEN.getIndex());
        }
        
        richTextStringData.applyFont(writeFont);
        return cellData;
    }

    public static List<CitySheet> cityList() {
        List<CitySheet> list = new ArrayList<>(10);
        list.add(CitySheet.builder().cityName("杭州市").cityDesc("杭州市一般指杭州。 杭州,简称“杭”,古称临安、钱塘,浙江省辖地级市、省会、副省级市、特大城市、国务院批复确定的浙江省经济、文化、科教中心,长江三角洲中心城市之一,环杭州湾大湾区核心城市、G60科创走廊中心城市。").build());
        list.add(CitySheet.builder().cityName("合肥市").cityDesc("合肥市一般指合肥。 合肥,简称“庐”或“合”,古称庐州、庐阳、合淝,安徽省辖地级市、省会,是合肥都市圈中心城市,国务院批复确定的中国长三角城市群副中心城市,全国四大科教基地、现代制造业基地和综合交通枢纽。").build());
        list.add(CitySheet.builder().cityName("武汉市").cityDesc("武汉市一般指武汉。 武汉,简称“汉”,别称江城,是湖北省省会,中部六省唯一的副省级市,超大城市,中国中部地区的中心城市,全国重要的工业基地、科教基地和综合交通枢纽,联勤保障部队机关驻地。").build());
        list.add(CitySheet.builder().cityName("深圳市").cityDesc("深圳市一般指深圳。 深圳,简称“深”,别称鹏城,广东省辖地级市,是广东省副省级市,国家计划单列市,超大城市,国务院批复确定的中国经济特区、全国性经济中心城市、国际化城市、科技创新中心、区域金融中心、商贸物流中心。").build());
        return list;
    }

    public static List<CompanySheet> companyList() {
        List<CompanySheet> list = new ArrayList<>(10);
        list.add(CompanySheet.builder().companyName("阿里巴巴").companyBoss("马云").companyBase("杭州市").companyDesc("阿里巴巴集团经营多项业务,另外也从关联公司的业务和服务中取得经营商业生态系统上的支援。业务和关联公司的业务包括:淘宝网、天猫、聚划算、全球速卖通、阿里巴巴国际交易市场、1688、阿里妈妈、阿里云、蚂蚁集团 [408]  、菜鸟网络等。").build());
        list.add(CompanySheet.builder().companyName("字节跳动").companyBoss("张一鸣").companyBase("北京市").companyDesc("字节跳动的全球化布局始于2015年 [3]  ,“技术出海”是字节跳动全球化发展的核心战略 [4]  ,其旗下产品有今日头条、西瓜视频、抖音、头条百科、皮皮虾、懂车帝、悟空问答等。").build());
        list.add(CompanySheet.builder().companyName("腾讯").companyBoss("马化腾").companyBase("深圳市").companyDesc("社交和通信服务QQ及微信/WeChat、社交网络平台QQ空间、腾讯游戏旗下QQ游戏平台、门户网站腾讯网、腾讯新闻客户端和网络视频服务腾讯视频等。").build());
        list.add(CompanySheet.builder().companyName("百度").companyBoss("李彦宏").companyBase("北京市").companyDesc("百度(Baidu)是拥有强大互联网基础的领先AI公司。百度愿景是:成为最懂用户,并能帮助人们成长的全球顶级高科技公司。").build());
        return list;
    }
}


シティシート.java

package com.example.springbooteasyexcel.sheet;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class CitySheet {

    @ExcelProperty(value = "城市名称", index = 0)
    @ColumnWidth(10)
    private String cityName;

    @ExcelProperty(value = "城市介绍", index = 1)
    @ColumnWidth(60)
    private String cityDesc;

}


CompanySheet.java

package com.example.springbooteasyexcel.sheet;


import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class CompanySheet {

    @ExcelProperty(value = "公司名称", index = 0)
    @ColumnWidth(10)
    private String companyName;

    @ExcelProperty(value = "公司创始人", index = 1)
    @ColumnWidth(10)
    private String companyBoss;

    @ExcelProperty(value = "公司总基地", index = 2)
    @ColumnWidth(10)
    private String companyBase;

    @ExcelProperty(value = "公司简介", index = 3)
    @ColumnWidth(50)
    private String companyDesc;
}


ユーザーシート.java

package com.example.springbooteasyexcel.sheet;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.metadata.data.WriteCellData;
import lombok.Builder;
import lombok.Data;

import java.util.Date;

@Data
@Builder
public class UserSheet {

    @ExcelProperty(value = "用户ID", index = 0)
    @ColumnWidth(10)
    private Long userId;

    @ExcelProperty(value = "用户名称", index = 1)
    @ColumnWidth(10)
    private String userName;

    @ExcelProperty(value = {"基本信息", "手机号码"}, index = 2)
    @ColumnWidth(20)
    private String userPhone;

    @ExcelProperty(value = {"基本信息", "电子邮箱"}, index = 3)
    @ColumnWidth(20)
    private String userEmail;

    @ExcelProperty(value = {"基本信息", "地址"}, index = 4)
    @ColumnWidth(20)
    private String userAddress;

    @ExcelProperty(value = "注册时间", index = 5)
    @ColumnWidth(20)
    private Date registerTime;

    @ExcelProperty(value = "性别,男:红色/女:绿色")
    @ColumnWidth(30)
    private WriteCellData<String> gender;

    
     * 忽略这个字段
     */
    @ExcelIgnore
    private Integer age;
}


SpringBootEasyexcelApplication.java

package com.example.springbooteasyexcel;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootEasyexcelApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootEasyexcelApplication.class, args);
    }

}


3. ファイルのインポート

Excel をデータベースにインポートします。EasyExcel を使用してインポートする方法をフローチャートを使用して示します。

EasyExcel には AnalysisEventListener があり、リスナーをカスタマイズして AnalysisEventListener を継承することができます。その中に invoke メソッドがあり、各データはこのメソッドに入ります。ここでは検証、保存、例外スローなどのアクションを実行できます。EasyExcel はこれらのプロセスを効率化し、コードを非常に快適に記述できるようにします。もちろん、カスタムリスナーはSpringでは管理できないため、Excelを読み込むたびに新しいリスナーを作成し、Springのコンストラクタメソッドで渡すなど、注意すべき点はいくつかあります。 。

以下はインポートに関連するいくつかのクラス コードです。最も重要なのは UserExcelReadListener です。詳しく見てみましょう。

ユーザーデータ.java

package com.example.springbooteasyexcel.read;

import java.util.Date;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.metadata.data.WriteCellData;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@Builder
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class UserData {

    private Long userId;

    private String userName;

    private Integer age;

    private String userPhone;

    private String userEmail;

    private String userAddress;

    private Date registerTime;

    private String gender;

}


UserExcelReadListener.java

package com.example.springbooteasyexcel.read;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.excel.util.StringUtils;

import lombok.extern.slf4j.Slf4j;


 * 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
 */
@Slf4j
public class UserExcelReadListener extends AnalysisEventListener<UserData> {

    
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;

    
     * 创建一个Pattern对象,使用正则表达式校验手机号格式
     */
    private static final Pattern PHONE_REGEX = Pattern.compile("^1[0-9]{10}$");

    
     * 缓存的数据
     */
    private List<UserData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    
     * 错误信息列表
     */
    private final List<String> errorMsgList = new ArrayList<>(BATCH_COUNT);

    @Override
    public void invoke(UserData userData, AnalysisContext analysisContext) {
        log.info("解析到一条数据:{}", userData);
        int rowIndex = analysisContext.readRowHolder().getRowIndex();
        String name = userData.getUserName();
        String phone = userData.getUserPhone();
        String gender = userData.getGender();
        String email = userData.getUserEmail();
        Integer age = userData.getAge();
        String address = userData.getUserAddress();
        
        if (nameValid(rowIndex, name) && phoneValid(rowIndex, phone) && genderValid(rowIndex, gender) &&
            emailValid(rowIndex, email) && ageValid(rowIndex, age) && addressValid(rowIndex, address)) {
            cachedDataList.add(userData);
        }
        
        if (cachedDataList.size() >= BATCH_COUNT) {
            
            
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        log.info("所有数据解析完成!全部校验通过的数据有{}条", cachedDataList.size());
        
        

    }

    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        if (exception instanceof RuntimeException) {
            throw exception;
        }
        int index = context.readRowHolder().getRowIndex() + 1;
        errorMsgList.add("第" + index + "行解析错误");
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        int totalRows = context.readSheetHolder().getApproximateTotalRowNumber() - 1;
        int maxNum = 2000;
        if (totalRows > maxNum) {
            errorMsgList.add("数据量过大,单次最多上传2000条");
            throw new RuntimeException("数据量过大,单次最多上传2000条");
        }
    }

    public List<String> getErrorMsgList() {
        return errorMsgList;
    }

    
     * 名称的校验
     *
     * @param rowIndex 行数
     * @param name     名称
     */
    private Boolean nameValid(Integer rowIndex, String name) {
        if (StringUtils.isBlank(name)) {
            errorMsgList.add("第" + rowIndex + "行,'姓名'不能为空");
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    private Boolean phoneValid(int rowIndex, String phone) {
        if (StringUtils.isBlank(phone)) {
            errorMsgList.add("第" + rowIndex + "行,'手机号'不能为空");
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    
     * 性别的校验
     *
     * @param rowIndex 行数
     * @param gender   性别
     */
    private Boolean genderValid(int rowIndex, String gender) {
        if (StringUtils.isBlank(gender)) {
            errorMsgList.add("第" + rowIndex + "行,'性别'不能为空");
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    
     * 地址校验
     *
     * @param rowIndex 行数
     * @param address  地址
     */
    private Boolean addressValid(int rowIndex, String address) {
        
        if (StringUtils.isBlank(address)) {
            errorMsgList.add("第 " + rowIndex + " 行,'地址'不能为空");
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    
     * 年龄的校验
     *
     * @param rowIndex 行数
     * @param age      年龄
     */
    private Boolean ageValid(int rowIndex, Integer age) {
        
        if (Objects.isNull(age)) {
            errorMsgList.add("第 " + rowIndex + " 行'年龄'不能为空");
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    
     * 邮箱的校验
     *
     * @param rowIndex 行数
     * @param email    邮箱
     */
    private Boolean emailValid(int rowIndex, String email) {
        
        if (StringUtils.isBlank(email)) {
            errorMsgList.add("第 " + rowIndex + " 行'邮箱'不能为空");
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }
}


package com.example.springbooteasyexcel.read;

import com.alibaba.excel.EasyExcel;

public class ReadExcelTest {

    public static void main(String[] args) {
        UserExcelReadListener userExcelReadListener = new UserExcelReadListener();
        EasyExcel.read("用户信息表.xlsx", UserData.class, userExcelReadListener).sheet().doRead();
        System.out.println(userExcelReadListener.getErrorMsgList());
    }
}


の結果

1. Alibaba EasyExcel は Excel の書き込みをサポートするだけでなく、Excel の読み取りと入力もサポートします。興味がある場合は、自分で調べてください。公式 Web サイトのアドレスは上に掲載されています。ここではガイドとしてのみ機能します。

2. 一般的に使用されるアノテーションは 3 つあります: @ExcelProperty@ColumnWidth@ExcelIgnore。 (1)@ExcelPropertyテーブルのヘッダーを決定するだけでなく、行をマージします。使用方法は次のとおりです。

  @ExcelProperty(value = {"基本信息", "手机号码"}, index = 2)
    @ColumnWidth(20)
    private String userPhone;

    @ExcelProperty(value = {"基本信息", "电子邮箱"}, index = 3)
    @ColumnWidth(20)
    private String userEmail;

    @ExcelProperty(value = {"基本信息", "地址"}, index = 4)
    @ColumnWidth(20)
    private String userAddress;

効果は次のとおりです。

(2)@ColumnWidth主要是控制列宽

(3)@ExcelIgnore出力する必要のないフィールドは無視します。 3. 書き込みには 2 つの形式があります (1) ファイルへの書き込み

  
     * 最简单的写
     * <p>
     * 1. 创建excel对应的实体对象 参照{@link DemoData}
     * <p>
     * 2. 直接写即可
     */
    @Test
    public void simpleWrite() {
        

        
        
        String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
        
        
        EasyExcel.write(fileName, DemoData.class)
            .sheet("模板")
            .doWrite(() -> {
                
                return data();
            });

        
        fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
        
        
        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());

        
        fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
        
        try (ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
            excelWriter.write(data(), writeSheet);
        }
    }

(2) Web ストリームに書き込む場合、ここの ContentType と CharacterEncoding は文字化けしないようにしてください。そうしないと、文字化けしやすくなったり、ファイルが破損したりします。

 
     * 文件下载(失败了会返回一个有部分数据的Excel)
     * <p>
     * 1. 创建excel对应的实体对象 参照{@link DownloadData}
     * <p>
     * 2. 设置返回的 参数
     * <p>
     * 3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
     */
    @GetMapping("download")
    public void download(HttpServletResponse response) throws IOException {
        
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        
        String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
    }

(3) カスタムリスナーをうまく活用することでコードを最適化し、ロジックをより明確にすることができます。

おすすめ

転載: blog.csdn.net/weixin_54542328/article/details/134856298