当前位置:   article > 正文

阿里开源的EasyExcel(导入、导出)_easyexcel是不是不能导入了

easyexcel是不是不能导入了

一、说明:

众所周知,Excel文件分为03版本excel和07版本excel文件

03版最多容量为65535*256,而07版单张sheet为1048576*16384,总容量无限制

03版的后缀名为.xls,07版的后缀是.xlsx

 二、对Excel文件处理

在Java领域中,对excel文件进行解析、生成比较闻名的框架是Apache poi和阿里的EasyExcel。但俩者有显著的区别。

POI技术在解析Excel文件时,是一次性将表里的数据加载到内存中,这很可能会导致内存溢出的问题,尤其是当excel的存在大数据量时,就很大可能会超出可用内存的内存限制。

所以POI技术非常消耗内存。

EasyExcel在解析文件时,是从磁盘上一行一行的进行读取数据,并通过设置监听器(观察者的模式)进行通知。因此,大大减少了占用内存。

三、使用EasyExcel

在了解的俩者区别后,我选择了使用EasyExcel来对excel文件进行处理

3.1导入依赖

在jdk版本为1.8及1.8以上时,导入EasyExcel的版本最好为3.xx的版本。

  1. //通用版本
  2. <dependency>
  3. <groupId>com.alibaba</groupId>
  4. <artifactId>easyexcel</artifactId>
  5. <version>3.1.4</version>
  6. </dependency>
  7. //若依赖中存在导入或不使用Slf4j依赖则需要将其中封装的取消导入
  8. <dependency>
  9. <groupId>com.alibaba</groupId>
  10. <artifactId>easyexcel</artifactId>
  11. <version>3.1.4</version>
  12. <exclusions>
  13. <exclusion>
  14. <groupId>org.slf4j</groupId>
  15. <artifactId>slf4j-api</artifactId>
  16. </exclusion>
  17. </exclusions>
  18. </dependency>

3.2实体

  1. /**
  2. * 用户ID
  3. */
  4. @TableId(type = IdType.AUTO)
  5. @ExcelIgnore
  6. private Long userId;
  7. /**
  8. * 用户名
  9. */
  10. @ExcelProperty("用户名")
  11. private String username;
  12. /**
  13. * 密码
  14. */
  15. @ExcelIgnore
  16. private String password;
  17. /**
  18. * 性别
  19. */
  20. @ExcelProperty(value = "性别",converter = SexUtil.class)
  21. private int gender;
  22. /**
  23. * 手机号
  24. */
  25. @ExcelProperty("手机号")
  26. /**
  27. * 邮箱
  28. */
  29. @ExcelProperty("邮箱")
  30. private String email;
  31. /**
  32. * 真实姓名
  33. */
  34. @ExcelProperty("姓名")
  35. private String realName;
  36. /**
  37. * 状态 0:禁用 1:正常
  38. */
  39. @ExcelIgnore
  40. private Integer status;
  41. /**
  42. * 创建时间
  43. */
  44. // @ExcelIgnore
  45. @DateTimeFormat(value = "yyyy-MM-dd")
  46. @ExcelProperty(value = "创建时间",converter = DateConverter.class )
  47. private Date createTime;
  48. @TableLogic(value = "0", delval = "1")
  49. @ExcelIgnore
  50. private int del;

对于导入导出的显示在excel字段 可以添加注解:@ExcelProperty、@ExcelIgnore

前者是需要将字段进行处理,后者是不需要显示在excel则添加。如果一个属性什么注解都没有,则将显示原本的如:属性为:email,则在excel也显示 email。添加了@ExcelProperty("邮箱") 则显示 邮箱。

