前言

必看!请确认完下述注意事项后再开始边看边练!

本文基于学校《基于JavaSwing的数据库管理项目实训》内容编撰,不含IDE编辑器、IDE编辑器插件、环境(Java、MySQL)的安装与破解教程。
另外部分内容与实际教学内容有所出处,请自行分辩或重新创建项目文件。

本文会以代码框形式附上对应代码并标注注意事项,但仍建议您手动敲写代码并善用 自动补全 功能,因为该功能会在补全后 自动导入 缺少的包,而且手动敲写代码有助于对项目的理解。

本文所有附图看不清可点击图片放大查看
本文所附代码部分未修改部分会使用注释注明省略,例如// 此处省略其他代码 ...
本文所附代码新增部分均有注释标注,例如// <<< 新增 // ↓↓↓ 新增,登录按钮的响应逻辑实现 // ↑↑↑ 新增,登录按钮的响应逻辑实现
请仅敲写或修改带有新增与修改注释或者在新增注释范围内的代码!
为避免误导,除截图以外的所有代码块都不含首行的 package 包字段,该字段在创建文件时会自动生成!

有关于代码高亮的注意事项

不同编辑器显示代码的格式不同,例如下图中 左是 IntelliJ IDEA 编辑器 右是 VS Code 编辑器 ,本博客使用的代码高亮格式也和下图的两种编辑器 不一样 ,所以在边看边练实操中出现高亮内容不一致是 正常 的。
Snipaste_2024-06-30_15-14-05.webp

本博客使用的代码高亮格式示例代码:

/**
 * @author Yaklo
 */
public class CreateOperFrame extends JFrame {
    public CreateOperFrame() {
        initComponents();
    }

