基于java socket的订票程序
课程作业,用java的socket写了一个控制台版本的机票预订程序,实现了机票的用户的登录,查询,和订票已经历史订票记录查询。
算是对以前学过的socket网络编程的一次巩固吧,有关socket简单的c/s模型可看我的这篇博客:点击打开链接
重要的是对等协议的使用,客户端和服务器端消息收发的对称性。
协议(protocal)都是是自己定义的。
这里使用了多线程,可以满足多个客户端同时登录,服务器端关于购票业务的同步并发做的不是很完善。
越做到后面越感觉重要的是业务,不是程序的实现了。
使用的知识有java+socket+thread+jdbc+mysql。
业务处理基本都在服务器端,算是一个胖服务器吧,下图差不多可以表示了:
下面是该程序设计的类图:
下面是代码:
package pack1;
import java.io.*;
import java.lang.Thread.State;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import com.dao.FlightManageDAO;
import com.dao.LoginDAO;
import com.dao.TicketManageDAO;
import com.model.Flight;
import com.model.Passenger;
import com.model.Ticket;
/**
* 服务器端
* @author XWZ
*
*/
/*常量协议接口*/
interface Protocal {
int QUERY = 1; //查询请求
int PURCHASE = 2; //购票请求
int ACCEPT = 3; //确认
int ERROR = 4; //错误
int EXIT = 5; //退出请求
int PAY = 6; //付款请求
int LOGIN = 7; //登录请求
int QUERYHISTORY = 8; //查询历史
int ISLOGIN = 9; //已登录
}
public class Server {
static final int PORT = 8888;
static int m_count = 0; //当前连接数
public Server() {}
public static void main(String[] args)
{
Object object = new Object();
ServerSocket server_socket = null;
// 使用线程池,设置最大连接数为100
ExecutorService threadPool = Executors.newFixedThreadPool(100);
try
{
server_socket = new ServerSocket(PORT);
System.out.println("Server is running");
while (true)
{
Socket client_socket = server_socket.accept();
m_count = ((ThreadPoolExecutor)threadPool).getActiveCount();
System.out.println("当前连接数:" + (m_count+1));
Thread thread = new Thread(new ProcessThread(client_socket,object));
threadPool.submit(thread);
}
}
catch (IOException e)
{
e.printStackTrace();
}
threadPool.shutdown();
}
}
/*服务器线程类*/
class ProcessThread implements Runnable,Protocal{
Socket client; //当前连接客户端
BookTicket bt; //业务处理对象
ProcessThread() {}
/*构造函数*/
ProcessThread(Socket client,Object object)
{
this.client = client;
this.bt = new BookTicket(object);
}
/* 线程函数 */
public void run()
{
try
{
System.out.println("get connect from:" + client.getInetAddress() + ",port:" + client.getPort());
while (onReceive())
;
System.out.println("客户端:" + client.getInetAddress() + ",port:" + client.getPort() + "退出");
client.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
//协议解析函数
public boolean onReceive() {
int flag = 0; //用户监测客户端是否断开连接,-1为断开
try {
//处理客户端异常断开
client.sendUrgentData(0);
ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(client.getInputStream()));
Integer nChoice = (Integer)is.readObject();
ObjectOutputStream os = new ObjectOutputStream(client.getOutputStream());
if(nChoice != null)
{
switch (nChoice)
{
case QUERY:
bt.queryFlight(is,os);
break;
case PURCHASE:
bt.bookTickt(is,os);
break;
case LOGIN:
bt.login(is,os);
break;
case QUERYHISTORY:
bt.queryHistory(is,os);
break;
case EXIT:
bt.logout();
flag = -1;
break;
default:
flag = -1;
break;
}//switch
}//if
}//try
catch (Exception e)
{
flag = -1;
bt.logout();
e.printStackTrace();
}
if((flag < 0) || (client.isClosed()))
{
return false;
}
return true;
}
}
/*订票业务处理类*/
class BookTicket implements Protocal{
FlightManageDAO fdao; //数据库访问对象
TicketManageDAO tdao; //购票数据库访问对象
LoginDAO ldao; //登录数据库访问对象
List<Flight> fList = null; //航班列表
Passenger passenger = null; //当前用户
static int i = 10; //剩余票数,用来模拟并发
Object object = null; //共用锁对象
/*构造函数*/
BookTicket(Object object)
{
this.fdao = new FlightManageDAO();
this.tdao = new TicketManageDAO();
this.ldao = new LoginDAO();
this.object = object;
}
/*机票查询函数*/
public void queryFlight(ObjectInputStream is,ObjectOutputStream os) throws ClassNotFoundException, IOException
{
Object obj1 = is.readObject();
Object obj2 = is.readObject();
//Object obj3 = is.readObject();
if (!(obj1 == null) && !(obj2 == null))
{
String start = (String) obj1;
String arrival = (String) obj2;
//String date = (String) obj3;
fList = fdao.queryFilght(start, arrival);
os.writeObject(fList);
}
}
/*机票预订函数*/
public synchronized void bookTickt(ObjectInputStream is,ObjectOutputStream os) throws IOException, ClassNotFoundException
{
Integer nChoice = (Integer)is.readObject(); //获取客户选择的航班
if(nChoice != null)
{
if(i>0) //有余票
{
if((fList.size()>nChoice) && (nChoice>=0))
{
os.writeObject(new Integer(PAY));
{
//处理支付环节
}
//生成订单
if((this.passenger != null))
{
Flight flight = fList.get(nChoice);
Ticket ticket = new Ticket(flight, passenger, i--);
int result = tdao.saveTicketInfo(ticket);
if(result > 0)
os.writeObject(ticket);
else
os.writeObject(ERROR);
}
}
}
else
{
os.writeObject(new Integer(ERROR));
}
}//if
}
/*查询历史购票记录*/
public void queryHistory(ObjectInputStream is,ObjectOutputStream os) throws IOException
{
List<Ticket> tList = tdao.queryHistoryTicket(passenger.getUsername());
os.writeObject(tList);
}
/*登录函数*/
public void login(ObjectInputStream is,ObjectOutputStream os) throws ClassNotFoundException, IOException
{
String username = (String)is.readObject();
String password = (String)is.readObject();
if((username != null) && (password != null))
{
Passenger p = ldao.checkPermission(username, password);
if(p != null)
{
this.passenger = p;
if(!p.isLogin())
{
os.writeObject(ACCEPT);
}
else
{ //已登录
os.writeObject(ISLOGIN);
}
}
else
{ //无此用户
os.writeObject(ERROR);
}
}
else
{ //用户名或密码为空
os.writeObject(ERROR);
}
}
public void logout()
{
ldao.logOut(passenger);
}
}
package com.client;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import com.model.Flight;
import com.model.Ticket;
/**
* 客户端
* @author XWZ
*
*/
/*常量协议接口*/
interface Protocal {
int QUERY = 1;
int PURCHASE = 2;
int ACCEPT = 3;
int ERROR = 4;
int EXIT = 5;
int PAY = 6;
int LOGIN = 7;
int QUERYHISTORY = 8;
int ISLOGIN = 9;
}
public class Client implements Protocal{
static final int PORT = 8888;
static final String HOST = "127.0.0.1";
int count = 0;
Socket socket = null;
public Client()
{
try
{
socket = new Socket();
socket.connect(new InetSocketAddress(HOST, PORT));
}
catch (IOException e)
{
//e.printStackTrace();
}
}
public static void main(String[] args)
{
Client client = new Client();
if(client.socket.isConnected())
{
while(!client.login())
;
while (client.menu())
;
System.out.println("GoodBye");
}
else
{
System.out.println("503 Service Unavailable,Server error..");
}
try
{
client.socket.close();
}
catch (Exception e) {}
}
public boolean menu()
{
if (count < 1)
{
System.out.println("-----------蓝天机票销售系统主界面----------");
System.out.println("1、机票查询");
System.out.println("2、查询历史乘机记录");
System.out.println("3、退出系统");
count++;
}
System.out.println("请输入操作选项:");
boolean flag = true;
Scanner sc = new Scanner(System.in);
Integer nChoice = sc.nextInt();
switch (nChoice) {
case 1:
queryTicket(socket);
break;
case 2:
queryHistory(socket);
break;
case 3:
flag = false;
exit(socket);
break;
default:
System.out.println("没有此选项,请重新输入!");
break;
}
if (!flag)
return false;
return true;
}
/* 机票查询 */
public void queryTicket(Socket socket)
{
String start = null;
String arrival = null;
int flag = -1;
try {
ObjectOutputStream os1 = new ObjectOutputStream(socket.getOutputStream());
os1.writeObject(new Integer(QUERY));
Scanner sc = new Scanner(System.in);
while(flag<0)
{
System.out.println("请输入出发城市:");
start = sc.nextLine();
System.out.println("请输入到达城市:");
arrival = sc.nextLine();
if(start.trim().equals("") || arrival.trim().equals(""))
{
System.out.println("出发地或目的地不能够为空!请重新输入:");
}
else
{
flag = 1;
}
}
System.out.println("出发地:"+start +" 目的地:"+arrival);
os1.writeObject(start);
os1.flush();
os1.writeObject(arrival);
ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
Object obj = is.readObject();
if (obj != null)
{
@SuppressWarnings("unchecked")
List<Flight> fList = (ArrayList<Flight>) obj;
if (fList.size() < 1)
{
System.out.println("无符合条件的航班!");
}
else
{
System.out.println("航班序号 航班号 初始地 目的地 日期 起飞时间 到达时间");
for (int i = 0; i < fList.size(); i++)
{
Flight flight = fList.get(i);
System.out.println((i + 1) + " "
+flight.getId() + " "
+flight.getFrom() + " "
+flight.getTo() + " "
+flight.getDate() + " "
+flight.getStartTime()+ " "
+flight.getArriveTime());
}
System.out.println("请选择航班序号或返回(0为返回)");
Integer nChoice = sc.nextInt();
if (nChoice != 0)
{
while ((nChoice < 0) || (nChoice > fList.size()))
{
System.out.println("输入错误,请重新输入!");
nChoice = sc.nextInt();
}
// 航班序号输入正确, 调用购票函数
bookTicket(socket, nChoice-1);
}
else
{
// 完成该次查询,返回主菜单
}
}
}
else
{
// System.out.println("数据传输出错");
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 机票预订
public void bookTicket(Socket socket, Integer nChoice)
{
try {
ObjectOutputStream os;
os = new ObjectOutputStream(socket.getOutputStream());
os.writeObject(new Integer(PURCHASE));
os.writeObject(nChoice);
ObjectInputStream is = new ObjectInputStream(socket.getInputStream());
Integer result = (Integer) is.readObject();
if (result == PAY)
{
//付款
System.out.println("请付款:");
Scanner sc = new Scanner(System.in);
sc.nextLine();
//接收订单信息
Object obj = is.readObject();
if(obj instanceof Ticket)
{
Ticket ticket = (Ticket)obj;
if(ticket != null)
{
System.out.println("恭喜您,订票成功!机票信息为");
System.out.println("订单号 航班号 出发日期 始发地 目的地 起飞时间 抵达时
间 乘机人 座位号 预订状态");
System.out.print(ticket.getOrderId());
System.out.print(" "+ticket.getFlight().getId());
System.out.print(" "+ticket.getFlight().getDate());
System.out.print(" "+ticket.getFlight().getFrom());
System.out.print(" "+ticket.getFlight().getTo());
System.out.print(" "+ticket.getFlight().getStartTime());
System.out.print(" "+ticket.getFlight().getArriveTime());
System.out.print(" "+ticket.getPassenger().getUsername());
System.out.print(" "+ticket.getSeat());
System.out.println(" "+ticket.getState());
}
}
else
{
System.out.println("系统繁忙!订票失败!");
}
}//if
} //try
catch (Exception e)
{
e.printStackTrace();
}
}
public void userInfoManage(Socket socket) {
}
/*查询历史订票记录*/
public void queryHistory(Socket socket)
{
try {
ObjectOutputStream os;
os = new ObjectOutputStream(socket.getOutputStream());
os.writeObject(new Integer(QUERYHISTORY));
ObjectInputStream is = new ObjectInputStream(socket.getInputStream());
@SuppressWarnings("unchecked")
List<Ticket> tList = (ArrayList<Ticket>) is.readObject();
if (tList.size()>0)
{
System.out.println("订单号 航班号 出发日期 始发地 目的地 起飞时间 抵达时间
乘机人 座位号 预订状态");
for(int i = 0; i < tList.size(); i++)
{
Ticket ticket = tList.get(i);
System.out.print(ticket.getOrderId());
System.out.print(" "+ticket.getFlight().getId());
System.out.print(" "+ticket.getFlight().getDate());
System.out.print(" "+ticket.getFlight().getFrom());
System.out.print(" "+ticket.getFlight().getTo());
System.out.print(" "+ticket.getFlight().getStartTime());
System.out.print(" "+ticket.getFlight().getArriveTime());
System.out.print(" "+ticket.getPassenger().getUsername());
System.out.print(" "+ticket.getSeat());
System.out.println(" "+ticket.getState());
}
}
else
{
System.out.println("您暂无订票记录!");
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
/*退出函数,与服务器断开连接*/
public void exit(Socket socket)
{
ObjectOutputStream os = null;
try {
os = new ObjectOutputStream(socket.getOutputStream());
os.writeObject(new Integer(EXIT));
} catch (Exception e) {
e.printStackTrace();
}
}
/*登录函数*/
public boolean login()
{
boolean result = false;
int flag = -1;
String username = null;
String password = null;
Scanner sc = new Scanner(System.in);
System.out.println("-----------蓝天机票销售系统登录界面----------");
while(flag<0)
{
System.out.print("请输入用户名:");
username = sc.nextLine();
System.out.print("请输入密码:");
password = sc.nextLine();
if(username.trim().equals("") || password.trim().equals(""))
{
System.out.println("用户名或密码为空!请重新输入用户名和密码:");
}
else
{
flag = 1;
}
}
try {
ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream());
os.writeObject(new Integer(LOGIN));
os.writeObject(username);
os.writeObject(password);
ObjectInputStream is = new ObjectInputStream(socket.getInputStream());
Integer nResult = (Integer)is.readObject();
if(nResult != null)
{
if(nResult == ACCEPT)
{
result = true;
System.out.println("登录成功! 跳转至主界面...");
}
else if (nResult == ISLOGIN)
{
System.out.println("您已登录,不能重新登录!");
}
else
{
System.out.println("用户名或密码错误!请重新登录");
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return result;
}
}
完整的代码可以到这里下载:点击打开链接
附加聊天室服务器端的实现: