ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

旅游网站系统毕设实战:Spring Boot+Vue从搭建到答辩全流程

旅游网站系统毕设实战:Spring Boot+Vue从搭建到答辩全流程 做毕业设计选了个“旅游网站系统”用的是 java 技术栈后端 springboot、前端 vue附带数据库脚本和毕业论文。这种组合在课程设计和毕设里非常常见但我发现很多同学拿到源码之后第一步就卡在“怎么把项目跑起来”更不用说后面还要改代码、写论文、准备答辩。这篇文章就把这套系统从技术选型、数据库设计到前后端联调、论文撰写、常见排错完整拆开讲一遍相当于按“做一个完整项目”的思路走一遍流程无论你现在是刚开始选题目还是已经拿到源码正愁怎么下手都可以直接参考。1. 项目定位与整体设计思路1.1 为什么选“旅游网站”这个题目毕设选题其实有个隐藏的逻辑既要能体现工作量又要能让评委一眼看出你做了什么。旅游网站系统正好落在这个区间里它不是一个纯展示型静态站点也不是那种需要分布式架构才能撑起来的高并发系统而是处于“业务逻辑完整、数据关系清晰、前后端交互典型”这个舒适区。从需求层面看旅游网站天然包含几个模块用户注册登录、景点与线路浏览、酒店信息展示、下单预订、个人中心、后台管理。这个信息量对本科毕设来说刚刚好既不会像“商城系统”那样订单状态极其复杂也不会像“个人博客”那样看起来过于单薄。从答辩角度来说旅游网站的业务场景很好讲解。你不需要跟评委解释太多行业概念只需要说清楚“游客怎么在前端选景点、下订单管理员怎么在后端管理数据”整个项目的价值就能被理解。而且这类系统的数据库表设计非常典型用户表、景点表、订单表、评论表之间的外键关系、多表查询、统计功能都能用上写论文的时候数据流和业务流的图也好画。1.2 技术选型Spring Boot Vue 的组合逻辑现在高校里的毕设项目Spring Boot Vue 已经成为事实标准这不是偶然而是这条路线的“性价比”决定的。后端用 Spring Boot核心原因是它把繁琐的配置简化了。传统 SSM 项目要写大量的 XML 配置数据源、事务、拦截器、扫描包全都要手工配很多精力消耗在“让项目跑起来”而不是“实现业务功能”。Spring Boot 的自动配置把这些内置了你只需要在 application.yml 里写好数据库连接、端口等信息就能快速进入业务开发。前端选 Vue是因为它的组件化开发模式非常适合这种管理系统加展示页面的组合。景点列表、酒店卡片、订单表格这些 UI 都可以拆成独立组件页面之间通过 Vue Router 跳转数据通过 Axios 请求后端接口整个前后端分离的开发链路非常清晰。这套技术栈还有一个现实优势学习资料极其丰富。遇到问题无论是 idea 里启动失败、Maven 依赖报红还是 npm install 卡住搜索一下都能找到对应的解决方案。这对毕设周期来说太重要了如果你选一个冷门框架光是排坑就能耗掉大半个月。提示如果你的学校对版本有要求建议优先选择 Spring Boot 2.7.x Vue 2 的搭配。Vue 3 虽然更现代但 Element UI 对 Vue 2 的生态更成熟网上能找到的完整前后端项目案例也更多。1.3 系统角色与功能模块划分一套标准的旅游网站系统一般会拆成前台和后台两个部分对应的角色就是游客用户和管理员。前台面向用户典型功能包括用户注册、登录、退出浏览景点列表、查看景点详情查看旅游线路、酒店信息收藏景点或线路在线下单预订个人中心查看我的订单、收藏列表、基本信息修改后台面向管理员典型功能包括管理员的登录验证景点信息的增删改查线路和酒店的管理订单状态管理用户账号管理评论审核或删除公告/资讯的发布这个划分参考的是大多数毕设项目的标准做法。因为每个人的源码具体设计可能有细微差别但大方向基本一致。拿到源码之后建议你先画出这样一个功能脑图再对照源码结构去看效率会提升很多。理解一个系统最快的方式不是一行一行读代码而是先知道“这个系统有哪些角色、每个角色能干什么”再带着问题去看代码。2. 后端核心功能拆解与实现要点2.1 数据库设计与表结构规划数据库是这套系统的地基表设计得好不好直接决定后面写接口的时候是轻松还是痛苦。我见过很多同学在答辩的时候被评委追问“为什么订单表里只存了用户ID不直接把用户名存进去”其实这就是表结构设计思路的问题。这套旅游网站系统的数据库核心表一般包括这几张我给你按业务关系梳理一下表名主要字段作用说明userid, username, password, nickname, phone, email, avatar, create_time前台用户信息adminid, username, password管理员登录信息通常独立建表scenicid, name, description, cover, images, price, address, city, status景点基础信息travel_lineid, title, content, days, price, scenic_ids, cover旅游线路可能引用多个景点hotelid, name, address, price, room_type, cover, status酒店信息ordersid, order_no, user_id, line_id, hotel_id, people_num, total_price, status, create_time订单表关联用户与线路/酒店favoriteid, user_id, scenic_id, create_time用户收藏记录commentid, user_id, scenic_id, content, create_time景点评论noticeid, title, content, create_time公告资讯其中订单表是核心表中的核心。在设计的时候要注意一个关键点订单状态字段必须要有一个默认值比如用数字 0 表示“待支付”、1 表示“已支付”、2 表示“已取消”这些状态在前后端要约定好前端根据不同的数字显示不同的按钮和文本。还有一个常见坑密码字段不要用明文存储。很多初学项目直接存明文密码这在论文里被评委一眼就能挑出毛病。至少也应该使用 MD5 加盐或 BCrypt 进行加密。如果你的源码里是明文建议改成加密存储这个改进点写进论文里反而是个加分项。数据库字符集建议统一使用 utf8mb4不要用 utf8。因为旅游景点介绍里可能会有生僻字或特殊符号utf8mb4 的兼容性更好。排序规则选 utf8mb4_general_ci 就行。2.2 Spring Boot 后端分层与接口设计拿到源码之后先看后端项目的包结构。一个规范的单体项目包结构通常会按照 controller、service、mapper、entity、config、common、utils 这几层来划分。entity数据库表对应的实体类字段和表字段一一对应mapper数据访问层写 SQL 或使用 MyBatis-Plus 提供的 CRUD 方法service业务逻辑层处理具体的业务判断controller接口入口层负责接收前端请求和返回数据config配置类的位置比如跨域配置、拦截器注册common通用的类比如统一返回结果 Result、自定义异常utils工具类比如 JWT 工具、字符串处理以“景点列表”这个功能为例它的请求链路是这样的前端发起 GET /api/scenic/list 请求controller 层接收参数后调用 service 层的方法service 层判断是否需要分页、是否需要按城市筛选然后调用 mapper 层查询数据库结果层层返回最终由统一返回结果对象 Result 包装后发给前端。前端拿到数据后渲染到页面上。这里有一个加分项统一返回结果。无论接口查询成功还是失败都返回相同的 JSON 结构例如{ code: 200, message: 操作成功, data: { } }这样做的好处是前端只需要封装一次 axios 拦截器根据 code 值统一处理成功或失败状态不用每个页面单独写错误处理逻辑。如果源码里没有统一返回结构你也可以自己加上这是一个投入产出比非常高的优化点。接口设计上RESTful 风格的命名会让答辩加分。比如POST /api/user/register 注册POST /api/user/login 登录GET /api/scenic/list 分页查询景点GET /api/scenic/{id} 查询景点详情POST /api/order 创建订单GET /api/order/my 查询用户自己的订单命名规范统一论文里的接口设计表也好写答辩演示的时候也容易讲清楚。2.3 关键业务场景的实现细节这套系统里最核心的业务场景有两个一个是用户下单另一个是管理员的后台管理。这两个场景串起了几乎所有表的关系也包含了最多的业务判断。先看下单流程。用户在前景点详情页点击“立即预订”前端会把线路 ID、出行人数、预订日期这些信息以 JSON 格式 POST 到后端。后端在 controller 层接收到请求之后先做参数校验比如人数不能为 0、线路 ID 不能为空然后调用 service 层处理核心业务逻辑第一步查询这条线路是否存在状态是否正常防止用户在前端改了参数提交一个不存在的 ID。第二步计算订单金额。单价乘以人数如果系统里有优惠券之类的东西还要在这一步扣减。第三步生成订单编号。订单号一般用时间戳加随机数避免重复。有的系统会用年月日时分秒加用户 ID 拼一个唯一单号。第四步保存订单把用户 ID、线路 ID、景点 ID、金额、状态等字段写入 orders 表。第五步返回订单 ID 给前端前端跳转到“我的订单”页面。这个流程虽然简单但每一步都是可以写进论文的“技术点”。答辩的时候如果被问到“你怎么防止用户恶意提交重复订单”你可以答“在后端生成唯一订单号同时数据库订单号字段设置唯一索引重复插入会被数据库拒绝”这就体现出了对业务的理解。后台管理模块的技术点则集中在图片上传和条件查询上。景点信息肯定要配图片图片上传的常见实现方式是本地磁盘存储前端把文件传给后端后端通过 MultipartFile 接收把文件保存到服务器某个目录再把访问路径存进数据库。注意这里有个很容易踩的坑保存到数据库的路径要存相对路径或者可访问的 URL不要存本地绝对路径否则前端没法访问图片。条件查询在后台景点管理里很常见管理员可能要根据城市、景点名称、价格区间来筛选数据。规范的实现是使用 MyBatis-Plus 的 QueryWrapper 动态拼接条件或者使用 XML 里的动态 SQL。如果你在答辩时能主动说出“这里用了动态 SQL如果城市参数不为空就追加城市条件”这比干巴巴说“我封装了一个查询方法”要加分得多。2.4 登录鉴权JWT 的使用旅游网站系统里面游客可以随便浏览景点但下单和查看“我的订单”必须是登录状态。这就是鉴权要解决的问题。现在主流的做法是使用 JWTJSON Web Token进行无状态认证。用户在登录成功后后端生成一个 token 返回给前端前端把它存在 localStorage 里之后每次请求都在请求头中带上Authorization: token 值。后端通过拦截器或注解来校验 token判断当前请求是否来自一个已登录的用户。具体实现时后端一般会在项目中加入一个拦截器HandlerInterceptor对除登录、注册以外的接口统一拦截。拦截器里从请求头取出 token用 JWT 工具类解析如果过期或非法就直接返回 401不再进入 controller。在 controller 方法里可以用RequestAttribute(userId)获取当前登录用户的 ID非常方便。我在实际操作中的体会是善用拦截器一个非常大的好处是“我的订单”这种接口不需要前端传来 userId后端直接从 token 里就能解析出来安全性也更好。如果你的源码里是通过前端传 userId 来查询订单建议改造成从 token 获取这也是答辩时一个值得聊的改进点。3. 前端 Vue 页面结构与前后端对接3.1 Vue 项目结构与页面划分前端项目的标准结构是 Vue CLI 或 Vite 创建出来的核心目录是 src里面的 src/views 存放页面组件src/router 管理路由src/api 封装接口请求src/utils 放工具封装。旅游网站系统的前端页面两者视角的布局差异比较明显但结构上是大致清晰明确的面向游客的部分首页 Home轮播图、推荐景点、最新公告景点列表 ScenicList按城市或关键词筛选景点详情 ScenicDetail图片、介绍、预订按钮线路列表 LineList / 线路详情 LineDetail登录页 Login、注册页 Register个人中心 UserCenter我的订单、我的收藏、修改资料面向管理员的部分后台布局 AdminLayout侧边栏 顶栏景点管理 AdminScenic订单管理 AdminOrder用户管理 AdminUser公告管理 AdminNotice登录 AdminLogin这些页面之间通过 Vue Router 联系路由需要区分是否需要登录才能访问。比如个人中心页面需要添加路由守卫未登录跳转到登录页。路由配置时有一个很实用的分组思路基础路由home、scenic和需要鉴权的路由user、order分开配置再用beforeEach做全局守卫。这个设计思路写进论文“前端设计”章节会显得你对前端整体逻辑有把控。3.2 Axios 封装与接口调用前端页面需要调用后端接口但每个页面都写一段 axios 请求代码会非常冗余。标准做法是封装一个统一的 request 工具类。以 Vue 2 项目为例通常会在 src/utils/request.js 里做以下事情import axios from axios import { Message } from element-ui import router from /router const service axios.create({ baseURL: /api, // 统一接口前缀 timeout: 10000 }) service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] token } return config }) service.interceptors.response.use( response { const res response.data if (res.code ! 200) { Message.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res }, error { Message.error(error.message || 网络错误) return Promise.reject(error) } ) export default service这样封装之后页面里调用接口就变成了import request from /utils/request export function getScenicList(params) { return request({ url: /scenic/list, method: get, params }) }有个细节值得注意baseURL 用的是/api这需要前端 vite 或 webpack 配置代理转发把/api开头的请求转发到后端 8080 端口。开发环境这样做的好处是页面请求不会产生跨域问题而且将来部署到服务器上只需要把/api的代理规则层反代到后端地址即可。3.3 前端交互细节与体验优化前端除了能跑通还要注意几个交互细节这些细节看似不起眼但在答辩演示页面时最能体现工作量。第一个是加载状态。景点列表和订单列表是异步请求数据没返回之前页面是空白的体验很差。实际项目里一般会在表格和卡片区域增加 loading 状态数据返回后再隐藏这需要在前端页面里增加数据加载标记loading字段请求发出之前置为 true请求结束后置为 false。第二个是空数据提示。旅游网站里景点筛选结果可能为空个人中心里新用户没有订单这些场景都要有对应的空状态占位图。如果页面直接显示一片空白演示时就很尴尬。第三个是登录状态在前端也要有“守卫”。路由守卫这个思路上面已经提到过它跟后端的 JWT 拦截器配合前后端双重校验登录状态前端拦截未登录的跳转后端拦截没有 token 的接口请求。这就是论文里常讲的“前后端分离的权限控制”实现方式。4. 从源码到运行完整实操流程4.1 环境准备把项目源码跑起来之前需要先确认本机环境缺少任何一个都会导致启动失败。这套项目需要以下基础环境JDK 1.8 或更高版本推荐 JDK 1.8 或 JDK 11Maven 3.6 以上用于后端依赖管理MySQL 5.7 或 8.0本地安装或者使用集成环境Node.js 14 或 16用于前端项目运行开发工具后端推荐 IntelliJ IDEA前端可以用 IDEA 的 Vue 插件或 Visual Studio Code如果你的电脑是全新的建议先装 JDK 和 Maven然后打开系统命令行验证一下版本java -version mvn -version node -v npm -v这四个命令都能正常输出版本号说明环境基础没问题。很多人一上来就卡在这里比如java 不是内部或外部命令本质是环境变量没配置好需要把 JDK 的 bin 目录加到系统 PATH 中。数据库方面最简单的方案是安装一个集成环境比如 phpStudy 或宝塔面板里的 MySQL也可以直接官方安装 MySQL。建议装 5.7兼容性最稳8.0 在驱动配置上稍微注意一下就行。4.2 数据库导入与配置数据库初始化是整个流程的第一道关卡。打开数据库管理工具Navicat、SQLyog 或者命令行新建一个数据库数据库名一般跟项目里的配置对应通常叫 travel 之类的创建时选择 utf8mb4 字符集。然后导入项目里提供的 SQL 脚本。在 Navicat 里直接右键运行 SQL 文件或者通过命令导入mysql -uroot -p travel travel.sql导入之后打开表列表确认一下关键表是否都创建成功。如果 SQL 脚本里本身包含建库语句你就不用提前建库了直接导入整个脚本即可。接下来进入后端项目找到 src/main/resources/application.yml 文件修改数据库连接信息server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/travel?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai username: root password: 123456URL 中这个serverTimezoneAsia/Shanghai很关键MySQL 8.0 不指定时会报时区错误。然后确认驱动配置和项目里 Maven 依赖的 MySQL 版本是否一致驱动类名com.mysql.cj.jdbc.Driver对应 MySQL 8.0com.mysql.jdbc.Driver对应 MySQL 5.7 及以下。另外还需要检查文件上传路径。如果项目里有图片上传功能application.yml 中一般会自定义一个上传目录配置例如file: upload-path: D:/upload/如果目录不存在启动时可能不会报错但上传图片时就会出问题。建议提前把目录建好或者在配置里改成相对路径。4.3 后端启动步骤后端启动分三种常见方式按个人习惯选择即可。第一种是在 IDEA 里打开项目。因为是通过 Maven 构建的IDEA 会自动加载依赖这个过程可能要下载大量 jar 包第一次会比较慢。如果 IDEA 提示找不到依赖可以在项目的 pom.xml 上右键选择 Maven - Reload Project强制刷新依赖。如果依然报红检查 Maven 的本地仓库位置和网络必要时改成国内镜像。第二种是命令行启动。在项目根目录执行mvn spring-boot:run第三种是打包后启动这种方式更适合部署流程mvn clean package -DskipTests java -jar target/travel-0.0.1-SNAPSHOT.jar启动成功后控制台会出现类似 Spring Boot 的 bannerMac 上会看到 “Started Application in X.XX seconds” 的日志。这时候打开浏览器访问http://localhost:8080如果接口路径带 /api 前缀可以试一下http://localhost:8080/api/scenic/list能返回 JSON 数据说明后端没问题。4.4 前端启动与前后端联调后端启动成功之后接着启动前端。进入前端项目目录执行npm installnpm install 是前端最容易卡住的一个环节如果下载速度非常慢或者直接报错可以先配置淘宝镜像npm config set registry https://registry.npmmirror.com然后再执行 npm install。依赖安装完成后先检查前端项目的接口地址配置。Vue CLI 项目里一般在 vue.config.js 中配置代理Vite 项目在 vite.config.js 中配置。这里以 vue.config.js 为例module.exports { devServer: { port: 3000, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }端口可以自选一般前端用 3000 或 8081避免跟后端 8080 冲突。配置代理之后启动前端npm run serve浏览器访问http://localhost:3000能看到首页就算大功告成。这时候可以注册一个账号登录后试着访问个人中心和下单页面把完整流程走一遍。如果能看到后端返回的数据说明前后端联调成功。注意如果前端页面能打开但接口返回 404 或 500优先检查后端的控制台日志和后端地址是否匹配。如果接口返回 401说明登录过期或请求头没有携带正确的 token。5. 常见问题与排查技巧实录5.1 数据库连接类问题这一类问题占比最高而且报错信息五花八门。最常见的是启动后端时报Access denied for user rootlocalhost这个不用怀疑就是 application.yml 里的数据库账号密码填错了改为你自己数据库实际账号密码即可。还有一种情况是报Communications link failure虽然密码没问题但可能是数据库服务没有启动或者端口不是默认的 3306。查一下 MySQL 是否真正在运行端口是否被占用。如果你用的 MySQL 8.0但驱动还是旧版会报Unable to load authentication plugin caching_sha2_password。解决办法有两个更新 MySQL 驱动依赖到 8.0.x或者把数据库用户的密码插件改成 mysql_native_password。5.2 端口占用问题后端启动时报Port 8080 was already in use说明 8080 端口已经被占用。解决方式有两种找到占用进程关掉或修改后端配置里的端口号。macOS 和 Windows 查进程的方式不同Windows 下在 cmd 执行netstat -ano | findstr 8080然后杀掉对应 PID。改端口号的话记得前端代理配置里的 target 后端地址也要同步改不然前端请求会打到错误端口上。5.3 前端跨域与请求异常页面能打开但接口请求报跨域错误最常见的原因是代理配置没生效。改完 vue.config.js 或 vite.config.js 之后要重新启动 npm run serve 才会生效很多人忘了这一步以为配置有问题。如果后端设置了单独的路由前缀比如统一加了/api而前端请求路径没有这个前缀时会直接导致 404反之前端加了但后端没加会遇到无法匹配的问题。入手角度上可以先从前端发起请求路径、后端 RequestMapping 路径确认它们能对应上再考虑代理是否命中规则。5.4 依赖下载失败与版本冲突后端 Maven 依赖报错优先检查本地仓库 settings.xml 是否配置了阿里云镜像。很多 IDEA 内置的 Maven 使用默认中央仓库国内下载速度非常慢甚至直接超时。在 Maven 的 conf/settings.xml 中找到 mirrors 节点加入阿里云镜像地址可以显著改善。前端的依赖版本冲突相对棘手npm 升级大版本可能导致依赖包不兼容。实际项目中我遇到过 Node 18 环境运行老项目报错的情况解决办法是安装nvmNode Version Manager切换回 Node 14 或 16 再跑。5.5 上传功能与图片显示问题景点图片上传后访问不到大概率是配置的磁盘路径不对或者上传时保存的是绝对路径前端无法直接通过 URL 访问。稳妥方案是在后端增加一个 WebMvcConfigurer把磁盘路径映射为虚拟路径例如把配置里的上传目录映射成/files/**这样前端请求/files/xxx.jpg就能访问到真实图片。如果图片能访问但还是不显示检查图片文件权限和后端返回的路径字段值是否符合前端预期。5.6 毕业论文的写作要点很多人以为项目跑通就万事大吉但毕业论文才是决定能否顺利通过的关键。论文结构一般分成六到七个章节绪论、需求分析、系统设计、系统实现、系统测试、总结与展望。写论文的时候最重要的一点是“让论文里的图和代码能对上号”。比如系统设计章节画了 E-R 图那数据库设计表就要跟 E-R 图一致系统实现章节写了接口逻辑截图就要显示真实运行结果。答辩评委很多都是从这个角度挑问题的“你论文里说有这个功能那请你演示一下”——如果系统里没有这个问题就会很难看。另一个常见问题是论文查重不需要用什么非常规手段就是务实去写自己项目的设计方案和代码实现数据库表结构设计、接口设计、测试用例这些都是自己项目的实际内容跟别人重复的概率天然不高。风险高的往往是绪论里的“背景与意义”这种公共段落这里的表达尽量精简重写时也别急着从网上抄模板。6. 项目扩展与答辩演示建议如果你的毕设只剩基础功能而你又想在答辩中拉开差距可以考虑在现有系统上做几个低成本的扩展方向。第一个方向是数据可视化。旅游网站天然适合做数据统计在后台增加一个数据看板通过 ECharts 展示订单量趋势、热门景点 TOP10、用户增长数。实现上只需要在订单表和景点表上做几个 SQL 聚合查询前端引入一个 ECharts 组件工作量和答辩效果非常可观。第二个方向是增加评价和互动维度。比如用户在订单完成后可以发表评论管理员审核后展示到景点详情页又比如增加攻略分享功能让用户发布游记内容。这类功能不需要大的架构调整只是复用了现有的表关系和文件上传能力。第三个方向是引入缓存和搜索优化。把景点列表首页的数据缓存到 Redis减少数据库压力这是一个非常有说服力的系统优化点。如果技术准备时间不足可以退一步考虑使用简单的关键词搜索替换 SQL 语句里的 LIKE 模糊搜索。答辩的时候演示顺序也值得注意。很多同学上来就先演示登录注册这是常规但有点浪费时间的顺序。好的演示顺序是先展示未登录状态可以浏览的页面比如首页、景点列表、景点详情然后登录后展示下单流程最后切到管理员后台展示增删改查操作。这样整个演示把系统从简单到复杂逐步带出来也符合系统设计的业务逻辑。我自己的实操经验是答辩之前一定要自己在真实环境里完整走一遍流程从用户注册、下单、后台确认订单、修改景点信息到最终的数据展示环节中途不要暂停去改配置。因为经常出现的情况是演示时 Spring Boot 突然启动不起来了或者前端 token 过期需要重新登录这些如果提前演练过一遍都能提前规避。从更大的视角看这套旅游网站项目已经覆盖了一个现代 Web 项目从数据库建模到前后端交互、权限控制、部署运行的关键链路。把这套链路真正吃透远比堆几个看起来很炫的功能更有价值因为面试官和评委看的都是你对这条链路有没有自己的理解。自己在本地多跑几遍、多改几行代码、多试几种方案哪怕只是把登录模块从简单的 session 改造成 JWT、后端加了一个 Redis 缓存这种改进经历也足够你在毕业答辩甚至后续找工作时聊上几句。
返回列表