资讯动态

SSM+Vue全栈实战:二手母婴交易系统从设计到部署

发布时间:2026/10/19 7:46:07 来源:尧图企业网站定制
看到这个标题估计不少正在准备毕业设计、或者想找个完整项目练手的朋友会会心一笑。SSM239一看就是典型的课程设计编号前三个字母代表了技术栈——Spring、SpringMVC、MyBatis后面跟着的项目内容“二手母婴商品交易系统Vue”则把业务场景和前端技术都交代清楚了。这个项目我前后带过几个同学做完也自己完整重构过一版可以说它表面上是“基础款”但真正把它做扎实、做完整里面能挖的东西远比想象中多从数据库设计到订单状态流转从图片上传到前后端联调几乎把Java Web全栈开发的常见知识点都串了一遍。这篇文章我想抛开那些课程设计报告里的套话纯粹从一个实际动手做过的人的角度把这个项目怎么拆、怎么设计、怎么一步步实现、以及最容易踩的坑都讲清楚。适合谁看正在做类似选题的学生、想快速上手前后端分离开发的新手、以及想了解SSMVue项目完整链路的朋友这篇文章应该都能给你一些参考。1. 项目整体设计与技术选型1.1 为什么是SSM Vue而不是Spring Boot先说一个很现实的问题现在企业里用Spring Boot的越来越多为什么还要做SSM从我接触的情况来看很多高校的Java Web课程至今还是以SSM为教学主线框架原理讲得细配置也要求手动完成。这其实是好事因为SSM的配置全都是“显式声明”你能清清楚楚看到Spring的容器是怎么装起来的、SpringMVC的拦截器是怎么挂上去的、MyBatis的SqlSessionFactory是怎么和数据源绑定的。换成Spring Boot很多东西被自动配置遮住了反而不容易理解底层联动。从项目本身来说SSM的骨架足够支撑这样一个中型的交易系统。用户管理、商品发布、订单流程、后台管理模块划分清晰事务边界可控。SpringMVC负责接口路由和参数绑定MyBatis负责SQL操作Spring负责把Service和Mapper串起来各司其职。对练手和毕设答辩来说这种“每个环节都能讲出道理”的技术栈反而是加分项。前端选择Vue现在的版本一般都用Vue2 Element UI或者Vue3 Element Plus。如果学校课程讲的是Vue2那就用Vue2生态稳定、资料多、遇到坑好搜。Vue负责页面渲染和数据交互通过axios调用后端接口整体就是典型的前后端分离开发模式。1.2 系统角色与权限边界二手母婴商品交易系统虽然看起来业务不算复杂但角色划分必须清晰。我习惯分三类普通用户买家浏览商品、搜索筛选、收藏、加入购物车、下单付款、确认收货、发表咨询。卖家用户商家自家也是普通用户注册而来但比买家多出“商品发布”“商品管理”“订单发货”“查看买家咨询”这几个能力。管理员登录后台审核商品上架、管理用户状态禁用/启用、管理商品分类、查看交易统计。这里有个关键设计点卖家和买家不是两张用户表而是在用户表里用字段区分身份比如role字段0代表普通用户1代表卖家2代表管理员。用户注册时默认是普通用户但普通用户也可以“申请成为卖家”这个在个人中心里做一个入口即可后台审核通过后role变为1。这样实现简单也符合电商系统的常见设计——先有买家再升级为卖家。权限控制怎么做后端用拦截器HandlerInterceptor拦截需要登录的接口从Session里取用户信息取不到直接返回未登录状态码。管理员接口则额外校验角色的值是否为2。前端配合路由守卫根据登录状态和角色控制页面跳转和菜单显示。前后端都做校验但真正的安全底线一定在后端。1.3 核心功能模块清单我习惯在动手写代码前先把功能模块铺开不然写到哪里算哪里代码很容易乱。端模块功能点前台用户注册、登录、退出、个人资料修改、头像上传前台商品分类浏览、关键词搜索、价格筛选、成色筛选、商品详情、收藏前台购物车加入购物车、修改数量、删除、批量结算前台订单提交订单、订单支付模拟、卖家发货、买家确认收货、取消订单前台商品发布卖家发布商品、图片上传、编辑、上架/下架前台咨询买家对商品发起询问卖家在商品管理里回复后台管理用户管理、商品审核、分类管理、订单总览、数据统计这个清单基本就是项目的全部业务范围。把每个模块的接口列表列出来开发的时候照着做就行不容易漏功能。2. 数据库设计与核心表结构2.1 设计原则与字段规划二手母婴商品交易系统的数据量不会很大但表关系要设计得规范。我设计表的时候遵循几点第一业务主键用自增ID订单号单独用一个唯一字符串。订单号要展示给用户看自增ID太暴露业务量而且多个表都可能引用所以订单表用order_no字段格式就是时间戳加随机数。第二状态字段全用整型。比如商品状态0待审核、1在售、2已下架、3已售出。订单状态0待付款、1待发货、2待收货、3已完成、4已取消。用数字存状态代码里定义常量或者枚举比直接用字符串科学得多。第三删除用逻辑删除。用户列表、商品列表都可能涉及“删除”但物理删除会破坏数据关联。所以每个核心表加一个deleted字段或者直接用status来表示失效状态。比如用户禁用就是status0商品下架就是status2都是逻辑层面的操作数据还留在库里。第四金额字段用BigDecimal。这一点必须强调我见过有人用double存价格最后计算总额出现0.10.2不等于0.3的经典问题。数据库里用decimal(10,2)Java对象里用BigDecimal避免浮点精度问题。2.2 核心表结构说明把表结构直接写出来也是后续开发的重要参考。用户表字段如下CREATE TABLE user ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL COMMENT 用户名, password varchar(100) NOT NULL COMMENT 密码加盐MD5, nickname varchar(50) DEFAULT NULL COMMENT 昵称, phone varchar(20) DEFAULT NULL COMMENT 手机号, avatar varchar(255) DEFAULT NULL COMMENT 头像路径, role tinyint(4) DEFAULT 0 COMMENT 角色0普通用户 1卖家 2管理员, status tinyint(4) DEFAULT 1 COMMENT 状态1正常 0禁用, create_time datetime DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;密码单独说一句真实项目肯定不能明文存储。我用了MD5加盐取用户名作为盐的一部分再加上一串固定密钥和密码拼起来后做MD5。虽然MD5不算强的加密算法但应对课程设计、演示项目足够答辩的时候还能把“为什么加盐”讲清楚。真要考虑安全性换BCrypt即可思路是一样的。商品表是核心业务表字段比较多CREATE TABLE goods ( id int(11) NOT NULL AUTO_INCREMENT, seller_id int(11) NOT NULL COMMENT 卖家用户ID, category_id int(11) DEFAULT NULL COMMENT 分类ID, title varchar(100) NOT NULL COMMENT 商品标题, description text COMMENT 商品描述, original_price decimal(10,2) DEFAULT NULL COMMENT 原价/参考价, sell_price decimal(10,2) NOT NULL COMMENT 售价, condition_level tinyint(4) DEFAULT 0 COMMENT 成色1全新 2九成新 3七成新 4五成及以下, cover_image varchar(255) DEFAULT NULL COMMENT 封面图, images varchar(1000) DEFAULT NULL COMMENT 图片列表逗号分隔, status tinyint(4) DEFAULT 0 COMMENT 状态0待审核 1在售 2已下架 3已售出, view_count int(11) DEFAULT 0 COMMENT 浏览次数, create_time datetime DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品表;图片字段这里多提一嘴单图用cover_image多图用images字符串存逗号分隔的路径列表查询时拆一下即可。这比单独建一张商品图片表省事而且对这个量级的项目完全够用。订单相关表是另一个核心模块。订单主表和订单明细表分开设计CREATE TABLE orders ( id int(11) NOT NULL AUTO_INCREMENT, order_no varchar(32) NOT NULL COMMENT 订单号, buyer_id int(11) NOT NULL COMMENT 买家ID, seller_id int(11) NOT NULL COMMENT 卖家ID, total_price decimal(10,2) DEFAULT NULL COMMENT 总金额, status tinyint(4) DEFAULT 0 COMMENT 状态0待付款 1待发货 2待收货 3已完成 4已取消, receiver_name varchar(50) DEFAULT NULL COMMENT 收货人姓名, receiver_phone varchar(20) DEFAULT NULL COMMENT 收货人电话, receiver_address varchar(255) DEFAULT NULL COMMENT 收货地址, remark varchar(255) DEFAULT NULL COMMENT 买家备注, create_time datetime DEFAULT NULL, pay_time datetime DEFAULT NULL COMMENT 付款时间, ship_time datetime DEFAULT NULL COMMENT 发货时间, finish_time datetime DEFAULT NULL COMMENT 完成时间, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单表;订单明细表记录每一件商品的信息CREATE TABLE order_item ( id int(11) NOT NULL AUTO_INCREMENT, order_id int(11) NOT NULL, goods_id int(11) NOT NULL, goods_title varchar(100) DEFAULT NULL COMMENT 商品标题快照, goods_image varchar(255) DEFAULT NULL COMMENT 商品图片快照, price decimal(10,2) NOT NULL COMMENT 成交单价, count int(11) DEFAULT 1 COMMENT 购买数量, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单明细表;注意明细表里的商品标题和图片这是“快照”字段。为什么冗余因为订单生成之后卖家完全可能修改商品标题、更换图片甚至删除商品订单数据不能被这些操作影响。这在电商系统里是标准的设计思路面试和答辩时能讲清楚这一点会加分不少。购物车表和收藏表结构相对简单CREATE TABLE cart ( id int(11) NOT NULL AUTO_INCREMENT, user_id int(11) NOT NULL, goods_id int(11) NOT NULL, count int(11) DEFAULT 1 COMMENT 数量, create_time datetime DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT购物车表; CREATE TABLE favorite ( id int(11) NOT NULL AUTO_INCREMENT, user_id int(11) NOT NULL, goods_id int(11) NOT NULL, create_time datetime DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT收藏表;2.3 订单状态流转设计二手交易和标准电商最大的不同在于角色结构买卖双方都是普通用户平台管理员主要负责审核和仲裁不直接参与交易流程。所以订单状态的流转要围绕“买家-卖家”两端交互来设计。我的设计中订单生命周期如下待付款 - 待发货 - 待收货 - 已完成 | | | | | --- 已取消买家在待发货前可取消 ----------------------- 已取消超时未付款简单演示可跳过买家提交订单后状态为待付款点击“立即支付”模拟支付成功这里不需要接真实支付网关直接用接口把状态改成待发货即可答辩时说明是为了演示而简化。卖家在自己的订单列表里看到待发货订单点击“发货”填写物流单号演示项目也可不填状态变为待收货。买家确认收货后状态变为已完成。待付款状态买家可以取消订单待发货状态如果卖家还没发货也可以由卖家关闭订单。这个状态机的核心是每次状态变更必须有明确的前置条件而且更新订单状态时SQL要加上状态条件防止并发导致状态错乱。比如UPDATE orders SET status 2, ship_time NOW() WHERE id #{orderId} AND status 1 AND seller_id #{sellerId}这样即使买家同时点了取消、卖家同时点了发货数据库层面也只会有一个操作生效。3. 后端核心功能实现3.1 SSM整合配置要点SSM整合的配置文件比较多第一次做的人容易被绕晕。我的经验是分四个配置文件web.xml管SpringMVC和字符编码过滤器spring-mvc.xml管控制器扫描、注解驱动、视图解析器spring-mybatis.xml管数据源、SqlSessionFactory、Mapper扫描、事务管理器mybatis-config.xml管驼峰映射、缓存配置。web.xml里一定不能漏掉的配置是两个一个是SpringMVC的DispatcherServlet另一个是字符编码过滤器。如果漏了编码过滤器你会发现前端传过来的中文全是乱码。DispatcherServlet的url-pattern如果配成/要注意静态资源放行不然图片、CSS、JS都会404。我在spring-mvc.xml里这样配置mvc:default-servlet-handler/这表示SpringMVC处理不了的请求交给容器默认Servlet处理静态资源才能正常访问。spring-mybatis.xml里数据源我用的是Druid连接池。数据库连接池这个选型不复杂Druid的好处是自带监控页面答辩演示时可以打开SQL监控面板展示项目真实执行的SQL这个细节很加分。关键配置大概是bean iddataSource classcom.alibaba.druid.pool.DruidDataSource property namedriverClassName valuecom.mysql.cj.jdbc.Driver/ property nameurl valuejdbc:mysql://localhost:3306/mall_db?useUnicodetrueamp;characterEncodingutf8amp;serverTimezoneAsia/Shanghai/ property nameusername valueroot/ property namepassword value123456/ property nameinitialSize value5/ property nameminIdle value5/ property namemaxActive value20/ /bean数据库连接串里的serverTimezoneAsia/Shanghai不能省。MySQL 8的驱动如果不指定时区连数据库的时候会直接报错这是新手最容易卡住的地方之一。MyBatis的Mapper扫描和事务管理器要配套bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.example.mall.dao/ /bean bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManager property namedataSource refdataSource/ /bean tx:annotation-driven transaction-managertransactionManager/事务管理一定要配。订单生成时要同时写入订单主表、订单明细表、删除购物车对应商品、扣减商品库存如果有库存概念这四步任何一个失败都应该回滚不配事务的话数据就乱了。3.2 用户注册登录与拦截器用户注册的核心逻辑是三步校验用户名是否已存在、对密码做加盐MD5、插入用户记录。这里唯一的坑在用户名唯一性判断上建议把username字段设置为唯一索引这样即使并发注册数据库也会兜底不会出现两个同名的用户。登录接口的处理方式是根据用户名查出用户比对密码比对通过后把用户对象存入Session。我在Service层返回一个统一的结果对象Result包含code、message、data三个字段。前端根据code判断登录是否成功成功就跳转首页失败就提示具体原因。拦截器是这个项目的权限核心。我写一个LoginInterceptorpublic class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session request.getSession(); User user (User) session.getAttribute(user); if (user null) { response.setContentType(application/json;charsetutf-8); response.getWriter().write({\code\:401,\message\:\未登录\}); return false; } return true; } }注意这里直接输出JSON而不是重定向因为前后端分离的项目里前端是通过axios请求的如果后端重定向到登录页前端拿到的是HTML而不是JSON处理起来很麻烦。统一返回401前端axios拦截器里判断到401就跳转登录页体验才正常。拦截器注册时要注意放行路径。注册、登录、商品列表、商品详情、商品搜索这些接口不需要登录都必须放行。购物车、订单、个人中心、发布商品这些接口才需要登录校验。管理员接口再额外加一个管理员拦截器校验session里的用户角色。3.3 商品发布与图片上传商品发布是卖家端的核心操作涉及表单提交和图片上传两个部分。我在设计时把这两个放在同一个接口里处理前端以multipart/form-data方式提交表单字段用普通的键值对图片文件用文件字段。上传文件的保存路径是另一个常见的坑。很多新手把文件写到项目目录下然后启动Tomcat部署的时候发现文件路径不对或者重启Tomcat后上传的图片不见了因为重新部署会把原目录清空。正确做法是把图片保存到服务器之外的独立路径比如Linux下的/usr/local/upload/Windows下的D:/upload/然后通过配置映射让Tomcat能访问到这个目录。在spring-mvc.xml中对静态资源做映射mvc:resources mapping/upload/** locationfile:D:/upload//这样前端访问http://localhost:8080/upload/xxx.jpg就能直接看到图片而文件本身存放在项目部署目录之外重启不丢失。文件名称也要处理。直接用原始文件名不安全而且可能重名。我的工具类里用UUID重命名保留原文件扩展名。这样既避免重名也防了路径穿越。商品发布的业务逻辑里还有一步状态设置为待审核status0。这是二手平台的一个典型规则——管理员审核通过之后商品才能在首页展示。所以卖家发布完成之后在自己的“我的商品”列表里能看到该商品但前台首页和搜索列表不会出现除非管理员在后台审核通过。3.4 订单流程与事务处理订单生成的接口是项目中事务最重的接口逻辑如下从请求里获取收货人信息、备注、以及本次结算的商品ID列表可以来自购物车也可以直接从前端传商品ID和数量。遍历商品ID查询商品信息校验商品状态必须是在售状态校验卖家不能是自己自己买自己的二手商品没有意义。计算总价生成订单号。插入订单主表拿到自增主键。批量插入订单明细表。删除购物车中对应的记录。如果有库存概念扣减库存这个项目二手商品大多只有一件所以下单后直接把商品状态改为已售出。整个方法加Transactional注解。有一个细节调用商品查询时如果商品在第一步查询显示在售但下单过程中别人抢先买走状态已经变成已售出怎么办所以更新商品状态的SQL要加上条件UPDATE goods SET status 3 WHERE id #{goodsId} AND status 1如果影响行数为0说明商品已经被别人买走抛异常回滚整个订单并向用户提示“商品已售出”。这就是乐观锁的思路——用条件更新代替锁表在这个场景下完全够用。订单号生成我用的是SimpleDateFormat sdf new SimpleDateFormat(yyyyMMddHHmmss); String orderNo sdf.format(new Date()) (int)((Math.random() * 9 1) * 10000);18位基本不会重复而且一眼能看出下单时间比UUID更适合展示给用户。3.5 后台管理功能实现后台管理的核心是商品审核。管理员从商品列表里筛选status0的记录查看商品详情和图片决定通过或驳回。通过就是status1驳回是status2或者单独一个状态此处简化。这里我加了一个可选的“驳回原因”字段方便用户了解原因。前端页面上后台管理系统我用了一套独立的布局左侧菜单商品审核、用户管理、分类管理、数据统计右侧内容区同样基于Element UI搭建。用户管理主要是禁用和启用用户。禁用用户时同时要考虑到这个用户还有在售商品怎么办我的处理是后台禁用一个用户时自动把该用户所有在售商品下架代码里就是两个UPDATE操作放在一个事务里。否则会出现“用户被封禁但商品还在卖”的逻辑漏洞这个细节在答辩时可以主动提。分类管理是简单的CRUD一个分类对应商品表里的category_id。商品列表和首页的分类导航都通过分类ID关联。新增分类时注意分类名的唯一性前端加校验后端也做查重。数据统计我做得比较轻量统计注册用户总数、商品总数、订单总数、交易总额再按近七天的订单量做一张简单的柱状图。数据接口用SQL的聚合函数就能实现前端ECharts画图。4. 前端Vue页面实现与接口联调4.1 项目搭建与路由设计Vue项目我用vue-cli创建选Vue2版本。依赖方面安装vue-router、axios、element-ui、qs或者直接手写序列化开发依赖装sass-loader和node-sass做样式预处理。路由设计要考虑不同角色的权限。路由表分为三个层级公共页面、登录后页面、管理员页面。我用vue-router的beforeEach守卫做登录校验和角色判断。核心逻辑是router.beforeEach((to, from, next) { const user localStorage.getItem(user) ? JSON.parse(localStorage.getItem(user)) : null; if (to.meta.requiresAuth !user) { next(/login); return; } if (to.meta.requiresAdmin (!user || user.role ! 2)) { next(/); return; } next(); });前后端都要做权限控制前端做的是体验优化后端才是安全防线。这个点写进文档或者答辩讲清楚就行。组件设计上我建议页面组件和通用组件分开。通用组件比如商品卡片展示商品图、标题、价格、成色、链接到详情页在首页、商品列表页、我的收藏页都要用抽出来复用能省大量重复代码。4.2 axios封装与接口调用axios一定要统一封装不要每个页面各自写一遍。我在utils/request.js里创建一个axios实例配置baseURL、请求超时时间、拦截器。请求拦截器负责往header里加token如果后端用了无状态方案响应拦截器统一处理code等于200正常返回数据等于401跳转登录页其他code用Element UI的Message组件弹出错误信息。import axios from axios; import { Message } from element-ui; import router from /router; const service axios.create({ baseURL: /api, timeout: 10000 }); service.interceptors.response.use( response { const res response.data; if (res.code 200) { return res; } else if (res.code 401) { localStorage.removeItem(user); router.push(/login); return Promise.reject(res); } else { Message.error(res.message || 请求失败); return Promise.reject(res); } }, error { Message.error(error.message || 网络异常); return Promise.reject(error); } ); export default service;这里baseURL是/api后面联调环节会说为什么这样配。4.3 前后端联调与跨域处理SSM后端默认跑在8080端口Vue开发服务器跑在8081端口。端口不同前端直接请求后端接口会触发跨域。解决办法有两个后端配CORS或者前端用devServer代理。我推荐前端代理因为部署到生产环境时前后端通常部署在同一域下代理配置只需要在开发阶段生效生产环境把前端打包后放到Tomcat的webapps下或者用Nginx反向代理同域下就没有跨域问题。vue.config.js里的代理配置module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/api: } } } } };这样前端请求/api/user/login开发环境下会被代理转发到http://localhost:8080/user/login后端接口路径不用加/api前缀。等到生产环境直接部署如果前后端都在8080端口下/api/user/login这个路径会直接404所以生产部署时还要在SpringMVC配置里加一个路径处理或者在nginx层做rewrite。我在实际部署时更常后端接口直接带/api前缀前端所有请求天然统一口径最省心。跨域还有一个小坑如果后端用了Session存用户信息axios请求默认不携带cookie会导致每次请求都是新会话。解决方法是给axios加上withCredentials: true同时后端的CORS配置中不能使用*通配符必须指定具体的域名。用代理方案可以完全避开这个问题这也是我推荐代理的原因之一。4.4 核心页面实现要点首页的结构比较简单顶部导航栏Logo、搜索框、分类菜单、登录状态区、中间分类导航、下面是最新商品和热卖推荐。首页数据接口返回商品列表每次进首页调用一次商品卡片点击后跳详情页。商品列表页要支持筛选筛选条件包括分类、成色、价格区间、排序方式最新发布、价格升序/降序。后端接口接收这些查询参数用MyBatis的动态SQL拼接查询条件。前端用Element UI的Select和Input组件绑定条件点击筛选时重新调用接口。商品详情页是信息量最大的页面左侧图片轮播多图、右侧标题价格、成色、卖家信息、收藏按钮、加入购物车和立即购买按钮、下方是详细描述和买家咨询列表。这里的咨询功能是一个测试常见但容易漏掉的模块买家可以针对商品提问卖家在商品管理页看到提问并回复。数据表用goods_id关联查询时按时间排序。购物车页面要做“是否选中”和“合计金额”的联动。我在前端用一个对象存储每个条目的选中状态用computed属性计算总价。结算时把选中的商品ID列表传给后端。个人中心包括我的信息、我的订单、我要卖货、我的商品、我的收藏几个子页面。用Tab切换。我的订单要区分买家视角和卖家视角同一个订单买家关心的是付款、确认收货卖家关心的是发货。所以前端要根据当前用户角色显示不同的操作按钮。后台管理页面是独立的一套布局左侧菜单固定右侧内容区根据菜单切换组件。商品审核列表用表格展示每条记录带“查看详情”和“通过/驳回”按钮。用户管理表格里显示用户名、手机号、角色、状态操作列是“禁用/启用”。5. 项目部署与本地运行5.1 环境准备我建议的环境配置是JDK 1.8、Maven 3.6、MySQL 5.7或8.0、Tomcat 8.5或9.0、Node 14前端构建用。这些版本相互兼容性好网上资料也多不推荐一上来就追求JDK 17、Tomcat 10这些新版本容易遇到兼容性问题。数据库初始化脚本要提前准备好。包括建库、建表、插入必要的初始化数据一个管理员账号如admin/admin123、一个测试卖家账号、几个商品分类婴儿车、婴儿床、玩具、衣物、喂养用品等、若干测试商品。这样项目启动后不用手动造数据就能直接看效果。5.2 部署步骤后端部署分为两步Maven打包成war包放到Tomcat的webapps目录下启动Tomcat后war包自动解压部署。注意项目打包名称最好改成好记的比如mall访问路径就是http://localhost:8080/mall/。前端部署也分两步先在项目根目录执行npm run build生成dist目录然后把dist目录下的文件拷贝到Tomcat的webapps下某个目录中。如果希望和前端在同一端口下部署可以在webapps下建一个mall目录把打包产物放进去同时保证后端接口路径和前端请求路径能对得上。我自己运行测试时经常不改动Tomcat直接用IDEA的Tomcat插件启动后端然后用npm run serve启动前端开发服务器开发体验很好。要演示给老师或者同学看时再打一个正式包部署。5.3 联调过程中必须验证的流程项目做完后不要直接交差我建议把核心流程完整走一遍。重点验证这几个业务闭环用户注册登录、退出登录、刷新页面后登录状态保持。卖家发布商品管理端能收到待审核商品审核通过后前台能搜到审核不通过则前台不可见。买家搜索商品、查看详情、加入购物车、提交订单、模拟支付。卖家在订单列表看到新订单执行发货买家确认收货。商品在售出后再次搜索这个商品状态显示已售出或直接下架不能被重复购买。管理员禁用一个用户后该用户无法登录其商品全部下架。每一个流程跑通项目才算真正能用。6. 常见问题与排查技巧实录6.1 启动报错与配置类问题最常遇到的启动报错是数据库连接失败。排查思路是固定的先看MySQL服务有没有启动再看账号密码对不对再看连接串时区配置有没有问题。如果报错信息里有Public Key Retrieval is not allowed在连接串末尾加上allowPublicKeyRetrievaltrue即可这是MySQL 8的新特性导致的问题。第二个常见的启动报错是Spring容器创建失败多半是Mapper接口扫描不到或者Bean注入失败。观察控制台报错提到的类名检查是否漏了MapperScan或者MapperScannerConfigurer的basePackage指向了错误的包。还有一个小问题是ServiceImpl和Controller都没有加注解检查时容易忽略养成写完一个模块就启动一次的习惯能快速定位。6.2 MyBatis相关的坑MyBatis最典型的问题是驼峰属性映射。数据表的字段是create_timeJava属性是createTime如果mybatis-config.xml里没有开启驼峰映射查询结果里的Create_time永远是null。一定要加settings setting namemapUnderscoreToCamelCase valuetrue/ /settings还有一种问题是SQL拼接错误。动态SQL里用了if标签但条件的写法不对导致整个查询查不出数据。排查技巧是在MyBatis的日志配置里打开SQL输出看实际生成的SQL语句是哪里拼错了一眼就能看到。日志配置在logback或log4j.properties里设置对应mapper包级别为DEBUG。6.3 图片上传与回显问题图片上传报错有几种情况。一种是文件大小超限SpringMVC默认单文件最大1MB需要配multipart配置bean idmultipartResolver classorg.springframework.web.multipart.commons.CommonsMultipartResolver property namemaxUploadSize value10485760/ property namemaxInMemorySize value4096/ /bean另一种是图片能上传但访问404。原因通常是静态资源映射没配置对路径中的file:前缀缺失。还有Tomcat目录权限问题如果映射的目录没有写权限上传操作直接报错。回显问题主要在于图片路径的拼接。数据库里存的是相对路径/upload/xxx.jpg前端渲染时直接拼接口域名即可。我建议数据库里就存完整可访问的URL比如http://localhost:8080/upload/xxx.jpg前端不用再拼接省得开发环境和生产环境之间来回改。6.4 前端联调中的细节问题前端最烦的两个问题一个是跨域一个是数据格式。跨域问题前面已经讲过了用代理基本能根治。数据格式问题主要在时间字段上。后端返回的Date类型默认序列化成一串时间戳数字前端显示很不友好。解决方法是配置Jackson的日期格式mvc:annotation-driven mvc:message-converters bean classorg.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean property nameobjectMapper refobjectMapper/ /bean /mvc:message-converters /mvc:annotation-driven或者给实体类的日期字段加JsonFormat(pattern yyyy-MM-dd HH:mm:ss, timezone GMT8)注解。我习惯用注解简单直接每个日期字段上加上就行。另一个联调细节是前端提交表单数据时如果提交的是JSON对象后端用RequestBody接收如果提交的是FormData格式后端用普通参数接收混用会导致参数绑定为null。在购物车勾选结算、商品发布表单、订单提交这几个接口上我要么统一JSON要么统一FormData前后端定义一个约定开发时就不会乱。6.5 项目答辩时的加分技巧如果你做这个项目是为了毕业答辩除了功能完整外我建议在技术点讲解上多准备几个亮点。比如订单生成的乐观锁处理、订单数据中的快照字段、图片独立目录存储方案、拦截器的多角色权限设计、前端路由守卫与后端拦截器双重校验这几点随便展开都能讲一两分钟而且能体现你对项目有真正的理解。再准备一套完整的演示数据和脚本答辩现场不要临时敲命令。数据库里准备好账号管理员、卖家、买家各一个每一个角色的核心操作都练熟演示的时候流畅不卡壳这比代码本身更容易给老师留下好印象。7. 写在最后的几点体会这套SSM Vue的二手母婴交易系统我前前后后带人做过好几轮每一次重做都会发现一些新问题、新优化点。最大的感受是这类“经典毕业设计”项目虽然技术栈看起来不新但它把Web开发中最重要的一整套链路都涵盖了——从需求拆解到数据库建模从接口设计到前端交互从本地联调到打包部署。认真做完一遍你对Java后端开发的整体认知会清晰很多这比单纯背面试题更管用。我个人在实际操作中养成了一个习惯每做完一个模块就立刻把前后端联调跑一遍不要等所有功能都写好再统一调试。比如用户模块做完马上注册一个账号登录、退出、改资料全套验证通过再做商品模块。模块之间独立开发但尽早集成能避免最后联调时一堆问题挤在一起定位起来特别痛苦。最后再分享一个小技巧项目目录结构从一开始就规划清楚后端按controller、service、mapper、pojo、utils分层前端按views、components、router、api、utils分层。这个习惯跟我做这个项目的时候一模一样后面扩展功能、换人接手时大家都省心。要是你正在做类似的项目遇到具体问题卡住了欢迎按这个思路对照排查大部分问题其实都在前面几节提到的坑里。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