Java使用poi导出Excel之格式设置

article/2025/9/30 13:27:48

最近接到一个需求,客户不满意原本导出的csv文件,想要导出Excel文件。不就导出Excel文件嘛,小意思,于是乎信心满满从网上扒导出的代码,一顿CV大法,搞定!代码如下:

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.xssf.usermodel.*;import java.io.File;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;@Slf4j
public class ExcelUtils {// 新版Excel文件后缀private static final String EXCEL_SUFFIX = ".xlsx";/*** 导出核心实现** @param fileName* @param headers* @param dataList* @return XSSFWorkbook*/@Deprecatedprivate static XSSFWorkbook writeDataToWorkbook(String fileName, List<String> headers, List<Map<String, Object>> dataList) {// 创建一个工作薄XSSFWorkbook workbook = new XSSFWorkbook();try {// 创建一个工作表XSSFSheet sheet = workbook.createSheet(fileName);// 设置表头字体格式XSSFFont headersFont = workbook.createFont();headersFont.setColor(new XSSFColor(java.awt.Color.DARK_GRAY));headersFont.setFontHeightInPoints((short) 14);headersFont.setBold(true);// 设置正文字体格式XSSFFont dataSetFont = workbook.createFont();dataSetFont.setColor(new XSSFColor(java.awt.Color.BLACK));dataSetFont.setBold(false);// 创建表头样式XSSFCellStyle headersStyle = workbook.createCellStyle();headersStyle.setBorderTop(BorderStyle.THIN);headersStyle.setBorderBottom(BorderStyle.THIN);headersStyle.setBorderLeft(BorderStyle.THIN);headersStyle.setBorderRight(BorderStyle.THIN);headersStyle.setFont(headersFont);// 表头内容对齐方式:居中headersStyle.setAlignment(HorizontalAlignment.CENTER);// 创建文本样式XSSFCellStyle textStyle = workbook.createCellStyle();textStyle.setBorderBottom(BorderStyle.THIN);textStyle.setBorderRight(BorderStyle.THIN);textStyle.setBorderLeft(BorderStyle.THIN);textStyle.setFont(dataSetFont);// 数据内容对齐方式:居左textStyle.setAlignment(HorizontalAlignment.LEFT);// 创建数字样式XSSFCellStyle numeralStyle = workbook.createCellStyle();numeralStyle.setBorderBottom(BorderStyle.THIN);numeralStyle.setBorderRight(BorderStyle.THIN);numeralStyle.setBorderLeft(BorderStyle.THIN);numeralStyle.setFont(dataSetFont);// 数据内容对齐方式:居右numeralStyle.setAlignment(HorizontalAlignment.RIGHT);// 此处设置数据格式XSSFDataFormat df = workbook.createDataFormat();int index = 0;// 创建表头并设置样式XSSFRow row = sheet.createRow(index);for (int i = 0; i < headers.size(); i++) {sheet.setColumnWidth(i, 20 * 256);XSSFCell cell = row.createCell(i);cell.setCellStyle(headersStyle);XSSFRichTextString text = new XSSFRichTextString(headers.get(i));cell.setCellValue(text);}// 导出正文数据,并设置其样式for (Map<String, Object> data : dataList) {index++;row = sheet.createRow(index);int column = 0;for (String key : data.keySet()) {XSSFCell cell = row.createCell(column++);Object value = data.get(key);if (value == null) {continue;}String dataType = value.getClass().getName();if (dataType.endsWith("BigDecimal") || dataType.endsWith("Double")) {// 带小数点的数字格式cell.setCellStyle(numeralStyle);numeralStyle.setDataFormat(df.getFormat("0.00"));//保留两位小数点cell.setCellValue(Double.parseDouble(value.toString()));} else if (dataType.endsWith("Integer") || dataType.endsWith("Long")) {// 整型数字格式cell.setCellStyle(numeralStyle);numeralStyle.setDataFormat(df.getFormat("General"));//数据格式采用常规cell.setCellValue(Double.parseDouble(value.toString()));} else if (dataType.endsWith("Date")) {//日期转为字符串cell.setCellStyle(textStyle);cell.setCellValue(date2Str((Date) value, "yyyy-MM-dd HH:mm:ss"));} else {// 文本格式cell.setCellStyle(textStyle);cell.setCellValue(value.toString());}}}} catch (Exception e) {log.error("writeDataToWorkbook error, ", e);}return workbook;}/*** 测试类*/public static void main(String[] args) {String filename = date2Str(new Date(), "yyyyMMddHHmmss");List<String> headers = Arrays.asList("客户编号", "手机号", "姓名", "创建时间", "账户余额", "账户余额1",  "账户余额2", "年龄");List<Map<String, Object>> datas = new ArrayList<>();Map<String, Object> map = new LinkedHashMap<>();map.put("id", 123);map.put("mobile", "0833344545");map.put("name", "jfdkdb ft#E@");map.put("time", new Date());map.put("amount", new BigDecimal("34276.8601"));map.put("amount1", 34276.8);map.put("amount2", 323455.10);map.put("days", 24);datas.add(map);XSSFWorkbook wb = writeDataToWorkbook(filename, headers, datas);try {File file = new File("/Users/test/" + filename + EXCEL_SUFFIX);FileOutputStream fileOutputStream = new FileOutputStream(file);wb.write(fileOutputStream);fileOutputStream.close();} catch (Exception e) {System.err.println(e.getMessage());}System.out.println("export excel " + filename + " succeed!");}public static String date2Str(Date date, String pattern) {if (null == date) return "";SimpleDateFormat sdf = new SimpleDateFormat(pattern);return sdf.format(date);}
}

项目跑起来本地测试一波看看效果:

好像没啥毛病,收。。。。球都么得,余额那几列的小数点位数好像不对啊!

回首撸代码,我设置了啊, 咋就没生效呢???

于是乎继续网上扒资料,各种说法都试一波:

1.如下图加celltype的设置,测试效果和第一次一样,失败;

 2.我又猜测是不是转double类型导致的,就改成如下图所示,赋值的时候用字符串格式:

        测试效果和第一次一样,不,比第一次还差,小数位数不对就算了,单元格左上角多了个绿色的小箭头,意味着客户不能直接框选看总额了,失败;

这么简单个功能,我居然卡这里了,心态。。崩了啊。。。。

3. 是你逼我的。要出绝招了,我自己处理数据,于是改成这样:

  跑起来,效果不错,小数位数都对了,但是单元格还是文本格式的。。。。

 4. 数据格式都对了,单元格格式嘛,简单,设置下入参就好了,So easy!马上改成下图:

 再次跑起来,结果如下所示:崩了。。。彻底崩。。了!

投降了。。我决定,文本格式就文本格式吧,数据格式对了就行,准备使用方案3了。

就在我要commit的时候,我突然看到结果4中的余额数据有","分割,我擦,这不是我设置的整型格式吗???我决定再试一把,我新建个数字格式专门给浮点型的数据用,代码又改成如下:


import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.xssf.usermodel.*;import java.io.File;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;@Slf4j
public class ExcelUtils {// 新版Excel文件后缀private static final String EXCEL_SUFFIX = ".xlsx";/*** 导出核心实现** @param fileName* @param headers* @param dataList* @return XSSFWorkbook*/@Deprecatedprivate static XSSFWorkbook writeDataToWorkbook(String fileName, List<String> headers, List<Map<String, Object>> dataList) {// 创建一个工作薄XSSFWorkbook workbook = new XSSFWorkbook();try {// 创建一个工作表XSSFSheet sheet = workbook.createSheet(fileName);// 设置表头字体格式XSSFFont headersFont = workbook.createFont();headersFont.setColor(new XSSFColor(java.awt.Color.DARK_GRAY));headersFont.setFontHeightInPoints((short) 14);headersFont.setBold(true);// 设置正文字体格式XSSFFont dataSetFont = workbook.createFont();dataSetFont.setColor(new XSSFColor(java.awt.Color.BLACK));dataSetFont.setBold(false);// 此处设置数据格式XSSFDataFormat df = workbook.createDataFormat();// 创建表头样式XSSFCellStyle headersStyle = workbook.createCellStyle();headersStyle.setBorderTop(BorderStyle.THIN);headersStyle.setBorderBottom(BorderStyle.THIN);headersStyle.setBorderLeft(BorderStyle.THIN);headersStyle.setBorderRight(BorderStyle.THIN);headersStyle.setFont(headersFont);// 表头内容对齐方式:居中headersStyle.setAlignment(HorizontalAlignment.CENTER);// 创建文本样式XSSFCellStyle textStyle = workbook.createCellStyle();textStyle.setBorderBottom(BorderStyle.THIN);textStyle.setBorderRight(BorderStyle.THIN);textStyle.setBorderLeft(BorderStyle.THIN);textStyle.setFont(dataSetFont);// 数据内容对齐方式:居左textStyle.setAlignment(HorizontalAlignment.LEFT);// 创建浮点型数字样式XSSFCellStyle floatStyle = workbook.createCellStyle();floatStyle.setBorderBottom(BorderStyle.THIN);floatStyle.setBorderRight(BorderStyle.THIN);floatStyle.setBorderLeft(BorderStyle.THIN);floatStyle.setAlignment(HorizontalAlignment.RIGHT);floatStyle.setFont(dataSetFont);floatStyle.setDataFormat(df.getFormat("#,##0.00"));// 创建整型数字样式XSSFCellStyle integerStyle = workbook.createCellStyle();integerStyle.setBorderBottom(BorderStyle.THIN);integerStyle.setBorderRight(BorderStyle.THIN);integerStyle.setBorderLeft(BorderStyle.THIN);integerStyle.setAlignment(HorizontalAlignment.RIGHT);integerStyle.setFont(dataSetFont);integerStyle.setDataFormat(df.getFormat("0"));int index = 0;// 创建表头并设置样式XSSFRow row = sheet.createRow(index);for (int i = 0; i < headers.size(); i++) {sheet.setColumnWidth(i, 20 * 256);XSSFCell cell = row.createCell(i);cell.setCellStyle(headersStyle);XSSFRichTextString text = new XSSFRichTextString(headers.get(i));cell.setCellValue(text);}// 导出正文数据,并设置其样式for (Map<String, Object> data : dataList) {index++;row = sheet.createRow(index);int column = 0;for (String key : data.keySet()) {XSSFCell cell = row.createCell(column++);Object value = data.get(key);if (value == null) {continue;}String dataType = value.getClass().getName();if (dataType.endsWith("BigDecimal") || dataType.endsWith("Double") || dataType.endsWith("Float")) {cell.setCellStyle(floatStyle);  // 带小数点的数字格式cell.setCellValue(Double.parseDouble(value.toString()));} else if (dataType.endsWith("Integer") || dataType.endsWith("Long")) {cell.setCellStyle(integerStyle);    // 整型数字格式cell.setCellValue(Double.parseDouble(value.toString()));} else if (dataType.endsWith("Date")) {cell.setCellStyle(textStyle);   //日期转为字符串cell.setCellValue(date2Str((Date) value, "yyyy-MM-dd HH:mm:ss"));} else {cell.setCellStyle(textStyle);   // 文本格式cell.setCellValue(value.toString());}}}} catch (Exception e) {log.error("writeDataToWorkbook error, ", e);}return workbook;}/*** 测试类*/public static void main(String[] args) {String filename = date2Str(new Date(), "yyyyMMddHHmmss");List<String> headers = Arrays.asList("客户编号", "手机号", "姓名", "创建时间", "账户余额", "账户余额1",  "账户余额2", "年龄");List<Map<String, Object>> datas = new ArrayList<>();Map<String, Object> map = new LinkedHashMap<>();map.put("id", 123);map.put("mobile", "0833344545");map.put("name", "jfdkdb ft#E@");map.put("time", new Date());map.put("amount", new BigDecimal("34276.8601"));map.put("amount1", 34276.8);map.put("amount2", 323455.10);map.put("days", 24);datas.add(map);XSSFWorkbook wb = writeDataToWorkbook(filename, headers, datas);try {File file = new File("/Users/test/" + filename + EXCEL_SUFFIX);FileOutputStream fileOutputStream = new FileOutputStream(file);wb.write(fileOutputStream);fileOutputStream.close();} catch (Exception e) {System.err.println(e.getMessage());}System.out.println("export excel succeed!");}public static String date2Str(Date date, String pattern) {if (null == date) return "";SimpleDateFormat sdf = new SimpleDateFormat(pattern);return sdf.format(date);}
}

结果如下:

我擦嘞,真的就好了???!

原来是

XSSFCellStyle integerStyle = workbook.createCellStyle();

创建出来的style只能赋值一次,后面的赋值无效导致的。

虽然被这个小问题折磨了快一天了,心态都崩了好几次,但是好在最后找到原因了,解决问题的感觉真爽,崩的稀碎的心态有重新凝聚起来,比以前更强大了呢。。。


http://chatgpt.dhexx.cn/article/CRy9AiQQ.shtml

相关文章

Java使用POI导出Excel

目录 一、前景二、概念2.1. 简介2.2.Excel版本和相关对象2.3.WorkBook2.4.POI依赖 三、POI - 写3.1.代码示例3.2. 性能对比3.3. 测试rowAccessWindowSize3.4. 导出Excel样式设置 四、POI - 读4.1.代码示例4.2.读取不同的数据类型4.3.读取公式 五、POI - 遇到的坑5.1.为什么模板…

Java实现八大排序算法

原文链接&#xff1a; 八大排序算法总结与java实现 - iTimeTraveler 概述 因为健忘&#xff0c;加上对各种排序算法理解不深刻&#xff0c;过段时间面对排序就蒙了。所以决定对我们常见的这几种排序算法进行统一总结&#xff0c;强行学习。首先罗列一下常见的十大排序算法&…

通过java实现八大排序的功能

八大排序(java实现) 常见的排序算法如下&#xff1a; 直接插入排序希尔排序简单选择排序堆排序冒泡排序快速排序归并排序基数排序 它们都属于内部排序&#xff0c;也就是只考虑数据量较小仅需要使用内存的排序算法&#xff0c;他们之间关系如下&#xff1a; 稳定与非稳定 …

c语言基数为3变为基数为10,必须知道的C语言八大排序算法(收藏)

概述 排序有内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#xff0c;而外部排序是因排序的数据很大&#xff0c;一次不能容纳全部的排序记录&#xff0c;在排序过程中需要访问外存。 我们这里说说八大排序就是内部排序。 当n较大&#xff0c;则应采用时…

数据结构( 排序)

排序 1、排序的基本概念2、插入排序①.直接插入排序②.折半插入排序③.希尔排序 3、交换排序①.冒泡排序②.快速排序 4、选择排序①.简单选择排序②.树形选择排序③.堆排序 5、归并排序6、基数排序7、总结8、例题与应用 1、排序的基本概念 排序是计算机内经常进行的一种操作&a…

十大经典排序算法python版本_【程序员面试必备】动画详解十大经典排序算法(C语言版)...

欢迎访问我的博客原文 排序算法是程序员必备的基础知识&#xff0c;弄明白它们的原理和实现很有必要。本文中将通过非常细节的动画展示出算法的原理&#xff0c;配合代码更容易理解。 概述 由于待排序的元素数量不同&#xff0c;使得排序过程中涉及的存储器不同&#xff0c;可将…

八大排序算法详解(Java语言实现)

概述 因为健忘&#xff0c;加上对各种排序算法理解不深刻&#xff0c;过段时间面对排序就蒙了。所以决定对我们常见的这几种排序算法进行统一总结&#xff0c;强行学习。首先罗列一下常见的十大排序算法&#xff1a; 直接插入排序希尔排序简单选择排序堆排序冒泡排序快速排序归…

九大排序算法-C语言实现及详解

概述 排序有内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#xff0c;而外部排序是因排序的数据很大&#xff0c;一次不能容纳全部的排序记录&#xff0c;在排序过程中需要访问外存。 我们这里说说八大排序就是内部排序。 当n较大&#xff0c;则应采用…

常用的排序算法-C语言

目录 冒泡排序   鸡尾酒排序  选择排序插入排序 二分插入排序  希尔排序  归并排序堆排序快速排序 我们通常所说的排序算法往往指的是内部排序算法&#xff0c;即数据记录在内存中进行排序。 排序算法大体可分为两种&#xff1a; 一种是比较排序&#xff0c;时间复杂度…

九大排序算法详解 - C语言篇

