通过easyExcel实现表格导入导出

学习参考文档

1、简单入门

1.1、依赖

<dependencies>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>easyexcel</artifactId>
        <version>2.2.6</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <version>2.3.5.RELEASE</version>
    </dependency>
    <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <version>1.18.16</version>
         <scope>compile</scope>
     </dependency>
</dependencies>

1.2、Execl写入

// JavaBean
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class User {
    @ExcelProperty(value = "用户编号")
    private Integer userId;
    @ExcelProperty(value = "姓名")
    private String userName;
    @ExcelProperty(value = "性别")
    private String gender;
    @ExcelProperty(value = "工资")
    private Double salary;
    @ExcelProperty(value = "入职时间")
    private Date hireDate;

    // lombok 会生成getter/setter方法
}

// 测试类
import com.alibaba.excel.EasyExcel;
import com.ublink.domain.User;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class test01 {

    @Test
    public void testWriteExcel() {
    	//没有文件的话就先去创建一下
        String filename = "C:\\Users\\Admin\\Desktop\\user.xlsx";

        // 向Excel中写入数据 也可以通过 head(Class<?>) 指定数据模板
        EasyExcel.write(filename, User.class)
                .sheet("用户信息")
                .doWrite(getUserData());
    }
	
	@Test
    public void testWriteExcel2() {
        String filename = "C:\\Users\\Admin\\Desktop\\user1.xlsx";
        // 创建ExcelWriter对象
        ExcelWriter excelWriter = EasyExcel.write(filename, User.class).build();
        // 创建Sheet对象
        WriteSheet writeSheet = EasyExcel.writerSheet("用户信息").build();
        // 向Excel中写入数据
        excelWriter.write(getUserData(), writeSheet);
        // 关闭流
        excelWriter.finish();
    }

    // 根据user模板构建数据
    private List<User> getUserData() {
        List<User> users = new ArrayList<User>();
        for (int i = 1; i <= 10; i++) {
            User user = User.builder()
                    .userId(i)
                    .userName("admin" + i)
                    .gender(i % 2 == 0 ? "男" : "女")
                    .salary(i * 1000.00)
                    .hireDate(new Date())
                    .build();
            users.add(user);
        }
        return users;
    }
}

一般来说的话文件写入在找不到文件时会自动创建,防止意外的话直接手动创建就是了

结果

在这里插入图片描述

在这里插入图片描述

1.3、Execl读出

数据准备

这些数据我写在user.xlsx的第二张表里
在这里插入图片描述

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.ublink.domain.User;
import org.junit.Test;

