文章目录
- 🚏 EasyExcel
- 🚀 一、初识EasyExcel
- 🚬 1、Apache POI
- 🚭 1.1 学习使用成本较高
- 🚭 1.2 POI的内存消耗较大
- 🚭 1.3 特点
 
- 🚬 2、EasyExcel
- 🚭 2.1 重写了POI对07版Excel的解析
- 🚭 2.2 特点
- 🚭 2.3 介绍
- 🚭 2.4 写注解的使用
 
 
 
- 🚄 二、快速入门
- 🚬 1、导入依赖坐标
- 🚬 2、最简单的读
- 🚭 1.1、需求、准备工作
- 🚭 1.2、编写导出数据的实体 or Map
- 🚭 1.3、 Excel的监听器
- 🚭 1.4、 读取Excel文件
 
- 🚬 3、最简单的写
- 🚭 2.1、编写导出数据的实体
- 🚭 2.3、 准备数据并写入到文件
 
- 🚬 4、文件上传和下载
- 🚭 4.1 文件上传
- 🛹 ①、实体类
- 🛹 ②、回调监听器
- 🛹 ③、文件上传实现
- 🛹 postApi测试
 
- 🚭 4.2 文件下载
- 🛹 ③、文件下载实现
 
 
- 🚬 5、自定义单元格样式
 
 
- 🚒 三、填充
- 🚬 1、填充一组数据
- 🚭 1.1 准备模板
- 🚭 1.2 封装数据
- 🚭 1.3 填充
 
- 🚬 2、填充多组数据
- 🚭 2.1 准备模板
- 🚭 2.2 封装数据
- 🚭 2.3 填充
 
- 🚬 3、组合填充
- 🚭 3.1 准备模板
- 🚭 3.2 封装数据
- 🚭 3.3 填充
 
- 🚬 4、水平填充
- 🚭 4.1 准备模板
- 🚭 4.2 封装数据
- 🚭 4.3 填充
 
- 🚬 5、 注意事项
- 🚬 6、填充综合练习
- 🚬 7、从数据库中读数据写到excel中
- 🚭 7.1 数据库依赖
- 🚭 7.2 实体类、Service、Mapper
- 🚭 7.3 Controller
 
 
 
- 🚤 四、常用API及注解
- 🚬 1、常用类
- 🚬 2、读取时的注解
- (1)、@ExcelProperty
- (2)、@ExcelIgnore
- (3)、@DateTimeFormat
- (4)、@NumberFormat
- (5)、@ExcelIgnoreUnannotated(一般不使用)
 
- 🚬 3、 读取时通用参数(工作簿、工作表中都可用)
- 🚬 4、ReadWorkbook(工作簿对象)参数
- 🚬 5、ReadSheet(工作表对象)参数
- 🚬 6、写入时的注解注解
- (1)、@ExcelProperty
- (2)、其他注解:
 
- 🚬 7、写入时通用参数
- 🚬 8、WriteWorkbook(工作簿对象)参数
- 🚬 9、WriteSheet(工作表对象)参数
 
 
😹 作者: gh-xiaohe
😻 gh-xiaohe的博客
😽 觉得博主文章写的不错的话,希望大家三连(✌关注,✌点赞,✌评论),多多支持一下!!!
🚏 EasyExcel
🚀 一、初识EasyExcel
🚬 1、Apache POI
🚭 1.1 学习使用成本较高
🚭 1.2 POI的内存消耗较大
总体上来说,简单写法重度依赖内存,复杂写法学习成本高。
🚭 1.3 特点
- 功能强大
- 代码书写冗余繁杂
- 读写大文件耗费内存较大,容易OOM 
  - OOM,全称"Out Of Memory",翻译成中文就是“内存用完了”
 
