news 2026/10/23 12:18:35

SSM+Vue红色旅游网站毕设开发全流程:从环境搭建到答辩攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SSM+Vue红色旅游网站毕设开发全流程:从环境搭建到答辩攻略

1. 先说结论:这个题目到底要做什么

如果你正打算把“基于 SSM + Vue 的漯河市红色旅游网站”作为 2026 届毕业设计,我先把话说透:这个题目不是让你去做一个新闻门户,也不是一个简单静态页面集合。它本质上是一个旅游信息管理系统 + 内容展示门户 + 在线互动平台的三合一项目,技术栈刚好覆盖了市面上最常见的 Java Web 后端和 Vue 前端,所以每年都是计算机专业毕设选题里的稳定选手。

很多同学拿到题目第一反应是“红色旅游网站就是放几个景区介绍页面”,这个理解不能说错,但远远不够。一个能过审、能答辩、能写出八千字论文的项目,至少要包含前台门户展示、后台数据管理、用户登录注册、景点路线推荐、评论收藏互动这几大块。换句话说,前台给游客看,后台给管理员用,中间再用接口把它们对接起来,这才是一个完整的“网站 + 管理平台”结构。

这个题目对三类人特别合适:一是 Java 基础一般、想把 Spring 家族知识完整串一遍的同学;二是前端只会写 HTML/JavaScript,想借毕设系统学 Vue 的同学;三是已经工作、需要快速产出一个能演示的成品项目的同学。它的上限不高,但下限很稳,只要架构不乱、功能闭环,拿个中等偏上的毕设成绩问题不大。

所谓“论文 + 程序”,指的是最后交付物里既要有可运行的系统,又要有按学校模板写出来的毕业设计论文。论文不是软件的说明书,而是从选题背景、需求分析、系统设计、功能实现到测试结论文的全部过程记录。所以不建议把论文放到最后一个月再写,最好边开发边截图、边记录,最后把材料拼装成文,工作量会比想象中少一半。

我在下文会按照“题目拆解 → 技术选型 → 后端搭建 → 前端实现 → 问题排查 → 论文答辩”的顺序,把你需要知道的细节全部展开。里面的配置方法、版本搭配和踩坑记录,都是我实际调试过的,可以直接拿来做项目时对照。

1.1 题目拆解:不是“做一个网站”这么简单

所有毕设题目都能拆成两个维度:技术维和业务维。技术维就是 SSM + Vue 这套组合,业务维就是“红色旅游”这个主题。

先看技术维。SSM 是 Spring + SpringMVC + MyBatis 三个框架的缩写。Spring 管对象生命周期和依赖注入,SpringMVC 管请求路由和参数绑定,MyBatis 管数据库访问。前端 Vue 负责渲染页面、绑定数据和调用后端接口。整个系统的请求链路是:浏览器里的 Vue 页面 → Ajax 请求 → SpringMVC Controller → Service 业务层 → MyBatis Mapper → MySQL 数据库。这个链路写进论文的系统设计里,就是一整章架构图。

再看业务维。红色旅游的核心不是“红色”两个字,而是“旅游”。你需要先想清楚一个游客来到这个网站会做什么:浏览景区列表、查看景区详情、看旅游攻略、查推荐线路、发表评论、收藏景区、在线预订门票或酒店。然后管理员要做什么:管理景区信息、管理线路、管理订单、管理用户、管理评论、发布公告、上传图片轮播。这些需求点组合到一起,才构成完整的功能矩阵。

把这个矩阵拆开,你可以有明显的“前台游客用”和“后台管理员用”两套界面。前台界面设计追求漂亮、直观,后台界面追求表格化、操作高效。很多同学做毕设只把后台做出来,前台做得很简陋,答辩时老师一问“游客体验怎么体现”,就容易会卡住。所以前台和后台必须成对出现,至少每个核心实体都配一套前台展示页面和一套后台管理页面。

1.2 前台与后台的功能边界

我建议把功能模块列成一个表格,既方便填进论文“功能需求分析”部分,也方便后续分工开发。一份标准的红色旅游网站功能表长这样:

角色功能模块具体功能点
游客(未登录)门户首页轮播图、热门景区推荐、路线推荐、公告通知
游客景区浏览景区列表、按分类筛选、搜索、景区详情、图片预览
注册用户用户中心登录注册、修改资料、我的收藏、我的评论、我的订单
注册用户互动操作收藏景区、发表评论、回复评论、预订申请
管理员内容管理景区分类管理、景区信息增删改查、图片上传
管理员业务管理订单管理、评论审核、公告管理、用户管理
管理员数据统计简单统计页面:景点访问量、用户量、订单量

从这张表能看出,业务核心实体有:景区、景区分类、推荐线路、订单、评论、收藏、公告、用户。后面数据库设计时,基本就是围绕这些实体建表。功能边界清晰之后,你在论文里画的用例图也会非常好画,一个游客用例,一个管理员用例,各拉出五六条分支线,整张图就很饱满。

2. 技术选型背后的逻辑

技术选型这部分,很多同学直接抄网上模板,不思考为什么,答辩被问到就容易露馅。我简单把每一层选择的逻辑讲透,你理解之后就算换题目、换框架也能举一反三。

2.1 SSM 只是 Spring 家族的老套餐

先说一个事实:现在企业里新项目基本都用 Spring Boot,很少有人再从零配置 SSM。但毕设选 SSM 并不意味着落伍,反而有一个好处:SSM 把 Spring 的显式配置过程全部暴露在面前,你可以在 applicationContext.xml 里看到 Bean 怎么声明、事务怎么开启、SqlSessionFactory 怎么创建。如果你懂 SSM,再看 Spring Boot 的自动装配,本质上是把 XML 配置换成了注解和自动配置类,原理没变,只是封装程度不同。

所以我的建议是:如果学校不强制框架版本,后端可以继续用 SSM,但代码风格尽量向 Spring Boot 靠拢。Controller 层用注解声明、Service 层用注解管理事务、Mapper 层用 MyBatis 注解或 XML 映射,避免写一堆古老的 XML Bean 定义。这样一来,你既满足了题目的 SSM 要求,又没有把代码写得太脱离时代。

技术栈建议:JDK 1.8 + Maven 3.6 + MySQL 5.7 + Tomcat 8.5,这是 SSM 最稳的一套组合。JDK 8 对很多老库兼容性最好,MySQL 5.7 在课程设计环境中最常见,Tomcat 8.5 支持 Servlet 3.1,跑 SpringMVC 没有任何压力。如果你的电脑已经装了更高版本,比如 MySQL 8,问题也不大,只要把驱动版本换成 mysql-connector-java 8.x,并把连接 URL 加上 useSSL=false 和 serverTimezone=Asia/Shanghai 即可。

2.2 Vue 端为什么选 Vue Router + Element UI

前端部分,Vue 生态里有两条路线:Vue 2 + Element UI 和 Vue 3 + Element Plus。对毕设来说,我更推荐Vue 2 + Element UI,不是因为 Vue 3 不好,而是因为 Vue 2 的教程、现成代码、问题排查资料最多,Element UI 的表格、表单、分页组件非常成熟,几乎就是给后台管理页面量身定做的。

Vue Router 负责前端路由。游客访问 /scenic 看到景区列表,访问 /scenic/detail/1 看到景区详情,管理员访问 /admin/scenic 看到管理页面,这些都是路由映射。路由不是简单“页面跳转”,它还要配合路由守卫做登录检查。比如后台管理页面必须在 localStorage 里能拿到管理员 token,否则强制跳回登录页。这个机制用 Vue Router 的 beforeEach 函数实现,代码量不大,但在论文里是“系统安全设计”的重要材料。

Axios 负责和后端通信。我习惯在项目里建一个单独目录封装请求,比如 request.js,里面设置 baseURL、请求拦截器、响应拦截器。请求拦截器统一往 header 里加 token,响应拦截器统一处理 401 状态码,这样每个页面里的 API 调用都干净很多,不会出现同一个 token 处理逻辑写了三十遍的情况。

2.3 数据库表怎么设计

