简介:这是一份基于SSM框架的养老院后台管理系统毕业设计源码与数据库资源,主要面向计算机相关专业正在准备毕业设计的学生,以及需要项目实战练习的Java学习者,同样适用于课程设计和期末大作业。压缩包共70个文件,以45个Java源码、20个XML配置、1个数据库SQL脚本及少量属性文件和说明文档为主,整体约43KB,文件结构紧凑,便于快速定位与导入开发环境。目前已有696人学习下载,资源适合直接作为毕设项目使用。项目后台采用SSM框架并配合MySQL数据库,开发环境为JDK与IDEA,已经过导师指导与严格调试,可稳定运行;内含完整项目源码、数据库脚本、开发工具指引和项目说明,能帮助读者理解养老院后台管理系统的分层架构与业务实现思路,也可为毕业设计答辩或课程设计提供参考。
1. 拿到“养老院后台管理系统”压缩包后,先别急着 import 工程
把“SSM框架养老院后台管理系统源码+数据库.zip”解压后,目录里通常躺着三样东西:一个 Maven 工程(或普通 Web 工程)、一个 .sql 数据库脚本、一份说明文档。这个结构决定了它的定位——不是生产级 SaaS,而是把 Java 后端三大框架 Spring、Spring MVC、MyBatis 串起来的完整 demo,附带建表语句和种子数据,适合做毕业设计二次开发,也适合刚入职的初级工程师拿来看懂一套后台管理系统从数据库到控制器的数据流。
但这类压缩包最容易在第一步就劝退人:IDEA 里 import 之后疯狂报红,Tomcat 启动直接 404,或者数据库连不上。问题大多不是源码本身,而是 JDK 版本、Maven 仓库、MySQL 字符集、Tomcat 路径这几样环境变量没对齐。本文会从工程结构和依赖入手,先讲清楚 SSM 三个框架在这个项目里各自扮演什么角色,再给出一套能复现的最小启动流程,最后落到 Shiro 权限控制和 MyBatis 动态 SQL 这两个实际开发中最常被打磨的环节——这两个点也是面试时围绕 SSM 项目最容易被追问的地方。全文不会出现虚构的官方文档,只会讲一线工程里验证过的做法和参数边界。
2. 先分清 SSM 里三个框架各自管什么,再谈改代码
2.1 Spring 是容器,Spring MVC 是 HTTP 入口,MyBatis 是 SQL 映射器
这套组合里,Spring 负责管理对象生命周期和依赖注入,被管理对象叫 Bean。养老院管理系统里的 Service、Mapper 接口、DataSource、事务管理器,全部注册进 Spring 容器。Spring MVC 是表现层框架,DispatcherServlet 接收 HTTP 请求后,通过 HandlerMapping 找到对应的 Controller 方法,再通过 ViewResolver 把 ModelAndView 解析成 JSP 或 JSON。MyBatis 是持久层框架,Mapper 接口的方法名与 XML 文件里的 statement id 对应,SQL 写死在 XML 里,由 SqlSessionFactory 创建 SqlSession 执行。
这个项目的关键在于:三个框架的配置文件是分开的,但彼此又通过 Spring 容器串联。典型配置是 applicationContext.xml 声明组件扫描、数据源、事务管理器;spring-mvc.xml 声明 Controller 扫描、注解驱动、视图解析器。MyBatis 的 SqlSessionFactoryBean 会通过 mapperLocations 属性指向 classpath 下的 mapper 目录,然后由 Spring 把 Mapper 接口代理实现注册进容器。
2.2 从依赖坐标判断这个工程用的是 SSM 的哪个版本组合
不同年代的 SSM 工程依赖版本差异很大,直接影响能否跑起来。养老院后台管理系统这类毕业设计多数基于 Spring 4.x 或 5.x,MyBatis 3.4.x-3.5.x,Spring MVC 与 Spring 同版本号。打开 pom.xml 后重点看这几个坐标:
| 框架 | 常见坐标 | 版本范围 |
|---|---|---|
| Spring & Spring MVC | org.springframework:spring-context / spring-webmvc | 4.3.x / 5.2.x |
| MyBatis | org.mybatis:mybatis | 3.4.x / 3.5.x |
| MyBatis-Spring 桥接 | org.mybatis:mybatis-spring | 1.3.x / 2.0.x |
| 数据库连接池 | com.alibaba:druid 或 commons-dbcp | 1.1.x / 1.4.x |
| Servlet API | javax.servlet:javax.servlet-api | 3.1.0 / 4.0.1 |
查看方式是在 IDEA 右侧 Maven 工具窗口展开 Dependencies。如果发现 spring-webmvc 和 spring-context 版本不一致,或者 mybatis-spring 与 mybatis 版本跨代,轻则启动报 NoSuchMethodError,重则 Bean 注入失败。常见做法是统一 Spring 家族版本号为同一个,MyBatis 与 mybatis-spring 遵循官方兼容矩阵(mybatis-spring 2.x 对应 mybatis 3.5+,1.x 对应 mybatis 3.4 及以下)。
另外,JDK 版本决定 Spring 版本上限。Spring 5.2.x 在 JDK 8 上运行没问题,但如果你本机装了 JDK 17,直接运行 Spring 4.x 工程大概率会报 IllegalAccessError 或 --add-opens 相关错误。建议安装 JDK 8,并在 pom.xml 里确认 maven.compiler.source 和 target 都是 1.8。以下是典型 pom.xml 关键片段:
<properties> <spring.version>5.2.22.RELEASE</spring.version> <mybatis.version>3.5.10</mybatis.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</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.0.7</version> </dependency> </dependencies>这段配置里,mybatis-spring 2.0.7 与 mybatis 3.5.10 是兼容组合,Spring 5.2.22 与 Servlet 3.1+ 容器兼容,Tomcat 8.5 或 9.0 都可以承载。注意:不要混用 javax.servlet 与 jakarta.servlet 依赖,Spring 5.x 走的是 javax 命名空间,Spring 6.x 才是 jakarta。
2.3 web.xml 加载顺序不对,Controller 永远进不来
SSM 工程没有 Spring Boot 的自动装配,所有配置的入口是 web.xml。它的加载顺序决定了 Spring 容器和 Spring MVC 容器谁先创建。先看一个标准配置:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>ContextLoaderListener 先读取 applicationContext.xml,创建父容器,管理 Service、Mapper、DataSource 这些业务层 Bean。DispatcherServlet 启动时再读取 spring-mvc.xml,创建子容器,管理 Controller。子容器可以拿到父容器的 Bean,所以 Service 能被注入到 Controller;但父容器不能反向引用子容器的 Bean。
/ 会把所有请求都交给 DispatcherServlet,包括静态资源。资源请求会被 MappingJackson2JsonView 或 HandlerAdapter 当成一个不存在的 Handler,从而 404。解决方式是在 spring-mvc.xml 里加 mvc:default-servlet-handler/ ,或者在 web.xml 里单独映射 .js/.css/.jpg 到 DefaultServlet。毕业设计项目很多直接把静态资源放在 webapp/static 下,如果访问不到,优先检查这一项。
3. 数据库脚本导入和 MyBatis 参数设置是启动成败的分水岭
3.1 用 Navicat 或命令行导入 .sql 的正确姿势
压缩包里附带的数据文件一般是 old_nurse_home.sql 或类似命名,里面包含 CREATE DATABASE、CREATE TABLE、INSERT INTO 语句。导入最常见的问题不是 SQL 语法错误,而是字符集。养老院系统里的中文数据包括老人姓名、护理等级、家属联系方式等,如果库表字符集不是 utf8mb4,导入后中文全部变成问号或乱码。命令行导入前先确认两件事:
CREATE DATABASE IF NOT EXISTS old_nurse_home DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;如果建库语句里只写了 utf8,建议改成 utf8mb4。utf8mb4 是 utf8 的超集,能存储 Emoji 和生僻字,而且与 utf8 的排序规则不冲突。对养老院管理系统来说,老人姓名里可能出现生僻字,utf8 一个字最多 3 字节,生僻字多为 4 字节,一旦存在就会报 Incorrect string value 错误。
导入命令是:
mysql -uroot -p --default-character-set=utf8mb4 old_nurse_home < old_nurse_home.sql加上 --default-character-set=utf8mb4 是为了让 mysql 客户端在解析 sql 文件中的字符串时按 utf8mb4 解码,避免文件里的中文在被服务端接收前就损坏。如果使用 Navicat,导入前在连接属性里把编码设置为 65001(UTF-8),不要选 GBK。图示路径是连接名右键 -> 编辑连接 -> 高级 -> 编码。
3.2 jdbc.properties 里的 5 个参数,改错一个连不上
SSM 工程的数据库连接信息通常放在 resources/jdbc.properties,由 Spring 的 PropertyPlaceholderConfigurer 读取。核心参数如下:
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/old_nurse_home?useUnicode=true&characterEncoding=utf8mb4&useSSL=false&serverTimezone=Asia/Shanghai jdbc.username=root jdbc.password=123456 jdbc.maxActive=50driver 这一行要注意:MySQL 5.7 及以下用 com.mysql.jdbc.Driver,MySQL 8.0 必须改成 com.mysql.cj.jdbc.Driver,否则驱动类加载时报 ClassNotFoundException。URL 里的 serverTimezone 参数在 MySQL 8.0 下是必填的,默认时区与 JVM 时区不一致会导致 java.sql.SQLException: The server time zone value '�й���ʱ��' 这类乱码错误。Asia/Shanghai 是稳妥选项。
maxActive 是连接池最大连接数,常见做法是设置在 20-50 之间。养老院管理系统的并发量不会太高,50 已经够用。如果设成 100+,MySQL 默认的 max_connections 是 151,连接池还没打满数据库就先拒绝了,报 Too many connections。压测时调整 maxActive 前,先查 MySQL 的 show variables like 'max_connections'。
3.3 MyBatis XML 里 resultMap 和动态 SQL 决定业务能不能跑
导入数据库后,下一步是验证 MyBatis 的 mapper 文件能正确映射。养老院系统的业务围绕老人档案、家属信息、护工排班、床位管理、费用记录展开,每个模块一个实体类对应一张表,一个 Mapper 接口对应一个 XML 文件。
以下是一个典型查询示例:
<resultMap id="ElderMap" type="com.example.entity.OldMan"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="careLevel" column="care_level"/> <result property="bedNo" column="bed_no"/> <association property="nurse" javaType="com.example.entity.Nurse"> <id property="id" column="nurse_id"/> <result property="realName" column="nurse_name"/> </association> </resultMap> <select id="selectElderList" resultMap="ElderMap" parameterType="map"> SELECT e.id, e.name, e.care_level, e.bed_no, n.id AS nurse_id, n.real_name AS nurse_name FROM old_man e LEFT JOIN nurse n ON e.nurse_id = n.id <where> <if test="name != null and name != ''"> AND e.name LIKE CONCAT('%', #{name}, '%') </if> <if test="careLevel != null and careLevel != ''"> AND e.care_level = #{careLevel} </if> </where> ORDER BY e.id DESC LIMIT #{offset}, #{limit} </select>这段 SQL 里, 标签会自动去除第一个满足条件下的多余 AND,这是 MyBatis 动态 SQL 的常见用法,避免手写 1=1 这种拼凑。LIKE 查询用 CONCAT 拼 %,而不是直接在 #{} 里写 %,因为 #{} 会预编译成占位符,字符串里的 % 不会被识别为通配符。LIMIT #{offset}, #{limit} 是分页查询的老写法,offset = (pageNum - 1) * pageSize,pageSize 对应每页条数。这里推荐在 Service 层计算 offset,不要在前端传原始页码。
需要特别注意的是 useGeneratedKeys 与自增主键回填。向 old_man 表插入数据后,主键 id 由数据库自增,MyBatis 默认不会把生成的主键写回实体对象。在很多毕业设计里,插入老人档案后马上要用这个 id 去关联家属表,拿不到 id 就只能再查一次。正确配置是:
<insert id="insertElder" parameterType="com.example.entity.OldMan" useGeneratedKeys="true" keyProperty="id"> INSERT INTO old_man (name, care_level, bed_no, nurse_id) VALUES (#{name}, #{careLevel}, #{bedNo}, #{nurseId}) </insert>keyProperty 对应实体类的 id 字段,插入完成后调用 getter 就能拿到新主键。如果没有配置 useGeneratedKeys,插入后 id 是 null,后续关联操作必挂。
3.4 Mapper 接口扫描漏配,启动不会报错但请求时 500
在 applicationContext.xml 或 spring-mvc.xml 里配置 Mapper 扫描有两种方式:MapperScannerConfigurer 或 mybatis:scan 。常见配置如下:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.example.dao"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean>basePackage 必须与 Mapper 接口所在的包完全一致。如果工程里 dao 包下既有 Mapper 接口又有普通类,会全部被当作 Mapper 注册,启动时报 Invalid bound statement 或 BeanCreationException。漏配或包名写错时,Spring 容器里没有 Mapper 代理对象,Service 注入时报 NoSuchBeanDefinitionException,这个错在启动阶段就会暴露,不会拖到请求期。
另一个排错点是 Mapper XML 的 namespace 必须与接口全限定名一致,statement id 必须与方法名一致。以下错误信息是微信里被问得最多的:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.example.dao.OldManMapper.selectElderList这类错误的原因是 mapper 接口编译后的 class 文件在 target/classes 里,而 XML 文件也在 resources/mapper 下,但 pom.xml 没有把 XML 打进最终产物。Maven 默认只打包 resources 目录下的文件,如果 XML 放在 src/main/java/com/example/dao 下,需要额外配置:
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> </resources> </build>这一点在导入毕业设计工程时很容易遇到:代码在 IDEA 里能看到 XML,但 Tomcat 部署的 war 包里没有,请求时 Invalid bound statement。建议在项目根目录执行 mvn clean package 后,解压 target 下的 war 或 jar,确认 mapper 目录存在再排查别的。
4. 权限控制:养老院后台里的管理员与护工角色怎么落地
4.1 用 Shiro 做认证授权,还是一律写在 Filter 里
SSM 工程里的权限控制有两种常见路径:集成 Apache Shiro,或自己写 HandlerInterceptor。养老院管理系统的角色包括超级管理员、前台、护工、家属,不同角色能看到的功能菜单和操作按钮不同。毕业设计里很多直接在每个 Controller 方法里判断 session 里的 userType,这样做虽然快,但权限判断散落在各业务代码里,改角色权限时要么改 Java 代码重新编译,要么漏掉某个入口。
案发率最低的做法是集成 Shiro。原因有三点:其一,Shiro 把认证、授权、会话管理封装成 Filter 链路,可以在 web.xml 里配置 URL 拦截规则,不需要侵入业务代码;其二,它天然支持基于角色的访问控制,一个注解 @RequiresPermissions("oldman:add") 就能在方法粒度上做校验;其三,登录成功后通过 SecurityUtils 获取当前用户,比手动从 session 取参数更规范。缺点是 Shiro 的过滤器链顺序严格,写错顺序会直接导致所有请求被匿名拦截。
4.2 Shiro 过滤链配置参数对照表
在 spring-shiro.xml 里配置 ShiroFilterFactoryBean,核心是 filterChainDefinitions。以下是一份养老院后台的常见配置:
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/login.html"/> <property name="unauthorizedUrl" value="/403.html"/> <property name="filterChainDefinitions"> <value> /login.html = anon /login = anon /css/** = anon /js/** = anon /images/** = anon /logout = logout /oldman/** = authc /nurse/** = authc /bed/** = authc, roles[admin] /finance/** = authc, roles[admin, cashier] /** = authc </value> </property> </bean>anon 表示匿名可访问,authc 表示必须登录,roles[admin] 表示必须拥有 admin 角色,logout 表示登出。每一行定义了一个 URL 模式的过滤器链,Shiro 按声明顺序匹配,所以 /login.html 必须在 /** 前面。roles[admin] 会要求当前 Subject 拥有指定角色,这里的角色是字符串,与数据库 user 表的 role 字段一一对应。配置 loginUrl 后,未登录访问 /oldman/** 会被重定向到登录页,但如果是前后端分离的 AJAX 请求,重定向会返回 HTML 而不是 JSON,此时需要自定义 UserFilter 重写 onAccessDenied 返回 JSON 状态码。
实际开发里还有一个坑:resources 目录下的静态资源会被 /login.html = anon 之外的规则拦截吗?不会,因为/css/** = anon声明在先,且 URL 模式匹配路径前缀,普通请求先命中的规则就生效。
4.3 数据库表结构与 Shiro 的关联模型
权限系统的表结构通常至少三张:用户表、角色表、用户角色关联表。养老院系统的 user 表可以这样设计:
CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(32) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, salt VARCHAR(32) DEFAULT NULL, role VARCHAR(20) NOT NULL DEFAULT 'nurse', real_name VARCHAR(32) NOT NULL, status TINYINT DEFAULT 1 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;Shiro 的 Realm 负责从数据库读取用户信息和角色信息。密码存储时不能是明文,常见做法是 MD5 加盐,或者用 BCrypt。因为 JDK 自带的 MessageDigest 对 MD5 的计算方式是多线程不安全的,所以写 Realm 时要用 Shiro 提供的 SimpleHash 来算:
SimpleHash hash = new SimpleHash("MD5", rawPassword, salt, 1024); String encodedPassword = hash.toHex();这段代码的四个参数分别为算法名、原始密码、盐值、哈希迭代次数。迭代次数 1024 是 Shiro 推荐的最低值,太低的 hash 容易被暴力破解。盐值可以用用户唯一标识,比如用户名或 UUID,存入数据库 salt 字段。登录校验时,Shiro 会调用 Realm 里的 doGetAuthenticationInfo 方法,把数据库里的盐值和密文返回给 CredentialsMatcher 做比对,不需要业务代码手动比对密码。
4.4 方法级权限注解的启用条件
Shiro 支持在 Controller 方法上加 @RequiresPermissions,但不会默认开启。必须在 Spring MVC 配置文件中启用:
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean>并且需要开启 CGLIB 代理或 JDK 动态代理。如果 Controller 类没有接口,则必须使用 CGLIB,默认配置在 Spring 5.x 下已经支持。没有这个 Advisor,@RequiresPermissions 注解会被静默忽略,权限校验完全失效,这是毕业设计里最容易出现的“看起来配了权限但一点用没有”的问题。
启用后,添加床位删除权限只需:
@RequiresPermissions("bed:delete") @GetMapping("/bed/delete") public String deleteBed(Integer id) { bedService.deleteById(id); return "redirect:/bed/list"; }权限字符串 bed:delete 是自定义的,不需要在数据库里维护权限表,只要拦截代码与调用方一致即可。建议在常量类里统一定义这些字符串,避免手写拼错导致权限永远不通过。
5. 毕业设计的完整落地:从压缩包跑到可二次开发
5.1 按流程走一遍:建库、导入、启动、验证
拿到压缩包后,按照时间线操作,每一步都有验证标准,不是跑完就完。先确认本机环境,推荐组合是 JDK 8、Maven 3.6.x、Tomcat 8.5、MySQL 5.7。JDK 版本与 Spring 版本要匹配,Spring 5.2.x 兼容 JDK 8 到 11,但 Tomcat 8.5 最高支持 JDK 11,如果用 JDK 17 就会遇到模块访问限制问题。
按以下步骤操作:
- 用 IDEA 的 Open 选择解压后的目录,等待 Maven 下载依赖。如果 pom.xml 没有被识别,右键 pom.xml -> Add as Maven Project。
- 使用 root 账号创建数据库并导入 SQL 脚本。
- 修改 jdbc.properties 里的数据库连接参数。
- 配置 Tomcat。IDEA 里 Run -> Edit Configurations -> Tomcat Server -> Local,Deployment 选项卡中添加 Artifact: exploded。
- 启动 Tomcat,观察控制台输出。看到 “Initializing Spring root WebApplicationContext” 和 “Initializing Spring FrameworkServlet 'dispatcher'” 两条日志后,说明 Spring 容器和 Spring MVC 容器都起来了。
启动后验证方式:浏览器访问http://localhost:8080/项目名/login.html。如果首页能正常渲染,说明静态资源配置正确。然后输入管理员账号登录,跳转到 index.html,后台菜单出现养护人员、床位管理、费用管理各模块,说明 Shiro 的认证流程和 JSP 模板渲染都通了。接着点击任意一个有新增功能的菜单,比如新增老人档案,表单提交后到数据库执行 SELECT,可查出一条新记录,且 id 自增,说明 MyBatis 的事务管理和主键回填配置正确。
5.2 把通用项目改造成内聚的后台服务时,先动这五个文件
很多学生在答辩前要加功能或改模块,与其新写一个模块,不如在现有业务上再做一层。排名靠前的改动点是实体类、Mapper、Service、Controller、前端 JSP 页面。举一个最常见的场景:新增“护工排班”功能。数据库需要新建一张 work_schedule 表,关联护工表和日期。实体类新建 WorkSchedule 类,对应表字段。Mapper 接口新建接口和 XML。Service 层写排班查询和保存逻辑。Controller 暴露页面入口。最后在左侧菜单的 JSP 或 HTML 中加上对应超链接即可。
如果源码里使用的是 JSP,那么修改后不需要重新编译 Java 代码,直接刷新页面就能看到效果。Tomcat 默认开启了 JSP 热加载。但如果改的是 Java 代码,需要重新编译并重新部署,IDEA 里快捷键 Ctrl+Shift+F10 只会编译当前文件,不会自动重新部署到 Tomcat。推荐用 JRebel 或直接点 Tomcat 配置里的 “Update resources”。
5.3 前后端分离改造的一个折中方案:Controller 返回 JSON
部分毕业设计要求做前后端分离,标题里也关联了 Vue3 后台管理系统。SSM 工程改造前后端分离不需要完美的 REST 化,常见做法是保持 Spring MVC 架构不变,把 Controller 里的返回值从 ModelAndView 改成 @ResponseBody,把 JSP 页面替换成静态 HTML,页面上的数据全部走 Axios 请求。
@RestController @RequestMapping("/api/oldman") public class OldManApiController { @Autowired private OldManService oldManService; @GetMapping("/list") public Result<List<OldMan>> list(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer limit) { int offset = (page - 1) * limit; List<OldMan> list = oldManService.selectList(offset, limit); return Result.success(list); } }这段代码里 @RestController 替代 @Controller + @ResponseBody 的组合,每个方法返回的对象会被 Jackson 序列化为 JSON。Result 是统一响应体包装,结构通常包含 code、msg、data 三个字段。前端 Vue3 项目里通过 Axios 拦截器统一处理 code,这样后端可以继续复用原来的 MyBatis 代码,不需要重写整套接口。对于这个标题里的毕业设计项目来说,这是一个收益高、风险低的改造路径,不会破坏原有 SSM 结构。
6. 高频报错的定位方法:从控制台日志反推根因
此章提炼几个最常见的错误日志和参数设置错误。解决这些问题不需要背 Spring 源码,只要会读日志、会看配置文件、会查表结构就足够。
第一个高频错误是Invalid bound statement (not found),前文已提到 XML 未打包的问题。定位方法:展开 target/classes 目录,确认是否存在 mapper 目录,没有则按 Maven resources 配置补全;存在则检查 namespace 与接口全限定名是否一致。
第二个高频错误是Table 'old_nurse_home.xxx' doesn't exist,常见原因是实体类对应的表名与数据库实际表名不一致。比如 Java 类叫 CareLog,但数据库表明叫 care_log,MyBatis 默认按实体类名驼峰转下划线查找表,若不一致需要在 @Table 注解或 XML 中明确表名。更稳妥的做法是养成编写 mapper XML 时显式写表名的习惯,不依赖自动转换。
第三个高频错误是Access denied for user 'root'@'localhost',检查 jdbc.properties 的账号密码,同时确认 MySQL 用户表里的 host 是否允许 localhost。如果是 Docker 容器里的 MySQL,host 可能是 '%',但本地连接时仍会有差异,把 host 设置成 localhost 即可。
第四个高频错误是 404 页面出现 “HTTP Status 404 - /oldman/list” 而控制台没有报错,这类错误多半是 Controller 类没有被 Spring MVC 容器扫描到。检查 spring-mvc.xml 的 component-scan base-package 是否包含了 controller 的包路径,注意区分大小写,且不能放在 applicationContext.xml 的扫描范围之外。
最后一个坑是中文乱码。控制台打印中文乱码是 IDEA 的编码设置问题,在 Help -> Edit Custom VM Options 加-Dfile.encoding=UTF-8。页面中文乱码是 JSP 页面编码不一致,统一使用 UTF-8 声明。数据库中文乱码的修复方式是删除重建库表,执行 ALTER TABLE xx CONVERT TO CHARACTER SET utf8mb4 不完整,因为存量数据的连接参数错误会继续产生乱码。
以上可以参考这些维度去检查 SSM 工程,配合一个办法:每次改动只动一个变量,验证过了再动下一个。这个方法本身不是 SSM 专属,但在类似 JSP、XML、Java 三处都要调整的场景里最有效,也最适合毕业设计这种小步快跑的项目。
本文还有配套的精品资源,点击获取