项目讲解:
本项目为单纯的后端练手项目,使用的开发工具是idea2022版,技术栈用到了javaEE,java多线程,java网络编程,JDBC。且分为两个分离的项目,一个服务器端,一个用户端。且每个用户在与服务器连接时,服务器都会新产生一个线程保持用户端的通信。
项目展示:
先启动服务器端,等待用户端连接,随后启动用户端
用户登录
用户端:
服务器端:
功能展示
1.用户查看个人信息
2.存款
数据库数据变化
3.转账
数据库数据变化
4.修改密码
数据库密码变化
5.退出登录
用户端自动退出
服务器端报告用户登出
服务器端代码
获取用户信息类
package com.wbf.function;
import com.wbf.JDBC.DBUtils;
import com.wbf.User.Account;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @BelongsProject: Bank-ATM-Manage
* @BelongsPackage: com.wbf.function
* @FileName: Message_
* @Author: 峰。
* @Date: 2023/7/20-10:22
* @Version: 1.0
* @Description:用于获取信息
*/
public class Message_ {
public static Account getAccount(Account account){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String sql =" select * from account where user_card = ?;";
try {
connection = DBUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,account.getCard());
resultSet = preparedStatement.getResultSet();
account.setAction(resultSet.getInt("action"));
account.setMoney(resultSet.getInt("user_money"));
account.setName(resultSet.getString("user_name"));
//结束后关闭数据库连接
DBUtils.ClearAll(connection,preparedStatement,resultSet);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
}
return account;
}
}
功能类
package com.wbf.function;
import com.wbf.JDBC.DBUtils;
import com.wbf.User.Account;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
/**
* @BelongsProject: Bank-ATM-Manage
* @BelongsPackage: com.wbf.function
* @FileName: Login_
* @Author: 峰。
* @Date: 2023/7/20-10:08
* @Version: 1.0
* @Description:
*/
public class Util_ {
public static boolean ReLogin(String card,String password,int num) {
Account account = new Account(card,password,num);
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
//遍历所有的账户,并从中挑选与用户名一致的进行密码对比
String sql = " select * from bank_account;";
HashMap<String, String> hm = new HashMap<>();
try {
connection = DBUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
//获取返回的resuleset对象后,将账号密码依次储存到hm里面去,然后进行验证
while (resultSet.next()) {
hm.put(resultSet.getString("user_card"), resultSet.getString("user_password"));
}
//结束后关闭数据库连接
DBUtils.ClearAll(connection, preparedStatement, resultSet);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
}
//开始验证
for (String s : hm.keySet()) {
if (account.getCard().equals(s)) {
if (account.getPassword().equals(hm.get(account.getCard()))) {
account.setLogin(true);
System.out.println(account.getCard() + "登录成功");
return account.isLogin();
} else {
System.out.println("用户名或密码错误");
return account.isLogin();
}
}
}
return false;
}
//用于获取账户信息
public static Account getMessage(Account account){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String sql = " select * from bank_account where user_card = "+account.getCard()+";";
try {
connection = DBUtils.getConnection();
// System.out.println("1111");/**/
preparedStatement = connection.prepareStatement(sql);
//preparedStatement.setString(1,account.getCard());
resultSet= preparedStatement.executeQuery(sql);
//将从数据库获取的信息给与account类中去
while (resultSet.next()) {
account.setMoney(resultSet.getInt("user_money"));
account.setAction(resultSet.getInt("user_action"));
account.setName(resultSet.getString("user_name"));
account.setPassword(resultSet.getString("user_password"));
}
//返回对象
//关闭通道
DBUtils.ClearAll(connection,preparedStatement,resultSet);
return account;
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//取款
public static Account withdraw(Account account){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String sql = " update bank_account set user_money = user_money -"+account.getMessage()+" where user_card = "+account.getCard()+";";
try {
connection = DBUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
//preparedStatement.setString(1,String.valueOf(account.getMessage()));
//preparedStatement.setString(2,account.getCard());
int res = preparedStatement.executeUpdate(sql);
System.out.println("执行了"+res+"条语句");
//数据存入account对象中
/*
while (resultSet.next()) {
account.setMoney(resultSet.getInt("user_money"));
}
*/
account = getMessage(account);
//返回对象并关闭通道
DBUtils.ClearAll(connection,preparedStatement,resultSet);
return getMessage(account);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//存款
public static Account StroageMoney(Account account){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String sql = " update bank_account set user_money = user_money +"+account.getMessage()+" where user_card = "+account.getCard()+";";
try {
connection = DBUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
//preparedStatement.setString(1,String.valueOf(account.getMessage()));
//preparedStatement.setString(2,account.getCard());
int res = preparedStatement.executeUpdate(sql);
System.out.println("执行了"+res+"条语句");
account = getMessage(account);
//数据存入account对象中
//返回对象并关闭通道
DBUtils.ClearAll(connection,preparedStatement,resultSet);
return getMessage(account);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//转账
public static Account transfser(Account account){
withdraw(account);
String user = account.getCard();
String tar_user = account.getTar_user();
account.setCard(tar_user);
StroageMoney(account);
account.setCard(user);
withdraw(account);
account = getMessage(account);
return account;
}
//修改密码
public static Account changePassword(Account account){
Account account1 = getMessage(account);
if (account1.getPassword().equals(account.getPassword())){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String sql = " update bank_account set user_password = '"+account.getTar_user()+"' where user_card = "+account.getCard()+";";
try {
connection = DBUtils.getConnection();
preparedStatement= connection.prepareStatement(sql);
// preparedStatement.setString(1,account.getTar_user());
// preparedStatement.setString(2,account.getCard());
int res = preparedStatement.executeUpdate(sql);
System.out.println("执行了"+res+"条语句");
DBUtils.ClearAll(connection,preparedStatement,resultSet);
return getMessage(account);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}else {
account.setTar_user("旧密码错误");
return account;
}
}
public static void Exit(){
}
}
数据库连接类
package com.wbf.JDBC;
import java.sql.*;
/**
* @BelongsProject: Tab8
* @BelongsPackage: com.JDBCConnect.www
* @FileName: DBUtils
* @Author: 峰。
* @Date: 2023/5/9-23:27
* @Version: 1.0
* @Description: JDBC工具类,两个方法,1)获取连接,2)释放资源
*/
public class DBUtils {
//1)建立连接
public static Connection getConnection() throws ClassNotFoundException, SQLException {
String url = "jdbc:mysql://localhost:3306/bank_";
String user = "root";
String password = "wbf";
Connection connection = (Connection) DriverManager.getConnection(url, user, password);
System.out.println("2222");
return connection;
}
//2)释放资源
public static void ClearAll(Connection connection, Statement statement, ResultSet resultSet) throws SQLException {
//空值不能关闭 先开后关
if (resultSet!=null){
resultSet.close();
}
if (statement!=null){
statement.close();
}
if (connection!=null){
connection.close();
}
}
}
数据库连接信息
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/db01 user=root password=wbf
线程类
package com.wbf.ThreadManage;
import com.wbf.User.Account;
import com.wbf.function.Util_;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
/**
* @BelongsProject: Bank-ATM-Manage
* @BelongsPackage: com.wbf.ThreadManage
* @FileName: ManageThread_
* @Author: 峰。
* @Date: 2023/7/20-10:34
* @Version: 1.0
* @Description:管理通讯线程
*/
public class ManageThread_ extends Thread{
private Socket socket;
private int ATM_number;
boolean bool = true;
Account account = null;
public ManageThread_(Socket socket,Account account){
this.socket = socket;
this.account = account;
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
public int getUser_card() {
return ATM_number;
}
public void setUser_card(String user_card) {
this.ATM_number = ATM_number;
}
@Override
public void run() {
System.out.println("服务器保持和ATM机"+ATM_number+"保持连接~");
try {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(account);
} catch (IOException e) {
throw new RuntimeException(e);
}
while(bool){
try {
//先验证account对象中的账号密码是否正确
if (Util_.ReLogin(account.getCard(),account.getPassword(),account.getATM_number())){
System.out.println(ATM_number+"账号信息验证成功");
while(bool){
//用于接收ATM机返回的对象
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
account = (Account) ois.readObject();
if (account.getMessageType() == 0){
account = Util_.getMessage(account);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//返回对象
oos.writeObject(account);
} else if (account.getMessageType() == 1){
//取款
account = Util_.withdraw(account);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//返回对象
oos.writeObject(account);
} else if (account.getMessageType() == 2) {
//存款
account = Util_.StroageMoney(account);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//返回对象
oos.writeObject(account);
} else if (account.getMessageType() == 3) {
account = Util_.transfser(account);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//返回对象
oos.writeObject(account);
} else if (account.getMessageType() == 4) {
account = Util_.changePassword(account);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//返回对象
oos.writeObject(account);
} else if (account.getMessageType() == 5){
//退出登录
System.out.println(account.getCard()+"退出登录");
account.setLogin(false);
bool = false;
socket.close();
}
}
}
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
}
线程管理类
package com.wbf.ThreadManage;
import java.util.HashMap;
/**
* @BelongsProject: Bank-ATM-Manage
* @BelongsPackage: com.wbf.ThreadManage
* @FileName: ThreadClass
* @Author: 峰。
* @Date: 2023/7/20-10:41
* @Version: 1.0
* @Description: 储存线程类
*/
public class ThreadClass {
static HashMap<Integer,ManageThread_> hm = new HashMap<>();
//添加线程的方法
public static void addThread(int ATM_number,ManageThread_ manageThread_){
hm.put(ATM_number,manageThread_);
}
}
两个实体类
package com.wbf.User;
import java.io.Serializable;
/**
* @BelongsProject: Bank-ATM-Service
* @BelongsPackage: com.wbf.User
* @FileName: Account
* @Author: 峰。
* @Date: 2023/7/19-11:39
* @Version: 1.0
* @Description: 账户登录显示
*/
public class Account implements Serializable {
private String card;
private String password;
private String name;
private int money;
private int action;
private int ATM_number;
private int MessageType;
private boolean login = false;
private int Message;
private String tar_user;
public String getTar_user() {
return tar_user;
}
public void setTar_user(String tar_user) {
this.tar_user = tar_user;
}
public int getMessageType() {
return MessageType;
}
public void setMessageType(int messageType) {
MessageType = messageType;
}
public int getMessage() {
return Message;
}
public void setMessage(int message) {
Message = message;
}
public boolean isLogin() {
return login;
}
public void setLogin(boolean login) {
this.login = login;
}
public String getCard() {
return card;
}
public void setCard(String card) {
this.card = card;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public int getAction() {
return action;
}
public void setAction(int action) {
this.action = action;
}
public int getATM_number() {
return ATM_number;
}
public void setATM_number(int ATM_number) {
this.ATM_number = ATM_number;
}
public Account(String card, String password, int number) {
this.card = card;
this.password = password;
this.ATM_number = number;
}
@Override
public String toString() {
return "Account{" +
"card='" + card + '\'' +
", name='" + name + '\'' +
", money=" + money +
", action=" + action +
", ATM_number=" + ATM_number +
", MessageType=" + MessageType +
", login=" + login +
", Message=" + Message +
'}';
}
public Account() {
}
}
package com.wbf.User;
import java.io.Serializable;
/**
* @BelongsProject: Bank-ATM-Service
* @BelongsPackage: com.wbf.ATM
* @FileName: ATM
* @Author: 峰。
* @Date: 2023/7/21-21:31
* @Version: 1.0
* @Description: ATM类
*/
public class ATM implements Serializable {
private int ATM_number;
private String card;
private String password;
public int getNum() {
return ATM_number;
}
public void setNum(int num) {
this.ATM_number = num;
}
public String getCard() {
return card;
}
public void setCard(String card) {
this.card = card;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
登录验证
package Manage_;
import com.wbf.ThreadManage.ManageThread_;
import com.wbf.ThreadManage.ThreadClass;
import com.wbf.User.ATM;
import com.wbf.User.Account;
import com.wbf.function.Util_;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @BelongsProject: Bank-ATM-Manage
* @BelongsPackage: Manage_
* @FileName: Manage
* @Author: 峰。
* @Date: 2023/7/19-11:51
* @Version: 1.0
* @Description:管理端
*/
public class Manage {
private ServerSocket ss = null;
private Account account = new Account();
boolean bool = true;
public Manage() throws IOException, ClassNotFoundException {
ss= new ServerSocket(8888);
// 服务器在端口8888监听事件
while (bool){
Socket socket = ss.accept();
System.out.println("服务端在8888端口监听");
//用于返回Message信息
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//得到socket关联的对象输入流
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
//接收客户端发送的ATM
ATM atm = (ATM) ois.readObject();
if (Util_.ReLogin(atm.getCard(),atm.getPassword(),atm.getNum())) {
// account = Message_.getAccount(account);
//返回对象
account.setCard(atm.getCard());
account.setPassword(atm.getPassword());
account.setATM_number(atm.getNum());
account.setLogin(true);
oos.writeObject(account);
//创建通讯线程,保持联系
ManageThread_ manageThread_ = new ManageThread_(socket, account);
//启动线程
manageThread_.start();
//储存线程
ThreadClass.addThread(atm.getNum(), manageThread_);
}else {
account.setLogin(false);
//返回对象
oos.writeObject(account);
System.out.println("登录失败");
}
}
}
}
用户端代码
用户端启动类
package com.wbf.ATM;
import com.wbf.User.Account;
import com.wbf.fuction.check_;
import java.util.Scanner;
/**
* @BelongsProject: Bank-ATM-Service
* @BelongsPackage: com.wbf.ATM
* @FileName: ATM_
* @Author: 峰。
* @Date: 2023/7/19-11:43
* @Version: 1.0
* @Description: ATM机启动界面
*/
public class ATM_ {
static public int number = 1;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("--------欢迎使用ATM机"+number+"号--------");
boolean bool = true;
boolean loop = true;
while (bool){
System.out.print("\n请输入账号:");
String user_card = scanner.next();
System.out.print("\n请输入密码:");
String user_password = scanner.next();
check_ check_ = new check_();
if (check_.check_Login(user_card,user_password,number)){
System.out.println("--------登录成功--------");
while (loop){
//进入功能菜单
System.out.println("请选择需要进行的操作:");
System.out.println("0.账户信息查询");
System.out.println("1.存款");
System.out.println("2.取款");
System.out.println("3.转账");
System.out.println("4.修改密码");
System.out.println("5.退出登录");
String choice = scanner.next();
switch (choice){
case "1":
check_.Stroage();
break;
case "2":
check_.Witdraw();
break;
case "3":
check_.transfer();
break;
case "4":
check_.changePassword();
break;
case "5":
check_.exit();
System.exit(0);
loop = false;
bool = false;
break;
case "0":
check_.checkMoney();
break;
}
}
}
}
}
}
功能实现类
package com.wbf.fuction;
import com.wbf.User.ATM;
import com.wbf.Thread_.ATMServerThread;
import com.wbf.Thread_.ThreadStroage;
import com.wbf.User.Account;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
/**
* @BelongsProject: Bank-ATM-Service
* @BelongsPackage: com.wbf.fuction
* @FileName: check_
* @Author: 峰。
* @Date: 2023/7/21-10:10
* @Version: 1.0
* @Description: 用于实现各种功能
*/
public class check_ {
private Scanner scanner = new Scanner(System.in);
ATM atm = new ATM();
private Account account =new Account();
private Socket socket = null;
public boolean check_Login(String user_card,String user_password,int ATM_number){
boolean b = false;
atm.setCard(user_card);
atm.setPassword(user_password);
atm.setNum(ATM_number);
//连接服务器
try {
socket =new Socket(InetAddress.getLocalHost(),8888);
System.out.println("与服务器建立连接成功");
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//发送对象
oos.writeObject(atm);
//接收返回的对象
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
account = (Account) ois.readObject();
if (account.isLogin()){
//验证登录成功则创建接收线程建立连接
ATMServerThread ast = new ATMServerThread(socket);
//启动线程
ast.start();
//储存线程,便于后续调用
ThreadStroage.addClientServerThread(user_card,ast);
//返回验证
return account.isLogin();
}else {
System.out.println("登录验证失败");
socket.close();
return account.isLogin();
}
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
//取款
public void Witdraw(){
account.setMessageType(1);
System.out.println("请输入取款金额:");
int num = scanner.nextInt();
account.setMessage(num);
ObjectTransfer();
}
//存款
public void Stroage(){
account.setMessageType(2);
System.out.println("请输入存款金额:");
int num = scanner.nextInt();
account.setMessage(num);
ObjectTransfer();
}
private void ObjectTransfer() {
//用于发送对象
try {
ObjectOutputStream oos = new ObjectOutputStream(ThreadStroage
.getClientConnectServerThread(account.getCard()).getSocket().getOutputStream());
//发送包含信息的对象
oos.writeObject(account);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//转账
public void transfer(){
account.setMessageType(3);
System.out.print("\n请输入目标账户:");
String tar_user = scanner.next();
System.out.print("\n请输入转账金额:");
int num = scanner.nextInt();
account.setTar_user(tar_user);
account.setMessage(num);
ObjectTransfer();
}
//修改密码
public void changePassword(){
account.setMessageType(4);
System.out.print("请输入旧密码:");
String newPassword = scanner.next();
if (newPassword.equals(account.getPassword())) {
System.out.print("请输入新密码:");
String OldPassword = scanner.next();
account.setTar_user(OldPassword);
ObjectTransfer();
}
}
//退出登录
public void exit(){
account.setMessageType(5);
ObjectTransfer();
}
//查看余额及账户信息
public void checkMoney(){
account.setMessageType(0);
ObjectTransfer();
}
}
AC异常解决类
package com.wbf.fuction;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/**
* AppendObjectOutputStream.java: 解决 java.io.StreamCorruptedException: invalid type code: AC 异常
*
* @author Spring-_-Bear
* @version 2021-10-30 21:48
*/
public class AppendObjectOutputStream extends ObjectOutputStream {
private static File file;
public static void initFile(File file) {
AppendObjectOutputStream.file = file;
}
public AppendObjectOutputStream(File file) throws IOException {
super(new FileOutputStream(file, true));
}
@Override
public void writeStreamHeader() throws IOException {
// 如果文件为空直接写入 StreamHeader
if (file == null || file.length() == 0) {
super.writeStreamHeader();
} else {
// 文件中存在内容,则说明文件中已经存在了一个 StreamHeader,调用父类的 reset() 方法保证文件中只存在一个 StreamHeader
this.reset();
}
}
}
用户端线程类
package com.wbf.Thread_;
import com.wbf.User.Account;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
/**
* @BelongsProject: Bank-ATM-Service
* @BelongsPackage: com.wbf.Thread_
* @FileName: ATMServerThread
* @Author: 峰。
* @Date: 2023/7/21-10:20
* @Version: 1.0
* @Description: 线程通讯类
*/
public class ATMServerThread extends Thread{
private Socket socket;
public ATMServerThread(Socket socket){
//通讯线程持有一个socket
this.socket=socket;
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//线程保持无限循环
while (true){
System.out.println("线程无限循环等待接收服务器发送的消息");
try {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Account account = (Account) ois.readObject();
System.out.println(account.toString());
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
}
用户端线程储存类
package com.wbf.Thread_;
import java.util.HashMap;
/**
* @BelongsProject: Bank-ATM-Service
* @BelongsPackage: com.wbf.Thread_
* @FileName: ThreadStroage
* @Author: 峰。
* @Date: 2023/7/21-10:49
* @Version: 1.0
* @Description: 储存线程, 方便后续调用
*/
public class ThreadStroage {
//把多个线程放入一个HashMap集合,key就是用户id,value就是线程
private static HashMap<String,ATMServerThread> hm = new HashMap<>();
//将某个线程加入集合
public static void addClientServerThread(String user_card,ATMServerThread ccst){
hm.put(user_card,ccst);
}
//通过方法获得线程
public static ATMServerThread getClientConnectServerThread(String user_card){
return hm.get(user_card);
}
}
省略了用户端俩个实体类