ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringBoot+Vue+MyBatis+MySQL服装商城系统开发复盘:从建表到部署上线

SpringBoot+Vue+MyBatis+MySQL服装商城系统开发复盘:从建表到部署上线 做一个能上线的服装商城系统是什么体验前后端分离、订单流转、商品管理、部署上线一个完整链路跑下来比看一百个教程都实在。这篇文章我拿自己最近梳理的一套SpringBoot Vue MyBatis MySQL 网上服装商城管理系统源码作为底子把整个项目的设计思路、数据库建模、后端接口、前端页面、部署踩坑全部复盘一遍。先说明这套系统是什么、能干什么用户端有商品浏览、按分类筛选、关键词搜索、加入购物车、提交订单、模拟支付、订单状态跟踪管理端有商品维护上架/下架/库存调整、分类管理、订单审核发货、用户管理、轮播图配置。如果你是刚学完 SSM 或者 SpringBoot 基础想找一个完整项目练手或者毕业设计想用现成源码二次开发甚至想快速搭一个可演示的电商 demo这套代码的架构和写法都很适合拿来改。1. 项目整体设计与技术选型思路先聊选型。为什么 2025 年做这种管理系统仍然首选SpringBoot Vue MyBatis MySQL这个组合因为对于一个中小规模电商系统来说它恰好把“开发效率、学习成本、维护友好度”这三个点平衡住了。SpringBoot 解决了传统 SSM 项目里繁琐的 XML 配置问题内嵌 Tomcat打出来的 Jar 直接跑Vue 做前端 SPA 页面用户体验好组件化开发也很舒服MyBatis 则让你把 SQL 攥在自己手里电商这种业务里经常有多表关联、统计查询、动态条件手写 SQL 反而最好控制和优化MySQL 是现阶段最普及的关系型数据库部署和运维资料多基本不会卡住你。1.1 为什么不做微服务、不用 Redis 兜底我在这套源码里故意没有引入 Spring Cloud、Nacos、Redis 这些偏重的组件。原因很简单业务量级没到这个程度硬上微服务只会把学习重心带偏。商城系统的核心难点从来不是服务拆分而是“商品、库存、订单、购物车”这四块数据怎么组织、状态怎么流转。单体架构 良好的分层足以支撑一个毕业设计或者小公司内部系统的并发需求。订单号用时间戳随机数库存扣减用 SQL 层面的条件更新优惠券逻辑先不接第三方支付这些都是为了把主链路跑通让你先看见一个可以完整演示的系统再去考虑复杂的分布式事务、消息队列、缓存一致性。这一点我建议所有做类似项目的人都参考——先把骨架做出来再谈花活。1.2 系统角色与功能模块划分整套系统的用户分为两类普通用户前台商城注册登录、浏览首页推荐、分类浏览商品、商品详情查看、加入购物车、结算下单、查看个人订单、确认收货、编辑收货地址。管理员后台管理统计分析简单看板、商品管理增删改查、上下架、库存调整、订单管理查看订单详情、发货、取消、用户管理禁用/启用、分类管理和轮播图维护。前后端分离的项目最忌讳的就是角色权限糅在一起。这套代码里我用路由守卫后端接口校验双重控制前端根据登录用户角色决定是否渲染后台菜单后端在管理端 Controller 统一校验登录状态和角色标识。虽然没上 Spring Security 这种重武器但对一个学习项目完全够用而且你看代码会更直观。2. 系统核心模块拆解与数据库设计源码拿到手第一步不是急着启动而是先看懂数据库。数据库设计是整个商城系统的地基地基歪了后面写接口全是补丁。2.1 核心数据表清单与设计思路我梳理出这套系统的主表一共 8 张左右每一张都有它存在的理由表名用途关键字段user用户表含管理员id, username, password, role, avatar, statuscategory商品分类表id, name, parent_id, sortproduct商品表id, category_id, name, cover, images, price, original_price, stock, sales, status, detailcart购物车表id, user_id, product_id, quantity, checkedorders订单主表id, order_no, user_id, total_amount, status, address_detail, create_timeorder_item订单明细表id, order_id, product_id, product_name, product_image, price, quantityaddress收货地址表id, user_id, receiver, phone, province, city, detailbanner首页轮播图表id, image, link, sort注意到我上表中订单相关的拆成了orders和order_item两张表这叫“主子表结构”。一个订单可以包含多个不同商品如果把商品信息全部拼在订单表里字段会无限膨胀查询订单时数据冗余也严重。主表只记录订单全局信息订单号、总金额、收货信息、订单状态明细表每行记录一个商品条目两张表通过order_id关联。2.2 建表 SQL 的几个细节给你看两个关键表的建表语句重点不是背 SQL是理解里面的设计取舍CREATE TABLE product ( id int(11) NOT NULL AUTO_INCREMENT COMMENT 商品ID, category_id int(11) NOT NULL DEFAULT 0 COMMENT 所属分类ID, name varchar(200) NOT NULL DEFAULT COMMENT 商品名称, cover varchar(500) DEFAULT COMMENT 商品封面图, images text COMMENT 商品相册图json数组存多图, price decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT 售价, original_price decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT 原价, stock int(11) NOT NULL DEFAULT 0 COMMENT 库存, sales int(11) NOT NULL DEFAULT 0 COMMENT 销量, status tinyint(1) NOT NULL DEFAULT 1 COMMENT 状态 1上架 0下架, detail text COMMENT 商品详情, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_category (category_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品表;价格字段一定不要用float或者double必须用decimal(10,2)。这个坑我亲眼见过用浮点存储价格0.1 0.2 ! 0.3订单总金额算出个99.999999用户付款直接懵。decimal是定点数专门解决金钱计算的精度问题。商品相册我用的text存 JSON 数组字符串[/upload/1.jpg,/upload/2.jpg]。这种存法适合中小项目简单直接无需额外关联表。前端拿到后JSON.parse就能遍历渲染。如果商品属性特别复杂尺码、颜色组合、SKU 库存那就要上商品属性表和 SKU 表了但基础版这样做完全没问题。订单主表CREATE TABLE orders ( id int(11) NOT NULL AUTO_INCREMENT, order_no varchar(32) NOT NULL DEFAULT COMMENT 订单编号, user_id int(11) NOT NULL DEFAULT 0 COMMENT 下单用户ID, total_amount decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT 订单总金额, status tinyint(1) NOT NULL DEFAULT 0 COMMENT 0待付款 1待发货 2待收货 3已完成 4已取消, receiver varchar(50) NOT NULL DEFAULT COMMENT 收货人, phone varchar(20) NOT NULL DEFAULT COMMENT 联系电话, address_detail varchar(500) NOT NULL DEFAULT COMMENT 收货地址详情, create_time datetime DEFAULT CURRENT_TIMESTAMP, pay_time datetime DEFAULT NULL, deliver_time datetime DEFAULT NULL, finish_time datetime DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_user (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单主表;order_no加唯一索引防止订单号重复。订单状态我建议用tinyint数字表示配合后端枚举或者常量类统一管理不要直接在代码里写魔法数字。每一个状态节点配备对应的时间字段比如待发货要记录支付时间待收货要记录发货时间这样用户和管理员都能看到完整的流转时间线。2.3 MyBatis 映射层的规划MyBatis 是这套代码的持久层核心。我采用了entity实体类、mapper接口、mapper.xmlSQL 映射三段式。实体类字段和表字段保持驼峰与下划线自动映射要在application.yml里开启mybatis: configuration: map-underscore-to-camel-case: true mapper-locations: classpath:mapper/*.xml type-aliases-package: com.shop.entity新手一定注意create_time要自动映射到createTime就必须打开map-underscore-to-camel-case。不开启的话你查出来的对象createTime永远是 null排查半天根本想不到是映射问题。商品分页查询的 XML 是这样写的select idselectProductPage resultTypecom.shop.entity.Product SELECT * FROM product where if testcategoryId ! null AND category_id #{categoryId} /if if testkeyword ! null and keyword ! AND (name LIKE CONCAT(%, #{keyword}, %)) /if AND status 1 /where ORDER BY id DESC LIMIT #{offset}, #{pageSize} /select这种动态 SQL 是 MyBatis 的核心优势。where标签自动帮你去掉多余的ANDif实现按条件拼 SQL搜索、筛选、排序都特别好用。同时统计总数的语句单独写一个select两个方法配合实现分页。3. 后端核心功能实现细节后端代码我按照经典的三层架构来组织Controller接收请求→ Service业务逻辑→ Mapper数据访问。每一层的职责边界必须清晰这是整个项目是否“干净”的分水岭。3.1 项目包结构与启动流程com.shop ├── controller // 接口层 │ ├── admin // 管理端接口 │ └── front // 商城端接口 ├── service // 业务层 │ └── impl ├── mapper // MyBatis接口 ├── entity // 实体类 ├── common // 公共类Result、常量、异常处理 ├── config // 配置类跨域、上传、拦截器 └── ShopApplication.java // 启动类拿到源码后本地跑起来分四步新建数据库shop_db导入项目里sql目录下的shop_db.sql。修改application.yml里的数据库用户名、密码。用 IDEA 打开项目等待 Maven 下载完依赖直接运行ShopApplication。启动成功后访问http://localhost:8080/api/xxx测试接口最好先用 Knife4j 或 Postman 验证登录接口。3.2 登录注册与 JWT 签发用户登录这块我用的JWTJSON Web Token方案。流程是用户提交用户名密码 → 后端校验通过 → 生成一个 Token 返回给前端 → 前端每次请求在 Header 里带上Authorization: Bearer token→ 后端写一个拦截器统一校验。为什么用 JWT 而不是 Session因为前后端分离项目前端可能部署在 80 端口、后端在 8080 端口Session 天然不适合跨域域名共享而 JWT 是无状态的后端不用存登录记录前端拿到 Token 自己保管非常契合分布式和前后端分离的场景。登录接口核心逻辑PostMapping(/login) public Result login(RequestBody User user) { User dbUser userService.findByUsername(user.getUsername()); if (dbUser null || !passwordEncoder.matches(user.getPassword(), dbUser.getPassword())) { return Result.error(用户名或密码错误); } if (dbUser.getStatus() 0) { return Result.error(账号已被禁用); } String token JwtUtil.createToken(dbUser.getId(), dbUser.getUsername(), dbUser.getRole()); MapString, Object data new HashMap(); data.put(token, token); data.put(userInfo, dbUser); return Result.success(data); }密码加密用的是BCryptPasswordEncoder不建议再用 MD5。MD5 是散列算法早就有彩虹表可以暴力反查BCrypt 每次加密自动加盐同样密码两次加密结果不一样安全性高一个档次。Spring Security 即使你不用完整框架单独引入spring-security-crypto依赖也能用它的BCryptPasswordEncoder。3.3 商品列表、搜索与分页查询商品查询是所有接口里最常见的我用了 PageHelper 分页插件也可以自己拼LIMIT。PageHelper 的好处是代码侵入小public PageInfoProduct getProductPage(int pageNum, int pageSize, Integer categoryId, String keyword) { PageHelper.startPage(pageNum, pageSize); ListProduct list productMapper.selectProductPage(categoryId, keyword); return new PageInfo(list); }PageHelper.startPage之后的第一个 Mapper 查询会被自动拦截并加上LIMIT同时还会自动执行一条COUNT(*)统计总数。很方便但有个细节startPage只对紧随其后的第一条查询生效中间不要插其他 SQL 操作。查询出来的商品列表需要给前端展示原价和现价促销逻辑我先用original_price和price两个字段做简单折扣展示不做复杂的营销系统。换算逻辑是前端算(originalPrice - price) / originalPrice * 100得到折扣率。这样的好处是后端接口保持简单前端展示灵活。3.4 购物车与订单提交的事务控制购物车这块比较简单加入购物车之前先查一下该用户购物车是否已有该商品如果有就数量加一没有就新增一条记录。这个查询 操作放在同一个方法里注意加事务注解防止并发重复插入。订单提交是整个后端最核心的业务我单独强调这里的逻辑顺序和事务查询购物车里勾选的商品列表。遍历每个商品校验库存是否充足。算总金额用数据库查询出来的最新价格算不信前端传过来的金额。生成订单号插入订单主表。批量插入订单明细表。扣减商品库存在 SQL 层面做条件更新防止超卖。删除对应用户的购物车记录。以上任何一个环节失败都要回到起点必须加Transactional。扣库存的 SQL 我建议写成Update(UPDATE product SET stock stock - #{quantity} WHERE id #{productId} AND stock #{quantity}) int reduceStock(Integer productId, Integer quantity);WHERE stock #{quantity}是防止超卖的关键。多线程同时下单时库存不够的那一条更新语句会返回 0 影响行数业务层根据返回值抛出“库存不足”异常事务回滚这一招在单体项目里是最简单可靠的防超卖手段。3.5 文件上传与图片访问图片上传用的是 SpringBoot 自带的文件上传没有上 OSS。生产环境可以换 OSS但本地项目先用本地存储足够了。配置spring: servlet: multipart: max-file-size: 10MB max-request-size: 20MB保存文件的目录我放在项目的upload/目录下然后注册一个资源映射器把/upload/**映射到本地磁盘路径Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceHandler(file: System.getProperty(user.dir) /upload/); } }不注册这个映射前端img src/upload/xxx.jpg直接 404。这也是很多新人第一次做上传功能最容易忽略的配置。上传成功后返回给前端的图片地址应该是一个可以访问的完整 URL而不是D:\xxx\yyy.jpg。4. 前端 Vue 开发与交互实现前端我用的 Vue 2 Element UI 组合。为什么不用 Vue 3源码兼容性考虑Vue 2 的项目资料多Element UI 组件库极其成熟很多老项目都在用。如果你熟悉 Vue 3改成 Vue 3 Element Plus 也不难这里先按 Vue 2 讲。4.1 前端工程结构src ├── api // 接口请求封装 │ ├── product.js │ ├── cart.js │ ├── order.js │ └── user.js ├── assets // 静态资源 ├── components // 公共组件 ├── router // 路由配置 ├── views // 页面组件 │ ├── front // 前台页面 │ ├── admin // 后台管理页面 ├── utils // 工具类request.js, auth.js ├── App.vue └── main.jsmain.js里全局挂载 Element UI 和 axios然后引入路由import Vue from vue import ElementUI from element-ui import element-ui/lib/theme-chalk/index.css import App from ./App.vue import router from ./router Vue.use(ElementUI) Vue.config.productionTip false new Vue({ router, render: h h(App) }).$mount(#app)4.2 axios 封装与请求拦截器axios 必须封装一层统一处理 Token 注入和错误提示不然每个请求都要写一遍headers会恶心死。// utils/request.js import axios from axios import { Message } from element-ui import router from /router const service axios.create({ baseURL: process.env.VUE_APP_BASE_API || /api, timeout: 10000 }) // 请求拦截器带上token service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config }) // 响应拦截器统一处理错误 service.interceptors.response.use( response { const res response.data if (res.code ! 200) { Message.error(res.message || 请求失败) if (res.code 401) { localStorage.removeItem(token) router.push(/login) } return Promise.reject(new Error(res.message)) } return res }, error { Message.error(error.message || 网络异常) return Promise.reject(error) } ) export default service这里有个小点response.interceptors的error分支里如果拿到的是跨域 CORS 错误浏览器控制台会先报一个Blocked by CORS policy很多人以为后端没配跨域其实可能是前端baseURL配错了导致请求没打到后端。排查时先看 Network 面板里的请求 URL 到底是否拼接正确。4.3 商城首页与商品列表渲染前台首页由轮播图、分类导航、商品瀑布流这几个板块组成。商品列表用v-for渲染div classproduct-grid div classproduct-card v-foritem in productList :keyitem.id clickgoDetail(item.id) el-image :srcitem.cover fitcover/ div classproduct-name{{ item.name }}/div div classproduct-price span classprice{{ item.price }}/span span classoriginal-price{{ item.originalPrice }}/span /div el-button typedanger sizemini click.stopaddToCart(item.id)加入购物车/el-button /div /div购物车的数量管理如果用 Vuex会比较优雅组件间共享状态不混乱。但我考虑到源码的学习性用的是 Vuex 模块化存储购物车 badge 数量真正购物车内容从后端接口获取。点击加入购物车调接口成功后发一个 Vuex action 刷新购物车角标。这样商城基本不需要做本地购物车缓存始终以服务端数据为准。商品详情页会展示相册图JSON 数组切换大图、选择数量、立即购买和加入购物车两个按钮。立即购买本质上也是进入结算页我建议直接复用购物车结算页把“立即购买”的商品临时构建成一条购物车数据即可。4.4 后台管理页面实现后台管理页面用一个总体的Layout布局左侧菜单、右侧内容区。路由配置时后台页面统一挂在/admin下并用路由守卫检查当前用户的role字段router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.path.startsWith(/admin)) { const userInfo JSON.parse(localStorage.getItem(userInfo) || {}) if (!token) { next(/login) } else if (userInfo.role ! 1) { next(/) } else { next() } } else { next() } })商品管理页用el-table展示商品列表行内提供编辑、上下架按钮顶部有新增按钮。点新增或编辑弹出一个el-dialog里面是商品表单包含分类选择用el-select、图片上传用el-upload组件、富文本详情可以用 wangEditor 或者简单的el-input typetextarea。图片上传组件上传成功后把返回的 URL 回填到表单的cover字段这样数据库存的是可直接访问的图片地址。订单管理页需要在订单列表展示订单状态不同状态显示不同标签颜色并提供“发货”操作按钮。发货操作调用后端接口后前端先做一次列表刷新也可以用 WebSocket 做实时刷新但对本项目来说没必要。5. 常见问题与排查技巧实录这个部分我整理了我实际开发和用户反馈中最常踩的坑按问题现象、原因、解决方案的方式写基本可以当成速查表用。5.1 前端请求跨域报错现象前端http://localhost:8080的页面去请求http://localhost:8080/api/login浏览器控制台报Access to XMLHttpRequest at http://localhost:8080/api/... from origin http://localhost:8080 has been blocked by CORS policy。原因前后端两个端口不同浏览器同源策略拦住了跨域请求。解决方案开发环境用 Vue CLI 的 devServer 代理前端请求写相对路径/api由 Node 代理转发到 Java 后端// vue.config.js module.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }生产环境用 Nginx 反向代理把/api路径转发到 Java 服务端口。这两种方案都比在后端写CrossOrigin注解好因为后端接口直接允许所有来源在线上有安全隐患代理方案对前端是透明的。5.2 MyBatis 查询结果字段全为 null现象明明表里有数据返回的实体对象里却有一半字段是 null尤其是createTime、userName这种带下划线的字段。原因没有开启驼峰映射或者实体类字段名和表字段名完全对不上。解决方案在application.yml中开启map-underscore-to-camel-case: true。还有一种办法是在 XML 中使用resultMap显式映射字段但能开全局配置就不要写一堆 resultMap。5.3 上传图片超过大小限制报错现象上传大图时报org.springframework.web.multipart.MaxUploadSizeExceededException。原因SpringBoot 默认的最大上传文件大小是 1MB一个服装商品详情页的商品图容易超过。解决方案在配置里调大限制spring: servlet: multipart: max-file-size: 10MB max-request-size: 20MB同时建议前端在el-upload的before-upload钩子里先检查文件大小和格式拦截不合理的上传请求减少后端压力。5.4 MySQL 8.0 连接报错现象启动项目时报com.mysql.cj.exceptions.CJException: The server time zone value йʱ is unrecognized或Public Key Retrieval is not allowed。原因MySQL 8.0 的驱动变成了com.mysql.cj.jdbc.Driver且默认时区和加密规则和 MySQL 5.x 不一样。解决方案连接串加上时区参数并指定allowPublicKeyRetrievaltruespring: datasource: url: jdbc:mysql://localhost:3306/shop_db?serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltruecharacterEncodingutf8 username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver如果你本机是 MySQL 5.7驱动用com.mysql.jdbc.Driver也行但我统一建议新项目直接用 8.0并用 8.0 的驱动。5.5 前端 JS 数字精度导致主键丢失现象后端返回的 ID 是 19 位的 Long前端处理之后最后两位变成 00删除或编辑时操作了错误数据。原因JavaScript 的 Number 类型安全整数范围是2^53 - 1约 9 千万亿超过这个范围会丢失精度。数据库自增主键或者雪花算法生成的长 ID 很容易超这个范围。解决方案让后端把需要传给前端的 Long 型 ID 序列化为字符串。在 SpringBoot 中可以写一个 Jackson 配置把 Long 统一转 String。前端拿到字符串类型的 id 以后就不会丢精度。5.6 订单提交库存对不上现象多个用户几乎同时下单库存有时会变负数有时订单金额和商品不一致。原因下单逻辑没有做并发控制或者扣库存用了查出来再更新先 select 再 update并发下出现覆盖写。解决方案扣库存必须用UPDATE ... SET stock stock - #{num} WHERE stock #{num}这种原子操作事务注解加在需要保证一致性的方法上至于防止一个用户重复提交订单可以在生成订单前查一下该用户最近是否有相同的待付款订单。5.7 打包后前端页面白屏现象Vue 项目npm run build之后把 dist 里的文件拷到 SpringBoot 的static目录启动后打开首页白屏或者刷新 404。原因前端路由用了 history 模式后端没有配置 fallback 到index.html或者打包的前端资源路径配错了。解决方案Vue 打包时把publicPath设置为相对路径./或者干脆不用 history 模式用 hash 模式刷新不会 404。对于部署到 Tomcat/SpringBoot 的情况优先用 hash 模式省心。6. 项目部署与上线实践源码能跑起来只是第一步真正把一个商城系统部署到服务器上还有不少门道。这一节我按照实际部署的顺序记录下来。6.1 前端打包与静态资源位置先在后端项目里创建一个webapp目录或者在resources/static把前端编译出来的index.html、js/css放进去。实际上我更推荐维护一个独立的shop-web前端工程上线时独立部署通过 Nginx 做静态服务器和反向代理这样前后端解耦最彻底。前端构建命令是npm run build生成的dist目录包含index.html和static资源文件夹。把dist整个上传到服务器例如/usr/share/nginx/html/shop。Nginx 配置参考server { listen 80; server_name your.domain.com; # 前端页面 location / { root /usr/share/nginx/html/shop; index index.html; try_files $uri $uri/ /index.html; } # 后端接口反向代理 location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # 上传的图片访问 location /upload/ { alias /home/shop/upload/; } }try_files配置是 history 路由模式的必须项务必保留。6.2 后端打包为 Jar 并启动后端打包前确认application.yml里的数据库配置改成服务器上的 MySQL 信息。执行mvn clean package -DskipTests打包成功后target目录下会有shop-server.jar。上传到服务器用java -jar启动nohup java -jar shop-server.jar --server.port8080 --spring.profiles.activeprod logs/shop.log 21 这里我把端口和环境参数直接放在启动命令里而不是改死在配置文件方便以后部署多套环境。生产环境建议用 systemd 管理 Java 进程崩溃后自动拉起[Unit] DescriptionShop Server Afternetwork.target [Service] ExecStart/usr/bin/java -Xms512m -Xmx512m -jar /home/shop/shop-server.jar --server.port8080 Restarton-failure Userroot [Install] WantedBymulti-user.targetXms512m -Xmx512m表示堆内存初始和最大 512MB对于这个规模的商城系统足够了不用随意给 2G。6.3 数据库初始化与线上数据准备上线前把本地sql目录里的建库脚本导入服务器 MySQLmysql -u root -p shop_db shop_db.sql然后执行几条初始化 SQL把管理员账号和默认分类造好。管理员账号的密码字段记得用 BCrypt 加密后的字符串直接在 SQL 里写明文是极其危险的一旦数据库泄露所有后台账号直接暴露。6.4 线上排查三板斧部署完成后如果接口异常我一般按下面的顺序排查看 Java 日志tail -f logs/shop.log有没有 SQL 报错、空指针。看 Nginx 错误日志/var/log/nginx/error.log确认是不是代理转发问题。curl 直连后端接口curl http://127.0.0.1:8080/api/product/list?pageNum1pageSize10绕开 Nginx 测试后端本身是否健康。这套流程走完90% 的问题能定位到是网络层、代理层还是应用层。结尾的一点大实话这里我特别想多说一句拿到任何一套“SpringBootVue商城管理系统源码”都不要急着去改功能先把它跑通然后按着“注册登录 → 浏览商品 → 加入购物车 → 模拟下单 → 后台发货”这个完整业务链路走一遍。只有亲手把十几个后端接口和十几个前端页面串成一条完整链路你才会真正理解哪些地方是设计得好的哪些地方是你自己的业务必须要改的。我自己的习惯是拿到源码第一周只做三件事跑通流程、看懂订单状态流转、画出数据库关系图。这三件事做完你可以在这个骨架上加入会员等级、优惠券、秒杀、积分商城等等你会发现一切都有章可循。这套系统我会持续完善后续也可能拆解更多细节和扩展玩法如果你也正在折腾商城项目希望这篇笔记能让你少走点弯路。
返回列表