详细设计报告
一、引言
1.1 编写目的:
本阶段在系统的需求分析的基础上,对航空订票系统做详细设计。主要解决了实现该系统程序模块具体设计问题。包括确定算法,数据结构,模块接口的使用,数据库的动态操作以及界面设计等。在以下的概要设计报告中将对在本阶段中对系统所做的所有详细设计进行详细的说明。
在下一阶段的编码过程中,程序设计员可参考此详细设计报告,在详细设计对机票预定系统所做的算法设计,数据结构以及数据库动态操作的基础上,对系统进行编码。
1.2 项目背景:
开发软件名称:航空订票系统。
用户:航空公司运行环境:宿舍电脑。开发平台:MyEclipse 7.0 PostgreSql 数据库。
系统架构:该系统采用java+jsp 框架
1.3 定义:
查询:对数据库的操作的一种,用于搜索数据信息。插入:对数据库的操作的一种,用于将数据存入数据库中。更新:对数据库的操作的一种,用于更改数据库中的数据信息。
PostgreSql: 系统服务器所使用的数据库管理系统(DBMS)。
SQL: 一种用于访问查询数据库的语言事务流:数据进入模块后可能有多种路径进行处理。主键:数据库表中的关键域。值互不相同。外部主键:数据库表中与其他表主键关联的域。
1.4 参考资料:
需求分析说明书软件开发小组
软件工程齐治昌谭庆平宁洪等高等教育出版社
实用软件工程郑人杰等,清华大学出版社。
二、总体设计
2.1 需求概述
航空订票系统的总目标是:在计算机网络,数据库和先进的开发平台上,利用现有的软件,配置一定的硬件,开发一个具有开放体系结构的、易扩充的、易维护的、具有良好人机交互界面的机票预定系统,实现航空公司的机票销售的自动化的计算机系统,为企业的决策层提供准确、精细、迅速的机票销售信息。具体功能为用户把预定机票的旅客信息(姓名、性别、身份证号码(护照号码)、乘坐时间、出行始发地和目的地等)输入到系统中,系统为旅客安排航班。当旅客交付了预订金后,系统打印出取票通知和帐单给旅客,旅客在飞机起飞前一天凭取票通知和帐单交款取票,系统核对无误即打印出机票给旅客。此外航空公司为随时掌握各个航班飞机的乘载情况,需要定期进行查询统计,以便适当调整。同时还需完成旅客延误了取票时间的处理,航班取消后的处理,旅客临时更改航班的处理等。
根据可行性研究的结果和客户的要求,分析现有情况及问题,采用B/S 结构,将机票预定系统划主要就是服务器端子系统。
2.2 软件结构:
图1 软件结构图
三、程序描述
3.1 各功能详细描述:
本系统主要用于机票预订,所以提供了以下几个子功能:机票预订,取票通知,查询航班,查询机票,退票,打印机票,各航班的营运统计,以及后台方面的航班的添加,取消航班,机票的生成,以及航班的查询等后台功能。
1、机票预订功能:用户和机场管理员有权力进行该项功能。首先通过查询得到旅客所需的航班,确定该航班还有没有被预订的座位,然后选择座位的等级,填写旅客的详细信息之后就可进行网上预订机票。
2、取票通知:该项功能只有用户和机场管理员有权力进行操作,在机票预订功能成功完成之后,系统会自动给浏览器端发送一条取票信息以及所需缴纳的费用。旅行社可以利用特定设备将该取票信息打印出来,这就是取票通知。
3、查询航班:可以通过输入出发地,目的地,日期和时间选定自己航班。
4、查询机票:该项功能用户、游客、管理员都可以操作,可以通过自己的身份证号以及取票通知上的机票号查询自己的机票信息。
5、退订机票:该功能只有用户和机场管理员有权力操作,利用身份证号和对应的机票号就可以查询到机票信息,然后就可以退订机票。
6、打印机票:该功能只有机场管理员有权力操作,只有当管理员确认旅客已经付款后才予以打印机票,可以通过身份证号和对应的取票信息上的机票号查询机票信息,然后服务器返回机票信息,管理员就可以打印该机票信息,交给旅客。
7、各航班的营运统计:该项功能只有机场管理员才能操作,他可以通过输入年份和月份查询当月个航班的营运情况,以便机场能够及时掌握航班动态。
8、后台的航班添加:该项功能只有机场管理员才能操作,他通过提供航班的具体信息 添加航班信息。 9、后台的取消航班:该项功能只有机场管理员才能操作,先通过航班号和航班日期查 询到航班信息后,取
消航班就可以将该航班从数据库中删除。
10、后台的航班查询: 该项功能只有机场管理员才能操作, 通过航班号和航班日期查询 到航班信息。 11、后台的机票生成: 该项功能只有机场管理员才能操作, 可以通过该项功能给刚添加 的航班生成对应的
飞机票号纪录。
3.2 主要的系统功能模块如下:
(1) 管理员登陆模块 ManagerDAO.getManager()
(2) 管理员修改密码模块 ManagerDAO.modifyPassword() (3) 删除用户 ManagerDAO.deleteConsumer() (4) 添加新管理员 ManagerDAO.addManager() (5) 删除管理员模块 ManagerDAO.deleteManager() (6) 发布新航班模块 ManagerDAO.addNewFlight() (7) 删除航班模块 ManagerDAO.deleteFlight()
(8) 根据信息查看航班信息模块 ConsumerDAO.getFlightByInformation()
1、用户模块:用户用例图如图 2 所示
(1) 用户登陆模块 ConsumerDAO.getConsumer() (2) 用户注册模块 ConsumerDAO.register()
(3) 查询航班模块
ConsumerDAO.getFlightByInformation()
(4) 订票模块 ConsumerDAO.orderTicket()
(5) 修改密码模块 ConsumerDAO.modifyPassword() (6) 付款模块 ConsumerDAO.paying() (7)
生成交易信息并 2、 退票模块 ConsumerDAO.returnTicket()
用户注册或登录
搜索飞机票
普通用户
删除已定机票
预订飞机票
付款
请用户确认
图2
管理员模块:管理员用例图如图 3 所示
信息采集器
3.3 数据库设计:
字段名 字段类型
是 否 为 空 默 认 值
字段含义 注释
consumerId VARCHAR2
(10) N
用户编号 用以标示不同用户。
consumerName
VARCHAR2 (20) N
用户名称
用户自己取的名字有利于用户 记忆,可以用来登录等。
consumerPasswor d
VARCHAR2 (20) N
用户密码
用于确定用户身份。
consumerGender VARCHAR2
(1) N
用户性别
consumerBooking Fligt
VARCHAR2 (20) Y
用户已订票航 班 用于储存用户已订票的航班。
consumerBooking Seat
VARCHAR2 (20) Y
用户已定机票
的座位号 用于储存用户已订票航班的座 位号。 consumerIDCardO
rPassportNo VARCHAR2
(20) N
用户的身份证
号或护照号
用户取票的凭证 (身份证号或护 照号)
删除用户 3 、创新点——通过关键字从其他网站找到一些信息推荐给用户模块
: 用例如图 4 所示。
推荐信息模块 InformationDAO.getInformationByKeyWord()
附近餐馆信息
管理员修改密码
管理员登录 查看航班信息
删除管理员
增加新管理员
管理员
发布新航班
删除航班
图3
交通状况
附近旅馆信息
管理员(Manager)
座位表()
、流程图:
将
request 对象写向服务
出票请求查询航班请求修改密码请登陆请求
调用调用调用调用
TicketOrder
D
AO FligthDao Branc h Dao Branc hDao
封装response 对象
将response 对象写往客
解析request 对象将结果显示在客
图5 流程图
3.5 DAO 接口设计
设计了通用的DAO接口,而不是直接写访问数据库的实现类,这样可以创建不同的实现类来实现接
口,使标准制定和标准实现分离。当换了数据库,或者换了数据库访问技术,就可以写新的实现类,不用改变原来的代码。如定义FlightDAO 接口,若从文件中读取数据可以定义FlightDaoFromFile 实现类,若利用JDBC访问数据可以定义FlightDaoFromJDBC 实现类,若利用hibernate 访问数据可以定义FlightDaoFromHibernate 实现类等。
3.5.1 FlightDAO
flightDAO 用来航班计划,航班的数据访问。
package com.tarena.abs.dao;
import com.tarena.abs.model.*;
import java.util.*;
// 对航班和航班计划数据访问的接口。
public interface FlightDAO{
// 根据指定出发地,目的地和出发日期在底层数据源中查找
// 得到所有的航班对象的集合。
public Set getAllFlights(String fromAddr,String toAddr,Calendar date);
// 执行出票的操作。
public boolean order(Order ord);
// 添加指定的航班计划对象。
public boolean addFlightSchedular(FlightSchedular fs);
// 根据给定的航班编号在底层数据源中删除该航班计划,
// 以及该计划下的所有航班。
public boolean removeFlightSchedular(String flightNumber);
// 得到所有航班计划对象
public Set getAllFlightSchedulars();
// 添加航班
public boolean addFlight(Flight fl);
}
3.5.2 TicketOrderDAO
TicketOrderDAO 用来访问票单数据。
package com.tarena.abs.dao; import java.util.Set;
import java.util.Calendar;
import com.tarena.abs.model.*;
// 机票出票记录访问接口
public interface TicketOrderDAO {
// 执行出票的操作。
public boolean order(Order ord);
// 执行退票操作。
public boolean cancelOrder(int TicketNumber);
// 查询指定营业网点在指定时间段内的出票记录
public Set getAllTicketOrder(Branch branch,Calendar startDate,Calendar
endDate);
// 得到指定营业网点指定日期内的营业额。
public double getAllTicketMoney(Branch branch,Calendar startDate,Calendar endDate);
// 得到所有营业网点指定日期内的营业额
public double getAllTicketMoney(Calendar startDate,Calendar endDate);
// 查询所有出票信息
public Set getAllTicketOrder();
}
4 关健代码分析
4.1 流程代码分析服务器启动时读取配置文件,读取数据,并且服务器端ServerSocket 等待客户端线程访问,当收到客户端相应后,则创建一个新的服务线程执行服务。
ServerSocket ss=null;
Socket s=null;
try {
// 创建服务器socket
ss=new
ServerSocket(Integer.parseInt(pro.getProperty("ServerPort")));
while(true){
s=ss.accept();
}
// 转发给serverThread 处理(传递socket 参数) new ServerThread(s).start()
}
} catch (IOException e)
{ e.printStackTrace();
服务线程ServerThread 通过构造函数接受socket ,然后转发给Controller public class ServerThread extends
Thread{ Socket s;
protected ServerThread(Socket s){ //
this.s=s;
用传入的socket 初始化} public void run(){
try {
new Controller(s).handle(); // }
catch (Exception e)
{ e.printStackTrace();
交给控制器处理
}finally{
try{s.close();}catch(IOException e){}
}
}
}
由controller 调用handle 方法,分析请求对象。
if(type.equals("login")){ // 登陆处理
loginHandle(req);
}else if(type.equals("flightSearch")){ // flightSearchHandle(req);
}else if(type.equals("order")){ //
航班计划查询处理订单处理
orderHandle();
}else if(type.equals("quit")){ // 退出处理
//quitHandle();
break;
}else if(type.equals("modifyPasswd")){
modifyPasswd(req);
}
有不同的处理程序,调用相应的dao 将查询信息封装到response 中。
hs=(HashSet)(flightDao.getAllFlights(fromAddr,toAddr,cal)); Response res=new
Response("flightSearch"); res.setData(hs);
4.2 用表格显示表单当客户端查询到航班计划时,把flightlist 航班集合传给FlightTableModel, FLightTableModel 传给JTable ,然后把JTable 加入JScorllPane ,就会自动显示数据。
再把FlightTableModel ftm = new FlightTableModel(flightlist);
JTable jt = new JTable(ftm); ClientMainClass.clientFrame.setTable(jt);
FlightTableModel 实现了AbstractTableModel 接口,实现了如下四个方法。package
com.tarena.abs.client;
import javax.swing.table.*;
import java.util.*;
import com.tarena.abs.model.*;
public class FlightTableModel extends AbstractTableModel{
ArrayList s;
public FlightTableModel(ArrayList s){
this.s=s;
}
// 获得列名
public String getColumnName(int arg0) { switch(arg0){
case 0:return "航班号";
case 1:return "出发地";
case 2:return "目的地";
case 3:return "起飞时间"
case 4:return "到达时间"
case 5:return "机型";
case 6:return "票价";
case 7:return "头等舱";
case 8:return "公务舱";
case 9:return "经济舱";
default: return null;
}
// 获得行数
public int getColumnCount() {
return 10;
}
// 获得列数
public int getRowCount() {
return s.size();
}
// 获得指定位置的值
public Object getValueAt(int row, int col) {
Flight f=(Flight)s.get(row);
if(row<0 || row>s.size())
return null;
switch(col){
case 0: return f.getSch().getFlightNumber();
case 1: return f.getSch().getFromAddress();
case 2: return f.getSch().getToAddress();
case 3: return f.getSch().getFromTime();
case 4: return f.getSch().getToTime();
case 5: return f.getSch().getPlane();
case 6: return
(int)(f.getSch().getPrice()*f.getPriceOff());
case 7: return f.getFCSRemain();
case 8: return f.getBCSRemain();
case 9: return f.getECSRemain(); default: return null;
}
}
}
4.3 Hibernate 映射关系
1、构建pojo(Plain Old Java Objects) 对象
用JDBC 储存数据时,涉及多个表格的修改,查找。工作难度较大。所以考虑用hibernate
实现数据储存。首先把模型改写为标准pojo 。
(1) 添加Long 类型的oid 属性。
(2) 为保存每个属性添加getter ,setter 方法。
(3) 添加无参构造函数。
(4) 写hibernate 映射文件。
2、Hibernate 储存原理
当储存数据时,hibernate 自动调用getter 方法,把属性存入相应字段。
当读取数据时,hibernate 自动调用无参构造方法创建对象,然后调用setter 方法给对象赋值,从而产生和原来对象相等( equals )的对象。
当增、删、改操作时,hibernate 会自动把与原数据相关联的表的字段修改(必须设置级联)。
3、映射关系分析
(1) 航班计划和飞机型号是多对一关系:每个航班计划都包含飞机型号属性,各飞机型号会被多个航班计划引用。
(2) 航班和航班计划是多对一的关系:每个航班都属于某个航班计划,因此每个航班都包含一个航班计划属性,而每个航班表都有一个外间指向航班计划的id 子段。
(3) 定单与航班是多对一关系:一个定单包含的航班信息有它包含的航班属性得到,通过航班属性还可以得到航班计划和飞机型号的信息。每个定单只能有一个航班,每个航班可以包含在多个定单中,因此定单与航班是多对一关系。
(4) 定单和网点是多对一的关系:原理同定单和航班的关系。
5 总结
航空订票系统使用软件分层结构,利用面向对象的设计方法,并把学到的知识应用于实践。实现了稳定、可维护、可扩展性的软件,并且完成业务需求。如做以下改进会使系统更加完善:
1、初始化配置参数:程序是直接读配置文件来读取初始化参数的,如下所示:
ServerIP=127.0.0.1
ServerPort=8888 可以将此参数放入程序中,由用户或管理员输入,来选侧不同的服务器。客户端的参数设置及重新连接功能有待实现。
2、服务器掉线:默认是实现是客户端先退出,通知服务器,服务器从内存中删掉此客户端,然后客户端关闭连接。
private void quitHandle(Request req){
String currentUserName=(String)req.getData("currentUser"); for(Object
o:onlineAgent){ Branch a = (Branch)o;
if(a.getName().equals(currentUserName)){ onlineAgent.remove(a);
}
} try { s.close();
} catch (IOException e) { e.printStackTrace();}
} 但是,当服务器由于网络故障,或者系统维修时,临时断开,没有通知客户端,当客户端此时向服务器发请求时,便会出现想不到的错误。一个有效的解决方法是:利用观察者模式。在服务器推出方法中遍历在线客户端socket ,发送等待信息。
Private void quit(){
For(Socket s:Currentsockets){ ······ // 封装等待信号给客户端
}
} 客户端受到等待信号后,执行waitServer() 方法,并禁止操作。
3、请求响应对象:
现在的request 对象封装了String 类型的Type 变量代表请求类型。Response 对象包装了Object 类型的Date 变量作为相应。可以把请求对象作为枚举类型,更安全,不易出错。
4、数据显示的轮动更新:
服务器端显示航班信息,网点信息,出现一张表,该表不能滚动和更新。可以利用可滚动、可更新的结果集以及Swing 的某些特性实现excel 中的实时修改数据功能。实现此功能较为复杂。
3.3 数据库连接的的主要代码块
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtils {
static {
try {
Class. forName ( "org.postgresql.Driver");
}catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
}
e.printStackTrace();
} public static Connection getConnection()throws SQLException{ Connection
DriverManager. " , "postgres"
getConnection
, "123" );
conn
( "jdbc:postgresql://localhost/postgres
return conn;
}
3.3 页面设计
主要的几个系统页面有登陆页面,主页面,已经其他子系统页面。页面代码如下:
主要代码:
<%
session.setAttribute( "use" , "traveller" );
String UserName=(String)request.getParameter( "username" );
String Password=(String)request.getParameter( "password" );
String Select=(String)request.getParameter( "load" ); if
(UserName.equals( "" ) || Password.equals( "" ))
{ out.print(show.errorBox( "请填写完整!" , "验证错误"));
} else
int intT=0;
if (Select!= null &&Select.equals( "user" )){
intT=data.getRowCount( "userload WHERE userid='" +UserName+"' AND password='" +Password+"'" );
if
(intT>0){ session.setAttribu
te( session.setAttribute( res
ponse.sendRedirect(
} else { out.print(show.errorBox( return ;
} "name" ,UserName); "use" , "user" );
"index_user.jsp" );
"检查你的用户名或密码!", "验证错误"));
}else if (Select!= null &&Select.equals( "admin" )){
intT=data.getRowCount( "adminload WHERE userid='" +UserName+"' AND
password='" +Password+"'" ); if
(intT>0){ session.setAttribute( session.setAttribute( response.sendRedirect(
} else { out.print(show.errorBox( return ; }
}else { out.print(show.errorBox( return ;
} }
%> body >
主要代码:
<%String use=(String)session.getAttribute( "use" ); %>
td > | height ="83" > td > tr > |
cellspacing =0 border ="0" > ="36" > td > tr > | | tr > | tr > |
|