3.3自定义转换类

 在进行对性别属性的数据库存储时,我采用了存储数字(0:女、1:男)这种方式存储的原因在此我就不多说了,懂的都懂。那为什么我要在此说明这个属性呢?因为在进行文件的导入导出时,总不能对性别进行导入1、0或者导出1、0供用户查看吧?所以在此仍需写一个处理性别数据转换的类。在EasyExcel提供了Converter接口。在处理文件的导入导出时,此接口提供了俩个方法:convertToJavaData和convertToExcelData。具体细看如下

  1. import com.alibaba.excel.converters.Converter;
  2. import com.alibaba.excel.metadata.GlobalConfiguration;
  3. import com.alibaba.excel.metadata.data.ReadCellData;
  4. import com.alibaba.excel.metadata.data.WriteCellData;
  5. import com.alibaba.excel.metadata.property.ExcelContentProperty;
  6. public class SexUtil implements Converter<Integer> {
  7. /**
  8. * 导入时,对数据的男、女进行转换
  9. * @param cellData
  10. * @param contentProperty
  11. * @param globalConfiguration
  12. * @return
  13. * @throws Exception
  14. */
  15. @Override
  16. public Integer convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
  17. String value = cellData.getStringValue();
  18. switch (value){
  19. case "男":
  20. return 1;
  21. case "女":
  22. return 0;
  23. default:
  24. return -1;
  25. }
  26. }
  27. /**
  28. * 导出时 对数据的1、0进行转换
  29. * @param value
  30. * @param contentProperty
  31. * @param globalConfiguration
  32. * @return
  33. * @throws Exception
  34. */
  35. @Override
  36. public WriteCellData<?> convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
  37. switch (value){
  38. case 1:
  39. return new WriteCellData<>("男");
  40. case 0:
  41. return new WriteCellData<>("女");
  42. default:
  43. return new WriteCellData<>("未知");
  44. }
  45. }
  46. }

 那怎么使用这个转换类?麻烦细看实体类中的性别字段

3.4IDEA中的导入实现

controller类

  1. /**
  2. * 文件上传
  3. * @param file
  4. * @return
  5. * @throws IOException
  6. */
  7. @PostMapping("/upload")
  8. @ResponseBody
  9. public R upload(MultipartFile file) throws IOException {
  10. EasyExcel.read(file.getInputStream(), EmpEntity.class, new
  11. UploadEmpListener(empService)).sheet().doRead();
  12. return R.ok();
  13. }

根据EasyExcel官网提供信息:使用read方法  并且设置一个监听类。

EasyExcel.read(file.getInputStream(), EmpEntity.class, new         
                        UploadEmpListener(empService)).sheet().doRead();

至于参数传service还是dao就看具体的用法

 监听类

  1. package com.wedu.modules.emp.listener;
  2. import com.alibaba.excel.context.AnalysisContext;
  3. import com.alibaba.excel.read.listener.ReadListener;
  4. import com.alibaba.excel.util.ListUtils;
  5. import com.alibaba.fastjson.JSON;
  6. import com.wedu.modules.emp.entity.EmpEntity;
  7. import com.wedu.modules.emp.service.EmpService;
  8. import lombok.extern.slf4j.Slf4j;
  9. import java.util.List;
  10. @Slf4j
  11. public class UploadResignListener implements ReadListener<EmpEntity> {
  12. /**
  13. * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
  14. */
  15. private static final int BATCH_COUNT = 100;
  16. /**
  17. * 缓存的数据
  18. */
  19. private List<EmpEntity> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
  20. /**
  21. * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
  22. */
  23. private EmpEntity empService;
  24. /**
  25. * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
  26. *
  27. * @param empService
  28. */
  29. public UploadResignListener(EmpEntity empService) {
  30. this.empService= empService;
  31. }
  32. /**
  33. * 这个每一条数据解析都会来调用
  34. *
  35. * @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
  36. * @param context
  37. */
  38. @Override
  39. public void invoke(ResignEntity data, AnalysisContext context) {
  40. log.info("解析到一条数据:{}", JSON.toJSONString(data));
  41. cachedDataList.add(data);
  42. // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
  43. if (cachedDataList.size() >= BATCH_COUNT) {
  44. saveData();
  45. log.info("准备清理!");
  46. // 存储完成清理 list
  47. cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
  48. }
  49. }
  50. /**
  51. * 所有数据解析完成了 都会来调用
  52. *
  53. * @param context
  54. */
  55. @Override
  56. public void doAfterAllAnalysed(AnalysisContext context) {
  57. // 这里也要保存数据,确保最后遗留的数据也存储到数据库
  58. saveData();
  59. log.info("所有数据解析完成!");
  60. }
  61. /**
  62. * 加上存储数据库
  63. */
  64. private void saveData() {
  65. log.info("{}条数据,开始存储数据库!", cachedDataList.size());
  66. empService.saveBatch(cachedDataList);
  67. log.info("存储数据库成功!");
  68. }
  69. }

