尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

前后端分离图书电商系统实战:SpringBoot+Vue+MyBatis+MySQL部署全解析

前后端分离图书电商系统实战:SpringBoot+Vue+MyBatis+MySQL部署全解析 前后端分离的图书电商系统SpringBoot Vue MyBatis MySQL这套组合在Java后端圈子里几乎成了标配。我最早接触这个技术栈组合是在给一个学校社团做图书漂流站管理系统的时候当时前后端还是用模板引擎渲染页面改一个按钮样式都要重启服务别提多难受了。后来完整重构了一版前后端分离的图书电商项目顺手也把部署流程全部记录下来。这篇文章就围绕这套完整源码把整体设计思路、核心功能拆解、踩过的坑和部署实操从头到尾讲清楚希望给准备做类似毕业设计或者Java技术栈练手的同学一些参考。这个项目的定位是一套可直接运行的图书电子商务网站系统包含前台用户购书、后台管理员管书两大模块覆盖了用户注册登录、图书浏览检索、购物车管理、订单生成、库存扣减、后台图书管理、分类管理、用户管理和订单处理这些常规电商闭环。适合正在学SpringBoot和Vue、想找完整实战项目理解前后端交互的人也适合需要一套能交差、能演示、代码结构清晰的课设/毕设项目的人。1. 整体设计与技术选型思路1.1 为什么选前后端分离架构早些年做Web开发主流的做法是服务端渲染JSP或者Thymeleaf模板直接在后端拼接HTML返回给浏览器。这种方式在项目规模小的时候挺顺手但一旦页面交互变复杂前后端代码纠缠在一起改前端样式可能弄崩后端逻辑联调效率低。前后端分离的核心变化是前端只负责页面渲染和用户交互后端只提供JSON格式的数据接口双方通过HTTP协议约定好的接口文档通信。图书电商这个场景前台需要频繁更新购物车、实时计算订单金额、动态渲染图书列表后台需要管理表格数据、处理弹窗表单这种交互密集型的业务天然适合前后端分离。而且前后端分离之后前端可以独立部署在Nginx上后端以Jar包形式运行在服务器上各自扩容互不影响。对于学习而言分离架构也能让你把Vue的组件化开发和后端接口设计两套技能分开学透定位问题的时候边界特别清楚。1.2 技术栈选型背后的考量后端选择SpringBoot核心原因是它解决了SpringMVC时代大量繁琐的XML配置问题。以前搭建SSM项目光配置文件就得写五六份SpringBoot的自动配置机制让项目可以“零配置”跑起来内嵌Tomcat让部署变成一条java -jar命令。项目里用到Spring Web做接口层Spring Security或拦截器做登录校验Spring Validation做参数校验这些都是SpringBoot的生态优势。持久层选MyBatis而不是JPA是因为图书电商系统的SQL场景比较适合MyBatis。比如图书搜索需要多条件动态拼接SQL图书列表需要分页查询订单统计需要多表联查MyBatis的XML映射文件可以精确控制每一条SQL语句复杂查询写起来比JPA的自动生成SQL要稳得多。当然MyBatis的缺点也很明显比如字段映射配置容易漏、二级缓存容易踩坑这个在后面章节我会详细说踩过的坑。Vue选2还是选3这个项目源码如果基于Vue 2搭配Element UI组件库是最成熟的组合生态资料多遇到问题搜一下就有答案。如果基于Vue 3组件库可以选Element Plus。实际上对于图书电商这种中后台项目Vue 2 Element UI和Vue 3 Element Plus没有本质区别核心是掌握组件化思维、Vue Router路由管理、Vuex或Pinia状态管理、Axios请求封装这四块。数据库选MySQL免费、稳定配合Navicat或者命令行工具管理数据都很方便。1.3 系统功能模块拆解整个系统按用户角色分为前台和后台两条线。前台面向普通用户核心功能有注册登录、图书浏览首页推荐、分类筛选、关键词搜索、图书详情查看、加入购物车、购物车管理数量修改、删除、勾选结算、订单生成与支付模拟、个人中心订单列表、地址管理、个人信息修改。这里要重点说说购物车和订单的联动通常做法是购物车数据存前端localStorage结算时把勾选的图书和数量一次性提交给后端生成订单。这种做法减少了对后端购物车表的频繁读写比较适合轻量级项目。后台面向管理员核心功能有管理员登录、图书管理新增、编辑、上下架、库存调整、图书分类管理、订单管理订单状态流转待付款、待发货、已发货、已完成、已取消、用户管理用户列表、禁用启用。后台通常也是单页应用通过路由守卫控制访问权限只有管理员账号才能进入后台页面。2. 核心实现细节与解析2.1 数据库设计的关键决策图书电商的数据库表主要围绕用户、图书、分类、订单、订单详情这几张核心表展开。用户表存账号密码和基本资料密码千万别明文存储我见过太多课设项目把密码直接写进数据库这是极其危险的做法。至少用MD5加盐或者BCrypt加密Spring Security自带BCryptPasswordEncoder直接用就行。图书表的核心字段包括书名、作者、出版社、ISBN编号、原价、售价、库存数量、销量、封面图片地址、上架状态、分类ID、图书简介。关键点在于封面图片不要存二进制数据到数据库存图片URL地址就行图片文件单独存在服务器目录或者对象存储里。数据库里存URL还有一个好处就是后续换CDN加速或者换图床只需要改数据库里的地址不用动代码。订单表需要区分主表和详情表。主表存订单编号、用户ID、订单总金额、订单状态、收货人信息、下单时间、支付时间、发货时间等。详情表存订单ID、图书ID、购买数量、成交单价。这种主从表设计是电商项目的基础因为一个订单可能包含多本图书主表一条记录对应详情表多条记录。订单编号不要用数据库自增ID直接暴露给用户容易被人遍历订单建议用时间戳加随机数的形式生成比如202505121030001234这种20位左右的编号。2.2 SpringBoot后端架构与MyBatis集成后端项目建议按controller、service、mapper三层结构分包另外加一个config包放配置类common包放统一返回结果和异常处理。Controller层只做参数接收和结果返回Service层写业务逻辑Mapper层负责SQL操作。我见过很多新手把业务逻辑全写在Controller里看起来跑通了但后续维护是真的痛苦改一个校验逻辑要翻半天代码。统一返回结果是前后端分离项目里特别容易忽略的点。前后端分离之后前端需要知道请求是成功还是失败失败的原因是什么。我习惯定义一个Result对象包含code、message、data三个字段code为200表示成功其他code表示各种错误状态。配合全局异常处理器Controller里不用每个方法都写try-catchService层抛出业务异常后由全局处理器统一转换为标准格式返回给前端这样接口的响应格式始终一致。MyBatis集成需要注意以下几点mapper接口和XML文件必须在同一个包路径下或者在application.yml中配置mapper-locations指定位置实体类字段和数据库字段的映射如果命名不一致一定要在XML里写清楚resultMap或者开启驼峰自动映射map-underscore-to-camel-case: true动态SQL是MyBatis最实用的功能图书搜索多条件查询一定要用if标签拼接条件用${}这种字符串拼接存在SQL注入风险参数占位必须用#{}分页查询建议用PageHelper插件一行代码就能完成分页但要注意PageHelper的线程安全问题每执行一条分页查询后要确保PageHelper.startPage(pageNum, pageSize)紧跟其后的第一条SQL就是你要分页的查询2.3 Vue前端核心实现Vue前端项目用Vue CLI或者Vite初始化配好Vue Router和Axios就可以开始写页面了。图书电商前端的核心页面包括首页、图书列表页、图书详情页、购物车页面、订单结算页、订单列表页、后台管理页等。Axios请求封装是前端项目的基建工作。我会在utils目录下创建一个request.js实例化Axios并配置baseURL和请求超时时间然后添加请求拦截器和响应拦截器。请求拦截器里从localStorage取token放到请求头响应拦截器里统一处理业务codecode不为200时用Element UI的Message提示错误信息401时跳转登录页。这样业务代码里只需要调用封装的request方法不用每个页面都重复处理错误。购物车模块有两个实现方案。方案一是将购物车数据存在后端数据库和Redis里登录后请求接口获取购物车列表操作实时同步后端。方案二是将购物车数据存在localStorage里结算时一次性提交。如果图省事且对数据一致性要求不高方案二就够了。但如果想做类似跨设备同步购物车这种功能还是老老实实走后端方案。我之前做的小型图书电商项目用的方案二体验上没问题代码量少了不少。2.4 前后端接口设计与跨域处理前后端分离项目最容易踩的坑就是跨域。前端跑在http://localhost:8080后端跑在http://localhost:9090浏览器会拦截跨域请求。解决办法有几种后端加上CrossOrigin注解仅限局部生效每个Controller都要加麻烦后端配置WebMvcConfigurer统一处理CORS全局生效推荐前端配置Vite或Webpack代理把/api的请求代理到后端地址开发环境推荐生产环境不适用生产环境用Nginx反向代理前端请求同源地址由Nginx转发到后端端口最推荐的方案下一节部署的时候详细讲接口设计方面RESTful风格在图书电商场景下也很实用。用户相关用/api/user/register、/api/user/login图书相关用/api/book/list、/api/book/detail/{id}购物车相关用/api/cart/add、/api/cart/list、/api/cart/delete/{id}订单相关用/api/order/create、/api/order/list。接口路径清晰前端调用的时候一目了然。3. 完整部署实战从源码到线上运行3.1 环境准备与MySQL数据库初始化部署的第一步是准备好环境。服务器或本地电脑需要安装JDK 1.8或以上版本推荐JDK 8兼容性最高、Maven 3.6以上、MySQL 5.7或8.0、Nginx如果要做前后端分离部署。Node.js环境在打包前端时才需要如果只是部署已经打包好的前端文件服务器上不需要Node。数据库初始化这里我要多说几句。很多新手拿着SQL脚本直接执行报错了不知道怎么回事。建议先用命令行工具登录MySQL创建一个专用数据库设置好字符集为utf8mb4这样中文才不会乱码mysql -u root -p CREATE DATABASE bookstore DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE bookstore; source /path/to/bookstore.sql;执行完SQL之后检查一下核心表的数据是否导入成功用SELECT COUNT(*) FROM book;看看图书数量是否和预期一致。如果SQL脚本里有外键约束导入前要注意表创建顺序先建主表再建从表否则外键关联会报错。另外MySQL 8.0之后默认的加密规则是caching_sha2_password老版本的应用连接时可能报认证插件错误此时需要在MySQL执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 密码;来兼容。3.2 后端项目打包与启动后端项目打包要用Maven。修改application.yml里的数据库连接配置把URL、用户名、密码改成自己环境的值。这里有个细节配置文件里不要用localhost连接数据库建议用127.0.0.1因为某些环境下localhost解析走IPv6的::1数据库如果只监听了IPv4就会出现连接超时。配置确认无误后在项目根目录执行打包命令mvn clean package -DskipTests打包成功后target目录下会生成一个bookstore.jar文件。启动前建议先检查端口是否被占用比如后端配置的端口是9090执行netstat -tlnp | grep 9090没有输出说明端口空闲可以启动应用java -jar bookstore.jar --spring.profiles.activeprod我在实际部署中会建议生产环境用nohup方式启动这样关闭终端后服务还能继续运行nohup java -jar bookstore.jar logs/bookstore.log 21 启动日志里看到Tomcat started on port(s): 9090这一行说明后端启动成功。此时用浏览器访问http://服务器IP:9090/api/book/list如果能返回JSON数据说明数据库连接和Mapper层都正常。3.3 前端项目构建与Nginx配置前端项目构建前要修改API请求地址的配置。开发环境通常配置成http://localhost:9090但生产环境不能写死IP或端口否则前端跨域和地址耦合问题会很难受。我在项目里习惯用环境变量区分# .env.development VUE_APP_BASE_API /api # .env.production VUE_APP_BASE_API /api两个环境都配成/api区别在于开发环境由Vite代理转发到后端生产环境由Nginx转发到后端。这样前端代码里永远只用相对路径换服务器也不用改前端代码。执行构建命令npm install npm run build构建成功后dist目录里就是所有静态资源文件。把这个dist目录整个上传到服务器比如放到/usr/share/nginx/bookstore-web/下面然后修改Nginx配置server { listen 80; server_name your_domain_or_ip; # 前端静态资源 location / { root /usr/share/nginx/bookstore-web; index index.html; try_files $uri $uri/ /index.html; } # 后端接口反向代理 location /api/ { proxy_pass http://127.0.0.1:9090/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }这里最核心的是try_files配置。Vue Router用的是history模式如果用户直接访问http://域名/book/detail/1这种路径Nginx找不到对应的物理文件会返回404。配置try_files $uri $uri/ /index.html之后找不到就返回index.html由前端路由接管解析刷新页面就不会白屏了。改完配置执行nginx -t检查语法然后nginx -s reload重载配置访问http://服务器IP就能看到图书商城首页了。打开浏览器F12调试切到Network面板点击一个能发起请求的按钮如果接口请求路径是/api开头、状态码200、返回JSON数据说明整个前后端链路贯通了。3.4 一页纸部署检查清单部署完之后建议做一个完整冒烟测试我整理了一个检查清单按顺序走一遍基本能排除90%的问题检查项预期结果常见问题前端首页访问页面正常渲染无白屏Nginx配置错误、静态文件路径不对接口连通性Network面板/api请求返回200反向代理路径配置错误、后端未启动数据库连接图书列表能加载数据库密码错误、字符集不匹配图片加载图书封面正常显示图片路径是绝对地址、跨域登录注册能收到验证码/能登录Token生成失败、拦截器误拦截购物车操作添加/删除/结算正常前端状态管理问题、接口参数缺失订单流程下单后订单状态流转正常库存扣减逻辑问题、事务未处理4. 常见问题与排查技巧实录4.1 数据库连接类问题MySQL连接这块我踩过的坑最多挑几个典型案例拿出来说说。第一个是error 2002 (HY000): Cant connect to local MySQL server through socket /tmp/mysql.sock。这个问题多半是MySQL服务没启动或者socket文件路径不对。环境上先后执行systemctl start mysql或service mysql start看看服务状态是不是running。如果服务正常还是报错检查一下MySQL的socket配置路径和客户端连接默认路径是否一致可以在连接命令里显式指定端口和hostmysql -h 127.0.0.1 -P 3306 -u root -p。第二个是MySQL 8.0的SSL连接错误。控制台报SSL connection error: unknown error number或者Establishing SSL connection without servers identity verification is not recommended。MySQL 8.0默认开启SSL加密连接JDBC驱动连接时会尝试建立SSL通道如果证书配置不对就会报错。解决办法是在JDBC连接串后面加上useSSLfalseallowPublicKeyRetrievaltrue。allowPublicKeyRetrievaltrue这个参数也非常关键MySQL 8.0用caching_sha2_password插件时如果连接不是SSL通道需要这个参数允许客户端获取公钥来加密传输密码。第三个是Access denied for user rootlocalhost。这个大概率是密码错误或者用户没有远程访问权限。如果代码部署在服务器本地localhost就够了如果从一个服务器连接另一台服务器的数据库需要给用户授权远程访问权限GRANT ALL PRIVILEGES ON bookstore.* TO bookuser% IDENTIFIED BY password; FLUSH PRIVILEGES;%表示允许任意IP访问。生产库这种授权方式要谨慎最好还是按实际IP段来限制。4.2 前端部署与跨域问题前端部署最典型的症状是页面能打开接口报403或404。403大概率是Nginx的location匹配冲突检查一下是不是有多个location块把/api路径吃掉。404则要看后端服务是否正常运行、代理目标地址是否正确。还有一个特别容易忽视的场景接口是通的但页面白屏。这种情况多半是前端代码里有console报错最常见的报错是Cannot read property of undefined。原因可能是后端返回的数据结构和前端预期不一致。调试这种问题我的经验是先打开控制台Network面板看接口返回的JSON结构再对照前端代码里对数据的引用路径很快就能定位。关于跨域还有一个开发环境的问题。如果你用Vite做开发服务器配置代理的时候一定要写对// vite.config.js server: { proxy: { /api: { target: http://localhost:9090, changeOrigin: true } } }changeOrigin必须设置为true否则后端拿到请求的host还是localhost:5173Vite默认端口某些场景下后端做URL重定向时会拼出错误地址。开发环境跨域和线上环境跨域是两套配置逻辑别混在一起排查。4.3 MyBatis相关的坑MyBatis的坑主要集中在字段映射、动态SQL和缓存三个方向。先说字段映射问题。实体类里定义了一个bookName属性数据库字段叫book_name如果配置了驼峰自动映射MyBatis会自动把book_name映射到bookName。但如果没开驼峰映射又没写resultMap查询结果就是纯null。很多新手排查半天不知道数据去哪了。开发项目一开始就建议在application.yml里加上mybatis: configuration: map-underscore-to-camel-case: true再说动态SQL的问题。多条件查询图书时如果直接用${}拼接参数用户输入的内容会被当作SQL代码执行。比如用户在书名搜索框输入1 OR 11如果用的是${bookName}相当于执行了SELECT * FROM book WHERE book_name 1 OR 11整张表的数据全查出来了。用#{}包裹参数后MyBatis会预编译SQL参数被当作字符串字面量处理这样就安全了。记住一个准则写动态SQL时永远优先使用#{}${}只有极少数场景才允许使用比如按字段名动态排序。最后是二级缓存问题。MyBatis的二级缓存默认是关闭的如果贸然开启而且操作了图书表的数据缓存里残留旧数据用户看到的信息就是过期的。图书电商这种数据一致性要求高的场景不建议开启二级缓存。一级缓存在同一个SqlSession内有效正常情况下问题不大但如果你在Service里用到了多个Mapper查询又不是在同一个事务里可能出现缓存查询不到最新数据的问题。如果对缓存机制吃不透最简单的做法就是把查询接口的时间戳参数加进去避免缓存串数据或者干脆关闭缓存靠MySQL自身的缓冲来兜底。4.4 Vue前端开发高频报错处理Vue开发中我遇到频率最高的报错有这么几个第一个是组件引入但页面空白。原因通常是组件没有正确的export default或者路由配置里component路径写错了。用Vue CLI创建的项目路由懒加载写法是component: () import(/views/Home.vue)如果路径少写一个s或者大小写不对编译能过但运行时白屏。第二个是npm install依赖安装报错。常见原因是Node.js版本和依赖包的版本不兼容。Vue 2项目建议Node.js 14到16Element Plus或Vue 3项目建议Node.js 16以上。npm install遇到peer dependency冲突时可以先删除node_modules和package-lock.json重新安装或者用npm install --legacy-peer-deps跳过依赖版本冲突检查。第三个是Vue DevTools插件无效。登录页、路由跳转这种逻辑用DevTools调试非常方便但经常会发现插件装了但检测不到Vue实例。这是版本匹配问题Vue 2要用Vue DevTools 5.xVue 3要用Vue DevTools 6.x两个版本不能混用。还有一点如果用生产环境部署的前端页面Vue DevTools默认是禁用的调试必须在开发环境跑。4.5 常见问题速查表整理一个排查速查表实际开发中遇到下面的报错信息直接对照找方向报错现象排查方向解决方案java.sql.SQLException: Access denied账号密码错误检查application.yml数据库配置报错Communications link failure数据库地址/端口不通确认MySQL服务状态、防火墙放行3306前端接口返回404Nginx代理路径错误检查location /api/配置和proxy_pass地址前端接口返回405请求方式不匹配确认POST和GET类型是否一致登录后刷新页面失效Token未持久化确认localStorage/sessionStorage存储页面刷新404路由history模式Nginx未配置Nginx添加try_files配置图片不显示图片路径跨域或不存在检查封面地址是否可访问、Nginx是否代理图片路径后台接口400参数缺失或格式错误对照接口文档检查请求参数订单库存负数未做并发控制使用乐观锁或悲观锁处理并发扣库存Vue组件不渲染组件未注册或路由路径不对检查import路径和export default5. 源码学习路径与二次开发建议这套源码拿到手不建议直接跑起来就算完我建议按这个路径去读代码收获会大很多第一步先读懂项目结构。把controller、service、mapper三层的包结构搞清楚每个类的作用是什么接口之间的调用关系是怎么串起来的。给你一个技巧用IDEA的Show Diagram功能把Service层的依赖图画出来整体脉络会清晰很多。第二步挑一个完整业务链路跟读。比如图书下订单这个动作从前端点击提交按钮开始请求到了后端哪个ControllerController调了哪个Service方法Service里哪些地方开了事务Mapper里的SQL是怎么写的一步一步跟下来整个前后端交互链路就通了。第三步动手改功能。改需求是理解代码最快的路径。比如要求图书列表按销量降序排列就去把查询SQL里的ORDER BY改一下要求用户注册时增加邮箱字段就去数据库加字段、实体类加属性、前后端加表单项这一套改下来你对这个项目代码的熟悉程度会明显提高。二次开发方面有几个方向很值得扩展引入Redis做图书分类缓存和购物车缓存减少数据库压力引入Elasticsearch做图书全文搜索替换现有的模糊查询接入真实支付SDK替换当前的模拟支付逻辑引入消息队列处理订单超时取消替换当前的定时轮询方案增加用户收藏、图书评分评论、优惠券系统这些电商通用功能这些方向每一个都能作为独立的扩展项目来做也是面试时可以展开讲的技术亮点。结合我个人的实操经验最后再强调几个容易走弯路的地方。第一MyBatis的XML文件路径配置不要猜直接用classpath*:mapper/*.xml这种通配符省心得多。第二SpringBoot版本别追新2024年前后推荐用2.7.x系列配JDK 8最稳。第三前端打包之前先把Node版本锁定好用.nvmrc文件固定版本能让团队协作和后续重新部署省掉一堆兼容性问题。第四部署上线前后一定多测几遍完整购物流程从注册登录、加购、下单到后台发货每个环节都走通一遍才敢把项目展示给别人看。这套流程走完前后端分离项目的开发到部署链路基本就能做到胸有成竹了。
返回列表