SpringBoot导入导出Excel
简单、快速的导入导出Excel 一、安装依赖 推荐使用最新版本,可通过文章末尾官方文档链接跳转查看 <dependency> <groupId>cn.gjing</groupId> <artifactId>tools-excel</artifactId> <version>2.2.9</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()方法对流进行关闭 四、注解驱动方式的导入导出 如果要使用注解驱动方式,需要在启动类或者配置类标注@EnableExcelDrivenMode注解 1、导出 导出的方法需增加@ExcelWrite注解 a、导出模板 /** * @author Gjing **/ @RestController public class ExcelDriveController { @GetMapping("/export") @ApiOperation("下载Excel模板") @ExcelWrite(mapping = SingleHead.class) public void export() { } } b、导出带标题的模板 导出带大标题的模板,你可以直接设置方法的返回值为bigTitle,也可以使用ExcelWriteWrapper包装器进行数据构造 直接返回方式 @RestController public class ExcelDriveController { @GetMapping("/export") @ApiOperation("导出带大标题的excel") @ExcelWrite(mapping = SingleHead.class) public BigTitle export() { return new BigTitle("啦啦啦"); } } 包装器方式 @RestController public class ExcelDriveController { @GetMapping("/export") @ApiOperation("导出带大标题的excel") @ExcelWrite(mapping = SingleHead.class) public ExcelWriteWrapper excelDrive() { return ExcelWriteWrapper.build() .title(new BigTitle("啦啦啦")); } } c、导出数据 导出带数据的Excel,你可以直接设置方法的返回值为数据List,也可以使用ExcelWriteWrapper包装器进行数据构造,包装器可以用于设置一些属性,如监听器、大标题、导出的数据等等。。 直接返回方式 /** * @author Gjing **/ @RestController public class ExcelDriveController { @Resource private UserService userService; @GetMapping("/export") @ApiOperation("导出带数据的excel") @ExcelWrite(mapping = SingleHead.class) public List<SingleHead> excelDrive() { return this.userService.userList(); } } 包装器方式 @RestController public class ExcelDriveController { @Resource private UserService userService; @GetMapping("/excel_drive") @ApiOperation("导出带数据的excel") @ExcelWrite(mapping = SingleHead.class) public ExcelWriteWrapper export() { return ExcelWriteWrapper.build(userService.userList()); } } 2、导入 导出的方法需要增加@ExcelRead注解 a、导入普通的模板 导入时,需要将方法返回值设置为ExcelReadWrapper,这是导入时的数据包装器,用于设置一些属性,如文件流、监听器、结果订阅... @RestController public class ExcelDriveController { @Resource private UserService userService; @PostMapping("/excel_drive5") @ApiOperation("导入excel") @ExcelRead public ExcelReadWrapper<SingleHead> read1(MultipartFile file) throws IOException { return ExcelReadWrapper.build(SingleHead.class) .data(file) .subscribe(e -> this.userService.saveUsers(e)); } } b、导入带大标题的模板 由上文可得知,如果模板带有大标题,需要我们指定表头开始下标,下标要根据你的模板标题有多少行而定,我们在导出时设置了两行,所以这里配置两行 @RestController public class ExcelDriveController { @Resource private UserService userService; @PostMapping("/excel_drive5") @ApiOperation("导入excel") @ExcelRead(headerIndex = 2) public ExcelReadWrapper<SingleHead> read1(MultipartFile file) throws IOException { return ExcelReadWrapper.build(SingleHead.class) .data(file) .subscribe(e -> this.userService.saveUsers(e)); } } Demo地址:excel-demo 注解参数说明与更多用法可查看:官方文档