八、调试过程中的主要问题、难点以及解决过程
实话说,在调试的过程中我遇到了很多问题,也查阅了很多技术博客,这之中有些确实能解决问题,而有些则是查阅了很多博客,尝试了很多方法还是没能解决问题,或者说出现了另一个问题,对此,我也渐渐摸索出了一套查找解决bug的方法,收获还是蛮大的。
以下列举了我调试中的几个主要问题和解决过程。
1.如何组织各个模块?
我一开始是采用递归循环的方式,但仔细一想,不对!经过我不断调试改进,最终用"套娃"的方式解决了问题,详细思路可以回到 第五部分、主要功能模块的算法流程图 去查看。
2.如何让整个项目有条不紊,井然有序?
整个项目累计代码总量超过千行,如果代码之间逻辑不清晰,关系复杂,那么这个项目调试,后期维护将变得举步维艰。
那么如何做到有条不紊,井然有序呢?
首先要做到项目结构清晰,可以像下面这样,实体类和实体类放在一起,工具类单独放在一起,资源配置文件放在一起,做到项目结构条理清晰。
其次,要做到代码封装抽象,具体做法就是把复用性高的代码抽离出来,封装成一个工具类,比如我要每个模块都有打印图书信息结果的需求,那么我们完全可以把它封装起来,比如这里我就把它封装成Displayer工具类,其内部有两个方法,如下图:
可以看到Displayer类有两个方法,但方法名其实都是show,只是针对不同情况进行重载,让方法用起来更加方便。这里还有个小细节,就是方法都是采用静态的方式,因为这里并没有要初始化的数据,所以采用静态,这样可以让代码调用的时候并不需要实例化即可调用其内的方法,让工具类使用起来就更加方便。
3.Maven项目,Mybatis框架,IDEA 的坑
上图是我在调试遇到的一个问题,可以看到程序报了Mapped Statements collection does not contain value for xxx的异常,这很明显是mybatis框架报的异常,通过报错信息大概猜测是mybatis XXX容器内不包含我写的Mapper(因为那时候我还不知道Mapped Statement是什么东西),然后我就无脑将这段报错信息贴到百度上搜,确实有很多博客记录了此错误及解决方法,我截了一个下来,如图:
但实际上我按照博客上一个个去做,并没有解决问题,这时候我已经花了一个下午时间去查找,问题没解决,倒是把mybatis框架复习了一遍。
苦思之下,我开始逐步调试,以下是我的思考过程:
因为问题肯定出在mybatis框架上,所以我逐步调试,但是呢,我又不懂mybatis源码,看得云里雾里。不过我之前自学Java的时候,跟着视频写过一个类似mybatis的框架------SORM框架(不过功能肯定没mybatis框架复杂,是个小型版的框架),做完后学了其他知识后,自己又回头帮它迭代优化了一下,增加了新的功能,优化了结构。
这段经历让我能大概理解mybatis框架的一些行为,比如在这个地方我就注意到了mappedStatement对象size为0。这时我就猜测这应该是框架本身并没有读取到我写的sql语句,那是由什么造成的呢?
这时候我就开始测试,不用接口类的方式(因为创建实体类也是mybatis框架底层做的),为了缩小问题的范围,我们采用原始的方式(但不是原生jdbc),发现还是这个错误,然后我开始怀疑mapper注册问题
这里我原本是采用包扫描的方式注册,然后我开始尝试用指定路径文件方式去注册
然后异常变了,说找不到这个文件
好家伙,之前包扫描的时候报的是Mapped Statements collection does not contain value for xxx,现在直接报没找到这个文件!
这时候我就开始思考为什么?
为什么我用包扫描的方式就不报错呢?而用具体的文件路径就报错呢?
真的是包扫描时找到了xml文件而具体文件路径没找到吗?
不对,不是这样的,换个角度讲,包扫描没扫描到,会报错吗?不会,那问题区间缩小,很可能就是因为xml文件路径的问题。而其他配置文件是找到了的,不然它根本不会提示找不到(路径是写在mybatis-config.xml文件里的),既然我们确定了问题所在,这时候我们就需要尝试改变路径
这时候我再去查博客,搜索的不是异常信息,而是配置文件的路径该怎么写?
在搜索的过程中我逐渐意识到我的项目结构可能与别人不同,所以我在搜索时加了Maven限定词,好家伙,不搜不知道,一搜我找到了原因所在。
原来Maven项目编译时会把文件全都输出到Target文件夹下面
而默认情况下配置文件只会把resource文件夹下面的配置文件输出,这就造成Java文件夹下面的Mapper文件根本不会输出到target里,这样当然就找不到了,于是我修改了Maven项目中核心配置文件pom.xml信息,加入了下面的配置
然后呢?
还是找不到…
本着不抛弃不放弃的精神,我开始关注target文件夹的文件结构
什么,居然有两个com.dreamchser,这是为什么呢?
然后我开始测试加百度,然后发现了IDEA的神坑之处------当我们创建一个包时,com.dreamchser和com/dreamchaser是不同的!
com.dreamchaser就是指第二个圈里的包,com/dreamchaser指的是第一个圈里的包
.和/的差别真的是坑死我我了!
我仔细思考了下,之前查询博客的时候,确实有博客提到idea中创建包时/和.是不一样,但当时我以为我的mapper是被读取进去了,所以没在意,只是检查了其他部分,知道后面调试运行底层源码时MappedStatement这个对象的size=0,通过字面意思猜测mybatis实际上是没有读取进去的,进而开始了这方面的排查,最终找到了原因。
如果用使用动态代理改造CRUD的方式,用接口实现,这意味着接口路径要和xml中那么namespace中的值一致,而在mybatis配置中mapper注册的时候路径要写的是被打包进target/classes下的路径,注意.和/ 的区别
这次经历让我明白了该如何去解决问题。要解决问题的前提就是要知道问题的原因,需要定位问题,而不是报个错就盲目复制粘贴报错报错信息去搜博客,这确实可能会让你解决问题,但是有很大几率是你搜遍了网上的解决方式也没有解决问题,因为通常一个框架的同一个异常其实是有很多原因,你就会像无头苍蝇那样乱转,运气好可能会解决问题,运气不好就会到处碰壁。
九.必做题和附加题
1.必做题
此部分另外已提交,就不在此赘述了
2. 附加题
①题目要求
要求写出算法思想和代码
编写三个函数分别实现高精度加法、减法和乘法运算。在主函数中输入任意两个很大的正整数,可根据菜单提示,反复选择相应的操作进行计算。
菜单:1、输入任意两个正整数
2、高精度加法
3、高精度减法
4、高精度乘法
0、退出
②算法思想
我们知道正常的类型是无法存储这种大数值的,这里我们采用两个String来存储两个正整数,然后模拟我们平常计算加减乘除的过程来写代码,对每一位分别处理,最终得到我们想要的结果。
③代码
package com.dreamchaser; import java.util.Scanner; public class Main { static Scanner scanner = new Scanner(System.in); static String s1 = ""; static String s2 = ""; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (true) { if (choosePattern(1) == 1) { break; } } } private static int choosePattern(int i) { if (i == 1) { System.out.println("\n\n1.输入任意两个正整数"); System.out.println("2.高精度加法"); System.out.println("3.高精度减法"); System.out.println("4、高精度乘法"); System.out.println("0、退出"); System.out.println("\n\n请输入你的选择(序号):"); } switch (scanner.nextInt()) { case 1: //吃掉回车 scanner.nextLine(); print(); return 0; case 2: add(); return 0; case 3: delete(); return 0; case 4: multiplication(); return 0; case 5: return 1; default: System.out.println("抱歉,输入的是非法字符,请重新输入:"); return choosePattern(0); } } private static void multiplication() { //表示进位 int i, j, k; int[] c = new int[202]; s1 = new StringBuilder(s1).reverse().toString(); s2 = new StringBuilder(s2).reverse().toString(); for (i = 0; i < s1.length(); i++) { for (j = 0; j < s2.length(); j++) { c[i + j] += (s1.charAt(i) - 48) * (s2.charAt(j) - 48); } } for (k = 1; k <= s1.length() + s2.length(); k++) { c[k] += c[k - 1] / 10; c[k - 1] %= 10; } while (c[k] == 0 && k >= 1) { k--; } for (; k >= 0; k--) { System.out.print(c[k]); } System.out.println(); } private static void delete() { //表示进位 int i, j, r = 0, k = 0; boolean flag = true; int[] c = new int[101]; for (i = s1.length() - 1, j = s2.length() - 1; j >= 0; i--, j--) { //两个位数相减再减去接的位数 c[k++] = (s1.charAt(i) - s2.charAt(j) - r); //清零标记 r = 0; if (c[k - 1] < 0) { c[k - 1] += 10; r = 1; }//如果是负数就借十,并标记 } //剩下的继续减 while (i >= 0) { //减去借的 c[k++] = (s1.charAt(i) - '0' - r); //清零标记 r = 0; //如果是负数就借十,并标记 if (c[k - 1] < 0) { c[k - 1] += 10; r = 1; } i--; } //输出 for (i = k - 1; i >= 0; i--) { //防止前导0输出的操作 if (c[i] != 0 || flag) { System.out.print(c[i]); flag = true; } } //如果都没有输出,说明相减结果为0,应当输出0 if (flag == false) { System.out.print(0); } System.out.println(); } private static void add() { //表示进位 int i, j, r = 0, k = 0; boolean flag = true; int[] c = new int[101]; //从最低位相加,相加他们的公共部分,所以j>=0 for (i = s1.length() - 1, j = s2.length() - 1; j >= 0; i--, j--) { //两个位数和进位的相加后取个位 c[k++] = (r + s1.charAt(i) - '0' + s2.charAt(j) - '0') % 10; //记录进位 r = (r + s1.charAt(i) - '0' + s2.charAt(j) - '0') / 10; } //再把剩下的继续加 while (i >= 0) { //位数和进位的相加后取个位 c[k++] = (r + s1.charAt(i) - '0') % 10; //记录进位 r = (r + s1.charAt(i) - '0') / 10; i--; } //如果还有进位,进到最高位 if (r != 0) { c[k++] = r; } //输出 for (i = k - 1; i >= 0; i--) { //防止前导0输出的操作 if (c[i] != 0 || flag) { System.out.print(c[i]); ; flag = true; } } if (flag == false) { System.out.print(0); } System.out.println(); } private static void print() { System.out.println("请输入第一个整数:"); s1 = scanner.nextLine(); System.out.println("请输入第二个整数:"); s2 = scanner.nextLine(); //把大的字符串放前面,方便操作 if (s1.length() < s2.length() || (s1.length() == s2.length() && s1.compareTo(s2) > 0)) { String temp = ""; temp = s1; s1 = s2; s2 = temp; } } }
④测试结果
十、短学期实践的心得体会
花了三天时间写代码,一天时间写实验报告,总计四天的努力,累计超过千行的代码(确切是1632行,没错,我真的算了!),虽然过程艰辛,但是结果令人满意。
这个项目是我第一个独立完成的项目!说真的,很多东西你看似会了,但是真正到自己去做项目的时候,会发现很多问题,这个不会,那个不会,最后还是要靠百度解决,毕竟面向百度编程这句话不是可不是白讲的。
在这个过程中其实我也学到了很多,尤其是关于mybatis框架和Maven的认识更加深入了。而且这个过程中我渐渐形成了一套属于自己代码风格和编程习惯,而且我对于如何去定位查找解决bug也有了更加清晰的认识。
在这个过程中,我也认识到了自己的很多不足,未来我也要更加扎实的学习,更要尝试去多做项目,这样才能将知识技术化为内在,才能做到真正的融汇贯通,游刃有余!