2026/8/31 19:33:16

SSM人事管理系统源码详解:数据库设计到项目部署踩坑指南

SSM人事管理系统源码详解:数据库设计到项目部署踩坑指南 简介这是一套面向Java初学者与SSM框架入门开发者的完整人事管理系统实战源码适用于课程设计、毕业设计及企业级管理类系统学习。系统基于SpringSpringMVCMyBatis主流整合架构覆盖用户、部门、职位、员工、公告、下载中心等六大核心模块完整实现CRUD、文件上传下载、权限拦截AuthorizedInterceptor、前端动态交互JQueryLayui等典型业务场景。压缩包共284个文件含29个核心Java类如EmployeeController、NoticeController、18个JSP页面、47个Jar依赖、20个JS脚本及1个SQL建库脚本结构清晰、分层规范便于理解MVC职责划分与SSM整合逻辑。资源包大小30.77MB已附详细导入运行文档含MySQL数据库初始化与IDEA/Eclipse配置说明。目前已有1475人学习下载配套代码经实测可直接运行是掌握Java Web企业开发全流程的高实用性参考项目。 先说个实在的SSM这套组合Spring SpringMVC MyBatis在Java后端里属于“老牌黄金搭档”虽然现在Spring Boot大行其道但只要你翻招聘要求或翻毕设题目就会发现SSM依然是绕不开的坎。尤其是一个基于SSM框架开发的人事管理系统它几乎把JavaWeb开发的核心知识点全串起来了三层架构、依赖注入、AOP事务、ORM映射、MVC分发、JSP渲染、MySQL表设计……一个项目全跑一遍比你看十遍教程都管用。这个项目源码我前前后后跑了很多遍也帮人排查过各种启动问题。今天不整虚的直接把这套人事管理系统的设计思路、数据库表结构、SSM整合细节、源码跑通步骤、高频踩坑记录全部摊开讲。不管你是准备毕设、做课程设计还是想靠这个项目补一补JavaWeb的底子这篇都能让你少走不少弯路。1. 项目整体设计与技术选型思路1.1 为什么这个项目首选SSM而非Spring Boot聊技术选型得结合场景。人事管理系统这种典型的业务型CRUD项目核心是员工信息管理、部门组织架构、考勤薪资记录、系统用户登录权限它不涉及高并发、不涉及分布式就是标准的B/S架构数据管理系统。这种场景下用SSM反而比Spring Boot更合适——因为练习价值更高。Spring Boot虽然“零配置”很爽但它把大量底层细节封装好了新手反而学不到东西。SSM需要手动整合Spring容器、手动配置SpringMVC的分发器、手动写MyBatis的Mapper映射每一步配置都能逼你搞清楚“框架到底在干什么”。等你把SSM这套手动挡玩明白了再去看Spring Boot的自动配置完全是降维打击。另外从实用角度看目前大量老系统的维护、高校课程设计、毕业设计题目库仍然以SSM为主。你拿着一个SSM人事管理系统无论用来应付毕设答辩还是写进简历作为项目经验认知度都非常高。面试官听到“SSM项目”通常会往下问“Spring IOC原理”“MyBatis动态SQL”“SpringMVC流程”这些都是你亲手搭过的答起来心里有底。1.2 人事管理系统的功能模块与权限边界划分人事管理系统不是一个单纯“增删改查”demo真正要落地至少要把下面这几个模块拆清楚员工管理模块员工信息的增删改查、按姓名/工号/部门筛选、员工离职状态变更。这是系统的核心主数据所有其他模块都以员工表为基准。部门管理模块部门树形结构维护部门新增、合并、撤销以及部门下的员工人数统计。考勤管理模块每日打卡记录导入或录入按月份汇总员工出勤天数、迟到早退次数。薪资管理模块基础工资、岗位工资、奖金、五险一金扣除项按月生成薪资报表。系统管理模块用户登录、修改密码、权限拦截。一般分为管理员和普通HR两种角色管理员能看全部数据普通HR只能操作自己负责的部分。很多入门源码只做了前两个模块考勤和薪资是“硬凑”的假模块数据不做关联。但你拿来做项目的话我建议至少把员工、部门、登录权限这三个模块做成完整闭环考勤和薪资做基础版本即可。这样既控制了开发量又能展示你“对业务有理解”毕竟权限和主数据才是HR系统的灵魂。1.3 技术栈分层与数据库交互路径SSM项目的代码分层非常固定也是这套框架“规范”的来源。一个用户请求从浏览器发出来最终落库再返回走的是这条路浏览器 → JSP页面发请求 → SpringMVC前端控制器DispatcherServlet → HandlerMapping找到对应Controller → Controller调用Service接口 → Service实现类调用Mapper接口 → MyBatis执行SQL → MySQL返回结果 → 逐层封装回填 → ModelAndView渲染JSP → 响应回浏览器这套链路里每一层都有明确的职责也是面试高频题Controller层只做参数接收、参数校验、调用Service、把结果放Model、指定跳转视图。Service层业务逻辑比如发放薪资时要先校验员工状态、计算个税、记录日志。Service接口和Impl分离是一种好习惯。Mapper层DAO层只负责数据库操作一个方法对应一条SQL。MyBatis的Mapper接口配合XML文件可以写动态SQL这是它比JDBC省事的地方。实体层entity/pojo对应数据库表的Java对象字段名与表字段一一映射。这里有个关键点MyBatis的ORM和Hibernate不同它不是完全自动的需要你写SQL。这既是缺点也是优点——执行效率可控、SQL灵活度极高尤其擅长处理多表联查和复杂统计。人事管理系统的报表查询基本都是多表关联用MyBatis写动态SQL比Hibernate的HQL舒服太多。2. 数据库设计人事管理系统的数据基石2.1 员工主表设计思路与字段规范数据库表设计直接决定系统能撑多远。人事系统最重要的是员工主表employee它的字段设计要兼顾可扩展性和查询效率。我常用的表结构是这样CREATE TABLE employee ( id INT NOT NULL AUTO_INCREMENT COMMENT 主键ID, emp_no VARCHAR(20) NOT NULL UNIQUE COMMENT 工号, name VARCHAR(50) NOT NULL COMMENT 姓名, gender TINYINT DEFAULT 1 COMMENT 性别1男 2女, birthday DATE DEFAULT NULL COMMENT 出生日期, id_card VARCHAR(18) DEFAULT NULL COMMENT 身份证号, phone VARCHAR(20) DEFAULT NULL COMMENT 手机号, email VARCHAR(100) DEFAULT NULL COMMENT 邮箱, education VARCHAR(20) DEFAULT 本科 COMMENT 学历, dept_id INT DEFAULT NULL COMMENT 所属部门ID, position_id INT DEFAULT NULL COMMENT 职位ID, hire_date DATE DEFAULT NULL COMMENT 入职日期, status TINYINT DEFAULT 1 COMMENT 在职状态1在职 2离职, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), KEY idx_dept_id (dept_id), KEY idx_name (name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT员工信息表;几个设计要点说一下工号emp_no设唯一索引。这符合真实企业场景工号是员工的业务标识不要用自增id当工号。万一员工离职后工号重复使用历史考勤和薪资记录会串数据。status字段做逻辑删除。人事系统里员工数据不能物理删除否则历史薪资、社保记录全断了。状态改为离职2即可员工列表默认只查status1后台可以查全部。外键不要物理建用普通索引。很多教程在建表时喜欢加FOREIGN KEY实际项目里外键会锁表、影响性能、而且MyBatis多表查询根本用不上外键约束。只需要在关联字段建索引就行。必填字段设置NOT NULL避免程序里各种空指针判断。2.2 部门、职位、考勤、薪资关联表设计除了员工主表系统还至少需要这几张核心表部门表departmentCREATE TABLE department ( id INT NOT NULL AUTO_INCREMENT, dept_name VARCHAR(50) NOT NULL COMMENT 部门名称, parent_id INT DEFAULT 0 COMMENT 上级部门ID0表示顶级, manager VARCHAR(50) DEFAULT NULL COMMENT 部门负责人, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;parent_id字段支持树形部门结构比如总公司 → 技术部 → 后端组。查询子部门时用递归或MyBatis的 拼接。考勤表attendanceCREATE TABLE attendance ( id INT NOT NULL AUTO_INCREMENT, emp_no VARCHAR(20) NOT NULL COMMENT 工号, att_date DATE NOT NULL COMMENT 考勤日期, status TINYINT DEFAULT 1 COMMENT 1正常 2迟到 3早退 4缺勤, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_emp_date (emp_no, att_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里有个特别容易踩的坑同一个员工同一天只能有一条考勤记录所以必须建联合唯一索引uk_emp_date(emp_no, att_date)。没有这个约束批量导入考勤数据时插两条重复记录月底统计就会翻车。薪资表salaryCREATE TABLE salary ( id INT NOT NULL AUTO_INCREMENT, emp_no VARCHAR(20) NOT NULL COMMENT 工号, salary_month VARCHAR(7) NOT NULL COMMENT 薪资月份例如2025-06, base_salary DECIMAL(10,2) DEFAULT 0 COMMENT 基础工资, performance DECIMAL(10,2) DEFAULT 0 COMMENT 绩效工资, bonus DECIMAL(10,2) DEFAULT 0 COMMENT 奖金, insurance DECIMAL(10,2) DEFAULT 0 COMMENT 五险一金扣除, should_pay DECIMAL(10,2) DEFAULT 0 COMMENT 应发工资, actual_pay DECIMAL(10,2) DEFAULT 0 COMMENT 实发工资, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_emp_month (emp_no, salary_month) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT薪资表;薪资表同样要建联合唯一索引避免重复发放记录。DECIMAL(10,2) 而不是 FLOAT因为金额必须精确运算FLOAT这种浮点类型在钱上会有精度问题这是需要用教训换来的经验。2.3 用户表与权限管理的简化方案人事系统登录用户表sys_user和员工表建议分开。因为有的系统维护人员可能不是企业员工而员工也不一定都有系统登录权限。用户表设计相对简单CREATE TABLE sys_user ( id INT NOT NULL AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE COMMENT 登录名, password VARCHAR(100) NOT NULL COMMENT 密码MD5加密存储, real_name VARCHAR(50) DEFAULT NULL COMMENT 真实姓名, role TINYINT DEFAULT 1 COMMENT 角色1管理员 2普通HR, status TINYINT DEFAULT 1 COMMENT 账号状态1启用 0禁用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;密码存储在实际项目里至少要MD5加盐更安全的做法是BCrypt。但很多课程设计源码直接明文存这属于演示代码的偷懒。你作为学习者哪怕项目是参考别人的也建议改成加密存储答辩时是加分项。权限这块我没用Spring Security或者Shiro。人事系统的需求相对简单用拦截器 session角色标记就够了。管理员和普通HR的区别通过Controller层或JSP页面的角色判断来控制菜单显示和操作按钮即可。杀鸡用牛刀只会增加学习负担。3. SSM整合与核心功能实现3.1 环境准备清单与版本匹配建议跑SSM项目之前先把环境装对版本不匹配会让你怀疑人生。我实测稳定的组合JDK1.8不要用11或17老项目在JDK18上经常遇到模块访问限制问题Maven3.6.3Tomcat8.5兼容JDK1.8支持Servlet 3.1MySQL5.7或8.0.338.0需要注意驱动名不同IDEA2020.3及以上都行Maven依赖版本也不是随便写的用我验证过的一组properties spring.version5.2.3.RELEASE/spring.version mybatis.version3.5.4/mybatis.version mysql.version8.0.33/mysql.version /properties如果你是MySQL 5.7mysql-connector-java用5.1.49如果是8.0驱动类名改为com.mysql.cj.jdbc.Driver并且URL后面要拼?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai否则要么报SSL警告要么报时区错误要么乱码。这三个参数少写一个都会出问题。3.2 Spring与MyBatis整合的配置要点SSM的整合核心就是让Spring容器管理MyBatis的SqlSessionFactory和Mapper接口代理这样你的Service里才能直接Autowired注入Mapper。这部分是源码里最关键的配置applicationContext.xml大致长这样!-- 读取数据库配置 -- context:property-placeholder locationclasspath:jdbc.properties/ !-- 配置数据源 -- bean iddataSource classcom.alibaba.druid.pool.DruidDataSource property namedriverClassName value${jdbc.driver}/ property nameurl value${jdbc.url}/ property nameusername value${jdbc.username}/ property namepassword value${jdbc.password}/ /bean !-- 配置SqlSessionFactory -- bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ property namemapperLocations valueclasspath:mapper/*.xml/ property nametypeAliasesPackage valuecom.hr.entity/ /bean !-- 扫描Mapper接口 -- bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.hr.mapper/ /bean !-- 开启Spring事务管理 -- bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManager property namedataSource refdataSource/ /bean tx:annotation-driven transaction-managertransactionManager/这里我特别想强调一下事务。很多入门源码把事务配置删了因为CRUD不涉及多表写入看不出问题。但薪资发放这种业务要同时改salary表、更新员工状态、记录操作日志任何一个环节出错整个数据就脏了。建议你在Service实现类上加上Transactional(rollbackFor Exception.class)并确保事务管理器配置正确这是“看起来小但很专业”的加分设计。3.3 SpringMVC配置与web.xml的拦截路由SpringMVC的配置核心是spring-mvc.xml负责扫描Controller、开启注解驱动、配置视图解析器。具体配置!-- 扫描Controller层 -- context:component-scan base-packagecom.hr.controller/ !-- 注解驱动 -- mvc:annotation-driven/ !-- 静态资源放行 -- mvc:default-servlet-handler/ !-- JSP视图解析器 -- bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/WEB-INF/views// property namesuffix value.jsp/ /bean注意prefix和suffix这两个配置Controller里return employee/list实际会找/WEB-INF/views/employee/list.jsp。把JSP放在WEB-INF下面是个好习惯因为用户没法直接通过URL访问WEB-INF目录下的文件只能通过Controller转发过来这能防止跳过登录直接打开页面。web.xml里要做三件事配置Spring容器监听器、配置DispatcherServlet、配置字符编码过滤器。很多项目中文乱码就是漏了编码过滤器filter filter-nameencodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping这个过滤器必须配置在DispatcherServlet之前并用/*匹配才能保证POST请求和响应都是UTF-8编码。3.4 登录鉴权与拦截器实现细节登录功能看着简单但它是人事系统最容易出安全问题的点。简单的做法是登录成功把用户对象放进session然后写一个拦截器统一校验public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行登录请求 if (request.getRequestURI().contains(/login)) { return true; } Object user request.getSession().getAttribute(loginUser); if (user null) { // 未登录直接重定向到登录页 response.sendRedirect(request.getContextPath() /toLogin); return false; } return true; } }然后在spring-mvc.xml里注册拦截器mvc:interceptors mvc:interceptor mvc:mapping path/**/ mvc:exclude-mapping path/login/ mvc:exclude-mapping path/toLogin/ mvc:exclude-mapping path/css/**/ mvc:exclude-mapping path/js/**/ mvc:exclude-mapping path/images/**/ bean classcom.hr.interceptor.LoginInterceptor/ /mvc:interceptor /mvc:interceptors小心别把静态资源也拦截了否则登录页的CSS样式全部加载不出来页面跟裸奔一样。排除的路径要按你的项目实际资源路径调整。登录密码的校验我也多说一句存库的密码加盐MD5加密登录时把用户输入的密码同样加盐加密再比对而不是直接用明文SQL去查。这样即使数据库泄露也不会直接暴露所有账号密码。3.5 员工管理模块的CRUD与分页查询逻辑员工列表页是整个系统最常用的功能这里用一个“带关键字的条件分页查询”举例这是最标准的写法Controller层Controller RequestMapping(/employee) public class EmployeeController { Autowired private EmployeeService employeeService; RequestMapping(/list) public String list(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, String keyword, Model model) { PageInfoEmployee pageInfo employeeService.findEmployeePage(pageNum, pageSize, keyword); model.addAttribute(pageInfo, pageInfo); model.addAttribute(keyword, keyword); return employee/list; } }Service层Override public PageInfoEmployee findEmployeePage(int pageNum, int pageSize, String keyword) { PageHelper.startPage(pageNum, pageSize); ListEmployee list employeeMapper.selectByCondition(keyword); return new PageInfo(list); }Mapper的XMLselect idselectByCondition resultTypecom.hr.entity.Employee SELECT e.*, d.dept_name, p.position_name FROM employee e LEFT JOIN department d ON e.dept_id d.id LEFT JOIN position p ON e.position_id p.id where e.status 1 if testkeyword ! null and keyword ! AND (e.name LIKE CONCAT(%, #{keyword}, %) OR e.emp_no LIKE CONCAT(%, #{keyword}, %)) /if /where ORDER BY e.create_time DESC /select分页用PageHelper插件它的原理是拦截器在MyBatis执行前改写SQL自动拼接LIMIT。要用它就在pom.xml里加依赖然后在MyBatis配置里加plugin interceptorcom.github.pagehelper.PageInterceptor/。这个插件不用配置太多东西但请注意版本要和MyBatis匹配pagehelper 5.x对应mybatis 3.x。之所以用LEFT JOIN而不是INNER JOIN是因为某些员工可能还没有分配部门dept_id为空LEFT JOIN能保证这些员工也查出来部门字段显示为空。这个细节在实际使用中非常容易出现很多人上线后才发现部门调整中的员工从列表里消失了。4. 实操过程从源码下载到项目跑通4.1 数据库初始化与账号准备我拿到一个SSM人事系统的源码第一步永远是导入数据库而不是先看代码。因为数据库跑通了代码基本就能跑通一半。先在MySQL里创建数据库CREATE DATABASE hr_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;建好库之后导入源码里自带的schema.sql或hr_system.sqlmysql -u root -p hr_system hr_system.sql或者直接用Navicat/DataGrip等工具运行SQL脚本。导入之后重点检查几件事employee、department等核心表是否有数据。有些源码故意不初始化员工数据你要手动插入几条测试数据。看看sys_user表里的账号密码是不是加密的。如果SQL里就直接是123456说明源码本身只是演示你在登录时要输入这个明文。确认下有没有金额字段如果有检查数据类型是不是DECIMAL。数据库这步一定别跳过。很多人在IDEA里折腾半天发现项目启动报错最后查出来是根本没导入数据库或者连接密码不对。4.2 IDEA导入SSM项目的工作流程在IDEA中导入SSM项目有几个关键步骤做错一个项目就起不来File → New → Project from Existing Sources选择源码目录选Maven导入等待依赖下载完成。如果网络慢或者镜像拉不下来记得在settings.xml里配置阿里云镜像。确认JDK版本。IDEA里File → Project Structure → Project设置Project SDK为1.8。配置Tomcat。Run → Edit Configurations → 点 号 → Tomcat Server → Local选择你本地Tomcat目录。Deployment里点 号选择ArtifactArtifact必须选“xxx:war exploded”Application context可以改为/hr_system。修改jdbc.properties里的数据库账号密码确认和本地MySQL一致。启动Tomcat控制台显示Server startup in xxx ms访问http://localhost:8080/hr_system。这里有个IDE的细节如果对war exploded打不起包要检查Project Structure → Artifacts里是否已经生成了这个模块的war exploded。没有就手动加 → Web Application: Exploded → From Modules选你这个模块。Output directory保持默认的tomcat/webapps下的路径就行。4.3 核心代码包结构与支撑类讲解跑通项目后我建议按这个顺序去读代码别一上来就抠业务com.hr ├── controller # 控制层接收请求、参数校验、返回视图 ├── service # 业务层接口定义业务方法 │ └── impl # 业务实现类容器扫描、事务控制 ├── mapper # MyBatis的Mapper接口数据访问方法声明 ├── entity # 实体类对应数据库表 ├── interceptor # 拦截器比如登录校验 └── common # 公共类统一返回值、常量、MD5工具类resources目录下resources ├── mapper/ # MyBatis映射文件和mapper接口对应 ├── applicationContext.xml # Spring核心配置 ├── spring-mvc.xml # SpringMVC配置 ├── jdbc.properties # 数据库连接参数 ├── mybatis-config.xml # MyBatis全局配置可选 └── log4j.properties # 日志配置可选读源码时有个小技巧从Controller开始往下看。比如想看员工列表逻辑就先看EmployeeController的list方法然后跳到EmployeeService接口和Impl再看EmployeeMapper接口最后打开resources/mapper/EmployeeMapper.xml看SQL。按这个链路走你能完整理解一条请求的生命周期比拿着源码从头一页一页翻效率高得多。4.4 JSP页面渲染与数据回显的实现方式SSM项目的JSP页面通常放在WEB-INF/views下配合JSTL标签库做数据遍历和格式化。以一个员工列表页面片段为例% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % taglib prefixfmt urihttp://java.sun.com/jsp/jstl/fmt % table classtable table-bordered thead tr th工号/th th姓名/th th部门/th th职位/th th入职日期/th th状态/th th操作/th /tr /thead tbody c:forEach items${pageInfo.list} varemp tr td${emp.empNo}/td td${emp.name}/td td${emp.deptName}/td td${emp.positionName}/td tdfmt:formatDate value${emp.hireDate} patternyyyy-MM-dd//td td c:if test${emp.status 1}在职/c:if c:if test${emp.status 2}离职/c:if /td td a href${pageContext.request.contextPath}/employee/edit?id${emp.id}编辑/a a href${pageContext.request.contextPath}/employee/delete?id${emp.id} onclickreturn confirm(确定删除该员工吗)删除/a /td /tr /c:forEach /tbody /table这里有个容易忽略的坑JSP页面上获取上下文的路径一定要用${pageContext.request.contextPath}而不是写死/hr_system。因为你的Application context可能改了写死了转发和跳转全部404。JSP渲染数据时还有一点实体类字段必须是驼峰命名并且提供getter/setter否则EL表达式${emp.empNo}取不到值。MyBatis在开启驼峰映射的前提下数据库字段emp_no能自动映射到empNo属性在mybatis-config.xml里加上settings setting namemapUnderscoreToCamelCase valuetrue/ /settings别小看这个配置不开启的话你查询结果里所有下划线字段都映射不上页面一片空白。5. 常见问题与排查技巧实录5.1 数据库连接失败与驱动版本冲突这个算是SSM新手报警率第一名。典型的报错Cannot create PoolableConnectionFactory (Access denied for user rootlocalhost (using password: YES))排查思路照顺序来检查jdbc.properties里面的账号密码有没有写错。注意properties文件里不需要给密码加引号password123456就对了有引号反而会把引号当作密码的一部分。检查URL里的IP和端口。本机用localhost:3306没问题如果是远程数据库要确认防火墙开放了3306端口。MySQL 8.0务必把驱动类改成com.mysql.cj.jdbc.Driver、URL加serverTimezoneAsia/Shanghai。用数据库客户端单独连一次排除数据库服务本身没起来。这里很多人会忽略一个点pom.xml里如果同时引入了5.1.x和8.0.x两个版本的mysql驱动Maven会默认选最近的版本可能导致驱动类和URL不匹配。建议pom里明确只保留一个版本。5.2 启动报错严重: 找不到类 org.springframework.web.servlet.DispatcherServlet这个报错一看就知道是IDEA部署Tomcat时“将依赖打进Artifact”这一步没做。Tomcat启动时不会自动去Maven仓库找jarwar包或war exploded必须把所有依赖的jar包放到WEB-INF/lib下。解决方法File → Project Structure → Artifacts → 选中你的war exploded → 右侧Available Elements里面找到你的module依赖右键 → Put into /WEB-INF/lib。然后重新Build → Rebuild再启动就好了。如果不做这一步Spring和MyBatis的jar包永远不在运行时里无论你怎么修pom都没用。我见过有人在网上搜各种答案折腾了几个小时其实就是这个设置。5.3 页面报404SpringMVC请求路径对不上页面访问http://localhost:8080/hr_system/employee/list返回404分三种情况Controller没扫描到spring-mvc.xml里的context:component-scan base-packagecom.hr.controller/包路径写错了或者你手动写了Controller注解但被Spring容器和SpringMVC容器重复扫描。视图解析器路径不对Controller返回employee/list但在WEB-INF/views下面没有employee目录或者没有list.jsp文件。检查一下文件真实位置。Tomcat的Application context路径不对如果你部署后App context是/hr_system_war_exploded而你访问的是/hr_system自然404。IDEA里Deployment页面可以修改这个值保持和你的访问路径一致即可。排查404最有效的办法是看Tomcat控制台日志如果Controller层有方法映射到日志里会打印RequestMappingHandlerMapping注册信息。如果压根没打印说明Controller没被扫到如果打印了那就是视图路径或者部署路径的问题。5.4 中文乱码问题的三级排查中文乱码在JSP SSM项目里几乎人人都会遇到而且乱码的源头可能不止一处。我的排查顺序是JSP页面本身% page contentTypetext/html;charsetUTF-8 languagejava %这行有没有。没有的话页面显示的中文直接乱码。数据库连接jdbc.properties里URL有没有characterEncodingutf8没有就乱码。另外建库时建议用utf8mb4比utf8能存更多字符。Tomcat接收参数如果是GET请求中文乱码在Tomcat的server.xml里给Connector加上URIEncodingUTF-8。如果是POST请求乱码用web.xml里的CharacterEncodingFilter解决。排查时在页面显示处打印一句固定的中文测试比如“测试中文”逐层确认是文件乱码、传输乱码还是存储乱码。这个问题看似小但在实际项目里最容易让人抓狂建议把三处配置一次性全部配好。5.5 IDEA中JSP函数引用无法跳转的问题很多用IDEA的小伙伴遇到过JSP里写的自定义函数或方法引用按住Ctrl点不进去甚至整个jsp文件都没有语法高亮。这不是代码问题是IDEA的Mark Directory没配好。解决办法在IDEA左侧项目树里找到你的webapp目录或src/main/webapp右键 → Mark Directory as → Web Resources Directory。再把WEB-INF下的jsp目录也标记好。如果还是没有高亮或跳转检查IDEA有没有装Java EE插件新版IDEA如2021默认不带Java EE支持要自己安装。另外太老的IDEA版本对JSP的动态EL表达式提示很弱建议升级到2022.2以上或者干脆用2024/2025版本体验会好很多。5.6 常见问题速查表为了方便你快速定位我整理了一份精简速查表现象根本原因快速解决启动报错Access denied数据库密码错误核对jdbc.properties启动报错Unknown database数据库名不存在先CREATE DATABASE端口8080被占用其他程序占用改Tomcat端口或杀掉占用进程页面全部没有样式静态资源被拦截在spring-mvc.xml放行静态资源登录成功后跳转404视图路径不对检查WEB-INF/views下是否有对应jspSQL语句报错无效列名数据库字段名或表别名错误核对Mapper.xml里的SQL时间显示为null实体类没有date类型转换用DateTimeFormat或手动格式化批量插入慢没有开启批处理MyBatis配置allowMultiQueries内存溢出OutOfMemoryTomcat默认内存不够在catalina.sh里调大-Xmx6. 这套源码的深层价值与扩展方向6.1 读源码的路线与学习方法建议把项目跑通只是第一步。很多同学跑通了就以为完事了等面试官问一句“你项目里权限怎么设计的”就傻眼。我建议跑通后做三件事第一关闭浏览器凭记忆在白纸上画出你理解的架构图从浏览器发请求到页面渲染返回经过了哪些类、哪些配置文件、哪些方法。画不出来就回去看直到能画出来。这张图就是你对SSM的完整认知。第二挑一个完整的功能模块读代码比如员工管理用刚才说的Controller → Service → Mapper → XML链路逐行读源码。读的时候问自己如果我要加一个字段“籍贯”要从数据库改到页面所有要动的文件有哪些这个功能改造练完基本就掌握这套源码了。第三用断点调试看一次请求的完整过程。在Controller入口打一个断点然后F7跟着代码一步步走观察request、model、MyBatis参数处理。比你看十遍文字教程都管用。6.2 从毕设/课程项目到“可写进简历”的优化路线如果这个项目你是要拿来写简历或面试聊的至少要把下面几个“平庸点”去掉把SQL查询做索引优化。在employee表的name、dept_id、status字段建联合索引用EXPLAIN看查询计划面试时能讲出“我的SQL是覆盖索引”这种话优势明显。加入简单的操作日志功能。写一个AOP切面统一记录哪个用户、什么时间、操作的哪个功能。人资系统的敏感操作日志是合规刚需这一点很实战。把密码加密从MD5升级到BCrypt。spring-security-crypto里自带BCryptPasswordEncoder登录时校验、注册时加密。面试时提“安全设计”很有说服力。增加数据导出功能。用POI/Aliyun EasyExcel在员工列表页加一个“导出Excel”按钮。人事系统导出报表是刚需做完你会觉得业务场景丰富很多。优化不是让你推翻重写而是基于现有源码做增量。每做完一个优化点就记一句笔记面试聊项目的时候你就能说出“我基于一个SSM人事管理系统做了日志切面、Excel导出、安全加固这三件事”瞬间和只会背增删改查的求职者拉开差距。我在实际带人和做项目的过程中最深的一个体会是代码跑通根本不值得兴奋把每一行配置、每一条SQL背后的为什么搞明白才是源码对你真正的价值。这套人事管理系统的源码我建议你至少完整敲一遍按钮、跟一遍调试、改一个功能、加一个模块。四步走完SSM这套东西就算真正长在你身上了以后无论看Spring Boot项目还是自己写JavaWeb都就是从“用过”变成了“懂”的状态。本文还有配套的精品资源点击获取