概述 排序有内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#xff0c;而外部排序是因排序的数据很大&#xff0c;一次不能容纳全部的排序记录&#xff0c;在排序过程中需要访问外存。 我们这里说说八大排序就是内部排序。 当n较大&#xff0c;则应采用时…

数据结构排序算法总结

学完数据结构已经有好长一段时间了&#xff0c;最近又重新回顾&#xff0c;做一个八大排序的总结&#xff0c;以便后期回顾。 目录 一、插入排序 1.直接插入排序 2.希尔排序 二、交换排序 1.冒泡排序 2.快速排序 三、选择排序 1.简单选择排序 2.堆排序 四、归并排序 …

程序员面试必备——动画详解十大经典排序算法(C语言版)

博客原文地址 排序算法是程序员必备的基础知识&#xff0c;弄明白它们的原理和实现很有必要。本文中将通过非常细节的动画展示出算法的原理&#xff0c;配合代码更容易理解。 概述 由于待排序的元素数量不同&#xff0c;使得排序过程中涉及的存储器不同&#xff0c;可将排序方…

【C语言八大排序思想及代码实现】

文章目录 系列文章目录前言一、冒泡排序二、选择排序三、直接插入排序四、希尔排序五、归并排序六、基数&#xff08;桶&#xff09;排序七、堆排序八、快速排序总结 一、冒泡排序 思想&#xff1a; 从第一个数开始依次向后进行比较&#xff08;第一个和第二个比较然后第二个…

经典排序算法总结(C实现)

一 排序算法介绍 1.0 排序的概述 在计算机计算和处理加工数据时&#xff0c;经常会直接或间接地涉及到数据的排序问题。可以简单地将排序操作理解为&#xff1a;将一个按值无序的数据序列转换成为一个按值有序的数据序列的过程。例如&#xff0c;将一个无序的数组 A[5] {7, …

主元排序法c语言程序,C/C++实现八大排序算法汇总

概述排序有内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#xff0c;而外部排序是因排序的数据很大&#xff0c;一次不能容纳全部的排序记录&#xff0c;在排序过程中需要访问外存。 我们这里说说八大排序就是内部排序。 当n较大&#xff0c;则应采用时间…

内排序算法小结

针对近两天所复盘的《数据结构》中的内排序部分&#xff0c;做一个小总结。尽力在最大程度上把考点重现出来&#xff0c;以便复盘之需。 本文所有算法均使用 C语言 实现。 本博客仅从个人的考点梳理为基&#xff0c;内容相较全局还有很多缺失&#xff0c;读者请权衡参考。 目…

数据结构-考研难点代码突破(C/C++/Java排序算法,性能及其稳定性分析(内部排序))

文章目录 1. 内部排序的基本种类2. 插入排序Ⅰ直接插入排序性能与稳定性分析Ⅱ 折半插入排序性能与稳定性分析Ⅲ 希尔排序性能与稳定性分析 3. 交换排序Ⅰ 冒泡排序性能与稳定性分析Ⅱ 快速排序key值选取&#xff08;三数取中&#xff09;三种交换方法① hoare左右指针② 挖坑法…

排序算法知识点总结和Java实现

排序算法知识点总结和Java实现 前言1. 术语解释2. 排序算法2.1 选择排序2.2 冒泡排序2.3 插入排序2.4 希尔排序2.5 归并排序2.6 快速排序2.7 堆排序2.8 计数排序2.9 桶排序2.10 基数排序 参考材料 前言 文章会有一些从参考材料中转载来的动图&#xff0c;如果构成侵权&#xf…

八大排序算法总结与java实现

原文链接&#xff1a; 八大排序算法总结与java实现 - iTimeTraveler 概述 因为健忘&#xff0c;加上对各种排序算法理解不深刻&#xff0c;过段时间面对排序就蒙了。所以决定对我们常见的这几种排序算法进行统一总结。首先罗列一下常见的十大排序算法&#xff1a; 直接插入排序…

C/C++最全排序算法汇总,原理+代码

1、简介 排序是计算机内经常进行的一种操作&#xff0c;其目的是将一组“无序”的记录序列调整为“有序”的记录序列。分内部排序和外部排序。若整个排序过程不需要访问外存便能完成&#xff0c;则称此类排序问题为内部排序。反之&#xff0c;若参加排序的记录数量很大&#x…