public class test02 {
    @Test
    // 在读取Excel表格数据时, 将读取的每行记录映射成一条LinkedHashMap记录, 而没有映射成实体类.
    public void testRead() {
        String filename = "C:\\Users\\Admin\\Desktop\\user.xlsx";
        // 创建ExcelReaderBuilder对象
        ExcelReaderBuilder readerBuilder = EasyExcel.read();
        // 获取文件对象
        readerBuilder.file(filename);
        // 指定映射的数据模板
        //  readerBuilder.head(DemoData.class);
        // 指定sheet
        readerBuilder.sheet(0);
        // 自动关闭输入流
        readerBuilder.autoCloseStream(true);
        // 设置Excel文件格式
        readerBuilder.excelType(ExcelTypeEnum.XLSX);
        // 注册监听器进行数据的解析
        readerBuilder.registerReadListener(new AnalysisEventListener() {
            // 每解析一行数据,该方法会被调用一次
            @Override
            public void invoke(Object demoData, AnalysisContext analysisContext) {
                // 如果没有指定数据模板, 解析的数据会封装成 LinkedHashMap返回
                // demoData instanceof LinkedHashMap 返回 true
                System.out.println("解析数据为:" + demoData.toString());
            }

            // 全部解析完成被调用
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                System.out.println("解析完成...");
                // 可以将解析的数据保存到数据库
            }
        });
        readerBuilder.doReadAll();
  /*  // 构建读取器
    ExcelReader excelReader = readerBuilder.build();
    // 读取Excel
    excelReader.readAll();
    // 关闭流
    excelReader.finish();*/
    }
    
	@Test
    public void testReadExcel() {
        // 读取的excel文件路径
        String filename = "C:\\Users\\Admin\\Desktop\\user.xlsx";
        // 读取excel
        EasyExcel.read(filename, User.class, new AnalysisEventListener<User>() {
            // 每解析一行数据,该方法会被调用一次
            @Override
            public void invoke(User user, AnalysisContext analysisContext) {
                System.out.println("解析数据为:" + user.toString());
            }
            // 全部解析完成被调用
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                System.out.println("解析完成...");
                // 可以将解析的数据保存到数据库
            }
        }).sheet().doRead();
    }

	@Test
	public void testReadExcel2() {
	    // 读取的excel文件路径
	    String filename = "D:\\study\\excel\\read.xlsx";
	    // 创建一个数据格式来装读取到的数据
	    Class<DemoData> head = DemoData.class;
	    // 创建ExcelReader对象
	    ExcelReader excelReader = EasyExcel.read(filename, head, new AnalysisEventListener<DemoData>() {
	        // 每解析一行数据,该方法会被调用一次
	        @Override
	        public void invoke(DemoData demoData, AnalysisContext analysisContext) {
	            System.out.println("解析数据为:" + demoData.toString());
	        }
	        // 全部解析完成被调用
	        @Override
	        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
	            System.out.println("解析完成...");
	            // 可以将解析的数据保存到数据库
	        }
	    }).build();
	    // 创建sheet对象,并读取Excel的第一个sheet(下标从0开始), 也可以根据sheet名称获取
	    ReadSheet sheet = EasyExcel.readSheet(0).build();
	    // 读取sheet表格数据, 参数是可变参数,可以读取多个sheet
	    excelReader.read(sheet);
	    // 需要自己关闭流操作,在读取文件时会创建临时文件,如果不关闭,会损耗磁盘,严重的磁盘爆掉
	    excelReader.finish();
    }
}
结果

结果1:
这是由于我将两张表放在一个文件里,因此打印了两张表的数据
在这里插入图片描述
结果2:映射后的效果
在这里插入图片描述

1.4、附——格式转换

@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class DemoData {
    @ExcelProperty(value = "字符串标题", index = 0)
    private String name;
    @ExcelProperty(value = "日期标题", index = 1)
   // 格式化日期类型数据
    @DateTimeFormat(value = "yyyy年MM月dd日 HH时mm分ss秒")
    private Date hireDate;
    @ExcelProperty(value = "数字标题", index = 2)
   // 格式化数字类型数据,保留一位小数
    @NumberFormat(value = "###.#")
    private String salary;
    //注意: @NumberFormat对于Double类型的数据格式化会失效,建议使用String类型接收数据进行格式化
//    private Double salary;
    // lombok 会生成getter/setter方法
}

1.end、可能的异常

在这里插入图片描述

我手敲的路径,少了个s(手动捂脸),大家作为反面教材引以为戒哈
C:\Users\Admin\Desktop\user.xlsx

在这里插入图片描述

我这边猜测的可能性最大的是:
文件被打开了(比如看看学习成果)导致文件访问异常

在这里插入图片描述

字段不匹配:检查一下表格文件的表头字段是不是跟JavaBean属性名对应

2、细化操作

2.1、写入

2.1.1、忽略写入字段
@Test
public void testWriteExcel3() {
    String filename = "C:\\Users\\Admin\\Desktop\\user.xlsx";
    // 设置排除的属性 也可以在数据模型的字段上加@ExcelIgnore注解排除
    Set<String> excludeField = new HashSet<String>();
    excludeField.add("hireDate");
    excludeField.add("salary");
    // 写Excel
    EasyExcel.write(filename, User.class)
            .excludeColumnFiledNames(excludeField)
            .sheet("用户信息")
            .doWrite(getUserData());
}

在这里插入图片描述

2.1.2、选择写入字段
@Test
public void testWriteExcel4() {
    String filename = "C:\\Users\\Admin\\Desktop\\user.xlsx";
    // 设置要导出的字段
    Set<String> includeFields = new HashSet<String>();
    includeFields.add("userName");
    includeFields.add("hireDate");
    includeFields.add("salary");
    // 写Excel
    EasyExcel.write(filename, User.class)
            .includeColumnFiledNames(includeFields)
            .sheet("用户信息")
            .doWrite(getUserData());
}

在这里插入图片描述

表头字段顺序按JavaBean顺序来,读出的时候按表格文件中的顺序来

2.1.3、调整顺序

修改后的JavaBean

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class User {
    @ExcelProperty(value = "用户编号")
    private Integer userId;
    @ExcelProperty(value = "姓名", index = 1)
    private String userName;
    @ExcelProperty(value = "性别")
    private String gender;
    @ExcelProperty(value = "工资", index = 0)
    private Double salary;
    @ExcelProperty(value = "入职时间", index = 2)
    private Date hireDate;

    // lombok 会生成getter/setter方法
}

再次执行testWriteExcel4方法查看结果
在这里插入图片描述

2.2、读出

格式化数据

在这里插入图片描述

使用@DateTimeFormat()注解转化日期时间,value属性填写日期格式
使用@NumberFormat()注解转化数字,value写数字格式,#代替数字位置

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.format.NumberFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class DemoData {
    @ExcelProperty(value = "字符串标题", index = 1)
    private String name;
    @ExcelProperty(value = "日期标题", index = 2)
    // 格式化日期类型数据
    @DateTimeFormat(value = "yyyy年MM月dd日 HH时mm分ss秒")
    private Date hireDate;
    @ExcelProperty(value = "数字标题", index = 0)
    // 格式化数字类型数据,保留一位小数
    @NumberFormat(value = "###.#")
    private String salary;
    //注意: @NumberFormat对于Double类型的数据格式化会失效,建议使用String类型接收数据进行格式化
//    private Double salary;
    // lombok 会生成getter/setter方法
}

测试类进行读取

@Test
    public void testRead() {
        String filename = "C:\\Users\\Admin\\Desktop\\user.xlsx";
        // 创建ExcelReaderBuilder对象
        ExcelReaderBuilder readerBuilder = EasyExcel.read();
        // 获取文件对象
        readerBuilder.file(filename);
        // 指定映射的数据模板
        //  readerBuilder.head(DemoData.class);
        // 指定sheet
        readerBuilder.sheet(0);
        // 自动关闭输入流
        readerBuilder.autoCloseStream(true);
        // 设置Excel文件格式
        readerBuilder.excelType(ExcelTypeEnum.XLSX);
        // 注册监听器进行数据的解析
        readerBuilder.registerReadListener(new AnalysisEventListener() {
            // 每解析一行数据,该方法会被调用一次
            @Override
            public void invoke(Object demoData, AnalysisContext analysisContext) {
                // 如果没有指定数据模板, 解析的数据会封装成 LinkedHashMap返回
                // demoData instanceof LinkedHashMap 返回 true
                System.out.println("解析数据为:" + demoData.toString());
            }

            // 全部解析完成被调用
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                System.out.println("解析完成...");
                // 可以将解析的数据保存到数据库
            }
        });
        readerBuilder.doReadAll();
  /*  // 构建读取器
    ExcelReader excelReader = readerBuilder.build();
    // 读取Excel
    excelReader.readAll();
    // 关闭流
    excelReader.finish();*/

    }

结果:
在这里插入图片描述

3、进阶操作

4、样式操作

4.1、设置表格宽高

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
@HeadRowHeight(value = 30) // 头部行高
@ContentRowHeight(value = 25) // 内容行高
@ColumnWidth(value = 20) // 列宽
public class WidthAndHeightData {
    @ExcelProperty(value = "字符串标题")
    private String string;
    @ExcelProperty(value = "日期标题")
    private Date date;
    @ExcelProperty(value = "数字标题")
    @ColumnWidth(value = 25)
    private Double doubleData;
    // lombok 会生成getter/setter方法
}
import com.alibaba.excel.EasyExcel;
import com.ublink.domain.WidthAndHeightData;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Test03 {
    @Test
    public void testWrite11() {
        String filename = "C:\Users\Admin\Desktop\userwh.xlsx";
        // 构建数据
        List<WidthAndHeightData> dataList = new ArrayList<WidthAndHeightData>();
        WidthAndHeightData data = WidthAndHeightData.builder()
	        .string("字符串")
	        .date(new Date())
	        .doubleData(888.88)
	        .build();
        dataList.add(data);
        // 向Excel中写入数据
        EasyExcel.write(filename, WidthAndHeightData.class)
            .sheet("行高和列宽测试")
            .doWrite(dataList);
    }
}

