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. 解决aspnetcore-browser-refresh.js:234 WebSocket connection to 'wss://localhost:62356/Admin/' failed问题

    前言 前段时间升级了Visual Studio到v17.1.1最新版本,然后今天来运行之前的一个.net5项目一直提示:aspnetcore-browser-refresh.js:234 WebSoc ...

  2. 连表操作join 子查询 SQL补充 数据库软件navicat pymysql模块

    目录 多表查询的两种方法 方式1:连表操作 方式2:子查询 SQL补充知识点 1.分组之前字段拼接 concat concat_ws 2.SQL执行判断条件 exists 3.表相关SQL补充 修改表 ...

  3. 安装es可视化软件Kibana

    一 Kibana介绍 Kibana 是一款开源的数据分析和可视化平台,它是 Elastic Stack 成员之一,设计用于和 Elasticsearch 协作. 您.可以使用 Kibana 对 Ela ...

  4. 填坑日志-云网络智慧课堂双网卡Mac地址读取错误的问题及解决

    云网络智慧课堂的双网卡问题记录及解决方案 教师端 其实这里双网卡的问题一直没有解决,分为了两部分,一部分是教师端,一部分是学生端.症状类似,问题也类似,都是在设计之初因为硬件限制可能没有考虑到双网卡的 ...

  5. 【深入浅出SpringCloud原理及实战】「SpringCloud-Alibaba系列」微服务模式搭建系统基础架构实战指南及版本规划踩坑分析

    Spring Cloud Alibaba Nacos Discovery Spring Boot 应用程序在服务注册与发现方面提供和 Nacos 的无缝集成. 通过一些简单的注解,您可以快速来注册一个 ...

  6. 红袖添香,绝代妖娆,Ruby语言基础入门教程之Ruby3基础数据类型(data types)EP02

    Ruby是强类型动态语言,即Ruby中一旦某一个对象被定义类型,如果不通过强制转换操作,那么它永远就是该数据类型,并且只有在Ruby解释器运行时才会检测对象数据类型,它的一切皆为对象(包括 nil 值 ...

  7. [LeetCode]最大连续1的个数

    题目 代码 class Solution { public: int findMaxConsecutiveOnes(vector<int>& nums) { int length= ...

  8. Java学习笔记:2022年1月10日

    Java学习笔记:2022年1月10日 ​ 摘要:这篇笔记主要记录了学习<Java核心技术 卷一>的第四章时的一些心得,主要阐述了对象与类这一部分的内容.需要注意的是,这一章的内容需要精心 ...

  9. 为什么要虚拟化,为什么要容器,为什么要Docker,为什么要K8S?

    前言 如标题中的问题所提到的虚拟化,容器,Docker和K8s那样,我们不妨这样问:这些技术到底适用于哪些场景,有没有别的技术可以替代?这些技术的优劣在哪里? 下面我将针对性地从以上几个问题的出发点, ...

  10. 特殊input框需求,粘贴文字或者扫码筛选检查后加密为password格式,否则正常显示/假如用户输入的信息是以mima开头,就切换输入框为密码类型

    1.angular8粘贴文字或者扫码筛选检查后加密为password格式,否则正常显示 <input [type]="myInputType" (keyup.enter)=& ...