1、依赖

<dependencies>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.69</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>

2、注解类

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyExcelName {
String name() default "";
}

3、实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class District implements Serializable {
/**
* 地址编码
*/
@MyExcelName(name="编码")
private String code;
/**
* 地址名称
*/
@MyExcelName(name="名称")
private String name;
/**
* 地址父级编码
*/
@MyExcelName(name="父级编码")
private String parentCode;
/**
* 当前地区对应的全称
*/
@MyExcelName(name="全称")
private String fullName; }

4、工具类

/**
* <p>描述 : csv帮助类
*
* <p>路径 : cn.tjhis.utils
*
* <p>工程 : ExcelExport
*
* <p>作者 : wanghx
*
* <p>日期 : 2023-03-04 05:56
*
* @author : Administrator
*/
public class MyCsvFileUtil {
/**
* 文件后缀
*/
private static final String FILE_SUFFIX = ".csv";
/**
* 分隔符
*/
private static final String CSV_DELIMITER = ",";
/**
* 换行符
*/
private static final String CSV_TAIL = "\r\n";
/**
* 文件名称
*/
protected static final String DATE_STR_FILE_NAME = "yyyyMMddHHmmssSSS"; /**
* 将字符串转成csv文件
*/
private 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 内容
*/
private 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) {
StaticLog.error("写文件异常|{}", e);
} finally {
if (fos != null) {
//关闭流
IOUtils.closeQuietly(fos);
}
if (writer != null) {
IOUtils.closeQuietly(writer);
}
}
} /**
* 构建文件名称
*
* @param dataList list 数据
* @return 文件名称
*/
private 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 list 数据
* @return 标题
*/
private static String buildCsvFileTableNames(List dataList) {
Map<String, Object> 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 dataList list 数据
* @return 标题
*/
private static String buildCsvFileTableNamesNew(List<String> dataList) { StringBuilder tableNames = new StringBuilder();
for (String name : dataList) {
tableNames.append(name).append(MyCsvFileUtil.CSV_DELIMITER);
}
return tableNames.append(MyCsvFileUtil.CSV_TAIL).toString();
} /**
* 构建excel内容
*
* @param dataLists list 数据
* @return 内容
*/
private static String buildCsvFileBodyMap(List dataLists) {
// 不管你传什么玩意,都搞成Map
List<Map<String, Object>> mapList = new ArrayList<>();
for (Object o : dataLists) {
mapList.add(toMap(o));
}
// 然后利用csv格式,对着map拼接数据
StringBuilder lineBuilder = new StringBuilder();
for (Map<String, Object> 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 <T> 泛型
* @return 返回的map集合
*/
private static <T> Map<String, Object> toMap(T entity) {
Class<?> bean = entity.getClass();
Field[] fields = bean.getDeclaredFields();
Map<String, Object> map = new TreeMap<>();
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) {
StaticLog.warn("toMap() Exception={}", e.getMessage());
}
}
return map;
}
/**
* 创建表格行标题 如果有注解 MyExcelName ,则用
*
* @param entity 实体
* @param <T> 实体
* @return 表头
*/
private static <T> List<String> resolveExcelTableName(T entity) {
Class<?> bean = entity.getClass();
Field[] fields = bean.getDeclaredFields();
Map<String, String> map = new TreeMap<>();
for (Field field : fields) {
try {
if (!"serialVersionUID".equals(field.getName())) {
String tableTitleName = field.getName();
MyExcelName myFieldAnn = field.getAnnotation(MyExcelName.class);
String annName = myFieldAnn.name();
// if (StrUtil.isNotBlank(annName)) {
// tableTitleName = annName;
// }
map.put(tableTitleName,annName);
}
} catch (Exception e) {
StaticLog.warn("toMap() Exception={}", e.getMessage());
}
}
return map.values().stream().toList();
}
/**
* 将文件导出到csv
*
* @param list 数据
* @param path 父级路径
* @param isShowChinese 表头是否显示中文
*/
public static String export(List list, String path, boolean isShowChinese) {
//存放地址&文件名
String fileName = path + buildCsvFileFileName(list);
String tableNames = "";
if (isShowChinese) {
// 创建表格行标题 注解名 ,可以是中文
tableNames = buildCsvFileTableNamesNew(resolveExcelTableName(list.get(0)));
} else {
// 创建表格行标题 属性名
tableNames = MyCsvFileUtil.buildCsvFileTableNames(list);
}
//创建文件
writeFile(fileName, tableNames);
//写入数据
String contentBody = buildCsvFileBodyMap(list);
//调用方法生成
writeFile(fileName, contentBody);
return fileName;
}
}

