简介:基于IDEA+Maven+SSM框架实现的超市管理系统,是一份面向Java学习者、毕业设计及期末大作业的完整项目源码。系统围绕超市日常经营管理,设计了用户管理、供应商管理、订单管理、账单管理等核心功能模块,采用JSP+Servlet+Spring+SpringMVC+MyBatis经典技术栈,包含登录验证、增删改查、分页搜索等典型业务场景,前后端交互与分层架构清晰,可帮助读者理解SSM整合流程、Spring容器管理、MyBatis映射及事务处理等关键知识点。压缩包共335个文件,主要包含Java后端源码、JSP视图页面、XML与properties配置文件、JavaScript与CSS前端脚本,以及项目所需的JAR依赖库和运行日志等,整体大小约29.28MB,目录按功能模块组织,便于按需查阅。目前已有174人学习浏览,适合用来对照练习、二次开发,也可作为课程设计或求职作品的基础模板。
1. 一个 .zip 里藏着的 SSM 超市管理系统,导入前先看清三件事
拿到一个名为IDEA+MAVEN+SSM框架 超市管理系统.zip的压缩包,先看目录结构。里面通常有pom.xml、src/main/java、src/main/resources和一份.sql脚本,说明是标准 Maven 工程。这个标题把技术栈列齐了:IDEA 负责开发调试,Maven 管依赖和构建,SSM 由 Spring、Spring MVC、MyBatis 三层组成,业务围绕超市的商品、库存、订单展开。要做的就是让这套超市管理系统在本地 IDEA 里跑起来,涵盖 Maven 环境配置、SSM 依赖整合、数据库初始化和请求链路调试。课程设计、毕业设计或老项目维护场景下都能用这套思路。
2. 导入前先定好地基:Maven 环境配置与 IDEA 侧绑定
2.1 先理清 Maven 是干嘛的:坐标、仓库与依赖管理
Maven 解决的并不只是“自动下载 jar”,而是把 SSM 三件套的版本关系和传递依赖统一收编到pom.xml。没有 Maven 时,你要手工整理 spring-core、spring-webmvc、mybatis、mybatis-spring、mysql-connector-java 这一串 jar,还要自己去适配版本组合;一旦某个 jar 的传递依赖覆盖了另一个 jar 里的类,错误往往要等 Tomcat 启动时才以ClassNotFoundException的形式爆发。
Maven 的核心机制可以拆成三个词:坐标、仓库、生命周期。坐标用groupId:artifactId:version唯一定位依赖;仓库分本地仓库和远程仓库,坐标写好后 Maven 先查本地仓库,没有再去远程下载;生命周期负责编译、测试、打包这串动作。很多人搜索“maven是干嘛的”,本质上就是没搞清这三个词之间的关系,把 Maven 误当成一种“能下载 jar 的插件”。
SSM 项目的依赖管理还牵扯到容器粒度。Spring 的 jar 如果出现 4.x 和 5.x 并存,Spring MVC 的DispatcherServlet和 Spring 根容器会各自加载一份 Class,导致 AOP 注解不生效。Maven 里的<properties>和dependencyManagement就是为了在根 POM 锁住版本,让每个dependency都继承同一个版本号。
2.2 用 settings.xml 配置阿里云镜像与本地仓库路径
settings.xml是 Maven 的全局配置文件,开发机上的所有项目都会读它。我一般会把默认的conf/settings.xml复制到~/.m2/settings.xml,避免升级 Maven 时配置被覆盖。这个文件里有两个地方最值得先改:本地仓库路径和远程镜像。尤其在国内网络下,从中央仓库拉 Spring 依赖经常卡到 10 分钟以上,换阿里云镜像后能压缩到 1 分钟内。
<!-- 位于用户主目录下的 .m2/settings.xml,所有 Maven 项目全局生效 --> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd"> <!-- 本地仓库:优先放在数据盘,避免系统盘重装后依赖全部失效 --> <localRepository>D:/repo/maven_repo</localRepository> <mirrors> <mirror> <!-- id 不能与仓库 id 重复,否则会报 conflict --> <id>aliyun-central</id> <name>Aliyun Central</name> <url>https://maven.aliyun.com/repository/public</url> <!-- 只镜像 central 仓库,保留第三方仓库直连能力 --> <mirrorOf>central</mirrorOf> </mirror> </mirrors> </settings>这段配置里,localRepository决定了依赖最终落在哪个目录。mirrorOf的取值很讲究:写central时只有中央仓库走镜像,写*时所有远程仓库都走这一个地址,会连带把某些私有 Maven 仓库地址也替换掉。对 SSM 项目来说,只镜像central就够了,Spring、MyBatis、MySQL 驱动都在 Aliyun 的 public 仓库里。
| 配置项 | 示例值 | 说明 |
|---|---|---|
| localRepository | D:/repo/maven_repo | 全局依赖缓存地址,路径中避免中文和空格 |
| mirror.id | aliyun-central | 唯一标识,与仓库 id 相同会解析失败 |
| mirrorOf | central | *会拦截全部仓库,导致私有源不可用 |
| mirror.url | maven.aliyun.com/repository/public | public 聚合了常用中央依赖 |
2.3 在 IDEA 里把 Maven 绑定到本地,并执行一次编译验证
配置完 settings.xml,还要让 IDEA 读到这份文件,否则 IDEA 会用内置 Maven 构建,和命令行mvn的行为不一致。打开 IDEA 的File > Settings > Build, Execution, Deployment > Build Tools > Maven,分别设置 Maven home path、User settings file、Local repository。
- Maven home path 指向本地安装的 Apache Maven 目录,不建议选 IDEA 自带的 bundled Maven,版本可能滞后。
- User settings file 勾选 Override 后填入
~/.m2/settings.xml。 - Local repository 勾选 Override 后填入
D:/repo/maven_repo。 - 点击 Maven 工具窗口的刷新按钮,触发一次 reimport。
# 命令行验证 Maven 环境 mvn -v # 只编译不打包,验证 SSM 项目依赖是否全部就绪 mvn clean compile -Umvn -v会打印 Maven 版本和 Java 版本;JDK 版本不一致时,Spring 5 编译会报invalid target release。mvn clean compile只做编译,不会生成可部署的 war,因此是导入阶段最安全的验证命令。-U强制检查远程仓库更新,适合刚切换镜像后的依赖补拉。
提示:Maven 下载失败时不要反复删仓库。先看本地仓库里有没有
.lastUpdated后缀文件,有就说明镜像地址或网络有问题,优先检查 settings.xml。
3. SSM 框架整合的依赖核心与三层配置,版本冲突先死在这里
3.1 从 pom.xml 看 SSM 依赖:版本属性和三组核心坐标
先从pom.xml里看 SSM 项目的最小依赖集合。Spring 与 Spring MVC 都在org.springframework.*下,MyBatis 是独立坐标org.mybatis。注意要额外引入spring-jdbc,没有它拿不到DataSourceTransactionManager,@Transactional会静默失效。
<!-- pom.xml 的核心依赖片段,版本号用属性统一管理 --> <properties> <!-- 5.3.x 是适配 JDK 8 到 17 的常用区间 --> <spring.version>5.3.x</spring.version> <mybatis.version>3.5.x</mybatis.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.1.x</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.x</version> </dependency> </dependencies>用${spring.version}这类属性,能让所有 Spring 相关依赖保持同一版本,避免出现“容器 jar 是 5.0、webmvc 是 5.3”的半新不旧组合。mybatis-spring是 MyBatis 和 Spring 之间的桥接包,负责把SqlSessionFactory交给 Spring 容器管理,它和 Spring 版本有对应关系,2.1.x 配 Spring 5.3.x 很常见。mysql-connector-java高版本驱动类名是com.mysql.cj.jdbc.Driver,如果从旧项目拷贝依赖只改了版本号,没改驱动类名,连数据库时直接报ClassNotFoundException。
| 依赖坐标 | 配套关系 | 常见坑 |
|---|---|---|
| spring-webmvc | 与 spring-jdbc 版本一致 | 多版本 jar 并存会报 NoClassDefFoundError |
| mybatis-spring | 2.x 适配 Spring 5 | 版本不匹配时 Mapper 扫描无声失败 |
| mysql-connector-java | 8.0.x 驱动类带 cj | 旧驱动类 com.mysql.jdbc.Driver 抛异常 |
| javax.servlet-api | 应在 pom 里配置 provided | 不打进 war,否则与 Tomcat 冲突 |
3.2 用 applicationContext.xml 把数据源、Mapper 和事务绑定在一起
SSM 整合通常拆成多个配置文件,分别管理根容器、MVC 子容器和 MyBatis 会话工厂。最常见的误配是根容器把 Controller 也扫了,造成事务在 Controller 上不生效,或者@Autowired出现循环依赖。
<!-- applicationContext.xml:根上下文,管理数据源、事务、DAO、Service --> <context:component-scan base-package="com.supermarket"> <!-- Controller 组件交给 spring-mvc.xml 扫描 --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/supermarket?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai"/> <property name="username" value="root"/> <property name="password" value="123456"/> <property name="maxActive" value="20"/> <property name="initialSize" value="5"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.supermarket.dao"/> </bean>context:component-scan用 exclude-filter 排除 Controller,是 SSM 整合的关键设置。数据源 url 里的useUnicode和characterEncoding决定中文是否乱码,serverTimezone不写时 MySQL 8 启动时大概率报时区异常。SqlSessionFactoryBean的mapperLocations指向 XML Mapper;如果压缩包里没有mapper目录而是注解式 SQL,就要去掉这行。MapperScannerConfigurer会把com.supermarket.dao包下的所有接口动态生成代理对象,放进 Spring 容器。
| 配置文件 | 扫描范围 | 主要职责 |
|---|---|---|
| applicationContext.xml | service、dao、数据源 | 事务、AOP、业务 Bean |
| spring-mvc.xml | controller、视图解析器、静态资源 | HandlerMapping、JSON 转换 |
| mybatis-config.xml | 全局设置,非必须 | 驼峰映射、日志实现 |
3.3 拿到现成压缩包后,如何快速判断 SSM 版本组合是否可用
拿到陌生人给的 zip 包,我一般先做三件事:第一,看pom.xml里的版本区间和当前 JDK 是否匹配;第二,看 Mapper XML 中的 SQL 写法和数据库列是否对得上;第三,执行依赖树命令,确认没有解析出多个 Spring 版本。
# 只看 spring 相关依赖,检查是否存在版本冲突 mvn dependency:tree -Dincludes=org.springframework如果dependency:tree结果里出现两个不同版本的spring-core,说明某个间接依赖强行传递了旧版本,要在对应依赖里用<exclusions>排除旧包。这个命令同样适用于mysql-connector-java,可以帮你快速判断是 pom 里的版本覆盖失败,还是镜像仓库里根本没有对应版本。
4. 超市管理系统跑通的最小闭环:初始化数据库、启动 Tomcat 并核对请求链路
4.1 执行 SQL 脚本,看清超市业务的最小表集合
超市管理系统里最常见的数据表就是商品分类表、商品表、会员表、订单主表和订单明细表。SQL 脚本多数放在db/supermarket.sql或项目根目录。执行脚本前先确认文件编码,Windows 下用记事本另存为 UTF-8 再执行,否则中文注释进库后就是乱码。
-- 初始化超市商品表 CREATE DATABASE IF NOT EXISTS supermarket DEFAULT CHARSET utf8mb4; USE supermarket; DROP TABLE IF EXISTS product; CREATE TABLE product ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '商品ID', name VARCHAR(64) NOT NULL COMMENT '商品名称', price DECIMAL(10,2) NOT NULL COMMENT '销售单价', stock INT NOT NULL DEFAULT 0 COMMENT '库存数量', category_id INT COMMENT '商品分类ID', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '入库时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表';AUTO_INCREMENT由数据库维护自增主键;DECIMAL(10,2)存金额,禁止用 float 或 double,二进制浮点会累积精度误差;utf8mb4比utf8多覆盖 emoji 和生僻字。stock字段一般还要配合应用层校验,保证扣减库存后不会变成负数。
| 表名 | 业务职责 | 核心字段 |
|---|---|---|
| category | 商品分类 | id, name, parent_id |
| product | 商品基本信息与库存 | id, name, price, stock, category_id |
| member | 会员信息 | id, phone, balance, integral |
| order_master | 销售订单主表 | id, order_no, total_amount, pay_type, create_time |
| order_detail | 销售订单明细 | id, order_id, product_id, quantity, price |
一个基础版超市系统先有这几张表就够了。在 SSM 代码里,order_master主表插入和order_detail明细插入要包在同一个事务里,也就是 Service 方法上标记@Transactional,保证订单主表写成功但明细失败时能整体回滚。
4.2 在 IDEA 里配置 Tomcat 和 Artifact,让 SSM 工程跑成 Web 应用
SSM 跑 Web 的方式和 Spring Boot 不同,需要手动配置一个 Tomcat Server。常见做法是在Run > Edit Configurations里新增 Tomcat Server > Local,然后把项目挂到 Deployment 页。IDEA 社区版默认不带 Tomcat 集成,需要装 Smart Tomcat 插件,或者用tomcat7-maven-plugin插件启动。
- 进入
Project Structure > Artifacts,确认存在supermarket: war exploded。 - 打开
Run > Edit Configurations,新增一个 Tomcat Server > Local。 - 切到
Deployment页,点加号选择Artifact,把war exploded添加进去。 - 把
Application context设置为/supermarket。 - 在
Server页把On Update action设为Update classes and resources,实现开发期热部署。
war exploded表示不解压的目录结构,IDEA 会把编译后的classes和webapp资源直接当作 Web 应用根目录,调试时不用反复打包。Application context决定访问路径,启动后地址类似http://localhost:8080/supermarket/product/list。如果 Tomcat 启动后 404,先检查这个 context 和 URL 是否一致。
注意:如果压缩包里没有
web.xml,要确认 Maven 是否配置了maven-war-plugin的failOnMissingWebXml为 false。没有 web.xml 也能运行,但DispatcherServlet必须通过WebApplicationInitializer初始化。
4.3 商品列表页从前端 AJAX 到 Controller 的参数链路排查
请求链路是排查 SSM 项目最核心的切入点:前端页面发 AJAX,经过web.xml里映射到DispatcherServlet的拦截规则,再落到@Controller方法。超市系统最常改的就是商品管理,浏览器控制台网络面板里出现 404,基本是路径没对上。
// 商品列表查询,使用 jQuery 发起 AJAX $.ajax({ url: 'product/list', type: 'GET', data: { categoryId: selectedId, pageNo: 1, pageSize: 10 }, dataType: 'json', success: function (res) { renderProductRows(res.data); }, error: function (xhr, status, error) { console.log(status, error); } });@Controller @RequestMapping("/product") public class ProductController { @Autowired private ProductService productService; /** 商品分页查询,categoryId 可为空 */ @RequestMapping("/list") @ResponseBody public Map<String, Object> list(Integer categoryId, @RequestParam(defaultValue = "1") Integer pageNo, @RequestParam(defaultValue = "10") Integer pageSize) { return productService.pageQuery(categoryId, pageNo, pageSize); } }前端 url 写product/list,后端方法返回的完整路径就是/product/list。注意@RequestParam的页面参数名pageNo是驼峰,前端 data 里的pageNo必须一字不差,否则 Spring MVC 会当作缺参直接 400。categoryId没有设置 required,所以可以传空值;不传时是 null,MyBatis 动态 SQL 里要用<if test="categoryId != null">做空判断。
看到Controller类名后,在 IDEA 里右键选择Diagrams > Show Diagram Popup,可以生成类图,一眼看清ProductController依赖了哪些 Service 和 DAO。排查 NPE 或 Mapper 实现类找不到时,这个图比逐个文件点开快很多。
5. 进阶:用 Maven Profile 把超市系统的开发配置和部署配置分离
5.1 在 pom.xml 中定义 dev 和 prod 两个 profile,并抽离资源目录
项目本地跑通后,真正交付时最怕把开发库的明文密码留在 war 里。Maven Profile 可以用来隔离环境参数,这是比手动改配置更可靠的做法。最常见的形式是把配置目录拆成resources、resources-dev、resources-prod三份。
<!-- pom.xml 中定义两套 profile --> <profiles> <profile> <id>dev</id> <properties> <env>dev</env> </properties> </profile> <profile> <id>prod</id> <properties> <env>prod</env> </properties> </profile> </profiles> <build> <resources> <!-- 先加载公共资源,再叠加环境特定资源 --> <resource> <directory>src/main/resources</directory> </resource> <resource> <directory>src/main/resources-${env}</directory> </resource> </resources> </build>执行mvn clean install -Pdev时,${env}会被替换成dev,Maven 会把src/main/resources-dev追加到 classpath。公共配置如日志框架的log4j2.xml留在resources,数据库地址、账号密码、图片上传路径这些和环境有关的内容放进resources-dev或resources-prod。两个目录里出现同名文件时,后声明的resources-${env}优先级更高,覆盖效果就是环境配置接管公共配置。
5.2 用 Maven 命令行 clean install 动态切换环境
# 开发环境打包,跳过测试 mvn clean install -DskipTests -Pdev # 生产环境打包,跳过测试并强制刷新快照 mvn clean package -DskipTests -Pprod -U-P后面跟的是profile的 id,和 pom 里定义的dev、prod一一对应。-DskipTests跳过测试执行,但测试类仍然会编译;如果项目里有依赖本地环境的测试用例,最好换成-Dmaven.test.skip=true,整个测试阶段都不执行。如果承接的 SSM 项目配置文件里写了${db.url}这类占位符,还要在对应的 resource 上加<filtering>true</filtering>,Maven 才会在复制文件时执行变量替换,否则打包到 war 里后,字符串仍然是${db.url}的字面量,启动时连数据库直接报错。
5.3 验证构建出来的 war 里没有残留开发环境痕迹
# 直接查看 war 中指定配置文件的真实内容 unzip -p target/supermarket.war WEB-INF/classes/jdbc.properties # 检索 war 中是否残留本地数据库地址 zipgrep 'localhost:3306' target/supermarket.warunzip -p会把文件内容输出到标准输出而不解压,是验证 profile 是否生效最快的办法;Windows 下没有 unzip 时,可以把 war 后缀临时改成 zip,用压缩软件打开查看。如果在jdbc.properties里还能看到localhost,说明环境目录没有被 Maven 选中,或者<filtering>没开启。验证通过后再把 war 改名或交给运维,线上包就不会带上开发库的连接串和密码。
本文还有配套的精品资源,点击获取