数据库课程设计

数据库课程设计报告

​ 这次的数据库课程设计是基于 JAVA 所设计的一个书店会员管理系统。由于数据库中亦有实体:管理员和工作人员,故此系统可分为3个界面:分别是会员交互系统,工作人员交互系统,以及管理员交互系统。

数据导入

​ 由于数据库中的图书数据匮乏,故写了一个爬虫爬取豆瓣的图书 TOP250,大致如下:

image-20211211102150545

​ 考虑到在交互界面演示时的流畅性,因此只导入前30条的图书数据。导入后的数据库中的表的数据如下:

image-20211211102331965

image-20211211102437202

image-20211211102348006

​ 在导入数据的过程中,使用了 $Functions.batchInputBook()$。

​ 大致代码如下:

 public static void batchInputBook()                 //用一次就够了噢~
    {       //对书本的信息进行批量的导入 CSV -------> 数据库
     
        String[][] results = CSVUtil2.CSVProcessing();
        
     for(int i = 0; i <results.length - 1; i++)
        {
            String book_author = results[i][1];
  
            BigDecimal book_price = new BigDecimal(results[i][2]);
         
            String book_press = results[i][3];
            String book_name = results[i][0];
            BigDecimal book_quantity = new BigDecimal(500);
            insertBookInformation(book_category, book_author, book_price, book_press, book_name, book_quantity);

        }

​ 首先通过 $CSVUtil2.CSVProcessing()$ 函数 对目录下的 $douban.csv$ 中的数据进行提取,然后再通过 $Functions$ 中的静态方法 $insertBookInformation()$ 将书的信息插入数据库。

数据属性

​ 考虑到数据库中各个实体的属性可能会存在多次使用的情况,因此将各个属性进行抽象实现。更加方便后续的界面设计。

图书信息

image-20211211103616268

​ 其中,各个变量的意义如下:

  • ​ $book_number$:图书编号。
  • ​ $book_author$:图书作者。
  • ​ $book_category$:图书类别。
  • ​ $book_name$:图书名称。
  • ​ $book_press$:图书出版社。
  • ​ $book_price$:图书价格。
  • ​ $book_quantity$:图书库存数量。

会员信息

image-20211211104126215

​ 其中,各个变量的意义如下:

  • ​ $member_category$:会员类别。
  • ​ $member_gender$:会员编号。
  • ​ $member_name$:会员姓名。
  • ​ $member_number$:会员编号。
  • ​ $member_phone_number$:会员联系方式(特指电话号码)。

购书信息

image-20211211104634914

​ 其中,各个变量的意义如下:

  • ​ $purchase_number$:购买记录编号。
  • ​ $member_number$:会员编号。
  • ​ $purchase_time$:购买时间。
  • ​ $member_name$:会员姓名。
  • ​ $member_phone_number$:会员联系方式。
  • ​ $category_number$:会员类别编号。
  • ​ $book_number$:图书编号。
  • ​ $book_name$:图书名称。
  • ​ $handle$:办理人。

退书信息

image-20211211105106598

​ 其中,各个变量的意义如下:

  • ​ $refund_number$:退书记录编号

  • ​ $member_number$:会员编号。
  • ​ $refund_time$:退书时间。
  • ​ $member_name$:会员姓名。
  • ​ $member_phone_number$:会员联系方式。
  • ​ $penalty$:罚金。
  • ​ $book_number$:图书编号。
  • ​ $book_name$:图书名称。
  • ​ $handle$:办理人。

员工信息

image-20211211105519217

​ 其中,各个变量的意义如下:

  • ​ $staff_number$:员工编号。
  • ​ $staff_name$:员工姓名:
  • ​ $staff_gender$:员工性别。
  • ​ $staff_id_number$:员工身份证号。
  • ​ $staff_post$:员工职位。
  • ​ $staff_wage$:员工工资。
  • ​ $administractor$:管理员。

登录界面设计

​ 登录界面的实现主要在文件 $LogIn.java$ 下。

​ 在其中,将 $username$ (即输入的用户名)和 $password$ (即输入的密码)设置为静态属性。方便其他类(如对数据库进行操作时)进行使用。

​ 验证码的实现见 **其余功能模块 **处。

image-20211211110145305

​ 在登录界面上,用户/员工/管理员可以输入自己的用户名和密码,然后进行登录。

​ 在进行登陆时,会进行多重的判断。

​ 首先会判断用户名和密码是否输入错误,若输入错误,则给出提示。

image-20211211110455061

​ 若用户名和密码输入正确,则会对验证码进行校验。输入错误则提示,输入正确则登录成功。

image-20211211110554281

​ 输入正确;

image-20211211110625778

​ 具体的登录校验过程,在文件 $LoggingVerification.java$ 中实现。

​ 在使用者点击确认登录后,会对文件 $account_information.txt$ 中的数据进行检索。查看是否存在该用户名和密码对,若存在,则登录成功,否则登录失败。

​ 在登录成功之后,会对 druid.properties 中的 username 和 password 进行修改,由于不同的用户属于不同的角色并且具有不同的权限,如此则可以实现不同用户的安全性访问。

验证过程

​ 另外,由于老师对账户是否成功登录持有一丝怀疑态度,接下来将对其登录的成功与否进行验证:

​ 首先,若与数据库连接的用户为 $root$

image-20211211115238778

​ 我们进行一个对图书信息修改的操作,如下:

Functions.modify_book_information("200002", 50.0);

​ 该语句表示,将图书编号为 200002 的图书库存数量增加50;执行结果如下:

​ 执行前:

image-20211211115438006

​ 执行后:

image-20211211115454960

​ 很显然,执行成功。故该函数功能并无错误;由于会员不具有对表的修改权限,接下来通过该函数来对用户是否成功登录进行验证。

​ 将登录的用户改为会员:

image-20211211115616903

​ 由于用户具有对图书表的查询权限,故执行下列语句:

Functions.getBookName();

​ 该函数查询所有的图书名并输入,运行结果如下:

image-20211211150852352

​ 显然,可以正常运行。

​ 接下来执行插入语句的函数。

image-20211211150944759

发生权限错误。故用户成功创建并且具有所分配的会员相应的权限。

​ 很重要的一个语句:

SET global activate_all_roles_on_login=ON;#在MYSQL中所执行

​ 其表示用户连接到服务器时自动激活所有显式授权和强制角色。

注册界面设计

​ 注册界面主要在 $Register.java$ 中实现。

image-20211211112014203

​ 由于为书店会员管理系统,故理所当然,此处的注册按钮仅供用于注册会员账号。

​ 在整个注册的过程中,同样有多重判断。

​ 首先会判断用户名是否与其他会员冲突,若冲突,则通过弹窗提醒。

image-20211211113447310

image-20211211113505392

​ 若上述内容输入正确,则对验证码进行校验。如下:

image-20211211113633229

​ 若输入正确;

image-20211211113619365

​ 此时,在数据库中的会员表中会存入新注册的会员的信息。

image-20211211113719665

​ 同时,会根据其用户米和密码,为其创建一个访问数据库的账户。

image-20211211114228634

​ 可见,注册成功。

会员交互系统设计

​ 会员界面的主要实现在 $user_interface$ 文件夹下。

​ 当输入会员账户密码登入成功后,会进入会员界面。

图书购买

​ 使用的函数包括:

  • ​ Functions.purchaseBook()

image-20211211131455015

​ 输入图书名称,即可进行购买。

​ 若输入错误,会弹出弹窗提示,如下:

image-20211211132030237

​ 输入正确;

image-20211211132057972

​ 当购买成功之后,购买记录会添加在第四项:个人的操作记录中,同时也会在数据库中添加响应的数据。

image-20211211132139150

图书退款

​ 使用的函数包括:

  • ​ Functions.refundBook()

image-20211211131512742

​ 输入图书名称,即可完成退款。

​ 若该会员并未购买过这本书,则无法完成退款,如下:

image-20211211132424603

​ 输入正确;

image-20211211132520937

​ 当退款操作完成后,退款操作会添加在第四项:个人的操作记录中同时也会在数据库中添加响应的数据。如下:

image-20211211132606586

图书信息查询

​ 使用的函数包括:

  • ​ Functions.inquireBookInformationOnBookName(book_name)

​ 当输入正确的书名时,查询成功,并将数据在上面表格进行显示。

image-20211211132817892

image-20211211132829375

​ 若书名不存在库中,弹出弹窗提醒查询失败。

image-20211211132914741

​ 多次查询后,结果如下:

image-20211211133008367

显示个人操作记录

​ 使用的函数包括:

  • ​ Functions.getMemberPurchaseInformation(username)

  • ​ Functions.getMemberRefundInformation(username)

​ 当该用户进行购买或退书的操作后,首先对数据库中的表 $purchase_information$ 或 $refund_information$ 进行修改,通过函数 $Functions.purchaseBook()$ 或 $Functions.refundBook()$ 实现,然后根据会员编号对表进行查询。

image-20211211131614646

批量购书

​ 使用的函数包括:

  • ​ Functions.purchaseBook()

image-20211211131737955

​ 在这里,会员可以实现勾选复选框来实现批量购买。另外,根据会员的级别不同(1,2,3),图书价格会享受不同的折扣(三级为最高),通过图书价格即可体现。

​ 若会员未勾选方框就进行购买,会弹出弹窗提示操作错误。

image-20211211133814157

​ 操作正确;

image-20211211133834064

​ 在进行批量购书后,同样,也会将这些购买记录显示在第四项:个人的操作记录中,同时,数据库中也会有相应的记录。

image-20211211133925078

image-20211211133958998

书单推荐

​ 书单推荐共有六本书,碍于篇幅限制,在此只展示3本。

​ 可通过上一页,下一页进行翻页查看。

image-20211211131749424

image-20211211131756216

image-20211211131808127

工作人员交互系统设计

图书信息查询

​ 使用到的函数包括:

  • ​ Functions.inquireBookInformationOnBookName(book_name)

​ 界面大抵如下,功能与会员界面中的图书信息查询相差无几,不再进行演示。

image-20211211134613458

会员信息查询及修改

​ 使用的函数包括:

  • Functions.inquireMemberInformationOnMemberNumber1(Integer.valueOf(member_number))。

  • Functions.inquireMemberInformationOnMemberName1(member_name)
  • Functions.modifyMemberInformation1(member_number, member_name, member_gender, member_phone_number, member_category)

image-20211211134656626

​ 在这个界面中,首先可根据会员的编号对会员信息进行查询。

​ 若输入错误的会员编号,则会提示数据输入错误。

image-20211211134747132

​ 若未输入数据便进行查询,同样会通过弹窗进行提示。

image-20211211134935700

​ 输入正确;

image-20211211134808142

​ 当查询到会员的记录后,可对会员的信息进行修改,如下:

image-20211211135043156

​ 修改后,数据库中的相应数据也会发生变化。

image-20211211135117442

image-20211211135130087

​ 点击清除数据后,即清除掉页面上查询到的所有内容。

image-20211211135758926

购买记录查询

​ 使用的函数包括

  • $Functions.inquirePurchaseInformationOnPurchaseNumber1(Integer.valueOf(purchase_number))$

  • $Functions.inquirePurchaseInformationOnMemberNumber1(Integer.valueOf(member_number))$

image-20211211135853913

​ 可根据会员编号进行查询,也可以根据购买记录编号进行查询。

​ 当未输入数据时进行查询,会通过弹窗进行提示。

image-20211211135948594

​ 通过会员编号进行查询:

image-20211211140020387

​ 通过购买记录编号进行查询:

image-20211211140051203

退书记录查询

image-20211211140214428

​ 可根据会员编号进行查询,也可以根据退书记录编号进行查询。

​ 当未输入数据时进行查询,会通过弹窗进行提示。

image-20211211140255450

​ 通过会员编号进行查询:

image-20211211140328366

​ 通过退书记录编号进行查询:

image-20211211140702428

image-20211211140716318

库存补充申请

image-20211211140938346

​ 管理人员可勾选单选框然后填写申请数目补充某个图书的数目,同时在数据库中,会插入该管理人员的库存补充申请记录。

​ 当未勾选任何图书便确认补充,会弹出弹窗提醒操作错误。

image-20211211141053226

​ 同样,若勾选了多个选项,会弹出弹窗提醒申请失败。

image-20211211141129055

​ 操作正确;

image-20211211141555212

​ 此时,数据库中也会多出相应的记录。

image-20211211141629188

​ 后续管理员将可以对申请进行审核,具体见下处 管理员交互系统设计。

管理员交互系统设计

员工信息查询及修改

image-20211211141855808

​ 通过这个界面,可以对员工的信息进行查询和修改。

​ 当未输入数据时,提示错误。

image-20211211150520573

​ 并且,当员工编号输入错误时,通过弹窗提示查询失败。

image-20211211150545433

​ 查询成功;

image-20211211150616170

​ 接下来对员工的信息进行修改。

image-20211211150646678

​ 在数据库中,

image-20211211150703748

image-20211211150713861

会员信息查询及修改

​ 大抵功能与管理员交互系统中的会员信息查询及修改相同,不再进行演示。

image-20211211141909340

图书信息查询(支持信息导出)

image-20211211141917608

​ 在此处可对库中的图书信息进行查询并导出为 .csv 文件。

​ 进行查询时,若未输入任何数据便点击查询,会通过弹窗提示错误。

image-20211211142611817

​ 若输入数据错误,亦会通过弹窗提示错误。

image-20211211142634985

​ 查询成功;

image-20211211142650746

image-20211211142655437

​ 多次查询后,

image-20211211143232097

​ 进行信息导出,会写在文件 output.csv 中。

image-20211211143329366

​ 文件中的内容如下:

image-20211211143406424

图书购买情况

​ 当管理员登陆后,会根据目前销售量最高的前5本书,生成如图所示的饼状图。其中会显示各个书在这5本书当中的销售占比。

​ 另外,会根据该图表在文件夹 generatePicture 中生成相应的 .png 文件并记录有生成的时间(此处的时间为 UNIX 时间戳)。如何管理员则可以通过查看历史记录来进行前后对比,观察某段时间内销量最好的是哪5本书籍。

image-20211211141942781

会员的购买情况

​ 在这个柱状图中,查询了5个会员的购买 8 个书的购买情况。由于图表限制,无法将书名完全显示。由于爬虫爬取的数据可能不太规范,导致部分过长无法显示。

​ 同样,会根据该图表在文件夹 $generatePicture$ 中生成相应的 $.png$ 文件并记录有生成的时间(此处的时间为 $UNIX$ 时间戳)。

image-20211211141953538

补货申请审批

​ 在工作人员提交了补货申请后,管理人员将可以在这里进行审批。

image-20211211142010515

​ 若未勾选任何选项,则会弹出弹窗提示错误。

image-20211211145921354

​ 审批完成;

image-20211211145942878

​ 当审批了一条记录后,数据库中的数据同时也会发生变化。

image-20211211150013902

image-20211211150027723

​ 同时,这个申请记录会被删掉,因为它已经完成了它的工作。

image-20211211150059111

image-20211211150126482

其余功能模块

验证码

​ 验证码的生成分为 $2$ 个文件,分别是 $Code.java$ 和 $CodePicture.java$。

​ 其中 $CodePicture.java$ 用于生成验证码图片,大致流程如下:

// 1.创建空白图片
BufferedImage image = new BufferedImage(
        WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
// 2.获取图片画笔
Graphics graphic = image.getGraphics();
// 3.设置画笔颜色
graphic.setColor(Color.LIGHT_GRAY);
// 4.绘制矩形背景
graphic.fillRect(0, 0, WIDTH, HEIGHT);
 // 5.画随机字符
        Random ran = new Random();
        for (int i = 0; i < SIZE; i++) {
            // 取随机字符索引
            int n = ran.nextInt(chars.length);
            // 设置随机颜色
            graphic.setColor(getRandomColor());
            // 设置字体大小
            graphic.setFont(new Font(
                    null, Font.BOLD + Font.ITALIC, FONT_SIZE));
            // 画字符
            graphic.drawString(
                    chars[n] + "", i * WIDTH / SIZE, HEIGHT / 2 + 10);
            // 记录字符
            sb.append(chars[n]);
        }
        // 6.画干扰线
        for (int i = 0; i < LINES; i++) {
            // 设置随机颜色
            graphic.setColor(getRandomColor());
            // 随机画线
            graphic.drawLine(ran.nextInt(WIDTH), ran.nextInt(HEIGHT),
                    ran.nextInt(WIDTH), ran.nextInt(HEIGHT));
        }
        // 7.返回验证码和图片
        return new Object[]{sb.toString(), image};

​ $Code.java$ 主要用于设置验证码图片位置及设置相关事件触发。

​ 对象创建及大小设置:

 JLabel code = new JLabel();
        Object[] obj = CodePicture.createImage();
        ImageIcon img = new ImageIcon((BufferedImage)obj[1]);//创建图片对象
        code.setIcon((Icon)img);
        code.setBounds(450, 290,150, 50);
        panel.add(code);

​ 鼠标点击监听:

  change.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e){
                if(e.getClickCount() == 1){
                    //重新获取验证码
                    Object[] obj1 = CodePicture.createImage();                      //再次生成对象。
                    ImageIcon img1 = new ImageIcon((BufferedImage)obj1[1]);//创建图片对象
                    code.setIcon((Icon)img1);
                    code.setBounds(450, 290,150, 50);
                    panel.add(code);
                }
            }
        });

