Spring Boot 我随手封装了一个万能的 Excel 导出工具,传什么都能导出!

简介: Spring Boot 我随手封装了一个万能的 Excel 导出工具,传什么都能导出!

前言

如题,这个小玩意,就是不限制你查的是哪张表,用的是什么类。


我直接一把梭,嘎嘎给你一顿导出。


我知道,这是很多人都想过的, 至少我就收到很多人问过我这个类似的问题。


我也跟他们说了,但是他们就是不动手,其实真的很简单。


不动手怎么办? 我出手呗。


不多说开搞 。


正文

玩法很简单。


要实现的效果 :


类是不确定的 ,User ?Student ? District ? 不确定。


但是呢我们封装出来的函数,要足够支撑不同的类,我们自动去读取遍历list ,然后导出生成文件。


核心的思路是什么 ?


其实就还是利用csv文件的内容格式本质 ,看这两幅图 :

8e0f3db6583ff679a33b1104b1a3035a_f8024466d1e147d09b82268360bbf7d1.png


8e55c1bd845c0eac2bfc3aab8bd31045_a96d2a9dfef747488c07b97ffaf55166.png



我们要实现万能的类导出excel !!!

思路是什么 :


① 我们从不确定的类 的集合list 中,取出 里面的类。

反射一手,拿出里面的属性名, 做第一行表格行标题名称拼接。


②拼接内容

因为类不确定,那么我们就采取反射把类全部字段属性作为key丢到map里面,同时把值丢到value里面。


这样我们拼接内容的时候只需要根据map 嘎嘎一顿遍历拼接即可。


推荐一个开源免费的 Spring Boot 最全教程:


https://github.com/javastacks/spring-boot-best-practice


1.依赖


  org.apache.poi

  poi-ooxml

  3.15

  org.apache.poi

  poi-scratchpad

  3.15

  com.alibaba

  fastjson

  1.2.69

  commons-io

  commons-io

  2.5


2. 核心的工具类,函数我都封装好了


MyCsvFileUtil.java


import lombok.extern.slf4j.Slf4j;

import org.apache.commons.io.IOUtils;


import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.OutputStreamWriter;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import java.text.SimpleDateFormat;

import java.util.*;


/**

* @author JCccc

* @Remark 是我

*/

@Slf4j

public class MyCsvFileUtil {

   public static final String FILE_SUFFIX = ".csv";

   public static final String CSV_DELIMITER = ",";

   public static final String CSV_TAIL = "\r\n";

   protected static final String DATE_STR_FILE_NAME = "yyyyMMddHHmmssSSS";


   /**

    * 将字符串转成csv文件

    */

   public static void createCsvFile(String savePath, String contextStr) throws IOException {


       File file = new File(savePath);

       //创建文件

       file.createNewFile();

       //创建文件输出流

       FileOutputStream fileOutputStream = new FileOutputStream(file);

       //将指定字节写入此文件输出流

       fileOutputStream.write(contextStr.getBytes("gbk"));

       fileOutputStream.flush();

       fileOutputStream.close();

   }


   /**

    * 写文件

    *

    * @param fileName

    * @param content

    */

   public static void writeFile(String fileName, String content) {

       FileOutputStream fos = null;

       OutputStreamWriter writer = null;

       try {

           fos = new FileOutputStream(fileName, true);

           writer = new OutputStreamWriter(fos, "GBK");

           writer.write(content);

           writer.flush();

       } catch (Exception e) {

           log.error("写文件异常|{}", e);

       } finally {

           if (fos != null) {

               IOUtils.closeQuietly(fos);

           }

           if (writer != null) {

               IOUtils.closeQuietly(writer);

           }

       }

   }


   /**

    * 构建文件名称

    * @param dataList

    * @return

    */

   public static String buildCsvFileFileName(List dataList) {

       return dataList.get(0).getClass().getSimpleName() + new SimpleDateFormat(DATE_STR_FILE_NAME).format(new Date()) + FILE_SUFFIX;

   }


   /**

    * 构建excel 标题行名

    * @param dataList

    * @return

    */

