news 2026/10/6 8:17:47

基于SSM+MySQL的文物管理系统:从环境搭建到答辩演示全流程解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于SSM+MySQL的文物管理系统:从环境搭建到答辩演示全流程解析

简介:一套基于SSM框架与MySQL数据库的文物管理系统毕业设计资料包,适合计算机专业学生用于课程设计、毕业设计以及项目实战参考。系统采用浏览器/服务器结构,使用JSP动态页面技术,后台选用MySQL数据库,覆盖文物分类、文物信息、文物外借、文物维修、留言板、论坛交流等完整功能模块。压缩包约68.17MB,共1331个文件,以Java后端代码、JSP页面与HTML/CSS/JavaScript前端资源为主,另含SQL数据库脚本、论文文档、MP4演示视频以及大量界面素材,可支撑从环境配置、代码阅读到演示答辩的全流程。包内论文部分对研究现状、设计目标、系统需求、总体设计、具体实现和测试进行了详细论述,便于理解整个系统的设计思路与实现细节。资料目前已有64人学习,内容结构清晰、模块完整,适合作为管理系统类课程设计与毕业设计的参考范本和二次开发基础。

1. 基于 SSM+Mysql 的文物管理系统:这套交付包里到底装了什么

文化遗产管理是 JavaWeb 课设和毕设里的高频选题,而这个标题最大的特点是“成套”:“基于 SSM+Mysql 的文物管理系统”把源码、论文、PPT、开发文档、演示视频五个交付物绑在一起,覆盖了从代码开发、文档撰写到答辩演示的完整链路。SSM 指的是 Spring、SpringMVC、MyBatis 三件套,MySQL 负责存文物档案和出入库流水。它解决的问题很具体:很多初学者代码能跑,但说不清架构;论文写完了,却没对应一条完整的演示路径。这套东西适合两类人,一是正在选毕设或课设题目,想快速跑通再二次定制功能的学生,二是想复用一套经典单体后台模板、做内部管理工具的开发者。

2. 从解压 ZIP 到数据库就绪:工程骨架、建库脚本和环境核对

拿到这种压缩包,第一步不是急着用 IDEA 打开,而是先解压、核对内部结构。行业惯例是包内同时放源码目录、sql 脚本和 doc 文档,分别对应“能跑的代码”“能建出业务的库”“能答辩的材料”。如果你解压后入口有点乱,记住这条判断标准:只要看到 pom.xml 和 src/main/java 的层级,这就是标准 Maven 工程,下面的步骤直接照着走即可。

2.1 解压后的标准 SSM 工程:Maven 目录结构怎么核对

既然标题后缀明确带“源码”,第一件事就是把工程目录过一遍。规范的 SSM 文物系统,逻辑分层大致是这样(不会每个包都完全同名,但骨架基本跑不出这个范围):

heritage-system/ ├── pom.xml # Maven 工程描述文件,版本和依赖都在这里 ├── sql/ │ └── heritage.sql # 建库建表脚本,通常会带几条测试数据 ├── src/main/ │ ├── java/com/heritage/ │ │ ├── controller/ # SpringMVC 控制器,接收请求 │ │ ├── service/ # 业务接口 │ │ │ └── impl/ # 业务实现类,事务边界在这里 │ │ ├── mapper/ # MyBatis Mapper 接口 │ │ └── entity/ # 数据库表对应的实体类 │ ├── resources/ │ │ ├── spring/ # Spring 容器配置,包括事务配置 │ │ ├── mybatis/ # MyBatis 全局配置和 Mapper XML │ │ └── jdbc.properties # MySQL 连接四要素 │ └── webapp/ │ └── WEB-INF/ │ ├── views/ # JSP 页面 │ └── web.xml # Web 应用部署描述符 └── README.md # 启动说明,先读它

核对拆包时有两点优先级最高:第一,pom.xml 是否在根目录,没有它说明不是 Maven 工程,就要改用传统 lib 导入方式,工作量会大一圈;第二,sql 目录是否存在,这决定了你需不需要从零建表。拿到后我一般会先扫一遍 sql 脚本内容,确认有无 CREATE DATABASE 语句,避免导入时报“No database selected”的尴尬。

这个结构本身就是业务模块划分的说明书。controller 收请求、service 写业务、mapper 只碰数据库。后面要二次开发加功能,也逃不出“Controller 调 Service、Service 调 Mapper”这个同构调用链,骨架不用动。

2.2 建库建表脚本:从文物主表到流转记录表

数据库是这套系统的主心骨。标题点名 MySQL,交付脚本多数基于 MySQL 5.7 或 8.0 编写。一个可行的判断方法:若演示视频日志里出现 Loading class com.mysql.jdbc.Driver,用的就是 5.x 驱动写法;若是 com.mysql.cj.jdbc.Driver,则是 8.0。建议保持和视频一致的版本,避免后期大量排错。下面按 5.7 的兼容写法给一套最小建库脚本,表名按文物系统里最常用的命名习惯定为 relic、sys_user、relic_log:

-- 建库:utf8mb4 必须优先定好,生僻字和文物名里的繁体写法才不会乱码 DROP DATABASE IF EXISTS heritage; CREATE DATABASE heritage DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE heritage; -- 文物主表:一张表装下文物基本属性 CREATE TABLE relic ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', relic_no VARCHAR(32) NOT NULL COMMENT '文物编号,业务唯一键', name VARCHAR(64) NOT NULL COMMENT '文物名称', category VARCHAR(32) DEFAULT NULL COMMENT '类别:陶器/书画/青铜器/玉器', status TINYINT NOT NULL DEFAULT 0 COMMENT '0在库 1借出 2维修', location VARCHAR(64) DEFAULT NULL COMMENT '存放位置,例如东库A-03', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '登记时间', UNIQUE KEY uk_relic_no (relic_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文物主表'; -- 系统用户表:登录和权限的最小实现 CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(32) NOT NULL, password VARCHAR(64) NOT NULL COMMENT '建议存 MD5/BCrypt 散列', role TINYINT DEFAULT 0 COMMENT '0管理员 1普通操作员' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统用户表'; -- 文物流转记录表:每一次出入库和借展归还都留下流水 CREATE TABLE relic_log ( id INT PRIMARY KEY AUTO_INCREMENT, relic_id INT NOT NULL COMMENT '对应 relic.id', action TINYINT NOT NULL COMMENT '1入库 2出库 3借出 4归还', from_location VARCHAR(64) DEFAULT NULL, to_location VARCHAR(64) DEFAULT NULL, operator_id INT DEFAULT NULL, remark VARCHAR(255) DEFAULT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_relic_id (relic_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文物流转日志';

脚本里有几处值得细看。relic_no 建唯一索引,是业务上防重复登记的最硬约束,比在 Service 里先 SELECT 再判断可靠得多;status 用 tinyint 而非 varchar,能避免入库时出现“在库”“In Stock”这类不一致的脏数据;relic_log 只存 relic_id 外键,不冗余大量文物字段,需要展示详情时再 JOIN 回主表,这是典型的三范式写法。

如果你下载的脚本是用 mysqldump 导出的,开头会出现大段 DROP TABLE 和 LOCK TABLES,这是 dump 工具的默认行为,不是脚本写坏了。执行顺序只要记住“先建库、再导表”就行。

2.3 最小运行环境:JDK / Tomcat / MySQL 版本搭配

SSM 是“老而稳”的技术栈,对环境不挑,但版本错配会把一个简单项目卡死在启动阶段。这里给出一套最稳妥的搭配表,照着配能省掉一半排错时间:

组件推荐版本说明
JDK1.8(8u201 及以上)SSM 对 JDK 9+ 的模块化支持不友好,别追新
Maven3.6.x和 JDK 8 搭配最顺,3.8+ 偶发中央仓库源问题
Tomcat8.5.x兼容性最好,9.x 也能用但要注意 Servlet 版本
MySQL5.7.44 或 8.0.x5.7 对旧驱动和 utf8mb4 都友好
IDEA2021 或更新旗舰版社区版也能跑,只是少了部分 Tomcat 集成功能

