分享

java使用 easyexcel 实现Excel 批量导入导出

 wwq图书世界 2019-11-18

本章提供了java使用阿里的easyexcel实现Excel导入,导出示例,还有网络下载的方法。

模板大家可以随意制作,本例中使用模板表头及数据已经截图,以供参考。

easyexcel背景:

Java解析,生成Excel比较有名的框架有Apache poi,jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版的Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大.easyexcel重写了POI对07版的Excel的解析,能够原本一个3M的Excel的用POI sax依然需要100M左右内存降低到KB级别,并且再大的Excel中不会出现内存溢出,03版依赖POI的萨克斯模式。在上层做了模型转换的封装,让使用者更加简单方便。

优缺点比较

easyexcel在解析耗时上比poiuserModel模式弱了一些主要原因是我内部采用了反射做模型字段映射,中间我也加了缓存,但感觉这点差距可以接受的但在内存消耗上差别就比较明显了,easye userxodel就不一大了,简直就要爆掉了。想想一个excel解析200M,同时有20个人再用估计一台机器就挂了。

本例中,工具类整合了easyexcel的导入导出,对导入的数据操作在监听类中实现,在这里可以做一些自己的业务逻辑,这也是使用easyexcel的一个原因,可以更加清晰的去关注业务逻辑。

1.准备:d:\\ 2007.xlsx

内容如下:

2.添加依赖(建议去maven仓库搜索easyexcel下载最新的依赖)

  1. <dependency>
  2. <groupId>com.alibaba</groupId>
  3. <artifactId>easyexcel</artifactId>
  4. <version>1.1.2-beat1</version>
  5. </dependency>

3.添加Excel的映射实体

  1. public class ExcelEntity extends BaseRowModel {
  2. @ExcelProperty(index = 0 , value = "工号")
  3. private String staff_code;
  4. @ExcelProperty(index = 1 , value = "姓名")
  5. private String name;
  6. @ExcelProperty(index = 2 , value = "性别")
  7. private String sex;
  8. @ExcelProperty(index = 3 , value = "联系电话")
  9. private String tel;
  10. @ExcelProperty(index = 4 , value = "邮箱")
  11. private String email;
  12. @ExcelProperty(index = 5 , value = "微信号")
  13. private String weixin;
  14. @ExcelProperty(index = 6 , value = "部门")
  15. private Integer department_id;
  16. @ExcelProperty(index = 7 , value = "职位")
  17. private Integer position_id;
  18. public String getStaff_code() {
  19. return staff_code;
  20. }
  21. public void setStaff_code(String staff_code) {
  22. this.staff_code = staff_code;
  23. }
  24. public String getName() {
  25. return name;
  26. }
  27. public void setName(String name) {
  28. this.name = name;
  29. }
  30. public String getSex() {
  31. return sex;
  32. }
  33. public void setSex(String sex) {
  34. this.sex = sex;
  35. }
  36. public String getTel() {
  37. return tel;
  38. }
  39. public void setTel(String tel) {
  40. this.tel = tel;
  41. }
  42. public String getEmail() {
  43. return email;
  44. }
  45. public void setEmail(String email) {
  46. this.email = email;
  47. }
  48. public String getWeixin() {
  49. return weixin;
  50. }
  51. public void setWeixin(String weixin) {
  52. this.weixin = weixin;
  53. }
  54. public Integer getDepartment_id() {
  55. return department_id;
  56. }
  57. public void setDepartment_id(Integer department_id) {
  58. this.department_id = department_id;
  59. }
  60. public Integer getPosition_id() {
  61. return position_id;
  62. }
  63. public void setPosition_id(Integer position_id) {
  64. this.position_id = position_id;
  65. }
  66. @Override
  67. public String toString() {
  68. return "ExcelEntity{" +
  69. "staff_code='" + staff_code + '\'' +
  70. ", name='" + name + '\'' +
  71. ", sex='" + sex + '\'' +
  72. ", tel='" + tel + '\'' +
  73. ", email='" + email + '\'' +
  74. ", weixin='" + weixin + '\'' +
  75. ", department_id=" + department_id +
  76. ", position_id=" + position_id +
  77. '}';
  78. }
  79. }

4.添加导入数据监听类

  1. import com.alibaba.excel.context.AnalysisContext;
  2. import com.alibaba.excel.event.AnalysisEventListener;
  3. import com.zdhs.cms.common.excelUtils.entity.ExcelEntity;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. /** 解析监听器,
  7. * 每解析一行会回调invoke()方法。
  8. * 整个excel解析结束会执行doAfterAllAnalysed()方法
  9. *
  10. * 下面只是我写的一个样例而已,可以根据自己的逻辑修改该类。
  11. */
  12. public class ExcelListener extends AnalysisEventListener {
  13. //自定义用于暂时存储data。
  14. //可以通过实例获取该值
  15. private List<Object> datas = new ArrayList<Object>();
  16. public void invoke(Object object, AnalysisContext context) {
  17. System.out.println("当前行:"+context.getCurrentRowNum());
  18. System.out.println(object);
  19. datas.add(object);//数据存储到list,供批量处理,或后续自己业务逻辑处理。
  20. doSomething(object);//根据自己业务做处理
  21. }
  22. private void doSomething(Object object) {
  23. ExcelEntity excel = (ExcelEntity) object;
  24. //1、入库调用接口
  25. }
  26. public void doAfterAllAnalysed(AnalysisContext context) {
  27. // datas.clear();//解析结束销毁不用的资源
  28. }
  29. public List<Object> getDatas() {
  30. return datas;
  31. }
  32. public void setDatas(List<Object> datas) {
  33. this.datas = datas;
  34. }
  35. }

5.编写导入导出工具类

  1. import com.alibaba.excel.ExcelReader;
  2. import com.alibaba.excel.ExcelWriter;
  3. import com.alibaba.excel.event.AnalysisEventListener;
  4. import com.alibaba.excel.metadata.BaseRowModel;
  5. import com.alibaba.excel.metadata.Sheet;
  6. import com.alibaba.excel.support.ExcelTypeEnum;
  7. import com.zdhs.cms.common.excelUtils.entity.ExcelEntity;
  8. import com.zdhs.cms.common.excelUtils.listen.ExcelListener;
  9. import java.io.*;
  10. import java.util.ArrayList;
  11. import java.util.List;
  12. public class ExcelUtils {
  13. /**
  14. * @param is 导入文件输入流
  15. * @param clazz Excel实体映射类
  16. * @return
  17. */
  18. public static Boolean readExcel(InputStream is, Class clazz){
  19. BufferedInputStream bis = null;
  20. try {
  21. bis = new BufferedInputStream(is);
  22. // 解析每行结果在listener中处理
  23. AnalysisEventListener listener = new ExcelListener();
  24. ExcelReader excelReader = EasyExcelFactory.getReader(bis, listener);
  25. excelReader.read(new Sheet(1, 1, clazz));
  26. } catch (Exception e) {
  27. e.printStackTrace();
  28. return false;
  29. } finally {
  30. if (bis != null) {
  31. try {
  32. bis.close();
  33. } catch (IOException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }
  38. return true;
  39. }
  40. /**
  41. *
  42. * @param os 文件输出流
  43. * @param clazz Excel实体映射类
  44. * @param data 导出数据
  45. * @return
  46. */
  47. public static Boolean writeExcel(OutputStream os, Class clazz, List<? extends BaseRowModel> data){
  48. BufferedOutputStream bos= null;
  49. try {
  50. bos = new BufferedOutputStream(os);
  51. ExcelWriter writer = new ExcelWriter(bos, ExcelTypeEnum.XLSX);
  52. //写第一个sheet, sheet1 数据全是List<String> 无模型映射关系
  53. Sheet sheet1 = new Sheet(1, 0,clazz);
  54. writer.write(data, sheet1);
  55. writer.finish();
  56. } catch (Exception e) {
  57. e.printStackTrace();
  58. return false;
  59. } finally {
  60. if (bos != null) {
  61. try {
  62. bos.close();
  63. } catch (IOException e) {
  64. e.printStackTrace();
  65. }
  66. }
  67. }
  68. return true;
  69. }
  70. public static void main(String[] args) {
  71. //1.读Excel
  72. FileInputStream fis = null;
  73. try {
  74. fis = new FileInputStream("D:\\2007.xlsx");
  75. Boolean flag = ExcelUtils.readExcel(fis, ExcelEntity.class);
  76. System.out.println("导入是否成功:"+flag);
  77. } catch (FileNotFoundException e) {
  78. e.printStackTrace();
  79. }finally {
  80. if (fis != null){
  81. try {
  82. fis.close();
  83. } catch (IOException e) {
  84. e.printStackTrace();
  85. }
  86. }
  87. }
  88. //2.读Excel
  89. FileOutputStream fos = null;
  90. try {
  91. fos = new FileOutputStream("D:\\export.xlsx");
  92. //FileOutputStream fos, Class clazz, List<? extends BaseRowModel> data
  93. List<ExcelEntity> list = new ArrayList<>();
  94. for (int i = 0; i < 5; i++){
  95. ExcelEntity excelEntity = new ExcelEntity();
  96. excelEntity.setName("我是名字"+i);
  97. list.add(excelEntity);
  98. }
  99. Boolean flag = ExcelUtils.writeExcel(fos,ExcelEntity.class,list);
  100. System.out.println("导出是否成功:"+flag);
  101. } catch (FileNotFoundException e) {
  102. e.printStackTrace();
  103. }finally {
  104. if (fos != null){
  105. try {
  106. fos.close();
  107. } catch (IOException e) {
  108. e.printStackTrace();
  109. }
  110. }
  111. }
  112. }
  113. }

6.大功告成!在ExcelUtils中运行主方法,简单的导入导出就已经完成了!

7.运行结果截图:

    7.1导入数据控制台打印:

    7.2导出数据添加姓名+循环次数:

另外,阿里easyexcel还提供了复杂格式的表头使用,和表格样式,有需要的小伙伴可以去github上一睹真容。

附:阿里巴巴开源easyexcel github地址:https//github.com/alibaba/easyexcel

 

8.最后多一嘴,文件导入,导出,下载模板的时候,Controller层的写法也加上来,记录一下。

  1. /**
  2. * @Auther : guojianmin
  3. * @Date : 2019/5/24 17:03
  4. * @Description : TODO用一句话描述此类的作用
  5. */
  6. @Api(tags = "ExcelDownloadController", description = "Excel 导入下载模板,导出 相关接口")
  7. @RestController
  8. @RequestMapping("/excel")
  9. public class ExcelDownloadController {
  10. private static final Logger log = LoggerFactory.getLogger(ExcelDownloadController.class);
  11. @Resource
  12. StaffService staffService;
  13. /**
  14. * 单个文件上传
  15. * @param file
  16. * @return
  17. */
  18. @ApiOperation(value="接口说明",httpMethod="POST",notes="单个文件上传")
  19. @RequestMapping(value = "/upload")
  20. public ResponseMsg upload(@RequestParam("file") MultipartFile file) {
  21. ResponseMsg msg = new ResponseMsg();
  22. try {
  23. if (file.isEmpty()) {
  24. msg.setMsg("文件为空");
  25. msg.setResult(false);
  26. return msg;
  27. }
  28. // 获取文件名
  29. String fileName = file.getOriginalFilename();
  30. log.info("上传的文件名为:" + fileName);
  31. // 获取文件的后缀名
  32. String suffixName = fileName.substring(fileName.lastIndexOf("."));
  33. log.info("文件的后缀名为:" + suffixName);
  34. //创建一个临时文件,用于暂时存放
  35. File tmpFile = File.createTempFile("tmp", null);
  36. //将MultipartFile 转换为 File 临时文件
  37. file.transferTo(tmpFile);
  38. //将临时文件转为输入流
  39. InputStream inputStream = new FileInputStream(tmpFile);
  40. ExcelUtils.readExcel(inputStream, ExcelModel.class);
  41. msg.setResult(true);
  42. msg.setMsg("上传成功");
  43. //上传完成 删除临时文件
  44. tmpFile.delete();
  45. return msg;
  46. } catch (IllegalStateException e) {
  47. e.printStackTrace();
  48. } catch (IOException e) {
  49. e.printStackTrace();
  50. }
  51. msg.setResult(false);
  52. msg.setMsg("上传失败");
  53. return msg;
  54. }
  55. /**
  56. * 下载模板,用于填写导入数据
  57. * @param request
  58. * @param response
  59. */
  60. @ApiOperation(value="接口说明",httpMethod="POST",notes="下载模板,用于填写导入数据")
  61. @RequestMapping("/downloadExcel")
  62. public void cooperation(HttpServletRequest request, HttpServletResponse response) {
  63. ServletOutputStream out = null;
  64. try {
  65. out = response.getOutputStream();
  66. response.setContentType("multipart/form-data");
  67. response.setCharacterEncoding("utf-8");
  68. String fileName = "导入模板";
  69. response.setHeader("Content-disposition", "attachment;filename="+ URLEncoder.encode(fileName,"UTF-8")+".xlsx");
  70. ExcelUtils.writeExcel(out,ExcelModel.class,null);
  71. out.flush();
  72. } catch (IOException e) {
  73. e.printStackTrace();
  74. }finally {
  75. if (out != null){
  76. try {
  77. out.close();
  78. } catch (IOException e) {
  79. e.printStackTrace();
  80. }
  81. }
  82. }
  83. }
  84. /**
  85. * 导出数据文件
  86. * @param request
  87. * @param response
  88. */
  89. @ApiOperation(value="接口说明",httpMethod="POST",notes="导出数据文件")
  90. @RequestMapping("/downloadExcelData")
  91. public void cooperationData(HttpServletRequest request, HttpServletResponse response) {
  92. ServletOutputStream out = null;
  93. try {
  94. out = response.getOutputStream();
  95. response.setContentType("multipart/form-data");
  96. response.setCharacterEncoding("utf-8");
  97. String fileName = "导出明细";
  98. response.setHeader("Content-disposition", "attachment;filename="+ URLEncoder.encode(fileName,"UTF-8")+".xlsx");
  99. //List<ExcelModel> data = 此处为 数据接口 返回一个list ;
  100. //把数据明细放在list data中
  101. System.out.println("把数据明细放在list data中:请完善查询数据接口调用,并把查询结果写入list data中");
  102. Boolean flag = ExcelUtils.writeExcel(out, ExcelModel.class, data);
  103. System.out.println("导出是否成功:"+flag);
  104. out.flush();
  105. } catch (IOException e) {
  106. e.printStackTrace();
  107. }finally {
  108. if (out != null){
  109. try {
  110. out.close();
  111. } catch (IOException e) {
  112. e.printStackTrace();
  113. }
  114. }
  115. }
  116. }
  117. }

9.最后,真的是最后,顺便了解一下Java 中File类的createNewFile()与createTempFile(), delete和deleteOnExit区别

感谢博主:https://www.cnblogs.com/kungfupanda/p/9472137.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多