免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

SpringBoot+Vue电商项目源码实战:从本地启动到Nginx部署

SpringBoot+Vue电商项目源码实战:从本地启动到Nginx部署 简介本资源是一套基于Spring Boot与Vue技术栈开发的二次元主题电商系统完整工程包面向Java全栈初学者及Web开发实践者解决从项目搭建、前后端联调到数据库落地的一站式学习需求。压缩包共715个文件含63个Java后端核心逻辑文件、38个Vue前端组件与交互脚本js、36个样式文件css及大量静态资源374张jpg、153张png另有2个SQL建表脚本、1个MySQL模型备份文件mwb.bak和1个application.yml配置示例整体30.09MB结构清晰、模块边界明确。已有330人学习下载配套提供详尽部署说明文档、系统功能模块图解含商品/订单/用户三大管理子系统及完整数据库表结构与字段说明可直接运行调试、二次开发或作为课程设计/毕设参考案例显著降低电商平台类项目的入门门槛与试错成本。1. 为什么一个“二次元商品购物商城”源码包成了 SpringBoot Vue 新手绕不开的练手靶场你刚学完 SpringBoot 的 REST 接口开发也跟着教程用 Vue CLI 搭了个带 Element UI 的登录页但一到“做点真东西”就卡在用户注册后怎么存头像商品图上传到哪购物车数据是存在 localStorage 还是发请求订单状态变更后前端怎么实时感知——这些不是概念题是每天真实发生的、带文件、带并发、带权限、带支付模拟的工程毛刺。这个标题里的.zip包本质是一套可运行、可调试、可拆解的最小闭环电商骨架后端用 SpringBoot含 MyBatis-Plus、Spring Security、文件上传、JWT 鉴权前端用 Vue2 Vue Router Axios Element UI注意不是 Vue3别被热词带偏数据库是 MySQL5.7所有 SQL 脚本、建表语句、初始数据都打包在内。它不追求高并发或微服务但把「用户-商品-购物车-订单-后台管理」五条主链路全跑通了连「管理员审核商品上架」「用户收藏夹同步」「图片防盗链基础处理」这种容易被忽略的细节都留了钩子。适合两类人一是想摆脱“Hello World”阶段、急需一个能本地启动并逐行 debug 的完整项目的新手二是需要快速验证某个技术点比如 SpringBoot 文件上传拦截器怎么写、Vue 路由守卫如何控制未登录跳转的熟手——你不用从零搭环境直接进src/main/java或src/views就能开干。下面我就按真实复现路径带你把这包源码从解压到上线跑通重点说清每一步为什么这么配、参数怎么调、哪里最容易翻车。2. 解压即启动SpringBoot 后端服务的三步落地法这个源码包的后端结构非常典型pom.xml里明确依赖了spring-boot-starter-web、mybatis-plus-boot-starter、spring-boot-starter-security、spring-boot-starter-thymeleaf用于后台管理页的简单渲染非必须、commons-fileupload处理图片上传。没有用 Lombok所以实体类里全是 getter/setter没集成 Redis购物车暂存用的是内存 Map这是刻意为之的教学设计不是缺陷。数据库连接配置在application.yml里关键字段如下spring: datasource: url: jdbc:mysql://localhost:3306/cosplay_shop?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver提示serverTimezoneAsia/Shanghai是 MySQL 8.0 必加参数漏掉会报The server time zone value XXX is unrecognized错误不是时区设置问题是 JDBC 驱动强制校验。2.1 创建数据库并导入初始化脚本源码包里一定包含sql/目录常见命名cosplay_shop.sql或init_db.sql里面是完整的建库建表语句。不要用 Navicat 或 DBeaver 的“执行 SQL 文件”功能一键导入——它们默认不识别/* */块注释和DELIMITER容易卡在存储过程或触发器上本项目虽无复杂过程但脚本里可能有兼容性注释。我一般会用命令行分步执行# 1. 登录 MySQL mysql -u root -p # 2. 手动创建数据库确保编码一致 CREATE DATABASE IF NOT EXISTS cosplay_shop CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # 3. 退出后用 source 命令导入路径替换成你解压后的绝对路径 mysql -u root -p cosplay_shop /path/to/your/zip/sql/cosplay_shop.sql导入后检查三张核心表user用户、product商品、order_info订单。特别注意product表的img_url字段是VARCHAR(255)说明图片路径是相对路径实际图片文件存在后端resources/static/upload/目录下——这是后续部署时必须映射的静态资源目录。2.2 修改 application.yml 适配你的本地环境除了数据库连接还有两处必须改文件上传路径application.yml中通常有类似配置# 文件上传配置 file: upload-path: D:/cosplay_shop/upload/这个路径必须是你电脑上真实存在的绝对路径且 Java 进程有写入权限。Windows 下建议改成D:/upload/Linux/macOS 改成/home/yourname/upload/。千万别留着D:/cosplay_shop/upload/—— 90% 的新手第一次启动失败就卡在这行报java.nio.file.AccessDeniedException。JWT 密钥如果用了 JWT大概率用了application.yml里会有jwt: secret: yourSecretKey123 expiration: 86400secret字段必须是至少 32 位的随机字符串JWT 规范要求否则 Spring Security 会抛InvalidKeyException。你可以用 Python 快速生成import secrets print(secrets.token_urlsafe(32)) # 输出类似XyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBc......改完后用 IDEA 或 Eclipse 右键SpringbootApplication.java→Run As→Java Application。看到控制台输出Started CosplayShopApplication in X.XXX seconds且无 ERROR 日志说明后端已就绪。此时访问http://localhost:8080/swagger-ui.html如果集成了 Swagger或http://localhost:8080/api/user/login测试接口返回401 Unauthorized是正常的——说明 Spring Security 已生效JWT 鉴权链路通了。3. Vue 前端从 npm install 到路由守卫的完整链路前端目录结构是标准 Vue CLI 3 项目src/下有assets/静态资源、components/复用组件、views/页面级组件、router/index.js路由配置、store/index.jsVuex 状态管理、utils/request.jsAxios 封装。关键依赖在package.json里vue2.6.14、vue-router3.5.3、axios0.21.4、element-ui2.15.6、js-cookie2.2.0存 token。注意不要升级 Vue 到 3.x因为 Element UI 2.x 不兼容 Vue3强行升级会导致el-button等组件报Unknown custom element错误。3.1 安装依赖与环境变量配置执行npm install后90% 的问题出在node_modules权限或镜像源。如果你用的是国内网络必须配淘宝镜像否则npm install会卡在node-sass编译# 全局设置镜像一次设置永久生效 npm config set registry https://registry.npmmirror.com # 如果已安装过 node-sass 失败先清除缓存再重装 npm cache clean --force npm uninstall node-sass npm install node-sass4.14.1 # 注意版本Vue2 项目必须用 4.x5.x 以上 require node-gyp 重编译极易失败环境变量配置在src/config/env.js或.env.development文件中不同项目位置不同。常见写法是// .env.development VUE_APP_BASE_API http://localhost:8080/api VUE_APP_UPLOAD_URL http://localhost:8080/upload这里VUE_APP_BASE_API必须和后端RestController的RequestMapping(/api)前缀一致VUE_APP_UPLOAD_URL对应后端文件上传接口的路径如PostMapping(/upload)。如果后端用了CrossOrigin注解但没指定origins前端跨域请求会被拦截——这是新手最常问的“为什么登录接口 200上传图片 403”的根源。3.2 路由守卫实现未登录跳转与权限拦截router/index.js里一定有全局前置守卫router.beforeEach逻辑类似router.beforeEach((to, from, next) { const token Cookies.get(token) if (to.meta.requiresAuth !token) { // 需要登录的页面但没 token next({ path: /login, query: { redirect: to.fullPath } }) } else if (to.path /login token) { // 已登录却访问登录页 next({ path: /home }) } else { next() } })注意to.meta.requiresAuth是在路由定义时手动加的元信息比如{ path: /cart, name: Cart, component: () import(/views/Cart.vue), meta: { requiresAuth: true } // 关键没这行守卫不生效 }玄学点来了如果你修改了路由配置但页面没反应不是代码没生效而是浏览器缓存了旧的chunk-vendors.js。强制刷新CtrlF5或清空浏览器缓存即可。Vue Router 的懒加载语法import(/views/xxx.vue)生成的 chunk 名是哈希值但开发服务器有时不会自动更新引用。4. 数据库同步与文件上传两个高频翻车点的避坑指南这个商城项目最常被问“为什么商品图传不上去”“为什么注册用户查不到”90% 源于数据库和文件系统没对齐。下面三条是我在带新人时记下的血泪经验每条都对应一个真实翻车现场。4.1 现象上传商品图片后前端显示http://localhost:8080/upload/20230501/abc.jpg但浏览器打开是 404原因SpringBoot 默认只提供classpath:/static/和classpath:/public/下的静态资源访问而upload-path配置的D:/upload/是外部磁盘路径不在 classpath 内。解决在CosplayShopApplication.java同级新建WebMvcConfig.java重写addResourceHandlersConfiguration public class WebMvcConfig implements WebMvcConfigurer { Value(${file.upload-path}) private String uploadPath; Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // 将 upload-path 映射为 /upload/** 路径 registry.addResourceHandler(/upload/**) .addResourceLocations(file: uploadPath); } }注意file:前缀不能少这是告诉 Spring 访问文件系统而非 classpath。Windows 路径分隔符用/不是\。4.2 现象MySQL 中user表有数据但登录时提示“用户名或密码错误”原因密码字段在数据库里是明文存储如123456但后端代码用了BCryptPasswordEncoder加密比对passwordEncoder.matches(rawPassword, user.getPassword())而初始化 SQL 脚本里插入的是明文没经过加密。解决两种方案二选一方案A推荐修改初始化 SQL用 BCrypt 加密123456后再插入。在线工具搜 “bcrypt generator”输入123456得到$2a$10$...开头的密文替换 SQL 里的password字段值方案B临时关闭密码加密在UserServiceImpl.java的登录方法里注释掉passwordEncoder.matches()直接用rawPassword.equals(user.getPassword())仅用于本地调试上线前必须恢复。4.3 现象管理员后台能新增商品但前端首页不显示新商品原因product表有个status字段tinyint值为0表示“未上架”1表示“已上架”。后台新增时默认设为0而首页查询 SQL 写的是WHERE status 1。解决检查ProductMapper.xml中的selectListSQL确认是否有AND status 1条件然后去 MySQL 手动执行UPDATE product SET status 1 WHERE id 1;把测试商品状态改为 1。这不是 bug是电商系统的标准设计——防止草稿商品被用户看到。5. 部署上线从 jar 包打包到 Nginx 反向代理的实操清单本地跑通只是第一步。真正交付时你需要把后端打成jar包扔到 Linux 服务器前端npm run build生成dist/目录交给 Nginx 托管。这个过程有三个硬性约束必须满足漏一条就 502。5.1 后端 jar 包排除前端资源指定 profilepom.xml里packaging一定是jar不是war。打包命令mvn clean package -Dmaven.test.skiptrue生成的target/cosplay-shop-0.0.1-SNAPSHOT.jar是可执行 jar。关键参数-Dspring.profiles.activeprod激活生产环境配置application-prod.yml里面数据库密码、JWT 密钥等敏感信息必须和本地不同--spring.config.locationfile:/opt/app/config/application-prod.yml指定外部配置文件路径避免把密码打进 jar 包。启动命令nohup java -jar cosplay-shop-0.0.1-SNAPSHOT.jar \ --spring.profiles.activeprod \ --spring.config.locationfile:/opt/app/config/ \ /opt/app/logs/start.log 21 5.2 前端 dist 目录Nginx 配置要点npm run build后dist/目录结构是dist/ ├── index.html ├── css/ ├── js/ └── img/ # 这里放的是 webpack 打包后的商品图小图但实际大图存在后端 upload 目录Nginx 配置/etc/nginx/conf.d/cosplay.confserver { listen 80; server_name your-domain.com; # 前端静态资源 location / { root /opt/app/dist; try_files $uri $uri/ /index.html; # 解决 Vue Router history 模式 404 } # 后端 API 代理关键避免跨域 location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # 上传图片代理让 /upload/ 走到后端 upload-path location /upload/ { proxy_pass http://127.0.0.1:8080/upload/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }注意proxy_pass末尾的/不能少proxy_pass http://127.0.0.1:8080/api/;会把/api/user/login代理成http://127.0.0.1:8080/api/user/login如果写成proxy_pass http://127.0.0.1:8080/api;没斜杠就会变成http://127.0.0.1:8080/apiuser/login直接 404。5.3 数据库与文件目录的生产环境映射MySQL确保application-prod.yml中url指向内网数据库 IP如jdbc:mysql://10.0.1.100:3306/...不是localhostDocker 容器内 localhost 指自己上传目录file.upload-path必须指向服务器上真实存在的路径如/opt/app/upload/并赋予www-data用户Nginx 进程用户读写权限mkdir -p /opt/app/upload chown -R www-data:www-data /opt/app/upload chmod -R 755 /opt/app/upload6. 进阶验证用 Postman Chrome DevTools 定位真实瓶颈跑通不等于可用。我习惯用三步法验证核心链路是否健壮接口层 → 网络层 → 渲染层。每个环节都有专属工具和检查点不是靠 F5 刷新看页面。6.1 接口层Postman 验证 JWT 流水线新建 Postman Collection按顺序建四个请求POST /api/user/loginBody 选x-www-form-urlencoded填usernameadminpassword123456成功返回token字段GET /api/product/listHeaders 加Authorization: Bearer 上面拿到的token检查返回商品列表 JSON 是否含img_url且路径可访问POST /api/order/createBody 用 raw JSON填{ productId: 1, count: 1 }Headers 同样带 token看是否返回订单号GET /api/order/mylist验证订单是否归属当前用户。提示如果第 2 步 401说明 token 过期或签名错误如果第 3 步 400检查productId是否真实存在且status1如果第 4 步返回空数组确认order_info表里user_id字段值和登录用户的id一致别用字符串 ID 比数字 ID。6.2 网络层Chrome DevTools 的 Network 面板深挖打开 Chrome → F12 → Network 标签页 → 刷新首页筛选XHR找到/api/product/list请求点开看Preview标签确认返回 JSON 结构和后端ProductController的ResponseBody返回对象一致点开Headers标签检查Request Headers里的Authorization是否带Bearer xxxResponse Headers里的Access-Control-Allow-Origin是否为*或你的域名筛选Img找商品图请求如果状态码是304Not Modified说明浏览器缓存了如果是404复制Request URL粘贴到新标签页看是否真 404 —— 如果是回到第 4 节检查WebMvcConfig的addResourceHandlers是否生效。6.3 渲染层Vue Devtools 查看响应式数据流安装 Vue Devtools 插件后F12 → Vue 标签页在商品列表页展开Products.vue组件看data下的productList是否为数组且长度 0点击某个商品的“加入购物车”按钮观察methods.addToCart执行后store.state.cartItems是否增加了一条记录如果cartItems没变检查store/modules/cart.js的mutations.ADD_TO_CART是否正确push了 item以及actions.addToCart是否 commit 了该 mutation。最后说个我踩过的坑某次上线后用户反馈“购物车数量一直显示 0”。排查发现是localStorage.setItem(cart, JSON.stringify(cartItems))里cartItems是undefined因为store.state.cartItems初始化为空数组[]但JSON.stringify([])是[]而JSON.parse([])返回[]逻辑没错……问题出在localStorage的setItem会把null转成字符串null而JSON.parse(null)返回null导致后续cartItems.length报错。解决方案是在getItem后加一层|| []安全兜底。这种细节只有真正在生产环境被用户骂过才会刻进 DNA。希望帮到你。本文还有配套的精品资源点击获取
返回列表