网上大量 mysql 安装教程讲的就是 5.7/8.0 的图形化安装,照着装的时候盯住两点:端口保持 3306;8.0 的默认认证插件是 caching_sha2_password,如果代码里还是 5.x 老驱动,登录直接报认证失败。嫌麻烦就在 MySQL 里把用户认证改回 mysql_native_password,两种方案都行,只要代码和数据库对齐。

启动顺序别乱:第一步启动 MySQL 并导入 sql 脚本;第二步改 jdbc.properties 里的用户名密码;第三步用 mvn clean package 打 war 包;第四步把 war 丢进 Tomcat 的 webapps 后启动;最后浏览器访问 http://localhost:8080/heritage-system/。按这个顺序走,每一步都能从日志里定位问题,而不是最后一次性冒出一屏报错无从下手。

3. 把 SSM 三件套配置衔接好:容器、注解和事务边界

环境坑排除之后,决定系统能不能稳定运行的是 SSM 三件套的配置衔接。不少从网上下载的源码启动时报一堆 NoSuchBeanDefinitionException 或 404,原因不是业务代码错,而是 Spring 根容器和 SpringMVC 子容器的扫描边界没划清楚。

3.1 Spring 与 SpringMVC 的父子容器:扫描边界与配置文件职责

这是 SSM 配置里最容易翻车的地方,先从机制上讲清。整个 Web 工程会启动两个容器:Spring 根容器管 service、mapper 等业务组件,SpringMVC 子容器管 controller 等 Web 组件。子容器能看见父容器里的 Bean,父容器看不见子容器里的 Bean。这个父子关系决定了扫描配置怎么划边界。

记住这条分配规则:applicationContext.xml 里只扫描 service 和 mapper,spring-mvc.xml 里只扫描 controller。如果把 controller 放进根容器扫描,事务 AOP 和 MVC 映射会互相干扰,表现为“控制器找到了但访问方法 404”,或者“事务不生效”;反过来把 service 放进 MVC 容器,根容器拿不到 service,启动直接抛异常。

<!-- applicationContext.xml:Spring 根容器配置骨架 --> <context:component-scan base-package="com.heritage"> <!-- 排除 Controller,把 Controller 留给 SpringMVC 子容器管理 --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 开启 MyBatis 的 Mapper 扫描:要求接口带 @Mapper 注解或 XML 能匹配 --> <mybatis:scan base-package="com.heritage.mapper"/> <!-- 事务管理器必须挂在同一个 DataSource 上,否则事务不生效 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/>
<!-- spring-mvc.xml:只处理请求映射和静态资源放行 --> <context:component-scan base-package="com.heritage"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan> <!-- 开启注解驱动,把参数绑定和 JSON 转换交给框架去办 --> <mvc:annotation-driven/> <mvc:default-servlet-handler/>

上面两段配置是这类交付项目的通用骨架。重点理解 exclude-filter 和 include-filter 的配合:根容器排除 Controller,MVC 容器包含 Controller 再排除 Service,两个容器各管一摊,又通过父子关系完成协作。实际调试时,如果某个 Service 注入不进去,先回来看扫描配置是不是把不该排除的排除掉了。

动手改配置前有个习惯建议养成:先把 resources 目录下的 XML 清单列出来,确认 spring 配置和 mybatis 配置是否分开放。看到有人把 Mapper XML 混在 Spring XML 里时,最好先按类别重排,否则排查起来很痛苦。至于用 XML 还是全注解,这种交付项目通常混用,不强求统一,只要保证每个 Bean 只被扫描一次。

3.2 把 SSM 常用注解串起来:@Controller / @Service / @Mapper 的联动规则