    private void button1(ActionEvent e) {
        // TODO add your code here
        String operNo = txtOperNo.getText();
        String pwd = new String(txtPwd.getPassword());
        String pwdAgain = new String(txtPwdAgain.getPassword());
        String operName = txtOperName.getText();

        //空输入校验检查
        if (StringUtils.isEmpty(operNo)) {
            JOptionPane.showMessageDialog(CreateOperFrame.this,"操作员账号不能为空!");
            txtOperNo.requestFocus();
            return;
        }

此注意事项仅为让您 理解与解惑 什么编辑器里的代码高亮与本篇文章的代码高亮不一致

环境要求与文件下载

建议
操作系统:Windows 7
编辑器:IntelliJ IDEA
编辑器插件:JFormDesigner
数据库:MySQL 8.0.11
数据库编辑器:Navicat Premium 16
运行环境:Java 11

本文使用环境
操作系统:Windows 11
编辑器:IntelliJ IDEA Community Edition
编辑器插件:JFormDesigner
数据库:MySQL 8.2.0
数据库编辑器:Navicat Premium 17
运行环境:Java 21


相关内容链接: 由于所使用环境均为国外产品,下载速度慢请耐心等待
IntelliJ IDEA 官网下载页访问官网下载站后往下划有免费的社区版!IntelliJ IDEA Community Edition
MySQL 官网下载页 请安装8.x版本,否则在实操中无法导入数据库
Liberica JDK Java环境,推荐使用JDK21
Navicat Premium 17 简体中文官网下载页 需破解,相关文章见下方

相关教程链接:
CSDN:IntelliJ IDEA设置为中文,中文汉化教程,附详细图解 简单来说就是在Plugins(插件)页面安装中文插件
CSDN:超详细MySQL安装及基本使用教程 请注意:数据库密码请设置为123456
CSDN:启动本地mysql的几种方式
CSDN:2024最新 Navicat Premium 17.0.8 简体中文版破解激活永久图文详细教程 教程相关文件见下方
脚本之家:IDEA中的JFormDesigner使用小结 教程相关文件见下方

相关文件下载:
[数据库文件]fund_db_sql.sql > 蓝奏云 | YakloSG | OneDrive 通过蓝奏云渠道下载的需解压
JFormDesigner注册工具.rar > 蓝奏云 | YakloSG | OneDrive
Navicat16.3补丁.zip > 蓝奏云 | YakloSG | OneDrive
[Java标准库增强包]commons-lang3-3.1.jar > 蓝奏云 | YakloSG | OneDrive
[JDBC驱动包]mysql-connector-j-8.4.0.jar > 蓝奏云 | YakloSG | OneDrive
[产品LOGO图片]fund-sys-title.jpg > 蓝奏云 | YakloSG | OneDrive 通过蓝奏云渠道下载的需解压

其他内容查阅:
YakloBlog:MySQL笔记 内容稍欠缺,但可作为参考。

环境检查单

请确认所有环境以及需破解的都完成后再开始实训!

请确保你已正确安装了 > IntelliJ IDEA 编辑器IJ编辑器插件JFormDesignerMySQL8版本以上Navicat Premium16版本或以上Java11版本或以上
请确保你已经破解了 > IJ编辑器插件JFormDesigner Navicat Premium
请确保你已经启动了 > MySQL

请确认所有环境以及需破解的都完成后再开始实训!


1 数据库数据导入

安装mysql后无法连接报错:Can't connect to MySQL server on 'localhost'Can't connect to MySQL server on '数据库IP'
可能是mysql服务端没启动或者被关闭了,查看教程启动一下 > CSDN:启动本地mysql的几种方式

1-1 链接数据库

打开Navicat Premium点左上角 连接连接筛选 选中 MySQL , 连接类型 选中 MySQL 后点击右下角 下一步
Snipaste_2024-06-29_17-22-23.webp

在这个新建连接页面 填写数据库密码 后测试链接尝试连接,能连接后点击 确定
可以修改 连接名称 取个别名,如果 你的数据库 不在本地 可以修改 主机 为你的数据库服务器地址例如192.168.50.10
Snipaste_2024-06-29_17-25-54.webp

1-2 数据导入

[数据库文件下载]fund_db_sql.sql > 蓝奏云 | YakloSG | OneDrive 通过蓝奏云渠道下载的需先解压

双击 刚刚通过连接页面创建的数据库以 连接数据库
随后将预先创建好的数据库 文件拖入窗口 以准备导入
请确保你的 我的连接选中了 例如图中的 MySQL 再拖入文件,否则无法导入!
Snipaste_2024-06-29_17-31-59.webp

直接点击 开始
Snipaste_2024-06-29_17-32-43.webp

直接点击 关闭
Snipaste_2024-06-29_17-33-12.webp

按下键盘按键 F5 刷新数据库,刷新后能看到刚刚的导入的数据库
Snipaste_2024-06-29_17-33-28.webp

2 创建项目

2-1 创建项目

打开IntelliJ IDEA有三种方式创建创建项目:
①在没有打开任何项目的情况下直接点击页面上的 新建项目
②在打开项目的情况下点击 左上角三横杠 再点击 文件 > 新建 > 项目
③在打开项目的情况下点击 项目菜单 再点击 新建项目
Snipaste_2024-06-29_17-58-31.webp

名称填写:FundMgrSys
位置默认C盘,可自行修改
可以取消勾选 添加示例代码
构建系统和JDK默认即可,点击 创建
Snipaste_2024-06-29_18-13-52.webp

2-2 创建软件包

右键 src文件夹,点击 新建 > 软件包
如果在创建项目的时候没有取消勾选添加示例代码则会创建Main.java,右键删掉即可,也可不删但是没有用处
Snipaste_2024-06-29_18-23-33.webp

在弹出的 新建软件包 界面填写 com.随便取个名.foudmgrsyscn.随便取个名.foudmgrsys 例如本文 cn.yaklo.foudmgrsys
这边新建软件包的名字写错了,应该是 com.随便取个名.fundmgrsys ,你们新建的时候可以改一下我文章已经写好了就不改了
Snipaste_2024-06-29_18-28-10.webp

然后再接着按上面的方法把包 dao 创建一下
Snipaste_2024-06-29_18-36-39.webp

在创建完 dao 后再右键创建新的包会发现怎么出来的页面自带了 dao ,其实删掉换成别的包就好了,只要创建了 至少两个包 就能直接右键 foudmgrsys 这个包创建其他的包了,接着创建完其他的包吧。
dao domain exception service ui util view
创建完后文件目录如下图2
Snipaste_2024-06-29_18-33-53.webp
Snipaste_2024-06-29_19-48-09.webp

2-3 HelloWorld

foudmgrsys 包中定义(新建)一个Java类:FundMgrApp
Snipaste_2024-06-29_18-45-37.webp
类型选择 回车即可创建
Snipaste_2024-06-29_18-47-11.webp

public class FundMgrApp {} 里输入 psvmTab 快速补全main方法
在main方法里随便打印一串字符,例如Hello World!

public class FundMgrApp {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

使用快捷键 Ctrl Shift F10 运行当前正在编辑的文件 ,如在弹出的运行框正确打印刚刚设置的内容即代表Java环境和代码都没问题。
Snipaste_2024-06-29_19-29-50.webp

3 新增操作员功能实现

3-1 包commons-lang3导入

[Java标准库增强包]commons-lang3-3.1.jar > 蓝奏云 | YakloSG | OneDrive

右键 项目文件夹点击 新建 > 目录
新建一个 lib 目录
使用快捷键复制:Ctrl C 粘贴:Ctrl V
commons-lang3-3.1.jar 复制到 lib 目录下
Snipaste_2024-06-29_20-02-21.png

再右键复制进来的包点击 添加为库
Snipaste_2024-06-29_20-08-26.webp

直接确定
Snipaste_2024-06-29_20-08-43.webp

3-2 操作员(Operator)的创建

业务实体基类(ValueObject)的创建
业务实体基类为ValueObject,是所有实体类的父类。该类为抽象类,禁止对其进行实例化,后续所有业务实体的共性方法,可以写在这里。该类定义如下:

业务实体类(Operator)的创建
foudmgrsys.domain 包中定义(新建)一个 Java类 ValueObject

/**
 * 业务实体基类
 */
public class ValueObject {
}

该类对应的数据库表 t_oper,各字段定义如下表所示:

定义数据表字段字段类型字段长度
账号oper_nochar6
密码oper_pwdchar6
姓名oper_namevarchar30
操作员类型oper_typechar1
创建时间oper_ctimedatetime

foudmgrsys.domain 包中定义(新建)一个 Java类 Operator
关于Operator类的私有成员变量的定义如下:
注意:类名首字母大写,属性名首字母小写,属性名和表的字段名最好形成下划线和驼峰命名的映射关系。
什么是驼峰命名法 > 百度百科:驼峰命名法

import java.util.Date;

/**
 * 操作员类
 */
public class Operator extends ValueObject { //注意,此处继承了ValueObject类
    //编号
    private String operNo; // <<< 新增
    //密码
    private String operPwd; // <<< 新增
    //姓名
    private String operName; // <<< 新增
    //类型
    private String operType; // <<< 新增
    //创建时间
    private Date operCreatetime; // <<< 新增
}

Operator 类所有的私有成员变量,定义相应的访问方法,其过程如下:
①右键代码空白处点击 生成
②在弹出的生成菜单选择 Getter和Setter
③在新弹出的菜单使用快捷键 Ctrl a 全选私有成员变量后点击确定
Snipaste_2024-06-29_20-49-56.webp

一键定义后的代码如下:
注意,此处的代码是通过上述操作一键生成的!

import java.util.Date;

/**
 * 操作员类
 */
public class Operator extends ValueObject {
    
    // 此处省略 原先关于私有成员变量定义 的部分代码 ...

    public String getOperNo() {
        return operNo;
    }

    public void setOperNo(String operNo) {
        this.operNo = operNo;
    }

    public String getOperPwd() {
        return operPwd;
    }

    public void setOperPwd(String operPwd) {
        this.operPwd = operPwd;
    }

    public String getOperName() {
        return operName;
    }

    public void setOperName(String operName) {
        this.operName = operName;
    }

    public String getOperType() {
        return operType;
    }

    public void setOperType(String operType) {
        this.operType = operType;
    }

    public Date getOperCreatetime() {
        return operCreatetime;
    }

    public void setOperCreatetime(Date operCreatetime) {
        this.operCreatetime = operCreatetime;
    }
}

设置通用实体类属性打印方法——print() 编辑 ValueObject,重写toString方法,增加类属性的打印方法(通过反射机制)。这样所有继承ValueObject的类的toString()方法,都将能够自动分析该类属性,打印该类的所有属性信息了,具体代码如下:

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;

/**
 * 业务实体基类
 */
public class ValueObject {
    // ↓↓↓ 新增,类属性的打印方法(通过反射机制)
    @Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this); //反射机制
    }
    // ↑↑↑ 新增,类属性的打印方法(通过反射机制)
}

3-3 操作员窗体的创建

foudmgrsys.view 包中结合JFormDesigner插件创建一个窗体
右键 view 包点击 新建 > JFormDesigner Form
Snipaste_2024-06-29_21-23-29.webp

在弹出的菜单中创建一个名为 CreateOperFrame 的JFrame窗体

Name: CreateOperFrame
Superclass: JFrame
Button bar: none
Layout manager: null Layout
null layout options: auto-size:取消勾选

Snipaste_2024-06-29_21-24-54.webp

点击一下窗体,然后在右下角的控件属性菜单中修改窗口标题( title )为:新增操作员
并设置 resizablefalse(取消勾选) 以及修改 Size Policy 项为 Design size
resizable选项为是否允许调整窗体大小,修改Size Policy在运行时让窗体以设计大小运行
Snipaste_2024-06-29_21-53-02.webp

按下图进行控件创建与布局

五个标签内容分别是:操作员账号 登录密码 密码确认 真实姓名 操作员类型
两个按钮内容分别是:创建 取消
可以双击控件或单击控件在右下角控件属性修改text项

两个输入框名字是:txtOperNo txtOperName
两个密码框名字是:txtPwd txtPwdAgain
一个下拉选择框名字是:cbOperType
单击控件在右下角控件属性修改Name项

Snipaste_2024-06-29_22-08-45.webp

单击下拉选择框在右下角控件属性里修改 model 项为 普通柜员高管 回车换行
Snipaste_2024-06-29_22-27-01.webp

3-4 按钮点击事件的监听

3-4-1 初步尝试按钮事件

右键 创建 按钮控件点击 AddEvent Handler > ActionListener - actionPerformed... 即可一键创建点击这个按钮事件的对应代码
这部分与课堂教学内容有出入,可以以你熟悉的方式进行操作
Snipaste_2024-06-29_22-59-42.webp

此窗口无需修改任何内容,直接点击 OK
Snipaste_2024-06-29_23-00-26.webp

随后会自动跳转到对应Java类文件 CreateOperFrame 创建相应代码,如下:
注意,此处为告诉你程序自动创建了什么代码,请勿按下述代码进行敲写编辑!

// 此处省略其他代码 ...

public class CreateOperFrame extends JFrame {
    public CreateOperFrame() {
        initComponents();
    }

