ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Spring Boot旅游网站毕设全攻略:从系统设计到部署上线

Spring Boot旅游网站毕设全攻略:从系统设计到部署上线 每年一到毕业设计季被问得最多的一个选题就是基于Spring Boot的旅游网站。我自己当年做毕设时就是这个题目这几年又陆陆续续帮学弟学妹改过不少版本对这个项目的套路已经熟到不能再熟。这个选题之所以受欢迎是因为旅游网站的业务链路清晰、功能模块好拆分、演示效果好加上 Spring Boot 把绝大多数组件化配置都封装好了你不需要在环境搭建上耗太多时间能把主要精力放在业务实现上。这个项目能做的就是一套完整的旅游服务平台用户端看景点、查线路、订酒店、写攻略管理端维护数据、处理订单、看统计报表。对有 JavaWeb 基础但没怎么独立做过完整系统的同学来说它是性价比极高的一个毕业设计选题。今天我把从选题、技术选型、数据库设计、核心功能实现到部署上线的完整思路整理出来全是实操层面的东西希望能帮你避开那些我当年踩过的坑。1. 选题与技术选型为什么是 Spring Boot 加旅游网站1.1 旅游网站做毕设的核心优势在哪先说结论旅游网站属于“看起来有工作量实际不难啃”的选题。对比电商系统它没有购物车、库存、优惠券、多级分销这些复杂逻辑对比社交平台它也没有即时通讯、好友关系、信息流推荐这些棘手的模块。旅游网站的核心动作就四件事展示内容、检索内容、下单预订、后台管理。业务链路清晰表结构好设计工期可控这是它最大的优点。还有一个容易被忽略的点旅游网站的展示素材非常丰富。景点有图片、有评分、有简介攻略有长文、有作者、有收藏数这些天然适合做列表页、详情页、搜索筛选和统计图表。毕设最终是要演示给老师看的视觉效果饱满的项目答辩时的体验会好很多。我见过不少做管理系统类毕设的同学演示时满屏表格老师看着都困而旅游网站至少能做轮播图、地图展示、评论区、数据大屏这些视觉效果展示环节天然占优。当然选题也有要注意的地方。正因为太多人做旅游网站如果你的功能只是景点CRUD加登录注册那在评审老师眼里就是“常规操作”很难拿高分。所以我建议在基础功能之外至少做一个有区分度的亮点模块。这篇文章后面会详细讲几个加分方向数据可视化统计、中文分词热词分析、文件上传与图片管理、订单状态机设计。1.2 技术栈怎么搭配更稳妥技术选型的第一原则是“求稳”不是“求新”。Spring Boot 版本我建议用2.7.18。这是 2.x 系列的最后一个版本资料多、生态稳、兼容 JDK8 和 JDK11。不要一上来就追 Spring Boot 3.x虽然新但它强制要求 JDK17很多老教程里的依赖坐标、配置写法都不适用遇到问题搜不到答案的时候你会非常崩溃。“springboot版本太高”导致的依赖冲突和配置差异是我见过最多的卡壳原因之一毕设阶段没必要冒这个险。持久层我用的是MyBatis-Plus。它比原生 MyBatis 省事单表 CRUD 不用手写 SQL分页和条件查询封装得也很顺手对毕设场景来说效率极高。如果你对 Spring Data JPA 更熟用它也完全可以但 MyBatis-Plus 的文档更接地气出问题时更容易定位。前端有两种方案需要根据自己的情况选方案一服务端渲染Thymeleaf。适合前端基础薄弱、不想折腾跨域和前后端联调的同学。Spring Boot 对 Thymeleaf 支持很成熟页面直接用th:each、th:text渲染数据写起来像 JSP 的进化版但比 JSP 干净。方案二前后端分离Vue Element Plus。适合想在答辩时展示工程化能力的同学。我自己的项目用的就是 Vue3 Vite Element Plus后端纯出 RESTful API。这个方案的缺点是你要额外处理跨域、token 存储、打包部署工作量会大一些但演示效果和简历含金量都更高。其他组件方面数据库用 MySQL 8.0缓存可以加一个 Redis用于首页热点数据、验证码存储、token 黑名单搜索场景用 MySQL 的 LIKE 就够不需要上 Elasticsearch。文件存储本地磁盘即可配合静态资源映射完全能满足毕设需求。如果简历已经写了微服务相关的技能可以额外整合一个 MinIO 做对象存储这个后面我会展开说。2. 系统设计与功能模块拆解2.1 用户角色与权限模型怎么设计旅游网站至少有三种角色游客、注册用户、管理员。权限模型不必上 Spring Security 那套复杂机制用JWT HandlerInterceptor就能实现得很干净。用户在登录接口提交用户名密码校验通过后服务端生成一个 token 返回给前端。前端每次请求在请求头里带上Authorization: Bearer token后端写一个拦截器统一解析 token拿到用户 ID 后放到请求上下文里。管理员接口额外校验用户角色字段不是 admin 直接返回 403。这样设计的好处是你不用去背 Spring Security 那套过滤器链和配置类核心逻辑自己掌控答辩时也能讲得清清楚楚。角色和权限相关的核心表我建议这样拆用户表userid、用户名、密码BCrypt 加密存储、昵称、头像、手机号、角色、状态。用户扩展表可省如果涉及用户收藏、浏览记录可以拆出来单独存关联关系。角色权限表可选如果只做单管理员表都不用建直接在用户表里加一个role字段就行。对于大部分毕设来说三张表足够用户表、角色表、用户角色关联表看起来规范但实际开发中你会发现徒增工作量。我的建议是用户表加一个role字段0游客/1普通用户/2管理员就可以应对所有场景。2.2 核心业务模块与数据库表设计旅游网站的核心业务我拆成五个模块来设计景点模块、旅游线路模块、酒店住宿模块、攻略社区模块、订单中心模块。各模块对应的核心表如下表名核心字段说明scenic_spotid、name、level5A/4A、city、description、cover_image、open_time、ticket_price景点基础信息图片建议存 URL 路径不要存 Base64travel_lineid、title、scenic_ids冗余、days、price、departure_city、cover_image旅游线路多条景点用逗号分隔简单场景足够hotelid、name、city、address、star_level、price_per_night、image酒店信息strategyid、user_id、title、content、cover_image、view_count、like_count、status用户发布的旅游攻略content 用 longtext 存富文本ordersid、order_no、user_id、product_type1景点门票/2线路/3酒店、product_id、quantity、total_price、status、create_time统一订单表用 product_type 区分业务类型commentid、user_id、target_type、target_id、content、score、create_time通用评论表景点和攻略都往这里写favoriteid、user_id、target_type、target_id、create_time收藏表bannerid、image_url、link_url、sort首页轮播图接入后台管理这段设计里有几个关键思路值得说订单表设计成“宽表 类型字段”而不是每个业务一张订单表。好处是后台统计总交易额、热门产品只需查一张表SQL 写起来极其顺手坏处是产品维度信息需要联表查。毕设场景下这个取舍非常划算。评论表和收藏表设计成通用表用 target_type 区分评论对象。这样评论模块只需要写一套 Service景点、酒店、攻略都能复用。所有关联业务都用逻辑删除。MyBatis-Plus 的TableLogic注解加上后删除操作自动变成 update数据不容易查丢。答辩时这一招很加分能体现你的工程意识。2.3 数据统计与可视化模块怎么做才有亮点这是让旅游网站逃离“普通 CRUD 项目”印象的关键模块。统计报表我建议围绕两类数据来做第一类是经营数据分析。比如一周内的订单量趋势、热门景点 Top10、酒店均价区间分布、游客来源城市分布。这些统计全部可以用 SQL 聚合查出来后端只需要写几个接口前端用 ECharts 画柱状图、折线图、饼图。举个例子热门景点 Top10 的核心 SQL 大概是SELECT s.name, COUNT(o.id) AS order_count FROM orders o JOIN scenic_spot s ON o.product_id s.id WHERE o.product_type 1 AND o.status paid GROUP BY s.id ORDER BY order_count DESC LIMIT 10;第二类是文本数据分析。旅游网站的攻略和评论是天然的中文文本数据你可以用 HanLP 分词工具做关键词提取拿到用户讨论最多的高频词然后渲染成词云图或 TopN 热词榜单。HanLP 在 Spring Boot 里的接入很简单引入依赖后直接调用ListString keywords HanLP.extractKeyword(content, 10);这个模块做完以后你的项目功能列表里就多出了“数据分析与可视化”这一项和那些只做增删改查的题目明显拉开了距离。演示顺序上我也建议把统计大屏放在第一屏老师一进来看到图表和数据面板第一印象就上来了。3. 核心功能实现与踩坑记录3.1 Spring Boot 自动装配原理答辩必问但你不用慌毕设答辩里出现频率最高的问题是“Spring Boot 为什么能开箱即用它自动装配的原理是什么”这个问题你必须能用自己的话讲出来不能只会背“约定大于配置”这句话。我习惯这样解释Spring Boot 的主启动类上有一个SpringBootApplication注解它是由SpringBootConfiguration、EnableAutoConfiguration、ComponentScan三个注解组合而成的。核心是EnableAutoConfiguration它会通过AutoConfigurationImportSelector去加载META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件里注册的所有自动配置类。这些配置类上带有ConditionalOnClass、ConditionalOnMissingBean之类的条件注解Spring Boot 根据当前的 classpath 里有没有对应的依赖 jar 包来决定要不要把某个配置类生效。举例来说你的 pom 里引入了spring-boot-starter-webclasspath 里出现了DispatcherServlet那么WebMvcAutoConfiguration就会被激活自动帮你配置好 Spring MVC 的核心组件。如果你引入的是 MyBatis-Plus 的 starter相关自动配置类检测到SqlSessionFactory相关类存在就会自动配置数据源和 SqlSession 工厂。这就是“框架帮你做决策”的底层逻辑。讲清楚这个原理对你实际开发也有帮助。比如遇到“配置了但没生效”的怪问题时第一反应就应该是去翻对应的自动配置类源码看它的生效条件是什么、有没有ConditionalOnProperty开关。追根溯源的能力比背一百个配置项有用得多。3.2 MyBatis-Plus 的常用套路与隐藏坑点MyBatis-Plus 在毕设里最常见的用法是这三板斧第一Service 层继承ServiceImplMapper 层继承BaseMapper。这样你就自动获得了save、getById、removeById、list这些基础方法不用重复写 CRUD。第二用 LambdaQueryWrapper 写条件查询。比如景点列表按城市筛选加价格排序一句搞定LambdaQueryWrapperScenicSpot wrapper new LambdaQueryWrapper(); wrapper.eq(ScenicSpot::getCity, city) .ge(ScenicSpot::getTicketPrice, minPrice) .le(ScenicSpot::getTicketPrice, maxPrice) .orderByDesc(ScenicSpot::getTicketPrice); page(page, wrapper);第三分页用Page对象加分页插件。在配置类里注册一个MybatisPlusInterceptor添加PaginationInnerInterceptor之后所有 Page 参数的分页查询都自动生效。接下来是几个容易踩的坑我写出来你记得避开驼峰映射失效。MyBatis-Plus 默认开启驼峰转换但你要确保application.yml里map-underscore-to-camel-case没被误关。数据库字段create_time映射到实体类的createTime靠的就是这个配置。逻辑删除字段必须加TableLogic。否则你调removeById执行的会是一条物理 DELETE。字段自动填充。create_time、update_time这类字段可以在实体类字段上添加TableField(fill FieldFill.INSERT)然后实现MetaObjectHandler来进行自动填充省去每次手动 set。XML 里的特殊符号转义。如果写自定义 SQL 包含号需要用lt;包一层否则 XML 解析直接报错。3.3 文件上传本地存储就够了别过度设计旅游网站必然涉及图片上传景点封面、用户头像、攻略配图都绕不开。很多同学一上来就想接 OSS 或者 MinIO但毕设的真实现状是本地存储完全够用且更不容易出乱子。具体做法是配置文件里设置一个上传目录upload.path比如/data/www/travel/upload/。文件上传后保存到该目录下数据库里只存相对路径比如/upload/images/20250611/xxx.jpg。然后配置静态资源映射Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourcePaths(file: uploadPath); } }这样浏览器直接访问/upload/images/xxx.jpg就能看到图片Spring Boot 会自动把它映射到本地磁盘目录。这里有一个非常关键的安全细节文件上传不能只看扩展名。恶意用户完全可以传一个伪造扩展名的文件绕过限制。正确的做法是限制上传文件大小spring.servlet.multipart.max-file-size做扩展名白名单jpg/png/gif/pdf同时用 UUID 重命名文件避免文件名中带路径字符或特殊符号造成目录穿越。对于 PDF 等非图片文件还要额外校验 MIME 类型和文件头魔数。3.4 全局过滤器处理 XSS只过滤文本字段放行文件内容“全局过滤器处理 XSS 攻击”是毕设里一个很容易做过头的地方。我的建议是用过滤器做轻量级参数转义但千万别对文件上传流做同样处理。XSS 的核心危害是前端把用户输入当作 HTML 或脚本渲染了。解决思路是后端拦截请求参数对、、、、等字符做 HTML 转义。Spring Boot 里常见的实现是写一个OncePerRequestFilter重写HttpServletRequestWrapperOverride public String getParameter(String name) { String value super.getParameter(name); return escape(value); }这里最需要注意的坑就在文件上传场景。如果过滤器对所有请求都强制转义那么 multipart 表单里的文件内容可能会被读取并转义导致上传的 PDF、图片文件直接被破坏解析失败。正确做法是在过滤器里判断Content-Type遇到multipart/form-data只清洗普通表单字段文件部分完全放行。或者干脆对上传接口的路径直接放行文件的合法性靠 3.3 节里说的扩展名和大小限制来保证。3.5 中文分词与搜索低成本拿下“智能”标签旅游门户网站上搜索框输入“杭州”要能搜出景点、线路、攻略三个模块的结果。普通实现就是对每个模块写一个 LIKE 查询然后拼成一个 List 返回。但如果你想在项目描述里加上“分词检索”“文本分析”这些关键词就可以用 HanLP 来增强搜索逻辑。思路是这样用户输入关键词句子后先用 HanLP 做分词和词性标注提取出地点名词比如“我想去杭州西湖玩两天”分词结果会得到“杭州”“西湖”“玩”。然后后端用这些分词结果分别构造查询条件就可以实现对多词组合输入的模糊匹配。HanLP 是纯 Java 实现直接在 pom 里加依赖就能用不需要部署 Python 服务Spring Boot 项目里接入成本极低。此外攻略详情页可以提取全文关键词生成标签评论列表可以统计高频词用于展示用户的关注热点。这一块做完后系统的可讲内容一下就多了。3.6 热更新与前后端联调的一些小经验使用 Thymeleaf 开发页面时每次都重启后端非常煎熬。调试前建议提前在application.yml里关闭模板缓存spring: thymeleaf: cache: false配合spring-boot-devtools使用模板文件改了以后刷新浏览器就能看到新效果开发效率翻倍。但注意这个配置只适合开发环境打包上线前一定要记得把 cache 改回 true否则每次修改模板不重启就看不到新内容容易误判成 bug。如果用 Vue 前后端分离模式最大的痛点是跨域。后端单独写一个CorsFilter配置类把允许的allowedOriginPatterns设为*开发模式下让前端 Vite 代理/api前缀转发到localhost:8080就行。注意携带 token 时不能只配allowedOrigins(*)因为 allowCredentials 为 true 时会触发浏览器安全限制用allowedOriginPatterns才能兼容。4. 部署上线与常见问题排查实录4.1 Docker 部署 Spring Boot 项目最简单也最稳的上线方式毕设能跑来演示的最终交付形态建议是独立可部署的 jar 包。如果你的简历里准备写 Docker 相关技能那就用 Docker 部署。步骤很少但每一步都值得说清楚。先把项目打成可执行 jar在项目根目录执行mvn clean package -DskipTeststarget 目录下生成travel-0.0.1-SNAPSHOT.jar。然后写一个 DockerfileFROM openjdk:8-jdk-alpine WORKDIR /app COPY target/travel-0.0.1-SNAPSHOT.jar app.jar EXPOSE 8080 ENV TZAsia/Shanghai ENTRYPOINT [java, -jar, app.jar, --spring.profiles.activeprod]接着构建镜像并启动容器docker build -t travel:1.0 . docker run -d -p 8080:8080 --name travel-server travel:1.0启动后访问http://服务器IP:8080就能看到系统。需要注意的点是如果 MySQL 不在容器里application-prod.yml里连接的数据库地址不能写localhost要写宿主机在 Docker 网络中的网关地址通常执行ip addr show docker0查看一般是172.17.0.1或者直接用host.docker.internalWindows/Mac 上可用。4.2 常见问题排查速查表做毕设时遇到问题先检查下面这几个高频点能省下不少搜错误日志的时间问题现象可能原因解决办法启动报端口被占用8080 被其他进程占用netstat -ano找到 PID结束进程或改server.port数据库连接失败 Unknown databaseURL 中数据库名错误先确认 MySQL 里已创建对应库URL 加?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai接口返回中文乱码数据库连接编码不对检查 MySQL 库表字符集是否为 utf8mb4连接 URL 加 characterEncodingjar 包能启动但访问白屏部署时前端静态资源路径不对检查 resources 下的 static、templates 是否打进 jar 包路径有没有拼错应用程序没生效配置Spring Boot 版本过高导致配置 key 变化优先锁定 2.7.18搜问题时限定版本号上传文件太大被拦截默认 max-file-size 只有 1MB修改 application.yml 的 multipart 配置时间字段比实际慢 8 小时JVM 默认时区不对JVM 启动参数加-Duser.timezoneAsia/Shanghai或容器设TZAsia/Shanghai4.3 源码丢失如何从 jar 包反编译找回项目每年都有同学因为没备份或误删导致源码丢失只能拿之前打包好的 jar 来想办法。当你手上只有部署产物时反编译是应急恢复代码的可行路径。我用过比较顺手的方案是先用 IDEA 的 Java Decompilerjava-decompiler.jar直接把 jar 拖进 IDEA 里反编译出.java源文件再用 JD-GUI 打开 jar把所有源码类导出然后把application.yml、SQL 建表脚本、前端静态资源等从 jar 里释放出来重新组装成一个可编译的工程。但要做好心理准备反编译出来的代码和原始代码会有差异比如局部变量名被简化、注释全部丢失、泛型被擦除。这些代码能帮你恢复业务逻辑但直接 run 起来大概率还要手动调整若干处。所以这件事只能作为应急保底手段日常还是要用 Git。毕设项目从第一天就要做git init每次完成一个模块就提交一个版本push 到 Gitee 或 GitHub 私有仓库这是成本最低的后悔药。4.4 答辩演示准备与高频问题梳理项目做完了演示环节掉链子的人其实不少。我的建议是准备一份演示脚本从首页轮播开始演示景点检索、线路详情、在线下单、后台订单处理最后切到数据统计页面展示图表。整个过程控制在 10 分钟左右熟悉到不用看屏幕也能操作。答辩问答阶段最有代表性的几个问题提前准备一下为什么选择 Spring Boot答简化配置、内嵌容器、生态成熟突出开发效率。自动装配原理是什么答见 3.1 节的解释能讲清楚EnableAutoConfiguration与条件注解即可。如何保证用户登录安全答BCrypt 加密密码、JWT 无状态认证、拦截器统一鉴权。订单状态怎么设计的答待支付、已支付、已取消、已完成四态流转支付回调更新状态。怎么防止 SQL 注入答MyBatis-Plus 使用预编译占位符严禁字符串拼接 SQL。数据统计模块的数据量这么小意义在哪答说明设计思路可以平滑扩展到大数据场景演示的是统计口径与分析链路。这些问题平时看起来很简单但要在现场流畅回答还是建议提前把草稿写出来念熟。毕设答辩考察的从来不只是代码而是你对自己项目的理解深度。5. 最后分享一点个人经验这套基于 Spring Boot 的旅游网站做下来我最深刻的体会是毕设难点从来不在技术本身而在“取舍”和“稳定”。很多同学一上来就想把所有功能都塞进系统景点、线路、酒店、攻略、订单、收藏、评论、后台、图表全都要结果是每个模块都写得半生不熟整体到处是坑。更聪明的做法是先搭好主链路让核心流程完整跑通再在有余力的情况下做加分模块。我当时就是先把景点浏览、登录、下单、后台管理跑通后面两周时间才陆续补上评论、收藏和数据可视化整个项目从头到尾没出现过推倒重来的局面。另外一个小建议开发过程中一定要随手写项目笔记。不是要写多么规范的设计文档而是把每次解决的问题记下来比如某个接口为什么这么设计、某个报错怎么解决的、某个配置改了之后影响了什么。别小看这半小时的事到写毕业论文时你会发现素材已经攒好一大半答辩时被提问也能信手拈来。这套“做项目留痕迹”的流程比毕设本身更能体现你未来工作中的工程素养。
返回列表