5、测试类

public class Main {
public static void main(String[] args) {
District district1 = new District("110101", "东城区", "110100", "北京北京市东城区");
District district2 = new District("110102", "西城区", "110100", "北京北京市西城区");
District district3 = new District("110105", "朝阳区", "110100", "北京北京市朝阳区");
District district4 = new District("110107", "石景山区", "110100", "北京北京市石景山区");
District district5 = new District("110108", "海淀区", "110100", "北京北京市海淀区");
District district6 = new District("110109", "门头沟区", "110100", "北京北京市门头沟区");
District district7 = new District("110111", "房山区", "110100", "北京北京市房山区");
District district8 = new District("110112", "通州区", "110100", "北京北京市通州区");
District district9 = new District("110113", "顺义区", "110100", "北京北京市顺义区");
District district10 = new District("110114", "昌平区", "110100", "北京北京市昌平区");
District district11 = new District("110115", "大兴区", "110100", "北京北京市大兴区");
District district12 = new District("110116", "怀柔区", "110100", "北京北京市怀柔区");
District district13 = new District("110117", "平谷区", "110100", "北京北京市平谷区");
District district14 = new District("110228", "密云区", "110100", "北京北京市密云区");
// 类不确定 随便怎么传都行
List<District> districts = new ArrayList<>();
districts.add(district1);
districts.add(district2);
districts.add(district3);
districts.add(district4);
districts.add(district5);
districts.add(district6);
districts.add(district7);
districts.add(district8);
districts.add(district9);
districts.add(district10);
districts.add(district11);
districts.add(district12);
districts.add(district13);
districts.add(district14);
String fileName = MyCsvFileUtil.export(districts, "d:\\",false);
MyCsvFileUtil.export(districts, "d:\\",true);
StaticLog.info("文件导出成功,文件名:{}", fileName);
}
}

6、效果图

  • 原始表头

  • 中文表头

