尧图精选

基于Web的酒品商城购物系统设计与实现:Spring Boot+Vue前后端分离实践

🕒 发布时间:2026/10/2 14:59:14 📁 来源:尧图网络
做计算机毕设选题的时候很多人一看到“基于web的酒品商城购物系统的设计与实现”这种题目就开始纠结是先把Java Web基础啃完还是先学Vue其实这类题目是最典型、也最稳的电商类毕设核心就一句话——把用户、商品、购物车、订单、后台管理这几件事做扎实论文和答辩内容就都有了。我这两年帮人排查过的毕设项目里酒品商城和图书商城、办公用品商城在业务逻辑上几乎同源区别只在于商品字段和几个特别页面。今天这篇就围绕“基于web的酒品商城购物系统”这个题目把我自己常用的一套设计与实现思路完整过一遍顺便把那些代码里容易踩的坑一次说清楚。适合正在准备毕设、想找一个能真正跑起来并且能讲清楚的web项目的同学参考。1. 别急着写代码先吃透需求与角色划分1.1 这个系统到底要做什么先把这个题目拆开看基于web说明通过浏览器访问酒品商城说明是销售酒类商品的电商平台购物系统说明核心流程是“逛商品—加购物车—下单—收货”。如果只是照着网上的源码跑起来就以为完事了答辩时一问三不知那才真的麻烦。所以我习惯先把需求翻译成用户能感知的功能。酒品和其他商品不一样的点在于品类属性更强浓香、酱香、清香、葡萄酒、啤酒不同分类下的用户筛选逻辑不同而且酒品详情页通常要展示酒精度、净含量、产地、年份这些特征。这意味着数据库设计时不能只做简单的“商品表”还要考虑扩展字段。虽然毕设论文一般不要求做到电商中台的粒度但字段设计上把容量、酒精度、产地这几个单独列出来答辩时就能讲出“我考虑了行业特殊性”。从角色上看整个系统分为游客、注册用户、管理员。游客只能看商品和搜索注册用户除了看还能加购物车、下单、管理地址、查看订单管理员负责商品上架、分类维护、订单发货和用户状态管理。这个划分清晰了权限控制才有依据。1.2 用户端与后台管理端的功能清单我一般会让学生先把功能清单做成表格再据此拆页面和接口。这样既方便安排开发进度也方便写到论文的“需求分析”章节。端功能模块具体操作用户端账号注册、登录、退出密码加密存储用户端商品浏览首页轮播、商品分类导航、酒品列表、搜索、详情用户端购物车加入购物车、修改数量、删除、全选结算用户端订单确认订单、选择收货地址、提交订单、模拟支付、订单列表、取消订单、确认收货用户端个人中心个人信息修改、收货地址管理管理端商品管理酒品增删改查、上下架、库存调整、上传图片管理端分类管理酒品分类新增、改名、删除管理端订单管理查看订单、按状态筛选、发货操作管理端用户管理查看用户列表、禁用/启用用户这里有一个容易被忽略的点订单状态不能只有“已支付/未支付”两个状态。电商系统天然要求订单有生命周期我建议至少设计成“待付款、待发货、待收货、已完成、已取消”。一方面是因为业务真实另一方面是答辩时你可以画一张状态流转图讲清楚哪个状态下用户能做什么操作、管理员能做什么操作这属于很好的加分内容。1.3 边界控制哪些功能可以砍掉做毕设最怕的就是需求失控。很多同学一开始想做一个“小淘宝”优惠券、秒杀、评论、直播带货全都要最后代码攒了几千行Bug也多得改不完。我个人的建议是主流程必须完整营销功能尽量不做。可以砍掉的功能包括优惠券、满减活动、秒杀、购物车跨端同步、物流轨迹查询、在线客服、商品评价。这些功能不是不重要而是它们会引入大量额外的前端交互和后端状态处理。比如秒杀就要考虑高并发库存这超出了毕设的范畴。你可以在论文的“系统不足与展望”里写“后期可扩展优惠券模块”反而显得你明白系统的边界在哪里。如果学有余力建议优先做两个“轻量加分项”一个是后台的简单数据统计比如商品总数、今日订单数、订单总金额另一个是订单的模拟支付流程。这两个东西工作量不大但能让系统看起来完整很多。2. 技术选型为什么我说“Spring Boot Vue MySQL”是省心组合2.1 前后端分离与单体JSP的取舍如果你翻到五年前的毕设源码大量题目还是Spring MVC JSP JSTL那一套。JSP时代不是不能用而是现在做项目前后端分离已经是团队协作的主流方式。用JSP最大的问题在于前端页面和后端逻辑耦在一起改个页面样式就要重新部署项目而且答辩时也很难说清楚“接口设计”这件事。前后端分离则完全不同后端专心提供JSON接口前端专心渲染页面。两边通过HTTP交互开发时可以并行部署时也灵活。对毕设来说采用前后端分离还有一个实际好处你很容易用Postman或Apifox来演示接口答辩时把请求和返回数据一展示老师立刻明白你的系统架构是清晰的两层结构。当然如果你Java基础确实比较薄弱跟前端分离部署Nginx也让你头疼退一步用Spring Boot Thymeleaf也可以。Thymeleaf比JSP现代而且能实现模板继承关键是它仍然是个服务端渲染方案写起来更简单。只是后续讲接口层面的内容会少一点。选哪种不丢人但如果你问我我优先推荐前后端分离。2.2 后端为什么用Spring BootSpring Boot不是靠“约定大于配置”这句话火的它是真的把项目启动成本降下来了。你创建一个Spring Boot项目内置Tomcat写好Controller就能跑不需要再单独装Tomcat、配web.xml、手动打war包。这对于毕设周期来说非常重要。版本选择上我建议用Spring Boot 2.7.x。原因很简单网上资料最多跟MyBatis-Plus、Spring Security等组件的兼容性最稳。如果你电脑上装的是JDK 8那2.7.x非常合适如果装的是JDK 17也可以用2.7.x它支持到JDK 17。Spring Boot 3.x现在也成熟了但它要求JDK 17起而且部分老博客里的配置会失效容易踩坑。毕设求稳没必要追新。配套的持久层框架我建议直接用MyBatis-Plus。它既保留了MyBatis的SQL控制力又提供了BaseMapper的通用单表CRUD和分页插件。对于酒品商城这种系统90%的数据库操作都是单表查询和简单联表MyBatis-Plus能让你少写大量重复的XML映射文件。2.3 前端为什么用Vue而不是纯HTML纯HTML CSS JavaScript也能写商城前台而且文件结构简单。但问题在于商品列表的状态、购物车的数量、订单确认页的数据共享用原生JS写起来到处都是DOM操作代码会越来越乱。Vue的核心价值是响应式数据绑定和组件化。你只需要维护一个JavaScript对象页面上的内容会自动跟着变这对商城类项目是刚需。我前端的推荐组合是Vue 3 Vite Vue Router Pinia Element Plus。Vite比Webpack启动快很多对新手的体验更友好Pinia管理购物车和用户登录态非常顺手Element Plus提供后台管理所需的后台表格、表单、弹窗等组件可以让你的管理页看起来有模有样。2.4 开发环境与依赖版本建议别把环境版本搞得太跳不然出现莫名其妙的问题时你都分不清是代码问题还是环境问题。我这里列一套经过验证的组合软件/框架建议版本说明JDK1.8 或 11长期支持版本兼容性好Maven3.6管理后端依赖Spring Boot2.7.18稳定且资料丰富MyBatis-Plus3.5.x配合Spring Boot 2.xMySQL5.7 或 8.0使用InnoDB引擎Node.js16 或 18运行前端工程Vue3.x配合Vite 4/5Element Plus2.xUI组件库注意MySQL 8.0和5.7的驱动类名不同。8.0的驱动类是com.mysql.cj.jdbc.Driver5.7是com.mysql.jdbc.Driver。很多同学报错ClassNotFoundException就是因为驱动写成了老版本。3. 数据库设计酒品商城最关键的是别把关系弄错3.1 核心表结构设计这张数据库ER图是整个项目的地基。我见过太多同学把用户的收货地址直接存在用户表里把购物车记录直接存在一张大宽表里后面写代码的时候发现越写越别扭。别着急写SQL先把表之间的关系梳理清楚。主表大致有这几张用户表、分类表、酒品表、购物车表、收货地址表、订单主表、订单明细表。去掉购物车表也能做可以从购物车直接提交后把它删除但为了用户登录后能持久化购物车还是建议建表。看下单表的设计这是比较核心的部分。用户下单后订单里要记录收货人信息、订单总金额、订单状态。很多人会问为什么收货人和手机号不从用户表里取而要冗余到订单表原因很简单用户后来改了地址信息历史订单也必须保留当时的下单地址。这就是“下单时生成快照”的思路。同理订单明细表里也要冗余商品名称和商品快照价格因为酒品价格以后肯定会调整但已经创建的订单不应该受商品价格变动影响。下面是一张酒品表的SQL示例字段比普通商品多了一些酒类特有的信息CREATE TABLE t_wine ( id bigint NOT NULL AUTO_INCREMENT COMMENT 酒品ID, category_id bigint NOT NULL COMMENT 分类ID, name varchar(100) NOT NULL COMMENT 酒品名称, subtitle varchar(255) DEFAULT COMMENT 卖点副标题, main_image varchar(255) DEFAULT COMMENT 主图URL, detail text COMMENT 商品详情, price decimal(10,2) NOT NULL COMMENT 售价, stock int NOT NULL DEFAULT 0 COMMENT 库存, alcohol_content decimal(4,1) DEFAULT NULL COMMENT 酒精度%vol, volume int DEFAULT NULL COMMENT 净含量ml, origin varchar(50) DEFAULT NULL COMMENT 产地, status tinyint NOT NULL DEFAULT 1 COMMENT 状态1在售0下架, 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_name (name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT酒品表;分类表很简单就是id、分类名称、排序、创建时间。购物车表主要字段是id、用户id、酒品id、数量、加入时间可以加一个唯一约束保证同一用户同一酒品只出现一条记录。订单主表和明细表的SQL我就不贴完整了重点强调订单主表要有订单号字段订单号可以用时间戳用户id生成也可以用数据库自增主键加日期拼接但一定要保证唯一便于前后端追踪。3.2 字段设计的几个坑第一金额永远不要用float或double。0.1加0.2在浮点数里会变成0.30000000000000004结算金额一旦出现这种误差非常尴尬。Java后端用BigDecimal数据库用decimal(10,2)两个地方都堵住。第二库存字段直接用int就行但扣库存的SQL必须带条件。后面下单流程我会专门讲这里提一句永远不要先查库存再在Java代码里相减要走UPDATE t_wine SET stock stock - 1 WHERE id ? AND stock 1这种原子操作。第三字符集统一用utf8mb4。饭馆里有些酒品名称会带特殊字符比如英文商标里的符号utf8mb4才能完整存储。数据库连接串也要带上characterEncodingutf8。第四关于逻辑删除。用户表、商品表建议加一个deleted字段默认为0做删除操作时更新为1查询时自动过滤。MyBatis-Plus本身有逻辑删除的全局配置开会话时可以提一下。3.3 索引与事务考虑商城业务里商品列表查询和订单查询是高频操作。商品表除了主键索引一定要在category_id上建索引订单表要在user_id上建索引否则用户查自己的历史订单时只能全表扫描数据一多就会卡。酒品名称的模糊查询走不走索引要看你的like写法%关键词%肯定不走但如果数据量只有几百条影响不大。事务方面最核心的一条规则生成订单、扣库存、清空购物车这三个操作必须放在同一个事务里。任何一个失败前面做的操作必须全部回滚。否则就会出现用户没下单成功、库存却扣了的严重问题。在Spring Boot里只需要在Service方法上加上Transactional注解同时注意默认只捕获RuntimeException如果自己手动catch了异常然后不抛出事务是不会回滚的。4. 核心功能实现从商品列表到下单全流程4.1 前端页面路由与组件划分前端页面不需要一开始就铺开我建议按照用户操作路径去拆分。先做首页和商品列表再做详情和购物车再做订单流程最后做后台管理。这样每完成一段流程系统就能跑通一个业务闭环心里不慌。Vue Router的路由示例const routes [ { path: /, name: Home, component: HomeView }, { path: /list, name: List, component: ListView }, { path: /detail/:id, name: Detail, component: DetailView }, { path: /cart, name: Cart, component: CartView }, { path: /order/confirm, name: OrderConfirm, component: OrderConfirm }, { path: /order/list, name: OrderList, component: OrderList }, { path: /admin, name: AdminLayout, component: AdminLayout, meta: { role: admin } } ]后台管理路由需要加上守卫简单做法就是判断本地存储里的用户角色是不是admin。不是管理员就重定向到首页这样至少能拦住非管理员通过URL直接进入后台页面。真正的接口权限控制的重点还是要放在后端这个我后面说。页面组件化的细节也很重要比如商品卡片可以抽成WineCard.vue首页和列表页都复用避免改样式要改两遍。这一步虽然不起眼但代码目录结构干净答辩时也能加分。4.2 商品搜索与分页接口后端提供商品列表接口时必须支持分页。分页不是可选项是商城的基本配置。一个简单的接口设计如下RestController RequestMapping(/api/wine) public class WineController { Autowired private WineService wineService; GetMapping(/list) public ResultPageResultWineVO list( RequestParam(defaultValue 1) Integer page, RequestParam(defaultValue 12) Integer size, RequestParam(required false) Long categoryId, RequestParam(required false) String keyword) { PageWine pageParam new Page(page, size); LambdaQueryWrapperWine wrapper new LambdaQueryWrapper(); wrapper.eq(categoryId ! null, Wine::getCategoryId, categoryId) .and(keyword ! null !keyword.isEmpty(), w - w.like(Wine::getName, keyword).or().like(Wine::getSubtitle, keyword)) .eq(Wine::getStatus, 1) .orderByDesc(Wine::getCreateTime); PageWine result wineService.page(pageParam, wrapper); return Result.success(PageResult.of(result)); } }这段代码里有一个小细节status 1的过滤条件必须写上去确保下架商品不在商城展示。很多人会把“上下架”交给前端判断其实前端根本不可信后端过滤才是底线。前端传categoryId和keyword时用URL query参数size默认12正好对应一页商品展示12个小卡片的常规布局。4.3 购物车登录态与本地态怎么处理购物车有两条常见路线一种完全存在前端localStorage另一种完全存在后端数据库。我的建议是别纠结毕设做后端数据库方案。理由是你后面下单的时候要在后端重新计算金额和校验库存购物车数据如果只在前端下单逻辑就得整体从前端传购物车列表给后端前端传什么后端就信什么这本身就有安全隐患。后端购物车表的结构之前已经说过核心方法就几个加入购物车、修改数量、删除、查询用户购物车列表。加入购物车时如果同一个酒品已经在购物车里那么数量累加不要插两条记录。这个逻辑可以用唯一约束加ON DUPLICATE KEY UPDATE实现也可以在Java代码里先查一次再insert。如果你还想再简单一点可以把购物车放在Redis里使用Hash存储key是用户idfield是酒品idvalue是数量。Redis的好处是天然支持存活时间和高性能。但毕设有时候不想额外引入中间件那数据库表其实完全够用。4.4 下单与库存扣减别让超卖毁掉答辩下单是整个项目技术含量最高、也最能拿来说的部分。简单流程是这样第一步根据当前登录用户获取购物车列表第二步从购物车列表取出酒品id列表查询数据库中的最新商品信息第三步校验商品状态、库存是否充足第四步计算总金额记住用数据库里的价格不能用前端传过来的价格第五步插入订单主表和订单明细表第六步扣减库存第七步清空购物车。扣库存的SQL是防止超卖的关键UPDATE t_wine SET stock stock - #{quantity}, update_time NOW() WHERE id #{wineId} AND stock #{quantity}执行这个update语句后如果返回的影响行数是0说明库存不足直接抛出异常让事务回滚。这就是乐观锁思想的一种简化实现通过stock quantity条件确保不会把库存扣成负数。很多人喜欢先SELECT stock然后在Java代码里if判断是否大于数量再UPDATE stock stock - quantity这样在多线程同时下单时会超卖。虽然毕设一般没有高并发压测但答辩老师一定会问“你这个扣库存会不会出问题”把这条SQL拿出来讲专业度立刻不一样。下单的事务实现示例Transactional(rollbackFor Exception.class) public Long createOrder(Long userId, Long addressId) { ListCartVO cartList cartMapper.selectUserCartList(userId); if (cartList null || cartList.isEmpty()) { throw new BizException(购物车为空); } // 计算总金额 BigDecimal totalAmount BigDecimal.ZERO; for (CartVO item : cartList) { Wine wine wineMapper.selectById(item.getWineId()); if (wine null || wine.getStatus() ! 1) { throw new BizException(商品已下架 item.getWineName()); } if (wine.getStock() item.getQuantity()) { throw new BizException(库存不足 item.getWineName()); } totalAmount totalAmount.add(wine.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))); } // 生成订单 Order order new Order(); order.setOrderNo(generateOrderNo(userId)); order.setUserId(userId); order.setAddressId(addressId); order.setTotalAmount(totalAmount); order.setStatus(0); orderMapper.insert(order); // 插入明细 扣库存 for (CartVO item : cartList) { OrderItem orderItem new OrderItem(); orderItem.setOrderId(order.getId()); orderItem.setWineId(item.getWineId()); orderItem.setWineName(item.getWineName()); orderItem.setPrice(item.getPrice()); orderItem.setQuantity(item.getQuantity()); orderItemMapper.insert(orderItem); int rows wineMapper.deductStock(item.getWineId(), item.getQuantity()); if (rows 0) { throw new BizException(库存扣减失败); } } // 清空购物车 cartMapper.deleteByUserId(userId); return order.getId(); }这一步里用Transactional(rollbackFor Exception.class)显式声明所有异常都回滚不光是运行时异常这是我特别想提醒的。4.5 订单状态管理订单状态是整个商城业务的一条主线建议用整数来存状态定义做成常量或枚举。我常用的状态定义0待付款、1待发货、2待收货、3已完成、4已取消。状态流转的规则要非常明确用户下单后状态是0用户点击“模拟支付”后后端把状态从0改成1这里一定要校验当前状态必须是0不能允许把已取消的订单直接支付管理员在后台把状态从1改成2表示发货用户点击“确认收货”后状态从2改成3用户可以在待付款状态取消订单变成4。这个状态机看起来简单但很多人会写成“无条件更新状态”。比如直接写update order set status 1 where id ?那就会导致已取消的订单被支付、已经发货的订单被重复发货。正确做法是更新时带条件UPDATE t_order SET status 1 WHERE id #{orderId} AND status 0影响行数为0时提示“订单状态异常”。这个小细节值得在论文或答辩中专门提一句我通过条件更新保证状态流转的合法性。5. 这几个“加分项”值得做但不必贪多5.1 后台管理端的权限拦截大多数毕设系统的权限拦截都是用拦截器检查请求头里有没有Token。具体做法是用户登录成功后后端生成一个UUID或JWT返回给前端前端每次请求都把它放到HTTP Header里。后端写一个HandlerInterceptor在进入Controller之前检查这个Token是否存在、对应的用户是不是管理员。这里我给你一个建议不要为了省时间跳过拦截器因为“购物车、订单、后台增删改查”的接口一旦裸奔你无法回答“我这个接口怎么保证安全”这类问题。简单的拦截器代码如下public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(token); if (token null || !TokenStore.isValid(token)) { response.setStatus(401); return false; } return true; } }注意还需要区分普通用户和管理员。最简单的办法是在Token里存用户ID和角色类型如果是管理员接口再查一次用户角色做校验。这样不需要引入Spring Security也能把权限问题讲明白。5.2 文件上传酒品图片后台管理里必然要上传酒品图片。比较稳妥的实现是把上传的图片保存到服务器本地某个目录然后把访问路径存到数据库。步骤如下获取MultipartFile校验文件后缀是jpg、png还是jpeg生成唯一文件名比如UUID加原后缀写到指定目录返回/images/xxx.jpg这样的访问URL。这里要提醒两个坑第一项目部署时上传目录最好不要放在idea工作区的target目录里否则重新打包后文件会被清掉。更好的做法是配置一个绝对路径目录然后让Spring MVC的静态资源映射指向它Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/images/**) .addResourceHandler(file: uploadPath /); } }第二文件重命名绝对不能直接用用户上传的文件名否则会有路径穿越风险。虽然毕设不要求像企业一样做安全审计但不使用原始文件名是一个基本习惯。5.3 简单的支付模拟别真接支付网关很多同学纠结是不是要对接支付宝微信支付。我的建议非常明确不要接除非你只是想体验一下。真实支付需要商户号、密钥、回调地址而且涉及资金不适合毕设环境。你只需要做一个“模拟支付”页面用户点击“确认支付”后端调用一个接口把订单状态从待付款改成待发货。为了看起来严谨你还可以在订单支付记录表里插入一条支付流水金额、时间、支付方式都记录下来。这样系统照样能讲成“完整的订单闭环”并且可以在“展望”里说“目前是模拟支付后续可对接第三方支付接口”。这是非常合理的取舍。5.4 日志与全局异常处理这一个加分项成本很低收益却不小。统一返回结果对象ResultT能让所有接口的返回格式保持一致Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } }再配合RestControllerAdvice做全局异常处理把业务异常和系统异常分别返回不同的code。这样做的好处很多一是前端统一处理错误弹窗二是数据库报错不会把堆栈直接暴露给浏览器三是这属于“工程规范”层面的内容写论文时放在系统实现里能体现你的工程素养。6. 常见问题与排查技巧实录6.1 中文乱码问题中文乱码是Java Web项目的经典问题。排查顺序从外到内第一步检查数据库表字符集是否utf8/utf8mb4第二步检查数据库连接串是否有characterEncodingutf8第三步检查后端响应头Spring Boot一般默认返回UTF-8但如果用了老版本的Spring MVC可以在RequestMapping的produces里指定第四步检查前端页面meta标签。我见过最多的情况是连接串没写编码导致存进去中文变成问号。6.2 跨域问题前后端分离开发时前端跑在localhost:5173后端跑在localhost:8080浏览器会拦截后端的异步请求。解决办法有两种开发环境用Vite的proxy代理把/api请求转发到8080或者后端统一配置CORS。我更推荐前端代理方案因为它更接近生产环境的同源配置也不会暴露后端端口。但如果你写的是管理端和前台同时访问同一个后端那么直接在后端加一个CorsConfig也很常见Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }6.3 刷新页面404Vue Router使用history模式时在路由页面刷新会出现404 Not Found这是因为刷新时浏览器直接访问了/list这个路径而后端服务器上没有这个物理文件。解决办法有两个一个是把Vue Router改成hash模式URL里会带#刷新不会出问题但不美观另一个是部署时在Nginx配置try_fileslocation / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; }我一般建议在写论文反复截图时用history模式因为URL干净然后把Nginx配置放到部署文档里既解决了问题又展示了运维能力。6.4 结算金额不一致排查下单时前端展示的金额如果和后端订单金额对不上首先不要怀疑前端计算要怀疑后端有没有信任前端传入的金额。排查步骤查看下单接口入参里有没有totalAmount字段如果前端传了这个字段就说明后端又把它存进了订单表这非常危险。正确做法是后端根据商品当前价格和购物车数量重新计算前端传的金额只能用于展示。发现不一致时优先检查后端是否重新查了商品价格。6.5 数据库连接失败初学者最常见的是MySQL 8.0的时区报错The server time zone value Öйú±ê׼ʱ¼ä is unrecognized。解决办法是在JDBC连接串后面加serverTimezoneAsia/Shanghai。此外还要确认数据库驱动版本和MySQL版本要对应8.0版本的驱动不能用在5.7的旧写法上反之亦然。下面把这几个常见问题汇总成表方便你排查现象常见原因解决办法存储中文变成问号表和连接串字符集不对统一utf8mb4URL带characterEncoding前端请求后端报跨域浏览器同源策略后端CORS或前端proxy刷新子路由404history模式缺少降级Nginx try_files或改用hash订单金额不对后端信了前端传的价格后端用数据库价格复算启动时报数据库时区错MySQL 8.0时区参数加serverTimezoneAsia/Shanghai登录后后台仍可绕过权限拦截只做了前端后端Interceptor统一校验7. 部署上线与答辩前最后准备7.1 本地打包与云服务器部署系统写完后总要部署到一台云服务器上演示或者至少在本地打包给老师看。后端打包非常直接在IDEA里执行mvn clean package得到可执行的jar包。服务器上只需要装好JDK和MySQL然后运行java -jar wine-mall-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod前端打包更简单执行npm run build后生成dist目录。把dist里的所有文件上传到Nginx的html目录。为了让后端接口和前端页面通过同一个域名访问在Nginx里加一条反向代理location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }这样前端请求/api/xxx会被转发到Java后端而页面静态资源由Nginx直接返回整体就形成了一个非常标准的前后端分离部署架构。7.2 答辩时怎么讲项目亮点答辩不是朗读论文你要把系统理解和实现思路讲清楚。我的建议是准备一条线“我用Spring Boot和Vue做了一个前后端分离的酒品商城核心流程是用户浏览酒品、加购物车、提交订单、管理员发货。数据库设计了七张表重点解决了库存扣减的一致性问题并且通过登录拦截器保护后台接口。”然后顺着这条线延伸。一定要准备两个问题第一个是“为什么用MyBatis-Plus而不用Spring Data JPA”你可以回答“因为商城系统有大量自定义查询MyBatis对SQL控制更直接”第二个是“如果用户同时下单导致库存超卖怎么办”你就把那条UPDATE ... WHERE stock quantity的SQL和Transactional讲出来。能把这个讲清楚项目深度已经超过绝大多数毕设了。7.3 我的一点建议我见过很多同学拿到题目后第一反应是到处找源码这本身没问题但找到源码后一定要自己动手改一遍。你哪怕只是改了几个字段名、加了两个页面也会逼着自己去理解表结构和接口调用关系。改完以后再跑一遍完整流程你会发现很多“源码直接能跑”的说法其实不靠谱数据库配置、依赖版本、前端API地址都需要调整。耐心把每一步调通比收藏一百份源码都有用。酒品商城这种题目技术上不炫业务上完整是那种“做出来就有底气”的项目。如果你能把库存扣减的SQL、订单状态的条件更新、权限拦截器这三件事讲透答辩老师的注意力基本就集中在你的实现细节上而不是在问你“你的系统有什么创新点”这种不太好接的问题上。祝你把项目跑通顺利通过答辩。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →