POI处理Excel (xlsx格式) 设置单元格格式为数值 且千分位分隔 保留两位小数

news2024/9/24 21:29:02

背景

某公司导出的一个Excel 其中有三列数据 是数字 但是导出后 实际上格式为 数值形式的字符串
客户要求这三列的格式改为 数值格式 且千分位分隔 保留两位小数

在这里插入图片描述

分析原因

先看导出用到了什么工具 查看源码发现 导出 使用了 EasyExcel
在这里插入图片描述

立马想到 一般情况下导出实体的字段类型可能是String 才会导致 数字类型 在Excel中是 数值类型的字符串

去找导出实体对象 查看相应字段类型
在这里插入图片描述
很遗憾 并不是想象中的一般情况
这里的字段类型都是BigDecimal 按道理来说 导出的 数字 应该就是数字类型的

深入看了下代码 发现excel写入的过程涉及到不同列的权限显示问题 一些数据是 动态写入的 不是EasyExcel的简单通过对象导出
考虑到使用到的EasyExcel版本比较老 且需要设置 千分位 保留两位小数等 格式
在这里插入图片描述
就不再研究1.1.2版本的EasyExcel 了 (如果有感兴趣的或者研究过 EasyExcel实现这种功能的朋友 还请在评论区讨论下)

确定解决方案

既然Excel已经生成好了 那么就在已经生成好的Excel上再次处理 使用POI (很显然这种方式很不友好 消耗内存 浪费更多的时间去重新遍历Excel 但是可以快速的解决目前遇到的问题)

在使用POI 进行处理的时候又遇到了一个坑

又遇到坑

如果直接获取对应cell之后 获取String类型的数字 然后转成double 再塞到cell里面 最后设置千分位 保留两位小数 会发现不生效

  // 单元格样式
            CellStyle cellStyle = wb.createCellStyle();
            cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,##0.00"));
            cellStyle.setAlignment(HorizontalAlignment.LEFT); //水平居左
            
			String cellValue13 = cellOrigin13.getStringCellValue();
            if(StringUtils.isNotEmpty(cellValue13)){
                 double parseDouble = Double.parseDouble(cellValue13);
                 cellNew13.setCellStyle(cellStyle);
                 cellNew13.setCellValue(parseDouble);
              }

 @PostMapping(value = "/export")
@ApiOperation(value = "导出")
public void exportForDistributor(@ParamHide CustomerBilling customerBilling, @ParamHide HttpServletRequest request, @ParamHide HttpServletResponse response) {
        customerBilling.setExportData(true);
        String filePath = customerBillingService.exportData(customerBilling, CustomerBillingData.class);

        // 处理Excel 格式开始
        if (StringUtils.isNotEmpty(filePath)) {
            XSSFWorkbook wb = returnWorkBookGivenFileHandle(filePath);
            if (wb == null) {
                log.error("returnWorkBookGivenFileHandle 方法获取的 XSSFWorkbook 对象wb 为空");
                return;
            }
            // 获取工作表1
            XSSFSheet sheet1 = wb.getSheet("1");

            // 获取总行数
            int rowNum = sheet1.getPhysicalNumberOfRows();

            // 单元格样式
            CellStyle cellStyle = wb.createCellStyle();
            cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,##0.00"));
            cellStyle.setAlignment(HorizontalAlignment.LEFT); //水平居左

            if(rowNum > 6){
                // 此时才有数据
                // 第七行开始    第 N O P列  开票金额 到款金额  本单余额  需要进行格式处理   13  14   15   注意处理空值
                for (int i = 6; i < rowNum; i++) {
                    XSSFRow row = sheet1.getRow(i);
                    XSSFCell cellOrigin13 = row.getCell(13);
                    XSSFCell cellOrigin14 = row.getCell(14);
                    XSSFCell cellOrigin15 = row.getCell(15);

                    String cellValue13 = cellOrigin13.getStringCellValue();
                    if(StringUtils.isNotEmpty(cellValue13)){
                        double parseDouble = Double.parseDouble(cellValue13);
                        XSSFCell cellNew13 = row.createCell(13);
                        cellNew13.setCellStyle(cellStyle);
                        cellNew13.setCellValue(parseDouble);
                    }else {
                        // 如果为空则创建空的空格 格式也做相同处理
                        XSSFCell cellNew13 = row.createCell(13);
                        cellNew13.setCellStyle(cellStyle);
                    }

                    String cellValue14 = cellOrigin14.getStringCellValue();
                    if(StringUtils.isNotEmpty(cellValue14)){
                        double parseDouble = Double.parseDouble(cellValue14);
                        XSSFCell cellNew14 = row.createCell(14);
                        cellNew14.setCellStyle(cellStyle);
                        cellNew14.setCellValue(parseDouble);
                    }else {
                        // 如果为空则创建空的空格 格式也做相同处理
                        XSSFCell cellNew14 = row.createCell(14);
                        cellNew14.setCellStyle(cellStyle);
                    }

                    String cellValue15 = cellOrigin15.getStringCellValue();
                    if(StringUtils.isNotEmpty(cellValue15)){
                        double parseDouble = Double.parseDouble(cellValue15);
                        XSSFCell cellNew15 = row.createCell(15);
                        cellNew15.setCellStyle(cellStyle);
                        cellNew15.setCellValue(parseDouble);
                    }else {
                        // 如果为空则创建空的空格 格式也做相同处理
                        XSSFCell cellNew15 = row.createCell(15);
                        cellNew15.setCellStyle(cellStyle);
                    }
                    saveExcel(wb,filePath);
                }
            }
        }
          // 处理Excel 格式结束


        CommonUtil.downloadJxlExcel(request, response, filePath, "客户对账单.xlsx");
    }


 /**
     * 得到一个已有的工作薄的POI对象
     *
     * @return XSSFWorkbook 对象
     */
    private XSSFWorkbook returnWorkBookGivenFileHandle(String filePath) {
        XSSFWorkbook wb = null;
        InputStream inputStream = null;
        try {
            File file = new File(filePath);
            // 获得inputStream对象
            try {
                inputStream = new FileInputStream(file);
            } catch (IOException e) {
                log.error("获取模板输入流为空 e", e);
            }
            if (inputStream != null) {
                wb = new XSSFWorkbook(inputStream);
            }
        } catch (Exception e) {
            log.error("获取Excel文件出错", e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException ignore) {
                }
            }
        }
        return wb;
    }


    /**
     * 保存工作薄
     *
     * @param wb XSSFWorkbook对象
     */
    private void saveExcel(XSSFWorkbook wb, String filePath) {
        FileOutputStream fileOut;
        try {
            fileOut = new FileOutputStream(filePath);
            wb.write(fileOut);
            fileOut.close();
        } catch (IOException e) {
            log.error("保存工作薄出错 e", e);
        }
    }

重处理Excel

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/356563.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

layui框架学习(7:选项卡样式)

选项卡&#xff08;Tab&#xff09;在C/S程序和B/S程序中应用比较广泛&#xff0c;CSDN中也能看到选项卡的身影&#xff08;如下图所示&#xff09;。Layui内置多种Tab风格&#xff0c;支持删除选项卡、并提供响应式支持。Layui官方教程中主要介绍了选项卡相关的样式设置&#…

Windows Server 2016远程桌面配置全过程

镜像下载 系统镜像网址 本次下载的是 Windows Server 2016 (Updated Feb 2018) (x64) - DVD (Chinese-Simplified) 远程桌面配置 Step 1 在开始菜单搜索服务&#xff0c;打开服务器管理器&#xff0c;点击右上角的管理按钮 Step 2 添加角色控制&#xff0c;点击下一步 S…

如何描述建筑在新型电力系统中的基本特征?——现状与展望(刘晓华)

刘晓华等人 | 如何描述建筑在新型电力系统中的基本特征&#xff1f;——现状与展望 2022如何描述建筑在新型电力系统中的基本特征&#xff1f;——现状与展望 摘要 建筑领域是实现碳中和目标的重要部门&#xff0c;未来零碳能源系统中建筑有望成为集能源生产、消费、调蓄“三…

【Redis】一、CentOS64 安装 Redis

1.下载redis https://download.redis.io/releases/2.将 redis 安装包拷贝到 /opt/ 目录 最好自己创建一个文件夹 3.解压 tar -zvxf redis-6.2.1.tar.gz4. 安装gcc yum install gcc5. 进入目录 cd /opt/redis/redis-6.2.1/6. 编译 make7.执行 make install 进行安装 8. …

Redis面试题:1~2亿条数据需要缓存,请问如何设计这个存储案例

目录 前言 一、哈希取余分区 优点 缺点 二、一致性哈希算法分区 背景 步骤 ① 算法构建一致性哈希环 ② 服务器IP节点映射 ③ key落到服务器的落键规则 优点 ① 容错性 ② 扩展性 缺点 三、哈希槽分区 前言 单机单台100%不可能&#xff0c;肯定是分布式存储&am…

【深度递归网络超分辨率双三次插值图像】

MuRNet: A deep recursive network for super resolution of bicubically interpolated images &#xff08;MuRNet:深度递归网络超分辨率双三次插值图像&#xff09; 在许多实际情况下&#xff08;如打印机设备和相机内插值&#xff09;&#xff0c;只有低分辨率图像的插值版…

SpringBoot+WebSocket+VUE实现一个简单的聊天机器人

文章目录前言SpringBootwebsocket引入jar包在Spring Boot的配置类中添加WebSocket配置创建聊天机器人处理器创建WebSocket处理器服务端测试启动springboot服务调用测试方法&#xff0c;能收到消息vue websocket使用代码地址前言 要实现一个简单的聊天机器人&#xff0c;可以使…

深入前端尾递归

在深入探讨前端尾递归前&#xff0c;我们先来了解递归和尾调用两个概念 递归 在函数内部调用自身&#xff0c;一般来说递归有两个状态 递归状态&#xff08;继续递归&#xff09;最终状态&#xff08;终止递归&#xff09; 递归式方法可以被用于解决很多的计算机科学问题&a…

QT学习记录(六)类对象属性

类对象属性用来描述类对象的一些信息和当前的状态。类对象属性可以由类的编写者在编写类的时候定义&#xff0c;也可以由类的使用者在使用对象的时候定义。 由类的编写者定义 QPROPERTY()宏就是用来定义一个对象属性。 以第二行属性举例 QPROPERTY(bool enabled READ isEnabl…

Makefile基础使用和实战详解

Makefile基础使用和实战详解一、基础1.1、简单的Makefile1.2、多文件编译1.3、伪对象.PHONY二、变量2.1、自动变量2.2、特殊变量2.3、变量的类别2.4、变量及其值的来源2.5、变量引用的高级功能2.6、override 指令三、模式四、函数4.1、addprefix 函数4.2、filter函数4.3、filte…

【JavaWeb】网络层协议——IP协议

目录 IP协议结构 IP地址管理 特殊IP 解决IP地址不够用 动态分配IP地址 NAT网络地址转换 IPV6 IP协议结构 版本&#xff1a;就是IP协议的版本号。目前只有 4 和 6。这里介绍的是IPV4 首部长度&#xff1a;单位是4字节。于TCP首部长度完全一致&#xff0c;也是可变的&…

python--pygame实现各级菜单栏目设置

随着学期的开始&#xff0c;同学们也即将进入计算机相关课程的课程设计了&#xff0c;对于python课程设计的小伙伴&#xff0c;可能有些是需要利用pygame来写应该小游戏的&#xff0c;因为最近很多小伙伴同学也在想我要一些基于python的pygame模块做的游戏项目&#xff0c;此外…

SpringBoot 2.x 实战专题——SpringBoot 2.6.X版本循环依赖(内含教学视频+源代码)

SpringBoot 2.x 实战专题——SpringBoot 2.6.X版本循环依赖&#xff08;内含教学视频源代码&#xff09; 教学视频源代码下载链接地址&#xff1a;https://download.csdn.net/download/weixin_46411355/87462754 目录SpringBoot 2.x 实战专题——SpringBoot 2.6.X版本循环依赖…

React SSR

ReactDOMServer 参考链接&#xff1a;https://zh-hans.reactjs.org/docs/react-dom-server.html ReactDOMServer 对象允许你将组件渲染成静态标记。通常&#xff0c;它被使用在 Node 服务端上 // ES modules import * as ReactDOMServer from react-dom/server; // CommonJS v…

全栈之路-前端篇 | 第二讲.基础前置知识【应用服务端与编程语言】学习笔记

欢迎关注「全栈工程师修炼指南」公众号 点击 &#x1f447; 下方卡片 即可关注我哟! 设为「星标⭐」每天带你 基础入门 到 进阶实践 再到 放弃学习&#xff01; 涉及 企业运维、网络安全、应用开发、物联网、人工智能、大数据 学习知识 “ 花开堪折直须折&#xff0c;莫待无花…

谓词exsits用法及与in的使用区别

exists用法 大白话的说&#xff0c;exists的执行&#xff0c;是依次拿外层表的每条记录&#xff0c;去和exsits后的子查询表按你所定义的运算规则&#xff08;如果有的话&#xff09;做运算&#xff0c;如果存在结果&#xff0c;也就是有返回数据&#xff0c;无论这部分数据有…

MySQL中使用索引优化

目录 一.使用索引优化 数据准备 避免索引失效应用-全值匹配 避免索引失效应用-最左前缀法则 避免索引失效应用-其他匹配原则 1、 2、 3、 4、 5、 一.使用索引优化 索引是数据库优化最常用也是最重要的手段之一,通过索引通常可以帮助用户解决大多数的MySQL的性能优化…

Pandas库入门仅需10分钟

数据处理的时候经常性需要整理出表格&#xff0c;在这里介绍pandas常见使用&#xff0c;目录如下&#xff1a; 数据结构导入导出文件对数据进行操作 – 增加数据&#xff08;创建数据&#xff09; – 删除数据 – 改动数据 – 查找数据 – 常用操作&#xff08;转置&#xff0…

Linux 配置RAID组

目录 配置RAID&#xff08;软件RAID&#xff09; 创建RAID组 RAID中出现坏盘如何操作 RAID 添加热备盘 删除RAID组 RAID所解决的问题 提升硬盘的I/O吞吐率 提高硬盘的读写能力 提高硬盘的安全性 进行备份 减少硬盘成本 RAID级别 存储RAID——RAID级别_静下心来敲木鱼的博…

Spring Boot中使用@Autowire装配接口是怎么回事?

在学习使用Spring Boot框架时候&#xff0c;发现了一个特别的现象UserMapper是一个接口&#xff0c;在另一个类中好像直接使用Autowired装配了一个UserMapper对象&#xff1f;&#xff1f;&#xff1f;我纳闷了一会儿&#xff0c;接口居然可以直接实例对象吗&#xff1f;根据我…