java-tocsv的更多相关文章

  1. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  2. Java 将Excel转为图片、html、XPS、XML、CSV

    通过文档格式转换,可满足不同办公场合对文档操作的需求.本文将介绍转换Excel文档为其他常见文档格式的方法.通过文中的方法,可支持将Excel转换为包括PDF.图片.html.XPS.XML.CSV. ...

  3. 故障重现(内存篇2),JAVA内存不足导致频繁回收和swap引起的性能问题

    背景起因: 记起以前的另一次也是关于内存的调优分享下   有个系统平时运行非常稳定运行(没经历过大并发考验),然而在一次活动后,人数并发一上来后,系统开始卡. 我按经验开始调优,在每个关键步骤的加入如 ...

  4. Elasticsearch之java的基本操作一

    摘要   接触ElasticSearch已经有一段了.在这期间,遇到很多问题,但在最后自己的不断探索下解决了这些问题.看到网上或多或少的都有一些介绍ElasticSearch相关知识的文档,但个人觉得 ...

  5. 论:开发者信仰之“天下IT是一家“(Java .NET篇)

    比尔盖茨公认的IT界领军人物,打造了辉煌一时的PC时代. 2008年,史蒂夫鲍尔默接替了盖茨的工作,成为微软公司的总裁. 2013年他与微软做了最后的道别. 2013年以后,我才真正看到了微软的变化. ...

  6. 故障重现, JAVA进程内存不够时突然挂掉模拟

    背景,服务器上的一个JAVA服务进程突然挂掉,查看产生了崩溃日志,如下: # Set larger code cache with -XX:ReservedCodeCacheSize= # This ...

  7. 死磕内存篇 --- JAVA进程和linux内存间的大小关系

    运行个JAVA 用sleep去hold住 package org.hjb.test; public class TestOnly { public static void main(String[] ...

  8. 【小程序分享篇 一 】开发了个JAVA小程序, 用于清除内存卡或者U盘里的垃圾文件非常有用

    有一种场景, 手机内存卡空间被用光了,但又不知道哪个文件占用了太大,一个个文件夹去找又太麻烦,所以我开发了个小程序把手机所有文件(包括路径下所有层次子文件夹下的文件)进行一个排序,这样你就可以找出哪个 ...

  9. Java多线程基础学习(二)

    9. 线程安全/共享变量——同步 当多个线程用到同一个变量时,在修改值时存在同时修改的可能性,而此时该变量只能被赋值一次.这就会导致出现“线程安全”问题,这个被多个线程共用的变量称之为“共享变量”. ...

  10. Java多线程基础学习(一)

    1. 创建线程    1.1 通过构造函数:public Thread(Runnable target, String name){}  或:public Thread(Runnable target ...

随机推荐

  1. ffmpeg库安装及入门指南(Windows篇)- 2022年底钜献

    最近项目需要,使用了 ffmpeg 做摄像头视频采集和串流.这几天有点时间,打算把相关的一些知识记录分享一下. 在撰写本文时,我又在另外一台电脑上把 ffmpeg 重新安装了一遍,所以绝对真实靠谱!如 ...

  2. 动态更改Spring定时任务Cron表达式的优雅方案

    "Most of you are familiar with the virtues of a programmer. There are three, of course: lazines ...

  3. 侦察工具——Httrack

    前言 web渗透学习笔记,实验环境为Metasploitable靶机上的DVWA.此随笔介绍Web渗透侦察工具Httrack Httrack 简介 Httrack能够克隆拷贝目标网站上的所有可访问.可 ...

  4. 教你用JavaScript实现乘法游戏

    案例介绍 欢迎来的我的小院,我是霍大侠,恭喜你今天又要进步一点点了!我们来用JavaScript编程实战案例,做一个乘法积分游戏.乘法游戏主要通过用户输入的数值和程序计算的数值进行对比,正确积一分,错 ...

  5. 快速排序算法实现 (y总课后)

    主要思路: 1.确定 边界 l----------r  (left right) 2.确定中间值  l--------x----------r 3.优雅快排: 设置两个指针i,j. i从左边开始运行 ...

  6. python之路55 cookie与session 操作 把模块变成字符串进行导入

    django中间件三个了解的方法 1.process_view 路由匹配成功之后执行视图函数/类之前自动触发(顺序同process_request) 2.process_exception 视图函数/ ...

  7. 《STL源码剖析》traits技法分析

    在完成一个迭代器的时候,我们可能会暴露太多的细节在外面,为了将这些细节给隐藏,我们需要封装,这也是为什么每一种STL容器都提供了一种专属的迭代器. 为了解决以"迭代器所指对象的型别" ...

  8. [Untiy]贪吃蛇大作战(二)——规则界面

    游戏规则界面: 从界面上可以看出,一共有三个按钮,两个切换按钮和一个退出按钮. 一共三张规则图片Sprite,我们通过设置其是否为Active来控制显示,其控制脚本代码如下: using System ...

  9. Spring 和 Spring MVC的区别

    Spring 和 Spring MVC的区别   学习Spring MVC也有几天时间了,那么Spring和Spring MVC的区别到底在哪里,二者是什么关系呢?认为二者是一个东西那肯定是不对的,而 ...

  10. 「Python实用秘技12」像导入模块一样导入ipynb文件

    本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第12 ...