• EasyExcel的使用


    官网:EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel (alibaba.com)

    依赖

    1. <dependency>
    2. <groupId>com.alibabagroupId>
    3. <artifactId>easyexcelartifactId>
    4. <version>3.1.1version>
    5. dependency>

    WEB中的使用

    首先:写个模板类

    1. package com.example.entity;
    2. import com.alibaba.excel.annotation.ExcelIgnore;
    3. import com.alibaba.excel.annotation.ExcelProperty;
    4. import com.baomidou.mybatisplus.annotation.*;
    5. import io.swagger.annotations.ApiModel;
    6. import io.swagger.annotations.ApiModelProperty;
    7. import lombok.Data;
    8. import java.io.Serializable;
    9. import java.time.LocalDateTime;
    10. /**
    11. * @TableName t_company
    12. */
    13. @TableName(value = "t_company")
    14. @Data
    15. @ApiModel("企业实体类")
    16. public class TCompany implements Serializable {
    17. /**
    18. * 主键
    19. */
    20. @TableId(value = "id", type = IdType.AUTO)
    21. @ApiModelProperty("主键")
    22. @ExcelIgnore
    23. private Integer id;
    24. /**
    25. * 用户名
    26. */
    27. @TableField(value = "user_name")
    28. @ApiModelProperty("企业用户名")
    29. @ExcelProperty("企业用户名")
    30. private String userName;
    31. /**
    32. * 登录密码
    33. */
    34. @TableField(value = "password")
    35. @ApiModelProperty("登陆密码")
    36. @ExcelIgnore
    37. private String password;
    38. /**
    39. * 企业名
    40. */
    41. @TableField(value = "name")
    42. @ApiModelProperty("企业真实名")
    43. @ExcelProperty("企业真实名")
    44. private String name;
    45. /**
    46. * 工商注册号
    47. */
    48. @TableField(value = "gszch")
    49. @ApiModelProperty("工商注册号")
    50. @ExcelIgnore
    51. private String gszch;
    52. /**
    53. * 营业执照
    54. */
    55. @TableField(value = "yyzz")
    56. @ApiModelProperty("营业执照")
    57. @ExcelIgnore
    58. private String yyzz;
    59. /**
    60. * 公司图标
    61. */
    62. @TableField(value = "img")
    63. @ApiModelProperty("公司图标")
    64. @ExcelIgnore
    65. private String img;
    66. /**
    67. * 公司规模
    68. */
    69. @TableField(value = "gsgm")
    70. @ApiModelProperty("公司规模")
    71. @ExcelProperty("公司规模")
    72. private String gsgm;
    73. /**
    74. * 公司行业
    75. */
    76. @TableField(value = "gshy")
    77. @ApiModelProperty("公司行业")
    78. @ExcelProperty("公司行业")
    79. private String gshy;
    80. /**
    81. * 联系人
    82. */
    83. @TableField(value = "contact")
    84. @ApiModelProperty("联系人")
    85. @ExcelProperty("联系人")
    86. private String contact;
    87. /**
    88. * 联系电话
    89. */
    90. @TableField(value = "phone")
    91. @ApiModelProperty("联系电话")
    92. @ExcelProperty("联系电话")
    93. private String phone;
    94. /**
    95. * 公司介绍
    96. */
    97. @TableField(value = "company_desc")
    98. @ApiModelProperty("公司介绍")
    99. @ExcelProperty("公司介绍")
    100. private String companyDesc;
    101. /**
    102. * 公司地址
    103. */
    104. @TableField(value = "address")
    105. @ApiModelProperty("公司地址")
    106. @ExcelProperty("公司地址")
    107. private String address;
    108. /**
    109. * 审核状态
    110. */
    111. @TableField(value = "audit_status")
    112. @ApiModelProperty("审核状态")
    113. @ExcelIgnore
    114. private Integer auditStatus;
    115. /**
    116. * 注册时间
    117. */
    118. @TableField(value = "create_time", fill = FieldFill.INSERT)
    119. @ApiModelProperty("注册时间")
    120. @ExcelIgnore
    121. private LocalDateTime createTime;
    122. /**
    123. * 更新时间
    124. */
    125. @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    126. @ApiModelProperty("更新时间")
    127. @ExcelIgnore
    128. private LocalDateTime updateTime;
    129. @TableField(exist = false)
    130. private static final long serialVersionUID = 1L;
    131. }

    最好使用注解,会自动对应我们的数据

    读操作:

    这里输入的参数讲解一下下,file.getInputStream(), 是前端上传的一个临时文件,我们获取他的一个输入流,TManger.class,是我们的一个实体类对象 

    new myListener(companyServiice))是我们的一个监听器,传递了一个service进去,可以看监听器的代码,传进去的目的就是,监听器里直接调用service的存储数据库操作

    .sheet(),是模板名称,不是文件名称

    .doRead();读

    1. /**
    2. * 文件上传
    3. *

    4. * 1. 创建excel对应的实体对象 参照{@link UploadData}
    5. *

    6. * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
    7. *

    8. * 3. 直接读即可
    9. */
    10. @PostMapping("upload")
    11. @ResponseBody
    12. public String upload(MultipartFile file) throws IOException {
    13. EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener(uploadDAO)).sheet().doRead();
    14. return "success";


    监听器:

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

    操作读

    1. /**
    2. * 文件上传
    3. *

    4. * 1. 创建excel对应的实体对象 参照{@link UploadData}
    5. *

    6. * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
    7. *

    8. * 3. 直接读即可
    9. */
    10. @PostMapping("upload")
    11. @ResponseBody
    12. public String upload(MultipartFile file) throws IOException {
    13. EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener(uploadDAO)).sheet().doRead();
    14. return "success";
    15. }

    监听器的异常处理:

    1. /**
    2. * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
    3. *
    4. * @param exception
    5. * @param context
    6. * @throws Exception
    7. */
    8. @Override
    9. public void onException(Exception exception, AnalysisContext context) {
    10. log.error("解析失败,但是继续解析下一行:{}", exception.getMessage());
    11. // 如果是某一个单元格的转换异常 能获取到具体行号
    12. // 如果要获取头的信息 配合invokeHeadMap使用
    13. if (exception instanceof ExcelDataConvertException) {
    14. ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
    15. log.error("第{}行,第{}列解析异常,数据为:{}", excelDataConvertException.getRowIndex(),
    16. excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData());
    17. }
    18. }

    这里的意思,应该是说,额,当一行数据解释失败的话,会打印出第几行解析失败,但是会继续解析,如果我们在方法里去抛出异常,就会停止解析

     看到了吗,他的默认方法时直接抛出异常,我们重写,就不抛出异常,这样他就一直读了

    写操作

    1. /**
    2. * 文件下载(失败了会返回一个有部分数据的Excel)
    3. *

    4. * 1. 创建excel对应的实体对象 参照{@link DownloadData}
    5. *

    6. * 2. 设置返回的 参数
    7. *

    8. * 3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
    9. */
    10. @GetMapping("download")
    11. public void download(HttpServletResponse response) throws IOException {
    12. // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
    13. response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    14. response.setCharacterEncoding("utf-8");
    15. // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
    16. String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
    17. response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
    18. EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
    19. }

    这个前面都时一些协议设置啥的,那个”测试“,时生成的文件名,还有最后的写操作,其他不关我们事

    失败情况:

    1. /**
    2. * 文件下载并且失败的时候返回json(默认失败了会返回一个有部分数据的Excel)
    3. *
    4. * @since 2.1.1
    5. */
    6. @GetMapping("downloadFailedUsingJson")
    7. public void downloadFailedUsingJson(HttpServletResponse response) throws IOException {
    8. // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
    9. try {
    10. response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    11. response.setCharacterEncoding("utf-8");
    12. // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
    13. String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
    14. response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
    15. // 这里需要设置不关闭流
    16. EasyExcel.write(response.getOutputStream(), DownloadData.class).autoCloseStream(Boolean.FALSE).sheet("模板")
    17. .doWrite(data());
    18. } catch (Exception e) {
    19. // 重置response
    20. response.reset();
    21. response.setContentType("application/json");
    22. response.setCharacterEncoding("utf-8");
    23. Map map = MapUtils.newHashMap();
    24. map.put("status", "failure");
    25. map.put("message", "下载文件失败" + e.getMessage());
    26. response.getWriter().println(JSON.toJSONString(map));
    27. }
    28. }

    看的懂吗,翻译一下,就是说当遇到解析不了的数据时,就会抛出异常,然后我们可以捕获这个异常,给他处理方式就是,在输出的Excel尾部加上Sorry,解析失败了。但是上面成功解析的还是会输出的

    以上没有测试,不想改我的代码,摆烂,但是,我感觉我看文档理解到的就是我要说的,然后这些代码都是直接官网复制的,哈哈

  • 相关阅读:
    【编程题 】HJ64 MP3光标位置(详细注释 易懂)
    【数据结构与算法】树、二叉树的概念及结构(详解)
    Golang 基础三
    【Go】单例模式与Once源码
    证书过期问题: https://registry.npm.taobao.org npm ERR! code CERT_HAS_EXPIRED npm ERR
    盲埋孔PCB叠孔设计的利与弊
    数学建模的初阶-快速上手
    小黑星巴克冰镇浓缩leetcode之旅:21. 合并两个有序链表
    【无标题】
    sklearn快速入门教程:处理连续型特征
  • 原文地址:https://blog.csdn.net/qq_33879443/article/details/126970261