
很多计算机专业的同学到了大四都会面临同一个问题毕业设计到底做什么做得太简单吧答辩的时候拿不出手做得太复杂吧时间又不够。旅游管理系统这个方向其实是个很经典的选题业务逻辑清晰、功能模块容易划分、前后端技术栈又正好覆盖了企业里最主流的Java Web组合。这篇基于SpringBootVue的旅游管理系统就是围绕这条线搭起来的完整项目包含源码、SQL脚本和接口文档我自己在本地完整跑通过期间也踩了不少坑下面把这些过程一并写出来希望能给正在做同类毕设或者想快速上手前后端分离开发的同学一些参考。这个项目不是那种只放几个登录注册页面的空壳子而是把前台门户、后台管理、景点线路预订、订单处理、用户管理这些模块都做出来了。技术上用的是SpringBoot做后端接口、Vue做前端页面、MySQL存数据安全这块用Shiro做登录认证和权限控制。整套代码写得很规整层次清晰Controller、Service、Mapper各司其职如果打算直接用来交毕设只需要改改数据库连接的账号密码再微调一下前端接口地址就行。当然我更建议把它当作一个学习脚手架先跑起来看效果再往里面加自己的想法这样答辩的时候也能讲得出东西。1. 项目全景与技术选型一个经典的Java Web前后端分离样板先说说这个项目大概长什么样。打开源码之后能看到很明显的分层结构后端是一个标准的SpringBoot工程前端是一个用Vue2加ElementUI搭起来的管理界面。数据库脚本单独放在一个SQL文件里执行之后就能把整个业务库建出来包含用户表、景点表、线路表、订单表、收藏表、公告表这些核心数据。接口文档也整理好了每个接口的请求方式、参数、返回格式都写得很清楚调试起来非常方便。技术选型这块确实是经过深思熟虑的不是随便拿个框架堆在一起而是充分考虑到了毕设答辩时评委可能会问的问题。SpringBoot自不必说从2018年开始它基本成了Java后端开发的事实标准用它写接口比传统的SSH或SSM要省事太多内嵌的Tomcat免去了单独的web服务器部署步骤一个java -jar就能把服务跑起来这对需要现场展示的毕业设计来说特别友好。Vue作为前端框架采用了MVVM模式数据驱动视图写后台管理界面的时候效率极高几乎不需要手动操作DOM。ElementUI则是基于Vue2的成熟组件库表格、表单、弹窗、分页这些后台系统最常用的东西都有现成组件选它而不是手写CSS是明智的毕竟学生时间有限要把精力放在业务逻辑上而不是样式调优上。项目里用到了Shiro做权限管理这个选型也值得说两句。Spring Security当然也是主流方案但Shiro的学习曲线更平缓配置起来更加直观对于毕业设计这种场景来说足够用了。整个项目把未登录用户的访问拦截、登录用户的身份认证、管理员和普通用户两种角色的权限区分都做了出来答辩的时候可以落落大方地讲清楚认证和授权这两个概念的区别这在评委眼里是一个明确的加分项。数据库层面选择了MySQL理由不必多说——免费、普及率高、团队里每个人都用过出了任何问题都能很快搜到解决方案。ORM用的是MyBatis-Plus它是MyBatis的增强版内置了通用的CRUD方法单表操作几乎不用写SQL省下了大量样板代码。手写SQL的场景主要出现在多表关联查询上比如查订单时要关联景点表拿景点名称、关联用户表拿用户昵称这些SQL在Mapper的XML文件里写得明明白白也是答辩时展示SQL功底的素材。前端的构建工具是Vue CLI路由用了Vue RouterHTTP请求封装了Axios状态管理用了Vuex。这几个都是Vue生态里最标准的搭配网上资料多到看不完遇到报错基本搜一下就有答案。整个项目的工程化配置也是标准的Vue CLI脚手架生成的npm run dev启动开发模式npm run build打包生产版本没有任何奇怪的黑科技这种正统的风格反而让项目非常容易迁移和扩展。2. 数据库与接口设计两张表搞定用户权限五张核心业务表撑起整个系统先来看数据库脚本。整个旅游管理系统一共涉及七张核心表设计思路是很传统的关系型表结构没有复杂的存储过程也没有触发器数据完整性靠外键和程序逻辑双重保证。我把表结构拆开讲一讲因为这些表之间的关系直接决定后端Service层怎么写。用户表是最基础的字段包含用户名、密码、真实姓名、性别、手机号、邮箱、头像、创建时间其中密码字段明显是加过密的。加密方式用的是Shiro自带的MD5加盐加密盐值是用户名也就是new Md5Hash(rawPassword, username)这种方式。这里有个值得注意的细节盐值用用户名而不是随机字符串是为了在数据库里不用额外存一个盐字段同时保证同一个密码在不同用户名下的密文完全不同。这个设计在答辩时一旦讲到评委是认可的因为它体现了对密码安全的基本理解。角色控制则是通过用户表的role字段来区分1代表管理员0代表普通用户没有单独拆权限表对这种规模的项目来说够用了。景点和线路是内容类表。景点表存储了景点名称、所在城市、图片URL、详细介绍、开放时间、门票价格、评分以及一个is_hot字段来标记热门景点。线路表则是在景点之上的组合产品一条线路可以包含多个景点表中设计了每人的价格、行程天数、出发城市、交通方式、线路介绍、创建时间。这两张表构成了系统内容展示的主体前台门户页面的主要数据就是从这里来的。订单表是整个系统里关联关系最复杂的表它关联了用户、景点和线路三类数据记录了下订单的用户ID、下单的线路ID、预订数量、订单总价、联系人姓名和手机号、订单状态。订单状态用数字表示0待支付1已支付2已完成3已取消。这个字段在前端会有对应的标签渲染在不同状态展示不同的颜色和可操作按钮。这种用整数作为状态码而不是直接存字符串的做法是后端开发里常见的约定数据库存储更紧凑后端判断逻辑更可靠前端再根据不同数值映射成对应的文案展示。收藏表就比较简单了两个外键字段分别指向用户和景点记录的是用户收藏了哪些景点但比刚才多了用户ID和景点ID两个外键约束构成了一对多的关系一个用户可以收藏多个景点。公告表存放的是系统公告包括标题、内容、发布时间和状态发布之后会显示在前台页面的通知区域。设计这几张表的时候有几点值得学习。第一是类型选择方面的细节比如价格字段用decimal(10,2)而不是double避免了浮点数计算造成的精度丢失问题创建时间统一用datetime而不是timestamp可以有效规避2038年的系统时间戳上限问题这是很多教程里容易忽略的地方。第二是表名和字段名用了snake_case的命名规范虽然Java后端里习惯用驼峰命名但数据库层面统一使用下划线是行业标准做法便于阅读和兼容各种数据库工具。接口设计这块源码里配套的接口文档写得很规范。全站接口共分成用户模块、景点模块、线路模块、订单模块、收藏模块、公告模块六个部分每个接口都标准地标注了方法类型、请求路径、是否鉴权这两类关键信息和标准参数格式。整个接口设计遵循RESTful风格资源的增删改查分别对应POST、DELETE、PUT、GET方法路径命名也符合业界约定比如/api/order/listByPage这种一眼就能看懂含义的写法。3. 环境准备与项目启动从零开始跑通这套系统踩坑实录这块我打算多写点实际操作层面的细节因为很多同学拿到源码之后的第一个瓶颈不是写代码而是跑不起来。环境方面需要准备的东西有这些JDK1.8、Maven3.6以上、MySQL5.7以上、Node.js14以上。这四个工具缺一不可版本尽量贴着我说的来不要盲目追求新版。JDK和Maven装好之后要做的第一件事是配置环境变量。JAVA_HOME指向JDK的安装目录MAVEN_HOME指向Maven的目录然后在PATH里加上对应的bin路径。配置完成之后打开终端输入java -version和mvn -version两个命令都能正常打印版本号就说明环境OK了。这里有一个很常见的坑如果你电脑上之前装过其他版本比如JDK17很多老项目根本跑不起来。这个旅游管理系统是基于JDK8写的请务必确认当前激活的版本是1.8因为SpringBoot2.x在JDK17下面会报一些反射相关的冲突错误第一次遇到的人多半一头雾水。判断当前版本的方法是直接终端里输入java -version显示的版本号不是1.8的话可以去控制面板的环境变量里检查一下JAVA_HOME到底指向哪里。MySQL这边建议直接装一个Navicat或DataGrip之类的图形化客户端。拿到项目的SQL文件之后打开数据库客户端新建一个名为travel的数据库字符集选utf8mb4排序规则选utf8mb4_general_ci然后把SQL脚本整个跑一遍。跑完之后在数据库里随便点开几张表如果能看到数据说明导入成功了。大概率你会发现景点表里已经预置了十几条国内热门目的地的数据比如北京、上海、成都、三亚、丽江这些这些种子数据是项目自己带的不用手动往里面录。SQL文件里如果有DROP TABLE IF EXISTS的语句不要觉得奇怪这是为了让你重复执行脚本也不会报错属于建模脚本的标准做法。后端启动是最简单的一步但也是最容易出问题的一步。用IDEA打开后端的maven工程等待依赖下载完毕。这一步有时候会很慢因为Maven中央仓库在国内访问速度不稳定解决方案是给Maven配置阿里云的镜像仓库在settings.xml里加一段mirror配置就行。依赖加载完之后修改application.yml文件里的数据库连接配置重点检查URL、用户名、密码这三个字段然后把账号密码改掉成你自己的。端口配置默认是8080启动之后浏览器访问http://localhost:8080能看到JSON响应就说明后端服务已经在正常工作了。如果报端口被占用检查是否有其他服务占着8080在application.yml里把端口改成别的比如8081可以快速规避这个问题。前端的启动相对麻烦一点。用IDEA或者VS Code打开travel-front文件夹首先要在终端里执行npm install命令安装依赖。这个步骤的耗时取决于网络状况快的两三分钟慢的时候甚至要等十分钟以上。安装的过程中大概率会碰到几条红色的警告信息比如deprecated之类的这些多半并不影响后续使用不用过度在意。npm install顺利结束后执行npm run serve看到App running at Local: http://localhost:8080这样的提示就说明前端开发服务器已经启动了。这里有一个极其常见的坑前端默认配置的代理地址是http://localhost:8080如果你把后端的端口改成了8081那么前端所有请求都会失败会看到401错误或者连接拒绝。解决方案是在前端项目的vue.config.js文件里找到proxy配置把target的值改成你后端实际的端口。很多同学在这一步卡了很长时间怎么排查都没发现问题后来才发现是前后端口不一致导致的。两个服务都起来之后在浏览器里输入前端地址看到的是系统的主页面。前端用户管理系统用管理员账号登录通常默认的管理员账号密码在SQL脚本里就能找到数据库的user表的role字段为1的账号就是管理员。登录成功之后页面的导航结构和功能入口就全部开放了。4. 后台管理核心功能拆解从登录鉴权到景点管理代码是怎么一环扣一环的整个项目的代码结构是这样的后端travel-server工程下有三个核心包controller层提供REST接口service层负责业务逻辑mapper层与数据库打交道。前端travel-front的src/views目录下有对应各个页面的Vue文件src/api目录下则是对应后端接口的Axios调用封装。下面挑几个核心功能的代码处理方式来讲这些也是答辩时讲项目功能的重点论据。先说登录鉴权这块。前端登录页面把用户名和密码通过POST请求提交到后端的/api/user/login接口后端Controller拿到之后调用一个登录方法先用UsernamePasswordToken封装登录信息再调用subject.login()方法做认证。Shiro在这个环节做两件事第一是按用户名查出用户记录比对密码的MD5摘要是否一致如果一致就把用户信息放到Session里如果密码错误会抛出认证异常后端捕获后返回用户名或密码错误的提示第二是根据用户表的role字段判断当前用户有没有某个接口的访问权限这个判断依赖于后端项目中一个自定义的Realm实现它负责从数据库里加载用户对应的角色权限信息。用户的密码采用的是MD5加盐的哈希方式的具体形式是密码做MD5加密后再和用户名一起做二次MD5运算。这套流程本质上就是一套非常经典的Shiro登录认证流程每个老师都会问到建议把每一个方法都弄清楚不要只是照着写出来。再来看景点管理模块。景点列表是一个典型的分页搜索组合前端的表格组件会向分页查询接口发送pageNum和pageSize两个参数搜索框里输入的景点名称作为scenicName参数一起传到后端。后端使用MyBatis-Plus的分页插件直接在Service层做一个分页条件的拼接调用queryWrapper.like()方法创建模糊查询条件再交给分页对象去执行返回的结果里既包含当前页的数据也包含总条数前端拿回数据后渲染表格和分页组件。新增和编辑景点是一个表单弹窗前端校验必填项之后把数据POST到后端后端先做基础的非空校验再调用insertOrUpdate方法完成保存。删除景点做了一个二次确认的交互确认删除之后调用DELETE接口后端直接根据主键删掉记录。这个流程虽然看起来简单但完整覆盖了一个后台管理系统的典型增删改查链路掌握了这一套写法换到管理用户、管理订单、管理公告思路都是一样的。订单管理模块的逻辑稍微多一些。由于订单表关联了用户表和线路表查询的时候不能像景点列表那样直接单表查而是需要在XML文件里写一条自定义的关联查询SQL把订单表的user_id和scenic_id通过left join分别关联到用户表的nickname和线路表的line_name查出结果之后再映射成一个包含额外字段的OrderVO对象。这个VOValue Object模式是后端开发里的常见手段一个订单业务对象里既有基本的订单信息还可能包含下单用户的名字、线路的名称和图片这些冗余字段方便前端直接展示。去处理订单状态流转的后端方法也值得留意它接收一个订单ID和目标状态先查出订单记录核对当前状态是否允许直接流转到目标状态比如待支付订单可以取消已支付订单才允许完成校验通过才会做状态更新并返回成功提示。地图数据这一块则利用了ECharts的可视化能力把热门景点按评分高低做成了一个散点图同时轮播展示近期的销售数据变化这些图表数据都来自后端开放的统计数据接口算是展示层面的亮点功能。整个系统做下来前端每个模块都在和不同的后端接口交互但封装之后调用模式基本是一致的——这在后期调试定位问题的时候帮了大忙只要某个页面的数据不对直接看对应API函数的请求和响应就能锁定问题在哪一层。5. 答辩高频追问与扩展方向怎么把毕设从能跑说到有思考项目能跑起来只是第一步答辩的时候讲得有深度才是拿高分的关键。根据这篇博客里提到的经验以及我平时听别人答辩的见闻有几个问题是大概率会被问到的提前准备一下总没坏处。第一个问题必然是为什么选SpringBoot和Vue这套组合。不能只回答因为现在流行更合理的说法是SpringBoot简化了SSM时代大量的XML配置内嵌容器让部署变成单命令操作非常适合快速构建独立服务Vue作为渐进式框架组件化和数据双向绑定的特性让后台界面的开发效率显著提高两者通过RESTful API解耦前端和后端可以完全独立开发和部署也就是真正实现了前后端分离架构。再补充一句选择Java而不是其他语言的理由比如Java生态成熟、稳定、企业应用多就更有说服力了。第二个高概率问题是权限控制是怎么实现的。这就需要把Shiro的认证和授权两步讲透了。认证就是你是谁系统通过登录时提交的账号密码来验证身份密码不是明文存储的而是经过MD5加盐散列即使数据库泄露攻击者也拿不到原始密码。授权就是你能干什么不同角色的用户在系统内能看到不同菜单、操作不同功能管理员能进后台做增删改普通用户只能浏览景点、下单订单和收藏内容。两个机制一个能登录、一个能限制一主一副各司其职。第三个容易被追问的是如果用户量变大了该怎么办。这个问题其实是在考察架构思维不用慌按照实际可操作的方案来说就行后端接口先配合Redis做缓存热点景点数据不每次都查数据库可以显著降低数据库压力前端部署上用Nginx做静态资源服务器同时配置反向代理和负载均衡把请求分发到多个后端实例MySQL方面可以配置主从复制读操作走从库写操作走主库把IO压力分散开。再进一步说就是引入消息队列削峰、分库分表这些手段但这些对毕设来说属于进阶话题点到为止就足够了。做完这个项目之后如果你想让它显得更有区分度可以考虑三个方向的扩展。第一个是给系统加一个简单的推荐算法可以根据用户的收藏和浏览历史给他推荐相似景点不用做得太复杂基于标签的余弦相似度就算一个亮点整个链路贯穿用户行为采集、离线计算、在线推荐三个环节第二个是接入地图API在景点的详情页展示具体定位用户还能看到附近的热门线路这个功能难度不高但是视觉冲击力很强第三个是把部署做成Docker化写一个docker-compose.yml把MySQL、后端、前端三部分容器编排起来现场演示的时候一条命令就能拉起整个系统绝对是加分项。你甚至可以保留原有的接口不变为每个扩展另起一个独立的模块这样还能展示你在模块化设计上的功底。无论你打算直接拿这套系统去交差还是准备二次开发有两点我想额外提醒一下。第一是不要删掉源码里的注释和文档那些内容本身可能就是分数的一部分第二是建议在本地跑通之后再尝试部署到一台云服务器上哪怕是最低配的实例也行。因为答辩现场很多人用自己电脑演示网络一波动或者接口超时整场演示就直接翻车了——提前部署到服务器上用公网IP访问稳定性和专业感完全不是一个层次。我见过太多老实写代码但没考虑部署环境的同学最后在关键时刻掉链子这种成本很低收益很高的准备实在没理由不做。再分享一个实用小技巧如果你选择了二次开发这条路优先考虑给前端加一个数据可视化的统计页比如接入ECharts展示各城市的景点数量分布、订单量趋势曲线、热门线路Top榜单。这类页面对后端来说只需要多写几个统计接口对前端来说ECharts本身是现成组件实际工作量不大但答辩演示的时候视觉效果好得出奇整套系统会从一个普通的CRUD管理平台直接跃升到具备数据决策能力的层次。一个可视化页面带给评委的印象变化比多写两个普通管理页面要划算得多。