在做后台管理系统的时候,很多场景都会遇到Execl的导入和导出,如果在以前的话,我们基本都是用POI这个组件,不得不说,这个组件的功能确实强大,但是也有有一些弊端,比如内存占用高、文件过大会导致OOM。后来,阿里开源的EasyExecl就能很好解决这些问题。

打开网易新闻 查看精彩图片

在开始之前,我们需要对EasyEexcl有个初步的了解,这里,我只有去Github或者是语雀查看相关的资料。

这里,我们先引入EasyExecl所以的组件

com.alibabagroupId> easyexcelartifactId> 2.2.7version>dependency>

EasyExecl常用注解

EasyExecl提供了很多注解,使得我们在导出Execl的时候更加的方便

ExcelProperty

指定当前字段对应excel中的哪一列。可以根据名字或者Index去匹配。当然也可以不写,默认第一个字段就是index=0,以此类推。千万注意,要么全部不写,要么全部用index,要么全部用名字去匹配。千万别三个混着用,除非你非常了解源代码中三个混着用怎么去排序的。

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface ExcelProperty { String[] value() default {""}; int index() default -1; #指定当前字段对应excel中的那一列 int order() default Integer.MAX_VALUE; #用于排序 Class converter() default AutoConverter.class; @Deprecated String format() default "";}

ExcelIgnore

默认所有字段都会和excel去匹配,加了这个注解会忽略该字段

DateTimeFormat

日期转换,用String去接收excel日期格式的数据会调用这个注解。里面的value参照java.text.SimpleDateFormat

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface DateTimeFormat { String value() default ""; boolean use1904windowing() default false;}

NumberFormat

数字转换,用String去接收excel数字格式的数据会调用这个注解。里面的value参照java.text.DecimalFormat

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface NumberFormat { String value() default ""; RoundingMode roundingMode() default RoundingMode.HALF_UP;}

@ExcelIgnore

这个注解的作用就是我们导出 Excel 的时候有些属性可以忽略,那么我们就在属性上面加上此注解即可。

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface ExcelIgnore {}

ExcelIgnoreUnannotated

这个注解的作用是忽略未注解的,我们如果一个实体类有太多想忽略的字段的话可以在实体类上加上该注解,这样就不用每个属性上去每个添加 @ExcelIgnore 注解了。

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface ExcelIgnoreUnannotated {}

ColumnWidth

表格列宽度

@Target({ElementType.FIELD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface ColumnWidth { int value() default -1; # 表格宽度,默认-1}

ContentRowHeight

表格行高

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface ContentRowHeight { short value() default -1;}

HeadRowHeight

表头行高

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface HeadRowHeight { short value() default -1;}

ContentLoopMerge

合并单元格。

@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface ContentLoopMerge { int eachRow() default -1; int columnExtend() default 1;}

除了上面这些注解,还有一些关于表格样式的注解,如HeadStyle、HeadFontStyle、ContentFontStyle等。下面,我就用注解来实现我们的Execl导出,首先需要一个类

@Getter@Setter@ContentRowHeight(15)public class PercentageExeclExportVo { @ColumnWidth(20) @ExcelProperty(value = "工号",index = 0) private String jobCode; @ExcelProperty(value = "姓名",index = 1) private String name; @ExcelProperty(value = "月份",index = 2) private String month; @ExcelProperty(value = "收入",index = 3) @NumberFormat(value ="#.##" ,roundingMode= RoundingMode.HALF_UP) private BigDecimal income;}

然后取出对应的数据,直接调用EasyExecl提供的API接口下载

@ApiOperation(value = "导出数据") @PostMapping(value = "/execl-export") public void execlExport(@RequestBody PercentageCalcResultInVo inVo, HttpServletResponse response) throws DefaultException { try { response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 String fileName = URLEncoder.encode("人员提成收入", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); // 这里需要设置不关闭流 EasyExcel.write(response.getOutputStream(), PercentageExeclExportVo.class).sheet("提成") .doWrite(percentageService.queryPercentageData(inVo)); } catch (Exception e) { throw new DefaultException(e.getMessage()); } }

打开网易新闻 查看精彩图片

这里只是做一个简单的示例,在语雀也有更多示例,朋友们就自己去借鉴一番。这里我只提一点,由于我们基于kubesphere将应用部署到Docker中会报错

Error: java.lang.reflect.InvocationTargetException com.alibaba.excel.exception.ExcelGenerateException: java.lang.InternalError: java.lang.reflect.InvocationTargetExceptionjava.lang.NullPointerException: null at java.desktop/sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1262)

我们最开始是Dockerfile是这样的

FROM java:openjdk-8-jre-alpineWORKDIR /homeCOPY *.jar /homeENV JAVA_OPTS="-server -Xmx2g -Xms2g"ENTRYPOINT java -jar *.jar ${JAVA_OPTS}

其实主要是因为openjdk的镜像中缺少字体包。所以,要解决这个问题,要么就是在docker加入字体,要么就更换镜像。我这边是用的后者,将Dockerfile改为

FROM java:8WORKDIR /homeCOPY *.jar /homeENV JAVA_OPTS="-server -Xmx2g -Xms2g"ENTRYPOINT java -jar *.jar ${JAVA_OPTS}