多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

ASP+SQL Server实现民航售票管理系统:从数据模型到部署答辩完整指南

ASP+SQL Server实现民航售票管理系统:从数据模型到部署答辩完整指南 简介民航售票管理系统毕业设计资料包基于ASP与SQL Server数据库开发面向计算机专业学生、毕业设计选题者以及初学Web开发的读者可用于毕业设计、课程设计或项目练手。系统采用B/S结构分为民航管理系统和民航售票系统包含会员注册、管理员后台、留言管理、航班查询、网上订票、网上退票等模块后台由数据库支撑体现了完整的需求分析和系统设计过程具有稳定性高、可移植性强等优点。压缩包共96个文件约1.14MB包含35个ASP页面源码、42个GIF图片、7个SWF动画、数据库文件和毕业论文文档数据库文件涵盖MDF、LDF、DB、MDB等类型便于环境还原。目前已有139人学习下载。通过这份资料可获取完整源码、数据库和论文有利于理解项目结构掌握从部署到文档撰写的全流程也便于快速搭建类似管理系统很有实用价值。1. 毕业设计遇上 ASPSQL Server 民航售票管理系统这套老方案为什么值得自己重做一遍“直接导入源码就能交差”的念头劝你趁早放下。民航售票管理系统几乎每年毕业设计里都会出现数据表不多却能把查询、下单、余票扣减、后台管理、报表统计串成一条完整业务线适合用来回答“业务怎么落成系统”这个问题。选 ASP SQL Server 这个组合很多人第一反应是“老”但老有老的好处资料多、环境简单、改起来直观。这篇文章不打算让你去复现某份神秘“原稿”而是给你一条按自己的理解从数据模型到答辩部署把整个系统讲明白的路线。2. 民航售票的业务边界与数据模型先把航班、订单、用户三张关系拆清民航售票系统能做什么直接决定表怎么建。最常见的业务口径是管理员录入航班旅客按出发城市和日期查航班选班次后填乘机人信息提交订单同时扣减余票管理员在后台看到订单、修改航班状态、取消订单。延伸出去可以再加退票和改签但毕业设计只要把“查、订、扣、管”这条主链路跑通就足够撑起一篇论文的完整度。真正要在答辩里讲清楚的是每个状态是怎么流转的而不是把功能清单背一遍。2.1 售票主流程里的状态流转订单不是一提交就变成“已出票”先给订单定义一个状态字段建议用整数而不是字符串0 待支付、1 已出票、2 已退票、3 已取消。很多毕业设计把支付省略或者做成“模拟支付”所以提交订单后直接置为已出票也可以但你必须在论文里明确写一句“支付模块不在本设计范围内”把边界划清楚。我一般会保留这个状态字段让后台能手动改状态演示的时候可以现场把一张订单从待支付改成已出票整个过程更有层次感。航班表也要存“剩余座位数”而不是只存“总座位数”原因很简单下单逻辑必须写成“扣减余票”而不是每次下单重新统计卖了多少。这是评委最容易追着问的点——你凭什么防止超售答案就是一条带条件的 UPDATE 语句配合事务后面第 4 章会给完整写法。状态字段的设计也影响查询前端查航班只显示 Status1 的可售航班后台停售直接把状态改 0比物理删除安全得多。2.2 SQL Server 2008 R2 里的核心表结构七张表怎么建、外键往哪指按最常见的毕业设计做法数据库可以叫 AirTicketDB核心表就三张Flights 航班表、Orders 订单表、Users 用户表。再为了查重和报表方便通常补一张 Airport 机场表或 Airline 航空公司表但我建议控制在 6 到 8 张以内表太多演示时手忙脚乱论文里反而难讲。列名类型说明FlightIDINT IDENTITY主键自增FlightNoNVARCHAR(20)航班号如 XX1234DepCityNVARCHAR(50)出发城市名称ArrCityNVARCHAR(50)到达城市名称DepDateDATE出发日期DepTimeVARCHAR(8)起飞时间HH:mmArrTimeVARCHAR(8)落地时间HH:mmPriceDECIMAL(10,2)票价TotalSeatINT总座位数LeftSeatINT剩余座位数StatusINT0 停售1 可售订单表字段类似OrderID 主键、OrderNo 订单号、FlightID 外键指向 Flights、PassengerName 乘机人、IDCard 身份证号、Phone 联系电话、Price 成交价、Status 订单状态、CreateTime 下单时间。Users 表就是 UserID、UserName、UserPwd、UserRole角色只分 admin 和普通用户。订单表里存 Price 而不是下单时再取航班表价格是为了保留“成交价”的历史快照以后航班涨价也不会影响已出票的订单。建库脚本直接在 SSMS 的新建查询窗口执行排序规则建议设成 Chinese_PRC_CI_AS这个配置对中文查询最友好。IF DB_ID(AirTicketDB) IS NULL CREATE DATABASE AirTicketDB COLLATE Chinese_PRC_CI_AS; GO USE AirTicketDB; GO CREATE TABLE Flights ( FlightID INT IDENTITY(1,1) PRIMARY KEY, FlightNo NVARCHAR(20) NOT NULL, DepCity NVARCHAR(50) NOT NULL, ArrCity NVARCHAR(50) NOT NULL, DepDate DATE NOT NULL, DepTime VARCHAR(8) NOT NULL, ArrTime VARCHAR(8) NOT NULL, Price DECIMAL(10,2) NOT NULL, TotalSeat INT NOT NULL DEFAULT 180, LeftSeat INT NOT NULL DEFAULT 180, Status INT NOT NULL DEFAULT 1 ); GO CREATE TABLE Orders ( OrderID INT IDENTITY(1,1) PRIMARY KEY, OrderNo NVARCHAR(30) NOT NULL, FlightID INT NOT NULL REFERENCES Flights(FlightID), PassengerName NVARCHAR(50) NOT NULL, IDCard NVARCHAR(30) NOT NULL, Phone NVARCHAR(20) NOT NULL, Price DECIMAL(10,2) NOT NULL, Status INT NOT NULL DEFAULT 0, CreateTime DATETIME NOT NULL DEFAULT GETDATE() ); GO CREATE TABLE Users ( UserID INT IDENTITY(1,1) PRIMARY KEY, UserName NVARCHAR(50) NOT NULL UNIQUE, UserPwd NVARCHAR(50) NOT NULL, UserRole INT NOT NULL DEFAULT 0 ); GO逻辑说明DepTime 用 VARCHAR 而不用 TIME 类型是为了页面展示和字符串拼接时少做一次类型转换DATE 类型在 SQL Server 2008 R2 之后才支持如果学校机房用的是 2005需要改成 DATETIME。外键我在这里只写了 FlightID 一条但答辩被问“为什么要外键”时你要能回答“保证订单不会指向不存在的航班”而不是说“工具自动生成的”。默认值 DEFAULT 180 是为了减少录入航班时的重复字段TotalSeat 和 LeftSeat 初始一致后面手动调整余票也有依据。2.3 页面文件怎么和表对应ASP 项目结构的常见分法经典 ASP 项目不搞 MVC而是按功能拆页面。常见做法是根目录放一个 conn.asp 作为统一连接文件其他页面用 INCLUDE 引入前台页面和后台页面可以平铺在根目录也可以拆成 admin 子目录。我最常用的文件划分是首页和查询一体下单提交独立一页后台登录和增删改查各一页。conn.asp统一数据库连接被其他页面 Includeindex.asp前台首页放查询表单search.asp航班查询结果页book.asp下单表单页通过 QueryString 接收 FlightIDorder_save.asp处理下单请求的接收页order_list.asp按订单号或身份证查订单admin_login.asp后台登录admin_index.asp后台首页框架admin_flight.asp航班管理admin_order.asp订单管理admin_report.asp完整的报表统计页这个清单看着简单但每个页面职责单一答辩讲流程时一句话带过一页把重点放在 order_save.asp 的事务逻辑上比堆一堆页面更讨巧。连接文件放根目录还是 inc 子目录都行关键是 Include 路径要写对用 file 还是 virtual 要分清父路径问题在第 5 章展开。3. 从零搭建 ASP SQL Server 运行环境本机复现的最小步骤这一章解决的是“拿到项目却跑不起来”的问题。我以 Windows 10 IIS SQL Server 2008 R2 为例这是机房和实验室最常见的组合。如果你拿到的是别人打包的 .mdf/.ldf 数据库文件可以用附加数据库的方式但毕业设计我更推荐执行 SQL 脚本自己建库后面改表结构、加演示数据都顺手论文里“数据库设计”部分也有真实素材。3.1 启用 IIS 的 ASP 功能安装、目录、父路径控制面板 → 程序 → 启用或关闭 Windows 功能 → Internet Information Services → 万维网服务 → 应用程序开发功能 → 勾选 ASP。装完后按 WinR 输入 inetmgr 打开 IIS 管理器在默认站点下建一个虚拟目录指向源码目录不需要绑定域名直接访问 http://localhost/项目名/index.asp 即可。到这里九成的人会碰到 500 错误或英文报错 “An error occurred on the server when processing the URL”原因多半是 ASP 父路径没开。IIS 管理器 → 选中站点 → 双击 ASP 图标 → 行为 → 启用父路径改为 True然后应用。因为页面里经常出现 这种上级目录引用父路径默认 False 会直接拒绝执行。另一个隐藏项是“应用程序池”的运行模式经典 ASP 不需要托管代码但如果你在 IIS 7 以上版本把应用池设成了 Integrated部分 A 级页面可能行为异常切到 Classic 模式更稳。3.2 SQL Server 2008 R2 安装与登录模式sa 账号为什么连不上安装 SQL Server 时如果选了仅 Windows 身份验证模式ASP 连接串里写 UIDsa 是连不上的必须安装时选“混合模式”。已经装完的也不用重装打开 SSMS → 服务器属性 → 安全性 → 服务器身份验证 → 选“SQL Server 和 Windows 身份验证模式”确定后到 SQL Server 配置管理器里重启服务即可。还有一个高频问题SQL Server 默认只启用了 Shared Memory 协议没有启用 TCP/IP。ASP 用的 ADO 连接默认走 TCP 1433 端口TCP/IP 没启用就会报“SQL Server 不存在或访问被拒绝”。解决路径是在 SQL Server 配置管理器 → SQL Server 网络配置 → 启用 TCP/IP再重启 SQL Server 服务。本地测试连接串可以先用 SSMS 验证能在 SSMS 里连上再去 ASP 页面试缩小排查范围。我常写的连接文件是这样的% dim conn set conn Server.CreateObject(ADODB.Connection) conn.ConnectionString ProviderSQLOLEDB;Data Sourcelocalhost;Initial CatalogAirTicketDB;User Idsa;Password你的密码; conn.Open %关键参数说明ProviderSQLOLEDB 是经典 ASP 连 SQL Server 最通用的 OLEDB 提供程序兼容 SQL Server 2000 到 2008 R2Data Source 填 localhost 或 127.0.0.1如果数据库实例是命名实例要写成 localhost\SQLEXPRESS 或 (local)\实例名Initial Catalog 就是数据库名。用 sa 连接不适合生产但演示环境没问题论文里补一句“实际开发应使用最小权限账号”会加分。3.3 用 ADO Command 写一个最小登录校验参数化查询的正确姿势登录页是安全相关的重点我不建议继续用字符串拼接 SQL。经典 ASP 支持 ADO Command 对象的参数集合写法如下% dim uname, upwd uname Trim(Request.Form(username)) upwd Trim(Request.Form(password)) dim cmd, rs set cmd Server.CreateObject(ADODB.Command) cmd.ActiveConnection conn cmd.CommandText SELECT UserID, UserRole FROM Users WHERE UserName? AND UserPwd? cmd.Parameters.Append cmd.CreateParameter(u, 200, 1, 50, uname) cmd.Parameters.Append cmd.CreateParameter(p, 200, 1, 50, upwd) set rs cmd.Execute if not rs.EOF then Session(uid) rs(UserID) Session(role) rs(UserRole) Response.Redirect index.asp else Response.Write 用户名或密码错误 end if rs.close : set rs nothing %逻辑说明CreateParameter 的第二个参数 200 代表 adVarChar即可变长字符串第三个参数 1 是 adParamInput表示输入参数第四个参数是长度必须与表字段长度一致身份证字段是 30 就写 30写短了会截断报错。用 ? 占位符而不是把变量直接拼进 SQL能挡住最简单的 SQL 注入也方便在论文里写“本系统对主要输入采用参数化查询”。但注意参数化后不能动态改 SQL 结构比如 ORDER BY 字段名如果要根据用户选择变化仍然要先在代码里做白名单校验。3.4 初始化演示数据没有航班首页就是空表建库后要往 Flights 表插至少 10 条有代表性的航班数据覆盖同一天不同时间和价位这样答辩演示时输入出发城市和到达城市就能看到列表。可以写一个 init_data.asp 放后台提供“一键初始化演示数据”按钮把清空、重插、返回结果包在事务里。这一步能省掉答辩前手动到 SSMS 补数据的慌乱而且每次演示前点一下数据状态永远可控。4. 核心业务代码怎么落航班查询、下单扣减、后台报表这一章是整个系统的命门。毕业论文可以把所有页面代码都贴进附录但答辩时只要讲三个点就够了动态查询 SQL、带事务的订单保存、余票扣减的 UPDATE 语句。这三处讲透项目深度就出来了。不要试图把每个页面都过一遍那样评委听完会觉得你没有重点。4.1 航班查询动态拼接 SQL 的条件与排序怎么写查询页接收 depCity、arrCity、depDate 三个参数用户可能只填出发城市也可能全填。所以 SQL 必须动态拼接且对空值做过滤。这也是毕业设计论文里“多条件组合查询”这个知识点的落点。% dim depCity, arrCity, depDate depCity Trim(Request(depCity)) arrCity Trim(Request(arrCity)) depDate Trim(Request(depDate)) dim sql, rs sql SELECT FlightID, FlightNo, DepCity, ArrCity, DepDate, DepTime, ArrTime, Price, LeftSeat FROM Flights WHERE 11 if depCity then sql sql AND DepCity depCity end if if arrCity then sql sql AND ArrCity arrCity end if if depDate then sql sql AND DepDate depDate end if sql sql AND Status 1 ORDER BY DepTime set rs Server.CreateObject(ADODB.Recordset) rs.Open sql, conn % table border1 trtd航班号/tdtd航程/tdtd日期/tdtd起飞/tdtd落地/tdtd票价/tdtd余票/tdtd操作/td/tr % do while not rs.EOF % tr td%rs(FlightNo)%/td td%rs(DepCity)% - %rs(ArrCity)%/td td%rs(DepDate)%/td td%rs(DepTime)%/td td%rs(ArrTime)%/td td%rs(Price)%/td td%rs(LeftSeat)%/td tda hrefbook.asp?FlightID%rs(FlightID)%预订/a/td /tr % rs.MoveNext loop rs.close : set rs nothing % /table逻辑说明WHERE 11 不是废话它让后续每一段 AND 都不需要判断“是不是第一个条件”动态拼接起来最省事。数据量在几百行以内对性能没影响答辩被问“为什么不把 11 去掉”回答“为了动态拼接时少写一层判断逻辑更清晰”就够。depDate 最好加一个 IsDate 校验防止用户在 URL 上塞非法值导致 SQL 报错。查询是读操作拼接风险相对可控但如果你追求完整也可以把这里的参数全部改成 ADO Command 方式把第 3.3 节的写法复用到查询上。4.2 下单并扣减余票事务和 UPDATE 条件防超售这是全系统的核心。一次订票要完成两件事往 Orders 插一条记录把 Flights 的 LeftSeat 减 1。两件事必须同时成功或同时失败所以要用事务。扣减语句必须带上 AND LeftSeat 0防止余票为零时继续卖。% dim flightID, name, idcard, phone flightID Trim(Request(FlightID)) name Trim(Request(PassengerName)) idcard Trim(Request(IDCard)) phone Trim(Request(Phone)) if not IsNumeric(flightID) then Response.Write 参数错误 Response.End end if conn.BeginTrans On Error Resume Next dim sqlInsert sqlInsert INSERT INTO Orders (OrderNo, FlightID, PassengerName, IDCard, Phone, Price, Status) sqlInsert sqlInsert SELECT NO CONVERT(VARCHAR(20), GETDATE(), 112) RIGHT(0000 CAST(OrderID AS VARCHAR(4)), 4), FlightID, name , idcard , phone , Price, 1 FROM Flights WHERE FlightID flightID dim sqlUpdate sqlUpdate UPDATE Flights SET LeftSeat LeftSeat - 1 WHERE FlightID flightID AND LeftSeat 0 conn.Execute sqlInsert conn.Execute sqlUpdate if Err.Number 0 And conn.Errors.Count 0 then conn.CommitTrans Response.Redirect order_list.asp?msgok else conn.RollbackTrans Response.Write 下单失败可能余票不足 Err.Description end if %这里的 INSERT ... SELECT 写法有两个用意一是直接从航班表取 Price避免页面提交一个自定义价格来篡改数据二是同时校验 FlightID 必须真实存在。OrderNo 用日期加自增数字拼接并不严格唯一但毕业设计演示足够论文里可以写“本设计采用时间戳加自增方式生成订单号唯一性依赖数据库自增列”。真正的防超售核心是那条 UPDATE 带了 LeftSeat 0如果影响行数为 0说明没有可扣的余票虽然 SQL 不报错也应该回滚。如果想更严谨可以用一个折中方案先执行 UPDATE然后检查影响行数为 1 才插入订单并提交为 0 直接回滚并提示余票不足。影响行数怎么判断在 SQL Server 里用 ROWCOUNT但在 ADO 里更稳妥的做法是重新查一次 LeftSeat或者把 UPDATE 写成“UPDATE ... OUTPUT INSERTED.LeftSeat”再读取。毕业设计写到“先扣减成功才插订单”这个层次已经比大部分示例源码成熟。事务的完整意义也在这里两个操作要么都发生要么都不发生。4.3 后台航班管理和简单统计用最少的代码撑起管理模块后台航班管理页一般是表格列出所有航班每行带“编辑、停售、删除”三个操作。我强烈建议用“停售”而不是“删除”因为删除会被订单表的外键挡住或者留下脆弱的引用。Status 字段的作用在此时体现后台把航班状态改成 0前端查询自动过滤掉效果和删除一样但数据还在不会破坏订单表的外键关联。统计报表不用花哨图表用 GROUP BY 做一个“最近 7 日出票量”就够既好讲又不容易出错。SELECT CONVERT(varchar(10), CreateTime, 120) AS D, COUNT(*) AS Cnt FROM Orders WHERE Status 1 AND CreateTime DATEADD(DAY, -7, GETDATE()) GROUP BY CONVERT(varchar(10), CreateTime, 120) ORDER BY D把这段结果循环输出成表格而不是引用任何图表控件因为答辩机不一定装了图表运行库。这里 CONVERT(varchar(10), CreateTime, 120) 是把日期时间转成 yyyy-MM-dd 字符串再按这个字符串 GROUP BY实现“按天分组”。120 是 ODBC 规范格式答辩时被问“为什么用 120”你要能答“为了把 datetime 统一成固定宽度日期字符串分组结果稳定”。统计页只要这一条 SQL配合一个简单表格就能对应到论文里“系统实现数据统计功能”那一节。5. 部署和答辩现场最容易翻车的地方五条避坑记录这一章全部来自调试这类项目时的真实经验每一条都对应着一次现场翻车。如果时间有限优先读完这一章至少能帮你避开一半以上的低级问题。5.1 IIS 父路径没开页面直接 500现象访问 index.asp 报“Active Server Pages error ASP 0131”或者干脆 500。原因页面里有用 引用上级目录而 IIS 的父路径默认 False。解决IIS 管理器 → 站点 → ASP → 启用父路径 → True。这个坑在十个求助里至少占六个属于第一排查项。改完设置记得刷新站点不用重启 IIS浏览器强制刷新再看。5.2 SQL Server 连接失败TCP/IP 协议没有启用现象SSMS 能登上数据库但 ASP 页面报“SQL Server 不存在或访问被拒绝”。原因SQL Server 2008 R2 默认启用了 Shared Memory但 ADO 连接走 TCP/IP 1433 端口TCP/IP 协议在配置管理器里是禁用状态。解决打开 SQL Server Configuration Manager → SQL Server 网络配置 → 启用 TCP/IP重启 SQL Server 服务。如果在实验室局域网里调试还要注意防火墙是否放行 1433 端口。演示前最好先在 ASP 页面放一个纯连接测试能避免把问题带到台上。5.3 中文乱码页面编码、数据库排序规则、连接字符集三方不一致现象浏览器里中文显示成问号或者从数据库读出来直接乱码。原因有三种页面文件本身保存成 UTF-8 没有 BOM而 Response.Charset 写的是 gb2312数据库排序规则不是 Chinese_PRC_CI_AS用了某些 ODBC 驱动时连接字符串缺字符集设置。解决统一方案是页面文件另存为 ANSI 编码页头写 % codepage936 %数据库排序规则用 Chinese_PRC_CI_AS字段全部用 NVARCHAR。如果页面已经是 UTF-8就不要混用 gb2312 输出二选一页面编码和 Response.Charset 必须一致。这个坑排查起来最费时间因为涉及文件保存、代码、数据库三层。5.4 SQL Server 版本差异2008 R2 的脚本拿到 2012 以上跑不跑得通现象本地 2008 R2 跑得好好的答辩机房装的是 SQL Server 2016运行时报语法错误常见关键词是 TOP、OUTER JOIN 这类老写法。原因高版本 SQL Server 对某些 2000/2008 时代的旧语法兼容行为变了。解决在答辩机上重新执行建库脚本而不是直接附加旧库如果不想改代码可以给数据库设置兼容级别ALTER DATABASE AirTicketDB SET COMPATIBILITY_LEVEL 100让新实例按 SQL Server 2008 的规则处理。这个命令很实用能在答辩前把兼容问题一次扫掉但要注意它只是兼容行为调整不改变物理存储格式。5.5 登录页的 SQL 注入问题至少能用一句话回答评委现象评委一定会追问“你的系统怎么防 SQL 注入”这也是毕业设计答辩的高频问题。如果你支支吾吾印象分会掉一半。解决把 3.3 节的参数化登录代码准备好答辩时说“用户名和密码通过 ADO Command 的 Parameters 集合传入数据库把参数当数据而不是代码来执行因此拼进 SQL 的输入不会改变查询结构。”这句话就够了。还要当心评委拿页面里的其他拼接 SQL 反问你要能解释“查询接口的参数可控写入接口全部参数化”别把两种写法混为一谈。6. 让演示不翻车预置好演示数据和一套固定讲解顺序答辩临近时不要再改代码而是把演示路径固定下来。我自己有个习惯答辩前做一次“冷启动测试”把浏览器缓存清掉、回收 IIS 应用池、重启 SQL Server 服务然后走完整条链路打开首页输入出发城市和到达城市点查询从列表里选一个余票充足的航班填乘机人信息提交提示订票成功到订单列表页看到状态再去后台把这个航班停售或把订单改状态。全程控制在三分钟以内每一步都知道屏幕应该出现什么结果。演示数据要固定成一套。我通常会在数据库里只保留一组登录账号和十几个航班小本子上写明测试账号、测试航班号、余票数量。这样不管现场点评老师怎么指你永远可以退回到这套数据重新演示。还有一个小习惯给页面所有增删改操作加失败提示不要出现白屏。即使老师现场试出“余票不足”你也能顺势展示系统的异常处理这反而是加分点。时间有余的话可以做一个“防超售验证”截图放进论文开两个浏览器同时提交同一个只剩一个座位的航班第二笔订单被拒绝。这一张截图胜过十页原理描述也让答辩现场有干货可讲。我帮人调过很多次这个项目最深的感觉是评委想听的是你能讲清一条订单从查询到入库的完整链路而不是你能说出多少个控件。把动态查询、事务扣减、防超售验证这三个点练熟即使页面朴素分数也不会低。希望这篇能把从环境搭建到答辩演示的路帮你走顺希望帮到你。本文还有配套的精品资源点击获取
返回列表