简单、快速的导入导出Excel
一、安装依赖
推荐使用最新版本,可通过文章末尾官方文档链接跳转查看
<dependency>
<groupId>cn.gjing</groupId>
<artifactId>tools-excel</artifactId>
<version>2021.12.3</version>
</dependency>
二、Excel导出
1、单表头
定义Excel映射实体, @Data
是lombok的注解
/**
* @author Gjing
**/
@Data
@Excel("单级表头")
public class SingleHead {
@ExcelField("姓名")
private String userName;
@ExcelField(value = "年龄", format = "0")
private Integer userAge;
@ExcelField("性别")
private Gender gender;
@ExcelField("爱好")
private String favorite;
}
/**
* @author Gjing
**/
@RestController
public class UserController {
@GetMapping("/test_export")
@ApiOperation("导出一级表头")
public void testExport(HttpServletResponse response) {
//指定映射的实体为刚刚定义的
ExcelFactory.createWriter(SingleHead.class, response)
.write(null)
.flush();
}
}
2、多级表头
数组中的每个值代表着一级表头
/**
* @author Gjing
**/
@Data
@Excel("多级表头")
public class MultiHead {
@ExcelField({"用户名","用户名"})
private String userName;
@ExcelField({"年龄","年龄"})
private Integer age;
@ExcelField({"形态","身高"})
private BigDecimal height;
@ExcelField({"形态","体重"})
private BigDecimal weight;
}
/**
* @author Gjing
**/
@RestController
public class TestController {
@GetMapping("/test_export")
@ApiOperation("多级表头")
public void testExport(HttpServletResponse response) {
ExcelFactory.createWriter(MultiHead.class, response)
//需要在write前激活多级表头,否则不会自动合并
.multiHead(true)
.write(null)
.flush();
}
}
3、带大标题
大标题的起始行是你要插入的sheet中最后一条数据的下一行,如果sheet中没有数据,就是第一行。你可以配置大标题占用的行数和起始单元格下标(默认第一个单元格)和结束单元格下标(默认跟随表头的数量)
/**
* @author Gjing
**/
@RestController
public class TestController {
@GetMapping("/test")
@ApiOperation("含大标题")
public void testExport(HttpServletResponse response) {
ExcelFactory.createWriter(SingleHead.class, response)
//大标题占用两行
.writeTitle(new BigTitle("我是大标题"))
.write(null)
.flush();
}
}
4、下拉框
单元格增加下拉框
注解方式
/** * @author Gjing **/ @Data @Excel("下拉框导出") public class SingleHead { @ExcelField("性别") @ExcelDropdownBox(combobox = {"男", "女"}) private Gender gender; @ExcelField("爱好") private String favorite; }
/** * @author Gjing **/ @RestController public class TestController { @GetMapping("/test_export") @ApiOperation("带下拉框") public void testExport(HttpServletResponse response) { ExcelFactory.createWriter(SingleHead.class, response) //需要在write前激活校验 .valid(true) .write(null) .flush(); } }
通过方法设置普通下拉框的选项
/** * @author Gjing **/ @RestController public class TestController { @GetMapping("/test_export") @ApiOperation("带下拉框") public void testExport(HttpServletResponse response) { Map<String, String[]> genderMap = new HashMap<>(8); //key为实体类的字段名,使用方法进行设置时,实体字段的@ExcelDropdownBox注解不在需要指定combobox //如果指定了也会去覆盖注解中的值 genderMap.put("gender", new String[]{"男", "女"}); ExcelFactory.createWriter(SingleHead.class, response) .valid(true) .write(null, genderMap) .flush(); } }
5、时间校验
导出时给列表头下方的单元格增加时间校验
/** * @author Gjing **/ @Data @Excel public class SingleHead { @ExcelField("姓名") private String userName; @ExcelField(value = "年龄", format = "0") private Integer userAge; @ExcelField(value = "生日", format = "yyyy-MM-dd") @ExcelDateValid(expr1 = "2000-01-01", operatorType = LESS_OR_EQUAL, errorContent = "出生日期不能超过2000年") private Date birthday; }
/** * @author Gjing **/ @RestController public class TestController { @GetMapping("/test_export") @ApiOperation("带时间校验") public void testExport(HttpServletResponse response) { ExcelFactory.createWriter(SingleHead.class, response) //需要在write前激活校验 .valid(true) .write(null) .flush(); } }
6、数字、文本校验
导出时给列表头下方的单元格增加数值校验。可以对数字的大小,文本的长度进行校验
/** * @author Gjing **/ @Data @Excel public class SingleHead { @ExcelField("姓名") //对输入的名称字数进行校验,字数限制小于4 @ExcelNumericValid(validType = TEXT_LENGTH,operatorType = LESS_THAN,expr1 = "4",errorContent = "姓名字数小于4") private String userName; }
/** * @author Gjing **/ @RestController public class TestController { @GetMapping("/test_export") @ApiOperation("带数值校验") public void testExport(HttpServletResponse response) { ExcelFactory.createWriter(SingleHead .class, response) //需要在write前激活校验 .valid(true) .write(null) .flush(); } }
7、数据转换
导出时对数据进行加工或者添加默认值,支持注解方式和接口方式
注解方式
/** * @author Gjing **/ @Data @Excel public class SingleHead { @ExcelField("姓名") private String userName; @ExcelField(value = "年龄", format = "0") //对每个人的年龄乘以10 @ExcelDataConvert(expr1 = "#userAge * 10") private Integer userAge; }
接口方式
/** * @author Gjing **/ public class MyDataConvert implements DataConvert<SingleHead> { @Override public Object toEntityAttribute(Object o, Field field) { return null; } @Override public Object toExcelAttribute(SingleHead singleHead, Object value, Field field) { return (int) value * 10; } }
实现接口后需要在你需要转换的字段上指定转换器
/** * @author Gjing **/ @Data @Excel public class SingleHead { @ExcelField("姓名") private String userName; @ExcelField(value = "年龄", format = "0", convert = MyDataConvert.class) private Integer userAge; }
导出方法调用最后一定要使用
flush()
方法进行数据刷新到Excel文件中三、导入
导入的实体类皆采用导出的实体类
1、单表头
/** * @author Gjing **/ @RestController public class TestController { @Resource private UserService userService; @PostMapping("/user_import") @ApiOperation("导入单表头") public void userImport(MultipartFile file) throws IOException { ExcelFactory.createReader(file, SingleHead.class) //在read()方法前通过订阅方法增加一个结果监听器,该监听器会在每一次read()结束之后触发 .subscribe(e -> this.userService.saveUsers(e)) .read() .finish(); } }
2、多级表头
前文有提到多级表头时,最后一级为实际表头,所以要在导入时指定实际表头开始下标,由于导出的模板映射实体设置两级表头,因此这里的实际表头为下标为
1
(Excel行和列下标都是默认0开始的
)/** * @author Gjing **/ @RestController public class TestController { @Resource private UserService userService; @PostMapping("/user_import") @ApiOperation("导入单表头") public void userImport(MultipartFile file) throws IOException { ExcelFactory.createReader(file, SingleHead.class) //在read()方法前通过订阅方法增加一个结果监听器,该监听器会在每一次read()结束之后触发 //如果Excel中数据量太大,不建议使用结果监听器,会造成生成了过多的映射实体对象造成内存溢出 .subscribe(e -> this.userService.saveUsers(e)) .read(1) .finish(); } }
在导入调用结束后,一定要在最后调用
finish()
方法对流进行关闭
Demo地址:excel-demo
注解参数说明与更多用法可查看:官方文档
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。