容器边界划好以后,业务代码里的 SSM 常用注解就是各层组件互相识别的凭证。最常用的一套组合固定如下:

  • @Controller:标记类是 SpringMVC 控制器,类里的方法通过 @RequestMapping 暴露成 URL。
  • @Service:标记业务类,交给 Spring 根容器管理,事务注解也打在 Service 实现上。
  • @Mapper(或 @Repository):标记数据访问层接口,MyBatis 会为它生成动态代理实现。
  • @Autowired:按类型注入依赖,Controller 注入 Service、Service 注入 Mapper 都靠它。
  • @GetMapping / @PostMapping:细分请求方法的映射注解,比老式 method 属性写法更简洁。

下面是一段最小但完整的调用链,可以在文物系统里任何模块复刻:

// RelicController.java @Controller @RequestMapping("/relic") public class RelicController { @Autowired private RelicService relicService; // 进入新增页面 @GetMapping("/add") public String addPage() { return "relic/add"; } // 接收表单提交,SpringMVC 自动把表单字段映射到 Relic 对象 @PostMapping("/add") public String add(Relic relic) { relicService.addRelic(relic); return "redirect:/relic/list"; // 重定向避免刷新时重复提交 } }
// RelicServiceImpl.java @Service public class RelicServiceImpl implements RelicService { @Autowired private RelicMapper relicMapper; @Override public void addRelic(Relic relic) { relicMapper.insert(relic); } }
// RelicMapper.java @Mapper public interface RelicMapper { int insert(Relic relic); }

这段链路有三个细节得放在最前面讲。第一,@GetMapping 和 @PostMapping 是 Spring 4.3 才引入的派生注解,如果项目里还是 Spring 4.2.x,就得统一退回 @RequestMapping(method = RequestMethod.GET/POST),否则直接编译失败。第二,insert 返回 int 表示受影响行数,Service 层可以拿返回值判断写库是否成功,不必依赖异常。第三,Controller 里用 redirect 而不用 forward,是为了避开表单重复提交——刷新页面时浏览器不会把上一次 POST 再发一次。

和这套注解配套的 Mapper XML 放在 resources/mybatis 目录,文件名和接口保持一致。有个硬规矩:XML 的 namespace 必须严格等于接口全限定名,语句 id 等于方法名,否则 MyBatis 启动时抛 BindingException。这个异常在 mybatis 源码里反复出现,是新手最常踩的绑定错误,后文会专门讲排查。

3.3 事务配置:用声明式事务顶住文物出入库的数据一致性

文物管理系统的核心数据不只是文物主表,每次出入库和借展都必须同时写“状态变更”和“流转日志”。如果这两步没被同一个事务包住,程序中途崩溃就会出现文物状态显示“已借出”,日志表里却没有对应记录。标准解法是声明式事务,也就是在 Service 方法上打 @Transactional,让 Spring AOP 在方法前后自动开启、提交或回滚事务。

事务要生效,前提是 3.1 节里的 transactionManager Bean 已配置,并且事务管理器和数据源用同一个 DataSource。事务不生效时的第一排查点就是这个 Bean 有没有接管当前库连接。第二排查点是 @Transactional 必须打在 public 方法上,且不能在本类内部调用——比如 addRelic 方法内部用 this.otherMethod() 调另一个带事务注解的方法,事务会绕过代理直接失效,这类问题肉眼很难发现。

