尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Spring Boot与Vue.js前后端分离项目实战:从零搭建任务管理应用

Spring Boot与Vue.js前后端分离项目实战:从零搭建任务管理应用 最近在完成一个教育内容创作周期后我重新将重心放回了技术研究与写作上。在这个过程中我深刻体会到无论是教育内容的体系化梳理还是技术研究的深度探索其底层方法论是相通的都需要清晰的逻辑、结构化的表达和可复现的路径。本文就将这种“研究写作”的心得结合一个具体的技术实战案例——基于Spring Boot与Vue.js的前后端分离项目搭建——进行拆解。无论你是想系统学习全栈开发还是希望提升自己的技术文档写作能力这篇文章都将提供一个从零到一的完整闭环。1. 背景与核心概念为什么选择这个技术栈在开始动手之前理解“为什么”比知道“怎么做”更重要。本次实战选择Spring Boot Vue.js的组合是当前企业级应用开发中非常主流和高效的技术选型。Spring Boot是一个基于Spring框架的“开箱即用”式开发框架。它极大地简化了Spring应用的初始搭建和开发过程通过自动配置和起步依赖开发者可以快速构建独立运行、生产级别的应用。它解决了传统Spring项目配置繁琐、依赖管理复杂的问题让我们能更专注于业务逻辑。Vue.js是一套用于构建用户界面的渐进式JavaScript框架。所谓“渐进式”意味着你可以从一个轻量级的核心库开始根据需求逐步引入路由、状态管理等其他库。Vue以其简洁的API、灵活的组件化和优秀的性能在前端领域占据了重要地位。将两者结合形成前后端分离架构是现代Web开发的标准实践。后端Spring Boot专注于提供清晰、稳定的RESTful API处理业务逻辑、数据持久化和安全性前端Vue.js则负责数据展示、用户交互和界面渲染。这种架构解耦了前后端允许团队并行开发也使得后端API可以被多种客户端Web、移动App等复用。2. 环境准备与版本说明一个可复现的环境是成功的第一步。请确保你的开发环境满足以下要求。本文示例基于当前撰写时的稳定版本如果你的项目环境不同请以官方文档为准但核心配置思路是通用的。2.1 后端开发环境操作系统: Windows 10/11, macOS, 或 Linux (如Ubuntu) 均可。Java开发工具包 (JDK): 版本 8、11 或 17 (推荐 LTS 版本 11 或 17)。本文使用 JDK 11。检查命令java -version构建工具: Apache Maven 3.6.3 或更高版本。检查命令mvn -v集成开发环境 (IDE): IntelliJ IDEA (社区版或旗舰版)、Spring Tools 4 for Eclipse 或 VS Code。本文演示使用 IntelliJ IDEA。数据库(可选用于后续扩展): MySQL 5.7 或 PostgreSQL。初期我们可以使用Spring Boot内置的H2内存数据库进行快速演示。2.2 前端开发环境Node.js: 版本 14.x 或 16.x 或更高。Node.js自带了包管理工具npm。检查命令node -v和npm -vVue CLI: Vue.js的官方脚手架工具用于快速创建项目。通过npm全局安装。安装命令npm install -g vue/cli检查命令vue --version2.3 项目结构预览在开始前我们先明确最终的项目目录结构这有助于理解前后端如何协作fullstack-demo/ # 项目根目录 ├── backend/ # Spring Boot后端项目 │ ├── src/ │ │ ├── main/ │ │ │ ├── java/com/example/demo/ │ │ │ │ ├── controller/ # REST API控制器 │ │ │ │ ├── service/ # 业务逻辑层 │ │ │ │ ├── repository/ # 数据访问层 (JPA) │ │ │ │ └── model/ # 数据实体类 │ │ │ └── resources/ │ │ │ ├── application.properties # 主配置文件 │ │ │ └── ... │ │ └── test/ │ └── pom.xml # Maven依赖管理文件 └── frontend/ # Vue.js前端项目 ├── public/ # 静态资源 ├── src/ │ ├── assets/ # 图片等资源 │ ├── components/ # Vue组件 │ ├── views/ # 页面视图 │ ├── router/ # 路由配置 │ ├── store/ # Vuex状态管理 (可选) │ ├── App.vue # 根组件 │ └── main.js # 入口文件 ├── package.json # npm依赖管理文件 └── vue.config.js # Vue项目配置文件3. 核心原理与配置拆解在搭建项目前理解几个关键配置点能让你在遇到问题时游刃有余。3.1 Spring Boot自动配置与起步依赖Spring Boot的核心魔法在于spring-boot-starter-*依赖。例如添加spring-boot-starter-web依赖就自动引入了Tomcat服务器、Spring MVC等开发Web应用所需的所有库。SpringBootApplication注解是一个组合注解它开启了组件扫描、自动配置和Spring Boot应用配置。application.properties(或application.yml) 文件是集中管理配置的地方如服务器端口、数据库连接等。3.2 Vue CLI工程化与单文件组件Vue CLI为我们搭建了现代化的前端开发流水线集成了Webpack、Babel、ESLint等工具。它支持单文件组件 (.vue文件)将一个组件的模板(template)、逻辑(script)和样式(style)封装在一个文件中极大提高了可维护性。3.3 前后端通信RESTful API与CORS前后端分离后通信通过HTTP协议进行。后端提供RESTful API前端使用axios等库发起AJAX请求。这里会遇到一个关键问题跨域资源共享 (CORS)。由于前端项目运行在http://localhost:8081后端运行在http://localhost:8080浏览器出于安全考虑会阻止这种跨域请求。解决方案是在后端进行CORS配置允许前端的源进行访问。4. 完整实战案例构建一个简单的任务管理应用我们将构建一个具有创建和查看任务功能的迷你应用覆盖从后端API到前端展示的全流程。4.1 创建Spring Boot后端项目使用Spring Initializr(https://start.spring.io) 或IDE内置的创建向导。选择Project: MavenLanguage: JavaSpring Boot: 选择稳定版本 (如 2.7.x)Group:com.exampleArtifact:demoDependencies: 添加Spring Web,Spring Data JPA,H2 Database(或你的目标数据库驱动如MySQL Driver),Lombok(简化代码可选但推荐)。生成并下载项目解压后导入到你的IDE中。核心的pom.xml依赖如下?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.10/version !-- 请使用最新稳定版 -- relativePath/ /parent groupIdcom.example/groupId artifactIddemo/artifactId version0.0.1-SNAPSHOT/version namedemo/name descriptionDemo project for Spring Boot/description properties java.version11/java.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency !-- H2 内存数据库方便演示 -- dependency groupIdcom.h2database/groupId artifactIdh2/artifactId scoperuntime/scope /dependency !-- Lombok自动生成getter/setter等方法 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration excludes exclude groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /exclude /excludes /configuration /plugin /plugins /build /project4.2 编写后端核心代码我们将按照MVC分层架构编写代码。第一步定义数据模型 (Model)创建实体类Task.java。// 文件路径src/main/java/com/example/demo/model/Task.java package com.example.demo.model; import lombok.Data; import javax.persistence.*; import java.time.LocalDateTime; Entity Data // Lombok注解自动生成getter, setter, toString等方法 Table(name tasks) public class Task { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; Column(nullable false) private String title; private String description; private Boolean completed false; private LocalDateTime createdAt; PrePersist protected void onCreate() { createdAt LocalDateTime.now(); } }第二步创建数据访问层 (Repository)Spring Data JPA会为我们自动实现基本的CRUD方法。// 文件路径src/main/java/com/example/demo/repository/TaskRepository.java package com.example.demo.repository; import com.example.demo.model.Task; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; Repository public interface TaskRepository extends JpaRepositoryTask, Long { // 可以在此定义自定义查询方法例如 // ListTask findByCompleted(Boolean completed); }第三步创建业务逻辑层 (Service)虽然简单项目可以直接在Controller调用Repository但引入Service层是更好的实践。// 文件路径src/main/java/com/example/demo/service/TaskService.java package com.example.demo.service; import com.example.demo.model.Task; import com.example.demo.repository.TaskRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; Service public class TaskService { Autowired private TaskRepository taskRepository; public ListTask getAllTasks() { return taskRepository.findAll(); } public Task createTask(Task task) { return taskRepository.save(task); } public OptionalTask getTaskById(Long id) { return taskRepository.findById(id); } // 可以继续添加更新、删除等方法 }第四步创建Web API层 (Controller)这是前后端交互的桥梁提供RESTful API。// 文件路径src/main/java/com/example/demo/controller/TaskController.java package com.example.demo.controller; import com.example.demo.model.Task; import com.example.demo.service.TaskService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; RestController RequestMapping(/api/tasks) // API路径前缀 CrossOrigin(origins http://localhost:8081) // 关键允许前端8081端口跨域访问 public class TaskController { Autowired private TaskService taskService; GetMapping public ResponseEntityListTask getAllTasks() { ListTask tasks taskService.getAllTasks(); return ResponseEntity.ok(tasks); } PostMapping public ResponseEntityTask createTask(RequestBody Task task) { // RequestBody 注解将前端传来的JSON自动绑定到Task对象 Task savedTask taskService.createTask(task); return new ResponseEntity(savedTask, HttpStatus.CREATED); } GetMapping(/{id}) public ResponseEntityTask getTaskById(PathVariable Long id) { return taskService.getTaskById(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } }关键点CrossOrigin(origins http://localhost:8081)注解解决了CORS问题允许来自localhost:8081的请求。第五步配置应用属性编辑src/main/resources/application.properties。# 服务器端口 server.port8080 # H2数据库配置 (内存模式数据重启后丢失仅用于演示) spring.datasource.urljdbc:h2:mem:testdb spring.datasource.driverClassNameorg.h2.Driver spring.datasource.usernamesa spring.datasource.password spring.jpa.database-platformorg.hibernate.dialect.H2Dialect # 在控制台打印SQL语句方便调试 spring.jpa.show-sqltrue spring.jpa.properties.hibernate.format_sqltrue # H2数据库Web控制台访问 http://localhost:8080/h2-console spring.h2.console.enabledtrue4.3 创建Vue.js前端项目打开终端进入你准备放置项目的目录例如D:\projects。运行命令创建Vue项目vue create frontend在提示中选择Manually select features然后勾选Babel,Router,Vuex(可选本文简单示例暂不需要)Linter / Formatter。其他选项按回车使用默认值。创建完成后进入项目目录并安装axios(用于HTTP请求)cd frontend npm install axios4.4 编写前端核心代码第一步配置Vue项目以代理API请求 (解决开发环境跨域)在frontend目录下创建或修改vue.config.js文件。// 文件路径frontend/vue.config.js const { defineConfig } require(vue/cli-service) module.exports defineConfig({ transpileDependencies: true, devServer: { port: 8081, // 前端开发服务器端口 proxy: { // 将所有以 /api 开头的请求代理到后端服务器 /api: { target: http://localhost:8080, // 后端地址 changeOrigin: true, pathRewrite: { ^/api: // 重写路径去掉 /api 前缀因为后端Controller已有 /api // 实际请求 /api/tasks - http://localhost:8080/api/tasks } } } } })为什么这样做在开发环境下Vue CLI的devServer代理可以将前端对/api的请求转发到后端服务器8080端口从而绕过浏览器的直接跨域限制。生产环境则需要通过Nginx等配置。第二步创建任务列表组件创建src/views/TaskList.vue。!-- 文件路径frontend/src/views/TaskList.vue -- template div classtask-list h1任务管理/h1 div classcreate-task input v-modelnewTask.title placeholder任务标题 / textarea v-modelnewTask.description placeholder任务描述/textarea button clickcreateTask创建任务/button /div ul li v-fortask in tasks :keytask.id h3{{ task.title }}/h3 p{{ task.description }}/p small创建于{{ formatDate(task.createdAt) }}/small span :class{ completed: task.completed } {{ task.completed ? 已完成 : 进行中 }} /span /li /ul /div /template script import axios from axios; export default { name: TaskList, data() { return { tasks: [], // 存储从后端获取的任务列表 newTask: { // 绑定到表单的新任务数据 title: , description: , completed: false } }; }, mounted() { this.fetchTasks(); // 组件挂载后加载任务 }, methods: { async fetchTasks() { try { // 请求会被 vue.config.js 中的代理转发到 http://localhost:8080/api/tasks const response await axios.get(/api/tasks); this.tasks response.data; } catch (error) { console.error(获取任务失败:, error); alert(获取任务列表失败); } }, async createTask() { if (!this.newTask.title.trim()) { alert(请输入任务标题); return; } try { const response await axios.post(/api/tasks, this.newTask); this.tasks.push(response.data); // 将新创建的任务添加到列表 this.newTask { title: , description: , completed: false }; // 清空表单 alert(任务创建成功); } catch (error) { console.error(创建任务失败:, error); alert(创建任务失败); } }, formatDate(dateTimeStr) { // 简单的日期格式化 if (!dateTimeStr) return ; const date new Date(dateTimeStr); return date.toLocaleString(); } } }; /script style scoped .task-list { padding: 20px; } .create-task { margin-bottom: 20px; } .create-task input, .create-task textarea { display: block; margin-bottom: 10px; width: 300px; padding: 8px; } ul { list-style: none; padding: 0; } li { border: 1px solid #ddd; padding: 15px; margin-bottom: 10px; border-radius: 5px; } .completed { color: green; font-weight: bold; } /style第三步修改路由和主组件修改src/router/index.js将默认主页指向我们的TaskList组件。// 文件路径frontend/src/router/index.js import { createRouter, createWebHistory } from vue-router import TaskList from ../views/TaskList.vue const routes [ { path: /, name: TaskList, component: TaskList } ] const router createRouter({ history: createWebHistory(process.env.BASE_URL), routes }) export default router修改src/App.vue简化模板。!-- 文件路径frontend/src/App.vue -- template div idapp router-view/ /div /template script export default { name: App } /script style #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #2c3e50; margin-top: 20px; } /style4.5 运行与验证启动后端在IDE中运行DemoApplication的main方法或使用命令行mvn spring-boot:run。控制台输出Tomcat started on port(s): 8080即成功。启动前端在frontend目录下打开终端运行npm run serve。终端会提示应用运行在http://localhost:8081。功能测试打开浏览器访问http://localhost:8081。在输入框中填写任务标题和描述点击“创建任务”。观察页面下方任务列表是否立即更新出新创建的任务。可以打开浏览器开发者工具的“网络(Network)”选项卡查看创建任务和获取任务列表的HTTP请求详情确认请求是否成功状态码200/201。5. 常见问题与排查思路在搭建过程中你可能会遇到以下典型问题问题现象可能原因排查步骤与解决方案前端访问localhost:8081报错Cannot GET /Vue路由模式为history模式且未正确配置生产服务器。1. 开发环境下确保npm run serve已成功启动。2. 检查vue.config.js中devServer.port是否为8081。3. 临时将路由模式改为hash模式createWebHashHistory测试。前端请求后端API时出现CORS error后端未配置CORS或配置的源(origin)不正确。1. 确认后端Controller类或方法上添加了CrossOrigin注解且端口正确。2. 或使用全局CORS配置在Spring Boot配置类中定义WebMvcConfigurerBean。3. 检查前端vue.config.js的代理配置是否正确。后端启动失败报Port 8080 already in use8080端口被其他程序占用。1. 在命令行使用netstat -ano | findstr :8080(Win) 或lsof -i :8080(Mac/Linux) 查找进程并终止。2. 或在application.properties中修改server.port8082。前端npm install或npm run serve失败Node.js版本不兼容或网络问题。1. 检查Node.js版本node -v建议使用14.x或16.x LTS版本。2. 尝试使用淘宝镜像npm config set registry https://registry.npmmirror.com。3. 删除node_modules和package-lock.json重新执行npm install。创建任务后刷新页面数据消失使用了H2内存数据库应用重启后数据丢失。这是预期行为。若要持久化需更换为MySQL等数据库并配置spring.datasource.url指向持久化数据库。后端控制台报BeanCreationException依赖缺失、配置错误或实体类扫描不到。1. 检查pom.xml依赖是否正确运行mvn clean compile。2. 确保主应用类 (SpringBootApplication) 所在的包是实体类、Repository等组件所在包的父级或同级。6. 最佳实践与工程建议将项目运行起来只是第一步要用于实际开发还需遵循以下工程化实践API设计规范RESTful风格使用合适的HTTP方法GET/POST/PUT/DELETE和资源路径。例如GET /api/tasks获取列表POST /api/tasks创建PUT /api/tasks/{id}更新DELETE /api/tasks/{id}删除。统一响应体封装一个通用的API响应对象包含状态码(code)、消息(message)和数据(data)。这便于前端统一处理。版本控制考虑在API路径中加入版本号如/api/v1/tasks为后续不兼容的升级留有余地。错误处理与日志全局异常处理在Spring Boot中使用ControllerAdvice和ExceptionHandler创建全局异常处理器将各种异常转化为结构化的错误信息返回给前端而不是暴露堆栈信息。前端错误处理在Vue中使用axios的拦截器(interceptors)统一处理网络错误和业务错误例如弹出友好提示或跳转到错误页面。日志记录使用SLF4J Logback记录关键业务日志、入参、出参和异常便于线上排查问题。安全与性能输入验证后端务必对接收到的参数进行校验可以使用Spring的Valid注解配合JSR-303验证注解如NotBlank,Size。防止SQL注入坚持使用Spring Data JPA或MyBatis等ORM框架的参数化查询绝对不要手动拼接SQL字符串。敏感信息数据库密码、API密钥等敏感信息绝不能硬编码在application.properties中。应使用环境变量、配置中心如Apollo或加密配置文件管理。前端性能对于Vue合理使用计算属性(computed)和侦听器(watch)避免在模板中进行复杂计算。对于大型列表考虑使用虚拟滚动。代码结构与可维护性后端分层清晰严格遵循Controller-Service-Repository的分层每层职责单一。Service层处理业务逻辑Controller层只负责参数校验和HTTP响应。前端组件化将可复用的UI元素如按钮、模态框、输入框抽离成独立的Vue组件。页面(views/)由多个基础组件(components/)组合而成。配置分离将开发、测试、生产环境的配置分离使用application-dev.properties,application-prod.properties并通过spring.profiles.active激活。前后端协作接口文档使用Swagger/OpenAPI自动生成API文档让前端开发者能清晰了解每个接口的用途、参数和返回值。在Spring Boot中集成springdoc-openapi-ui非常简单。Mock数据在前端开发初期后端接口可能尚未完成可以使用Mock.js或配置axios的适配器(adapter)来模拟后端数据实现并行开发。从教育内容创作回归到深度技术研究写作最大的感触是“结构”和“细节”同样重要。本文不仅展示了一个可运行的项目更试图拆解每一步背后的“为什么”。技术学习是一个从搭建环境到理解原理再到优化实践的过程。建议你在成功运行本项目后尝试添加“任务更新”、“任务删除”、“按状态筛选”等功能并实践文中提到的错误处理、API版本化等最佳实践。真正的掌握始于对每个环节的主动思考和反复调试。
返回列表