任务描述
银行存取款程序,实现查存取转款,注册登录和查询流水六个主要功能。
运行结果
基本类(Message,MessageType,User)
package study.J2023_3_31._4.bankclient.common;
import java.io.Serializable;
/**
* @Author: Rougue_Y
* @Date: 2023/4/24 8:57
* 用户信息
**/
public class User implements Serializable {
private String userId, password;//账号密码
private double banlence;//余额
private String MesType = MessageType.MESSAGE_LOGIN;//注册or登录
public User(String account, String password) {
this.userId = account;
this.password = password;
}
public User() {
}
public User(String account, String password, double banlence) {
this.userId = account;
this.password = password;
this.banlence = banlence;
}
public String getMesType() {
return MesType;
}
public void setMesType(String mesType) {
MesType = mesType;
}
public void modifyBanlence(double money) {//存取款
this.banlence += money;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public double getBanlence() {
return banlence;
}
public void setBanlence(double banlence) {
this.banlence = banlence;
}
}
package study.J2023_3_31._4.bankclient.common;
/**
* @Author: Rougue_Y
* @Date: 2023/4/25 7:19
**/
public interface MessageType {
String MESSAGE_REGISTER = "0";//注册
String MESSAGE_LOGIN = "1";//登录
String MESSAGE_CHECK = "2";//查款
String MESSAGE_DEPOSIT = "3";//存款
String MESSAGE_WITHDRAWAL = "4";//取款
String MESSAGE_TRANSFER_ACCOUNTS = "5";//转账
String MESSAGE_FLOW_DETAILS = "6";//流水明细
String MESSAGE_EXIT = "9";//退出
}
package study.J2023_3_31._4.bankclient.common;
import java.io.Serializable;
/**
* @Author: Rougue_Y
* @Date: 2023/4/24 8:57
* 用户信息
**/
public class User implements Serializable {
private String userId, password;//账号密码
private double banlence;//余额
private String MesType = MessageType.MESSAGE_LOGIN;//注册or登录
public User(String account, String password) {
this.userId = account;
this.password = password;
}
public User() {
}
public User(String account, String password, double banlence) {
this.userId = account;
this.password = password;
this.banlence = banlence;
}
public String getMesType() {
return MesType;
}
public void setMesType(String mesType) {
MesType = mesType;
}
public void modifyBanlence(double money) {//存取款
this.banlence += money;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public double getBanlence() {
return banlence;
}
public void setBanlence(double banlence) {
this.banlence = banlence;
}
}
客户端
界面类
package study.J2023_3_31._4.bankclient.bankview;
import study.J2023_3_31._4.bankclient.clientservice.ClientService;
import study.J2023_3_31._4.bankclient.clientservice.UserService;
import study.J2023_3_31._4.bankclient.common.User;
import study.J2023_3_31._4.utils.Utility;
/**
* @Author: Rougue_Y
* @Date: 2023/4/24 9:08
* 客户端菜单界面
**/
public class View {
private UserService userService = new UserService();
private ClientService clientService = new ClientService();
public void menu() {
boolean b = true;
User user = new User();
while (b) {
String account, password;
System.out.println("========一级菜单========");
System.out.print("1.登录\t\t2.注册\t\t9.退出\n请选择:");
String switch_1 = Utility.readString(1);
if (switch_1.equals("1")){//登录
System.out.print("账号:");
account = Utility.readString(50);
System.out.print("密码:");
password = Utility.readString(50);
user.setUserId(account);
user.setPassword(password);
}else if (switch_1.equals("2")){//注册
System.out.print("账号:");
account = Utility.readString(50);
System.out.print("密码:");
password = Utility.readString(50);
user.setUserId(account);
user.setPassword(password);
userService.register(account,password);
continue;
}else if (switch_1.equals("9")){//退出
System.out.println("客户端退出");
break;
}else {//不处理
System.out.println("无此选项,重新输入!");
continue;
}
//这里需要进行网络通讯判断账号密码是否合法
//初始化user
if (userService.checkUser(account, password)) {//登录合法
while (b) {
System.out.println("========二级菜单========");
System.out.print("1.存款\t2.取款\t3.查询\t4.转账\n5.流水信息\t9.退出\n请选择:");
String switch_2 = Utility.readString(1);
if (switch_2.equals("1")) {
clientService.deposit(userService.getUser(), userService.getSocket());
} else if (switch_2.equals("2")) {
clientService.withDrawal(userService.getUser(), userService.getSocket());
} else if (switch_2.equals("3")) {
clientService.checkBalence(userService.getUser(), userService.getSocket());
} else if (switch_2.equals("4")) {
clientService.transferAccounts(userService.getUser(), userService.getSocket());
} else if (switch_2.equals("5")) {
clientService.flowDetails(userService.getUser(),userService.getSocket());
} else if (switch_2.equals("9")) {
System.out.println("退出系统!");
clientService.logout(userService.getUser(), userService.getSocket());
b = false;
} else {
System.out.println("非法输入!");
}
}
}
}
}
public static void main(String[] args) {
new View().menu();
}
}
服务类(注册和登录功能)
package study.J2023_3_31._4.bankclient.clientservice;
import study.J2023_3_31._4.bankclient.common.Message;
import study.J2023_3_31._4.bankclient.common.MessageType;
import study.J2023_3_31._4.bankclient.common.User;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
* @Author: Rougue_Y
* @Date: 2023/5/8 12:15
* 客户端服务
**/
public class UserService {
private Socket socket;
private User user;
public User getUser() {
return user;
}
public Socket getSocket() {
return socket;
}
//检测账户合法
public boolean checkUser(String account, String password) {
boolean b = false;
user = new User(account, password);
try {
//注册情况会连接本机9999端口
socket = new Socket(InetAddress.getLocalHost(), 1234);
//把account对象传入服务器
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(user);
//读取message信息
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message = (Message) ois.readObject();
if (message.isSuccess()) {//登陆成功
//启动客户端接收服务端信息线程
ClientConnetServerThread clientConnetServerThread = new ClientConnetServerThread(socket, user);
clientConnetServerThread.start();
b = true;
} else {//登陆失败
//关闭
System.out.println("登陆失败");
socket.close();
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return b;
}
//注册账号
public void register(String account, String password) {
//准备一个注册消息对象
user = new User(account, password);
user.setMesType(MessageType.MESSAGE_REGISTER);
try {
//连接本机9999端口
socket = new Socket(InetAddress.getLocalHost(), 1234);
//发送注册用户对象
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(user);
//接收注册信息对象
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message = (Message) ois.readObject();
if (message.isSuccess()) {//注册成功
System.out.println(message.getUserId() + "注册成功!");
//启动客户端接收服务端信息线程
} else {//注册失败
System.out.println(message.getUserId() + "用户已存在,注册失败!");
}
socket.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
功能类(rucd和流水明细)
package study.J2023_3_31._4.bankclient.clientservice;
import study.J2023_3_31._4.bankclient.common.Message;
import study.J2023_3_31._4.bankclient.common.MessageType;
import study.J2023_3_31._4.bankclient.common.User;
import study.J2023_3_31._4.utils.Utility;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Date;
/**
* @Author: Rougue_Y
* @Date: 2023/5/9 20:31
* 用户功能
**/
public class ClientService {
//给服务端发送退出信息
public void logout(User user, Socket socket) {
//准备发送的信息
Message message = new Message();
message.setUserId(user.getUserId());
message.setMesType(MessageType.MESSAGE_EXIT);
message.setTime(new Date().toString());
//发送退出信息
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
//客户端正常退出
System.exit(0);
}
//给服务端发送查款消息
public void checkBalence(User user, Socket socket) {
//准备一个查款消息对象
Message message = new Message();
message.setMesType(MessageType.MESSAGE_CHECK);
message.setUserId(user.getUserId());
message.setTime(new Date().toString());
//发送查款消息对象
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
//给服务器发送存款消息
public void deposit(User user, Socket socket) {
System.out.print("请输入存款金额:");
String modifyMoney = Utility.readString(10);
//准备一个存款消息对象
Message message = new Message();
message.setUserId(user.getUserId());
message.setTime(new Date().toString());
message.setModifyMoney(Double.parseDouble(modifyMoney));
message.setMesType(MessageType.MESSAGE_DEPOSIT);
message.setContent("存款" + modifyMoney + "元\n\t\t" + message.getTime());
//发送存款消息对象
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
//给服务器发送取款消息
public void withDrawal(User user, Socket socket) {
System.out.print("请输入取款金额:");
String modifyMoney = Utility.readString(12);
//准备一个取款消息对象
Message message = new Message();
message.setMesType(MessageType.MESSAGE_WITHDRAWAL);
message.setModifyMoney(Double.parseDouble(modifyMoney));
message.setUserId(user.getUserId());
message.setTime(new Date().toString());
message.setContent("取款" + modifyMoney + "元\n\t\t" + message.getTime());
//发送取款消息对象
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
//给服务器发送转账信息
public void transferAccounts(User user, Socket socket) {
System.out.print("请输入转账人:");
String payee = Utility.readString(50);
System.out.print("请输入转账金额:");
String modifyMoney = Utility.readString(12);
//准备一个转账消息对象
Message message = new Message();
message.setMesType(MessageType.MESSAGE_TRANSFER_ACCOUNTS);
message.setUserId(user.getUserId());
message.setPayee(payee);
message.setModifyMoney(Double.parseDouble(modifyMoney));
message.setTime(new Date().toString());
message.setContent("转账" + modifyMoney + "元到" + payee + "\n\t\t" + message.getTime());
//发送一个转账消息对象
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
//给服务器发送流水信息
public void flowDetails(User user, Socket socket) {
//准备发送一个流水明细消息对象
Message message = new Message();
message.setUserId(user.getUserId());
message.setMesType(MessageType.MESSAGE_FLOW_DETAILS);
//发送一个流水明细消息对象
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
接收服务端信息线程类
package study.J2023_3_31._4.bankclient.clientservice;
import study.J2023_3_31._4.bankclient.common.Message;
import study.J2023_3_31._4.bankclient.common.MessageType;
import study.J2023_3_31._4.bankclient.common.User;
import study.J2023_3_31._4.utils.Utility;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
/**
* @Author: Rougue_Y
* @Date: 2023/5/8 22:53
* 客户端接收服务端信息线程
**/
public class ClientConnetServerThread extends Thread {
private User user;
private Socket socket;
public ClientConnetServerThread(Socket socket, User user) {
this.socket = socket;
this.user = user;
}
@Override
public void run() {
Message message;
while (true) {
try {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
message = (Message) ois.readObject();
if (message.getMesType().equals(MessageType.MESSAGE_CHECK)) {//查款
System.out.println(message.getUserId() + "余额为:" + message.getBanlence() + "\n\t\t" + message.getTime());
} else if (message.getMesType().equals(MessageType.MESSAGE_DEPOSIT)) {//存款
System.out.println(message.getUserId() + "存入" + message.getModifyMoney() +
"后余额为:" + message.getBanlence() + "\n\t\t" + message.getTime());
} else if (message.getMesType().equals(MessageType.MESSAGE_WITHDRAWAL)) {//取款
if (!(message.isSuccess())) {//余额不足
System.out.println(message.getUserId() + "余额不足!您当前余额为:" + message.getBanlence());
continue;
}
System.out.println(message.getUserId() + "取出" + message.getModifyMoney() +
"后余额为:" + message.getBanlence() + "\n\t\t" + message.getTime());
} else if (message.getMesType().equals(MessageType.MESSAGE_TRANSFER_ACCOUNTS)) {//转账
if (!(message.isSuccess())) {//用户不存在或余额不足
System.out.println("用户不存在或余额不足");
continue;
}
//转账成功
System.out.println(message.getUserId() + "转账" + message.getModifyMoney() + "到" +
message.getPayee() + "成功!当前余额为:" + message.getBanlence() + "\n\t\t" + message.getTime());
} else if (message.getMesType().equals(MessageType.MESSAGE_FLOW_DETAILS)) {//接收流水明细信息
System.out.println("========" + message.getUserId() + "流水明细========");
String[] userflow = message.getContent().split("~");
for (int i = 0; i < userflow.length; i++) {
System.out.println(userflow[i]);
if (i % 10 == 0 && i > 0) {//十个一行
System.out.print("输入Y继续查看,任意退出:");
String Y = Utility.readString(1);
if (!(Y.equals("Y"))) {
break;
}
}
}
} else {//暂不处理
System.out.println("暂无此功能");
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
服务端
连接客户端,实现登录注册功能
package study.J2023_3_31._4.bankserver.serverservice;
import study.J2023_3_31._4.bankclient.common.Message;
import study.J2023_3_31._4.bankclient.common.MessageType;
import study.J2023_3_31._4.bankclient.common.User;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author: Rougue_Y
* @Date: 2023/4/24 8:58
* 这是服务器, 在监听1234,等待客户端的连接,并保持通信
**/
public class BankServer {
private ServerSocket serverSocket = null;
private static ConcurrentHashMap<String, User> validUsers = new ConcurrentHashMap<>();//所有合法用户保存在此
public static ConcurrentHashMap<String, User> getValidUsers() {
return validUsers;
}
public static void registerUser(String userId,User user) {
validUsers.put(userId,user);
}
//默认合法人员
static {
validUsers.put("Ba",new User("Ba","123456"));
validUsers.put("小明",new User("小明","123"));
//加入流水明细,不然未登录过会导致转账目标用户无法加入转账流水
Iterator<String> iterator = validUsers.keySet().iterator();
while (iterator.hasNext()){
FlowDetails.addFlowDetails(new Message(iterator.next(), new Date().toString()));
}
}
public BankServer(){
try {
//监控1234端口
serverSocket = new ServerSocket(1234);
while (true){
//等待与客户端连接
Socket socket = serverSocket.accept();
//接收user用户并判断合法
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
User user = (User)ois.readObject();
//准备回复登陆是否合法信息
Message message = new Message();
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//发送登录非法信息
if (user.getMesType().equals(MessageType.MESSAGE_REGISTER)) {//注册
//发送登录非法信息
message.setUserId(user.getUserId());
message.setMesType(MessageType.MESSAGE_REGISTER);
if (validUsers.containsKey(user.getUserId())){//存在此用户不能注册
//准备发送注册失败信息
message.setSuccess(false);
//发送注册失败信息
oos.writeObject(message);
}
//成功注册则加入合法集合中
registerUser(user.getUserId(),user);
//发送注册成功信息
oos.writeObject(message);
FlowDetails.addFlowDetails(new Message(user.getUserId(),new Date().toString()));
socket.close();
continue;
}
if (validUsers.containsKey(user.getUserId())&&
validUsers.get(user.getUserId()).getPassword().equals(user.getPassword())){//用户合法
//发送登陆合法信息
message.setMesType(MessageType.MESSAGE_LOGIN);
oos.writeObject(message);
//启动该服务器连接用户线程接收信息
ServerConnectClientThread serverConnectClientThread =
new ServerConnectClientThread(socket,BankServer.getValidUsers().get(user.getUserId()));
serverConnectClientThread.start();
}else {//用户账号或密码不合法
message.setSuccess(false);
message.setMesType(MessageType.MESSAGE_LOGIN);
oos.writeObject(message);
//关闭与客户端通讯
socket.close();
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
//服务器异常退出情况
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new BankServer();
}
}
接收客户端线程类
package study.J2023_3_31._4.bankserver.serverservice;
import study.J2023_3_31._4.bankclient.common.User;
import study.J2023_3_31._4.bankclient.common.Message;
import study.J2023_3_31._4.bankclient.common.MessageType;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
/**
* @Author: Rougue_Y
* @Date: 2023/5/8 20:42
* 该线程用户接收用户信息
**/
public class ServerConnectClientThread extends Thread {
private Socket socket;
private User user;
public ServerConnectClientThread(Socket socket, User user) {
this.socket = socket;
this.user = user;
}
@Override
public void run() {
Message message;//用于接收用户的message
while (true) {
try {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
message = (Message) ois.readObject();
System.out.println("与客户端" + message.getUserId() + "通讯中");
if (message.getMesType().equals(MessageType.MESSAGE_CHECK)) {//查款
//准备发送准备的message
message.setBanlence(user.getBanlence());
//发送message
oos.writeObject(message);
} else if (message.getMesType().equals(MessageType.MESSAGE_DEPOSIT)) {//存款
//更新用户余额
user.setBanlence(user.getBanlence()+message.getModifyMoney());
//准备发送准备的message
message.setBanlence(user.getBanlence());
//发送message
oos.writeObject(message);
FlowDetails.addFlowDetails(message);
} else if (message.getMesType().equals(MessageType.MESSAGE_WITHDRAWAL)) {//取款
//能否取款
if (message.getModifyMoney() > user.getBanlence()) {//余额不足
message.setSuccess(false);
message.setBanlence(user.getBanlence());
oos.writeObject(message);
} else {//成功取款
//更新用户余额
user.setBanlence(user.getBanlence() - message.getModifyMoney());
message.setBanlence(user.getBanlence());
//发送message
oos.writeObject(message);
FlowDetails.addFlowDetails(message);
}
} else if (message.getMesType().equals(MessageType.MESSAGE_TRANSFER_ACCOUNTS)) {//汇款
//先判断转账到达的用户是否存在
if (!(BankServer.getValidUsers().containsKey(message.getPayee()))) {//不存在此用户
message.setSuccess(false);
oos.writeObject(message);
continue;
}
//余额是否足够转账
if (message.getModifyMoney() > user.getBanlence()) {//余额不足
message.setSuccess(false);
message.setBanlence(user.getBanlence());
} else {
//更新相关两个用户余额
user.setBanlence(user.getBanlence() - message.getModifyMoney());
User payeeUser = BankServer.getValidUsers().get(message.getPayee());
payeeUser.setBanlence(payeeUser.getBanlence() + message.getModifyMoney());
//准备发送转账信息对象
message.setBanlence(user.getBanlence());
}
//发送message
oos.writeObject(message);
FlowDetails.addFlowDetails(message);
}else if (message.getMesType().equals(MessageType.MESSAGE_FLOW_DETAILS)){//流水明细
//准备发送流水明细
message.setContent(FlowDetails.getFlowDetails(message));
//发送流水明细消息
oos.writeObject(message);
}
else if (message.getMesType().equals(MessageType.MESSAGE_EXIT)) {//退出
System.out.println(message.getUserId() + "退出");
break;
} else {
System.out.println("暂不处理");
}
}catch (IOException | ClassNotFoundException e){
e.printStackTrace();
}
}
}
}
实现流水明细功能
package study.J2023_3_31._4.bankserver.serverservice;
/**
* @Author: Rougue_Y
* @Date: 2023/5/11 20:34
* 流水明细功能处理
**/
import study.J2023_3_31._4.bankclient.common.Message;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
/**
* 每个用户都有一份独有的流水明细
* 流水明细会随着存取转款随时变化,应注意线程安全
* 注册后应在集合内就已有此用户名
*/
public class FlowDetails {
private static ConcurrentHashMap<String, LinkedList<String>> allflow = new ConcurrentHashMap<>();
//添加流水明细
public static void addFlowDetails(Message message) {
if (!(allflow.containsKey(message.getUserId()))) {//用户刚注册,不存在
allflow.put(message.getUserId(), new LinkedList<>());
allflow.get(message.getUserId()).add(message.getUserId() + "注册成功!\n\t" + message.getTime());
} else {//存在此用户
allflow.get(message.getUserId()).add(message.getUserId() + message.getContent());
if (message.getPayee() != null&&allflow.containsKey(message.getPayee())){
allflow.get(message.getPayee()).add(message.getUserId() + message.getContent());
}
}
System.out.println(message.getUserId() + "添加流水成功");
}
//获取流水明细
public static String getFlowDetails(Message message) {
Iterator<String> flowlist = allflow.get(message.getUserId()).iterator();
String userflow = "";
while (flowlist.hasNext()) {
userflow = flowlist.next() + "~" + userflow;
}
return userflow;
}
}