ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

酒店预订App开发实战:Android+Spring Boot+MySQL毕设全解析

酒店预订App开发实战:Android+Spring Boot+MySQL毕设全解析 1. 为什么酒店预订App能成为毕设选题里的常青树每年带毕设都能遇到穿酒店预订这双鞋的学生坦白说这题目不算新颖但它确实耐打。业务场景足够常见所有人都住过酒店、下过订单不需要解释背景老师一听到需求就秒懂。技术范围覆盖移动端、服务端、数据库、接口联调一整条链路工作量适合一个学期完成既不会太浅让评审觉得没东西看也不会难到学生卡死在某个环节。这类题目的核心价值在于前后端分离但业务完整。学生可以借此写清楚Android端怎么搭、Spring Boot怎么起、MySQL表怎么设计答辩时的表达空间很大。我给学生的建议是如果目标是平稳毕业且要学到真东西Android客户端Spring Boot后端MySQL这种组合是最稳妥的方案做出来是完整可运行的App而不是只写个静态页面交差。这题适合几类人。一类是Android方向的学生想用原生开发把移动端生命周期、网络请求、数据缓存这套玩明白。一类是打算走Java后端路线的学生想借Spring Boot把接口设计和数据库落地练一练。还有一种就是时间紧、求稳的学生抄一套代码改一改也能过但如果想好好答辩建议老老实实把每个模块的来龙去脉都啃一遍答辩才能对答如流。1.1 评审老师最关心的三个评分点第一眼看演示效果App能不能跑起来、界面是否完整、核心流程是否闭环。第二眼看工作量文档里有没有讲清楚表结构、接口设计、异常处理而不是一堆代码贴图。第三眼看创新点哪怕只是加了地图定位、接入了微信登录手机号、做了图表统计订单量都算加分项。我见过不少学生把精力全砸在界面UI上按钮做得花里胡哨结果后端只写了一个/user接口演示的时候就卡死在登录页。这属于典型的面子工程答辩时老师一翻源码就问住了。正确做法是先把业务流程走通登录、列表、详情、下单、订单管理这条主线一点不能缺然后再在UI和交互上做美化。1.2 一个毕设题目如何覆盖整条技术链路这题的精妙之处在于天然拆成三块。Android端负责界面呈现和用户交互Spring Boot端负责业务逻辑和数据处理MySQL负责持久化存储。三块拼起来就是一套真实业务系统跟企业里的小型移动项目结构几乎一致。学生做完这个项目后至少能回答这几个问题Android的Activity和Fragment怎么配合、RecyclerView怎么承载动态列表、Retrofit怎么封装网络请求、Token怎么存储和刷新、Spring Boot的Controller-Service-Mapper分层是干嘛的、数据库表之间怎么设计外键关联。这些知识点全都能在答辩时被问到也是毕业设计想考察的核心能力。2. 技术选型与整体架构思路技术选型是最容易纠结的地方尤其Spring Boot版本的话题在网上讨论极多。我个人的建议是毕设不要追新稳定优先。Spring Boot用2.7.x系列配JDK 8是最稳妥的组合JDK 17加Spring Boot 3.x也能跑但有些老教程、老依赖不兼容学生排查起来费劲。别问版本太高行不行能跑起来并且能复现才最重要。Android端建议用Java而不是Kotlin不是说Kotlin不好而是Java教程多、报错搜得到答案学生自己写代码时遇到问题能更快解决。主题上用XML布局就好Compose虽然新潮但学习成本高毕设时间有限没必要在UI框架上冒险。网络层用Retrofit加OKHttp图片用GlideJSON解析用Gson这套组合是Android开发里最普及的方案任何报错都能搜到解决方案。2.1 后端Spring Boot的技术细节后端搭建时用MyBatis-Plus做持久层它能省掉大量重复的CRUD代码内置的分页插件也稳定。项目结构严格按Controller层、Service层、Mapper层拆分这个分层习惯就是答辩时的加分项。统一返回结果封装成Result类数据结构保持{code, message, data}这样的格式前端解析时就非常顺畅。JWT做登录认证是个明智选择。用户登录成功后后端签发一个Token返回给Android端Android端把Token存到SharedPreferences里之后每次请求都在Header里带上Authorization字段。服务端用一个拦截器验Token未登录的请求直接返回401状态码。这套机制在企业项目里也是标配写进文档里很有分量。顺便提一下Spring Boot的配置文件里要注意数据库连接、扫描包路径、端口冲突这几个点。学生最容易踩的坑是忘了在启动类上写MapperScan或者数据库账号密码配置错了连不上启动直接报错。这些细节我在实操部分会展开讲。2.2 Android端的架构与界面方案Android端采用单Activity多Fragment的结构底部导航放三个Tab首页、订单、我的。Activity作为容器的好处是Fragment切换流畅不会出现Activity栈堆积的问题。首页里用RecyclerView展示酒店列表每一项显示酒店图片、名称、城市、星级和参考价格点击进入详情页。网络层封装时要注意线程切换。Retrofit的回调默认在子线程执行更新UI必须切回主线程很多新手把Toast写在回调里发现不弹就是这个原因。后来引入RxJava或者LiveData可以简化操作但毕设里没必要搞那么复杂Retrofit自带回调加runOnUiThread就够了。我会建议学生写一个简单的异步工具类统一处理请求成功和失败的分支代码看起来干净答辩时也容易讲。酒店详情页要展示房间类型列表Standard Room、Deluxe Room这样分类每个房间类型有价格、面积、床型、可订数量。这一点必须做成动态接口不能写死否则就失去了App的意义。用户选择入住日期和离店日期后系统自动计算天数、算总价然后提交订单。2.3 前后端接口对接的约定前后端联调最怕你说东、我说西所以接口约定要在开发前先定好。建议用一个Swagger文档或简单的Markdown接口说明把每个接口的地址、请求参数、响应结构定死。我习惯让学生先定义统一的Result结构所有接口都返回这个对象。这里有一个很关键的约定是时间格式。Java后端默认返回的日期格式是带T的ISO格式比如2025-01-01T14:30:00Android端用Gson解析时如果没配置格式就会被当成字符串处理或者报错。最好在后端统一配置成yyyy-MM-dd HH:mm:ss或者在Android端配置Gson的日期格式两边统一省得联调时互相甩锅。3. 核心功能模块拆解与实现要点功能拆解如果做得好开发的思路就会无比清晰。我按模块来讲每个模块对应Android端的页面、后端的接口以及数据库的表这是整个项目的主干线。主线走通了就说明毕设的核心功能完成度超过80%。用户端的功能需求一般包含注册登录、酒店浏览搜索、酒店详情查看、在线预订下单、我的订单管理、个人信息编辑这么几个板块。后台管理端如果需要的话可以做一个简单的Web页面但毕设时间紧张的话也可以直接用SQL语句管理数据或者做一个简陋的Android管理端。我更推荐做一个独立的Web管理界面哪怕只是用Spring Boot写几个带模板的页面也能在答辩时体现系统的完整性。3.1 用户注册与登录模块设计注册逻辑要注意密码加密用BCryptPasswordEncoder千万不能明文存库。这个点看似基础但很多学生的数据库表里真的明文存着密码答辩老师问一句密码怎么保护就答不上来了。注册时校验手机号和密码长度手机号作为唯一登录名同一手机号不能重复注册。登录成功后后端返回Token和用户昵称Android端保存后跳转主界面。注意退出登录时要把本地Token清掉并且要区分401和500401说明Token过期或无效应自动跳回登录页500说明服务器出了Bug要提示用户稍后重试。很多学生的App没有做这个区分用户Token失效后一直报服务器错误很影响体验。短信验证码这块做不做因需求而异。真实系统肯定要接短信平台但毕设环境里可以做模拟比如把验证码打印在服务端日志里或者固定校验123456。若想加分可以接一个免费的短信平台但这个费用和审核周期往往超出毕设预期我个人建议做成模拟验证码并在文档里注明生产环境需替换为真实短信通道。3.2 酒店浏览与搜索功能酒店列表接口支持按城市筛选和关键词模糊搜索后端用MyBatis-Plus的QueryWrapper拼接条件即可。城市列表可以从酒店表中distinct查询出来做成筛选条件栏。关键词可以匹配酒店名称、地址和简介用like查询实现。列表分页做成每页10条通过下拉刷新加载新数据。图片展示是酒店详情页的重点。酒店图片用Glide加载URL存在数据库的image字段里。这里有个实操心得一张图片的URL如果失效页面会直接黑一块特别难看。建议Glide加上placeholder图片加载中显示灰色占位图加载失败显示图片加载失败这样即使有些图片挂了页面也不会崩。酒店的排序逻辑也可以做一点文章支持按价格从低到高、按评分从高到低、按默认推荐排序。这个切换逻辑在Android端用排序标识字段传给后端后端在QueryWrapper里动态追加排序条件实现不复杂但展示效果很直观。3.3 预订下单流程的实现细节预订流程是整个App里业务逻辑最密的一段。用户在房间列表里选择一个房型进入下单页选择入住日期和离店日期此时前端要实时计算两个东西入住天数和订单总金额。天数用离店日期减去入住日期Java里用ChronoUnit.DAYS.between计算即可。总金额等于每日价格乘以天数可以加一个10%的服务费逻辑更真实。提交订单时后端核心要处理的是库存校验。房间可订数量为空或库存不足时直接返回房间已被订完。同时并发场景下容易出现超卖毕设虽然不要求做分布式锁但我推荐至少加一个简单的数据库事务和行锁用SELECT FOR UPDATE查询库存再更新避免并发下单把库存打穿。这个细节写进论文里抢住系统考虑并发安全这个点答辩会很加分。订单号必须唯一不能自增流水号凑合。订单插入前用时间戳加随机数生成订单号比如yyyyMMddHHmmss加6位随机数识别度和唯一性都能兼顾。生成订单后跳转到订单详情页同时把订单状态置为待支付。这里要注意毕设里支付功能通常接不了真实渠道模拟支付即可。3.4 订单管理与会话保持策略订单管理界面对App体验的影响不可小觑。订单列表按状态分组待支付、已支付、已取消、已完成各占一个Tab。RecyclerView展示订单卡片卡片上要有酒店名称、房型、入住日期、总金额、状态标签。用户点击卡片进详情待支付状态的订单可以点去支付模拟支付或取消订单。这里要特别提一下Remind头Token的保存方式。Android端把Token持久化到SharedPreferences每次创建Retrofit请求时从里面取出Token加进Header。订单接口查询用户自己的订单时后端从Token里解析出userId而不是让前端传userId过来否则传递假userAlias就能查别人的订单这是一个非常容易被答辩老师挑刺的安全问题。4. 数据库设计与接口规划数据库设计我会要求学生先画ER图再建表这是文档里必须有的部分。整体表结构围绕用户、酒店、房间类型、订单四条主线展开每张表的字段设计都要说得出为什么要有这个字段。主键一律自增id创建时间自动填充更新逻辑需要考虑。酒店表与房间类型表是一对多关系一个酒店有多个房型。订单表与用户、房间类型都有关联但存储时要把冗余字段存进去比如酒店名称、房型名称、价格快照。原因是业务上用户下单后如果酒店名称或价格变了订单记录不应跟着变快照能保留下单时的原貌。这个设计能体现学生对业务逻辑细节的把握建议写进文档。4.1 核心表结构与字段说明用户表t_userid、username、password、nickname、phone、avatar、create_time。username和phone可以合并直接用手机号当登录账号字段少了反而更好维护。password存储BCrypt加密后的密文长度至少60位。avatar存用户头像URL。酒店表t_hotelid、name、city、address、description、level、score、image_urls、create_time。level表示星级档位score是用户评分image_urls用逗号拼接多个图片URL。城市字段单独拆成一个city表也可以但毕设直接从酒店表distinct出一个城市列表更简单。房间类型表t_room_typeid、hotel_id、type_name、area、bed_type、price、stock、image_url。重点提一下hotel_id外键关联酒店表和stock字段表示可订房间数每次下单成功后要减一。房屋面积、床型显示在详情页能帮助用户做决策。订单表t_orderid、order_no、user_id、hotel_id、room_type_id、hotel_name、room_type_name、check_in_date、check_out_date、nights、amount、status、contact_name、contact_phone、create_time、pay_time、cancel_time。不建议把状态用数字代替建议直接用字符串PENDING、PAID、CANCELLED、COMPLETED可读性远好于1234这样的魔术数字。4.2 RESTful接口的规范设计接口设计风格统一用RESTful资源用名词复数动作用HTTP方法表示。用户注册登录用POST酒店列表用GET创建订单用POST取消订单用PUT或者POST。每个接口的路径和参数的命名语义要一致不要再出现getHotelList和queryRoom这样风格混乱的命名。端口接口/api/auth/register、/api/auth/login必做/api/hotels?citykeywordpage1size10必做/api/hotels/{id}/roomTypes必做/api/orders需要登录后携带Token访问/api/orders/{id}/cancel是用户取消订单的操作。每个接口都要有异常处理参数不足返回400传参不存在返回404业务校验未通过返回200但code非0前端根据code区分。我建议学生把接口测试用Postman跑一遍导出一份接口测试文档放进毕设材料里。老师在答辩时很可能会问接口怎么调试的有Postman请求记录比空口白话有说服力得多。4.3 关键业务逻辑的触发点预定流程的后端触发逻辑要完整。用户提交订单先校验Token得到用户身份再校验房间类型是否存在、入住日期是否合法、库存是否充足最后事务性扣减库存并生成订单。订单生成后支付逻辑可以简化直接在订单详情页提供一个模拟支付按钮点击后调用后端接口把订单状态从待支付改成已支付再把支付时间写入。拦截器的配置也属于业务规则的范畴。在Spring Boot中写一个HandlerInterceptor实现Token校验excludePathPatterns里放行注册、登录、酒店查询这些公开接口其余接口统一拦截。Token过期返回的JSON里code要定义为401而不是笼统的500这样Android端才能精确处理跳转登录页和提示网络错误这两个不同的场景。5. 实操过程与核心环节实现这一部分是最容易出岔子的我把从零到能跑通全流程的操作记录写在这里。先起后端再写Android端最后联调。不要两头一起改出Bug时根本分不清是前端还是后端的问题经验之谈。后端我用Spring Boot 2.7.14JDK 8MySQL 8.0依赖引入spring-boot-starter-web、mybatis-plus-boot-starter、mysql-connector-java、jjwt和lombok。pom.xml里的依赖版本不需要手记网上搜spring boot 2.7 mybatis-plus就能找到对应配置重点是别混用Spring Boot 3.x的依赖启动时容易报不兼容错误。5.1 后端工程启动到接口验证新建项目后第一步改application.yml配置数据源。数据库名称用hotel_db连接字符串localhost:3306/hotel_db账号root密码自己本地数据库为准。mybatis-plus的配置要注意驼峰命名自动映射默认是打开的所以Java字段userName会自动对应数据库列user_name省去大量ResultMap。启动类上加上MapperScan(com.example.hotel.mapper)否则Spring容器扫描不到Mapper接口启动会报Invalid bound statement。这个报错几乎每个学生都会遇到我的习惯是在创建工程时就检查这块配置省得后面排查。数据表先建好用Navicat或Workbench执行建表SQL。然后写Controller、Service、Mapper的骨架代码。用MyBatis-Plus的BaseMapper接口单表CRUD基本不用写SQL业务复杂点的查询用QueryWrapper条件构造器或者Select注解写原生SQL。接口写完后用Postman验证登录成功返回Token酒店列表有数据创建订单成功扣库存。后端能跑通后再切到Android端不要着急一上来就两端一起联调。5.2 Android工程搭建与依赖配置Android端我用Java开发minSdkVersion为24targetSdkVersion为34。把Retrofit、Glide、Gson、RecyclerView依赖写进build.gradle。AndroidManifest.xml里记得申请网络权限别忘了开启usesCleartextTraffic属性因为后端如果跑在本地接口地址是http://10.0.2.2:8080这种明文HTTP协议Android 9之后默认禁止明文流量不加这个配置请求永远失败。如果是真机调试网络地址要把localhost换成电脑的局域网IP并且保持手机和电脑连同一个WiFi。我常给学生说Android模拟器访问宿主机用10.0.2.2真机用192.168.x.x这个细节不弄清楚光连接不上服务器就能卡一上午。界面用XML布局搭建首页的酒店列表是核心RecyclerView加LinearLayoutManager即可。每个item卡片布局需要展示图片、名称、星级、价格。item点击事件通过接口回调传给Fragment然后startActivity跳转详情页面详情页再传酒店id。5.3 前后端联调的整体流程与结果验证联调阶段建议按登录-列表-详情-下单的顺序逐层验证。先调登录和注册确认Token能拿回来。接着调酒店列表看数据是否渲染出10条。再进酒店详情看房间类型加载是否正常。最后下一单到订单列表里确认状态是否同步。这条链路每走通一步进度就往前推进一分比茫然地东改一下西改一下高效得多。联调时最常见的表现就是后端返回了数据但前端解析不出来。这时候先看Retrofit的Log拦截器把请求和响应的完整内容打出来。响应里fields名为data、前端拿到却是null大概率是Gson解析用了错误的Bean字段名比如把后端字段hotelId拼成了hotel_id这种低级问题看日志一分钟就能定位。最好写一个简单的日志过滤器HTTP连接情况、响应体内容都在Logcat里打印这样前端排查效率能翻倍。整个项目能完整跑通后再把后端打包成jar部署到云服务器上App就能用公网地址访问答辩演示时就不再受限于本机和模拟器效果完全不同。6. 毕设避坑指南与答辩经验文章写到这里基本方案和代码路径全都清楚了。最后这一part大概率是很多读者最想看的毕竟很多坑不亲踩一遍根本不知道还有这种问题。我根据这几年带毕设的经验把最典型的坑和对应的排查思路总结成一张速查表再聊聊怎么做功能扩展和答辩加分。6.1 高频报错与排查方法速查表现象可能原因排查建议启动报Invalid bound statementMapper没被扫描到检查启动类是否有MapperScan真机连不上后端地址用了localhost改成电脑局域网IP手机和电脑同WiFiAndroid请求报Cleartext明文HTTP被拦截Manifest开启usesCleartextTraffic中文乱码编码不一致后端接口层produces设为application/json;charsetutf-8图片加载不出URL失效或子线程问题Glide加placeholder和error占位图库存扣了但订单没有事务忘记加Transactional确保生成订单和扣库存写在同一事务内Token过期一直报500拦截器状态码没区分正确返回401Android端据此跳转登录这几个问题覆盖了几届学生掉过的坑。内存里都留着教训整理成表希望新一届的人看看至少少走半天弯路。6.2 让项目优于普通毕设的三个扩展方向如果你想把评分往上提一个档次可以从地图、统计、消息三个方向选一个做深。酒店列表页集成百度地图或高德地图SDK把酒店的经纬度标记在地图上点击标记弹出酒店名称再跳详情视觉冲击力很强。管理端做一个简单的订单统计页面用ECharts展示每日订单数和收入趋势数据从订单表的create_time字段按天聚合MAX和MIN一眼就能看出业务波动。还有一个方向是把Spring Boot后台包装成一个小管理端提供酒店增删改查、订单列表管理系统的完整性就高了很多。这三个方向选一个做透就行贪多嚼不烂。6.3 文档撰写与答辩演示的建议毕设文档别到最后才开始写。前端页面、后端代码每一部分写完就去更新对应的文档章节到了最后整理复制粘贴的痕迹就会很少。论文里除了表结构、接口文档、ER图尽量加入几张界面截图、Postman验证截图这些图片是最有效的证明材料。答辩时从演示App开始把注册登录、搜索酒店、下订单、取消订单的流程完整走一遍。然后打开Swagger文档或Postman展示接口列表最后切到数据库表把订单表和酒店表挖出来展示数据是怎么变化的。演示前建议提前录一条完整流程视频存到手机上万一答辩现场没网、服务器没启动不至于人在台上尬住。我个人体会是这个课题最大的价值就是让你把一个虚拟业务完整落地。把酒店预订App做完你学到的不是某个框架的API而是一个想法如何变成可运行的软件的整套思路。如果能把其中的错误处理、并发控制、接口规范都理解到位那就不仅仅是为了交差而是真正往前走了一步。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进