   public static String buildCsvFileTableNames(List dataList) {

       Map map = toMap(dataList.get(0));

       StringBuilder tableNames = new StringBuilder();

       for (String key : map.keySet()) {

           tableNames.append(key).append(MyCsvFileUtil.CSV_DELIMITER);

       }

       return tableNames.append(MyCsvFileUtil.CSV_TAIL).toString();

   }


   /**

    * 构建excel内容

    * @param dataLists

    * @return

    */

   public static String buildCsvFileBodyMap(List dataLists) {

       //不管你传什么玩意,我都给你反射一手,搞成Map

       List> mapList = new ArrayList<>();

       for (Object o : dataLists) {

           mapList.add(toMap(o));

       }

       //然后利用csv格式,对着map嘎嘎一顿拼接数据

       StringBuilder lineBuilder = new StringBuilder();

       for (Map rowData : mapList) {

           for (String key : rowData.keySet()) {

               Object value = rowData.get(key);

               if (Objects.nonNull(value)) {

                   lineBuilder.append(value).append(MyCsvFileUtil.CSV_DELIMITER);

               } else {

                   lineBuilder.append("--").append(MyCsvFileUtil.CSV_DELIMITER);

               }

           }

           lineBuilder.append(MyCsvFileUtil.CSV_TAIL);

       }

       return lineBuilder.toString();

   }


   /**

    * 类转map

    * @param entity

    * @param

    * @return

    */

   public static Map toMap(T entity){

       Class bean = entity.getClass();

       Field[] fields = bean.getDeclaredFields();

       Map map = new HashMap<>(fields.length);

       for(Field field:fields){

           try {

               if(!"serialVersionUID".equals(field.getName())){

                   String methodName = "get"+field.getName().substring(0, 1).toUpperCase()+field.getName().substring(1);

                   Method method = bean.getDeclaredMethod(methodName);

                   Object fieldValue = method.invoke(entity);

                   map.put(field.getName(),fieldValue);

               }

           } catch (Exception e) {

               log.warn("toMap() Exception={}",e.getMessage());

           }

       }

       return map;

   }

}


代码注意点(各种小封装):


①类转map


54ba1fbadc7ca96b3fb8597331b9c363_c95c7a40addb44d08f4b7d7bbec933c3.png


② 反射转map 取字段属性名 拼接 标题


c56d86312607cbd9308b15b082195e8e_5364dcc697364fd889054f6387c50c99.png


③ 针对list<不确定类>转化成list,然后拼接excel内容


4cb63f68e54a28f9ffd1fb53fdee2464_29bdbaccdbc94e839a93e2bd579eb2d6.png


测试代码:


@RequestMapping("/createCsvFileJcTest")

public void createCsvFileJcTest() {

   //类不确定 随便怎么传都行

   List districts = districtService.queryByParentCodes(Arrays.asList("110100"));

   //存放地址&文件名

   String fileName = "D:\\mycsv\\"+MyCsvFileUtil.buildCsvFileFileName(districts);

   //创建表格行标题

   String tableNames = MyCsvFileUtil.buildCsvFileTableNames(districts);

   //创建文件

   MyCsvFileUtil.writeFile(fileName, tableNames);

   //写入数据

   String contentBody = MyCsvFileUtil.buildCsvFileBodyMap(districts);

   //调用方法生成

   MyCsvFileUtil.writeFile(fileName, contentBody);

}

72f946a87189b5404715f6dd6ae1e35d_c56f0ad9b1f944f0bbf9afc95d979e16.png


看看效果:

1ceed3d9b54937c701b466bebc342d41_929811d21e3e4cb3a84a5210b8451270.png


5adcf14fc4d273a083fa56be54f27b73_0e38f781c6a34a4da89d4c3b49c89fab.png



导出的excel文件内容:


4d91c9e54111cb6c102dd852e332342e_4da70e72b9fd423b8904564e9145a16a.png


接下来换个类玩玩:


5ccf378c8ac8427c98e37a42ffcf994d_e0c9cefe767849fea5a96a5e904a8713.png


然后导出看看效果:


2c2e93bd2e2e857b7bf8ea259d3d87f8_5e161c29b7bf4836a5206d28777c18bb.png


