合作建站方案,江苏省建设工程考试网站,网站设计术语,wordpress空格代码java生成Excel比较有名的框架有Apache poi、jxl等#xff0c;但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。 EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。… java生成Excel比较有名的框架有Apache poi、jxl等但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。 EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部载到内存中而是从磁盘上一行行读取数据逐个解析。EasyExcel采用一行一行的解析模式并将一行的解析结果以观察者的模式通知处理( AnalysisEventListener )。 1、pom添加easyexcel依赖
dependencygroupIdcom.alibaba/groupIdartifactIdeasyexcel/artifactIdversion3.1.3/version
/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional
/dependency
dependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion5.8.18/version
/dependency2、实体类UserDO与Excel数据对应
Data
public class UserDO {// 设置excel表头名称ExcelProperty(用户编号)ColumnWidth(20)private Long id;// 设置该列的名称为用户名ExcelProperty(用户名)// 设置表格列的宽度为20ColumnWidth(20)private String username;// 导出时忽略该字段ExcelIgnoreprivate String password;ExcelProperty(昵称)ColumnWidth(20)private String nickname;ExcelProperty(生日)ColumnWidth(20)// 按照指定的格式对日期进行格式化DateTimeFormat(yyyy-MM-dd)private Date birthday;ExcelProperty(手机号)ColumnWidth(20)private String phone;ExcelProperty(身高米)NumberFormat(#.##)ColumnWidth(20)private Double height;// 自定义内容转换器ExcelProperty(value 性别, converter GenderConverter.class)ColumnWidth(10)private Integer gender;}常用注解有 ExcelProperty 指定当前字段对应excel中的哪一列。可以根据名字或者Index去匹配。当然也可以不写默认第一个字段就是index0以此类推。千万注意要么全部不写要么全部用index要么全部用名字去匹配。千万别三个混着用除非你非常了解源代码中三个混着用怎么去排序的。 ExcelIgnore EasyExcel默认所有字段都会和excel去匹配加了这个注解会忽略该字段 DateTimeFormat 日期转换用String去接收excel日期格式的数据会调用这个注解。里面的value参照java.text.SimpleDateFormat NumberFormat 数字转换用String去接收excel数字格式的数据会调用这个注解。里面的value参照java.text.DecimalFormat 3、converter自定义转换器 自定义转换器将数据库中表示性别的1、0转换成男、女 3.1、GenderConverter
/*** 性别转换器* */
public class GenderConverter implements ConverterInteger {Overridepublic Class? supportJavaTypeKey() {// 实体类中对象属性类型return Integer.class;}Overridepublic CellDataTypeEnum supportExcelTypeKey() {// Excel中对应的CellData(单元格数据)属性类型return CellDataTypeEnum.STRING;}/*** 将单元格里的数据转为java对象也就是女转成2男转成1用于导入excel时对性别字段进行转换* */Overridepublic Integer convertToJavaData(ReadConverterContext? context) throws Exception {// 从CellData中读取数据判断Excel中的值将其转换为预期的数值return GenderEnum.convert(context.getReadCellData().getStringValue()).getValue();}/*** 将java对象转为单元格数据也就是2转成女1转成男用于导出excel时对性别字段进行转换* */Overridepublic WriteCellData? convertToExcelData(WriteConverterContextInteger context) throws Exception {// 判断实体类中获取的值转换为Excel预期的值并封装为CellData对象return new WriteCellData(GenderEnum.convert(context.getValue()).getDescription());}
} 3.2、GenderEnum
Getter
AllArgsConstructor
public enum GenderEnum {/*** 未知*/UNKNOWN(0, 未知),/*** 男性*/MALE(1, 男性),/*** 女性*/FEMALE(2, 女性);private final Integer value;JsonFormatprivate final String description;public static GenderEnum convert(Integer value) {
// 用于为给定元素创建顺序流
// values:获取枚举类型的对象数组return Stream.of(values()).filter(bean - bean.value.equals(value)).findAny().orElse(UNKNOWN);}public static GenderEnum convert(String description) {return Stream.of(values()).filter(bean - bean.description.equals(description)).findAny().orElse(UNKNOWN);}}
4、导出
/*** 设置响应结果** param response 响应结果对象* param rawFileName 文件名* throws UnsupportedEncodingException 不支持编码异常*/
private void setExcelResponseProp(HttpServletResponse response, String rawFileName) throws UnsupportedEncodingException {//设置内容类型response.setContentType(application/vnd.vnd.ms-excel);//设置编码格式response.setCharacterEncoding(utf-8);//设置导出文件名称避免乱码String fileName URLEncoder.encode(rawFileName.concat(.xlsx), UTF-8);// 设置响应头response.setHeader(Content-disposition, attachment;filename*utf-8 fileName);
}private Date getBirthday(int year, int month, int day){Calendar calendar Calendar.getInstance();calendar.set(year, month, day);return calendar.getTime();
}/*** 导出数据* */
GetMapping(/export/user)
public void exportUserExcel(HttpServletResponse response) throws IOException {OutputStream outputStream response.getOutputStream();try {this.setExcelResponseProp(response, 用户列表);// 模拟根据条件在数据库查询数据ListUserDO userList new ArrayList();for(int i 0;i 30;i){UserDO userDO new UserDO();userDO.setBirthday(getBirthday(2001,1,i));userDO.setGender(1);userDO.setHeight(Double.valueOf(i));userDO.setId(Long.valueOf(i));userDO.setPhone(138i);userDO.setNickname(yuanhaoz);userDO.setPassword(5849i);userDO.setUsername(monkyi);userList.add(userDO);}//这个实现方式非常简单直接使用EasyExcel的write方法将查询到的数据进行处理以流的形式写出即可EasyExcel.write(outputStream,UserDO.class)//对应的导出实体类.excelType(ExcelTypeEnum.XLSX)//excel文件类型包括CSV、XLS、XLSX.sheet(用户列表)//导出sheet页名称.doWrite(userList); //查询获取的数据集合ListT转成excel} catch (IOException e) {throw new RuntimeException(e);}finally {outputStream.flush();outputStream.close();}
}5、多sheet导出
/*** 多sheet导出数据* */
GetMapping(/manySheet)
public void exportManySheet(HttpServletResponse response)throws IOException{OutputStream outputStreamresponse.getOutputStream();ExcelWriter writer EasyExcel.write(outputStream, UserDO.class).excelType(ExcelTypeEnum.XLSX).build();try {this.setExcelResponseProp(response, 用户列表);// 模拟根据条件在数据库分页查询数据for(int j 1;j 5;j){ListUserDO userList new ArrayList();for(int i 0;i 30;i){UserDO userDO new UserDO();userDO.setBirthday(getBirthday(2001,1,i));userDO.setGender(1);userDO.setHeight(Double.valueOf(i));userDO.setId(Long.valueOf(i));userDO.setPhone(138i);userDO.setNickname(yuanhaozi);userDO.setPassword(5849i);userDO.setUsername(monkyi);userList.add(userDO);System.out.println(i);}//创建新的sheet页WriteSheet writeSheet EasyExcel.writerSheet(用户信息 j).build();//将list集合中的对象写到对应的sheet中去writer.write(userList,writeSheet);}} catch (IOException e) {throw new RuntimeException(e);//给提示todo}finally {writer.finish();outputStream.flush();outputStream.close();}
}6、导入
6.1、UserListener
/*** 自定义监听器对下载的excel中的数据进行校验* */
public class UserListener extends AnalysisEventListener {ListString names new ArrayList();/*** 每解析一行回调该方法** param data* param context*/Overridepublic void invoke(Object data, AnalysisContext context) {//校验名称String name ((UserDO) data).getUsername();if (StrUtil.isBlank(name)) {throw new RuntimeException(String.format(第%s行名称为空请核实, context.readRowHolder().getRowIndex() 1));}if (names.contains(name)) {throw new RuntimeException(String.format(第%s行名称已重复请核实, context.readRowHolder().getRowIndex() 1));} else {names.add(name);}}/*** 出现异常回调** param exception* param context* throws Exception*/Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {if (exception instanceof ExcelDataConvertException) {/**从0开始计算*/Integer columnIndex ((ExcelDataConvertException) exception).getColumnIndex() 1;Integer rowIndex ((ExcelDataConvertException) exception).getRowIndex() 1;String message 第 rowIndex 行第 columnIndex 列 数据格式有误请核实;throw new RuntimeException(message);} else if (exception instanceof RuntimeException) {throw exception;} else {super.onException(exception, context);}}/*** 解析完,全部回调** param context*/Overridepublic void doAfterAllAnalysed(AnalysisContext context) {//解析完,全部回调逻辑实现names.clear();}
}
6.2、ImportData
/*** 导入数据* */
PostMapping(value /importData)
public void ImportData(MultipartFile file){try {//获取文件的输入流InputStream inputStream file.getInputStream();ListUserDO list EasyExcel.read(inputStream) //调用read方法//注册自定义监听器字段校验可以在监听器内实现.registerReadListener(new UserListener()).head(UserDO.class) //对应导入的实体类.sheet(0) //导入数据的sheet页编号0代表第一个sheet页如果不填则会导入所有sheet页的数据.headRowNumber(1) //列表头行数1代表列表头有1行第二行开始为数据行.doReadSync(); //开始读Excel返回一个ListT集合继续后续入库操作//模拟导入数据库操作for (UserDO userDO : list){System.out.println(userDO.toString());}} catch (IOException exception){throw new RuntimeException(exception);}
}