ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

SSM商城项目实战:环境搭建、架构拆解与避坑指南

SSM商城项目实战:环境搭建、架构拆解与避坑指南

简介:这是一套基于SSM(Spring+SpringMVC+MyBatis)框架与MySQL数据库开发的线上商城项目源码,配套完整后台管理平台,面向Java Web初学者、课程设计或毕业设计开发者,帮助其理解电商系统的分层架构与业务实现。压缩包共341个文件,约1.71MB,其中49个Java文件承载控制层、服务层与实体类逻辑,35个HTML与12个CSS、51个JS文件构成前后端页面与交互,另有15个XML配置、1个SQL建库脚本及图片、字体等静态资源,目录结构清晰,便于按模块阅读。项目涵盖商品展示、购物车、订单管理与后台增删改查等典型电商功能,可直接部署运行,也可作为二次开发的基础模板。目前已有116人学习下载,适合需要完整SSM实战案例、快速掌握框架整合与数据库设计的读者参考借鉴。

1. 一个能跑起来的 SSM 商城长什么样:从 start.bat 到后台管理

拿到一个 JavaWeb 项目压缩包,最怕的不是代码烂,而是根本跑不起来。这个基于 SSM 框架加 MySQL 的线上商城项目,带一套独立的管理平台,解压后第一眼看到的是start.bat和一堆 layui 的样式文件——layui.css、main.css、layer.css、laydate.css、skin.css,还有layui.mobile.css。这说明前端不是裸写 HTML,而是用了 layui 这套经典的后台 UI 库,管理平台的表格、弹层、日期选择器基本都靠它撑起来。项目定位很明确:一套能直接部署的电商练手项目,前台是商品展示和下单流程,后台是商品管理、订单管理、用户管理。适合谁?正在学 SSM 整合、需要完整案例写进简历或者做课程设计的同学,以及想拿一套现成后台模板改造成自己业务系统的开发者。它解决的核心问题是:不用从零搭 Spring + SpringMVC + MyBatis 的架子,不用自己写 CRUD 和分页,拿到就能改业务逻辑。但前提是,你得先把环境跑通,而这一步恰恰是血泪经验最多的地方。

2. 环境搭建与数据库初始化:MySQL 版本选择和建表脚本执行

2.1 为什么这个项目对 MySQL 版本有要求

SSM 项目本身对 MySQL 版本不挑,5.7 和 8.0 都能跑,但驱动包和连接串写法不一样。项目里如果用的是mysql-connector-java5.x 版本,连 MySQL 8.0 会报Unknown system variable 'query_cache_size'或者时区错误。常见做法是:要么把 MySQL 降到 5.7,要么换 8.0 的驱动包并改连接串。我一般会先看pom.xml或者lib目录里的驱动版本,再决定装哪个数据库。如果你机器上已经装了 MySQL 8.0,不想折腾降级,那就把驱动换成mysql-connector-java-8.0.28.jar,连接串加上serverTimezone=Asia/Shanghai和useSSL=false。这一步选错了,后面启动 Tomcat 直接给你抛异常,连登录页都看不到。

2.2 建库建表与 SQL 脚本执行

项目压缩包里通常会有一个.sql文件,可能是shop.sql或者db.sql。先创建数据库,字符集用utf8mb4,排序规则utf8mb4_general_ci。命令行操作如下:

# 登录 MySQL,注意 8.0 和 5.7 的登录命令一样 mysql -u root -p # 创建数据库,指定字符集,避免中文乱码 CREATE DATABASE shop_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 切换到该数据库 USE shop_db; # 执行建表脚本,路径换成你解压后的实际位置 source D:/projects/shop/sql/shop.sql;

执行完用SHOW TABLES;确认表是否都建好了。一般会有user、product、order、order_item、category、admin这几张核心表。如果脚本里带了DROP TABLE IF EXISTS,重复执行不会报错,但会清空数据,注意别在已有数据的库上跑。

2.3 数据库连接配置修改

找到src/main/resources下的jdbc.properties或者db.properties,也可能是直接写在applicationContext.xml里。需要改的是 URL、用户名、密码。一个典型的 8.0 连接串长这样:

jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/shop_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true jdbc.username=root jdbc.password=你的密码

allowPublicKeyRetrieval=true这个参数在 8.0 里经常被忽略,不加的话第一次连接会报Public Key Retrieval is not allowed。serverTimezone不设,插入时间字段会差 8 小时。这两个坑我踩过不止一次。

2.4 Tomcat 部署与 start.bat 的作用

start.bat通常是 Windows 下的一键启动脚本,里面可能写了startup.bat的调用,或者直接java -jar启动内嵌 Tomcat。如果是传统 SSM 项目,你需要自己配 Tomcat。把项目打成 war 包丢进webapps,或者直接在 IDEA 里配 Tomcat Server。start.bat里如果有set JAVA_HOME和set CATALINA_HOME,检查路径是否和你本机一致。启动后访问http://localhost:8080/项目名/,看到商城首页就算成功了一半。后台地址一般是/admin或者/manage,具体看web.xml里的 servlet 映射。

3. SSM 三层架构拆解:从 Controller 到 Mapper 的调用链

3.1 前台商品列表的请求流转

以商城首页商品列表为例,请求/product/list进入ProductController,Controller 调用ProductService,Service 调用ProductMapper接口,MyBatis 通过 XML 映射文件执行 SQL 返回List<Product>,再封装成PageInfo返回给 JSP 或者前端页面。这条链路是 SSM 的标准写法,理解一条,其他模块照葫芦画瓢。关键要看的是ProductMapper.xml里的 SQL 怎么写,分页是用LIMIT还是 PageHelper 插件。如果用了 PageHelper,pom.xml里会有pagehelper依赖,Service 层调用PageHelper.startPage(pageNum, pageSize)即可,不用手写LIMIT。

3.2 后台管理的权限拦截