可以看到数据导出也是OK的:


22d2a101ffec60074876072c7f11e80a_4b1fb15e5c264d44809b7a24a620c218.png


没错就是这么简单, 当然也是抛转引玉, 希望大家看了这篇文章,可以借鉴这些反射的函数玩法,做更多的好玩的封装,比如加上一些自定义注解的解析,比如加上一些前后置拦截器拓展等等。


扩展

上面的示例中导出的表头是属性名,如果正式的导出通常需要自定义表头名称,我们这里可以使用自定义注解来完成。


JcExcelName.java


/**

* @Author : JCccc

* @CreateTime : 2020/5/14

* @Description :

**/


@Target({ElementType.METHOD, ElementType.FIELD})

@Retention(RetentionPolicy.RUNTIME)

public @interface JcExcelName {


   String name() default "";


然后在想导出的类里面,想加看得懂的名字就加,不加就拿属性名:

89327bae0ee23b3972d4bb6a0b5193bb_3f994bfdf74742c08e16071d8a7a472c.png



随手再写一个 ,新的反射解析拿字段属性注解值函数:


public static  List resolveExcelTableName(T entity) {

   List tableNamesList = new ArrayList<>();

   Class bean = entity.getClass();

   Field[] fields = bean.getDeclaredFields();

   Map map = new HashMap<>(fields.length);

   for (Field field : fields) {

       try {

           if (!"serialVersionUID".equals(field.getName())) {

               String tableTitleName = field.getName();

               JcExcelName myFieldAnn = field.getAnnotation(JcExcelName.class);

               String annName = myFieldAnn.name();

               if (StringUtils.hasLength(annName)) {

                   tableTitleName = annName;

               }

               tableNamesList.add(tableTitleName);

           }

       } catch (Exception e) {

           log.warn("toMap() Exception={}", e.getMessage());

       }

   }

   return tableNamesList;

}



然后根据解析出来的注解值列名拼接 表格标题名格式:


public static String buildCsvFileTableNamesNew(List dataList) {

   StringBuilder tableNames = new StringBuilder();

   for (String name : dataList) {

       tableNames.append(name).append(MyCsvFileUtil.CSV_DELIMITER);

   }

   return tableNames.append(MyCsvFileUtil.CSV_TAIL).toString();

}


测试看看效果:


public static void main(String[] args) {


   User user = new User();

   List nameList = MapUtils.resolveExcelTableName(user);

   System.out.println(nameList.toString());

   String tableNames = buildCsvFileTableNamesNew(nameList);

   System.out.println(tableNames);


}


效果嘎嘎好:


71c397e2ab3ced13d4be7637dc72232d_2239ae1ee8a44a87a7a91fd85b5b4b6d.png


然后反手就搞到我们前面的文章使用例子里面:


String tableNames = MyCsvFileUtil.buildCsvFileTableNamesNew( MyCsvFileUtil.resolveExcelTableName(dataList.get(0)));

4d7e530eadd7de1a6b6874863e0e7486_e9b46a37922b49bca7e634df19e8b5e3.png


执行一下示例接口,看看效果:


e840b38fe45343cc7a9443185bf4a5e2_99129a30b608400ba3ce74130748991a.png


文件出来了:

8432ef38a89b7bf799e92f4bfbf5b331_5b37ec3ddbb346bc84e1ed72bbbb6a56.png



打开看看效果:


5083eafeaa4ea170dfb860a0f8ab113b_f03eb391522846b8b6aa47100c93c4e0.png


好了,就到这吧,非常完美。


来源:blog.csdn.net/qq_35387940/article/details/129062470

————————————————

版权声明:本文为CSDN博主「Java技术栈」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/youanyyou/article/details/130846002

相关文章
|
9天前
|
SQL 分布式计算 数据挖掘
从Excel到高级工具:数据分析进阶指南
从Excel到高级工具:数据分析进阶指南
109 54
|
2月前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——封装统一返回的数据结构
本文介绍了在Spring Boot中封装统一返回的数据结构的方法。通过定义一个泛型类`JsonResult&lt;T&gt;`,包含数据、状态码和提示信息三个属性,满足不同场景下的JSON返回需求。例如,无数据返回时可设置默认状态码&quot;0&quot;和消息&quot;操作成功!&quot;,有数据返回时也可自定义状态码和消息。同时,文章展示了如何在Controller中使用该结构,通过具体示例(如用户信息、列表和Map)说明其灵活性与便捷性。最后总结了Spring Boot中JSON数据返回的配置与实际项目中的应用技巧。
134 0
|
3月前
|
分布式计算 大数据 数据处理
从Excel到大数据:别让工具限制你的思维!
从Excel到大数据:别让工具限制你的思维!
201 85
|
2月前
|
人工智能 数据可视化 前端开发
Probly:开源 AI Excel表格工具,交互式生成数据分析结果与可视化图表
Probly 是一款结合电子表格功能与 Python 数据分析能力的 AI 工具,支持在浏览器中运行 Python 代码,提供交互式电子表格、数据可视化和智能分析建议,适合需要强大数据分析功能又希望操作简便的用户。
376 2
|
5月前
|
人工智能 自然语言处理 Java
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
FastExcel 是一款基于 Java 的高性能 Excel 处理工具,专注于优化大规模数据处理,提供简洁易用的 API 和流式操作能力,支持从 EasyExcel 无缝迁移。
695 9
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
|
5月前
|
人工智能 自然语言处理 JavaScript
Univer:开源全栈 AI 办公工具,支持 Word、Excel、PPT 等文档处理和多人实时协作
Univer 是一款开源的 AI 办公工具,支持 Word、Excel 等文档处理的全栈解决方案。它具有强大的功能、高度的可扩展性和跨平台兼容性,适用于个人和企业用户,能够显著提高工作效率。
475 9
Univer:开源全栈 AI 办公工具,支持 Word、Excel、PPT 等文档处理和多人实时协作
|
6月前
|
数据可视化 数据挖掘 项目管理
打破协作壁垒,Excel多人协同编辑工具带来翻天覆地的变化!
在现代办公中,团队协作和信息共享至关重要。Excel的多人协同编辑功能显著提升了工作效率,避免了版本冲突和重复劳动。市场上的Google Sheets、Airtable、板栗看板和Zoho Sheet等工具也提供了类似功能。以其清晰的界面和强大的数据分析能力,特别适合项目管理和进度追踪,帮助团队高效协作,达成目标。
|
6月前
|
SQL 数据可视化 数据挖掘
想让Excel表格设计更美观?试试这几款好用工具!
Excel表格设计在项目管理和数据分析中至关重要。本文推荐四款辅助工具:板栗看板、Excel自动图表助手、Think-Cell Chart 和 Power BI,分别在任务管理、图表生成、数据可视化等方面表现突出,帮助你设计出更专业、美观的表格。
279 2
|
5月前
|
数据采集 数据可视化 数据挖掘
利用Python自动化处理Excel数据:从基础到进阶####
本文旨在为读者提供一个全面的指南,通过Python编程语言实现Excel数据的自动化处理。无论你是初学者还是有经验的开发者,本文都将帮助你掌握Pandas和openpyxl这两个强大的库,从而提升数据处理的效率和准确性。我们将从环境设置开始,逐步深入到数据读取、清洗、分析和可视化等各个环节,最终实现一个实际的自动化项目案例。 ####
685 10
|
7月前
|
数据采集 存储 JavaScript
自动化数据处理:使用Selenium与Excel打造的数据爬取管道
本文介绍了一种使用Selenium和Excel结合代理IP技术从WIPO品牌数据库(branddb.wipo.int)自动化爬取专利信息的方法。通过Selenium模拟用户操作,处理JavaScript动态加载页面,利用代理IP避免IP封禁,确保数据爬取稳定性和隐私性。爬取的数据将存储在Excel中,便于后续分析。此外,文章还详细介绍了Selenium的基本设置、代理IP配置及使用技巧,并探讨了未来可能采用的更多防反爬策略,以提升爬虫效率和稳定性。
422 4

热门文章

最新文章