前后端分离的 Spring Boot + Vue 项目,被卡在第一步的人远比你想象的多。很多人不是不会写代码,而是项目根本跑不起来:版本对不上、目录乱成一团、前端到后端的请求跨域、端口冲突,随便一个都能让人怀疑人生。这篇是系列(1),只讲新建项目这一件事。我会带你从后端初始化、前端创建、到两边服务在本地真正跑通,把“第一步”这个地基打牢。如果后面你很顺利,大概二十分钟能搞定;如果中间踩坑,这篇文章也会帮你把常见的坑都填平。
之所以要把“新建项目”单独拿出来讲一篇,原因是很多人后面部署出问题、联调出问题,往回追往往都是这一步留下的隐患:项目名乱取、依赖版本乱选、目录结构随手建、端口规划没概念。这些都是可以在一开始就避免的。所以这篇不是敷衍的“打开 IDE 点下一步”,而是把一个合格从业者在这一步真正会做的规划、选择和配置讲透。适合刚接触这套技术栈的新手,也适合以前照老教程搭过、但想理清版本和结构的老手。
这篇会先讲版本选型和目录规划,然后分别搭建后端和前端,最后把前后端在本地打通。等到下一篇我们再进入业务代码和数据库,再往后才是真正的部署上线。现在开始。
1. 开工之前:先把版本和目录规划好
新建项目这件事,最怕的就是“打开工具直接干”。工具默认给的版本、模板不一定适合你手头的情况,等你代码写了一半发现问题,再回头改版本基本等于重建项目。所以我习惯在任何代码落盘之前,先花五分钟把版本、目录、端口这三件事定死。
1.1 版本选型:不是越新越好,是越稳越好
先说后端。目前 Spring Boot 已经到 3.x,它跟 2.x 最大的区别是强制要求 JDK 17 及以上,很多老教程还在用 JDK 8 + Spring Boot 2.x 的组合。你要是照着老教程硬套,大概率会在依赖下载或者编译的时候出问题,然后在百度上搜一圈才发现是版本不兼容。
我选型的建议很简单:
| 工具 | 推荐版本 | 选型理由 |
|---|---|---|
| JDK | 17(LTS) | Spring Boot 3.x 的硬性要求,长期支持版,稳 |
| Spring Boot | 3.x 最新稳定版 | 官方推荐,安全更新和社区资料都齐全 |
| Maven | 3.6.3 及以上 | 支持 JDK 17 的编译,默认配置无需额外处理 |
| Node.js | 20 LTS | Vite 5 以上要求 18+,20 是长期支持版,生态兼容最好 |
| Vue | 3.x | 当前主流,组件语法和生态最成熟 |
| Vite | 5.x | Vue 官方推荐的构建工具,启动速度比旧版 Webpack 快太多 |
你机器上如果已经装了好几个 JDK 版本,那要注意 IDEA 或者 IDE 里要单独确认一下项目用的到底是哪个 JDK,这个后面编译的时候很容易踩坑。Node 版本管理推荐用 nvm,装错了随时切版本,比卸载重装省事太多。
1.2 目录结构规划:一个总目录,两个子项目
前后端分离的项目,最忌讳的是后端一个目录、前端一个目录,放得到处都是,过两个月你自己都找不着。我比较推荐在一个总项目目录下划分两个子目录,后面部署的时候也方便统一上传和打包。
比如你的项目叫某业务管理系统,那就建一个总目录business-system/,里面再建:
business-system/ ├── backend/ # Spring Boot 后端 ├── frontend/ # Vue 前端 └── docs/ # 接口文档、部署说明等这个结构的优点是路径清晰,后面打jar包、构建dist静态文件的时候,所有产物都在同一个大目录下,部署脚本也好写。我个人还会在docs里建一个deploy.md,专门记录服务器上的部署步骤,省得每次上线都靠脑子回忆。
1.3 开发工具和网络环境:先把坑填平
后端开发我建议直接用 IDEA,社区版就够用;前端开发用 VS Code 顺手一些。两者可以同时开,改前端代码和改后端代码互不干扰。
另外有一个很现实的问题:依赖下载速度。国内拉 Maven 和 npm 的依赖经常慢到怀疑人生,这不是项目的问题,是网络环境的问题。解决办法很简单,先配置国内镜像。
Maven 镜像在settings.xml里加一段:
<mirror> <id>aliyunmaven</id> <mirrorOf>*</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>npm 镜像在命令行执行:
npm config set registry https://registry.npmmirror.com这两步看起来不起眼,但能让你后面少等至少一半的下载时间。很多新手卡在“依赖一直下载不动”这个环节,其实不是电脑坏了,就是镜像没配。
2. 后端 Spring Boot 项目搭建:三分钟跑通第一个接口
规划做完了,下面开始真正动手。我先从后端开始,因为前端联调必须要有一个能响应请求的后端服务在跑,否则前端只能看一个空页面。
2.1 用 Spring Initializr 创建后端项目
打开浏览器访问 Spring Initializr,这个网站是 Spring 官方的项目生成器,省得自己在 IDE 里一步步点。需要填的几个关键项:
- Group 填你的包名倒序,比如
com.example,如果是公司项目就填公司域名倒序 - Artifact 填项目名,比如
backend,生成的项目名就是backend - Java 版本选 17
- Spring Boot 版本选当前 3.x 稳定版
依赖这一栏,这一篇建议只选三个:
- Spring Web:提供 REST 接口能力,必选
- Lombok:简化实体类的 getter/setter 代码,必选
- Validation:后面做参数校验要用,提前选上不亏
数据库相关的依赖(比如 MyBatis、JPA、MySQL Driver)这款先不加。原因是数据库驱动的依赖在启动时如果没有对应的配置,会直接报错;这一篇的目标是先把骨架跑通,数据库等下一篇讲业务的时候再加,这样每一篇的起点都是“可运行”的。
生成之后会下载一个 zip 包,解压到你刚才建好的backend目录,然后用 IDEA 打开。第一次打开 Maven 会自动下载依赖,这个过程不要中断,等右下角的进度条走完。
这里有一个新手最容易看懵的事情:IDEA 里怎么确认 Maven 用的是你本地的 settings.xml?看 IDEA 的Settings -> Build, Execution, Deployment -> Build Tools -> Maven,User settings file 那一栏要指向你的 Maven 配置文件,否则镜像配置不生效,下载依旧慢。
2.2 配置文件应用 yml 格式并规划端口
Spring Initializr 默认生成的是application.properties文件,我习惯把它改成application.yml,因为 YAML 的层级结构在配置多的时候更清晰。
在src/main/resources下新建application.yml,写入:
server: port: 8080 spring: application: name: backend3.x 的 Spring Boot 会把默认端口定在 8080,这没问题,但是你要记住了:后端 8080,前端 5173,这两个端口后面联调要用。
如果你的 8080 已经被占用了,java.net.BindException: Address already in use就会找上门,这时候两条路:一是杀掉占用 8080 的进程,二是在 yml 里改成别的端口。我建议统一用 8080,因为后面 Nginx 反代配置的时候会少一些端口映射的心智负担。
2.3 第一个 REST 接口与启动验证
后端项目刚生成是没有接口的,我们写一个最简单的接口来验证服务能跑通。在com.example.backend主包下新建一个controller包,然后在里面创建:
package com.example.backend.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api") public class HelloController { @GetMapping("/hello") public String hello() { return "Hello from Spring Boot"; } }不要小看这个/api前缀。我见过很多项目接口直接写/hello、/login,后面部署到 Nginx 的时候,前端请求要转发到后端,如果接口路径不带统一前缀,Nginx 的location规则会写得很绕。带/api前缀以后,所有前后端交互的请求都是/api/xxx,规则统一,代理配置省心很多。
然后启动项目:右键BackendApplication,选 Run。控制台看到类似这样的日志就说明后端跑通了:
Tomcat started on port(s): 8080 (http) with context path ''这时候打开浏览器访问http://localhost:8080/api/hello,应该能看到一段纯文本。
其实第一次搭后端的项目,我建议在验证接口之前先看一眼控制台有没有报错。最经典的一个报错就是 Lombok 相关的编译异常,这是因为 IDE 里没安装 Lombok 插件,或者编译器没有开启注解处理。新版 IDEA 基本是内置的,但如果你用的插件版比较旧,装一下 Lombok 插件,并且在Settings -> Compiler -> Annotation Processors里勾选Enable annotation processing,就稳了。
3. 前端 Vue 项目搭建:从脚手架到能调通后端
后端跑通了,接下来创建前端项目。这里我会用 Vite 而不是旧版的 Vue CLI,因为 Vite 启动快、配置简单,官方现在也推荐这条路。
3.1 用 create-vue 还是 create-vite?
Vue 官方提供的脚手架有两个入口:
npm create vue@latest,用于创建带官方推荐工程结构的 Vue 3 + Vite 项目,会问你需不需要 Router、Pinia、ESLint 等npm create vite@latest,是 Vite 官方的通用脚手架,选 Vue 模板后只给你最精简的空框架
我给的建议是直接用npm create vue@latest。原因很简单:后面写页面基本都会用到路由和状态管理,与其之后手动集成,不如一开始就选上。它在交互式问答里会问你要不要 TypeScript、Vue Router、Pinia,你按需选就行。
在business-system目录下执行:
npm create vue@latest frontend创建过程会问一系列问题,建议的选项是:TypeScript 可以先不选(这一篇为了减少心智负担,用 JS 就行);Vue Router 选 Yes,因为后面页面跳转几乎必用;Pinia 按需选,现在要是不用可以先 No;ESLint / Prettier 选 Yes,代码风格统一一下。
进入项目并启动:
cd frontend npm install npm run dev看到Local: http://localhost:5173/就说明前端也跑起来了。浏览器打开这个地址,你会看到 Vue 官方的欢迎页。
3.2 前端目录结构设计与基础依赖安装
脚手架生成的目录已经有一些基础结构,但还不够应付真实项目。我自己的习惯是在src下再规划出这么几个目录:
src/ ├── api/ # 所有接口请求封装 ├── assets/ # 静态资源(图片、样式) ├── components/ # 公共组件 ├── router/ # 路由配置 ├── stores/ # 全局状态管理(如果选了 Pinia) ├── views/ # 页面组件 └── utils/ # 工具函数这一步在手把手的新建项目阶段就能做好,不要等代码写多了再来返工。
然后安装 axios,这是每个前后端分离项目都绕不开的 HTTP 库:
npm install axios如果你想用现成的 UI 组件库,推荐 Element Plus 装一个:
npm install element-plus这套组合(Vue 3 + Vite + Element Plus)在业务管理系统里非常常见,接下来的整个系列都会基于这套技术栈展开。
3.3 Vite 代理配置:解决跨域,让 /api 直达后端
现在前端和后端都在跑,但如果你直接在浏览器里从http://localhost:5173请求http://localhost:8080/api/hello,会碰到跨域问题,浏览器会拦截响应,控制台报错。
解决这个的业内标准做法是:利用 Vite 开发服务器的代理功能,让浏览器认为请求发往的是同一台服务器,实际由 Vite 在服务端转发给后端。这样开发环境完全不需要后端开启 CORS。
在frontend/根目录下找到vite.config.js,改成这样:
import { fileURLToPath, URL } from 'node:url' import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } }, server: { port: 5173, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } })关键就是server.proxy这一段。它表示:所有以/api开头的请求,都会被 Vite 开发服务器转发到http://localhost:8080。
这里我多说一句changeOrigin的作用。有些后端服务会校验请求头里的 Host,不设置changeOrigin: true的话,后端看到的 Host 还是localhost:5173,有些严格的服务会拒绝;设为true后,代理转发时会改成目标地址的 Host。在本地开发环境里基本不会出问题,但加上这个配置总归是更稳妥的。
修改完配置文件,Vite 会自动重启,无需手动重启。这个特性很舒服。
4. 前后端联调与地基整理:把准备工作做到位
骨架都有了、代理也配好了,接下来最重要的就是“让两边真的能对话”。只要这一次对话成功了,整个开发环境的地基就稳了大半。
4.1 联调验证:看到一个字符串出现在页面上
先确认后端还在 8080 跑着,前端 dev server 还在 5173 跑着。然后打开前端项目里主要的页面组件,在onMounted里用 axios 请求后端的接口。
以脚手架生成项目为例,在src/views/下新建一个HomeView.vue,内容写成:
<template> <div> <h1>{{ msg }}</h1> </div> </template> <script setup> import { ref, onMounted } from 'vue' import axios from 'axios' const msg = ref('正在请求后端...') onMounted(async () => { const res = await axios.get('/api/hello') msg.value = res.data }) </script>然后把路由的默认指向改到HomeView,浏览器访问http://localhost:5173,页面应该从“正在请求后端...”变成Hello from Spring Boot。
这一步的意义怎么强调都不为过。它验证了四件事:
- 后端 Spring Boot 项目能正常运行
- 前端 Vue 项目能正常运行
- axios 请求发出去了
- Vite 代理把
/api请求正确转发给后端
四件事只要有一件不行,这里就过不去。联调不成功的话,优先打开浏览器的开发者工具看 Network 面板:如果请求状态是 404,看路径前缀是不是写错了;如果是 502,看代理目标地址的端口是不是和后端对不上;如果是 CORS 报错,说明代理配置没生效,检查 Vite 配置后重启。
4.2 统一响应结构:减少后面返工的第一件事
我在新建项目阶段就会把前后端的“接口约定”定下来,而不是等写了三五个接口再回头统一。推荐做一个统一的响应体,后端所有接口都返回这个结构:
package com.example.backend.common; import lombok.Data; @Data public class Result { private Integer code; private String message; private Object data; public static Result success(Object data) { Result result = new Result(); result.setCode(200); result.setMessage("success"); result.setData(data); return result; } public static Result error(String message) { Result result = new Result(); result.setCode(500); result.setMessage(message); return result; } }这样前端 axios 请求里就可以统一做拦截处理:先看code是不是 200,不是的话弹个提示。好处是接口越多,前后端沟通成本越低。前端也可以对应建一个src/utils/request.js,封装 axios 实例,统一处理响应码。
这个环节现在做只需要几分钟,等业务接口写多了再改,就是几十个接口的大工程。
4.3 本地常见问题速查表
我非常确定你新建项目的时候会碰到下面一些问题,先列出来,遇到直接对照着排查:
| 问题 | 可能原因 | 解决方法 |
|---|---|---|
后端启动报Address already in use | 8080 端口被占用 | 用netstat -ano找到占用进程杀掉,或改 yml 端口 |
前端npm install卡住 | npm 源访问慢 | 配置镜像后重装 |
| 前端启动报 Node 版本错误 | Node 版本低于 18 | 用 nvm 切换到 20 LTS |
页面请求/api/hello404 | 后端接口路径不对 | 确认后端 Controller 的 RequestMapping 和 GetMapping |
页面请求/api/helloCORS 报错 | Vite 代理没生效 | 检查 vite.config.js,改后重启 dev server |
| Maven 依赖下载报错 | 镜像未配置,或 Maven 版本过低 | 配置阿里云镜像,升级 Maven 到 3.6.3+ |
| 后端编译报 Lombok 相关错误 | IDE 注解处理未开启 | 安装 Lombok 插件,开启 Annotation Processing |
我自己这些年带过的项目里,最坑的一个问题不是技术,而是“两个项目同时开着,前端调用时才发现后端没启动”。这种情况浏览器报的是 ECONNREFUSED,容易让人误以为代码有问题。所以联调之前永远先确认:后端控制台有没有日志,后端页面能不能直接访问。先把这条养成本能反应,能省很多瞎排查的时间。
4.4 为下一步部署做的准备:提交一次干净的初始版本
新建项目完成、联调通过之后,我建议你做一次完整的 git 提交,把这个“可运行的初始状态”固定下来。为什么?因为接下来写业务代码、接数据库的过程中,你可能随时改出问题,有了这个干净的基准确认,心里就不慌,随时能退回来。
提交的时候注意一个点:在项目根目录建一个.gitignore文件,把node_modules/、target/、dist/这些目录全部排除掉。一开始不建的话,很容易把几十万个前端依赖打进仓库,后面每次提交都痛苦。
前后端分离的新建项目到这一步就完成了。地基是最无聊也最不能省的部分,我把这一篇的内容都踩实之后,下一篇就能放心地进入数据库设计和业务接口开发,而不必担心还在结构问题上绕圈。
我个人在实际项目里的一个习惯是:新建项目后不是马上写业务代码,而是花半天把基础结构完整跑通一遍,甚至把部署脚本的雏形都写出来。原因很简单,基础的每一点混乱,都会在后面的联调和部署阶段被放大。把这里做扎实,后面整个项目周期都会省心得多。