1.多线程
在本项目中的线程安全体现在客户端的读线程, 通过人为的控制和调度, 保证共享资源的多线程访问成为线程安全, 保证结果的准确
//一个对象一把锁,即所有客户端的读线程是共用一把锁
synchronized (ClientDemo.class) {
if (ClientDemo.lastResponse == null) {
try {
ClientDemo.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 读到了消息
MyResponse lastResponse = ClientDemo.lastResponse;
ClientDemo.lastResponse = null;
System.out.println(lastResponse.getrMeg().get(MyResponse.MEG_CONTENT));
// 判断登入是否成功,成功则进入操作界面,不成功就返回到开始界面
if (lastResponse.isSuccess()) {
// 登入成功进入第二层操作界面
this.uName = uName;
SecondMenu sm = new SecondMenu(oos, lastResponse);
sm.operateMenu(level, uName);// 登入成功后三个身份界面
} else {
startMenu();
}
ClientDemo.class.notify();
}
}
2.客户端-服务器通信
MyRequest类和MyResponse类为服务器和客户端两个项目共享
MyRequest是请求对象,由客户端写,服务器读,
MyResponse是响应对象,由服务器写,客户端读
MyRequest类
比如登录功能,输入用户名密码后,点击登录按钮,输入的用户名密码包装成request对象
客户端对myquest对象的包装方式:常量type是请求类型,放入成员属性type中,字典集中key为string类型常量,value为实际的信息.
如:key:MEG_UNAME value:aa存放用户名
package com.bwf.jar;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
public class MyRequest implements Serializable{
/**
* 序列化
*/
private static final long serialVersionUID = -1837937764657754236L;
private int type;
private Map<String,String> umap = new HashMap<>();
//常量
public static final int TYPE_REGIST = 1;
public static final int TYPE_LOGIN = 2;
public static final int TYPE_LOGOUT = 16;
//彩民
public static final int TYPE_CHANGEPWD = 4;
public static final int TYPE_RECHARGE = 5;
public static final int TYPE_BET = 6;
public static final int TYPE_SHOWMESSAGE = 7;
public static final int TYPE_DELETEME = 8;
public static final int TYPE_BET_FLUSH = 9;
//管理员
public static final int TYPE_ADMIN_ISSUE = 10;
public static final int TYPE_ADMIN_FINDBUYER = 11;
public static final int TYPE_ADMIN_SORTBUYER_BYID = 12;
public static final int TYPE_ADMIN_SORTBUYER_BYMONEY = 13;
public static final int TYPE_ADMIN_GETHISTORY = 19;
//公证员
public static final int TYPE_GREFFIER_DRAWLOTTERY = 14;
public static final int TYPE_GREFFIER_SHOWLOTTERYMEG = 15;
//登入者的信息
public static final String MEG_USERNAME = "uName";
public static final String MEG_USERPWD = "uPwd";
public static final String MEG_LEVEL = "level"; //登入者的身份
public static final String MEG_NEWPWD = "newPwd";//修改密码的时候需要设置
public static final String MEG_ADDMONEY = "addMoney";//修改余额
//彩票信息
public static final String LOTTERY_SELECTNUM = "selectNum";//彩票号码
public static final String LOTTERY_BUYCOUNT = "buyCount";//彩票注数
public static final String LOTTERY_TIME = "time";//彩票期号
public static final String LOTTERY_NEWPRICE = "newPrice";//新的单价
public static final String LOTTERY_WINNUM = "winNum";//开奖号码
public static final String ADMIN_BUYERID = "buyerId";//被查询的彩民ID
public static final String MEG = "meg";
public MyRequest(int type) {
super();
this.type = type;
}
public int getType() {
return type;
}
public Map<String, String> getUmap() {
return umap;
}
@Override
public String toString() {
return "MyRequest [type=" + type + ", umap=" + umap + "]";
}
}
客户端写线程通过套接字的输出流把请求对象发送到服务器
扫描二维码关注公众号,回复:
3666081 查看本文章
package com.bwf.client;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import com.bwf.jar.MyRequest;
import com.bwf.jar.MyResponse;
public class ClientMenu {
private Socket socket;
private ObjectOutputStream oos;
private String uName;
public ClientMenu(Socket socket) throws IOException {
super();
//套接字由构造传入
this.socket = socket;
oos = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
}
// 这里放所有客户端的菜单方法
public void startMenu() throws IOException {
while (true) {
// 开始界面就是登入界面
login();
}
}
private void login() throws IOException {
// 这里修改成GUI的界面
System.out.println("登入界面:");
System.out.println("请输入你是否需要注册:0-是,1-不是");
int chose = ClientDemo.sc.nextInt();
if (chose == 0) {
regist();
return;
}
System.out.println("请输入用户名:");
String uName = ClientDemo.sc.next();
System.out.println("请输入密码:");
String uPwd = ClientDemo.sc.next();
System.out.println("还需要接收一个值,表示登入者的身份:");
// 三个身份(1-彩民,2-管理员,3-公证员)这个身份也决定了服务器从那个表中查询数据
String level = "彩民";
// 包装成一个类
MyRequest request = new MyRequest(MyRequest.TYPE_LOGIN);
request.getUmap().put(MyRequest.MEG_USERNAME, uName);
request.getUmap().put(MyRequest.MEG_USERPWD, uPwd);
request.getUmap().put(MyRequest.MEG_LEVEL, level);
// 包装好了,就发送过去,序列化
oos.writeObject(request);
oos.flush();
//一个对象一把锁,即所有客户端的读线程是共用一把锁
synchronized (ClientDemo.class) {
if (ClientDemo.lastResponse == null) {
try {
ClientDemo.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 读到了消息
MyResponse lastResponse = ClientDemo.lastResponse;
ClientDemo.lastResponse = null;
System.out.println(lastResponse.getrMeg().get(MyResponse.MEG_CONTENT));
// 判断登入是否成功,成功则进入操作界面,不成功就返回到开始界面
if (lastResponse.isSuccess()) {
// 登入成功进入第二层操作界面
this.uName = uName;
SecondMenu sm = new SecondMenu(oos, lastResponse);
sm.operateMenu(level, uName);// 登入成功后三个身份界面
} else {
startMenu();
}
ClientDemo.class.notify();
}
}
// private void tellServer() throws IOException {
// MyRequest request = new MyRequest(MyRequest.TYPE_LOGOUT);
// request.getUmap().put(MyRequest.MEG, "用户下线!!!");
// request.getUmap().put(MyRequest.MEG_USERNAME, uName);
//
// oos.writeObject(request);
// oos.flush();
//
// }
private void regist() throws IOException {
// 接受用户输入的用户名和密码
System.out.println("请注册:");
System.out.println("请输入用户名:");
String uName = ClientDemo.sc.next();
System.out.println("请输入密码:");
String uPwd = ClientDemo.sc.next();
// 包装成一个类
MyRequest request = new MyRequest(MyRequest.TYPE_REGIST);
request.getUmap().put(MyRequest.MEG_USERNAME, uName);
request.getUmap().put(MyRequest.MEG_USERPWD, uPwd);
// 包装好了,就发送过去,序列化
oos.writeObject(request);
oos.flush();
synchronized (ClientDemo.class) {
if (ClientDemo.lastResponse == null) {
try {
ClientDemo.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 读到了消息
MyResponse lastResponse = ClientDemo.lastResponse;
ClientDemo.lastResponse = null;
System.out.println(lastResponse.getrMeg().get(MyResponse.MEG_CONTENT));
if (lastResponse.isSuccess()) {
startMenu();
}else {
}
notify();
}
}
}
服务器收到后根据响应类型转到相应的case进行处理
package com.bwf.server;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import com.bwf.context.ApplicationContext;
import com.bwf.jar.MyRequest;
import com.bwf.jar.MyResponse;
import com.bwf.service.AdminService;
import com.bwf.service.UserService;
public class ServerThread implements Runnable {
private Socket socket;
private UserService us;
private AdminService as;
// 这个记录所有在线的客户
public static Map<String, ObjectOutputStream> onLineMap = new HashMap<>();
public ServerThread(Socket socket) {
super();
this.socket = socket;
}
@Override
public void run() {
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
try {
//通过套接字获得输入输出流
ois = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
oos = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
MyRequest request = null;
// 初始化读取xml文件,实例化对象并存入map,注入依赖
ApplicationContext.init();
us = (UserService) ApplicationContext.getBean("UserService");
as = (AdminService) ApplicationContext.getBean("AdminService");
while ((request = (MyRequest) ois.readObject()) != null) {
System.out.println(request);// 测试通信
MyResponse response = null;// 日志功能暂时不做,但是保留这个
switch (request.getType()) {
case MyRequest.TYPE_REGIST:
try {
response = us.doRegist(request, oos);
System.out.println("注册成功!!");
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case MyRequest.TYPE_LOGIN:
try {
response = us.doLogin(request, oos);
System.out.println(response.toString());
} catch (Exception e) {
System.out.println("登入失败!!");
System.out.println(e.getMessage());
}
break;
case MyRequest.TYPE_CHANGEPWD:
try {
response = us.doChangePwd(request, oos);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case MyRequest.TYPE_RECHARGE:
try {
response = us.doRecharge(request, oos);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case MyRequest.TYPE_BET:
try {
response = us.doBet(request, oos);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case MyRequest.TYPE_SHOWMESSAGE:
try {
response = us.doShowMessage(request, oos);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case MyRequest.TYPE_BET_FLUSH:
try {
response = us.doBetFlush(request, oos);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
// case MyRequest.TYPE_USER_LOGOUT:
// try {
// System.out.println(request);
// response = us.doUserLogout(request,oos);
// } catch (Exception e) {
// System.out.println(e.getMessage());
// }
// break;
// 从这里开始是管理员的功能
case MyRequest.TYPE_ADMIN_ISSUE:
try {
response = as.doIssue(request, oos);
System.out.println(response.isIssue());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case MyRequest.TYPE_ADMIN_FINDBUYER:
try {
response = as.doFindBuyer(request, oos);
System.out.println(response.isIssue());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case MyRequest.TYPE_ADMIN_SORTBUYER_BYID:
try {
response = as.doSortBuyerById(request, oos);
System.out.println(response.isIssue());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case MyRequest.TYPE_ADMIN_SORTBUYER_BYMONEY:
try {
response = as.doSortBuyerByMoney(request, oos);
System.out.println(response.toString());
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
// case MyRequest.TYPE_ADMIN_SORTBUYER_BYMONEY:
// try {
// response = as.doSortBuyerByMoney(request, oos);
// System.out.println(response.toString());
// } catch (Exception e) {
// System.out.println(e.getMessage());
// }
// break;
//
//这里开始是公证员的功能
case MyRequest.TYPE_GREFFIER_DRAWLOTTERY:
try {
response = as.doDrawLottery(request, oos);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case MyRequest.TYPE_GREFFIER_SHOWLOTTERYMEG:
try {
System.out.println(request);
response = as.doShowLotteryMeg(request, oos);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case MyRequest.TYPE_LOGOUT:
delClientUser(request);
break;
default:
break;
}
// if(response != null) {
// LogRecord log = new LogRecord(new Date(), socket.getInetAddress().toString(),
// request, response);
// FileUtil.saveLog(log);
// }
}
} catch (SocketException e) {
Iterator<Entry<String, ObjectOutputStream>> iterator = onLineMap.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, ObjectOutputStream> next = iterator.next();
if (next.getValue().equals(oos)) {
iterator.remove();
System.out.println(next.getKey() + "删除成功!!");
}
}
System.out.println("客户端退出!!");
return;
} catch (IOException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private void delClientUser(MyRequest request) {
String name = request.getUmap().get(MyRequest.MEG_USERNAME);
onLineMap.remove(name);
}
// private String getNewContent(String content, String name, String str) {
// Date date = new Date();
// SimpleDateFormat sdf = new SimpleDateFormat("yy/MM/dd HH:mm:ss ");
// String s_date = sdf.format(date);
//
// StringBuilder sb = new
// StringBuilder(s_date).append(name).append(str).append(" : ").append(content);
// return sb.toString();
// }
}
服务器处理完成后包装响应对象发送回客户端,响应对象和请求对象类似,故不做赘述.
客户端收到后根据响应类型作相应处理.