🚬 2、EasyExcel
官网:https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read
🚭 2.1 重写了POI对07版Excel的解析
-  EasyExcel重写了POI对07版Excel的解析,可以把内存消耗从100M左右降低到10M以内,并且再大的Excel不会出现内存溢出,03版仍依赖POI的SAX模式。 
-  在上层做了模型转换的封装,让使用者更加简单方便 
🚭 2.2 特点
- 在数据模型层面进行了封装,使用简单
- 重写了07版本的Excel的解析代码,降低内存消耗,能有效避免OOM
- 只能操作Excel
- 不能读取图片
🚭 2.3 介绍
-  工作簿:一个excel文件就是一个工作簿 
-  工作表:一个工作簿中可以有多个工作表(sheet) 
-  填充数据选用 类 或选用 Map 
-  多组填充 和 单组填充 一起使用的问题 : 组合填充时,因为多组填充的数据量不确定,需要在多组填充完之后另起一行 
🚭 2.4 写注解的使用
- 1、生成的excel表格列名顺序,默认是根据类中的字段的顺序一致
- 2、@ExcelProperty(value = “编号”,index = 3) 设置列名 
  - value 列名 index 在excel中的位置
- 如果不从索引0开始给,会把第一行空出来 
    - 支持多表头 @ExcelProperty(value = {“学生信息表”,“学生姓名”}) , 当所有的列头,都一致是,自动合并
 
 
- 3、@ExcelIgnore 该字段不参与读写
- 4、@ColumnWidth(30) 设置宽度
- 5、@DateTimeFormat(“yyyy-MM-dd”) 指定日期格式
- 6、@HeadRowHeight(20) 表头的行高 只能使用在类上 高度
- 7、@ContentRowHeight(20) 内容的行高 只能使用在类上
🚄 二、快速入门
🚬 1、导入依赖坐标
<!-- EasyExcel -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.1.6</version>
</dependency>
<!-- lombok 优雅编程 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
</dependency>
<!-- junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>
🚬 2、最简单的读
🚭 1.1、需求、准备工作
🚭 1.2、编写导出数据的实体 or Map
@Data
public class StudentRead {
    /**
     * 学生姓名
     */
    private String name;
    /**
     * 学生出生日期
     */
    private Date birthday;
    /**
     * 学生性别
     */
    private String gender;
    /**
     * id
     */
    private String id;
}
🚭 1.3、 Excel的监听器
/**
 *  读取文档的监听器
 */
public class StudentListenerRead extends AnalysisEventListener<StudentRead> {
    /**
    * 每读取一行数据会调用该invoke方法一次
    */
    @Override
    public void invoke(StudentRead student, AnalysisContext analysisContext) {
        System.out.println("student="+student);
    }
    /**
    * 读取完整个文档后会调用的内容
    */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    }
}
🚭 1.4、 读取Excel文件
    /**
     * 读excel文件
     */
    @Test
    public void test01() {
        // 读取文件,读取完之后会自动关闭
        /**
         * Build excel the read
         *          构建excel读取
         * @param pathName
         *          File path to read.    要读取的文件路径。
         * @param head
         *          Annotate the class for configuration information. 为类注释配置信息。
         * @param readListener
         *          Read listener.    读监听器,每读一行就会调用一次该监听器的invoke方法
         * @return Excel reader builder.    Excel阅读器生成器。
         *
         *          sheet方法参数: 工作表的顺序号(从0开始)或者工作表的名字,不传默认为0
         */
        //  获取工作簿对象
        ExcelReaderBuilder readWorkBook = EasyExcel.read("杭州黑马在线202003班学员信息表.xlsx", StudentRead.class, new StudentListenerRead());
        //  获取工作表对象
        ExcelReaderSheetBuilder sheet = readWorkBook.sheet();
        //  读取表中的内容
        sheet.doRead();
    }
🚬 3、最简单的写
🚭 2.1、编写导出数据的实体
@HeadRowHeight(20)//表头高度
@ContentRowHeight(20)//内容的行高
@Data
public class StudentWrite {
    //  和excel表中数据一一对应
    /**
     * 注意:
     *      1、生成的excel表格列名顺序,默认是根据类中的字段的顺序一致
     *      2、@ExcelProperty(value = "编号",index = 3)  设置列名
     *          value 列名  index 在excel中的位置
     *          如果不从索引0开始给,会把第一行空出来
     *              支持多表头 @ExcelProperty(value = {"学生信息表","学生姓名"}) , 当所有的列头,都一致是,自动合并
     *      3、@ExcelIgnore  该字段不参与读写
     *      4、@ColumnWidth(30) 设置宽度
     *      5、@DateTimeFormat("yyyy-MM-dd") 指定日期格式
     *      6、@HeadRowHeight(20) 表头的行高 只能使用在类上      高度
     *      7、@ContentRowHeight(20) 内容的行高 只能使用在类上
     *
     */
    /**
     * id
     */
    @ExcelIgnore
    @ExcelProperty(value = "编号",index = 3)
    private String id;
    /**
     * 学生姓名
     */
    @ExcelProperty(value = {"学生信息表","学生姓名"}, index = 0)
//    @ExcelProperty(value = "学生姓名", index = 0)
    @ColumnWidth(30)
    private String name;
    /**
     * 学生性别
     */
    @ExcelProperty(value = "学生性别", index = 2)
    @ColumnWidth(30)
    private String gender;
    /**
     * 学生出生日期
     */
    @ExcelProperty(value = "学生出生日期", index = 1)
    @ColumnWidth(30)
    @DateTimeFormat("yyyy-MM-dd")//指定日期格式
    private Date birthday;  
}
🚭 2.3、 准备数据并写入到文件
/**
     * 需求:单实体导出
     * 导出多个学生对象到Excel表格
     * 包含如下列:姓名、性别、出生日期
     * 模板详见:杭州黑马在线202003班学员信息.xlsx
     */
    @Test
    public void test02(){
        /**
         * Build excel the write    构建excel
         *
         * @param file
         *            File to write 要写入的文件路径
         * @param head
         *            Annotate the class for configuration information
         *              为类注释配置信息     封装写入的数据的实体类型
         * @return 写的工作表对象
         */
        // 获取工作簿对象
        ExcelWriterBuilder writeWorkBook = EasyExcel.write("学员信息表.xlsx", StudentWrite.class);
        // 获取工作表对象
        ExcelWriterSheetBuilder sheet = writeWorkBook.sheet();
        // 准备数据
        List<StudentRead> students = initData();
        // 读取表中的内容
        sheet.doWrite(students);
    }
    /**
     * @return  构建10条表数据
     */
    private static List<StudentRead> initData() {
        ArrayList<StudentRead> students = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            StudentRead data = new StudentRead();
            data.setName("杭州黑马学号0" + i);
            data.setBirthday(new Date());
            data.setGender("男");
            students.add(data);
        }
        return students;
    }
🚬 4、文件上传和下载
基于SpringBoot的文件上传和下载
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
🚭 4.1 文件上传
🛹 ①、实体类
🛹 ②、回调监听器
- 注意:@Scope(“prototype”) // 需要是多例的
@Component
@Scope("prototype") // 需要是多例的
public class WebStudentListener extends AnalysisEventListener<StudentRead> {
    @Autowired
    StudentService studentService;
    List<StudentRead> students = new ArrayList<>();
    @Override
    public void invoke(StudentRead student, AnalysisContext analysisContext) {
        students.add(student);
        //  五个操作一次
        if (students.size() % 5 == 0) {
            studentService.readExcel(students);
            students.clear();
        }
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    }   
}
🛹 ③、文件上传实现
@Controller
@RequestMapping("student")
public class StudentController {
    @Autowired
    WebStudentListener webStudentListener;
    /**
     * 文件上传
     */
    @PostMapping("read")
    @ResponseBody
    public String readExcel(MultipartFile uploadExcel) {
        try {
            //  工作薄
            ExcelReaderBuilder readBookWork = EasyExcel.read(uploadExcel.getInputStream(), StudentRead.class, webStudentListener);
            //  工作表sheet
            readBookWork.sheet().doRead();
            return "成功";
        } catch (IOException e) {
            e.printStackTrace();
            return "失败";
        }
    }
}
🛹 postApi测试

🚭 4.2 文件下载
🛹 ③、文件下载实现
@Controller
@RequestMapping("student")
public class StudentController {
    @Autowired
    WebStudentListener webStudentListener;
    /**
     * 文件导出,访问直接下载文件
     */
    @GetMapping("write")
    @ResponseBody
    public void writeExcel(HttpServletResponse response) throws Exception {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 防止中文乱码
        String fileName = URLEncoder.encode("测试", "UTF-8");
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + fileName + ".xlsx");
        // 工作簿对象
        ServletOutputStream outputStream = response.getOutputStream();
        ExcelWriterBuilder writeWorkBook = EasyExcel.write(outputStream, StudentWrite.class);
        // 工作表对象
        ExcelWriterSheetBuilder sheet = writeWorkBook.sheet();
        // 写
        sheet.doWrite(initData());
    }
    private static List<StudentWrite> initData() {
        List<StudentWrite> students = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            StudentWrite data = new StudentWrite();
            data.setName("测试" + i + 2);
            data.setGender("男");
            data.setBirthday(new Date());
            students.add(data);
        }
        System.out.println(students);
        return students;
    }
}
🚬 5、自定义单元格样式
EasyExcel支持调整行高、列宽、背景色、字体大小等内容,但是控制方式与使用原生POI无异,比较繁琐,不建议使用。
但是可以使用模板填充的方式,向预设样式的表格中直接写入数据,写入数据的时候会保持原有样式。
🚒 三、填充
- 单组数据填充:Excel表格中用 {} 来表示包裹要填充的变量
- 多组数据填充:Excel表格中用 { .xxxx} 来表示包裹要填充的变量
- { } 转义:在括号前面使用斜杠转义\{.\}
- 用来填充数据的实体对象的成员变量名或用来填充map集合的key需要和Excel中被0包裹的变量名称一致。
🚬 1、填充一组数据
🚭 1.1 准备模板
Excel表格中用{} 来表示包裹要填充的变量,如果单元格文本中本来就有
{、}左右大括号,需要在括号前面使用斜杠转义\{、\}。代码中用来填充数据的实体对象的成员变量名或用来填充map集合的key需要和Excel中被0包裹的变量名称一致。
 ![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1FbRm6Yx-1677574095487)(imgs/simpleFillTemplate.png)]](https://img-blog.csdnimg.cn/fdbf78da19fd4d7883a297b342e8206d.png)
🚭 1.2 封装数据
编写封装填充数据的类或选用Map
/**
 * 使用实体类封装填充数据
 *
 *  实体中成员变量名称需要和Excel表各种{}包裹的变量名匹配
 */
@Data
public class FillData {
    private String name;
    private int age;
}
🚭 1.3 填充
实体类 和 map 的方式均有测试
    /**
     * 单组数据的填充
     */
    @Test
    public void test03(){
        // 准备模板
        String template = "fill_data_template1.xlsx";
        // 获取工作簿对象
        ExcelWriterBuilder excelWriterBuilder = EasyExcel.write("Excel单组数据填充.xlsx", FillData.class).withTemplate(template);
        // 获取工作表对象
        ExcelWriterSheetBuilder sheet = excelWriterBuilder.sheet();
        // 准备数据一: 可以从实体里面获取数据
        FillData fillData = new FillData();
        fillData.setName("张三");
        fillData.setAge(12);
        // 准备数据二: 可以从map里面获取数据
        HashMap<String, String> stringHashMap = new HashMap<>();
        stringHashMap.put("name","李四");
        stringHashMap.put("age","15");
        // 填充数据
//        sheet.doFill(fillData);
        sheet.doFill(stringHashMap);
    }
🚬 2、填充多组数据
🚭 2.1 准备模板
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LzTsVI5a-1677574095488)(EasyExcel.assets/image-20230226103051072.png)]](https://img-blog.csdnimg.cn/cc7e238097154088ba23c4dc711bca61.png)
🚭 2.2 封装数据
🚭 2.3 填充
    /**
     * 多组数据的填充
     */
    @Test
    public void test04(){
        // 准备模板
        String template = "fill_data_template2.xlsx";
        // 获取工作簿对象
        ExcelWriterBuilder excelWriterBuilder = EasyExcel.write("Excel多组数据填充.xlsx", FillData.class).withTemplate(template);
        // 获取工作表对象
        ExcelWriterSheetBuilder sheet = excelWriterBuilder.sheet();
        // 准备数据
        List<FillData> fillData = initFillData();
        // 填充数据
        sheet.doFill(fillData); // doFill 自动关闭流操作
    }
    /**
     * @return  构建10条表数据
     */
    private static List<FillData> initFillData() {
        ArrayList<FillData> fillDataList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            FillData fillData = new FillData();
            fillData.setName("张三" + i);
            fillData.setAge(10 + i);
            fillDataList.add(fillData);
        }
        return fillDataList;
    }