数据库是毕设项目的核心,很多同学开发到一半发现功能加不进去,原因往往是表结构设计缺字段或者表间关系没理顺。红色旅游网站我的建议是建八张核心表,再加两张辅助表:

表名主要字段作用
t_userid, username, password, nickname, phone, avatar, create_time前台注册用户
t_adminid, username, password, real_name后台管理员
t_categoryid, name, sort景区分类,比如“旧址纪念馆”“红色村镇”“烈士陵园”
t_scenicid, category_id, name, cover, images, address, intro, content, visits景区主体信息,content 存富文本详情
t_lineid, title, days, price, cover, content, scenic_ids推荐线路,scenic_ids 存景点 id 组合
t_commentid, user_id, scenic_id, content, create_time, status评论,status 控制是否显示
t_collectid, user_id, scenic_id, create_time收藏,user_id + scenic_id 做唯一约束
t_orderid, order_no, user_id, line_id, contact_name, contact_phone, status, create_time线路预订订单
t_noticeid, title, content, create_time公告
t_bannerid, image, url, sort首页轮播图

这里面有两个设计细节值得注意。一是景点图片不要单独建表,直接在 scenic 表里放一个主图 cover 字段,另外用 images 字段存逗号分隔的副图地址,简单实用,毕设完全够用。二是评论和收藏表都要加 user_id 和 scenic_id 联合唯一约束,防止用户重复收藏、重复评论的边界问题。这两点写进论文“数据库设计说明”里,老师会觉得你考虑得挺周全。

3. 实操:从零搭一套可运行的 SSM 后端

接下来进入正题,这部分我会按实际开发顺序来讲。后端建议在 IntelliJ IDEA 里建 Maven 工程,下面给出可以直接抄的配置和目录结构。

3.1 环境版本搭配(推荐组合)

先把版本锁死,减少环境问题。我的推荐组合如下:

组件版本备选版本
JDK1.811 也行,但必须改部分依赖
Maven3.6.33.8.x
MySQL5.78.0,需换驱动
Tomcat8.57.0 不推荐,Servlet 版本太低
Spring5.3.x4.3.x 老项目常用
MyBatis3.5.x3.4.x
Vue2.6.x2.7.x
Element UI2.15.x无
Node14 或 1618+ 会碰到 OpenSSL 问题,后面章节讲

如果你的电脑上 Node 已经是 18 或者 20,可以先装 Vue CLI 5,然后用 Vue 2.7 和 Element UI,问题会少很多。Vue CLI 5 底层用的是 webpack 5,对高版本 Node 更友好。但注意 Vue CLI 5 默认拉取的模板已经是 Vue 3,创建项目时你要手动选择 Vue 2 预设,或者直接用命令 vue create -p 创建,别被版本搞混。

3.2 Maven 依赖与目录结构

在 pom.xml 里,核心依赖有这些:spring-webmvc、spring-jdbc、mybatis、mybatis-spring、mysql-connector-java、druid 连接池、jackson-databind、javax.servlet-api、commons-fileupload、lombok。我用一个缩略版本展示:

<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.20</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.20</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.10</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.11</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.3</version> </dependency> </dependencies>

目录结构建议这样划分:

src/main/java ├── com.lh.redtour │ ├── controller # 控制器层 │ ├── service # 业务接口 │ ├── service.impl # 业务实现 │ ├── mapper # MyBatis Mapper 接口 │ ├── entity # 实体类 │ ├── common # 统一结果、公共常量、工具类 │ ├── interceptor # 登录拦截器 │ └── config # Spring 配置类 src/main/resources ├── mapper # MyBatis XML 映射文件 ├── spring-mvc.xml ├── spring-mybatis.xml └── jdbc.properties src/main/webapp ├── upload # 上传图片保存目录 └── WEB-INF/web.xml

实体类建议用 Lombok 的 @Data 注解,减少 getter/setter 的代码量。Controller 返回统一结果对象,比如 Result 类,里面有 code、msg、data 三个字段,前端拿到后统一判断 code 是否为 200。这个设计很小,但能让前后端联调时少吵很多架。

