热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

postman怎么调试request.getattribute_框架源码调试实战之easypoi异常解决方案精讲

最近有个同事遇到了个棘手的问题,easypoi导出文件出了bug,却不知道是怎么回事,无从下手,无可奈何,由于

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

导出的错误文件如下:

9e0f77ed5fe15f215387c20a316dcf3e.png

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

779843199214be50bec1744cefafcb86.png

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

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

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

8811deb56bd4c9f2475885def4d3a037.png

68080f2b29d36526a3ecaee740bd97ed.png

92ff161f98d41eb7429103c31b0341ce.png

305b244c9ed0abf1ff7c168711505e6b.png

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

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

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

6ad0b9866254606e06301d148dfbfb0d.png

9ba7ed800d3ba35c8dc5a7c5ee6fc674.png

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

067e83bececd363acf7bfec713e75822.png

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

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

5f7e82936a8215927a1ebbdaa1ec27e6.png

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

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

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

1d130454829aae0773f4c0071a94b9ed.png

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

f2a979b5f8787f10782653b1d93c3902.png

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

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

80b9c6ca6450a174aa77d6d51bd71959.png

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

a82769ae347da4b3ddf48bdaf3269106.png

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

e3fffb62cae302c718f00ac8ed600bbe.png

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

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

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

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

baaa7cff811a9c45cfb24f3c9cf82289.png

原来是因为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,相信遇到的人都应该明白了,不要太过于相信框架而质疑自己的代码有错,当你找不到自己的错误的时候,就该想想是不是自己使用的框架有问题了。

fc6a5fcf7801c52447ad2aa439208eba.png




推荐阅读
  • Python已成为全球最受欢迎的编程语言之一,然而Python程序的安全运行存在一定的风险。本文介绍了Python程序安全运行需要满足的三个条件,即系统路径上的每个条目都处于安全的位置、"主脚本"所在的目录始终位于系统路径中、若python命令使用-c和-m选项,调用程序的目录也必须是安全的。同时,文章还提出了一些预防措施,如避免将下载文件夹作为当前工作目录、使用pip所在路径而不是直接使用python命令等。对于初学Python的读者来说,这些内容将有所帮助。 ... [详细]
  • 如何用JNI技术调用Java接口以及提高Java性能的详解
    本文介绍了如何使用JNI技术调用Java接口,并详细解析了如何通过JNI技术提高Java的性能。同时还讨论了JNI调用Java的private方法、Java开发中使用JNI技术的情况以及使用Java的JNI技术调用C++时的运行效率问题。文章还介绍了JNIEnv类型的使用方法,包括创建Java对象、调用Java对象的方法、获取Java对象的属性等操作。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • PHP反射API的功能和用途详解
    本文详细介绍了PHP反射API的功能和用途,包括动态获取信息和调用对象方法的功能,以及自动加载插件、生成文档、扩充PHP语言等用途。通过反射API,可以获取类的元数据,创建类的实例,调用方法,传递参数,动态调用类的静态方法等。PHP反射API是一种内建的OOP技术扩展,通过使用Reflection、ReflectionClass和ReflectionMethod等类,可以帮助我们分析其他类、接口、方法、属性和扩展。 ... [详细]
  • 本文介绍了在Go语言中可见性与scope的规则,包括在函数内外声明的可见性、命名规范和命名风格,以及变量声明和短变量声明的语法。同时,还介绍了变量的生命周期,包括包级别变量和局部变量的生命周期,以及变量在堆和栈上分配的规则和逃逸分析的概念。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
  • JavaWeb中读取文件资源的路径问题及解决方法
    在JavaWeb开发中,读取文件资源的路径是一个常见的问题。本文介绍了使用绝对路径和相对路径两种方法来解决这个问题,并给出了相应的代码示例。同时,还讨论了使用绝对路径的优缺点,以及如何正确使用相对路径来读取文件。通过本文的学习,读者可以掌握在JavaWeb中正确找到和读取文件资源的方法。 ... [详细]
  • ShiftLeft:将静态防护与运行时防护结合的持续性安全防护解决方案
    ShiftLeft公司是一家致力于将应用的静态防护和运行时防护与应用开发自动化工作流相结合以提升软件开发生命周期中的安全性的公司。传统的安全防护方式存在误报率高、人工成本高、耗时长等问题,而ShiftLeft提供的持续性安全防护解决方案能够解决这些问题。通过将下一代静态代码分析与应用开发自动化工作流中涉及的安全工具相结合,ShiftLeft帮助企业实现DevSecOps的安全部分,提供高效、准确的安全能力。 ... [详细]
  • AFNetwork框架(零)使用NSURLSession进行网络请求
    本文介绍了AFNetwork框架中使用NSURLSession进行网络请求的方法,包括NSURLSession的配置、请求的创建和执行等步骤。同时还介绍了NSURLSessionDelegate和NSURLSessionConfiguration的相关内容。通过本文可以了解到AFNetwork框架中使用NSURLSession进行网络请求的基本流程和注意事项。 ... [详细]
  • 前段时间做一个项目,需求是对每个视频添加预览图,这个问题最终选择方案是:用canvas.toDataYRL();来做转换获取视频的一个截图,添加到页面中,达到自动添加预览图的目的。 ... [详细]
  • 浅解XXE与Portswigger Web Sec
    XXE与PortswiggerWebSec​相关链接:​博客园​安全脉搏​FreeBuf​XML的全称为XML外部实体注入,在学习的过程中发现有回显的XXE并不多,而 ... [详细]
author-avatar
jizi456
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有