@Override @Transactional(rollbackFor = Exception.class) public void borrowRelic(Integer relicId, String toLocation, Integer operatorId) { // 第一步:改主表状态为“借出”,并更新存放位置 relicMapper.updateStatus(relicId, 1, toLocation); // 第二步:插入一条流转记录 RelicLog log = new RelicLog(); log.setRelicId(relicId); log.setAction(3); // 3=借出 log.setFromLocation("东库A-03"); log.setToLocation(toLocation); log.setOperatorId(operatorId); relicLogMapper.insert(log); // 第二步抛异常时,第一步的状态变更会一起回滚,不会留下半截数据 }

rollbackFor = Exception.class 这个参数值得专门说明:Spring 默认只对 RuntimeException 回滚,对检查型异常如 IOException 不会回滚。课设项目里显式声明 rollbackFor 是最省心的写法。隔离级别用默认的即可,MySQL InnoDB 默认 REPEATABLE READ 对这套系统已经足够稳妥,不需要为了展示“学术含量”去手动改成 READ_COMMITTED,反而可能引入讲不清楚的并发行为。

关于 mysql 事务处理,还有一个常被忽略的怪现象:事务明明开着,数据却直接写进去了。多半是 jdbc.properties 里被设置了 connectionAutoCommit=true,把它去掉,连接提交时机统一交还给事务管理器。

4. 核心业务落地:文物登记、出入库与列表分页查询

配置骨架立住后,就可以沿着业务线把功能跑通。这套系统的功能一般落在登录、文物登记、列表查询、出借归还这几块。登录每个课设都有且做法雷同,这里不展开,重点讲能体现“管理”二字的三块:登记、流转、查询。

4.1 文物登记模块:从页面表单到数据库的完整调用链

登记文物是整个系统的主入口,也是验证配置是否正确的最短路径。实体类 Relic 对应 relic 表,核心字段是 relicNo、name、category、status、location。页面用一个 POST 表单提交,Controller 方法签名直接写 Relic 接收参数,SpringMVC 会按表单字段名自动绑定,省去逐行 getParameter 的繁琐代码。

public class Relic { private Integer id; private String relicNo; private String name; private String category; private Integer status; private String location; // getter/setter 用 IDEA 的 Alt+Insert 一键生成,不手写 }

页面表单提交到 /relic/add 后,Mapper XML 的 insert 语句如下:

<mapper namespace="com.heritage.mapper.RelicMapper"> <insert id="insert" parameterType="com.heritage.entity.Relic" useGeneratedKeys="true" keyProperty="id"> INSERT INTO relic (relic_no, name, category, status, location) VALUES (#{relicNo}, #{name}, #{category}, #{status}, #{location}) </insert> </mapper>

useGeneratedKeys="true" 配 keyProperty="id" 这一行要单独划重点:它的作用是在插入成功后把数据库自增主键回填到 Java 对象的 id 字段。后面写借展流水时你需要用新增后的 relic.getId() 去关联 relic_log,漏掉这个配置,拿到的 id 永远是 null,关联记录就写不进去。这是数据访问层最典型的“代码看着对但结果就是错”的位置。

登记的编号查重可以放在 Service 里先查一次,提升用户体验;但真正兜底的还是数据库唯一索引。Service 查重只是软约束,唯一索引才是硬保险,两者叠加才能保证业务上不出现两条相同文物编号的数据。

4.2 借展与归还:一个事务方法里同时改状态和写流水

出入库是这套系统最像“业务”的功能。以“借展出库”为例,流程可以拆成三步:更新文物状态为“借出”、更新目的地、新增一条流转日志。这三步必须原子执行,正是 3.3 节事务要保护的对象。

@Override @Transactional(rollbackFor = Exception.class) public void borrowRelic(Integer relicId, String targetLocation, Integer operatorId) { Relic relic = relicMapper.selectById(relicId); if (relic == null) { throw new RuntimeException("文物不存在,无法借出"); } if (relic.getStatus() != 0) { throw new RuntimeException("文物当前不在库,状态为:" + relic.getStatus()); } // 业务校验通过后,先更新文物状态为“借出” relicMapper.updateStatus(relicId, 1, targetLocation); // 再插入一条借出流水,from_location 取更新前查出来的旧位置 RelicLog log = new RelicLog(); log.setRelicId(relicId); log.setAction(3); log.setFromLocation(relic.getLocation()); log.setToLocation(targetLocation); log.setOperatorId(operatorId); relicLogMapper.insert(log); }

这段代码里有三个常被问到的设计点。第一,业务校验放在事务方法内部,校验失败抛 RuntimeException,事务被标记回滚;如果校验放 Controller 层,事务还没开启,虽然结果也是“不成功”,但不符合“所有变更都在同一事务边界”的语义。第二,relic.getStatus() != 0 直接拿 Integer 和 int 字面量比较,Java 会自动拆箱,空值场景要留意 NPE,严谨写法是判空后再比较。第三,from_location 用的是更新前查出来的旧位置,这样每一条流水都能完整还原“从哪来到哪去”。

入库操作几乎是借出的反向:status 改回 0,位置改回库房编号,action 记 1,写流水。归还同理,action 记 4。逻辑完全一致,复制模板改参数即可。

4.3 列表查询的实用写法:MySQL 排序、分页 LIMIT 与动态 SQL

列表页是用户接触最多的页面,也最能体现“查询做得顺不顺手”。SSM 项目里列表无非是“条件查询 + 分页”,但条件不能靠字符串拼接,那既容易 SQL 注入又难维护。正确做法是 MyBatis 动态 SQL,在 XML 里用 if 和 where 标签拼条件:

<select id="searchRelic" resultType="com.heritage.entity.Relic"> SELECT id, relic_no, name, category, status, location, create_time FROM relic <where> <if test="name != null and name != ''"> AND name LIKE CONCAT('%', #{name}, '%') </if> <if test="category != null and category != ''"> AND category = #{category} </if> <if test="status != null"> AND status = #{status} </if> </where> ORDER BY create_time DESC, id DESC LIMIT #{offset}, #{limit} </select>

ORDER BY create_time DESC 是最常用的排序方式:新登记或新流转的文物排最前。但这里有个 MySQL 排序的边界场景:create_time 是 DATETIME,同一秒内插入多条记录时排序不稳定。要绝对稳定就加 id DESC 作为第二排序键,在 MySQL 排序里,“看着稳定”和“真稳定”就差一个字段。

分页的 LIMIT 参数不要写死在 XML 里,由 Controller 从查询参数接收。常见做法是引入 PageHelper 插件,一行 PageHelper.startPage(pageNum, pageSize) 自动拦截下一条 SQL 做 count 和 limit;课设项目里手写 LIMIT #{offset}, #{limit} 也完全够用。手工分页时注意 MyBatis 的多参数规则:接口方法的每个参数必须加 @Param 注解,否则报 “Parameter 'offset' not found”。看到这个错,去接口方法签名补上 @Param("offset") Integer offset 和 @Param("limit") Integer limit 即可。

5. 高频踩坑实录:SSM + MySQL 文物系统最容易翻车的 5 个环节

这个项目本身不难,但它属于典型的“配置比业务更费神”的工程。下面把最容易让新手卡上好几个小时的坑按“现象 → 原因 → 解决”展开,可以直接对照排查。

5.1 Maven 依赖版本打架:Spring 5 配低版本 mybatis-spring

现象:IDEA 启动 Tomcat 时控制台报 BeanCreationException,堆栈能看到 NoSuchBeanDefinitionException 或 ClassNotFoundError,业务代码本身没有语法错误。

原因:SSM 工程年代久,网上流传的 pom.xml 依赖版本很混乱。最典型的是 Spring 5.x 配了 mybatis-spring 1.3.x,而 mybatis-spring 1.3.2 是基于 Spring 4 编译的,跑在 Spring 5 容器里创建 MapperFactoryBean 时直接失败。Maven 依赖传递还会拉进冲突的 spring-jdbc 版本。

解决:把 pom.xml 里三个核心依赖收敛到同一版本线。常见稳定组合是 Spring 5.1.x + mybatis 3.5.x + mybatis-spring 2.0.x,MySQL 驱动用 5.1.49(对应 5.7 库)或 8.0.x(对应 8.0 库)。改完 pom 后执行 mvn clean package 重新拉依赖,别只点 IDEA 刷新按钮就当万事大吉。

5.2 MySQL 8.0 时区与认证方式不兼容

现象:数据库装的是 8.0,项目里驱动仍是 com.mysql.jdbc.Driver,启动时报 “The server time zone value is unrecognized”,或登录时报认证插件 caching_sha2_password cannot be loaded。

原因:MySQL 8.0 默认认证插件换成了 caching_sha2_password,旧驱动不认识;时区问题则是 8.0 对连接 URL 里的 serverTimezone 参数有强制要求,不像 5.7 可以缺省。

解决:驱动类改成 com.mysql.cj.jdbc.Driver,连接 URL 追加 ?serverTimezone=Asia/Shanghai&useSSL=false&characterEncoding=utf8。useSSL=false 还能顺手消掉 SSL 握手警告,mysql ssl 连接错误 多半就是这个参数没设置。如果必须用 5.x 老驱动,就进 MySQL 把用户认证改回 mysql_native_password,执行 ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码'; 再 FLUSH PRIVILEGES。

5.3 表单提交中文乱码

现象:登记“唐三彩”三个字,落库后变成“?¤?à????”或“????”。

原因:三层字符集不一致。JSP 页面编码、Tomcat 的 URIEncoding、JDBC 连接 characterEncoding、MySQL 表字符集,只要有一层是 latin1 或 GBK,全链路就断。

解决:统一按 utf8mb4 拉齐。Tomcat 的 server.xml 给 Connector 加 URIEncoding="UTF-8";JSP 页面第一行 pageEncoding="UTF-8";web.xml 配 CharacterEncodingFilter,强制 request 和 response 都走 UTF-8;JDBC 连接串带 characterEncoding=utf8,最后确认表是 utf8mb4。我的习惯是一上项目就把这五处编码配置先写好,比事后逐层排查快得多。

5.4 请求路径对不上导致 404

现象:点“文物管理”菜单,浏览器地址栏路径是对的,但页面 404,Tomcat 日志显示 No mapping found for HTTP request with URI。

原因:第一是 @RequestMapping 的类级注解和方法级注解拼出来的完整路径,和 JSP 里的链接不一致;第二是静态资源被前端控制器拦截了没放行,表现为 CSS、JS、图片全部 404,而 JSP 还能打开。

解决:先把类上的 @RequestMapping("/relic") 和方法的 @GetMapping("/list") 拼起来,得到 /relic/list 才是完整访问路径,再核对前端 form action 和 href 是否缺了或多了一层 context path。如果路径正确仍 404,去 spring-mvc.xml 看有没有 mvc:default-servlet-handler,没有就补上放行静态资源。

5.5 表字段下划线名与 Java 驼峰属性映射不上

现象:查询出来的 Relic 对象 name 有值,createTime 永远是 null;或者 insert 时报“字段 create_time 不存在”。

原因:数据库列名下划线写 create_time,Java 属性是驼峰 createTime,MyBatis 默认不做自动映射,需要明确开启驼峰转换开关。

解决:在 mybatis-config.xml 里加 。如果项目走 Spring Boot 方式,则在 application.properties 配 mybatis.configuration.map-underscore-to-camel-case=true。开启后下划线列自动映射到驼峰属性,手写 resultMap 的工作量能砍掉一半。

6. 验收演示路径:把跑通的系统变成答辩故事线

压缩包里附带的论文、PPT、开发文档、演示视频不是凑数文件,它是一套四层配套:开发文档讲代码怎么写,演示视频讲页面按什么顺序点,论文把功能转成文字和截图,PPT 把论文压成答辩能讲的十五到二十页。系统跑通后,值得做的事不是急着改代码,而是沿着演示视频的路径把功能完整走一遍,核对每个页面状态和视频对得上。

建议按这个顺序做一次“验收式巡检”:登录 → 新增一件文物 → 列表页确认数据出现 → 按名称和类别各做一次查询 → 借出该文物 → 确认列表状态变成“借出” → 归还 → 确认状态回到“在库” → 退出登录。整个过程不超过五分钟,但能覆盖系统九成以上的功能点。巡检时把 Tomcat 日志窗口开着,每成功一步就在日志里找对应的 SQL 输出,能同步确认后端逻辑真的被调用了,而不只是页面效果好看。

被追问“系统有什么亮点”时,不建议回答“我用了 SSM 框架”,那只会减分。把话题引向两个当场能验证的点。一个是事务一致性:借出时改状态和写流水要么同时成功要么同时回滚,演示时故意把流水表字段改错让插入失败,展示主表状态未变,效果好过任何架构图。另一个是唯一索引:重复录入同一个文物编号会被数据库拒绝,这也是一个可复现的现场亮点。

我自己的习惯是在验收前把每张表的索引和事务边界在笔记里列一遍,然后带着问题去点功能,比如“文物编号唯一索引到底挡没挡住重复数据”“借出操作断在写日志那一步时主表状态是否真的没变”。带着问题巡检比漫无目的地乱点更能留下印象,这套方法不挑项目,换成任何管理系统都能直接用。希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/6 8:17:46

从源码部署到二次开发:一套旗舰版CRM系统的完整落地指南

简介&#xff1a;这是一套功能完整的旗舰版CRM客户关系管理系统源码&#xff0c;适合中小企业及具备二次开发能力的PHP开发者使用&#xff0c;用于高效管理客户、销售、采购、库存、售后等全流程业务。资源共1903个文件&#xff0c;以PHP后端逻辑、HTML前端页面、JavaScript交互…

作者头像 李华
网站建设 2026/10/6 8:17:45

PHP开源CRM系统源码解析:线索池、工作流与二次开发实战

简介&#xff1a;这款旗舰版CRM客户管理系统源码&#xff0c;面向需要规范客户全流程管理的中小企业及二次开发人员。系统完整覆盖线索、客户、商机、合同、财务、销售、采购、库存、产品、任务、日程、知识、日志、站内信、营销等核心业务模块&#xff0c;支持员工限时限额领取…

作者头像 李华
网站建设 2026/10/6 8:16:51

学生资助小程序开发实战:SSM+微信原生+MySQL全流程落地

简介&#xff1a;本资源是一套完整的毕业设计项目——学生资助在线管理小程序&#xff0c;面向计算机专业本科生及Java全栈初学者&#xff0c;解决高校学生资助业务中信息分散、流程低效、角色协同不足等实际问题。系统采用微信小程序前端&#xff08;含136个Vue组件&#xff0…

作者头像 李华
网站建设 2026/10/6 8:14:38

ST-GCN骨骼动作识别实战:图卷积原理、PyTorch实现与避坑指南

简介&#xff1a;这是一份面向毕业设计、期末大作业及课程设计的Python实战项目&#xff0c;基于时空图卷积网络&#xff08;ST-GCN&#xff09;实现骨骼动作识别。项目代码包含详细注释&#xff0c;从数据处理、模型构建到训练推理均有清晰呈现&#xff0c;适合具备一定Python…

作者头像 李华
网站建设 2026/10/6 8:14:32

Linux下Eclipse JEE 2023-06-R安装配置与Tomcat集成实战

简介&#xff1a;Eclipse JEE 2023-06-R 是面向 Java 企业级开发者的 64 位 Linux 集成开发环境&#xff0c;基于 GTK 图形库构建&#xff0c;适合从事 Web 应用、Servlet、JSP、EJB 等 Java EE 项目开发的中高级程序员使用。压缩包共收录 2000 个文件&#xff0c;以 844 个 js…

作者头像 李华
网站建设 2026/10/6 8:13:11

JavaEE6+Oracle12c真实生产级仓库系统搭建指南

简介&#xff1a;这是一套面向计算机专业本科生的毕业设计级仓库管理系统实战资源&#xff0c;适用于课程设计、大作业及工程实训场景&#xff0c;帮助初学者掌握JavaEE全栈开发与Oracle数据库协同应用的核心流程。资源完整包含可运行源码、建库SQL脚本、配套论文文档及系统操作…

作者头像 李华