【项目实战】 图书信息管理系统(Maven,mybatis)(第一个自己独立完成的项目3)

简介: 【项目实战】 图书信息管理系统(Maven,mybatis)(第一个自己独立完成的项目)

八、调试过程中的主要问题、难点以及解决过程


实话说,在调试的过程中我遇到了很多问题,也查阅了很多技术博客,这之中有些确实能解决问题,而有些则是查阅了很多博客,尝试了很多方法还是没能解决问题,或者说出现了另一个问题,对此,我也渐渐摸索出了一套查找解决bug的方法,收获还是蛮大的。


以下列举了我调试中的几个主要问题和解决过程。


1.如何组织各个模块?

我一开始是采用递归循环的方式,但仔细一想,不对!经过我不断调试改进,最终用"套娃"的方式解决了问题,详细思路可以回到 第五部分、主要功能模块的算法流程图 去查看。

2.如何让整个项目有条不紊,井然有序?

整个项目累计代码总量超过千行,如果代码之间逻辑不清晰,关系复杂,那么这个项目调试,后期维护将变得举步维艰。


那么如何做到有条不紊,井然有序呢?


首先要做到项目结构清晰,可以像下面这样,实体类和实体类放在一起,工具类单独放在一起,资源配置文件放在一起,做到项目结构条理清晰。

q4.png

其次,要做到代码封装抽象,具体做法就是把复用性高的代码抽离出来,封装成一个工具类,比如我要每个模块都有打印图书信息结果的需求,那么我们完全可以把它封装起来,比如这里我就把它封装成Displayer工具类,其内部有两个方法,如下图:

q3.png

可以看到Displayer类有两个方法,但方法名其实都是show,只是针对不同情况进行重载,让方法用起来更加方便。这里还有个小细节,就是方法都是采用静态的方式,因为这里并没有要初始化的数据,所以采用静态,这样可以让代码调用的时候并不需要实例化即可调用其内的方法,让工具类使用起来就更加方便。

3.Maven项目,Mybatis框架,IDEA 的坑

q2.png


上图是我在调试遇到的一个问题,可以看到程序报了Mapped Statements collection does not contain value for xxx的异常,这很明显是mybatis框架报的异常,通过报错信息大概猜测是mybatis XXX容器内不包含我写的Mapper(因为那时候我还不知道Mapped Statement是什么东西),然后我就无脑将这段报错信息贴到百度上搜,确实有很多博客记录了此错误及解决方法,我截了一个下来,如图:


q1.png


但实际上我按照博客上一个个去做,并没有解决问题,这时候我已经花了一个下午时间去查找,问题没解决,倒是把mybatis框架复习了一遍。


苦思之下,我开始逐步调试,以下是我的思考过程:


因为问题肯定出在mybatis框架上,所以我逐步调试,但是呢,我又不懂mybatis源码,看得云里雾里。不过我之前自学Java的时候,跟着视频写过一个类似mybatis的框架------SORM框架(不过功能肯定没mybatis框架复杂,是个小型版的框架),做完后学了其他知识后,自己又回头帮它迭代优化了一下,增加了新的功能,优化了结构。


去.png


这段经历让我能大概理解mybatis框架的一些行为,比如在这个地方我就注意到了mappedStatement对象size为0。这时我就猜测这应该是框架本身并没有读取到我写的sql语句,那是由什么造成的呢?



去.png

这时候我就开始测试,不用接口类的方式(因为创建实体类也是mybatis框架底层做的),为了缩小问题的范围,我们采用原始的方式(但不是原生jdbc),发现还是这个错误,然后我开始怀疑mapper注册问题



w3.png

这里我原本是采用包扫描的方式注册,然后我开始尝试用指定路径文件方式去注册


w2.png


然后异常变了,说找不到这个文件


好家伙,之前包扫描的时候报的是Mapped Statements collection does not contain value for xxx,现在直接报没找到这个文件!


这时候我就开始思考为什么?


为什么我用包扫描的方式就不报错呢?而用具体的文件路径就报错呢?


真的是包扫描时找到了xml文件而具体文件路径没找到吗?


不对,不是这样的,换个角度讲,包扫描没扫描到,会报错吗?不会,那问题区间缩小,很可能就是因为xml文件路径的问题。而其他配置文件是找到了的,不然它根本不会提示找不到(路径是写在mybatis-config.xml文件里的),既然我们确定了问题所在,这时候我们就需要尝试改变路径



w1.png

这时候我再去查博客,搜索的不是异常信息,而是配置文件的路径该怎么写?


在搜索的过程中我逐渐意识到我的项目结构可能与别人不同,所以我在搜索时加了Maven限定词,好家伙,不搜不知道,一搜我找到了原因所在。


原来Maven项目编译时会把文件全都输出到Target文件夹下面


q5.png


而默认情况下配置文件只会把resource文件夹下面的配置文件输出,这就造成Java文件夹下面的Mapper文件根本不会输出到target里,这样当然就找不到了,于是我修改了Maven项目中核心配置文件pom.xml信息,加入了下面的配置



q4.png

然后呢?


还是找不到…


本着不抛弃不放弃的精神,我开始关注target文件夹的文件结构



q3.png

什么,居然有两个com.dreamchser,这是为什么呢?


然后我开始测试加百度,然后发现了IDEA的神坑之处------当我们创建一个包时,com.dreamchser和com/dreamchaser是不同的!


com.dreamchaser就是指第二个圈里的包,com/dreamchaser指的是第一个圈里的包


.和/的差别真的是坑死我我了!


我仔细思考了下,之前查询博客的时候,确实有博客提到idea中创建包时/和.是不一样,但当时我以为我的mapper是被读取进去了,所以没在意,只是检查了其他部分,知道后面调试运行底层源码时MappedStatement这个对象的size=0,通过字面意思猜测mybatis实际上是没有读取进去的,进而开始了这方面的排查,最终找到了原因。



q2.png

如果用使用动态代理改造CRUD的方式,用接口实现,这意味着接口路径要和xml中那么namespace中的值一致,而在mybatis配置中mapper注册的时候路径要写的是被打包进target/classes下的路径,注意.和/ 的区别


q1.png


这次经历让我明白了该如何去解决问题。要解决问题的前提就是要知道问题的原因,需要定位问题,而不是报个错就盲目复制粘贴报错报错信息去搜博客,这确实可能会让你解决问题,但是有很大几率是你搜遍了网上的解决方式也没有解决问题,因为通常一个框架的同一个异常其实是有很多原因,你就会像无头苍蝇那样乱转,运气好可能会解决问题,运气不好就会到处碰壁。


九.必做题和附加题


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;
        }
    }
}


④测试结果

q4.png

q3.png


q2.png

q1.png



十、短学期实践的心得体会


花了三天时间写代码,一天时间写实验报告,总计四天的努力,累计超过千行的代码(确切是1632行,没错,我真的算了!),虽然过程艰辛,但是结果令人满意。


这个项目是我第一个独立完成的项目!说真的,很多东西你看似会了,但是真正到自己去做项目的时候,会发现很多问题,这个不会,那个不会,最后还是要靠百度解决,毕竟面向百度编程这句话不是可不是白讲的。


在这个过程中其实我也学到了很多,尤其是关于mybatis框架和Maven的认识更加深入了。而且这个过程中我渐渐形成了一套属于自己代码风格和编程习惯,而且我对于如何去定位查找解决bug也有了更加清晰的认识。


在这个过程中,我也认识到了自己的很多不足,未来我也要更加扎实的学习,更要尝试去多做项目,这样才能将知识技术化为内在,才能做到真正的融汇贯通,游刃有余!



相关文章
|
14天前
|
Java 关系型数据库 MySQL
Maven——创建 Spring Boot项目
Maven 是一个项目管理工具,通过配置 `pom.xml` 文件自动获取所需的 jar 包,简化了项目的构建和管理过程。其核心功能包括项目构建和依赖管理,支持创建、编译、测试、打包和发布项目。Maven 仓库分为本地仓库和远程仓库,远程仓库包括中央仓库、私服和其他公共库。此外,文档还介绍了如何创建第一个 SpringBoot 项目并实现简单的 HTTP 请求响应。
67 1
Maven——创建 Spring Boot项目
|
17天前
|
Java 关系型数据库 MySQL
如何使用 maven 创建一个 Spring Boot项目
Maven 是一个强大的项目管理工具,通过配置 `pom.xml` 文件自动获取所需的 jar 包,提高开发效率。其核心功能包括项目构建和依赖管理。项目构建支持编译、测试、打包和发布等流程,而依赖管理则通过中央仓库、本地仓库和私有服务器获取和管理项目依赖。示例中展示了如何创建第一个 SpringBoot 项目并实现简单接口。
16 1
如何使用 maven 创建一个 Spring Boot项目
|
24天前
|
Java Maven Kotlin
idea maven创建kotlin项目
本文介绍了在IntelliJ IDEA中使用Maven创建Kotlin项目的步骤,包括在`pom.xml`文件中添加Maven中央仓库、配置`kotlin-maven-plugin`插件、指定源目录、添加测试插件和执行插件,以及添加Kotlin测试依赖和标准库依赖。文中还提到了如何通过更换镜像或使用代理来解决依赖下载速度慢的问题,并展示了运行示例代码的截图。
51 4
idea maven创建kotlin项目
|
23天前
|
Java Maven Android开发
eclipse创建maven项目
本文介绍了在Eclipse中创建Maven项目的步骤,包括打开Eclipse、选择Java项目、完成项目创建以及自动下载插件的过程。
64 2
eclipse创建maven项目
|
4天前
|
缓存 IDE Java
idea的maven项目打包时没有source下的文件
【10月更文挑战第21天】idea的maven项目打包时没有source下的文件
10 1
|
5天前
|
Java API Apache
除了 Maven,还有哪些工具可以管理项目的依赖和版本冲突
除了Maven,常用的项目依赖管理和版本冲突解决工具有Gradle、Ivy、Ant+Ivy、SBT等。这些工具各有特点,适用于不同的开发环境和需求。
|
20天前
|
Java 应用服务中间件 Maven
【终极解决方案】IDEA maven 项目修改代码不生效。
【终极解决方案】IDEA maven 项目修改代码不生效。
147 1
|
24天前
|
Java 应用服务中间件 Maven
idea+maven+tomcat+spring 创建一个jsp项目
这篇文章介绍了如何在IntelliJ IDEA中使用Maven和Tomcat创建一个JSP项目,包括配置Maven依赖、设置Tomcat服务器、编写JSP页面、创建控制器和配置文件,以及项目的运行结果。
102 0
idea+maven+tomcat+spring 创建一个jsp项目
|
25天前
|
Java Maven
使用javadoc生成maven项目的文档
本文介绍了如何在Maven项目中使用maven-javadoc-plugin插件来生成项目的JavaDoc文档,并展示了配置插件、编写代码、运行Maven命令以及查看生成文档的完整步骤。
15 0
使用javadoc生成maven项目的文档
|
18天前
|
Java 应用服务中间件 Maven
SpringBoot Maven 项目打包的艺术--主清单属性缺失与NoClassDefFoundError的优雅解决方案
SpringBoot Maven 项目打包的艺术--主清单属性缺失与NoClassDefFoundError的优雅解决方案
214 0

推荐镜像

更多