文章目录
- 仓库链接🔗
- 功能构架图
- 基层构建util.sql
- JNI
- 整体框架
- gradeChart界面
仓库链接🔗
https://gitee.com/honiestbutter/student-management-system
功能构架图
基层构建util.sql
⭐️DAO模式
数据库内容
由于我的这个成绩管理系统是以数据库为基础的,所有对数据进行的增删减改操作都是直接对数据库操作,所以java对数据库命令操作的是在最底层的,前段按钮所有的命令根源都要传输到底层包装中,转化成对数据的命令来进行对数据库的操作,实现最终目的。
在数据库中我建立了两个表格,一个名为all
用来储存学生信息,一个是user
用来储存登陆的用户名信息。
登陆数据库
- 打开数据库所在的目录
- 弹出输入密码
zhangzihan@zhangzihandeMacBook-Air ~ % cd /usr/local/mysql/bin //打开目录
zhangzihan@zhangzihandeMacBook-Air bin % ./mysql -u root -p //输入命令
Enter password: //输入密码
//有以下显示表示成功打开数据库
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 8.0.25 MySQL Community Server - GPL
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
建立表格
Student信息表格
(
`id` BIGINT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`gender` VARCHAR(10) NOT NULL,
`classname` VARCHAR(20) NOT NULL,
`math` INT DEFAULT 0,
`java` INT DEFAULT 0,
`pe` INT DEFAULT 0,
`sumscore` INT DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1000001
DEFAULT CHARSET = utf8;
User信息表格
![](https://pic.imgdb.cn/item/60dbf3a75132923bf8b58104.png)
前端与后端的连接,转化为数据库命令我主要是通过:
前端组件触发事件,获取信息分类传送给相应的类和方法,提取出参数和要实现的功能(要进行的操作),然后只需要将相应参数传给后端,就可以实现对数据库的操作
(因为只用到了一个数据库,所以没有定义DAO接口,最基层的就是数据库的具体实现类)
核心BaseDAO类——数据库的具体实现
在基类BaseDAO
中,把对数据库的操作都封装到方法中
👍🏽1:getBd()方法——实现只创建一次对象,提高内存利用率
👍🏿2:getCon() 方法——只创建一次对数据库的连接,后面都利用这个连接,提高速率
if(con==null||con.isClosed()){ con=DriverManager.getConnection(url,usename,password);//2.只需要第一次的时候建立连接
}
后期需要具体了解的方法:(这里不详说了)
1.数据库的连接口令
2.查找query
3.修改(添加删除修改)upgrade
DAO接口manage DAO
1.继承接口方法
StudentDAO
和userDAO
都继承manageDAO
接口,实现与数据库底层的操作,接口中的方法:
-
⭐️
final BaseDAO bd = BaseDAO.getBd();
通过
BaseDAO
方法获得BaseDAO对象而不是new
——优点:-
避免对数据库进行操作时,多次重复新建对象造成内存的占用和浪费,这样相当于只创建一次对象
-
避免对数据库重复的连接和关闭——数据库的连接过程其实是很消耗资源的,这样只创建一次
BaseDAO
对象相当于只要打开数据库就不关闭了 -
保护
BaseDAO
类中的私有变量public static BaseDAO getBd(){//返回对象 if(bd==null){ bd=new BaseDAO(); } return bd; } //只有第一次的时候需要new一个对象,后面都使用这个对象,降低内存占用(避免重复新建对象)
-
-
void closeAll();
关闭数据库
2.为什么要建立这个接口
实现分工
因为StudentDAO
和manageDAO
类有共同的特征,都要通过BaseDAO
实现对数据库的操作,这两个类的作用都是==实体类:实现存放和传输具体数据==,只不过接收的数据种类不同,StudentDAO
转化的是学生信息,userDAO
转化的是用户账号密码信息。
通过建立这个接口,提取共同实现的功能,降低代码的重复性耦合性,提高重复利用率。
实体类1:userDAO——对用户信息的分析
按下注册按钮和登陆按钮时需要对用户信息分析
登陆:
用户名是否存在and密码是否与用户名相匹配——BaseDAO
查找功能
registerDialog注册界面
- ⭐️三个文本框不能为空
- 用户名不能已存在——
BaseDAO
查找功能 - 密码两次输入要统一
实体类2:StudentDAO——对学生信息的分析
⚠️:只有与数据库有关的对信息的分析和处理的方法可以放在StudentDAO
和UserDAO
中
JNI
JNI是Java调用C或C++程序的一种技术
创建JNI接口
新建一个类,在类中声明带有native
关键词的方法,那么这个方法就是接下来要在C\Cpp
程序中要调用的函数
public class RandomGenerate {
public native void get();//调用native本地方法————调用C++程序
}
随后让终端来该改类所在的文件夹,输入
javac -h . 类名.class
随后会在该目录下的到一个.h
的头文件,这个文件就是Java和C/Cpp程序进行交互的接口啦
![](https://pic.imgdb.cn/item/60dbf5d15132923bf8c4bfc7.jpg)
编写C++程序
- 在提供的
.h
头文件中,会出现一个已经定义好的函数,这个就是咱们要实现的函数。
![](https://pic.imgdb.cn/item/60dbf5115132923bf8bf54d1.jpg)
JNIEXPORT void JNICALL Java_util_random_RandomGenerate_get
(JNIEnv *, jobject);
//java中定义的native方法对应在C++文件中就是这个函数
-
C++文件
Cachieve
中实现的不再是int main()
而是以这个.h
文件中生成的函数下的函数体 -
C++文件实现的事随机生成数据输出到文件中
-
在实现完函数之后,执行编译命令——生成
.so
文件
clang++ -o2 -I"/Library/Java/JavaVirtualMachines/liberica-jdk-11-full.jdk/Contents/Home/include" -I"/Library/Java/JavaVirtualMachines/liberica-jdk-11-full.jdk/Contents/Home/include/darwin" -shared -o getRandom.so a.cpp
-o2
是开启编译优化,提高程序运行速度;-shared
是创建动态链接库,供JVM虚拟机调用。
在java程序中调用编译好的C++文件
复制编译好的程序的具体目录和名称,在要调用的代码中写下如下:
class 类名 {
static {
System.load("目录名和文件名");
}
}
随后再调用就行啦
![](https://pic.imgdb.cn/item/60dbf65f5132923bf8c8d644.png)
输出栏显示进度
整体框架
![](https://pic.imgdb.cn/item/60dbf3a25132923bf8b56456.png)
整体分为了三个包,face
包中实现的主要是登陆界面loginWindow
和注册界面registerWindow
的完善
登陆之后进入主界面,有三个大模块构成(三个包实现)——
-
学生成绩概览
GradeChart
-
图例化分析
-
生成海量数据
![](https://pic.imgdb.cn/item/60dbf3ad5132923bf8b5a8cc.png)
loginWindow
这个窗口比较简单,实现的主要是javaSwing
的应用进行布局
单击两个按钮产生的Actionevent
事件,生成两个窗口
单击登陆会产生对输入的用户名和密码的信息判断——UserDAO
登陆界面
![](https://pic.imgdb.cn/item/60dbf71b5132923bf8ce6853.png)
登陆界面
如果用户名密码不匹配提示错误
注册界面
![](https://pic.imgdb.cn/item/60dbf39c5132923bf8b53a3f.png)
如果什么都不输入直接注册的话会错误提示
用户名已存在也会错误提示
两次密码输入不一致错误提示
登陆成功后进入主界面MainWindow
MainWindow
进入到gradeChart
包
![](https://pic.imgdb.cn/item/60dbf3ad5132923bf8b5adfd.png)
gradeChart界面
1️⃣JTable——实现数据库内容输出到java页面表格
private JTable gradeTable;
private DefaultTableModel gradeTableModel;
DefaulttableModel
DefaulttableModel
的对象规定的是表格格式
gradeTableModel = new DefaultTableModel(stuTools.studentList(StudentDAO.ORDER_BY_ID), head) {//DefaultTableModel是Table的子接口
new
构造方法中传入:
- 表格内容(二维数组)——🎃从数据库中调出的表格(调用方法返回特定符合条件的数组作为参数)
- 表头head(字符串一维数组)
Jtable
以DefaulttableModel
对象规定的表格格式建立表格
gradeTable = new JTable(gradeTableModel);
构造方法中传入的DefaulttableModel
对象(规定表格格式)
table表格放入JscrollPane
否则表格不会显示,这个我也不知道为什么。
scrollPane = new JScrollPane(gradeTable);
add(scrollPane, BorderLayout.CENTER);
Actionevent
ActionEvent
包含一个事件,该事件为执行动作事件ACTION_PERFORMED
.
触发这个事件的动作为:
- 点击按钮
- 双击列表中选项——改写学生信息用到
- 选择菜单项——精确查找和按需输出时用到
- 在文本框中输入回车——暂时没用到
2️⃣添加add
![](https://pic.imgdb.cn/item/60dbf84c5132923bf8d7c025.jpg)
获得文本框中输入的所有信息放到数组中,传送给StudentDAO
中的插入命令insert(String inf[])
⭐️刷新新建信息后的table表
方法:每创建成功后,调用方法把数据库中的信息再倒入到table中一遍,实现刷新
if(sd.insert(inf)){
gc.updateGradeTable();//🔺更新数据
刷新table方法updateGadeTable()
public void updateGradeTable() {//获得table的DefaultTableModel格式
gradeTableModel.setDataVector(stuTools.studentList(StudentDAO.ORDER_BY_ID), head);
//重写从数据库中拉取数据,获得更新🔺
}
DefaultTableModel.setDataVector()方法
DefaultTableModel.setDataVector(Object[][]dataVector,Object []head)
用数组 dataVector
中的值替换 dataVector
实例变量中的值,表头为head
3️⃣删除delete
![](https://pic.imgdb.cn/item/60dbf8565132923bf8d8122b.jpg)
⭐️获得所点击的table列的学生信息
int row = gradeTable.getSelectedRow();
既要在数据库中实现学生信息的修改(StudentDAO的delete方法
),又要在table中实现
table中删除信息(行)
((DefaultTableModel) gradeTable.getModel()).removeRow(row);
4️⃣修改rewrite
一.两种触发修改事件的方式:
2.双击学生信息
⭐️实现方法:给table增加一个鼠标事件判断——如果检测到点击次数两次,就触发和点击修改按钮同样的事件,弹出修改窗口
gradeTable.addMouseListener(new MouseAdapter() {//鼠标事件
@Override
public void mouseClicked(MouseEvent e) {
if(e.getClickCount() > 1) {//如果双击
rewriteButton.doClick();//触发点击rewrite的功能🔺
}
}
})
🔺同时要修改gradeTableModel
的构造方法:因为默认是双击修改单元格内容,要改成双击打开修改框,所以要关闭这个功能
gradeTableModel = new DefaultTableModel(stuTools.studentList(StudentDAO.ORDER_BY_ID), head) {//DefaultTableModel是Table的子接口
@Override
public boolean isCellEditable(int row, int column) {//重写接口中的方法——双击窗口不能修改表格中的内容
return false;
}
//默认可以修改(但是想要实现双击激发rewrite重写按钮同时实现重写数据库和表格的内容,这里冲突(只能重写表格中的内容))
};
2. 点击修改按钮
修改框和增加框类似,都是获得文本框信息,只不过修改框调用的是update
方法
二.仅刷新更改的这一行信息(实现对table中内容的更改)
int row = table.getSelectedRow();
for (int i = 0; i < table.getColumnCount(); i++) {
table.setValueAt(inf[i], row, i);//🔺仅刷新这一行的数据
5️⃣精确查找find
![](https://pic.imgdb.cn/item/60dbf8695132923bf8d8a9b0.jpg)
注意错误信息提醒
-
如果两个选项都没有选择的时候,
JRadioButton
返回的是-1,需要进行提示。 -
如果没查到,返回的结果数组长度为0,需要提示信息
if(stu.length>0){ ((DefaultTableModel)table.getModel()).setDataVector(stu, head); } else{ JOptionPane.showMessageDialog(null,"未找到学生信息!","Sorry",JOptionPane.ERROR_MESSAGE); }
-
ID必须是数字串
-
输入内容不能为空
查找成功后都要刷新table表
final var stu=sd.findStudent( contentField.getText(), StudentDAO.FIND_BY_ID);
if(stu.length>0){
((DefaultTableModel)table.getModel()).
setDataVector(stu, head);
}
6️⃣按需求展示信息class
![](https://pic.imgdb.cn/item/60dbf8785132923bf8d91ea2.jpg)
![](https://pic.imgdb.cn/item/60dbf8a05132923bf8da582b.jpg)
7️⃣生成个人/班级成绩详细对比表
班级为单位:
个人为单位:
8️⃣数据可视化(柱状图)
![](https://pic.imgdb.cn/item/60dbf3bc5132923bf8b60d69.png)
9️⃣输出到EXCEL表(print)
POI操作
![](https://pic.imgdb.cn/item/60dbf3bd5132923bf8b615f1.png)