背景音乐

​ 由于无法演示,故将其挪至其余功能模块。

​ 背景音乐的播放主要通过模块 $javax.sound.sampled$ 实现。

​ 需要带有的功能有:

  • ​ 获取数据(音频中的)
  • ​ 播放音频。
  • ​ 暂停播放音频。
  • ​ 继续播放音频。
  • ​ 生成音频主线程。
  • ​ 暂停音频线程。
  • ​ 继续音频线程。

表格风格修改

​ 由于当个修改表格的字体、间隔等过于麻烦,故通过一个函数进行统一处理。

​ 若想修改某个表格的风格,则使用 $TableStyle.setTableStyle()$ 即可。

​ 在这个文件中,主要对表格做了如下的修改:

  • ​ 表头自动排序。
  • ​ 标头的文字居中显示。
  • ​ 字体的调整。
  • ​ 根据内容对表格的列宽度进行调整。
  • ​ 设置表格每行的高度。

修改配置文件

​ 在 ModifyDruidProperties.java 中实现对配置文件的修改,以达到切换用户连接数据库的目的。

​ 实现则是简简单单的文件操作,不再进行阐释。

​ 注:在每次一个用户登录后,对$username$,$password$,分别进行修改。在用户退出后,把 $username$,$password$,修改回 $root$。另,此处的退出需手动叉掉用户界面然后在通过按钮来停掉主程序,否则可能会出现无法写回 $root$ 用户名密码的情况。

数据库连接

​ 主要在 $JDBCUtil.java$ 下进行实现。

​ 首先通过 $Properties$ 来获取 $URL$,$DRIVER$,$PASSWORD$等;

​ 其次再使用 $Druid$ 连接池进行连接。

​ 使用 $Druid$ 进行连接有如下的好处:

  • ​ 可以有效地避免 $sql$ 注入问题。
  • ​ $Druid$ 提供了一个高效、功能强大、可扩展性好的数据库连接池,并有效的替换了 $DBCP$ 和 $C3P0$。
  • ​ 可以对数据库的访问性能进行监控,基于其中的一个叫 $StatFilter$ 的插件。
  • ​ 可以实现对 $JDBC$ 层的扩展。