ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Spring Boot 3.x与Vue 3.x全栈实战:从零构建美食分享网站

Spring Boot 3.x与Vue 3.x全栈实战:从零构建美食分享网站 最近在辅导学生做毕业设计时发现很多同学对如何从零开始构建一个完整的JavaWeb项目感到迷茫尤其是在整合前后端分离架构时常常在环境配置、接口联调、数据库设计等环节卡住。本文将以一个“美食分享网站”为例手把手带你完成一个基于Spring Boot 3.x和Vue 3.x的毕业设计项目。从项目初始化、数据库设计、核心功能开发到最终部署全程提供可复制的代码和清晰的步骤旨在帮助计算机专业的同学高效、高质量地完成毕业设计也为希望学习全栈开发的开发者提供一个完整的实战案例。1. 项目概述与技术选型1.1 项目简介美食分享网站是一个典型的Web应用旨在为用户提供一个分享、浏览、搜索美食菜谱的平台。核心功能包括用户注册登录、菜谱发布、图片上传、菜谱分类浏览、收藏点赞、评论互动以及后台管理。这类项目业务逻辑清晰技术栈主流非常适合作为毕业设计或全栈入门项目。1.2 技术栈详解本项目采用前后端分离架构这是当前企业级Web开发的主流模式。后端 (Backend):Spring Boot 3.x: 作为核心后端框架它简化了Spring应用的初始搭建和开发过程提供了自动配置、内嵌Web服务器等特性能让我们快速构建RESTful API。Spring Security JWT: 用于实现用户认证与授权。Spring Security提供强大的安全框架结合JWTJSON Web Token可以实现无状态的、可扩展的认证机制。MyBatis-Plus: 一个强大的MyBatis增强工具在MyBatis的基础上只做增强不做改变简化了CRUD操作内置通用Mapper和分页插件能极大提高开发效率。MySQL 8.0: 关系型数据库用于存储用户、菜谱、评论等结构化数据。Redis: 作为缓存数据库可用于存储用户会话、热门菜谱列表、验证码等提升系统响应速度。Maven: 项目构建与依赖管理工具。前端 (Frontend):Vue 3.x (Composition API): 渐进式JavaScript框架用于构建用户界面。Vue 3的Composition API提供了更灵活的逻辑复用和代码组织方式。Vite: 下一代前端构建工具提供极速的冷启动和快速的热更新开发体验远超Webpack。Element Plus: 基于Vue 3的桌面端组件库提供了丰富的UI组件能快速搭建美观的界面。Axios: 基于Promise的HTTP客户端用于向后端API发送请求。Vue Router: Vue.js官方的路由管理器用于构建单页面应用。Pinia: Vue 3官方推荐的状态管理库用于管理跨组件的共享状态。开发工具:IntelliJ IDEA: 后端Java开发。Visual Studio Code: 前端Vue开发。Postman/Apifox: API接口调试。Navicat/DBeaver: 数据库管理。2. 开发环境准备2.1 基础软件安装在开始编码前请确保你的开发环境已安装以下软件JDK 17: Spring Boot 3.x要求JDK 17及以上版本。安装后配置JAVA_HOME环境变量。Node.js 18 npm: Vue 3.x和Vite的运行时环境。建议安装LTS版本。MySQL 8.0: 安装并启动MySQL服务记住root用户的密码。Redis 7.x: 安装并启动Redis服务。Maven 3.6: 用于管理后端项目依赖。2.2 初始化后端Spring Boot项目使用Spring Initializr可通过IDEA内置工具或访问 start.spring.io 快速生成项目骨架。Project: MavenLanguage: JavaSpring Boot: 3.2.x (选择稳定版本)Project Metadata:Group:com.foodshareArtifact:food-share-backendPackaging: JarDependencies: 添加以下依赖Spring WebSpring SecurityMyBatis FrameworkMySQL DriverLombok (简化POJO代码)Validation (参数校验)生成项目后用IDEA打开等待Maven下载完所有依赖。2.3 初始化前端Vue项目打开命令行工具执行以下命令创建Vue项目# 使用Vite官方模板创建项目 npm create vuelatest food-share-frontend # 进入项目目录 cd food-share-frontend # 安装依赖 npm install # 安装额外需要的库 npm install element-plus axios vue-router pinia # 启动开发服务器 npm run dev创建过程中根据提示选择需要的特性如TypeScript, Vue Router, Pinia等。3. 后端核心功能实现3.1 数据库设计与建表根据业务需求设计核心数据表。以下为部分关键表的SQL示例-- 用户表 CREATE TABLE sys_user ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, username varchar(50) NOT NULL COMMENT 用户名, password varchar(255) NOT NULL COMMENT 密码, nickname varchar(50) DEFAULT NULL COMMENT 昵称, avatar varchar(500) DEFAULT NULL COMMENT 头像URL, email varchar(100) DEFAULT NULL COMMENT 邮箱, status tinyint DEFAULT 1 COMMENT 状态1正常 0禁用, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci COMMENT用户表; -- 菜谱表 CREATE TABLE recipe ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, title varchar(200) NOT NULL COMMENT 菜谱标题, description text COMMENT 菜谱描述, cover_image varchar(500) DEFAULT NULL COMMENT 封面图URL, user_id bigint NOT NULL COMMENT 发布者ID, category_id bigint DEFAULT NULL COMMENT 分类ID, difficulty tinyint DEFAULT NULL COMMENT 难度1简单 2中等 3困难, prep_time int DEFAULT NULL COMMENT 准备时间分钟, cook_time int DEFAULT NULL COMMENT 烹饪时间分钟, steps json DEFAULT NULL COMMENT 步骤JSON数组, ingredients json DEFAULT NULL COMMENT 食材JSON数组, view_count int DEFAULT 0 COMMENT 浏览数, like_count int DEFAULT 0 COMMENT 点赞数, collect_count int DEFAULT 0 COMMENT 收藏数, status tinyint DEFAULT 1 COMMENT 状态1公开 0私密 2审核中, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_id (user_id), KEY idx_category_id (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci COMMENT菜谱表;建议使用utf8mb4字符集以支持存储Emoji表情。3.2 集成MyBatis-Plus与代码生成在pom.xml中添加MyBatis-Plus依赖dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.5/version /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-generator/artifactId version3.5.5/version /dependency配置application.yml数据库连接和MyBatis-Plusspring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/food_share_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: your_password data: redis: host: localhost port: 6379 database: 0 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印SQL生产环境关闭 global-config: db-config: logic-delete-field: deleted # 全局逻辑删除字段名 logic-delete-value: 1 # 逻辑已删除值 logic-not-delete-value: 0 # 逻辑未删除值使用MyBatis-Plus代码生成器快速生成Entity,Mapper,Service,Controller层代码可以编写一个简单的生成类或使用官方提供的插件。3.3 实现JWT认证与Spring Security配置添加JWT依赖如jjwt。创建JwtUtil工具类用于生成和解析Token。创建LoginUser类实现Spring Security的UserDetails接口。创建JwtAuthenticationTokenFilter过滤器用于拦截请求并验证JWT。配置SecurityConfiguration放行登录、注册等接口并配置密码加密器。 核心配置示例Configuration EnableWebSecurity public class SecurityConfig { Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // 禁用CSRF因为使用JWT无状态认证 .csrf().disable() // 设置会话管理为无状态 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() // 配置请求授权 .authorizeHttpRequests(auth - auth .requestMatchers(/api/auth/login, /api/auth/register, /api/recipes/public/**).permitAll() // 公开接口 .anyRequest().authenticated() // 其他所有接口需要认证 ) // 添加JWT过滤器 .addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class) // 配置异常处理 .exceptionHandling() .authenticationEntryPoint(authenticationEntryPoint) // 认证失败处理 .accessDeniedHandler(accessDeniedHandler); // 授权失败处理 return http.build(); } Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }3.4 核心业务接口开发以菜谱模块为例开发RESTful API。Controller层 (RecipeController.java): 定义API端点处理HTTP请求和响应。RestController RequestMapping(/api/recipes) RequiredArgsConstructor public class RecipeController { private final RecipeService recipeService; GetMapping(/{id}) public ResultRecipeVO getRecipeById(PathVariable Long id) { RecipeVO recipe recipeService.getRecipeDetail(id); return Result.success(recipe); } PostMapping public ResultLong createRecipe(Valid RequestBody RecipeCreateDTO dto) { Long recipeId recipeService.createRecipe(dto); return Result.success(recipeId); } GetMapping public ResultPageResultRecipeVO listRecipes(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) Long categoryId) { PageResultRecipeVO page recipeService.listRecipes(pageNum, pageSize, categoryId); return Result.success(page); } }Service层 (RecipeServiceImpl.java): 实现业务逻辑如参数校验、数据组装、事务管理等。DTO/VO对象: 使用RecipeCreateDTO接收创建请求使用RecipeVO返回给前端与数据库实体Recipe解耦。统一响应封装 (Result.java): 定义统一的API响应格式。Data NoArgsConstructor AllArgsConstructor public class ResultT { private Integer code; private String message; private T data; private Long timestamp; public static T ResultT success(T data) { return new Result(200, success, data, System.currentTimeMillis()); } // 其他静态方法如 error, fail 等 }3.5 文件上传功能使用Spring Boot的MultipartFile处理图片上传并集成OSS如阿里云OSS、MinIO或保存到本地。配置文件上传大小限制。创建FileService处理文件上传、生成访问URL、删除等逻辑。在Controller中提供上传接口。PostMapping(/upload) public ResultString uploadImage(RequestParam(file) MultipartFile file) { if (file.isEmpty()) { return Result.error(文件不能为空); } // 校验文件类型、大小 // 调用FileService上传 String url fileService.upload(file); return Result.success(url); }4. 前端核心功能实现4.1 项目结构搭建与配置在food-share-frontend项目中组织清晰的目录结构src/ ├── api/ # 所有API请求封装 ├── assets/ # 静态资源 ├── components/ # 公共组件 ├── composables/ # 组合式函数 ├── router/ # 路由配置 ├── stores/ # Pinia状态管理 ├── utils/ # 工具函数 ├── views/ # 页面组件 └── App.vue配置Vue Router和Pinia并在main.js或main.ts中引入Element Plus。4.2 封装全局请求工具在utils/request.js中使用Axios创建实例并配置请求/响应拦截器用于自动添加JWT Token、处理通用错误等。import axios from axios; import { ElMessage } from element-plus; import router from /router; import { useUserStore } from /stores/user; const service axios.create({ baseURL: import.meta.env.VITE_APP_BASE_API, // 从环境变量读取 timeout: 10000, }); // 请求拦截器 service.interceptors.request.use( (config) { const userStore useUserStore(); if (userStore.token) { config.headers[Authorization] Bearer ${userStore.token}; } return config; }, (error) { return Promise.reject(error); } ); // 响应拦截器 service.interceptors.response.use( (response) { const res response.data; if (res.code ! 200) { ElMessage.error(res.message || Error); // 处理特定错误码如 401 跳转登录 if (res.code 401) { router.push(/login); } return Promise.reject(new Error(res.message || Error)); } else { return res; } }, (error) { ElMessage.error(error.message || 请求失败); return Promise.reject(error); } ); export default service;4.3 用户登录与状态管理在stores/user.js中创建Pinia store管理用户登录状态、Token等信息。创建登录页面Login.vue调用封装好的登录API。登录成功后将Token存储到Pinia和localStorage中并跳转到首页。template div classlogin-container el-form :modelform :rulesrules refloginFormRef el-form-item propusername el-input v-modelform.username placeholder请输入用户名 / /el-form-item el-form-item proppassword el-input v-modelform.password typepassword placeholder请输入密码 / /el-form-item el-button typeprimary clickhandleLogin :loadingloading登录/el-button /el-form /div /template script setup import { ref, reactive } from vue; import { useRouter } from vue-router; import { ElMessage } from element-plus; import { useUserStore } from /stores/user; import { login } from /api/auth; const router useRouter(); const userStore useUserStore(); const loginFormRef ref(); const loading ref(false); const form reactive({ username: , password: , }); const rules { username: [{ required: true, message: 请输入用户名, trigger: blur }], password: [{ required: true, message: 请输入密码, trigger: blur }], }; const handleLogin async () { await loginFormRef.value.validate(); loading.value true; try { const res await login(form); userStore.setToken(res.data.token); userStore.setUserInfo(res.data.userInfo); ElMessage.success(登录成功); router.push(/); } catch (error) { console.error(error); } finally { loading.value false; } }; /script4.4 菜谱列表与详情页开发列表页 (RecipeList.vue): 使用Element Plus的el-row和el-col进行栅格布局结合el-card展示菜谱卡片。通过调用分页查询API获取数据并实现分类筛选、搜索等功能。详情页 (RecipeDetail.vue): 根据路由参数中的ID调用获取菜谱详情的API。页面布局可划分为顶部菜谱信息标题、封面、作者、食材列表、步骤图文展示、评论区。组件化: 将评论列表、点赞收藏按钮等抽离为独立组件提高复用性。4.5 菜谱发布与富文本编辑使用v-form和Element Plus表单组件构建发布页面。集成富文本编辑器如wangeditor/editor-for-vue用于编辑菜谱的描述和步骤。注意处理图片上传到后端。表单数据校验使用async-validator或Vue的响应式校验。提交时将表单数据包含富文本HTML内容或JSON格式的步骤通过API提交到后端。5. 前后端联调与跨域处理5.1 后端解决跨域在Spring Boot后端配置全局CORS允许前端开发服务器的请求。Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) // 匹配所有路径 .allowedOriginPatterns(*) // 允许所有源生产环境应指定具体域名 .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }5.2 前端代理配置在Vite项目根目录的vite.config.js中配置开发服务器代理避免开发时出现跨域问题。import { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], server: { proxy: { /api: { target: http://localhost:8080, // 后端服务地址 changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ) } } } })这样前端在开发时请求/api/recipes会被代理到http://localhost:8080/api/recipes。5.3 联调技巧使用浏览器的开发者工具F12的Network面板查看请求和响应。使用Postman或Apifox先独立测试后端API确保接口逻辑正确。前端调用API时注意请求方法GET/POST、请求头Content-Type, Authorization、请求体格式JSON/FormData要与后端定义一致。善用console.log和断点调试。6. 项目部署与上线6.1 后端打包与运行使用Maven打包mvn clean package -DskipTests会在target目录生成food-share-backend-0.0.1-SNAPSHOT.jar。在服务器上运行java -jar food-share-backend-0.0.1-SNAPSHOT.jar。可以使用nohup或配置为系统服务如systemd使其在后台运行。生产环境配置:使用application-prod.yml覆盖开发配置设置正确的数据库、Redis连接信息。关闭开发工具如spring-boot-devtools和调试日志。配置正确的CORS源而不是允许所有(*)。确保文件上传路径有读写权限或正确配置OSS。6.2 前端打包与部署构建生产版本npm run build生成静态文件在dist目录。部署方式方式一前后端分离: 将dist目录下的文件部署到Nginx或Apache等Web服务器。需要配置Nginx将API请求反向代理到后端服务。# Nginx 配置示例 server { listen 80; server_name your-domain.com; location / { root /path/to/frontend/dist; index index.html; try_files $uri $uri/ /index.html; # 支持Vue Router的history模式 } location /api/ { proxy_pass http://localhost:8080/; # 代理到后端 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }方式二静态资源托管: 将dist目录上传至云存储如阿里云OSS、腾讯云COS并开启静态网站托管配合CDN加速。7. 常见问题与排查思路在开发过程中你可能会遇到以下典型问题问题现象可能原因排查与解决思路前端访问后端API出现4041. 后端服务未启动。2. 请求URL路径错误。3. 后端Controller未正确映射。1. 检查后端服务日志确认是否启动成功。2. 核对前端请求的URL与后端RequestMapping定义的路径是否一致。3. 使用Postman直接测试后端接口。登录成功但后续请求返回4011. 前端未正确携带Token。2. Token已过期。3. 后端JWT解析失败或密钥不匹配。1. 检查Axios请求拦截器是否成功添加了Authorization头。2. 检查Token有效期实现Token自动刷新逻辑。3. 检查后端JWT工具类使用的密钥是否一致。文件上传失败或无法访问1. 文件大小超出限制。2. 存储路径权限不足。3. 返回的URL路径不正确。1. 检查Spring Boot的spring.servlet.multipart.max-file-size配置。2. 检查服务器上文件保存目录的读写权限。3. 确认文件访问URL是否被正确拼接Nginx是否配置了静态资源映射。Vue页面刷新后路由丢失或404Vue Router使用了history模式但服务器未配置。在Nginx配置中添加try_files $uri $uri/ /index.html;见6.2节。数据库连接失败1. MySQL服务未启动。2. 连接URL、用户名或密码错误。3. 时区设置问题。1. 检查MySQL服务状态。2. 核对application.yml中的配置。3. 在JDBC URL中添加serverTimezoneAsia/Shanghai。页面样式错乱或Element Plus组件未生效1. Element Plus未正确引入或注册。2. 组件按需引入配置错误。1. 检查main.js中是否全局引入了Element Plus。2. 如果使用按需导入检查unplugin-vue-components插件配置。8. 项目优化与扩展建议一个合格的毕业设计不应只停留在功能实现适当的优化和扩展能体现你的技术深度。8.1 性能优化数据库层面:为recipe表的user_id,category_id,create_time等常用查询字段建立索引。对复杂的多表关联查询考虑使用MyBatis-Plus的查询优化或手动编写优化后的SQL。合理使用数据库连接池如HikariCPSpring Boot默认集成。应用层面:缓存: 使用Redis缓存热点数据如首页菜谱列表、用户信息。注意设置合理的过期时间和缓存更新策略如删除更新。异步处理: 对于耗时的操作如发送邮件、生成复杂报表可以使用Spring的Async注解或消息队列如RabbitMQ进行异步处理提升接口响应速度。图片处理: 用户上传的图片进行压缩、生成缩略图并使用CDN加速访问。8.2 功能扩展搜索功能: 集成Elasticsearch实现菜谱标题、描述、食材的全文本搜索并支持高亮、分词和相关性排序。社交功能: 增加关注用户、私信、动态Feed流类似朋友圈等功能。数据可视化: 在后台管理界面使用ECharts展示网站数据统计如每日新增用户、热门菜谱排行等。第三方登录: 集成微信、QQ、Github等OAuth2.0第三方登录提升用户体验。容器化部署: 编写Dockerfile和docker-compose.yml将后端、前端、MySQL、Redis等服务容器化实现一键部署。8.3 代码质量与安全API文档: 使用SpringDoc OpenAPISwagger UI自动生成并维护API文档方便前后端协作。参数校验: 在DTO类中使用NotNull,Size,Pattern等注解进行入参校验并在Controller中使用Valid注解触发。全局异常处理: 使用ControllerAdvice和ExceptionHandler定义全局异常处理器统一处理业务异常、参数校验异常等返回友好的错误信息。SQL防注入: 坚持使用MyBatis的#{}预编译方式避免使用字符串拼接的${}。密码安全: 使用BCrypt等强哈希算法存储用户密码绝对禁止明文存储。接口限流与防刷: 对登录、注册、短信发送等接口使用Guava RateLimiter或Redis实现简单的限流防止恶意请求。通过以上步骤你不仅完成了一个功能完整的美食分享网站更系统地实践了从需求分析、技术选型、环境搭建、编码实现、联调测试到部署上线的全流程。这个项目涵盖了JavaWeb开发的核心技术栈可以作为你求职简历中的一个有力项目经历。在开发过程中多思考、多尝试、多总结遇到问题善用搜索引擎和官方文档你的工程能力一定会得到质的提升。
返回列表