3.3 Spring/MyBatis 配置

传统 SSM 有两种配置方式:全注解和 XML。为了论文里能写“框架配置文件”,也为了你自己能看懂底层原理,我建议 spring-mvc.xml 和 spring-mybatis.xml 保留,但内容尽量精简。

spring-mybatis.xml 的核心是这样:

<context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:mapper/*.xml"/> <property name="typeAliasesPackage" value="com.lh.redtour.entity"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.lh.redtour.mapper"/> </bean>

spring-mvc.xml 里除了开启注解驱动和组件扫描,还有两件关键事:文件上传解析器和静态资源放行。文件上传是为了后台传景点图片,静态资源放行是为了让上传目录里的图片能被 URL 直接访问,否则你图片存进去了但浏览器访问总是 404。

<mvc:annotation-driven/> <context:component-scan base-package="com.lh.redtour.controller"/> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760"/> <property name="defaultEncoding" value="UTF-8"/> </bean> <mvc:resources mapping="/upload/**" location="/upload/"/>

web.xml 里要配置 DispatcherServlet 和 CharacterEncodingFilter。CharacterEncodingFilter 必须放在所有过滤器的最前面,而且 forceEncoding 要设成 true,否则你从表单提交的中文会乱码。这个乱码问题几乎每位做 SSM 的同学都会踩一次,提前写上能省一天时间。

3.4 跨域、登录与文件上传

前端 Vue 开发服务器默认跑在 8080 端口,后端 Tomcat 跑在 8081,两个端口不同,浏览器就会拒绝 Ajax 请求,这叫跨域。解决跨域最简单的方式是后端加一个 CorsFilter。

@Component public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); response.setHeader("Access-Control-Allow-Credentials", "true"); chain.doFilter(req, res); } }

登录鉴权,毕设里最常用的是 JWT 或简单 token。我给一个折中方案:用户登录成功后,后端生成一个 UUID 作为 token,把这个 token 存到数据库的 token 字段里,失效时间用 create_time + 2 小时判断。前端每次请求把 token 放在 Authorization header 里,后端用拦截器统一校验。这个方案不依赖 Redis,也没有 JWT 的过期密钥问题,代码量少,原理还好讲。

文件上传这块,后端接收 MultipartFile,保存到本地 upload 目录,返回拼接好的访问路径。保存文件名一定不要用用户原始文件名,容易乱码也容易重名,我习惯用 UUID + 原始后缀。

String originalFilename = file.getOriginalFilename(); String ext = originalFilename.substring(originalFilename.lastIndexOf(".")); String filename = UUID.randomUUID().toString().replace("-", "") + ext; String path = uploadDir + File.separator + filename; file.transferTo(new File(path)); return "http://localhost:8081/upload/" + filename;

4. 前端 Vue 站点搭建与核心交互

后端接口就绪后,前端的工作是把页面视觉呈现出来,并和后端接口对接。下面讲几个核心环节的实现思路。

4.1 用 Vue CLI 创建项目和安装依赖

假设你已经装好 Node 和 npm,全局安装 Vue CLI:

npm install -g @vue/cli vue create red-tour-web

创建时选择 Vue 2 预设,风格选标准模式。进入项目目录后再安装 Element UI、Axios 和 Vue Router。如果你在创建项目时已经选了 Vue Router,就不用重复装,选择时留意一下。

npm install element-ui npm install axios npm install vue-router@3

注意 Vue 2 对应 Vue Router 3,Vue 3 对应 Vue Router 4。如果直接 npm install vue-router,有可能会给你装上版本 4,在 Vue 2 项目里跑起来全是报错。装依赖时养成习惯,先查版本,别一把梭。

main.js 里全局注册 Element UI:

import Vue from 'vue' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' import App from './App.vue' import router from './router' Vue.use(ElementUI) Vue.config.productionTip = false new Vue({ router, render: h => h(App) }).$mount('#app')

4.2 路由守卫和登录状态管理

前台游客页面和管理后台要分开。我的做法是在 router 里给后台页面统一加一个 meta 字段,标记 needAdmin: true,然后在全局路由守卫里判断。

router.beforeEach((to, from, next) => { const token = localStorage.getItem('adminToken') if (to.meta.needAdmin && !token) { next('/admin/login') } else { next() } })

游客端登录状态我用 localStorage 存 token 和用户昵称,不需要 Vuex。用户量不大、状态共享不复杂,Vuex 反而增加概念负担。如果你后面想扩展购物车、多页面共享用户信息,再上 Vuex 也不迟。

axios 封装的逻辑是所有接口通用的:

import axios from 'axios' const request = axios.create({ baseURL: 'http://localhost:8081/api', timeout: 10000 }) request.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = token } return config }) request.interceptors.response.use(res => { const data = res.data if (data.code === 401) { localStorage.removeItem('token') this.$router.push('/login') } return data }) export default request

4.3 景点详情页、收藏、评论联调

景点详情页是一个互动最密集的页面,包含景点信息、图片展示、收藏按钮、评论列表和发表评论输入框。我建议把详情页拆成几个子组件,用 props 把数据传下去,中间如果涉及业务状态变化,再用 $emit 向上抛事件。这就是 Vue 最基本的组件通信方式,用心做好这一页,组件的知识就够答辩用了。

收藏功能是一个典型“按钮状态切换”场景。页面加载时,调用 isCollected 接口查询当前用户是否收藏过;用户点击收藏,调用 addCollect 接口;再点一下取消,调用 cancelCollect 接口。前端用一个布尔变量控制按钮文字,接口返回成功后再翻转状态。不要做成点击后就前端自嗨改状态,那样刷新页面就会露出问题。

评论列表用 Element UI 的 el-comment 样式没有现成组件,通常用卡片列表自己写。要注意评论时间从后端返回的格式一般是 java.util.Date 的默认格式,直接展示很难看。后端要么转成字符串返回,要么前端用 dayjs 格式化。我建议后端在实体类里加一个格式化字段,比如 commentTimeStr,专门给前端展示用,别让前端去解析后端时间格式比较省事。

4.4 组件插槽复用和样式冲突排查

Vue 的插槽适合做公共组件。比如每个页面顶部都要展示一个 banner 区域,就可以封装一个 PageHeader 组件,中间内容用 slot 插入,标题、描述、操作按钮都在使用时传入。这样整个项目里前台页面的头部风格统一,代码量也少,论文里还可以写“通过插槽机制实现公共组件复用”。

样式冲突是 Vue 单文件组件里最常见的坑之一。因为 Vue 默认会给组件里的 style 标签加 scoped 属性,但 Element UI 的内部样式不受 scoped 影响,有时候你想覆盖某个 Element 组件的样式会覆盖不掉。解决办法是使用深度选择器 /deep/,比如:

/deep/ .el-carousel__indicators { bottom: 20px; }

在 Vue 2 里 /deep/ 是可靠写法,Vue 3 里换成了 :deep()。如果你发现自己写的样式不生效,先检查是不是 scoped 和子组件样式冲突,再检查是否是选择器权重不够。大部分样式问题都能靠这两个排查思路解决。

5. 毕设开发中最容易踩的坑

这部分是正文里我最想让你认真看的。以下坑位我周围不下五个人踩过,有些甚至能耽误整整两天。我按出现频率排好序,配合解决方案列出来。

5.1 前端白屏、跨域和 404

前端白屏最常见的三个原因:路由配置错误、接口跨域、打包后资源路径不对。开发阶段如果白屏,先打开浏览器 F12 看 Console 面板,是 JS 报错还是网络请求报错,信息会直接告诉你方向。路由配置里如果用了 history 模式,部署到 Tomcat 后刷新二级页面会 404,因为 Tomcat 不知道要去 index.html,这时需要后端加一个 fallback。开发阶段建议直接用 hash 模式,地址栏会有 # 号,但省很多麻烦。

如果你用 Vite 或 Vue CLI 的 dev server 代理后端口能对上,用代理代替后端 CorsFilter 也行,做法是在 vue.config.js 里配置 devServer.proxy。但如果后端将来要部署到 Tomcat 供老师演示,我还是建议后端把 CORS 写好,这样前端打包后放到任意端口都能访问,不用改代理。

5.2 Vue 依赖和 Node 版本冲突

我见过最多的错误长这样:error:0308010C:digital envelope routines::unsupported。这是 Node 17 以上版本和 webpack 4 的 OpenSSL 算法冲突。Vue CLI 4 系列底层是 webpack 4,如果你 Node 版本太高,就会报这个错。两个解决办法:一是装 Node 16 LTS 版本,最稳;二是在命令行执行:

set NODE_OPTIONS=--openssl-legacy-provider

Windows 上注意 set 而不是 export。如果你是 Mac 或 Linux,用 export。这个变量设置好再执行 npm run serve,一般就能跑起来。如果你用的是 Vite,那不存在这个问题,但 Vite 官方对 Node 版本也有要求,低版本同样跑不起来。

还有一个高频报错是Failed to load tsconfig '@vue/tsconfig/tsconfig.web.json'。这个大多出现在 Vue 3 + TypeScript 项目中,因为本地没有安装 @vue/tsconfig 这个依赖。毕设项目如果用 JavaScript 开发根本不会触发,但如果你为了加印象分强行上 TypeScript,就要先把这个依赖装好,并在 tsconfig 的 extends 里写对路径。我个人对毕设的建议是:除非你 TypeScript 非常熟练,否则别给自己加戏,JS 足够完成这个项目。

5.3 MyBatis 映射和 JSON 序列化问题

MyBatis 里最容易出错的点有两个:XML 里的 resultMap 字段没对上,以及多表查询返回 null。前端明明请求成功,但数据对象里某个字段是 null,十有八九是数据库字段命名是下划线风格,比如 create_time,而实体类字段是驼峰风格 createTime,MyBatis 默认不会自动转换。解决办法是在 mybatis 配置里开启驼峰映射:

<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>

另一个问题是 LocalDateTime 序列化格式。MySQL 5.7 的 datetime 映射到 Java 的 LocalDateTime 后,Jackson 默认序列化格式是一长串数组,前端拿到根本没法看。解决办法是在 spring-mvc.xml 里配置日期格式:

@Bean public Jackson2ObjectMapperBuilderCustomizer customizer(){ return builder -> builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss"); }

5.4 图片上传路径 404 和中文乱码

图片上传成功后显示 404,十有八九是访问路径没有映射到实际磁盘目录。Tomcat 默认只读取 webapp 目录下的文件,如果你把图片保存到项目的某个自定义目录,必须像前文那样配置<mvc:resources>把 URL 映射过去。如果是 IDEA 开发工程,项目目录在内存里,图片写到 target 目录,重启后又消失,那就要把上传根目录设置为绝对路径。

中文乱码问题,除了 web.xml 的 CharacterEncodingFilter,还要检查 JSP 或 HTML 页面编码、数据库连接 URL 字符集、MySQL 表字段字符集。我们一般统一用 UTF-8。MySQL 建表语句写成 DEFAULT CHARSET=utf8mb4,这个能存 emoji,也兼容中文。连接 URL 附加 characterEncoding=utf8 参数,三处同时改好,乱码基本绝迹。

5.5 常见错误速查表

错误现象可能原因解决方案
前端请求 404接口路径不匹配,或后端没配 CORS检查 @RequestMapping 路径,检查 CORS 过滤器
前端请求 401token 过期或未携带检查拦截器逻辑,检查 axios 请求头
数据库连接失败密码错误/驱动缺失/MySQL 8 驱动版本不匹配检查 jdbc.properties,更新依赖
页面中文乱码编码过滤器缺失或页面编码不一致统一 UTF-8,增加 CharacterEncodingFilter
图片上传成功但加载不出来静态资源映射缺失配置 mvc:resources 映射到上传目录
刷新页面 404前端 history 路由模式改用 hash 模式或后端配置 fallback
npm run serve 报 OpenSSLNode 版本过高设置 NODE_OPTIONS=--openssl-legacy-provider
Element UI 样式加载失败main.js 未引入样式文件检查是否引入 theme-chalk/index.css

这张表可以直接搬到论文的“系统测试与问题处理”章节,再配上几张真实报错截图,会显得测试过程很扎实。

6. 论文写作、源码交付与答辩准备

程序做完只完成了一半,另一半是论文和答辩。这两个环节的工程量不亚于写代码,很多人最后挂在这上面,不是因为代码不行,而是因为论文像流水账、答辩说话颠三倒四。

6.1 论文结构与写作顺序

一篇 SSM 毕设论文的标准章节结构大致如下:

章节内容建议页数
第一章 绪论选题背景、研究意义、国内外现状、主要工作4-6 页
第二章 相关技术介绍SSM、Vue、MySQL、开发工具4-5 页
第三章 需求分析可行性分析、业务流程、功能需求、用例图6-8 页
第四章 系统设计总体架构、功能模块设计、数据库表设计、E-R 图8-10 页
第五章 系统实现前台功能展示+核心代码说明、后台管理功能10-12 页
第六章 系统测试测试环境、测试用例表、测试结果5-6 页
第七章 总结与展望完成工作、不足、后续改进2-3 页

写作顺序不要按章节从前往后,建议:先写第二章技术介绍和第三章需求分析,这两部分不用等代码写完,可以参考网上同类资料整理。然后边写代码边截图,填充第五章系统实现。等系统功能稳定,再回头补第四章数据库设计和第六章测试。最后写第一章绪论和第七章总结。这样论文能写的素材才不会丢。

页面数量控制在 40 页左右是正常范围,50 页以上除非你的项目特别丰富,否则显得注水。每张图必须有图注,每张表必须有表头,这是论文最基本的规范。

6.2 给论文配图的方法

系统实现章节里,前台页面截图、后台管理截图、数据库表截图、代码截图这四类缺一不可。截图要清晰,不要带任务栏或者浏览器的收藏夹。推荐使用 PicPick 或 Snipaste,滚动截屏和矩形截图都很方便。

代码截图不要截大段,只截核心方法,比如 Controller 里的登录接口、MyBatis 的 resultMap、Vue 的路由守卫。截图上加上红框或高亮,标注你接下来要解释的关键点。每段代码不要超过十五行,超过就显得像在凑字数,而且答辩时老师扫一眼就看不出重点。

数据库设计部分,至少要有 E-R 图和数据库表结构说明表。E-R 图用 Visio 或 draw.io 画,实体间的关系线标注 1 对多、多对多,画完导出为图片插入论文。表结构表是每个字段一行,列出字段名、类型、是否主键、备注说明。这个工作量不大,但特别容易出彩。

6.3 答辩演示脚本

答辩现场时间通常五到十分钟,系统演示要提前准备一条“演示路径”,不要临时乱点。我的习惯是这样:

第一步,从登录页开始,演示管理员登录,说明登录的 token 鉴权机制。第二步,进入后台,新增一个景区分类,再添加一个景区,上传图片,展示后台 CRUD 功能。第三步,回到前台,演示注册用户登录,搜索刚才添加的景区,查看详情,发表评论,收藏操作。第四步,回到后台,看到用户新增的评论和收藏记录,对应表数据变化。第五步,如果时间允许,再演示订单流程。

整套演示脚本的逻辑是“管理员发布内容 → 用户消费内容 → 后台收到反馈”,把前后台串成一条完整的数据流。老师看到的是你能把一个业务从零到一跑通,而不是零散的功能点拼接。

答辩老师常问的几个问题,提前准备好答案:

  • SSM 的三个框架分别负责什么?
  • 你怎么解决跨域的?
  • 登录 token 存在哪里?过期怎么处理?
  • 为什么评论需要审核,审核状态存在哪个字段?
  • 数据库表之间有哪些关联关系?
  • 如果用户量增大,系统瓶颈在哪?

每个问题都能说两到三句话,控制在半分钟以内,不要长篇大论。尤其最后那个“瓶颈在哪”的问题,主动说“当前系统是单机部署,数据量大之后需要引入 Redis 缓存或者数据库分表”,体现你考虑过扩展性。

6.4 代码交付和打包上线的注意事项

学校要求的交付物一般是源码压缩包 + 论文 Word/PDF,有的还要运行环境说明。源代码发给别人之前,注意三件事:删掉数据库里的测试垃圾数据,给数据库提供建表 SQL 和初始化数据 SQL,写一份 README 说明环境版本和启动步骤。

如果你没有部署到真实服务器的需求,用 IDEA 打完 war 包放到本机 Tomcat 的 webapps 目录即可。前端打包:

npm run build

生成 dist 目录,把里面的静态文件放到 Tomcat 的 webapps/ROOT 下,后端接口和前端页面同一个端口访问。如果不想让前端直接调用后端跨域,打包后把接口请求 baseURL 改成相对路径 /api,再在 Tomcat 里配置反向代理或者后端 Controller 路径统一加 /api 前缀。毕设场景一般不加代理,本地演示够了。

有一点我要专门提醒:源码压缩包里别带上 node_modules 目录和 target 目录,一个项目几个 G,老师打开都费劲。正确做法是压缩前删掉 node_modules 和 target,README 里写清楚 npm install 和 mvn clean package 的步骤。对方拿到后几分钟就能恢复,这才叫“可复现交付”。

7. 我做完这个项目后的体感

我个人实际做过 SSM + Vue 的旅游类毕设项目,最大的体感是这个题目的“完成门槛”不高,但“做好门槛”比想象中高。很多人做毕设最大的问题是不知道做到什么程度算完成,于是反复在功能上做加法,结果代码越写越乱、论文越写越水。我自己后来总结了一条经验:先确定一条核心业务流程,把这条流程从头到尾跑通,再向周围填充附属功能。对红色旅游网站来说,核心业务流程就是游客浏览景区、注册登录、收藏评论、后台维护内容,这条流程通了,项目就立住了。

另外一个小建议是:每天开发完,随手截两张图,记录一个遇到的问题和解决方案。等到写论文时,这些素材就是最宝贵的内容,不用再去翻聊天记录或者凭空编测试过程。如果你现在刚拿到题目,建议先花两天时间把数据库表和前端路由搭好,再开始填充业务逻辑,骨架对了,后面就是重复劳动。

最后分享一个实用技巧:如果你打算把项目源码传到 GitHub 或者发给别人,记得把数据库信息的 jdbc.properties 和上传目录配置写成外部可改的形式,同时在 README 里写好三句话:用什么版本环境、怎么导数据库、怎么启动前端和后端。这种细节不会给你加多少分,但它会在毕业设计和未来工作面试里,给人留下“这个同学做事很规范”的印象。这个习惯值得从毕设开始养成。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 14:00:19

FAT32数据恢复实战:用WinHex手动还原误删与格式化文件

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 14:00:19

晶圆盒FOUP ID识别实战:一体式读码设备的光学、算法与调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 14:00:17

飞凌嵌入式系统安装Java环境

文章目录1.安装JDK2.mysql注意事项3.redis注意事项4.nginx注意事项5.开机自启1.安装JDK 使用tar -zxvf解压不支持↓ 用zip来解压↓ which gzip gzip -d jdk-15.0.2_linux-aarch64_bin.tar.gz tar -xvf jdk-15.0.2_linux-aarch64_bin.tar2.mysql注意事项 mysql安装也一样&…

作者头像 李华
网站建设 2026/10/20 15:59:46

ponytail插件实战:用收束思维打造高效工作流

1. 从“ponytail”这个热词说起&#xff1a;它到底是什么第一次看到“ponytail”被当成一个技能、一个插件来讨论的时候&#xff0c;我其实愣了一下。马尾辫&#xff1f;这不是发型吗&#xff1f;但稍微在圈子里泡几天就明白了&#xff0c;现在大家嘴里的 ponytail&#xff0c;…

作者头像 李华
网站建设 2026/10/21 15:52:43

Copilot CLI 安装及命令:把 endpoint 改到 TaoToken 的完整配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华