参考:https://blog.csdn.net/hanyi_/article/details/118117484,https://blog.csdn.net/sunyuhua_keyboard/article/details/125482353,https://lhalcyon.com/alpine-font-issue/,https://github.com/alibaba/easyexcel/issues/1476(没字体)

首先吧,因为每周列会需要看用户使用情况报表,我这边需要把整合好的数据整理下给产品,但我比较追求便捷化,想一次性做成并导出成excel,上回直接拿导出的sql已经够难看了,这回想做个全面自动化,接着就是行动,需求是看到用户使用的多个设备的不同使用时长情况,这个其实很简单无非就是把用户跟设备一条条全查出来,挨的近些到时候直接合并并居中就好了,昨天已经做成了导出一条条数据的excel,今天就是想在原来基础上合并并居中再上线测试。

于是我开始了第一步,找了好多easyExcel合并单元格的文章最终确定了一个使用strategy策略用Excel.write方式去实现的,同时辨别如果是相同的就合并单元格

以下是CustomMergeStrategy的代码



import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress; import java.util.List; public class CustomMergeStrategy implements CellWriteHandler {
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
if (isHead){
//如果是表头不做处理
return;
}
//如果当前是第一行不做处理
if(relativeRowIndex==0){
return;
} //获取当前行下标,上一行下标,上一行对象,上一列对象
Sheet sheet = cell.getSheet();
int rowIndex = cell.getRowIndex();
int rowIndexPrev=rowIndex- 1;
Row row = sheet.getRow(rowIndexPrev);
Cell cellPrev = row.getCell(cell.getColumnIndex()); //得到当前单元格值和上一行单元格
// Object cellValue =cell.getCellType()== CellType.STRING?cell.getStringCellValue() : cell.getNumericCellValue();
// Object cellValuePrev =cellPrev.getCellType()==CellType.STRING?cellPrev.getStringCellValue():cellPrev.getNumericCellValue();
String cellValue =cell.getCellType()== CellType.STRING?cell.getStringCellValue() : String.valueOf(cell.getNumericCellValue());
String cellValuePrev =cellPrev.getCellType()==CellType.STRING?cellPrev.getStringCellValue():String.valueOf(cellPrev.getNumericCellValue()); System.out.println("cellValuePrev = " + cellValuePrev);
System.out.println("cellValue = " + cellValue);
//如果当前单元格和上一行单元格值相等就向下执行合并
// 这边if不能调顺序
if (StringUtils.isEmpty(cellValue) && StringUtils.isEmpty(cellValuePrev)){
return;
}
if (!cellValue.equals(cellValuePrev)) {
return;
} //获取已有策略
List<CellRangeAddress> mergedRegions = sheet.getMergedRegions(); boolean mergen=false;
for (int i = 0; i < mergedRegions.size(); i++) {
CellRangeAddress cellAddresses = mergedRegions.get(i);
if(cellAddresses.isInRange(rowIndexPrev,cell.getColumnIndex())){
sheet.removeMergedRegion(i);
cellAddresses.setLastRow(rowIndex); sheet.addMergedRegion(cellAddresses);
mergen=true;
break;
} }
if (!mergen){
CellRangeAddress cellAddresses = new CellRangeAddress(rowIndexPrev, rowIndex, cell.getColumnIndex(), cell.getColumnIndex());
sheet.addMergedRegion(cellAddresses); } } }

然后被我业务代码调用实现

EasyExcel.write("/app/static/用户统计"+dateStr+".xlsx")
.head(UserTimeLengthExcelItemDTO.class)
.registerWriteHandler(new CustomMergeStrategy())
.sheet("用户统计").doWrite(tmpUserTimeLengthExcelItemDTOList);

ok以上代码就简单实现了excel导出和合并单元格,接着我看到

这个样子有点丑啊,至少要居中吧,于是找了很多甚至还想多谢个策略类然后把add到registerWriteHandler这个里面去,不过没有成功,一直报错,继续想办法不断百度百度,都不大行,那就算了我就google看下好了哇,google出来第一个说加个注解就行了,于是我便到导出dto上面加

@HeadStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)

在执行下果然可以,看下效果图,

发现还有点别扭啊,这个字居中是居中了,但是在底部不好看啊,继续找上下居中,查了下还是注解上加

@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, verticalAlignment = VerticalAlignmentEnum.CENTER)//内容样式

这样子就可以了嘛,发现还有问题,空的和空的合并了,但是他们不是一个用户下的,没有截图,于是我想应该要加个判断如果是空的就不要合并,看了下逻辑他只是对如果是空就就合并做了判断,我就在上头加了个空的判断吗,ok这样子一个令人满意的报表就生成好了。

上传到线上,然后尝试生成excel,看到报错

ERROR c.c.platform.core.exception.GlobalExceptionHandler - 未知异常!原因是:ExcelGenerateException: java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11FontManager

没找到,按我在本地时候以为是文件夹不存在或者没有权限,我就去改保存的文件夹路径,前后改了3次都不成功,于是我好好看了报错内容再去google上查下发现有人说这个是没有找到字体的原因,好吧,没有字体我就装字体好吧,先apt updatealiyun真的慢等了很久终于好了,再执行命令

apt-get install -y fonts-dejavu libfreetype6-dev fontconfig

也等了好久终于好了,然后尝试继续报错,我想不应该呀,我先重启容器再说,果然我再次请求生成就可以了,好吧这样子的话我只能把当前容器再打个镜像以后就以这个新镜像跑了,想起之前有个人评论说的可能是你的镜像是silm的原因,我想我要不要看下Dockerfile里用的是啥,果然看到用的FROM openjdk:17-slim,乖乖,保底的有了,我要把这个silm删了再试试,等了一会容器起来了,在尝试生成下,成功!

md,折腾了靠一天,终于好了,拜拜,去搞scoop了

关于easyExcel导出文字合并居中和服务器导出失败踩了一天的坑的更多相关文章

  1. poi合并单元格同时导出excel

    poi合并单元格同时导出excel POI进行跨行需要用到对象HSSFSheet对象,现在就当我们程序已经定义了一个HSSFSheet对象sheet. 跨第1行第1个到第2个单元格的操作为 sheet ...

  2. springMVC中使用POI方式导出excel至客户端、服务器实例

    Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. 这里的方法支持导出excel至项目所在服务器,或导 ...

  3. C#+OpenGL+FreeType显示3D文字(1) - 从TTF文件导出字形贴图

    C#+OpenGL+FreeType显示3D文字(1) - 从TTF文件导出字形贴图 +BIT祝威+悄悄在此留下版了个权的信息说: 最近需要用OpenGL绘制文字,这是个很费时费力的事.一般的思路就是 ...

  4. icon图标和文字整体居中在button按钮

    icon图标和文字整体居中在button按钮 icon图标和文字整体居中 一般我们常做的button按钮是文字居中 现在这个需要icon图标和文字一起居中在背景色 <a href="# ...

  5. angular2^ typescript 将 文件和Json数据 合并发送到服务器(2.服务端)

    nodejs 中使用框架 express web框架 multer 文件接受 直接贴代码了,我就不解释了 "use strict"; exports.__esModule = tr ...

  6. 怎么让Word形状里的文字上下左右居中

    怎么让Word形状里的文字上下左右居中? 第一:左右居中,用段落居中方法: 第二:上下居中,选定图形,单击鼠标右键并选择“设置形状格式”,在选项卡的“文本框”中,选择中部对齐 效果图:

  7. css垂直居中怎么设置?文字上下居中和图片垂直居中

    css 居中分css垂直居中和css水平居中,水平居中平时比较常用,这里我们主要讲css上下居中的问题.垂直居中又分为css文字上下居中和css图片垂直居中,下面我们就分别来介绍一下. css文字上下 ...

  8. 小程序canvas中文字设置居中锚点

    小程序中经常会遇到要生成图片的需求,图片一般会加上用户的头像和昵称之类的,头像只需要把腾讯域名添加到request和download列表中,使用wx.getImageInfo()就可以缓存到本地,成功 ...

  9. i8浏览器不支持placeholder属性解决办法,以及解决后,文字不居中问题

    这里想实现的效果是:设置和移除文本框默认值,如下图鼠标放到文本框中的时候,灰字消失. 1.可以用简单的方式,就是给input文本框加上onfocus属性,如下代码: <input id=&quo ...

  10. RadioButton的drawableTop图片文字不居中

    在安卓应用的开发中,一般普通应用用到最多的就是底部放一个RadioGroup实现切换的布局,今天在实现的时候,却出现了底部RadiButton的drawableTop图片及文字无法居中的情况,经过对比 ...