我使用的是SpringBoot+Mybatis-plus 所以我直接使用了mybatis-plus提供的批量插入方法

 3.5Vue的导入实现

我使用的Element-UI提供的组件

  1. <el-upload
  2. action="http://localhost:8080/emp/info/upload"
  3. :headers="tokenInfo"
  4. style="display: inline-block"
  5. :show-file-list="true"
  6. :before-upload="headUpload"
  7. :on-success="handleExcelImportSuccess"
  8. name="file">
  9. <el-button type="primary" style="margin: 10px " >
  10. <template #icon>
  11. <el-icon><Upload /></el-icon>
  12. </template>
  13. 导入
  14. </el-button>
  15. </el-upload>

action:请求的路径

:headers 我使用了jwt令牌,携带了token往后端进行判断。看各位具体使用,不一定使用

:show-file-list="true" 为true时,则显示上传的文件

:before-upload="headUpload" 顾名思义是上传前的操作

:on-success="handleExcelImportSuccess"  则是成功后的操作

 具体的我们可去Element-UI官网查看更多的使用。接着我们看看上传前需要什么操作

  1. headUpload(file) {
  2. const isExcel1 = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
  3. const isExcel2 = file.type === 'application/vnd.ms-excel';
  4. const isLt10M = file.size / 1024 / 1024 < 10;
  5. const filexlsx =!(file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  6. const filexls = !(file.type === 'application/vnd.ms-excel');
  7. if(filexlsx && filexls) {
  8. this.$message.error('上传Excel文件只能是xlsx/xls 格式!');
  9. return false;
  10. }
  11. if (!isLt10M) {
  12. this.$message.error('上传Excel文件大小不能超过 10MB!');
  13. }
  14. return (isExcel1 || isExcel2) && isLt10M;
  15. }

先前我曾说明excel是有俩种版本,则分别对应了'application/vnd.ms-excel'、'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'

则在此方法中,我进行了上传前的判断,是否为这俩种excel中的其中一种,还有文件的大小是否超过10M

 然后就是上传后的处理,查看响应。由于后端我使用的是统一格式类进行返回。

  1. handleExcelImportSuccess(response,file){
  2. if(response.msg == 'success'){
  3. alert("导入成功")
  4. }
  5. }

3.6IDEA中的导出实现

 controller类

  1. @PostMapping("/down")
  2. public void create(@RequestBody Long[] userIds, HttpServletResponse response) throws IOException {
  3. List<SysUserEntity> list = empService.getDown(Arrays.asList(userIds));
  4. String fileName = "数据测试";
  5. ExcelUtils.createExcel(response,fileName,list,SysUserEntity.class);
  6. }

我是在前端选择要导出的数据,并只传回对应的id在到后端进行查询,查询在此就不展示了,相信对于各位看官都是轻松的事情。取到数据后,传到我自定义的工具类中。

工具类

  1. import com.alibaba.excel.EasyExcel;
  2. import com.alibaba.excel.support.ExcelTypeEnum;
  3. import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
  4. import com.alibaba.excel.write.metadata.style.WriteCellStyle;
  5. import com.alibaba.excel.write.metadata.style.WriteFont;
  6. import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
  7. import com.wedu.config.CustomCellWriteWidthConfig;
  8. import org.apache.poi.ss.usermodel.FillPatternType;
  9. import org.apache.poi.ss.usermodel.HorizontalAlignment;
  10. import org.apache.poi.ss.usermodel.IndexedColors;
  11. import org.apache.poi.ss.usermodel.VerticalAlignment;
  12. import javax.servlet.http.HttpServletResponse;
  13. import java.io.IOException;
  14. import java.net.URLEncoder;
  15. import java.util.List;
  16. public class ExcelUtils {
  17. public static <T> void createExcel(HttpServletResponse response, String fileName, List<T> list,Class<T> clazz) throws IOException {
  18. response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
  19. response.setCharacterEncoding("utf-8");
  20. fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+","%20");
  21. response.setHeader("Content-disposition", "attachment;filename=" + fileName+".xlsx");
  22. //定义ExcelWriterSheetBuilder
  23. ExcelWriterSheetBuilder excelWriterSheetBuilder = EasyExcel
  24. .write(response.getOutputStream())
  25. .head(clazz)
  26. .excelType(ExcelTypeEnum.XLSX)
  27. .registerWriteHandler(new CustomCellWriteWidthConfig())
  28. .sheet("sheet");
  29. //设置头样式
  30. WriteCellStyle headWriteCellStyle = new WriteCellStyle();
  31. WriteFont headWriteFont = new WriteFont();
  32. //设置表头字体
  33. headWriteFont.setFontName("宋体");
  34. //设置设置表头字体大小
  35. headWriteFont.setFontHeightInPoints((short) 13);
  36. //设置表头是否加粗
  37. headWriteFont.setBold(true);
  38. //填充到表头样式
  39. headWriteCellStyle.setWriteFont(headWriteFont);
  40. headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
  41. headWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
  42. headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
  43. //设置内容格式
  44. WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
  45. WriteFont contentWriteFont = new WriteFont();
  46. // 设置内容样式
  47. contentWriteFont.setFontName("宋体");
  48. contentWriteFont.setFontHeightInPoints((short) 12);
  49. contentWriteCellStyle.setWriteFont(contentWriteFont);
  50. HorizontalCellStyleStrategy horizontalCellStyleStrategy =
  51. new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
  52. //设计内容居中
  53. contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
  54. contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  55. //设置内容自动换行
  56. // contentWriteCellStyle.setWrapped(true);
  57. excelWriterSheetBuilder.registerWriteHandler(horizontalCellStyleStrategy);
  58. //调用doWrite方法
  59. excelWriterSheetBuilder.doWrite(list);
  60. }
  61. }

无需返回值,在此后端的导出就结束了。

 3.7Vue的导出实现

  1. down(){
  2. var userIds = this.dataListSelections.map(item => {
  3. return item.userId
  4. })
  5. this.$http({
  6. url: this.$http.adornUrl('/emp/info/down'),
  7. method: 'post',
  8. responseType: 'blob',
  9. data: this.$http.adornData(userIds, false)
  10. }).then(response => {
  11. // 创建一个 URL 对象,指向返回的二进制数据
  12. const url = window.URL.createObjectURL(new Blob([response.data]));
  13. // 创建一个 <a> 元素,设置其属性,模拟点击下载
  14. const link = document.createElement('a');
  15. link.href = url;
  16. link.setAttribute('download', '员工信息.xlsx'); // 设置下载文件的默认名称
  17. document.body.appendChild(link);
  18. link.click();
  19. // 清理创建的 URL 对象
  20. window.URL.revokeObjectURL(url);
  21. }).catch(error => {
  22. console.error('下载失败', error);
  23. });
  24. }

首先我们应当遍历我们选中的id。我将选中的id都进行存储到dataListSelections的数组中

在<el-table>标签的属性中@selection-change="selectionChangeHandle"定义选中方法

然后 在return 中 定义 dataListSelections: [] 数组

selectionChangeHandle (val) {

        this.dataListSelections = val

 }

这样就能实现将id存储到数组中

 导出时仍需对响应进行处理,处理的不是后端,因为后端没有返回值。而是处理导出的文件。

到此,导入导出就成功实现了。我不推荐各位只是cv工程,还是可以多看看官网提供的使用方法。若小弟存在错误的地方,各位也可以提出来一起学习!哈哈

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/机器思考机器/article/detail/61031
推荐阅读
相关标签
  

闽ICP备14008679号