Cover

12307 火车票购买平台

Wenxuan SHI /
May 28, 2020
7 min read

大二课程数据库原理的期末项目。有查票、中转、订票、余票查询、线路管理等等功能。后端使用了 Flask 框架,前端使用了 Vue。项目最终获得了满分。

12307 是我第一次制作前端页面。之前写 WannaAC (上一篇博客) 的时候涉及过一点点,不过它只有单页面,也就是一张表格、一个输入框的难度。这次的前端涉及到页面路由、按钮交互、身份验证、后端 API 调用等等……所以我花了点时间在研究 Vue 框架上。

项目对前端不做要求,很多组都只做了 CLI 交互。

我平常比较喜欢简单整洁的界面,这次用 ElementUI 实现的网页样式就是我心仪的设计风格。

订票页面
订票页面

Vue 提倡将重复元素抽象成组件以方便复用。我绘制了一个“火车票组件”,并且在查看订单的页面上放了几张「真的火车票」。比起显示一堆文字,这样感觉上更直观。

查看订单
查看订单

Work From Home

制作这个项目的时候正好是 Covid-19 新型冠状病毒爆发的疫情期间,学校在线教学,我和队友 @macromogic 也是在线上完成了项目的合作。一个月来,基本上每天晚上都用腾讯会议开屏幕共享一起写代码。

线上做项目其实也很有意思,我们强迫自己练习了 Git 的各种使用技巧。比如 rebasefast-forward,还有 git -f 😅。

后来才知道这其实就是敏捷开发里“结伴编程”的雏形。选一个好队友真的非常重要。后续我们一起合作了嵌入式、面向对象、计算机网络、操作系统、软件工程的期末项目。

ORM

ORM 是加分项。但其实像票务系统这种表关系复杂的数据库,个人是不赞同过度 ORM 的。

🤔 何时不使用 ORM
ORM 本意是转译层,方便将数据库中的“数据”转换成 OO 语言中的“对象”。因为 OO 语言处理“对象”的能力非常强大,所以 ORM 能在后端项目中大放光彩。 然而 ORM 不是灵丹妙药(或称 silver bullet)。在查询复杂度非常高的时候,ORM 的心智负担远大于直接写 SQL 语句。由于 ORM 转译不透明,进行代码调试或架构调整也非常困难。

比如在火车票余票查询过程中,我们要在一个查询中实现的逻辑有:

  • 从起点到终点有直达的火车班车
  • 在这样一趟列车中,是否存在一个座位,它从起点到终点的每个区间都可预定

这个描述翻译成 SQL 就是 7~8 张表的联合查询。如果翻译成 ORM,就是接下来长达一整个屏幕的、眼花缭乱、难以维护的代码。

使用 ORM 查询余票信息
使用 ORM 查询余票信息

中转火车

查询中转列车应该怎么设计算法?看起来我们只需要跑一个最短路算法查询,就可以得到结果。如果提前跑好最短路,将方案存储成为 [车站数 * 车站数] 的方阵,应该是可行的算法。

实际查询比想象的方案复杂。中转的次数要尽可能低。中转的等待时间要尽可能少。车票的价格要尽可能的低。这已经成为一个没有最优解的多目标优化问题。加上中铁经常调整火车调图(停运或增运列车),各线路客流量有区别,设计一个动态优秀的中转算法是非常困难的。

我们的设计加入了一点启发式搜索。因为中转通常发生在客流量较大的城市枢纽站,所以我们按照客流量动态提升大型枢纽站的权重。为了进一步提升搜索速度,我们在最短路算法中不会从小站出发进行边集拓展。经过这样的优化,我们的中转火车算法总体上令人满意。

轶事

2021 年上半年,我偶然收到一封邮件,内容是询问我这个项目(开源在 GitHub 上)如何启动。仔细一查,竟然是一个外校学生想用这个项目充当他的毕业设计……

由于这个项目是两个大二学生的期末作业,所以还有非常多可以优化的部分。如果你对于火车订票系统有兴趣,我们可以一起讨论。如果你喜欢这篇博客,可以通过 RSS 订阅更新。欢迎关注我的 GitHub 和推特账号,我将分享更多有趣的优质内容。如果你对这篇文章有任何疑问或建议,请在下方留言。再会~

© LICENSED UNDER CC BY-NC-SA 4.0

Loved this post? Consider following me.

I work on topics related to system security aside with many other interesting things. I would love to have friends who share the same interests.

Wish you happy