随机推荐

  1. idea破解《当脚本破解方式无效或不方便执行时可采用此方法》

    idea新版破解有时会各种不成功,很耽误事.所以,再次整理一个相对省事有效的办法.<此方式为修改idea启动脚本破解方式>内容如下: 一:下载此激活工具 二:按下图从下载的文件中找到箭头标 ...

  2. 火山引擎ByteHouse:如何为OLAP设计高性能向量检索能力?

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 背景 随着LLM技术应用及落地,数据库需要提高向量分析以及AI支持能力,向量数据库及向量检索等能力"异军 ...

  3. windows 10 制作招聘系统镜像

    我一直以来都有个想法,就是彻底攻破重装系统这块,但是一直没有时间 没有攻破,今天终于攻破.参考了文章:https://www.cnblogs.com/del88/p/12667087.html 需求: ...

  4. 解析Sermant热插拔能力:服务运行时动态挂载JavaAgent和插件

    本文分享自华为云社区<服务运行时动态挂载JavaAgent和插件--Sermant热插拔能力解析>,作者:华为云高级软件工程师 栾文飞 一.概述 Sermant是基于Java字节码增强技术 ...

  5. 如何做好一个基础的搜索功能?记一个因客户大数据量而导致的后发先至Bug

    壹 ❀ 引 上篇文章算是开了一个新系列,因为工作缘故,我基本每天都在跟各式各样的bug打交道.其实站在一个开发的角度,我想每个人应该都更喜欢创造新代码,创造新bug,而不是每天都泡在茫茫代码海洋中定位 ...

  6. JS leetcode 翻转字符串里的单词 题解分析

    壹 ❀ 引 今天来做一道难度中等,但实际难度并不是很高的题目,题目来源leetcode151. 翻转字符串里的单词,题目描述如下: 给定一个字符串,逐个翻转字符串中的每个单词. 示例 1: 输入: & ...

  7. NC16681 [NOIP2003]加分二叉树

    题目链接 题目 题目描述 ​ 设一个n个节点的二叉树tree的中序遍历为(l,2,3,-,n),其中数字1,2,3,-,n为节点编号.每个节点都有一个分数(均为正整数),记第j个节点的分数为di,tr ...

  8. 【Android】使用Binder实现进程间通讯简单案例

    1 前言 使用AIDL实现进程间通讯简单案例 和 使用AIDL实现进程间传递对象案例 中介绍了使用 AIDL 进行进程间通讯,文中提到在编写完 aidl 文件(如:IMessageManager.ai ...

  9. Springboot实现remember-me记住我功能

    1.什么是remeber-me? remeber-me即记住我功能,是我们在登录web系统时的常见勾选项.当我们登录一个web系统时除了输入常规的用户名.密码后还可以勾选记住我选项(假设该系统提供了该 ...

  10. spring boot+bootstrap实现动态轮播图实战

    1.bootstrap轮播图 最近开发了个网站需要用到轮播图,正好前端用的是Bootstrap,这里就实战一下. 水平一般能力有限,仅供参考. 前提条件: bootstrap4.5 jquery 3张 ...