logo
0
1
WeChat Login

excel-spring-boot-starter

此项目底层基于 FastExcel 实现 Excel 的读写。

此项目1.2.10 & 3.1.3 版本及之前版本,底层基于 EasyExcel 实现 Excel 的读写。

FastExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。 64M内存1分钟内读取75M(46W行25列)的Excel,当然还有急速模式能更快,但是内存占用会在100M多一点

依赖引用

  • 项目已上传至 maven 仓库,直接引入即可使用

Maven Central

版本支持
3.x.x适配 SpringBoot3.x
1.x.x适配 SpringBoot2.x
<dependency> <groupId>com.kangaroohy</groupId> <artifactId>excel-spring-boot-starter</artifactId> <version>${lastVersion}</version> </dependency>

导入 Excel

  • 接口类定义List 接受表格对应的数据 使用 @RequestExcel 标记
@PostMapping("/upload") public void upload(@RequestExcel List<DemoData> dataList,BindingResult bindingResult){ // JSR 303 校验通用校验获取失败的数据 List<ErrorMessage> errorMessageList=(List<ErrorMessage>)bindingResult.getTarget(); }
  • 实体声明
@Data public class Demo { @ExcelProperty(index = 0) private String username; @ExcelProperty(index = 1) private String password; }

导出 Excel

只需要在 Controller 层返回 List 并增加 @ResponseExcel注解即可

@Documented @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ResponseExcel { String name() default ""; ExcelTypeEnum suffix() default ExcelTypeEnum.XLSX; String password() default ""; Sheet[] sheets() default @Sheet(sheetName = "sheet1"); boolean inMemory() default false; String template() default ""; String[] include() default {}; String[] exclude() default {}; Class<? extends WriteHandler>[] writeHandler() default {}; Class<? extends Converter>[] converter() default {}; Class<? extends HeadGenerator> headGenerator() default HeadGenerator.class; boolean i18nHeader() default false; boolean fill() default false; String waterMark() default ""; }

基础用法

  • 返回单 sheet, 全部字段导出
@ResponseExcel(name = "test", sheets = @Sheet(sheetName = "testSheet1")) @GetMapping("/e1") public List<DemoData> e1(){ List<DemoData> dataList=new ArrayList<>(); for(int i=0;i< 100;i++){ DemoData data=new DemoData(); data.setUsername("tr1"+i); data.setPassword("tr2"+i); dataList.add(data); } return dataList; } // 实体对象 @Data public class DemoData { private String username; private String password; }

img.png

  • 自定义字段属性
@Data public class DemoData { @ColumnWidth(50) // 定义宽度 @ExcelProperty("用户名") // 定义列名称 @ContentStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40) private String username; @ExcelProperty("密码") private String password; }

img_1.png

  • 忽略部分字段
@Data public class DemoData { @ColumnWidth(50) // 定义宽度 @ExcelProperty("用户名") // 定义列名称 @ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40) private String username; @ExcelIgnore // 忽略这个字段 private String password; }

img_2.png

导出并加密

@ResponseExcel(name = "kangaroohy", password = "kangaroohy") @GetMapping("/e1") public List<DemoData> e1(){ return list(); }

img_3.png

导出多sheet

@ResponseExcel(name = "kangaroohy", sheets = { @Sheet(sheetName = "第一个Sheet"), @Sheet(sheetName = "第二个sheet") }) @GetMapping("/e1") public List<List<DemoData>>e1(){ List<List<DemoData>>lists=new ArrayList<>(); lists.add(list()); lists.add(list()); return lists; }

img_4.png

导出不同的 Sheet

这里两个 sheet 导出不同类型的对象,只导出 DemoData 中的 username 属性,且将 testData 中的 number 属性排除。

@Controller @RequestMapping("public/excel") public class ExportMultiSheetController { @ResponseExcel(name = "不同Sheet的导出", sheets = { @Sheet(sheetName = "demoData", includes = {"username"}), @Sheet(sheetName = "testData", excludes = {"number"}) }) @GetMapping("/different-sheet") public List<List> multiDifferent() { List<List> lists = new ArrayList<>(); lists.add(demoDatalist()); lists.add(testDatalist()); return lists; } private List<DemoData> demoDatalist() { List<DemoData> dataList = new ArrayList<>(); for (int i = 0; i < 100; i++) { DemoData data = new DemoData(); data.setUsername("tr1" + i); data.setPassword("tr2" + i); dataList.add(data); } return dataList; } private List<TestData> testDatalist() { List<TestData> dataList = new ArrayList<>(); for (int i = 0; i < 100; i++) { TestData data = new TestData(); data.setStr("str" + i); data.setNumber(i); data.setLocalDateTime(LocalDateTime.now()); dataList.add(data); } return dataList; } // 实体对象 @Data public static class DemoData { private String username; private String password; } @Data public static class TestData { private String str; private Integer number; @ColumnWidth(50) // 定义宽度 private LocalDateTime localDateTime; } }

导出不同的 Sheet

导出并自定义头信息

测试实体类:

@Data public class SimpleData { @ExcelProperty("字符串标题") private String string; @ExcelProperty("日期标题") private Date date; @ExcelProperty("数字标题") private Integer number; // 忽略 @ExcelIgnore private String ignore; }

自定义头信息生成器

注意需要实现 HeadGenerator 接口,且注册为一个 spring bean.

@Component public class SimpleDataHeadGenerator implements HeadGenerator { @Override public HeadMeta head(Class<?> clazz) { HeadMeta headMeta = new HeadMeta(); headMeta.setHead(simpleDataHead()); // 排除 number 属性 headMeta.setIgnoreHeadFields(new HashSet<>(Collections.singletonList("number"))); return headMeta; } private List<List<String>> simpleDataHead() { List<List<String>> list = new ArrayList<>(); List<String> head0 = new ArrayList<>(); head0.add("自定义字符串标题" + System.currentTimeMillis()); List<String> head1 = new ArrayList<>(); head1.add("自定义日期标题" + System.currentTimeMillis()); list.add(head0); list.add(head1); return list; } }

该头生成器,将固定返回 自定义字符串标题 和 自定义日期标题 两列头信息,实际使用时可根据业务动态处理,方便在一些权限控制时动态修改或者增删列头。

测试代码:

@RequestMapping("/head") @RestController public class ExcelHeadTestController { @ResponseExcel(name = "customHead", headGenerator = SimpleDataHeadGenerator.class) @GetMapping public List<SimpleData> multi() { List<SimpleData> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { SimpleData simpleData = new SimpleData(); simpleData.setString("str" + i); simpleData.setNumber(i); simpleData.setDate(new Date()); list.add(simpleData); } return list; } }

自定义头信息

添加水印

@RequestMapping("/water-mark") @RestController public class ExcelWaterMarkTestController { @ResponseExcel(name = "用户记录", sheets = { @Sheet(sheetName = "用户信息") }, waterMark = "这是水印") @GetMapping public List<User> exportWithWaterMark() { List<User> userList = new ArrayList<>(); for (int i = 0; i < 100; i++) { userList.add(User.builder() .id((long) i) .username("username" + i) .password("password" + i) .build()); } return userList; } }

waterMark.png

国际化的导入导出

国际化配置基于 Spring 的 MessageSource,开启国际化时,spring 容器中必须有一个 MessageSource 的 Bean。

具体 Spring

的国际化使用这里不再展开,想要了解的可以参看官方文档 Spring MessageSource 使用

以及 SpringBoot 国际化配置

首先在 resource 下,新建国际化配置文件

  • messages.properties

    DemoData.username=Username DemoData.age=Age
  • messages_en_US.properties

    DemoData.username=Username DemoData.age=Age
  • messages_zh_CN.properties

    DemoData.username=用户名 DemoData.age=年龄

测试类的注解信息上,使用 {} 标记配置文件中的 key

@Data public class DemoData { @ExcelProperty(value = "{DemoData.username}", index = 0) private String username; @ExcelProperty(value = "{DemoData.age}", index = 1) private Integer age; }

**导出注解上设置 i18nHeader=true **

@ResponseExcel(name = "i18nExport", i18nHeader = true) @GetMapping("excelExport") public List<DemoData> i18nExport(){ List<DemoData> list=new ArrayList<>(); for(int i=0;i< 10;i++){ DemoData demoData=new DemoData(); demoData.setUsername("username:"+i); demoData.setAge(i); list.add(demoData); } return list; }

使用 Postman 测试导出

请求头上使用 Accept-Language 指定当前语言区域,中文是 zh-CN, 英文是 en-US

SpringBoot 的国际化默认会读取请求头中的 Accept-Language 进行判断当前区域,可以通过定制 LocaleResolver 替换这一默认行为

导出效果

导出效果

导入 controller

注意,这里导入接受的对象如果和导出是同一个的话,由于列名是国际化配置的占位符,无法和实际上传文件进行对应,所以需要给该对象的属性指定 index,导入文件根据 index 进行数据映射。

当然,也可以使用额外的导入类来接收导入信息。

@PostMapping("i18n") @ResponseBody public List<DemoData> importExcel(@RequestExcel List<DemoData> list){ return list; }
  • 导入获取excel 行号,实体属性增加 @ExcelLine 注解即可
/** * 导入时候回显行号 */ @ExcelLine @ExcelIgnore private Long lineNum;

使用 Postman 测试导入

添加全局自定义转换器(Converter)

0.0.7 版本开始添加了全局自定义转换器注入的功能,你只需要将自定义的 Converter 注册成 Spring bean 即可。

示例代码如下(对 set 类型转换):

@Data public class TestModel { @ExcelProperty("名称集合") private Set<String> nameSet; } /** * 集合转换器 * */ @Component public class SetConverter implements Converter<Set<?>> { private final ConversionService conversionService; SetConverter() { this.conversionService = DefaultConversionService.getSharedInstance(); } @Override public Class<?> supportJavaTypeKey() { return Set.class; } @Override public CellDataTypeEnum supportExcelTypeKey() { return CellDataTypeEnum.STRING; } @Override public Set<?> convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { String[] value = StringUtils.delimitedListToStringArray(cellData.getStringValue(), ","); return (Set<?>) conversionService.convert(value, TypeDescriptor.valueOf(String[].class), new TypeDescriptor(contentProperty.getField())); } @Override public CellData<String> convertToExcelData(Set<?> value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return new CellData<>(StringUtils.collectionToCommaDelimitedString(value)); } }

高级用法模板导出

/** * 默认读取 classpath:excel/ 目录下的模板文件,具体模板使用参考官方文档 * */ @ResponseExcel(name = "模板测试excel", sheet = "sheetName", template = "example.xlsx") @GetMapping("/e1") public List<DemoData> e1(){ return list(); }

导出添加批注

@Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ExcelNotation { /** * 文本内容 */ String value() default ""; }

标识是否必填

此处只是简单的改变表头字体颜色,醒目提醒用户字段必填

@Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ExcelRequired { /** * 字体颜色 */ IndexedColors frontColor() default IndexedColors.RED; }

设置单元格下拉框

用于设置导出时,excel 的单元格下拉框的选项

@Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ExcelSelector { /** * 固定数据 */ String[] value() default {}; /** * 字典key */ String dictKeyValue() default ""; /** * 服务类,需要交给spring管理,如 @Service,如果只有一个实现类时,此属性可以不设置 */ Class<? extends ExcelSelectorService> serviceClass() default ExcelSelectorService.class; /** * 设置下拉框的起始行,默认为表头的下一行 */ int firstRow() default -1; /** * 设置下拉框的结束行,默认为int最大值,65535 */ int lastRow() default 0x10000; }

导入时校验数据是否重复

类注解

@Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ExcelUniqueFields { /** * 该组内所有字段组合保证唯一性 * * @return */ String[] groupUnique() default {}; /** * 该组内每个字段单独保证唯一,字段之间可以允许重复 * * @return */ String[] singleUnique() default {}; /** * 空值不做校验,false时 null 也会当成值的一种参与校验 * * @return */ boolean skipNull() default true; }

其他用法

About

excel 导入导出封装,导入导出注解支持

1.88 MiB
0 forks1 stars2 branches14 TagREADMEApache-2.0 license
Language
Java100%