🚬 3、组合填充
🚭 3.1 准备模板
即有多组数据填充,又有单一数据填充,为了避免两者数据出现冲突覆盖的情况,在多组填充时需要通过
FillConfig对象设置换行。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tNi1teXR-1677574095488)(imgs/mixFillTemplate.png)]](https://img-blog.csdnimg.cn/99f1dcc93ec546a08eaff1d8b44f0d85.png)
🚭 3.2 封装数据
🚭 3.3 填充
	/**
     * 组合数据的填充:多组填充 和 单组填充
     */
    @Test
    public void test05(){
        // 准备模板
        String template = "fill_data_template3.xlsx";
        // 获取工作簿对象 手动关闭流操作   doFill 会自动关闭流操作
        ExcelWriter workBook = EasyExcel.write("Excel组合数据填充.xlsx", FillData.class).withTemplate(template).build();
        // 获取工作表对象
        WriteSheet sheet = EasyExcel.writerSheet().build();
//        // 准备数据   会出现问题  数据填充时,多组数据填充 没有进行换行
//        List<FillData> fillData = initFillData();
//        HashMap<String, String> dateAndTotal = new HashMap<>();
//        dateAndTotal.put("date","2023-2-26");
//        dateAndTotal.put("total","1000");
//
//        // 多组数据填充
//        workBook.fill(fillData, sheet);
//
//        // 单组填充
//        workBook.fill(dateAndTotal, sheet);
//
//        // 关闭流操作
//        workBook.finish();
        /**
         * 多组填充 和 单组填充 一起使用的问题 :
         *      组合填充时,因为多组填充的数据量不确定,需要在多组填充完之后另起一行
         */
        // 换行
        FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
        // 准备数据
        List<FillData> fillData = initFillData();
        HashMap<String, String> dateAndTotal = new HashMap<>();
        dateAndTotal.put("date","2023-2-26");
        dateAndTotal.put("total","1000");
        // 多组数据填充
        workBook.fill(fillData, fillConfig,sheet); // 加入换行
        // 单组填充
        workBook.fill(dateAndTotal, sheet);
        // 关闭流操作
        workBook.finish();
    }
🚬 4、水平填充
🚭 4.1 准备模板
水平填充和多组填充模板一样,不一样的地方在于,填充时需要通过
FillConfig对象设置水平填充。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vYo4GsVD-1677574095490)(imgs/HORIZONTALFillTemplate.png)]](https://img-blog.csdnimg.cn/de6ddd330fa24ccab22d31bdb071c6f2.png)
🚭 4.2 封装数据
🚭 4.3 填充
    /**
     * 水平数据的填充 方式一:推荐
     */
    @Test
    public void test06(){
        // 准备模板
        String template = "fill_data_template4.xlsx";
        // 获取工作簿对象
        ExcelWriterBuilder excelWriterBuilder = EasyExcel.write("Excel水平组数据填充1.xlsx", FillData.class).withTemplate(template);
        // 获取工作表对象
        ExcelWriterSheetBuilder sheet = excelWriterBuilder.sheet();
        // 换行   WriteDirectionEnum.HORIZONTAL 枚举 水平 VERTICAL 垂直
        FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
        // 准备数据
        List<FillData> fillData = initFillData();
        // 填充数据
        sheet.doFill(fillData,fillConfig); // doFill 自动关闭流操作
    }
    /**
     * 水平数据的填充 方式二:
     */
    @Test
    public void test07(){
        // 准备模板
        String template = "fill_data_template4.xlsx";
        // 获取工作簿对象
        ExcelWriter workBook = EasyExcel.write("Excel水平组数据填充.xlsx", FillData.class).withTemplate(template).build();
        // 获取工作表对象
        WriteSheet sheet = EasyExcel.writerSheet().build();
        // 换行   WriteDirectionEnum.HORIZONTAL 枚举 水平 VERTICAL 垂直
        FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
        // 准备数据
        List<FillData> fillData = initFillData();
        // 多组数据填充
        workBook.fill(fillData, fillConfig,sheet); // 加入换行
        // 关闭流操作
        workBook.finish();
    }
🚬 5、 注意事项
为了节省内存,所以没有采用把整个文档在内存中组织好之后再整体写入到文件的做法,而是采用的是一行一行写入的方式,不能实现删除和移动行,也不支持备注写入。多组数据写入的时候,如果需要新增行,只能在最后一行增加,不能在中间位置添加。
🚬 6、填充综合练习
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZPPCbhF6-1677574095491)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230228164728673.png)]](https://img-blog.csdnimg.cn/1c90e3adf57146f290db784c756806ff.png)
    /**
     *  综合练习:运行数据统计
     */
    @Test
    public void test08(){
        // 准备模板
        String template = "report_template.xlsx";
        // 获取工作簿对象 手动关闭流操作   doFill 会自动关闭流操作
        ExcelWriter workBook = EasyExcel.write("Excel组合练习.xlsx", FillData.class).withTemplate(template).build();
        // 获取工作表对象
        WriteSheet sheet = EasyExcel.writerSheet().build();
        /**
         * 多组填充 和 单组填充 一起使用的问题 :
         *      组合填充时,因为多组填充的数据量不确定,需要在多组填充完之后另起一行
         */
        // 换行
//        FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
        // 准备数据
        // 日期
        HashMap<String, String> dateMap = new HashMap<String, String>();
        dateMap.put("date", "2020-03-16");
        // 总会员数
        HashMap<String, String> totalCountMap = new HashMap<String, String>();
        dateMap.put("totalCount", "1000");
        // 新增员数
        HashMap<String, String> increaseCountMap = new HashMap<String, String>();
        dateMap.put("increaseCount", "100");
        // 本周新增会员数
        HashMap<String, String> increaseCountWeekMap = new HashMap<String, String>();
        dateMap.put("increaseCountWeek", "50");
        // 本月新增会员数
        HashMap<String, String> increaseCountMonthMap = new HashMap<String, String>();
        dateMap.put("increaseCountMonth", "100");
        
        // 新增会员数据
        List<StudentRead> students = initData();
        // **** 准备数据结束****
        // 写入数据
        // 单组填充
        workBook.fill(dateMap, sheet);
        workBook.fill(totalCountMap, sheet);
        workBook.fill(increaseCountMap, sheet);
        workBook.fill(increaseCountWeekMap, sheet);
        workBook.fill(increaseCountMonthMap, sheet);
        // 多组数据填充
        workBook.fill(students,sheet); // 加入换行
        // 关闭流操作
        workBook.finish();
    }
🚬 7、从数据库中读数据写到excel中
使用Mybatis-Plus 操作数据库
🚭 7.1 数据库依赖
🚭 7.2 实体类、Service、Mapper
/**
 * 分类
 */
@Data
@TableName("category")
public class Category1 implements Serializable {
    private static final long serialVersionUID = 1L;
    @ExcelProperty(value = "id")
    private Long id;
    // 1 菜品分类 2 套餐分类
    @ExcelProperty(value = "类型")
    private Integer type;
    //分类名称
    @ExcelProperty(value = "分类名称")
    private String name;
    //顺序
    @ExcelProperty(value = "顺序")
    private Integer sort;
    //创建时间
    @ExcelProperty(value = "创建时间")
    @DateTimeFormat("yyyy-MM-dd")//指定日期格式
    @ColumnWidth(50)
    private Date createTime;
    //更新时间
    @ExcelProperty(value = "更新时间")
    @DateTimeFormat("yyyy-MM-dd")//指定日期格式
    @ColumnWidth(50)
    private Date updateTime;
    //创建人
    @ExcelProperty(value = "创建人")
    @ColumnWidth(30)
    private Long createUser;
    //修改人
    @ExcelProperty(value = "修改人")
    @ColumnWidth(30)
    private Long updateUser;
}
🚭 7.3 Controller
@RestController
@RequestMapping("/category")
public class CategoryController {
    @Autowired
    private CategoryService1 categoryService;
    /**
     * 将 Category 分类 表中的数据写入到excel中
     */
    @RequestMapping("categoryExcel")
    public void categoryExcel() {
        // 工作簿
        ExcelWriterBuilder categoryExcel = EasyExcel.write("G:/EasyExcel/EasyExecl-demo/瑞吉外卖中的分类表数据导入.xlsx", Category1.class);
        // 工作表
        ExcelWriterSheetBuilder categorySheet = categoryExcel.sheet();
        // 准备数据
        List<Category1> list = categoryService.list();
        System.out.println("list = " + list);
        categorySheet.doWrite(list);
        System.out.println("导入数据成功");
    }
}

🚤 四、常用API及注解
两两一组
🚬 1、常用类
- EasyExcel:入口类,用于构建开始各种操作;
- ExcelReaderBuilder:构建出一个ReadWorkbook对象,即一个工作簿对象,对应的是一个Excel文件;
- ExcelWriterBuilder:构建出一个WriteWorkbook对象,即一个工作簿对象,对应的是一个Excel文件;
- ExcelReaderSheetBuilder:构建出一个ReadSheet对象,即一个工作表的对象,对应的Excel中的每个sheet,一个工作簿可以有多个工作表;
- ExcelWriterSheetBuilder:构建出一WriteSheet对象,即一个工作表的对象,对应的Excel中的每个sheet,一个工作簿可以有多个工作表;
- ReadListener:在每一行读取完毕后都会调用ReadListener来处理数据,我们可以把调用service的代码可以写在其invoke方法内部;
- WriteHandler:在每一个操作包括创建单元格、创建表格等都会调用WriteHandler来处理数据,对使用者透明不可见;
- 所有配置都是继承的:Workbook的配置会被Sheet继承。所以在用EasyExcel设置参数的时候,在EasyExcel…sheet()方法之前作用域是整个sheet,之后针对单个sheet。
🚬 2、读取时的注解
(1)、@ExcelProperty
使用位置:标准作用在成员变量上,把实体类中属性和excel表中列关联起来
可选属性:
| 属性名 | 含义 | 说明 | 
|---|---|---|
| index | 对应Excel表中的列数 | 默认-1,建议指定时从0开始 | 
| value | 对应Excel表中的列头 | |
| converter(一般情况不使用) | 成员变量转换器 | 自定义转换器需要实Converter接口 | 
使用效果:index属性可以指定当前字段对应excel中的哪一列,可以根据列名value去匹配,也可以不写。
如果不使用@ExcelProperty注解,成员变量从上到下的顺序,对应表格中从左到右的顺序;
使用建议要么全部不写,要么全部用index,要么全部用名字去匹配,尽量不要三个混着用。
(2)、@ExcelIgnore
标注在成员变量上,默认所有字段都会和excel去匹配,加了这个注解会忽略该字段
(3)、@DateTimeFormat
标注在成员变量上,日期转换,代码中用String类型的成员变量去接收excel中日期格式的数据会调用这个注解。里面的value参照java.text.SimpleDateFormat
// 5. 按照指定的格式写入Excel内容
(4)、@NumberFormat
标注在成员变量上,数字转换,代码中用String类型的成员变量去接收excel数字格式的数据会调用这个注解。里面的value参照java.text.DecimalFormat
(5)、@ExcelIgnoreUnannotated(一般不使用)
标注在类上。
不标注该注解时,默认类中所有成员变量都会参与读写,无论是否在成员变量上加了@ExcelProperty 的注解。
标注该注解后,类中的成员变量如果没有标注@ExcelProperty 注解将不会参与读写。
🚬 3、 读取时通用参数(工作簿、工作表中都可用)
ReadWorkbook,ReadSheet 都会有的参数,如果为空,默认使用上级。
-  converter转换器,默认加载了很多转换器。也可以自定义。
-  readListener监听器,在读取数据的过程中会不断的调用监听器。
-  headRowNumber指定需要读表格的 列头行数。默认有一行头,也就是认为第二行开始起为数据。
-  head与clazz二选一。读取文件头对应的列表,会根据列表匹配数据。建议使用clas,就是文件中每一行数据对应的代码中的实体类型。
-  clazz与head二选一。读取文件的头对应的class,也可以使用注解。如果两个都不指定,则会读取全部数据。
-  autoTrim字符串、表头等数据自动trim
-  password读的时候是否需要使用密码
🚬 4、ReadWorkbook(工作簿对象)参数
- excelType当前excel的类型,读取时会自动判断,无需设置。
- inputStream与- file二选一。建议使用file。
- file与- inputStream二选一。读取文件的文件。
- autoCloseStream自动关闭流。
- readCache默认小于5M用 内存,超过5M会使用- EhCache,不建议使用这个参数。
- useDefaultListener- @since 2.1.4默认会加入- ModelBuildEventListener来帮忙转换成传入- class的对象,设置成- false后将不会协助转换对象,自定义的监听器会接收到- Map<Integer,CellData>对象,如果还想继续接听到- class对象,请调用- readListener方法,加入自定义的- beforeListener、- ModelBuildEventListener、 自定义的- afterListener即可。(一般不使用)
🚬 5、ReadSheet(工作表对象)参数
- sheetNo需要读取Sheet的编号,建议使用这个来指定读取哪个Sheet
- sheetName根据名字去匹配Sheet,excel 2003不支持根据名字去匹配
🚬 6、写入时的注解注解
(1)、@ExcelProperty
使用位置:标准作用在成员变量上
可选属性:
| 属性名 | 含义 | 说明 | 
|---|---|---|
| index | 对应Excel表中的列数 | 默认-1,指定时建议从0开始 | 
| value | 对应Excel表中的列头 | |
| converter | 成员变量转换器 | 自定义转换器需要实Converter接口 | 
使用效果:index 指定写到第几列,如果不指定则根据成员变量位置排序;
 value指定写入的列头,如果不指定则使用成员变量的名字作为列头;
 如果要设置复杂的头,可以为value指定多个值。
(2)、其他注解:
基本和读取时一致
-  @ContentRowHeight() 标注在类上或属性上,指定内容行高 
-  @HeadRowHeight() 标注在类上或属性上,指定列头行高 
-  @ColumnWidth() 标注在类上或属性上,指定列宽 
-  ExcelIgnore` 默认所有字段都会写入excel,这个注解会忽略这个字段 
-  DateTimeFormat日期转换,将Date写到excel会调用这个注解。里面的value参照java.text.SimpleDateFormat
-  NumberFormat数字转换,用Number写excel会调用这个注解。里面的value参照java.text.DecimalFormat
-  ExcelIgnoreUnannotated默认不加ExcelProperty的注解的都会参与读写,加了不会参与
🚬 7、写入时通用参数
WriteWorkbook、WriteSheet都会有的参数,如果为空,默认使用上级。
-  converter转换器,默认加载了很多转换器。也可以自定义。
-  writeHandler写的处理器。可以实现WorkbookWriteHandler,SheetWriteHandler,RowWriteHandler,CellWriteHandler,在写入excel的不同阶段会调用,对使用者透明不可见。
-  relativeHeadRowIndex距离多少行后开始。也就是开头空几行
-  needHead是否导出头
-  head与clazz二选一。写入文件的头列表,建议使用class。
-  clazz与head二选一。写入文件的头对应的class,也可以使用注解。
-  autoTrim字符串、表头等数据自动trim
🚬 8、WriteWorkbook(工作簿对象)参数
-  excelType当前excel的类型,默认为xlsx
-  outputStream与file二选一。写入文件的流
-  file与outputStream二选一。写入的文件
-  templateInputStream模板的文件流
-  templateFile模板文件
-  autoCloseStream自动关闭流。
-  password写的时候是否需要使用密码
-  useDefaultStyle写的时候是否是使用默认头
🚬 9、WriteSheet(工作表对象)参数
-  sheetNo需要写入的编号。默认0
-  sheetName需要些的Sheet名称,默认同sheetNo



















