使用Socket实现银行查看余额,存款,取款用来理解Socket的使用,和如何在配置文件中存取数据有深刻的理解
相关变量
//操作存钱取钱查看钱的业务代码
BankService bankService = new BankService();
//获取与客户端连接的相关流
InputStream inputStream = socket.getInputStream();
//DataInputStream流可以直接对基本数据类型操作 使用简单 不需使数据类型转换
DataInputStream dis = new DataInputStream(inputStream);
OutputStream outputStream = socket.getOutputStream();
//DataOutputStream流可以直接对基本数据类型操作 使用简单 不需使数据类型转换
DataOutputStream dos = new DataOutputStream(outputStream);
boolean running = true;
//将running设置为true 循环接受客户端消息
查看余额
客户端实现
System.out.println("|查询金额:1|\n|存款:2|\n|取款:3|");
case "1":
cmd = "balance\n";
break;
//将命令写回服务端 服务端执行相关操作
dos.writeBytes(cmd);
System.out.println("请输入账号:");
String account = scanner.nextLine();
//将账号写回服务端 服务端执行相关操作
dos.writeBytes(account + "\n");
服务端实现
//接收客户端命令信息 用来操作下面的查看余额等操作
String cmd = dis.readLine();
System.out.println(cmd);
//输出客户端输入的账号信息
String account =dis.readLine();
System.out.println(account);
//查询余额
case "balance":
//调用bankService业务代码 得到账号余额
String balance = bankService.balance(account);
dos.writeBytes(balance + "\n");
break;
存款
客户端实现
System.out.println("|查询金额:1|\n|存款:2|\n|取款:3|");
case "2":
cmd = "deposit\n";
break;
//将命令写回服务端 服务端执行相关操作
dos.writeBytes(cmd);
System.out.println("请输入账号:");
String account = scanner.nextLine();
//将账号写回服务端 服务端执行相关操作
dos.writeBytes(account + "\n");
//如果不是查看余额 则用户有存取款金额操作
if (!"balance\n".equals(cmd)) {
System.out.println("请输入金额:");
double money = scanner.nextDouble();
dos.writeDouble(money);
//scanner.nextDouble(); 只能接受到double数 用scanner.nextLine();接收回车
scanner.nextLine();
}
服务端实现
//存款
case "deposit":
//客户端输入存入的金额
money = dis.readDouble();
//调用bankService业务代码存款并得到账号余额
System.err.println("存入金额:" + money);
String deposit = bankService.deposit(account, money);
//将存入后的新金额数写回给客户端 "DataInputStream"类读取时需要换行符 否则会阻塞 所以加上 \n
dos.writeBytes(deposit + "\n");
break;
取款和上面存款操作差不多 主要看下当取款金额大于当前金额时的业务代码
Service
//取款
public String withdraw(String account,double money){
//先取出当前账户的金额
String accountMoney = oprateProperties.getKeyValue(account);
//若当前取款金额大于账户金额 返回ERROR取钱失败
double withdrawMoney = Double.parseDouble(accountMoney) - money;
if(withdrawMoney < 0){
return "ERROR";//取款金额大于账号总金额
}
//当最后一个参数为flase表示取钱 将money的钱取入account账户中 存入properties文件中
oprateProperties.setKeyValue(account, money+"", false);
return oprateProperties.getKeyValue(account);
}
//从properties中设置账户和金额 flag为true时对原始金额做存款操作 flag为false时对原始金额做取款操作
public void setKeyValue(String key,String value,boolean flag){
//进行存取款操作
String val = getKeyValue(key);
//账户里的金额
double previousMoney = Double.parseDouble(val);
//要操作的金额数
double changedMoney = Double.parseDouble(value);
//操作后的金额
String currentMoney;
//flag 为true 存款
if(flag){
currentMoney = (previousMoney + changedMoney) + "";
}else{
//false 取款
currentMoney = (previousMoney - changedMoney) + "";
}
//将账号的金额数改变
properties.setProperty(key, currentMoney);
//将数据保存到properties文件中
storeProperties();
}
完整实现代码:
需要手动创建一个空的bank.properties文件
//要存入的文件名 放在src下
public final static String FILE_NAME = "bank.properties";
可以改成自己定义的名字
操作properties的工具类OprateProperties
OprateProperties.java
package com.jt.utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class OprateProperties {
//要存入的文件名 放在src下
public final static String FILE_NAME = "bank.properties";
private Properties properties = new Properties();
//获取此文件的输入流 对properties进行加载操作
private InputStream in = OprateProperties.class.getClassLoader().getResourceAsStream(FILE_NAME);
//得到当前账号key的金额 key为账号 account
public String getKeyValue(String key){
loadProperties();
if(properties.containsKey(key)){
return properties.getProperty(key);
}
//如果没有当前账号则返回 0 设置值时 新建此用户
return "0";
}
//从properties中设置账户和金额 flag为true时对原始金额做存款操作 flag为false时对原始金额做取款操作
public void setKeyValue(String key,String value,boolean flag){
//进行存取款操作
String val = getKeyValue(key);
//账户里的金额
double previousMoney = Double.parseDouble(val);
//要操作的金额数
double changedMoney = Double.parseDouble(value);
//操作后的金额
String currentMoney;
//flag 为true 存款
if(flag){
currentMoney = (previousMoney + changedMoney) + "";
}else{
//false 取款
currentMoney = (previousMoney - changedMoney) + "";
}
//将账号的金额数改变
properties.setProperty(key, currentMoney);
//将数据保存到properties文件中
storeProperties();
}
//加载配置文件里面的账号金额信息
public void loadProperties(){
try {
properties.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//将数据保存到properties文件中
public void storeProperties(){
try {
//获取src下文件的绝对路径
String filePath = System.getProperty("user.dir")+"\\src\\" + FILE_NAME;
FileOutputStream fos = new FileOutputStream(new File(filePath));
System.out.println(filePath);
//第二个参数 是注解 #bank server
properties.store(fos, "bank server");
} catch (IOException e) {
e.printStackTrace();
}
}
}
完成Bank的业务代码BankService
BankService.java
package com.jt.socket.bank;
import com.jt.utils.OprateProperties;
public class BankService {
//oprateProperties相当于数据库操作的dao层
private OprateProperties oprateProperties = new OprateProperties();
public String balance(String account){
//获得account账号的money值
return oprateProperties.getKeyValue(account);
}
//存款
public String deposit(String account,double money){
//将钱存入properties文件中 当最后一个参数为true表示存钱 将money的钱存入account账户中
oprateProperties.setKeyValue(account, money+"", true);
//返回存好前后的金额
return oprateProperties.getKeyValue(account);
}
//取款
public String withdraw(String account,double money){
//先取出当前账户的金额
String accountMoney = oprateProperties.getKeyValue(account);
//若当前取款金额大于账户金额 返回ERROR取钱失败
double withdrawMoney = Double.parseDouble(accountMoney) - money;
if(withdrawMoney < 0){
return "ERROR";//取款金额大于账号总金额
}
//当最后一个参数为flase表示取钱 将money的钱取入account账户中 存入properties文件中
oprateProperties.setKeyValue(account, money+"", false);
return oprateProperties.getKeyValue(account);
}
}
BankServer服务端代码
BankServer.java
package com.jt.socket.bank;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class BankServer {
@SuppressWarnings("deprecation")
public static void main(String[] args) throws Exception {
//操作存钱取钱查看钱的业务代码
BankService bankService = new BankService();
//Bank服务端创建 和 与客户端建立连接
ServerSocket server = new ServerSocket(9999);
Socket socket = server.accept();
System.out.println("客户端连接成功");
//获取与客户端连接的相关流
InputStream inputStream = socket.getInputStream();
//DataInputStream流可以直接对基本数据类型操作 使用简单 不需使数据类型转换
DataInputStream dis = new DataInputStream(inputStream);
OutputStream outputStream = socket.getOutputStream();
//DataOutputStream流可以直接对基本数据类型操作 使用简单 不需使数据类型转换
DataOutputStream dos = new DataOutputStream(outputStream);
boolean running = true;
//将running设置为true 循环接受客户端消息
while (running) {
//接收客户端命令信息 用来操作下面的查看余额等操作
String cmd = dis.readLine();
System.out.println(cmd);
//输出客户端输入的账号信息
String account =dis.readLine();
System.out.println(account);
//用来操作 存款和取款操作
double money = 0;
//判断是什么cmd命令
switch (cmd) {
//查询余额
case "balance":
//调用bankService业务代码 得到账号余额
String balance = bankService.balance(account);
dos.writeBytes(balance + "\n");
break;
//存款
case "deposit":
//客户端输入存入的金额
money = dis.readDouble();
//调用bankService业务代码存款并得到账号余额
System.err.println("存入金额:" + money);
String deposit = bankService.deposit(account, money);
//将存入后的新金额数写回给客户端 "DataInputStream"类读取时需要换行符 否则会阻塞 所以加上 \n
dos.writeBytes(deposit + "\n");
break;
//取款
case "withdraw":
//客户端输入存入的金额
money = dis.readDouble();
//调用bankService业务代码取款并得到账号余额
System.err.println("取出金额:" + money);
String withdraw = bankService.withdraw(account, money);
//将存入后的新金额数写回给客户端 "DataInputStream"类读取时需要换行符 否则会阻塞 所以加上 \n
dos.writeBytes(withdraw + "\n");
break;
}
}
server.close();
}
}
客户端BankClient代码
BankClient.java
package com.jt.socket.bank;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class BankClient {
@SuppressWarnings("deprecation")
public static void main(String[] args) throws Exception {
// 客户端与服务端建立连接
Socket socket = new Socket("127.0.0.1", 9999);
// 创建一个控制台输入对象
Scanner scanner = new Scanner(System.in);
// 获取与客户端连接的相关流
InputStream inputStream = socket.getInputStream();
// DataInputStream流可以直接对基本数据类型操作 使用简单 不需使数据类型转换
DataInputStream dis = new DataInputStream(inputStream);
OutputStream outputStream = socket.getOutputStream();
// DataOutputStream流可以直接对基本数据类型操作 使用简单 不需使数据类型转换
DataOutputStream dos = new DataOutputStream(outputStream);
boolean running = true;
//将running设置为true 循环接受服务端消息
while (running) {
//提示用户操作
System.out.println("_______________________________");
System.out.println("|查询金额:1|\n|存款:2|\n|取款:3|");
System.out.println("_______________________________");
String commend = scanner.nextLine();
String cmd = null;
//用户输入命令
switch (commend) {
case "1":
cmd = "balance\n";
break;
case "2":
cmd = "deposit\n";
break;
case "3":
cmd = "withdraw\n";
break;
}
//将命令写回服务端 服务端执行相关操作
dos.writeBytes(cmd);
System.out.println("请输入账号:");
String account = scanner.nextLine();
//将账号写回服务端 服务端执行相关操作
dos.writeBytes(account + "\n");
//如果不是查看余额 则用户有存取款金额操作
if (!"balance\n".equals(cmd)) {
System.out.println("请输入金额:");
double money = scanner.nextDouble();
dos.writeDouble(money);
//scanner.nextDouble(); 只能接受到double数 用scanner.nextLine();接收回车
scanner.nextLine();
}
//读取服务端执行相关命令后返回给用户的金额
String currentMoney = dis.readLine();
System.out.println(account + "当前金额:" + currentMoney);
}
socket.close();
scanner.close();
}
}