管理平台一般会有一个LoginInterceptor或者 Filter,拦截/admin/*路径,检查 session 里有没有admin对象。没有就跳登录页。这个拦截器在springmvc.xml里配置:

<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/admin/**"/> <bean class="com.shop.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>

注意/admin/**和/admin/*的区别,前者匹配多级路径,后者只匹配一级。写错了会导致后台某些页面能直接访问,或者登录页也被拦截造成死循环。这是权限模块最常见的翻车点。

3.3 MyBatis 映射文件与实体类对应关系

实体类Product的字段名和数据库列名如果不一致,需要在ProductMapper.xml里用resultMap做映射,或者在 SQL 里用AS起别名。比如数据库列是product_name,实体类是productName,MyBatis 默认的驼峰映射如果没开,查出来就是 null。开启方式是在mybatis-config.xml里加:

<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>

这个配置一开,product_name自动映射到productName,省去大量resultMap手写工作。但要注意,如果项目里已经写了resultMap,这个配置不会冲突,只是多一层保险。

3.4 事务管理配置

SSM 的事务一般配在applicationContext.xml里,用DataSourceTransactionManager,然后开启注解驱动<tx:annotation-driven transaction-manager="transactionManager"/>。Service 层方法上加@Transactional即可。注意默认只对RuntimeException回滚,如果捕获了异常没抛出去,事务不会回滚。下单扣库存这种操作,一定要让异常抛到 Service 外层,或者手动TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。这个坑在订单模块特别容易踩。

4. 避坑排查:启动报错、乱码、静态资源 404 的常见问题

4.1 启动报 ClassNotFoundException 或 NoClassDefFoundError

现象:Tomcat 启动时控制台刷java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener。原因:Spring 的 jar 包没放到WEB-INF/lib下,或者 Maven 依赖没打包进去。解决:检查pom.xml里 spring-web、spring-context、spring-tx 等依赖是否齐全,IDEA 里看 Artifacts 配置有没有把 Maven 依赖输出到WEB-INF/lib。如果是手动导 jar 的老项目,确认lib目录下 jar 包完整。

4.2 页面中文乱码

现象:JSP 页面显示问号或者乱码。原因:三处编码没统一——数据库字符集、连接串编码、JSP 页面编码。解决:数据库用utf8mb4,连接串加characterEncoding=utf8,JSP 头部加<%@ page contentType="text/html;charset=UTF-8" language="java" %>,同时在web.xml里配CharacterEncodingFilter:

<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

forceEncoding设为 true 才会强制请求和响应都用 UTF-8,只设 encoding 有时候不够。

4.3 静态资源 404,layui.css 加载失败

现象:页面样式全丢,F12 看layui.css、main.css返回 404。原因:SpringMVC 的DispatcherServlet拦截了所有请求,包括静态资源。解决:在springmvc.xml里加<mvc:default-servlet-handler/>或者<mvc:resources mapping="/static/**" location="/static/"/>。如果项目里静态资源放在webapp/static下,用后者更精确。加完之后,/static/layui/css/layui.css就能正常访问了。

4.4 数据库连接池报错 Connection refused

现象:启动时Could not get JDBC Connection,或者Communications link failure。原因:MySQL 服务没启动,或者端口不对,或者防火墙拦了。解决:net start mysql启动服务,确认端口是 3306,检查jdbc.url里的 IP 是不是localhost。如果是 Docker 里的 MySQL,注意容器端口映射,localhost要换成宿主 IP 或者用host.docker.internal。

4.5 后台登录后 session 丢失

现象:登录成功跳转后台首页,再点其他菜单又跳回登录页。原因:拦截器判断 session 的逻辑有问题,或者 Tomcat 的 session 超时太短。解决:检查拦截器里request.getSession().getAttribute("admin")是否为空,登录时有没有session.setAttribute("admin", admin)。另外web.xml里<session-config>的session-timeout单位是分钟,默认 30,别设成 30 秒。

5. 二次开发与功能扩展:从改一个字段到加一套权限

5.1 给商品表加一个字段并打通全链路

假设要给商品加一个stock库存字段。步骤:数据库ALTER TABLE product ADD COLUMN stock INT DEFAULT 0;,实体类Product加private Integer stock;和 getter/setter,ProductMapper.xml的insert、update、select语句里加上stock列,前台商品详情页和后台商品编辑页的 JSP 加上对应输入框。改完重启 Tomcat,测试新增商品时库存能不能写入,下单时库存能不能扣减。这条链路走通一次,以后加任何字段都是重复这个流程。

5.2 用拦截器实现简单的后台权限分级

如果想让不同管理员看到不同菜单,可以在admin表加一个role字段,登录时把 role 存进 session。拦截器里根据 role 判断是否有权限访问某个路径。比如/admin/user/**只允许role=super访问。代码大致如下:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Admin admin = (Admin) request.getSession().getAttribute("admin"); if (admin == null) { response.sendRedirect(request.getContextPath() + "/admin/login"); return false; } String uri = request.getRequestURI(); if (uri.contains("/admin/user/") && !"super".equals(admin.getRole())) { response.sendRedirect(request.getContextPath() + "/admin/noPermission"); return false; } return true; }

这种硬编码路径的方式适合小项目,路径多了不好维护,但胜在直观,改起来快。

5.3 把 layui 表格换成前后端分离的 JSON 交互

原项目后台表格可能是 JSP 直接渲染,如果想改成 layui 的table.render异步加载,需要把 Controller 返回值改成@ResponseBody返回 JSON。layui 表格要求返回格式为{code: 0, msg: "", count: 总数, data: [列表]}。Controller 里用Map封装即可。这样改完,页面不刷新就能翻页和搜索,体验提升明显。但要注意日期格式,layui 默认接收时间戳或者yyyy-MM-dd HH:mm:ss字符串,Java 端用@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")注解在实体类日期字段上。

5.4 日志配置与线上排错

项目里如果没有配 logback 或者 log4j,排错全靠System.out.println,效率极低。建议在src/main/resources下加一个logback.xml,把 MyBatis 的 SQL 日志打到控制台:

<logger name="com.shop.mapper" level="DEBUG"/>

这样每次执行 SQL 都会打印语句和参数,哪个字段传错了、哪个条件没拼上,一眼就能看到。线上环境把 level 改成 INFO,避免日志文件爆炸。这个习惯我从第一次做 SSM 项目就养成了,后来每次接手新项目,第一件事就是看日志配置全不全。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进