依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.3</version>
</dependency>
通过注解实现导入导出
实体类示例:该实体类包含了EasyExcel常用的注解
@Data
// 表头字体样式
@HeadFontStyle(fontHeightInPoints = 14, color = 1, fontName = "微软雅黑")
// 表头行高
@HeadRowHeight(30)
// 表头样式
@HeadStyle(fillForegroundColor = 13, // 背景色
horizontalAlignment = HorizontalAlignmentEnum.CENTER // 居中对齐
)
// 内容行高
@ContentRowHeight(25)
// 内容字体样式
@ContentFontStyle(
fontHeightInPoints = 12,
fontName = "微软雅黑"
)
// 默认列宽
@ColumnWidth(20)
// 内容样式
@ContentStyle(
horizontalAlignment = HorizontalAlignmentEnum.CENTER)
public class Student implements Serializable {
@ExcelProperty(value = "姓名", index = 1)
private String name;
@ExcelProperty(value = "性别", index = 2)
@ContentFontStyle(color = 10)
private String sex;
@ExcelProperty(value = "出生日期", index = 3, format = "yyyy-MM-dd")
private Integer birthday;
@ExcelProperty(value = "学号", index = 0)
private String no;
@ExcelProperty(value = "年级", index = 4)
private String grade;
@ExcelProperty(value = "班级", index = 5)
private String clazz;
@ExcelProperty(value = "联系电话", index = 6)
@ColumnWidth(25)
private String phone;
@ExcelProperty(value = "邮箱地址", index = 7)
// 设置文本居左
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.LEFT)
private String email;
@ExcelProperty(value = "入学时间", index = 8, format = "yyyy-MM-dd HH:mm:ss")
// 设置日期格式
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
private String enrollmentDate;
@ExcelProperty(value = "是否住校", index = 9,converter = BooleanConverter.class)
@ColumnWidth(20)
private Integer boarding;
@ExcelIgnore // 忽略该字段不导出
private String remark;
@ExcelProperty(value = "家庭住址", index = 10)
// 设置字体大小
@ContentFontStyle(fontHeightInPoints = 18)
private String address;
@ExcelProperty(value = "身份证号", index = 11)
@ColumnWidth(25)
private String idCard;
@ExcelProperty(value = "视力", index = 12)
// 保留两位小数 且四舍五入
@NumberFormat(value = "0.0", roundingMode = RoundingMode.HALF_UP)
private Double views;
}
常用注解:
- @ExcelProperty:设置列属性 value表示导出的字段名 index表示导出的顺序 converter设置转换器
- **@ContentFontStyle:**color设置字体颜色 bold设置字体加粗 underline设置下划线 fontName设置字体名称 fontHeightInPoints设置字体大小 italic设置斜体
- @ColumnWidth:设置列宽
- @ContentStyle:设置单元格样式
- @DateTimeFormat:设置日期格式
- @NumberFormat:设置数字格式
我们重点了解一下转换器converter
转换器converter主要是为了解决数据映射问题,实际开发中对于一些枚举类数据存储在数据库中一般存储的是数字编号,比如状态字段:1-显示 0-隐藏 ,数据库存储的是'0或1',但是在导出数据里希望看到的是实际的含义'显示/隐藏',@ExcelProperty里面的converter就可以指定转换器,通过实现 Converter<T> 接口 泛型T表示实体类属性数据类型也就是数据库实际存储的数据类型
示例:
public class BooleanConverter implements Converter<Integer> {
/**
* java对象实体类属性数据类型
* @return
*/
@Override
public Class<?> supportJavaTypeKey() {
return Integer.class;
}
/**
* Excel文件实际存储数据类型
* @return
*/
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
/**
* 导入时数据映射
* @param cellData
* @param contentProperty
* @param globalConfiguration
* @return
* @throws Exception
*/
@Override
public Integer convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
String stringValue = cellData.getStringValue();
if ("是".equals(stringValue)) {
return 1;
} else if ("否".equals(stringValue)) {
return 0;
}
return 0;
}
/**
* 导出时的数据映射
* @param value
* @param contentProperty
* @param globalConfiguration
* @return
*/
@Override
public WriteCellData<?> convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
if (value == null) {
return new WriteCellData<>("");
}
return new WriteCellData<>(value == 1 ? "是" : "否");
}
导入导出代码示例:单工作表
public class ExcelExportAnnotationController {
@GetMapping("/easyExcel")
public String easyExcelExport(HttpServletResponse response){
ServletOutputStream outputStream= null;
try {
response.setCharacterEncoding("utf-8");
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition", "attachment; filename=" +
URLEncoder.encode("学生信息表", "UTF-8") + ".xlsx");
outputStream = response.getOutputStream();
List<Student> students = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Student student = new Student();
student.setNo("NO" + String.format("%03d", i + 1));
student.setName("学生" + (i + 1));
student.setSex(i % 2 == 0 ? "男" : "女");
student.setBirthday(2000 + (i % 5) + (i % 12 + 1) * 100 + (i % 28 + 1)); // 模拟日期格式 YYYYMMDD
student.setGrade("年级" + ((i % 3) + 1));
student.setClazz("班级" + ((i % 5) + 1));
student.setPhone("138" + String.format("%08d", (12345678 + i) % 100000000));
student.setEmail("student" + (i + 1) + "@school.com");
student.setEnrollmentDate("2020-09-01 08:00:00");
student.setBoarding(i % 2 == 0 ? 1 : 0);
student.setAddress("北京市朝阳区某某街道" + (i + 1) + "号");
student.setIdCard("110101199001011234");
student.setViews(i + 0.5);
students.add(student);
}
EasyExcel.write(outputStream, Student.class)
.sheet("学生信息")
.doWrite(students);
} catch (IOException e) {
throw new RuntimeException(e);
}
return "导出成功";
}
@PostMapping("/import")
public String importExcel(MultipartFile file){
try {
List<Student> students = EasyExcel.read(file.getInputStream(), Student.class, null)
.sheet(0)
.doReadSync();
for (Student student : students) {
System.out.println(student);
}
}catch(IOException e){
System.out.println("读取文件异常");
}
return "导入成功";
}
}
导出效果