结果
在这里插入图片描述

4.2、颜色、字体等

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.poi.ss.usermodel.FillPatternType;

import java.util.Date;

@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
@HeadRowHeight(value = 30) // 头部行高
@ContentRowHeight(value = 25) // 内容行高
@ColumnWidth(value = 20) // 列宽
// 头背景设置成红色 IndexedColors.RED.getIndex()
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 10)
// 头字体设置成20, 字体默认宋体
@HeadFontStyle(fontName = "宋体", fontHeightInPoints = 20)
// 内容的背景设置成绿色  IndexedColors.GREEN.getIndex()
@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 17)
// 内容字体设置成20, 字体默认宋体
@ContentFontStyle(fontName = "宋体", fontHeightInPoints = 20)
public class DemoStyleData {

    // 字符串的头背景设置成粉红 IndexedColors.PINK.getIndex()
    @HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 14)
    // 字符串的头字体设置成20
    @HeadFontStyle(fontHeightInPoints = 30)
    // 字符串的内容背景设置成天蓝 IndexedColors.SKY_BLUE.getIndex()
    @ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40)
    // 字符串的内容字体设置成20,默认宋体
    @ContentFontStyle(fontName = "宋体", fontHeightInPoints = 20)
    @ExcelProperty(value = "字符串标题")
    private String string;
    @ExcelProperty(value = "日期标题")
    private Date date;
    @ExcelProperty(value = "数字标题")
    private Double doubleData;
    // lombok 会生成getter/setter方法
}
@Test
public void testWrite12() {
    String filename = "C:\Users\Admin\Desktop\user12.xlsx";
    // 构建数据
    List<DemoStyleData> dataList = new ArrayList<>();
    DemoStyleData data = DemoStyleData.builder()
            .string("字符串")
            .date(new Date())
            .doubleData(888.88)
            .build();
    dataList.add(data);
    // 向Excel中写入数据
    EasyExcel.write(filename, DemoStyleData.class)
            .sheet("样式设置测试")
            .doWrite(dataList);
}

结果
在这里插入图片描述

4.3、单元格合并

@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
@HeadRowHeight(value = 25) // 头部行高
@ContentRowHeight(value = 20) // 内容行高
@ColumnWidth(value = 20) // 列宽
/**
 * @OnceAbsoluteMerge 指定从哪一行/列开始,哪一行/列结束,进行单元格合并
 * firstRowIndex 起始行索引,从0开始
 * lastRowIndex 结束行索引
 * firstColumnIndex 起始列索引,从0开始
 * lastColumnIndex 结束列索引
 */
// 例如: 第2-3行,2-3列进行合并
@OnceAbsoluteMerge(firstRowIndex = 1, lastRowIndex = 2, firstColumnIndex = 1, lastColumnIndex = 2)
public class DemoMergeData {

    // 每隔两行合并一次(竖着合并单元格)
//    @ContentLoopMerge(eachRow = 2)
    @ExcelProperty(value = "字符串标题")
    private String string;
    @ExcelProperty(value = "日期标题")
    private Date date;
    @ExcelProperty(value = "数字标题")
    private Double doubleData;
    // lombok 会生成getter/setter方法
}

@Test
public void testWrite13() {
    String filename = "C:\Users\Admin\Desktop\user13.xlsx";
    // 构建数据
    List<DemoMergeData> dataList = new ArrayList<>();
    DemoMergeData data = DemoMergeData.builder()
            .string("字符串")
            .date(new Date())
            .doubleData(888.88)
            .build();
    dataList.add(data);
    // 向Excel中写入数据
    EasyExcel.write(filename, DemoMergeData.class)
            .sheet("单元格合并测试")
            .doWrite(dataList);
}

结果
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值