专栏首页Java深度编程框架源码调试实战之easypoi异常解决方案精讲

框架源码调试实战之easypoi异常解决方案精讲

最近有个同事遇到了个棘手的问题,easypoi导出文件出了bug,却不知道是怎么回事,无从下手,无可奈何,由于事态紧急,只能火急火急的求助于我。我问他:“开发的时候功能调通了吗?测试阶段通过了吗?” 同事均回答:“之前测试都没有问题,之前的账号数据可以导出,却唯独是这个不行。我仔细看了我写的代码,根本就不觉得有什么问题啊,不知道原因出在哪里……”

导出的错误文件如下:

正常导出的文件应该是这样的:

在详细了解情况以后我便开始了我的源码探究之路。确实,很多人在遇到此类问题的时候往往想到的就是自己的代码有问题,或者是使用框架不当,未按框架的规则来编写代码才导致出现问题,而极少会想到是自己使用的框架本身就有问题,本身就有bug。要知道框架也是人写的,是人就会犯错!更何况像easypoi是近年来才出现的新型框架,还不太成熟,潜在的bug多,出错的概率就更大些。

我帮人解决问题的同时,我习惯性的是希望帮助人学习到解决问题的能力,而不是仅仅解决这个问题。正所谓授人以鱼不如授人以渔,所以我便亲自在这位向我求助的同事面前掩饰了一番,如何去解决这个问题。

首先,我们将导出正确,和导出错误的两组参数进行收集,然后使用postMan分别进行调制,在关键代码初打上断点,如下图:

从上图可以看出,导出的关键代码在workbook.write(outputStream),于是我先执行能正常导出的debug,教同事用正常的参数去逐步熟悉整体运行的过程;然后我再执行第二遍debug,这时候传入错误导出的参数,当执行到关键代码处的时候观察两者的区别,从而判断问题所在。经过调试,我发现错误的代码再执行到单sheet时,执行代码

Sheet sheet = workbook.getSheet(param.getExportParams().getSheetName());

结果获取到了一个空对象,然后正常能导入时不时空对象,如下:

那么问题就出在这里,正是由于行对象sheet对象为null才导致了后面的报错。

这时候就应该再进入更深层次的代码,探究为何传入为何有时候能获取到sheet对象,有时候却不行。

我们点开 workbook.getSheet(param.getExportParams().getSheetName())方法,继续打断点:

打开源码方法时,常出现的需要选择进入那个实现方法,这时候很多初级程序员就很懵逼,我到底应该进去那个方法啊?有可能会一时半会摸不着头脑,只能一个试。其实这也是有技巧的,这个技巧就是追溯对象的源头。上面是使用workbook调用的,我们往上寻找,是如何得到这个对象的,代码在

//单sheet导出
 workbook = ExcelExportUtil.exportExcel(param.getExportParams(), param.getClazz() , param.getList());

那么我们再进入ExcelExportUtil.exportExcel()方法,如下:

从上可以看出workbook对象是XSSFWorkbook类型的,那么我们使用workerbook对象调方法的时候调的就必定是XSSFWorkbook下的方法,于是就知道了进入workbook.getSheet(param.getExportParams().getSheetName())方法应该选择第三个XSSFWorkbook类型的。其实除了此方式外,还可以再往前追溯入参,往往也能找到答案,本例子中的前端封装参数的时候是指定了ExcelType的类型的,如下图:

通过以上两种途径便可以知道框架的源码方法,众多实现中究竟应该调用那一个源码方法,快速定位方法,能大大节约一个个尝试的时间成本。

接着我们进入gerSheet()方法进一步调试:

我们可以看到sheet页对象的名称和传入的名称不相等,迭代器没有下一个值,于是便return null了:

而正常参数下是能够直接获取到sheet对象的:

正常参数下,判断为false,不会再次进入do while循环中

整个过程的逻辑如下:1.首先创建了迭代器;2.执行了一次do……while循序,在循环中判断迭代器是否还有下一个值,第一次的时候有下一个值于是没有返回null,而是创建了sheet对象;3.第一次循环执行完毕后,才开始判断条件(do……while循环是先执行一次循环,再判断条件),这时候入参名称和sheet的名称相同,取反后便不成立,于是返回了有值的对象,反之则再次进入了循环,这时候迭代器已经没有下一个值了,于是就返回了null。

既然知道了以上的逻辑,那么就已经定位清楚问题了,问题的根源就在于名称不相等了,为啥名称不相等了呢? 这时候我们仔细观察两个名称的值,发现sheet的名称和入参名称name相比,是取了name的前31位字符,为什么会这样子呢?

我们打开.xlsx文档,输入页码名称,发现也是最大只能输入31个字符的,如下图:

原来是因为xlsx文档限制了最大的页码名称只能输入31个字符,所以框架自动截取了前31个字符。这坑爹的框架也不说处理全面一点,留下了这个bug坑苦了广大程序员,哈哈……

既然知道了这个问题,那么如何修复这个框架的bug了? 按理来说这是框架的bug,应该改框架的源码最正确,可这样得反编译后,修改编码了再打包进去,很费时费力。而在入参时每个都做判断会增大代码量,也容易忽视这个问题。介于我已经封装了一个公用的导出组件类,那么我的思路是在公共组件进行处理。

将思路告诉向我求助的同事后,他便写了下面的代码:

 //单sheet页面设置样式
     String sheetName = param.getExportParams().getSheetName();
     if(sheetName.length() > 31) {
         sheetName = sheetName.substring(0,31);
     }
     Sheet sheet = workbook.getSheet(sheetName)

我就点评说这样写并不好,因为你只是把入参的值给改了,但是原参数param中依然保留了旧的,可能出现问题的参数,依然容易引发其它问题,这是一个变成思想的问题,代码应该这么写:

    //单sheet页面设置样式
    //生成Sheet和提示信息
    //xlsx文件的sheet页名称最大只支持31个长度,当传参sheet名称长度>31时,将会无法获取sheet对象,所以需要截取
    String sheetName = param.getExportParams().getSheetName();
    if(sheetName.length() > 31) {
         param.getExportParams().setSheetName(sheetName.substring(0,31));
    }
    Sheet sheet = workbook.getSheet(param.getExportParams().getSheetName());

上面的这种写法才是正确的,更能体现变成思想能力,从源头消除隐患。

总结:经过此次框架的bug,相信遇到的人都应该明白了,不要太过于相信框架而质疑自己的代码有错,当你找不到自己的错误的时候,就该想想是不是自己使用的框架有问题了。

本文分享自微信公众号 - Java深度编程(JavaDeep),作者:龚文学

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-09-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 框架源码调试实战之easypoi异常解决方案精讲

    最近有个同事遇到了个棘手的问题,easypoi导出文件出了bug,却不知道是怎么回事,无从下手,无可奈何,由于事态紧急,只能火急火急的求助于我。我问他:“开发的...

    Java深度编程
  • SQL优化之LIMIT语法, limit n,m 和 limit n有什么区别?

    在某些面试题中会遇到这样的问答或笔试题:“limit 0,1 和 limit 1有什么区别?” 要准确回答这个问题就等深入明白limit一个参...

    Java深度编程
  • Java 8新特性 -- 函数式接口

    JDK1.8提供一种特殊的接口 -- 函数式接口(Functional Interface),它与普通接口相比,就是比普通的接口多了一个方法。 函...

    Java深度编程
  • ​OpenGL 学习系列---投影矩阵

    OpenGL 在观察空间转换到裁剪空间时,需要用到投影矩阵。而在着色器脚本中,也需要提供一个投影矩阵给对应的 u_ProjectionMatrix变量。

    glumes
  • nginx+php-fpm独立节点的部署wordpress笔记

    今天同学说他分开部署nginx+php-fpm出现了问题,总是报502,正好我也没试验过,于是自己也做了一遍,也遇到些问题,记下来以备以后用到。

    二狗不要跑
  • 揭密:微信红包前传

    春节已经过去,火爆一时的微信红包也渐渐归于平静。 腾讯官方公布的一组数据颇能说明问题: 从除夕到初八,超过800万用户参与了抢红包活动,超过4000万个红包被领...

    腾讯大讲堂
  • 观点 | Waymo自动驾驶车每天行驶25000英里,但CEO却告诉我们距离成功还远

    纽约 3 月 27 日,Waymo 首席执行官约翰·科拉菲克(John Krafcik)站在一辆捷豹 I-Pace 旁。自动驾驶汽车先驱 Waymo 将从捷豹路...

    机器之心
  • 数值微分|理查森外推法

    理查森外推法( Richardson extrapolation)是一种提高某些数值过程精度的简单方法,在数值方法中广泛应用。

    fem178
  • Android 实现图片转二进制流及二进制转字符串

    以上这篇Android 实现图片转二进制流及二进制转字符串就是小编分享给大家的全部内容了,希望能给大家一个参考。

    砸漏
  • 谷歌自动驾驶项目开始帮助超市接送顾客

    Alphabet(谷歌母公司)旗下的Waymo公司表示,该公司正开始尝试将沃尔玛超市的顾客接送到位于亚利桑那州菲尼克斯的沃尔玛门店。

    人工智能快报

扫码关注云+社区

领取腾讯云代金券