前后端分离的网站毕业设计:新手入门实战与避坑指南
摘要:许多计算机专业学生在毕业设计中首次接触前后端分离架构,常因技术选型混乱、接口联调困难或部署流程不熟导致项目延期。本文从零开始,详解如何基于 Vue + Spring Boot 构建一个结构清晰、可维护的前后端分离项目,涵盖 RESTful API 设计、跨域处理、JWT 认证及 Nginx 部署等核心环节。读者将掌握标准化开发流程,避免常见配置陷阱,高效完成可展示的毕业作品。
1. 前后端协作的四大痛点
第一次做毕设,最怕“前后端说不到一块去”。我踩过的坑,总结下来就这四点:
接口约定不清
后端把字段名写成user_name,前端却按userName解析,一跑就 500。本地联调失败
前端npm run dev起在localhost:5173,后端SpringBoot跑在localhost:8080,浏览器一条CORS错误直接劝退。环境差异
本机Windows路径大小写不敏感,到了云服务器Linux静态资源 404,毕业答辩现场翻车。部署流程不熟
把dist文件夹整个丢进Tomcat的webapps,结果刷新页面 404,老师一句“路由管理呢?”直接问懵。
2. 技术栈选型:为什么 Vue + Spring Boot 最适合毕设
时间紧、任务重,别给自己加戏。我对比过三套主流方案:
| 技术栈 | 学习曲线 | 生态成熟度 | 毕设适配度 |
|---|---|---|---|
| React + Express | 中高 | 社区大 | 需要配很多中间件,容易超纲 |
| Vue + Express | 低 | 社区中 | 轻量,但 Node 部署对新手陌生 |
| Vue + Spring Boot | 低 | 生态全 | 一键热部署、教材案例多,导师也熟 |
结论:Vue 单文件组件写法直观,Spring Boot 零配置开箱即用,俩都“中文文档友好”,最适合 3~4 个月周期的毕设。
3. 核心实现细节拆解
3.1 RESTful 接口规范
先写“契约”再写代码,我习惯用一张表把资源、动词、状态码一次性对齐:
| 资源 | 动词 | 路径 | 返回码 | 说明 |
|---|---|---|---|---|
| 用户 | POST | /api/users | 201 | 注册 |
| 用户 | GET | /api/users/{id} | 200 | 查询 |
| 登录 | POST | /api/auth/login | 200 + JWT | 登录 |
把这张表丢进README.md,前后端就能并行开发,谁也别等谁。
3.2 Axios 封装:让请求“傻瓜化”
新建src/utils/request.js:
import axios from 'axios' import { ElMessage } from 'element-plus' // 1. 创建实例 const service = axios.create({ baseURL: import.meta.env.VITE_API_BASE, // 本地/生产环境一键切换 timeout: 5000 }) // 2. 请求拦截 Token service.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) config.headers.Authorization = `Bearer ${token}` return config }) // 3. 统一异常提示 service.interceptors.response.use( res => res.data, err => { ElMessage({ type: 'error', message: err.response?.data?.message || '服务异常' }) return Promise.reject(err) } ) export default service页面里直接import request from '@/utils/request'即可,代码干净,错误提示统一。
3.3 CORS 配置:本地开发“零代理”也能跑通
很多教程让你配vue.config.js代理,其实后端一行代码就能解决:
@Configuration public class CorsConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowCredentials(true); } }; } }前端无需代理,直接访问http://localhost:8080/api/**,联调速度翻倍。
3.4 JWT 无状态认证:毕业设计够用,还简单
登录成功后,后端下发JWT,前端存localStorage,之后每次请求带Authorization头即可。
后端工具类:
public class JwtUtil { private static final String KEY = "graduation_secret_2025"; private static final long EXPIRE = 86400000; // 1d public static String generate(String username) { return Jwts.builder() .setSubject(username) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + EXPIRE)) .signWith(SignatureAlgorithm.HS256, KEY) .compact(); } public static String getUsername(String token) { return Jwts.parser().setSigningKey(KEY).parseClaimsJws(token).getBody().getSubject(); } }过滤器里校验:
OncePerRequestFilter { protected void doFilterInternal(...) { String token = request.getHeader("Authorization"); if (token != null && token.startsWith("Bearer ")) { String username = JwtUtil.getUsername(token.substring(7)); SecurityContextHolder.getContext().setAuthentication(...); } chain.doFilter(request, response); } }4. 关键代码片段:Clean Code 示范
4.1 后端分页接口
@GetMapping("/api/articles") public PageVO<Article> list(@RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size) { Pageable p = PageRequest.of(page, size, Sort.by("id").descending()); Page<Article> data = articleRepo.findAll(p); return PageVO.of(data); // 统一封装总条数、列表 }4.2 前端列表调用
// views/Article.vue import request from '@/utils/request' const loadArticles = async () => { const { content, totalElements } = await request.get('/api/articles', { params: { page: currentPage.value - 1, size: 10 } }) tableData.value = content total.value = totalElements }5. 安全与性能:毕设也别留“后门”
XSS 防护
Vue 默认转义插值,千万别用v-html渲染用户输入;后端可用jsoup过滤富文本。Token 刷新
简单策略:Token 过期前 30 分钟访问任意接口,后端在Response Header中带回新 Token,前端无痛替换。本地开发性能
把Spring Boot的spring.devtools.restart.enabled打开,改完代码 3 秒热重启;Vite本身秒级刷新,双端热更新体验飞起。
6. 生产环境避坑指南
6.1 构建 & 上传
npm run build生成dist目录,仅 3~5 MB,丢到云服务器/var/www/html。
6.2 Nginx 一刀流配置
server { listen 80; server_name yourdomain.com; root /var/www/html; # 1. 静态资源缓存 location ~* \.(js|css|png)$ { expires 1y; add_header Cache-Control "public, immutable"; } # 2. 前端路由刷新 404 问题 location / { try_files $uri $uri/ /index.html; } # 3. API 反向代理 location /api/ { proxy_pass http://localhost:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }6.3 HTTPS 免费证书
用Certbot一行命令即可:
certbot --nginx -d yourdomain.com证书 90 天自动续期,答辩时浏览器地址栏一把“小锁”,老师印象分 +10。
7. 一张图总结流程
8. 动手下一步:把“接口契约”写进你的 README
看到这里,别急着关网页。打开编辑器,新建API.md,把资源、路径、字段、状态码一次性写清楚,再@你的搭档。前后端并行,不加班也能准时提测。
等你把项目跑通,再回头思考:如果团队扩大到 5 人,如何设计接口版本演进?如何用OpenAPI自动生成文档?毕设只是起点,真正的工程化思维,就从“写契约”开始。