    // ↓↓↓ 自动创建的内容
    private void button1(ActionEvent e) {
        // TODO add your code here
        // 在此处编写点击按钮事件的代码
    }
    // ↑↑↑ 自动创建的内容

    private void initComponents() {
        // 此处省略其他代码 ...

        //---- button1 ----
        button1.setText("\u521b\u5efa");
        button1.addActionListener(e -> button1(e)); // <<< 自动创建的内容
        contentPane.add(button1);
        button1.setBounds(new Rectangle(new Point(85, 225), button1.getPreferredSize()));

        // 此处省略其他代码 ...
    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY 此处省略其他代码 ...
}

创建 按钮的点击事件代码中实现弹出一个弹窗并显示内容“你点击了我!”

private void button1(ActionEvent e) {
    // TODO add your code here
    JOptionPane.showMessageDialog(CreateOperFrame.this,"你点击了我!"); // <<< 新增
}

虽然你为按钮编写了点击事件,但这串代码还不能运行,因为在这个Java类中还缺少了让这个窗体显示的代码
在倒数第二行中插入代码,输入 psvmTab 快速补全main方法
在main方法中把 CreateOperFrame 窗口 赋值 给一个自变量 COF 以进行控制
设置自变量 COF 里的窗口的显示状态为 true
设置默认关闭窗口后会执行的行为 为退出程序
如不设置默认关闭后的行为,在关闭窗口后程序不会退出!
示例代码如下:

// 此处省略其他代码 ...

public class CreateOperFrame extends JFrame {
    public CreateOperFrame() {
        initComponents();
    }