导入效果

导出多工作表示例:
public void easyExcelExportToMore(HttpServletResponse response){
ServletOutputStream outputStream= null;
try {
response.setCharacterEncoding("utf-8");
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition", "attachment; filename=" +
URLEncoder.encode("学生信息表", "UTF-8") + ".xlsx");
outputStream = response.getOutputStream();
//先造数据 实际开发中数据从数据库中获取
List<Student> students = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Student student = new Student();
student.setNo("NO" + String.format("%03d", i + 1));
student.setName("学生" + (i + 1));
student.setSex(i % 2 == 0 ? "男" : "女");
student.setBirthday(2000 + (i % 5) + (i % 12 + 1) * 100 + (i % 28 + 1)); // 模拟日期格式 YYYYMMDD
student.setGrade("年级" + ((i % 3) + 1));
student.setClazz("班级" + ((i % 5) + 1));
student.setPhone("138" + String.format("%08d", (12345678 + i) % 100000000));
student.setEmail("student" + (i + 1) + "@school.com");
student.setEnrollmentDate("2020-09-01 08:00:00");
student.setBoarding(i % 2 == 0 ? 1 : 0);
student.setAddress("北京市朝阳区某某街道" + (i + 1) + "号");
student.setIdCard("110101199001011234");
student.setViews(i + 0.5);
students.add(student);
}
List<Teacher> teachers = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Teacher teacher = new Teacher();
teacher.setName("老师" + (i + 1));
teacher.setSex(i % 2 == 0 ? 1 : 0);
teacher.setBirthday(2000 + (i % 5) + (i % 12 + 1) * 100 + (i % 28 + 1));
teacher.setNo("NO" + String.format("%03d", i + 1));
teachers.add(teacher);
}
WriteSheet sheet1 = EasyExcel
.writerSheet("学生信息")
.head(Student.class)//设置表头指定类 根据类上面的注解创建表头
.build();
WriteSheet sheet2 = EasyExcel.writerSheet("老师信息").head(Teacher.class).build();
ExcelWriter build = EasyExcel.write(outputStream).build();
build.write(students, sheet1);
build.write(teachers, sheet2);
build.finish();
outputStream.flush();
outputStream.close();
build.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
按模板导出
模板文件规范
{变量名}:表示单个数据占位符
{.变量名}:表示列数据填充
模板示例:

测试实体类:
@Data
public class Score implements Serializable {
private String no;
private String name;
private Integer age;
private String sex;
private String score;
}
数据生成方法:
private List<Score> getList(){
List<Score> clumData =new ArrayList<>();
for (int i = 0; i < 10; i++){
Score score = new Score();
score.setNo("202143901" + (i + 1));
score.setName("张三" + (i + 1));
score.setAge(18);
score.setSex(i % 2 == 0 ? "男" : "女");
score.setScore(new Random().nextInt(100) + "");
clumData.add(score);
}
return clumData;
}
单工作表导出
模板文件:src/main/resources/templates/学科成绩模板--单工作表.xlsx

代码:
private static final String ONE_TEMPLATE_PATH = "templates/学科成绩模板--单工作表.xlsx";
/**
* EasyExcel实现excel按模板导出--单个工作表
* @param response
*/
public void exportOne(HttpServletResponse response) {
try (InputStream inputStream = new ClassPathResource(ONE_TEMPLATE_PATH).getInputStream()){
//设置响应头
response.setCharacterEncoding("utf-8");
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition", "attachment; filename=" +
URLEncoder.encode("语文成绩表", "UTF-8") + ".xlsx");
try(ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
.withTemplate(inputStream).build()){
//写入工作表设置,注意写入工作表配置,意思是数据需要被填充在模板里面的哪个工作表上
//如果只有一个工作表,那么writeSheet可以不配置参数,默认第一个工作表
WriteSheet writeSheet = EasyExcel.writerSheet().build();
//如果有多个工作表,那么writeSheet需要配置,比如配置工作表名称,表示填充到哪个工作表上,不配置默认第一个工作表
//writeSheet.setSheetName("语文");
//生成测试数据
Map<String, Object> map = new HashMap<>();
map.put("title", "语文");
map.put("avg","69");
List<Score> clumData =getList();
// 构建填充配置,设置是否强制换行,列数据在填充时会自动换行,避免覆盖模板其他数据
FillConfig fillConfig =
FillConfig.builder().forceNewRow(Boolean.TRUE).build();
//填充数据
excelWriter.fill(clumData,fillConfig, writeSheet);
excelWriter.fill(map, writeSheet);
}catch (Exception e){
throw new RuntimeException(e);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
导出结果:

注意:
WriteSheet表示写入哪个工作表,默认是写入第一个工作表,如果有多个工作表的情况下需要指定工作表名称
FillConfig填充配置,最好配置强制换行,比如我的模板文件里面以一行'备注',如果不强制换行的话备注会被填充数据覆盖
多工作表导出
模板文件:src/main/resources/templates/学科成绩模板--多工作表.xlsx

代码实现;
private static final String MORE_TEMPLATE_PATH = "templates/学科成绩模板--多工作表.xlsx";
public void exportMore(HttpServletResponse response) {
try (InputStream inputStream = new ClassPathResource(MORE_TEMPLATE_PATH).getInputStream()){
//设置响应头
response.setCharacterEncoding("utf-8");
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition", "attachment; filename=" +
URLEncoder.encode("成绩表", "UTF-8") + ".xlsx");
try(ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
.withTemplate(inputStream).build()){
// 构建填充配置,设置是否强制换行
FillConfig fillConfig =
FillConfig.builder().forceNewRow(Boolean.TRUE).build();
//写入语文工作表
WriteSheet writeSheet = EasyExcel.writerSheet().build();
writeSheet.setSheetName("语文");
//生成测试数据
Map<String, Object> map = new HashMap<>();
map.put("title", "语文");
List<Score> chineseList = getList();
//填充数据
excelWriter.fill(map, writeSheet);
excelWriter.fill(chineseList,fillConfig, writeSheet);
//写入数学工作表
writeSheet = EasyExcel.writerSheet().build();
writeSheet.setSheetName("数学");
List<Score> mathList = getList();
map = new HashMap<>();
map.put("title", "数学");
excelWriter.fill(map, writeSheet);
excelWriter.fill(mathList, fillConfig,writeSheet);
//写入汇总工作表
map = new HashMap<>();
map.put("date", LocalDate.now());
map.put("cavg", 69);
map.put("cmax", 98);
map.put("cmin", 45);
map.put("csort", 4);
map.put("mavg", 78);
map.put("mmax", 100);
map.put("mmin", 20);
map.put("msort", 6);
writeSheet = EasyExcel.writerSheet().build();
writeSheet.setSheetName("汇总");
excelWriter.fill(map, writeSheet);
}catch (Exception e){
throw new RuntimeException(e);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
导出结果:
