前言:
因为自己学习能力有限和特殊情况必须要找一个项目来做,但是上网搜的那些项目有两种(一种是技术太多,自己能力不够;一种是技术太少,项目太简单)导致都不适合本人,本人现有技术只有Mysql和java和jdbc,因此就自己搞了一个项目,用来当作账本用;
时间太短,不能保证健壮性和效率(见谅),我在文章中会提到哪里可以优化(蓝色部分),我是真的没时间了,你们感兴趣了可以自己设计。
功能
此账本系统包括用户登录和记账记录,所有信息都会存到数据库中。
用户的姓名、密码等信息;记账的时间、原因、人物等都会涉及
包括:添加新成员、删除成员、汇入资金、使用资金、查询余额、查询记录、修改密码
数据库和表的设计
create database laboratory_charge;
use laboratory_charge;
/**
* 创建学生表
* 姓名 学号 班级
*/
create table stu_info(
name varchar(10) primary key,
stu_id varchar(15),
grade varchar(20)
);
/*
* 创建实验室成员表
* 姓名 网名 密码
*/
create table lab_member(
name varchar(10) ,
vir_name varchar(10),
password varchar(20),
constraint lab_member_name foreign key (name) references stu_info(name)
);
create table Balance(
balance decimal(8,2),
charge_number int primary key auto_increment
);
/**
* 创建记账记录
* 姓名 时间 原因 使用金额 汇入金额 剩余资金 借款编号
*/
create table charge_list(
charge_number int primary key auto_increment,
name varchar(10) not null,
reason varchar(255),
time date ,
u_money decimal(8,2),
a_money decimal(8,2),
balance decimal(8,2)
);
alter table charge_list
modify u_money decimal(8,2) default 0;
alter table charge_list
modify a_money decimal(8,2) default 0;
共包含四张表
学生信息表
name varchar(10) primary key:name作为主键约束,且不能为空也不能重复,在之后的实验室成员表中会关联到它的name;
stu_id varchar(15):学生的学号
grade varchar(20):学生的年级信息
实验室成员表
name varchar(10) :没什么可说的,一会要关联
vir_name varchar(10):网名信息
password varchar(20):登录的密码
constraint lab_member_name foreign key (name) references stu_info(name):关联操作,因为当时的想法是一定先有学生才有的实验室成员嘛。
记账记录
charge_number int primary key auto_increment:自增长列且不重复的实验室编号
name varchar(10) not null:名字
reason varchar(255):记账的原因,你是因为什么想要改变资金的
time date :记录时间,与Java中sql包下的date一个类型
u_money decimal(8,2):使用的金额,我在之后对他进行了修改(默认值为0,因为用了这两个中的任意一个,另一个绝对为0),其实应该用double的,单都差不多,主要是因为java里面只能用double(我的技术问题)。
a_money decimal(8,2):同上
balance decimal(8,2):记录实验室剩余金额
修改默认值为0的操作
alter table charge_list
modify u_money decimal(8,2) default 0;
alter table charge_list
modify a_money decimal(8,2) default 0;
余额记录
create table Balance(
balance decimal(8,2),//经过第几次账本记录后剩余的金额
charge_number int primary key auto_increment//记录账本记录的次数,本来应该关联一下记账表中的此字段的,但是时间不够,没来及多想
);
java中代码的实现
import com.mysql.cj.jdbc.Driver;
import java.sql.*;
import java.sql.Date;
import java.util.*;
/**
* ClassName: ${NAME}
*
* @author 奈奈朵
* @vesion 17
* @Create 2024/2/26 19:22
*/
public class Main {
public static final Scanner scan = new Scanner(System.in);
public static void main(String[] args) throws SQLException, ClassNotFoundException {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/laboratory_charge","root","121400bjy.");
Statement statement = connection.createStatement();
try {
menu(statement);
}finally {
connection.close();
statement.close();
scan.close();
};
}
public static void menu(Statement statement) throws SQLException, ClassNotFoundException {
// DriverManager.registerDriver(new Driver());
// new Driver();
boolean judge = true;
System.out.println("*****欢迎使用实验室记账系统*****");
System.out.println("******************************");
while(judge) {
System.out.println(" 1.登录 2.退出 3.新用户 ");
int cho = scan.nextInt();
String master = null;
if (cho != 3) {
while (true) {
if (cho != 2) {
System.out.println("请输入用户名:");
String username = scan.next();
master = username;
System.out.println("请输入你的密码:");
String password = scan.next();
String sql = "select lm.password\n" +
"from lab_member lm\n" +
"where lm.name = '" + username + "'";
ResultSet resultSet = statement.executeQuery(sql);
String truepw = null;
while (resultSet.next()) {
truepw = resultSet.getString("password");
System.out.println(truepw);
}
if (password.equals(truepw)) {
System.out.println("*****登陆成功,欢迎使用!*****");
menu1(statement,master);
break;
} else {
System.out.println("密码错误!请选择");
System.out.println(" 1.登录 2.退出 ");
cho = scan.nextInt();
if (cho == 2) {
return;
}
}
} else {
return;
}
}
}
else {
addmember(statement);
}
}
}
public static void menu1(Statement statement ,String master) throws SQLException {
if ("小羽".equals(master)) {
while (true) {
System.out.println("--1.邀请成员 2.踢出成员--");
System.out.println("--3.资金汇入 4.资金支出--");
System.out.println("--5.查询余额 6.修改密码--");
System.out.println("--7.查询记录 8.退出 --");
System.out.println("选择你要执行的业务:");
int choose = scan.nextInt();
switch (choose) {
case 1:
addmember(statement);
break;
case 2:
deletemember(statement);
break;
case 3:
abmoney(statement);
break;
case 4:
usmoney(statement);
break;
case 5:
double balance = 0;
balance = getBalance(statement);
System.out.println("实验室剩余资金为"+ balance +"元!");
break;
case 6:
modifypas(statement,master);
break;
case 7:
alllist(statement);
break;
case 8:
break;
}
if (choose == 8) {
break;
}
}
} else {
while (true) {
System.out.println("--1.资金汇入 2.资金支出--");
System.out.println("--3.查询余额 4.修改密码--");
System.out.println("--5.查询记录 6.退出 --");
System.out.println("选择你要执行的业务:");
int choose = scan.nextInt();
switch (choose) {
case 1:
abmoney(statement);
break;
case 2:
usmoney(statement);
break;
case 3:
double balance = 0;
balance = getBalance(statement);
System.out.println("实验室剩余资金为"+ balance +"元!");
break;
case 4:
modifypas(statement,master);
break;
case 5:
alllist(statement);
break;
case 6:
break;
}
if (choose == 6) {
break;
}
}
}
}
/**
* 添加新成员
*
*/
public static void addmember(Statement statement) throws SQLException {
System.out.println("正在创建新用户!");
System.out.println("请输入你的姓名:");
String username = scan.next();
System.out.println("请输入你的密码(不能超过20个字符):");
String password = scan.next();
System.out.println("请输入你的网名:");
String vir_name = scan.next();
System.out.println("请输入你的学号:");
String stu_id= scan.next();
System.out.println("请输入你的班级信息:");
String grade= scan.next();
String sql1 = "insert into stu_info values('"+username+"','" + stu_id + "','" +grade + "');";
String sql2 = "insert into lab_member values('"+username+"','" + vir_name + "','" +password + "');";
int i = statement.executeUpdate(sql1);
int j = statement.executeUpdate(sql2);
System.out.println("创建成功!");
}
/**
* 删除成员
* @param statement
* @throws SQLException
*/
public static void deletemember(Statement statement) throws SQLException {
System.out.println("请输入删除姓名:");
String username = scan.next();
String sql1 =
"delete from lab_member \n" +
"where name = '"+ username +"';";
String sql2 =
"delete from stu_info \n" +
"where name = '"+ username +"';";
int i = statement.executeUpdate(sql1);
int j = statement.executeUpdate(sql2);
System.out.println("删除成功!");
}
/**
* 汇入资金
* @param statement
* @throws SQLException
*/
public static void abmoney(Statement statement) throws SQLException {
System.out.println("你的姓名是:");
String name = scan.next();
System.out.println("原因:");
String reason = scan.next();
System.out.println("所汇入的金额为:");
double money = scan.nextDouble();
double balance = getBalance(statement)+money;
Date date = null;
String sqlGetTime = "select current_date() ;";
ResultSet resultSet = statement.executeQuery(sqlGetTime);
while(resultSet.next()){
date = resultSet.getDate(1);
}
String sql = "insert into charge_list (name,reason,time,u_money,a_money,balance)\n" +
"values(\n" +
"'毕竞羽',\n" +
"'"+reason+"',\n" +
"'"+date+"',\n" +
"0,\n" +
money+",\n" +
balance+"\n" +
");";
int i = statement.executeUpdate(sql);
sql = "insert into Balance (balance)\n" +
"values(\n" +
balance+"\n" +
")";
int j = statement.executeUpdate(sql);
System.out.println("记录成功!");
}
/**
* 使用资金
* @param statement
* @throws SQLException
*/
public static void usmoney(Statement statement) throws SQLException {
System.out.println("你的姓名是:");
String name = scan.next();
System.out.println("原因:");
String reason = scan.next();
System.out.println("所申请的金额为:");
double money = scan.nextDouble();
double balance = getBalance(statement)-money;
Date date = null;
String sqlGetTime = "select current_date() ;";
ResultSet resultSet = statement.executeQuery(sqlGetTime);
while(resultSet.next()){
date = resultSet.getDate(1);
}
String sql = "insert into charge_list (name,reason,time,u_money,a_money,balance)\n" +
"values(\n" +
"'毕竞羽',\n" +
"'"+reason+"',\n" +
"'"+date+"',\n" +
money+",\n" +
"0,\n" +
balance+"\n" +
");";
int i = statement.executeUpdate(sql);
sql = "insert into Balance (balance)\n" +
"values(\n" +
balance+"\n" +
")";
int j = statement.executeUpdate(sql);
System.out.println("记录成功!");
}
/**
* 查询余额
* @param statement
* @return
* @throws SQLException
*/
public static double getBalance(Statement statement) throws SQLException {
String sql = "select b.balance\n" +
"from balance b \n" +
"order by charge_number desc \n" +
"limit 0,1;";
ResultSet resultSet = statement.executeQuery(sql);
double money =0;
while(resultSet.next()){
money = resultSet.getDouble("balance");
}
return money;
}
/**
修改密码
*/
public static void modifypas(Statement statement,String name) throws SQLException {
String password = null;
while(true){
System.out.println("请输入新密码:");
password = scan.next();
System.out.println("请再次确认新密码:");
String copy_password1 = scan.next();
if(password.equals(copy_password1)){
break;
}else{
System.out.println("两次密码不相同!请重新操作:");
}
}
String sql = "\n" +
"update lab_member \n" +
"set password = '"+ password +"' \n" +
"where name = '"+ name +"';";
int i = statement.executeUpdate(sql);
System.out.println("修改成功!");
};
/**
* 账单
* @param statement
*/
public static void alllist(Statement statement) throws SQLException {
String sql = "select * \n" +
"from charge_list ;";
ResultSet resultSet = statement.executeQuery(sql);
List<Map> list= new ArrayList<Map>();
ResultSetMetaData metaData = resultSet.getMetaData();
int clumn = metaData.getColumnCount();
while(resultSet.next()){
Map map = new HashMap();
for (int i = 1; i < clumn; i++) {
Object value = resultSet.getObject(i);
String columnLabel = metaData.getColumnLabel(i);
map.put(columnLabel,value);
}
list.add(map);
}
System.out.println(list);
}
}
主方法
先注册驱动,创建连接,创建小汽车(之后的每次往返都用这个小汽车);
并且把关闭资源的操作全放在finally中。
注册驱动的方法不限,你想怎么注册就怎么注册,能用就行
这里的小汽车statement应该用prepareStatement代替,它的好处我不多说了,所以可以优化一下
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/laboratory_charge","root","121400bjy.");
Statement statement = connection.createStatement();
try {
menu(statement);
}finally {
connection.close();
statement.close();
scan.close();
};
菜单一
最初的界面
这个过程存在这样的问题:就是登录失败后,他不会保留原来的名字,而是让你重新输入名字和账号,所以感兴趣的人这里可以优化一下让使用更方便
public static void menu(Statement statement) throws SQLException, ClassNotFoundException {
// DriverManager.registerDriver(new Driver());
// new Driver();
boolean judge = true;
System.out.println("*****欢迎使用实验室记账系统*****");
System.out.println("******************************");
while(judge) {
System.out.println(" 1.登录 2.退出 3.新用户 ");
int cho = scan.nextInt();
String master = null;
if (cho != 3) {
while (true) {
if (cho != 2) {
System.out.println("请输入用户名:");
String username = scan.next();
master = username;
System.out.println("请输入你的密码:");
String password = scan.next();
String sql = "select lm.password\n" +
"from lab_member lm\n" +
"where lm.name = '" + username + "'";
ResultSet resultSet = statement.executeQuery(sql);
String truepw = null;
while (resultSet.next()) {
truepw = resultSet.getString("password");
System.out.println(truepw);
}
if (password.equals(truepw)) {
System.out.println("*****登陆成功,欢迎使用!*****");
menu1(statement,master);
break;
} else {
System.out.println("密码错误!请选择");
System.out.println(" 1.登录 2.退出 ");
cho = scan.nextInt();
if (cho == 2) {
return;
}
}
} else {
return;
}
}
}
else {
addmember(statement);
}
}
}
菜单二
还记得我为什么传进去登陆姓名master吗,我定义里应该是只要是小羽,他的菜单就比别人多两个功能(增删成员),所以说小羽这个字符串可以更改为你认为的主人。
这里的查询余额操作之所以单独做了有返回值的出来是因为资金汇入和支出的方法里会使用到他。
有没有感觉我while用了好多,你可以自己想你的思路,优化代码。
public static void menu1(Statement statement ,String master) throws SQLException {
if ("小羽".equals(master)) {
while (true) {
System.out.println("--1.邀请成员 2.踢出成员--");
System.out.println("--3.资金汇入 4.资金支出--");
System.out.println("--5.查询余额 6.修改密码--");
System.out.println("--7.查询记录 8.退出 --");
System.out.println("选择你要执行的业务:");
int choose = scan.nextInt();
switch (choose) {
case 1:
addmember(statement);
break;
case 2:
deletemember(statement);
break;
case 3:
abmoney(statement);
break;
case 4:
usmoney(statement);
break;
case 5:
double balance = 0;
balance = getBalance(statement);
System.out.println("实验室剩余资金为"+ balance +"元!");
break;
case 6:
modifypas(statement,master);
break;
case 7:
alllist(statement);
break;
case 8:
break;
}
if (choose == 8) {
break;
}
}
} else {
while (true) {
System.out.println("--1.资金汇入 2.资金支出--");
System.out.println("--3.查询余额 4.修改密码--");
System.out.println("--5.查询记录 6.退出 --");
System.out.println("选择你要执行的业务:");
int choose = scan.nextInt();
switch (choose) {
case 1:
abmoney(statement);
break;
case 2:
usmoney(statement);
break;
case 3:
double balance = 0;
balance = getBalance(statement);
System.out.println("实验室剩余资金为"+ balance +"元!");
break;
case 4:
modifypas(statement,master);
break;
case 5:
alllist(statement);
break;
case 6:
break;
}
if (choose == 6) {
break;
}
}
}
}
添加新成员
因为数据库中学生表的name和实验室成员表中name关联的影响,所以我们创建新用户时要先向学生表插入信息再向实验室成员表中插入信息。
这里的方法也有问题:创建的新成员名字如果和已存在的成员名重复,那么它会直接报错,所以其实可以优化,先查询这个新用户的名字是否已存在表中,根据结果进行之后的操作
另外就是,我们其实可以先向数据库发送创建触发器的指令,再插入实验室成员表前插入学生表,就不用再java里编写2个sql语句发送了。
public static void addmember(Statement statement) throws SQLException {
System.out.println("正在创建新用户!");
System.out.println("请输入你的姓名:");
String username = scan.next();
System.out.println("请输入你的密码(不能超过20个字符):");
String password = scan.next();
System.out.println("请输入你的网名:");
String vir_name = scan.next();
System.out.println("请输入你的学号:");
String stu_id= scan.next();
System.out.println("请输入你的班级信息:");
String grade= scan.next();
String sql1 = "insert into stu_info values('"+username+"','" + stu_id + "','" +grade + "');";
String sql2 = "insert into lab_member values('"+username+"','" + vir_name + "','" +password + "');";
int i = statement.executeUpdate(sql1);
int j = statement.executeUpdate(sql2);
System.out.println("创建成功!");
}
删除成员
我们其实可以先向数据库发送创建触发器的指令,在插入学生表前先删除实验室成员表,就不用再java里编写2个sql语句发送了。和添加一样的优化
如果删除的成员名字不在表中会进行报错,所以这里也可以优化,而且优化很大,交给你们了
public static void deletemember(Statement statement) throws SQLException {
System.out.println("请输入删除姓名:");
String username = scan.next();
String sql1 =
"delete from lab_member \n" +
"where name = '"+ username +"';";
String sql2 =
"delete from stu_info \n" +
"where name = '"+ username +"';";
int i = statement.executeUpdate(sql1);
int j = statement.executeUpdate(sql2);
System.out.println("删除成功!");
}
汇入资金
先用方法得到汇入资金后的剩余余额,因为在记录中会要求导入剩余余额,其他的不难理解
public static void abmoney(Statement statement) throws SQLException {
System.out.println("你的姓名是:");
String name = scan.next();
System.out.println("原因:");
String reason = scan.next();
System.out.println("所汇入的金额为:");
double money = scan.nextDouble();
double balance = getBalance(statement)+money;
Date date = null;
String sqlGetTime = "select current_date() ;";
ResultSet resultSet = statement.executeQuery(sqlGetTime);
while(resultSet.next()){
date = resultSet.getDate(1);
}
String sql = "insert into charge_list (name,reason,time,u_money,a_money,balance)\n" +
"values(\n" +
"'毕竞羽',\n" +
"'"+reason+"',\n" +
"'"+date+"',\n" +
"0,\n" +
money+",\n" +
balance+"\n" +
");";
int i = statement.executeUpdate(sql);
sql = "insert into Balance (balance)\n" +
"values(\n" +
balance+"\n" +
")";
int j = statement.executeUpdate(sql);
System.out.println("记录成功!");
}
使用资金
和汇入资金差不多
public static void usmoney(Statement statement) throws SQLException {
System.out.println("你的姓名是:");
String name = scan.next();
System.out.println("原因:");
String reason = scan.next();
System.out.println("所申请的金额为:");
double money = scan.nextDouble();
double balance = getBalance(statement)-money;
Date date = null;
String sqlGetTime = "select current_date() ;";
ResultSet resultSet = statement.executeQuery(sqlGetTime);
while(resultSet.next()){
date = resultSet.getDate(1);
}
String sql = "insert into charge_list (name,reason,time,u_money,a_money,balance)\n" +
"values(\n" +
"'毕竞羽',\n" +
"'"+reason+"',\n" +
"'"+date+"',\n" +
money+",\n" +
"0,\n" +
balance+"\n" +
");";
int i = statement.executeUpdate(sql);
sql = "insert into Balance (balance)\n" +
"values(\n" +
balance+"\n" +
")";
int j = statement.executeUpdate(sql);
System.out.println("记录成功!");
}
查询余额
因为我有单独搞了一张表专门记录操作后的余额,因此实验室最后一次记录就是最新的余额,按序号倒叙排从0开始的第一个就是最新余额
public static double getBalance(Statement statement) throws SQLException {
String sql = "select b.balance\n" +
"from balance b \n" +
"order by charge_number desc \n" +
"limit 0,1;";
ResultSet resultSet = statement.executeQuery(sql);
double money =0;
while(resultSet.next()){
money = resultSet.getDouble("balance");
}
return money;
}
修改密码
提前传入登陆的master给name修改name本人的密码
public static void modifypas(Statement statement,String name) throws SQLException {
String password = null;
while(true){
System.out.println("请输入新密码:");
password = scan.next();
System.out.println("请再次确认新密码:");
String copy_password1 = scan.next();
if(password.equals(copy_password1)){
break;
}else{
System.out.println("两次密码不相同!请重新操作:");
}
}
String sql = "\n" +
"update lab_member \n" +
"set password = '"+ password +"' \n" +
"where name = '"+ name +"';";
int i = statement.executeUpdate(sql);
System.out.println("修改成功!");
};
记账记录
得到的结果集可以用一个元素类型为map的list来存储,一行数据等于一个map对象,key为列的名称,value为改列的数据;随着游标往后下走,,直到无数据
这里的列的名称可以用别名,且显示出来的结果记录观感差,可以试着让他更美观、可读一些
public static void alllist(Statement statement) throws SQLException {
String sql = "select * \n" +
"from charge_list ;";
ResultSet resultSet = statement.executeQuery(sql);
List<Map> list= new ArrayList<Map>();
ResultSetMetaData metaData = resultSet.getMetaData();
int clumn = metaData.getColumnCount();
while(resultSet.next()){
Map map = new HashMap();
for (int i = 1; i < clumn; i++) {
Object value = resultSet.getObject(i);
String columnLabel = metaData.getColumnLabel(i);
map.put(columnLabel,value);
}
list.add(map);
}
System.out.println(list);
}
jar包的导入
我已经资源绑定了
需要导入这三个,而且记得右键lib点add……操作
后言:
我会试着把这些放到githup里面,你们有时间的话一定要优化试试,原本的代码健壮性和效率很差,再提醒一次蓝色的部分为可以优化部分,如果你认为有其他的部分可以优化也可以评论区提出来。
此项目适合刚学完jdbc的(已经有mysql和java基础)学生,如果是大佬请找别的项目,不喜勿喷。