    private void button1(ActionEvent e) {
        // TODO add your code here
        JOptionPane.showMessageDialog(CreateOperFrame.this,"你点击了我!");
    }

    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY 此处省略其他代码 ...
    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY 此处省略其他代码 ...

    // ↓↓↓ 新增,显示窗体的main方法
    public static void main(String[] args) { //输入psvm再按Tab键能快速补全这行代码
        CreateOperFrame COF = new CreateOperFrame(); //把CreateOperFrame窗口赋值给一个自变量COF以进行控制
        COF.setVisible(true); //设置自变量COF里的窗口的显示状态为true
        COF.setDefaultCloseOperation(COF.EXIT_ON_CLOSE); //设置默认关闭窗口后会执行的行为 为退出程序
    }
    // ↑↑↑ 新增,显示窗体的main方法
}

创建按钮的点击事件与显示窗体相关的代码展示:
Snipaste_2024-06-29_23-41-11.webp

使用快捷键 Ctrl Shift F10 运行当前正在编辑的文件,运行Java类 CreateOperFrame 测试刚刚为 创建 按钮所编写的代码
运行后点击创建按钮,如代码编写没问题则会弹出一个消息窗口并显示你点击了我!
Snipaste_2024-06-29_23-46-30.webp

现在进一步实践按钮点击事件,按如上操作为 取消 按钮创建点击事件的代码并在其中添加 关闭窗体 的代码

private void button2(ActionEvent e) { // <<< 自动创建,勿手动敲写
    // TODO add your code here
    CreateOperFrame.this.dispose(); // <<< 新增,关闭当前窗口
} // <<< 自动创建,勿手动敲写

你可以使用快捷键 Ctrl Shift F10 运行测试一下

3-4-2 输入数据的合法性校验

现在修改 创建 按钮的点击事件,为其添加 输入数据的合法性校验
主要涉及到各输入域的空输入校验和确认密码的一致性校验,其关键代码如下:
部分代码过长,在此代码块底部有滚动条可以滑动查看遮挡部分

// 此处省略其他代码 ...

import org.apache.commons.lang3.StringUtils; // <<< 新增,导入该库以进行字符判断

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * @author Yaklo
 */
public class CreateOperFrame extends JFrame {
    public CreateOperFrame() {
        initComponents();
    }

    private void button1(ActionEvent e) {
        // TODO add your code here
        //JOptionPane.showMessageDialog(CreateOperFrame.this,"你点击了我!");
        // ↑ 删除刚刚创建的测试代码
        // ↓↓↓ 新增的输入数据合法性校验的代码
        String operNo = txtOperNo.getText();
        String pwd = new String(txtPwd.getPassword());
        String pwdAgain = new String(txtPwdAgain.getPassword());
        String operName = txtOperName.getText();

        //空输入校验检查
        if (StringUtils.isEmpty(operNo)) {
            JOptionPane.showMessageDialog(CreateOperFrame.this,"操作员账号不能为空!");
            txtOperNo.requestFocus();
            return;
        }
        
        //密码空输入校验
        if (StringUtils.isEmpty(pwd)) {
            JOptionPane.showMessageDialog(CreateOperFrame.this,"操作员登录密码不能为空!");
            txtPwd.requestFocus();
            return;
        }

        //确认密码空输入校验
        if (StringUtils.isEmpty(pwdAgain)) {
            JOptionPane.showMessageDialog(CreateOperFrame.this,"操作员登录确认密码不能为空!");
            txtPwdAgain.requestFocus();
            return;
        }

        //操作员姓名空输入校验
        if (StringUtils.isEmpty(operName)) {
            JOptionPane.showMessageDialog(CreateOperFrame.this,"操作员真实姓名不能为空!");
            txtOperName.requestFocus();
            return;
        }

        //登录密码和确认密码的一致性
        if (!pwd.equals(pwdAgain)) {
            JOptionPane.showMessageDialog(CreateOperFrame.this,"操作员登录密码和确认密码不一致!");
            txtPwdAgain.requestFocus();
            return;
        }
        // ↑↑↑ 新增的输入数据合法性校验的代码
    }
    
    // 此处省略其他代码 ...

↑此处有代码框滚动条

3-4-3 数据的获取和封装

现在再接着为 创建 按钮的点击事件添加 数据的获取和封装
从各个输入控件中,获取数据,封装成Operator对象,并打印输出,其关键代码如下:

// 此处省略其他代码 ...

import cn.yaklo.foudmgrsys.domain.Operator; // <<< 新增,导入通用实体类属性打印方法
import org.apache.commons.lang3.StringUtils;

import java.awt.*;
import java.awt.event.*;
import java.util.Date; // <<< 新增,处理时间数据的包
import javax.swing.*;

/**
 * @author Yaklo
 */
public class CreateOperFrame extends JFrame {
    public CreateOperFrame() {
        initComponents();
    }

    private void button1(ActionEvent e) {
        // TODO add your code here
        
        // 此处省略 输入数据的合法性校验 的部分代码 ...
        
        //登录密码和确认密码的一致性
        if (!pwd.equals(pwdAgain)) {
            JOptionPane.showMessageDialog(CreateOperFrame.this,"操作员登录密码和确认密码不一致!");
            txtPwdAgain.requestFocus();
            return;
        }

        // ↓↓↓ 新增的数据的获取和封装
        Operator operator = new Operator();

        operator.setOperNo(operNo);
        operator.setOperPwd(pwd);
        operator.setOperName(operName);

        //注意对下拉框选项的识别
        if (cbOperType.getSelectedIndex()==0)
            operator.setOperType("a");
        else
            operator.setOperType("b");
        
        operator.setOperCreatetime(new Date());
        System.out.println(operator);
        // ↑↑↑ 新增的数据的获取和封装
    }

    // 此处省略其他代码 ...

3-4-4 运行测试

使用快捷键 Ctrl Shift F10 运行在各个输入框填入数据并点击创建按钮测试一下
正常情况下会在终端输出你刚刚输入的数据以及当前时间
数据的获取和封装代码运行效果如下:
Snipaste_2024-06-30_00-54-25.webp

3-5 包mysql-connector-j-8.4.0导入

[JDBC驱动包]mysql-connector-j-8.4.0.jar > 蓝奏云 | YakloSG | OneDrive

使用快捷键复制:Ctrl C 粘贴:Ctrl V
mysql-connector-j-8.4.0.jar 复制到 lib 目录下
再右键复制进来的包点击 添加为库
Snipaste_2024-06-30_01-02-33.webp

直接确定
Snipaste_2024-06-30_01-02-43.webp

3-6 数据库连接构建和资源释放

3-6-1 创建数据库连接

foudmgrsys.util 包中,构建(新建) DBUtils (Java)类,并编制常量保存数据库的JDBC链接串、用户名以及密码等信息

关于JDBC链接串:jdbc:mysql://localhost:3306/fund_db?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8
jdbc:mysql:// 这是JDBC URL的前缀,指定了使用JDBC连接MySQL数据库。
localhost:3306 这部分指定了数据库服务器的地址和端口号。
/fund_db 这是数据库的名称,即你想要连接的数据库叫做fund_db。
? 这个问号标志着查询参数的开始。
useUnicode=true 这个参数指定了连接应该使用Unicode字符编码。
&characterEncoding=utf8 这个参数指定了字符编码为UTF-8,这是一种广泛使用的Unicode字符集。
&useSSL=true 这个参数指示JDBC驱动程序尝试使用SSL(安全套接层)来建立安全的连接。
&serverTimezone=GMT%2B8 这个参数设置服务器的时区为GMT+8,这通常用于确保时间相关的操作在正确的时区中执行。%2B是URL编码,代表加号+。

输入 prsfTab 快速补全 private static final
代码如下:

/**
 * 数据库工具类(负责数据库的连接的获取和资源的释放)
 */
public class DBUtils {
    //请根据实际运行环境修改数据库IP和端口
    //输入 prsf 按 Tab 快速补全 private static final
    // ↓↓↓ 新增,数据库的JDBC链接串、用户名以及密码信息
    private static final String CONN_STR = "jdbc:mysql://localhost:3306/fund_db?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8";
    private static final String USERNAME = "root"; //数据库登录用户账号
    private static final String PWD = "123456"; //数据库登录密码
    // ↑↑↑ 新增,数据库的JDBC链接串、用户名以及密码信息
}

数据库连接对象的创建
这里首先要去加载jdbc驱动类的入口点,就是 com.mysql.cj.jdbc.Driver 类,如果在类路径中无法找到,则驱动加载失败,代码如下:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
// ↑↑↑ 新增,这里引入的三个包可以使用java.sql.*替代

/**
 * 数据库工具类(负责数据库的连接的获取和资源的释放)
 */
public class DBUtils {
    //请根据实际运行环境修改数据库IP和端口
    //输入 prsf 按 Tab 快速补全 private static final
    private static final String CONN_STR = "jdbc:mysql://localhost:3306/fund_db?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8";
    private static final String USERNAME = "root";
    private static final String PWD = "123456";
    
    // ↓↓↓ 新增,数据库连接对象的创建
    public static Connection getConn() {
        Connection conn = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver"); //此处双引号内容支持自动补全
            conn = DriverManager.getConnection(CONN_STR,USERNAME,PWD);
        } catch (ClassNotFoundException e) {
            System.out.println("mysql jdbc驱动未加载!");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }
    // ↑↑↑ 新增,数据库连接对象的创建
}

3-6-2 数据库连接测试

构建测试类,新建 foudmgrsys.test 包并构建测试类 Tester
小技巧,直接右键 foudmgrsys 包新建Java类,文件名填写 test.Tester IntelliJ IDEA 会帮你自动创建 test 包,并在其中创建 Tester 类文件
Snipaste_2024-06-30_01-39-48.webp

验证数据库连接实例的构建是否成功,代码如下

import cn.yaklo.foudmgrsys.util.DBUtils; // <<< 新增,导入DBUtils数据库连接方法

public class Tester {
    public static void main(String[] args) { //输入 psvm 按 Tab 快速补全main方法
        System.out.println(DBUtils.getConn()); //打印数据库连接指针
    }
}

使用快捷键 Ctrl Shift F10 运行测试
如果报错则可能是数据库未启动、账号密码错误、数据库未导入、数据库地址错误等问题
终端输出的内容: com.mysql.ck.jdbc.ConnectionImpl@后的数字每次运行都是随机的,有这段输出则代表连接正常
Snipaste_2024-06-30_01-33-35.webp

3-6-3 资源的释放

在JDBC操作过程中,要释放的资源,主要是Connection,PreparedStatement,ResultSet三个核心对象,他们在操作过程中都将消耗不小的内存。这里请注意它们释放的先后顺序
返回 foudmgrsys.util 包中的 DBUtils 类,代码如下:

// 此处省略其他代码 ...

// 此处 数据库连接对象的创建 部分代码 ...

// ↓↓↓ 新增,资源释放
public static void releaseRes(Connection conn, PreparedStatement pstmt, ResultSet rset) {
    try {
        if (rset!=null) rset.close();
        if (pstmt!=null) pstmt.close();
        if (conn!=null) conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

3-7 使用JDBC API保存数据

3-7-1 构建OperatorDao接口及其实现类

foudmgrsys.dao 包中构建OperatorDao接口及其实现类
DAO包是数据访问对象,负责某个业务实体的所有CRUD操作
文件 OperatorDao接口OperatorDaoImpl 为类
Snipaste_2024-06-30_02-01-58.webp

OperatorDao 代码如下:

import cn.yaklo.foudmgrsys.domain.Operator; // <<< 新增

public interface OperatorDao {
    public int addOper(Operator oper); // <<< 新增
}

OperatorDaoImpl 代码如下:
此处新增的代码public int addOper(Operator oper) {}会冒红是正常的,后面的章节会往{}里添加代码,添加完代码后就不冒红了

import cn.yaklo.foudmgrsys.domain.Operator; // <<< 新增

public class OperatorDaoImpl implements OperatorDao { // <<< 修改,注意,此处实现了OperatorDao接口
    @Override // <<< 新增
    public int addOper(Operator oper) {} // <<< 新增
}

3-7-2 保存Operator类对象到数据库对应表

先获得链接对象,让后生成PreparedStatement语句对象,并填充“?”参数部分,然后执行update操作。最后,请注意一定要释放资源,OperatorDaoImpl 代码如下:

import cn.yaklo.foudmgrsys.domain.Operator;
import cn.yaklo.foudmgrsys.util.DBUtils; // <<< 新增

// ↓↓↓ 新增,这里引入的四个包可以使用java.sql.*替代
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
// ↑↑↑ 新增,这里引入的四个包可以使用java.sql.*替代

public class OperatorDaoImpl implements OperatorDao {
    private static final String SQL_ADD = "insert into t_oper values(?,?,?,?,?)";  // <<< 新增
    @Override
    public int addOper(Operator oper) {
        // ↓↓↓ 新增,保存Operator类对象到数据库对应表
        Connection conn = DBUtils.getConn();
        PreparedStatement pstmt = null;

        int cnt = 0;
        try {
            pstmt = conn.prepareStatement(SQL_ADD);
            pstmt.setString(1, oper.getOperNo());
            pstmt.setString(2, oper.getOperPwd());
            pstmt.setString(3, oper.getOperName());
            pstmt.setString(4, oper.getOperType());
            pstmt.setTimestamp(5,new Timestamp(oper.getOperCreatetime().getTime()));
            cnt = pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtils.releaseRes(conn,pstmt,null); //释放资源
        }
        return cnt;
        // ↑↑↑ 新增,保存Operator类对象到数据库对应表
    }
}

foudmgrsys.view.CreateOperFrame 中的 创建 按钮点击事件中 添加将操作员信息保存到数据库的代码

import cn.yaklo.foudmgrsys.dao.OperatorDao; // <<< 新增
import cn.yaklo.foudmgrsys.dao.OperatorDaoImpl; // <<< 新增
//其他导入包 ...
public class CreateOperFrame extends JFrame {
    // 此处省略其他代码 ...
    private void button1(ActionEvent e) {
        // TODO add your code here
        // 此处省略 输入数据的合法性校验 的部分代码 ...

        Operator operator = new Operator();

        operator.setOperNo(operNo);
        operator.setOperPwd(pwd);
        operator.setOperName(operName);

        //注意对下拉框选项的识别
        if (cbOperType.getSelectedIndex()==0)
            operator.setOperType("a");
        else
            operator.setOperType("b");

        operator.setOperCreatetime(new Date());
        System.out.println(operator);
        
        // ↓↓↓ 新增,将操作员信息保存到数据库
        OperatorDao operDao = new OperatorDaoImpl();
        int cnt = operDao.addOper(operator);

        if (cnt==1)
            System.out.println("保存操作员信息到数据库成功!");
        // ↑↑↑ 新增,将操作员信息保存到数据库
    }
    
    // 此处省略其他代码 ...

使用快捷键 Ctrl Shift F10 运行进行信息录入测试
请注意:由于数据库关于账号和密码的字段长度为6,所以录入的信息不能超过6个字符,以及真实姓名的字符长度是30,如果超过这个长度在点击创建按钮时代码会报错!
可查看#3-2-操作员operator的创建部分回顾
如果字符长度没有超过但点击创建按钮后代码还是报错可能是数据重复了,不要点两次创建按钮或者创建数据库已有的操作员账号
Snipaste_2024-06-30_02-55-58.webp

打开 Navicat Premium 查看 fund_db 数据库的 t_oper 数据表是否有刚刚添加的数据,如果没有可以用快捷键 F5 刷新一下再查看。
Snipaste_2024-06-30_03-01-36.webp

4 系统登录操作的实现

4-1 登录窗体的创建

[产品LOGO图片]fund-sys-title.jpg > 蓝奏云 | YakloSG | OneDrive 通过蓝奏云渠道下载的需解压

在src目录下创建一个 images 包用于专门放置图片,将 fund-sys-title.jpg 复制到 images 包里
Snipaste_2024-06-30_03-26-29.webp

foudmgrsys.view 包里创建 LoginFrame 窗体
名字设置一下,关闭 auto-size 其余默认即可,参考下图:
Snipaste_2024-06-30_03-33-00.webp

使用 JLable 来承载图片,适当拉大 JLable 并修改 icon 属性以显示图片
Snipaste_2024-06-30_03-41-00.png

按下图进行控件创建与布局

两个标签内容分别是:登录账号 登录密码
两个按钮内容分别是:登录 取消
可以双击控件或单击控件在右下角控件属性修改text项

一个输入框名字是:txtOperNo
一个密码框名字是:txtOperPwd
单击控件在右下角控件属性修改Name项

Snipaste_2024-06-30_04-17-43.webp

设置窗体初次出现的时候,相对屏幕进行水平和垂直居中,在窗体的构造方法中添加 this.setLocationRelativeTo(null) ,代码插入位置如下:

// 此处省略其他代码 ...

    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents  @formatter:off
        // 此处省略其他代码 ...
        label1 = new JLabel();
        label2 = new JLabel();
        label3 = new JLabel();
        txtOperNo = new JTextField();
        txtOperPwd = new JPasswordField();
        button1 = new JButton();
        button2 = new JButton();

        //======== this ========
        setTitle("\u57fa\u91d1\u7ba1\u7406\u7cfb\u7edf");
        setResizable(false);
        var contentPane = getContentPane();
        contentPane.setLayout(null);
        this.setLocationRelativeTo(null); // <<< 新增,设置居中显示窗体

        //---- label1 ---- ...
        // 此处省略其他代码 ...

代码插入位置截图演示:
Snipaste_2024-06-30_04-29-26.webp

4-2 登录底层实现

4-2-1 编制OperatorDao的查询方法

OperatorDao 接口的 查询方法 中编写代码
foudmgrsys.dao 包中 OperatorDao代码如下:

import cn.yaklo.foudmgrsys.domain.Operator;

public interface OperatorDao {
    public int addOper(Operator oper);
    public Operator getOperByNo(String operNo); // <<< 新增
}

foudmgrsys.dao 包中 OperatorDaoImpl代码如下:
其中,ResultSet是用来装载从数据库中查出的用户记录信息。如果没有这个用户,则返回null

import cn.yaklo.foudmgrsys.domain.Operator;
import cn.yaklo.foudmgrsys.util.DBUtils;

import java.sql.*; //修改,原先这里引入的四个包被IntelliJ IDEA使用java.sql.*替代

public class OperatorDaoImpl implements OperatorDao {
    private static final String SQL_ADD = "insert into t_oper values(?,?,?,?,?)";
    @Override
    public int addOper(Operator oper) {
        // 此处省略 保存Operator类对象到数据库对应表 的部分代码 ...
        return cnt;
    }
    
    // ↓↓↓ 新增,编制OperatorDao的查询方法
    private static final String SQL_GET_OPER_BYNO = "select * from t_oper where oper_no=?";
    @Override
    public Operator getOperByNo(String operNo) {
        Connection conn = DBUtils.getConn();
        PreparedStatement pstmt = null;
        ResultSet rset = null;
        Operator oper = null;
        try {
            pstmt = conn.prepareStatement(SQL_GET_OPER_BYNO);
            pstmt.setString(1,operNo);
            rset = pstmt.executeQuery();
            if (rset.next()) {
                oper = new Operator();
                oper.setOperNo(operNo);
                oper.setOperName(rset.getString("oper_name"));
                oper.setOperPwd(rset.getString("oper_pwd"));
                oper.setOperType(rset.getString("oper_type"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtils.releaseRes(conn,pstmt,rset);
        }
        return oper;
    }
    // ↑↑↑ 新增,编制OperatorDao的查询方法
}

4-2-2 创建登录业务实现类

foudmgrsys.service 业务包中,构建 OperService 接口及其实现类,通过异常机制向窗口通报异常
文件 OperService接口OperServiceImpl 为类
Snipaste_2024-06-30_05-25-58.webp

OperService 代码如下:

import cn.yaklo.foudmgrsys.domain.Operator; // <<< 新增

public interface OperService {
    public Operator checkOper(String operNo, String operPwd);  // <<< 新增
}

OperServiceImpl 代码如下:

import cn.yaklo.foudmgrsys.dao.OperatorDao; // <<< 新增
import cn.yaklo.foudmgrsys.dao.OperatorDaoImpl; // <<< 新增
import cn.yaklo.foudmgrsys.domain.Operator; // <<< 新增

public class OperServiceImpl implements OperService{  // <<< 修改,注意,此处实现了OperService接口
    // ↓↓↓ 新增,登录业务实现类
    @Override
    public Operator checkOper(String operNo, String operPwd) {
        OperatorDao operDao = new OperatorDaoImpl();
        Operator oper = operDao.getOperByNo(operNo);
        if (oper==null)
            throw new RuntimeException("账号不正确,请检查!");
        if (!oper.getOperPwd().equals(operPwd))
            throw new RuntimeException("密码不正确,请检查!");
        return oper;
    }
    // ↑↑↑ 新增,登录业务实现类
}

4-3 按钮点击事件的监听

4-3-1 登录按钮的响应逻辑实现

回到 foudmgrsys.view 包中的 LoginFrame.jfd 窗体文件
右键 登录 按钮控件点击 AddEvent Handler > ActionListener - actionPerformed... ,弹出的窗口 无需修改 任何内容,直接点击 OK 即可一键创建点击这个按钮事件的对应代码
这部分与课堂教学内容有出入,可以以你熟悉的方式进行操作
Snipaste_2024-06-30_05-16-32.webp

随后会自动跳转到对应Java类文件 LoginFrame 创建相应代码
登录按钮的响应逻辑实现 ,首先从界面上获得登录账号和密码后,执行登录业务逻辑,在此过程中,如果有发现登录异常,则用对话框提示错误原因。登录成功后,关闭登录界面,显示主窗口(主窗口设计见后续章节)

//其他代码

import cn.yaklo.foudmgrsys.domain.Operator; // <<< 新增
import cn.yaklo.foudmgrsys.service.OperService; // <<< 新增
import cn.yaklo.foudmgrsys.service.OperServiceImpl; // <<< 新增

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * @author Yaklo
 */
public class LoginFrame extends JFrame {
    public LoginFrame() {
        initComponents();
    }

    private void button1(ActionEvent e) {
        // TODO add your code here
        // ↓↓↓ 新增,登录按钮的响应逻辑实现
        OperService operService = new OperServiceImpl();
        try {
            Operator oper = operService.checkOper(txtOperNo.getText(),new String(txtOperPwd.getPassword()));
            JOptionPane.showMessageDialog(LoginFrame.this,"登录成功");
            LoginFrame.this.dispose();
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(LoginFrame.this,ex.getMessage());
        }
        // ↑↑↑ 新增,登录按钮的响应逻辑实现
    }

    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY 此处省略其他代码 ...
    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY 此处省略其他代码 ...
}

4-3-2 退出按钮的响应逻辑实现

按如上操作为 取消 按钮创建点击事件的代码并在其中添加 关闭窗体 的代码

private void button2(ActionEvent e) {
    // TODO add your code here
    LoginFrame.this.dispose();
}

4-3-3 窗体显示与登录测试

这个Java类中还缺少了让这个窗体显示的代码
在倒数第二行中插入代码,输入 psvmTab 快速补全main方法
在main方法中把 LoginFrame 窗口 赋值 给一个自变量 LF 以进行控制
设置自变量 LF 里的窗口的显示状态为 true
设置默认关闭窗口后会执行的行为 为退出程序
如不设置默认关闭后的行为,在关闭窗口后程序不会退出!
示例代码如下:

// 此处省略其他代码 ...
 
public class LoginFrame extends JFrame {
    public LoginFrame() {
        initComponents();
    }

    // 此处省略 登录按钮的响应逻辑实现 的部分代码 ...

    // 此处省略 退出按钮的响应逻辑实现 的部分代码 ...
 
    // JFormDesigner - Variables declaration - DO NOT MODIFY ...
    
    // ↓↓↓ 新增,显示窗体的main方法
    public static void main(String[] args) { //输入psvm再按Tab键能快速补全这行代码
        LoginFrame LF = new LoginFrame(); //把LoginFrame窗口赋值给一个自变量LF以进行控制
        LF.setVisible(true); //设置自变量LF里的窗口的显示状态为true
        LF.setDefaultCloseOperation(LF.EXIT_ON_CLOSE); //设置默认关闭窗口后会执行的行为 为退出程序
    }
    // ↑↑↑ 新增,显示窗体的main方法
}

使用快捷键 Ctrl Shift F10 运行登录测试一下,正常情况下登录成功后点击确定程序就会退出
Snipaste_2024-06-30_05-42-38.webp

4e 小结

这是目前完成内容的目录结构和窗体布局
Snipaste_2024-06-30_14-54-56.webp
在前面的这四个章节里我们主要实现了两个功能:新增操作员系统登录操作
如果课程有后续再更新吧~


前方的道路以后再来探索吧 ......
To be continued ......

一名既不Kirakira也不让人Dokidoki的普通人~