ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SSM+MySQL访客登记系统实战:表设计、三层架构与避坑指南

SSM+MySQL访客登记系统实战:表设计、三层架构与避坑指南 简介面向高校软件专业学生的学校访客登记系统毕业设计/课程设计资源基于SSMSpringSpringMVCMyBatis与MySQL实现访客登记、查询与管理功能。系统采用典型分层架构Spring管理业务对象与事务SpringMVC处理Web层请求和数据封装MyBatis负责数据库交互与持久化代码结构清晰适合Java初学者系统学习。资源包大小34.16MB共957个文件涵盖jsp页面、java源文件、class编译文件、jar依赖库、xml配置、css/js前端样式与脚本、gif/jpg图片素材以及SQL建库脚本和Word、PPT说明文档从运行环境到项目文档一应俱全。已有169人学习下载。压缩包内提供完整工程源码和数据库设计按说明配置即可启动运行附带的PPT和设计文档可直接用于答辩展示或功能讲解也便于针对访客登记流程做二次扩展对巩固SSM框架整合与MySQL表设计能力很有帮助。1. 学校访客登记 SSM MySQL一个值得亲手做一遍的入门组合门卫的登记本换成网页表单就是学校访客登记系统要解决的事。标题里的 SSM 指 Spring SpringMVC MyBatisMySQL 是背后的存储源码、论文和 PPT 则是课程设计或毕业设计常见的三件套交付物。为什么这个组合值得做因为访客登记的业务边界比电商、办公系统小得多要管的实体就几个访客、被访教职工、预约单、进出记录、后台账号。SSM 把请求、事务和 SQL 拆成三层正好把后端最常被问的框架问题全兜住。适合两类人一是需要交课程设计或毕业设计的在校生二是想用一个完整项目补 Spring 后端经验、准备转开发的在职者。这篇按我自己的落地顺序来讲先建表再写三层代码最后把预约、登记、签离串起来。2. 先建模再写码访客登记系统的库表设计与 MySQL 初始化SSM 项目写代码前我把一半时间花在定表和字段上。MySQL 里表结构定了MyBatis 的实体类、Mapper XML 全都要跟着走后期改一张表Controller、Service、页面都得动代价很大。访客登记的业务量不大但流程有分支有的访客提前预约过有的直接拿身份证来校门口登记。为了避免把不同状态搅在同一张表里我习惯拆成下面这种分表方式。2.1 拆业务建表为什么是五张表而不是一张大表先用一句话描述业务访客是谁、找哪位教职工、有没有预约、什么时间进校、什么时间离校。这五个问题对应五张表就够了visitor访客档案、staff教职工名单、appointment预约单、visit_log进出记录和 admin_user后台管理员。它们的分工用一张表就能讲清表名记录的是事实关键外键/索引与主流程的关系visitor人的档案id_card 唯一索引登记时先查或先落这条staff被访教职工无外键预约和登记时被选中appointment预约关系visitor_id、staff_id可选访客可预约也可直登visit_log一次进出的事实visitor_id、enter_time每行代表一次入校admin_user谁在后台操作username 唯一登录用业务上独立新手最容易踩的直觉误区是“访客表里存一个 visit_count 字段省得每次 join 统计”。这个字段加上去每次进出都要 UPDATE 主表历史记录一多visit_count 和 visit_log 就成了两个事实副本两边迟早对不上。访问次数应当在报表页用 COUNT 动态算MySQL 在这类小表上的聚合毫秒级返回没必要牺牲一致性。visitor 和 visit_log 之间的主从关系是整张模型的核心。visitor 存人id_card 加唯一索引visit_log 存事同一个人可以出现多行。常见错法是直接把 id_card 塞进 visit_log那同一个身份证会重复存储改一次联系方式就得批量更新历史记录没必要。保留 visitor 表visit_log 只存 visitor_id查询走主键和外键变更也只动一张表。2.2 建库建表 SQL字段类型、索引和默认值下面这段 SQL 按 MySQL 5.7 和 8.0 都能直接跑的方式写。建库时显式声明 utf8mb4避开后期中文和特殊字符入库乱码。执行顺序是先建库、再建表有外键的表放在被依赖表后面否则 MySQL 会报“外键关联的表不存在”。CREATE DATABASE IF NOT EXISTS school_visitor DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE school_visitor; CREATE TABLE visitor ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(30) NOT NULL COMMENT 访客姓名, id_card VARCHAR(18) NOT NULL COMMENT 身份证号, phone VARCHAR(11) DEFAULT COMMENT 手机号, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 建档时间, PRIMARY KEY (id), UNIQUE KEY uk_id_card (id_card) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT访客基础信息表; CREATE TABLE staff ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(30) NOT NULL COMMENT 教职工姓名, dept_name VARCHAR(50) DEFAULT COMMENT 所在部门, office VARCHAR(50) DEFAULT COMMENT 办公室, phone VARCHAR(11) DEFAULT COMMENT 联系电话, status TINYINT NOT NULL DEFAULT 1 COMMENT 1在职 0停用, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT被访教职工表; CREATE TABLE appointment ( id INT NOT NULL AUTO_INCREMENT, visitor_id INT NOT NULL, staff_id INT NOT NULL, appoint_date DATE NOT NULL COMMENT 预约日期, appoint_time VARCHAR(20) DEFAULT COMMENT 希望到访时间段, reason VARCHAR(200) DEFAULT COMMENT 来访事由, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待处理 1已通过 2已拒绝 3已取消, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_visitor (visitor_id), KEY idx_staff (staff_id), CONSTRAINT fk_app_visitor FOREIGN KEY (visitor_id) REFERENCES visitor (id), CONSTRAINT fk_app_staff FOREIGN KEY (staff_id) REFERENCES staff (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT预约单表; CREATE TABLE visit_log ( id INT NOT NULL AUTO_INCREMENT, visitor_id INT NOT NULL, appointment_id INT DEFAULT NULL COMMENT 预约单ID直接登记时为空, enter_time DATETIME NOT NULL COMMENT 进校时间, leave_time DATETIME DEFAULT NULL COMMENT 签离时间空表示在校, remark VARCHAR(200) DEFAULT COMMENT 备注, PRIMARY KEY (id), KEY idx_enter_time (enter_time), CONSTRAINT fk_log_visitor FOREIGN KEY (visitor_id) REFERENCES visitor (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT进出记录表;几个字段的取舍说明status 用 TINYINT 而不是 VARCHAR因为“待处理、已通过、已拒绝、已取消”是固定的四态用数字存占用空间小程序里定义常量比字符串比较更安全。appointment 表的 appoint_date 用 DATEappoint_time 用 VARCHAR因为校园预约一般只约到“上午、下午、晚上”没必要拆成时间区间表。visit_log 的 appointment_id 允许为空对应未预约直接到校登记的场景这是流程里很重要的一支。索引上不需要堆砌visitor 的 id_card 建唯一索引是业务层面的强约束一个人不能有两份档案visit_log 的 enter_time 建普通索引是因为“今日访客、滞留未签离”这类查询全是按时间范围过滤的没有索引时数据量过万后明细页会明显变慢。MySQL 里想让整数字段默认值为 0直接在 DDL 写 DEFAULT 0 就行比在 INSERT 语句里每行都带上更稳也避免程序漏传字段时写入 NULL。2.3 MySQL 连接配置驱动名、时区和连接池参数建完表开始接 SSM第一步是 jdbc.properties。这里有一个隐藏最深的坑MySQL 5 和 MySQL 8 的驱动类名不一样。如果本机装的是 MySQL 8还用老写法 com.mysql.jdbc.DriverTomcat 启动时类加载都会失败。我给出一版 MySQL 8 下能直接跑的配置jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/school_visitor?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue jdbc.usernameroot jdbc.password123456参数逐个说useUnicode 和 characterEncoding 保证中文以 utf8 传输服务端建库也要对齐否则出来就是问号serverTimezoneAsia/Shanghai 是 MySQL 8 的强制要求不写会抛异常说 CST 时区无法识别useSSLfalse 关掉加密连接本地开发没有证书开着反而会报 ssl 连接错误allowPublicKeyRetrievaltrue 针对 MySQL 8 默认的 caching_sha2_password 认证插件不开的话某些驱动版本会连不上。如果你正好卡在 mysql 安装配置这一步先在命令行跑mysql -uroot -p能进去就说明服务起来了剩下的就是授权和 URL 参数的事。SSM 里数据源常用 Druid 连接池spring 配置文件的 bean 长这样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} / property nameinitialSize value5 / property namemaxActive value20 / property namemaxWait value60000 / property namevalidationQuery valueSELECT 1 / /beaninitialSize 是启动时建立 5 个连接maxActive 是上限 20maxWait 是拿不到连接时的等待毫秒数。validationQuery 写成 SELECT 1作用是让连接池定期探活避免 MySQL 端的空闲连接超时被断开后首次请求拿到的还是“已死”的连接。这几项是受访客系统并发量不大却最容易出问题的参数先按这个设后面避坑章节再展开讲。3. SSM 三层代码落地Controller → Service → Mapper 的最小可跑骨架表结构定完进入 SSM 的编码环节。很多照着视频写的人卡在“不知道文件该放哪”。SSM 的 Maven 工程目录是约定俗成的放错位置轻则扫描不到重则启动直接 404。3.1 项目结构和 Maven 依赖先看包怎么分一个最常用的骨架结构如下src/main/java com.school.visitor controller/ 接收请求返回页面或 JSON service/ 业务逻辑和事务 mapper/ MyBatis 的 Mapper 接口 entity/ 与表字段对应的实体类 common/ 统一返回结果 Result、分页参数等 src/main/resources mybatis/mapper/ Mapper XML和 Mapper 接口同名同路径 mybatis-config.xml spring/ spring 配置、springmvc 配置 jdbc.properties src/main/webapp WEB-INF/jsp/ 管理端页面和保安端页面依赖里最容易被漏的是 jackson。SpringMVC 的 ResponseBody 要把 Java 对象转成 JSON没有 jackson-databind 会直接报 500。核心依赖我一般固定这几样spring-webmvc、mybatis、mybatis-spring、mysql-connector-java、druid、jstl、jackson-databind。pom 的关键片段如下dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.3.20/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.10/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.0.7/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.30/version /dependency这里的版本是五三的通用稳定版可以按你本机的 Spring 版本微调。核心是 mybatis-spring 必须存在它负责把 MyBatis 的 SqlSessionFactory 交给 Spring 容器管理否则 Autowired 注入 Mapper 接口全会失败。接口和 XML 的对应关系我的惯例是 Mapper 接口放 com.school.visitor.mapper.VisitLogMapperXML 放 resources/mybatis/mapper/VisitLogMapper.xml然后在 spring 配置里加上 mapperLocations 指向 classpath:mybatis/mapper/*.xml。这样做的好处是接新表时不用改配置文件文件放进去就生效。3.2 Controller 层接收登记、按身份证查老访客Controller 是请求入口。访客登记的核心操作是保安输入身份证号系统先查这个人在不在 visitor 表在就复用档案不在就建档然后往 visit_log 插入一条进入时间记录。Controller 代码如下Controller RequestMapping(/visit) public class VisitLogController { Autowired private VisitLogService visitLogService; PostMapping(/register) ResponseBody public Result register(RequestBody VisitRegisterDTO dto) { if (dto.getIdCard() null || dto.getIdCard().trim().isEmpty()) { return Result.error(身份证号不能为空); } int logId visitLogService.register(dto); return Result.ok(登记成功记录ID logId); } GetMapping(/list) public String list() { return visit/list; } }注意三个点PostMapping 把入口限制为 POST避免浏览器直接拼 URL 造成脏数据RequestBody 接收 JSON前端需要配合 axios 或 jQuery 的 JSON 提交别用 form 表单Result 是统一返回体里面放 code、message、data 三个字段避免每个接口各返回各的格式。list 方法返回字符串SpringMVC 会去 WEB-INF/jsp/visit/list.jsp 找视图这是 SSM 和前后端分离项目一个很重要的区别页面跳转靠视图解析器不靠重定向。3.3 Service 层事务边界和完整的登记方法Service 层最容易被问到的就是事务。登记业务里包含两步第一步查访客或插入访客第二步插入 visit_log。这两步必须同生共死否则会出现 visit_log 里有记录但 visitor 表没有档案的情况。ServiceImpl 的写法如下Service public class VisitLogServiceImpl implements VisitLogService { Autowired private VisitorMapper visitorMapper; Autowired private VisitLogMapper visitLogMapper; Override Transactional(rollbackFor Exception.class) public int register(VisitRegisterDTO dto) { Visitor visitor visitorMapper.findByIdCard(dto.getIdCard()); if (visitor null) { visitor new Visitor(); visitor.setName(dto.getName()); visitor.setIdCard(dto.getIdCard()); visitor.setPhone(dto.getPhone() null ? : dto.getPhone()); visitorMapper.insert(visitor); } VisitLog log new VisitLog(); log.setVisitorId(visitor.getId()); log.setAppointmentId(dto.getAppointmentId()); log.setEnterTime(new Date()); log.setRemark(dto.getRemark()); visitLogMapper.insert(log); return log.getId(); } }Transactional(rollbackFor Exception.class) 必须写全。默认情况下 Spring 事务只对 RuntimeException 回滚如果 visitLogMapper.insert 抛的是 IOException 或自定义的 checked exception不加 rollbackFor 就只提交不回滚访客表已插入的数据就留下了。这个细节是答辩时最高频的追问点也能直接展示你是否真的理解事务。查询方法不要加 Transactional纯查询加事务等于白占连接池资源并发一高就把连接耗尽。3.4 Mapper 层 XML动态 SQL 与参数绑定Mapper 接口只写方法签名真正的 SQL 在 XML 里。访客列表中“按姓名模糊查、按手机号精确查、不传条件就查全部”是典型场景动态 SQL 正好解决select idfindVisitorPage resultTypecom.school.visitor.entity.Visitor SELECT id, name, id_card, phone, create_time FROM visitor where if testname ! null and name ! AND name LIKE CONCAT(%, #{name}, %) /if if testphone ! null and phone ! AND phone #{phone} /if /where ORDER BY create_time DESC /select标签会自动去掉第一个条件前面的 AND这是 MyBatis 里最实用的语法避免拼 SQL 时出现 WHERE AND name LIKE 这种错误。参数绑定必须用 #{}它会生成预编译占位符防 SQL 注入${} 是字符串拼接只适合传 ORDER BY 的列名这种受信任值绝不能用它拼用户输入。resultType 指定实体类全限定名字段名和下划线列名的映射要在 mybatis-config.xml 里开启 mapUnderscoreToCamelCase这样 id_card 才能自动映射到 idCard不然查出来全是 null。4. 把预约、进校登记、离校签离串成一条完整流程表和三层代码都有了接下来要把几条独立的功能拼成完整流程。一个访客从进校到离校状态要经历预约可选到登记再到签离。每一步都要有对应的数据落库。4.1 预约状态机和管理端审批访客在手机端填预约单选择教职工、日期和原因。管理端看到的是一条状态为“待处理”的记录。审批通过后访客到校门报身份证号保安在登记页面能看到这条预约一键带入访客信息。预约状态建议按下表设计status 值含义后续动作0待处理教职工或管理员审批1已通过可到校登记关联 visit_log2已拒绝流程结束可备注原因3已取消访客自行取消流程结束审批动作的 Service 逻辑不复杂但有个规范要守update 语句要带 status 条件。例如把“待处理变成已通过”时SQL 应写成UPDATE appointment SET status 1 WHERE id #{id} AND status 0。这样能防止两个管理员同时点审批导致业务状态被覆盖。如果 update 返回行数为 0说明这条预约已经被别人处理过了直接提示“该预约已处理请刷新”而不是盲目覆盖成通过。4.2 进校登记老访客复用和记录落库进校登记分两种情况。查询 visit_log 时先按身份证查预约记录如果能查到“已通过”的今天预约把预约单里的 staff_id 和 reason 带到 visit_log 里保安不用重复录入查不到就直接走 3.3 的直登流程。这里我用一个前端流程描述来替代代码保安输入身份证号页面发 AJAX 请求查访客档案有则回显姓名、电话无则显示“新访客”。选择被访教职工教职工下拉框按部门分组数据来自 staff 表。若有有效预约自动带出预约信息被访人和来访事由不许改只允许补备注。点击登记后端 service 执行事务写入 visit_logenter_time 为当前时间。这一步的实际开发重点在“无效预约”的判定。预约的 appoint_date 等于今天、status 等于 1两个条件缺一不可。有人会把 status 等于 0 也算有效结果访客到了门口还进不去又改成只要记录存在就放行导致已拒绝的预约也能登记。判定条件我一般单独抽成一个私有方法返回布尔值方便写单元测试也方便答辩时讲。4.3 离校签离与滞留提醒一条 SQL 和一条定时任务签离功能是最简单的更新操作按记录 ID 把 leave_time 置为当前时间即可。难的是“哪些人还没走”的查询。一个实用 SQL 是查所有签离时间为空且进入时间早于 8 小时的记录SELECT vl.id, v.name, v.phone, vl.enter_time, s.name AS staff_name FROM visit_log vl JOIN visitor v ON v.id vl.visitor_id LEFT JOIN appointment a ON a.id vl.appointment_id LEFT JOIN staff s ON s.id a.staff_id WHERE vl.leave_time IS NULL AND vl.enter_time DATE_SUB(NOW(), INTERVAL 8 HOUR) ORDER BY vl.enter_time;这段 SQL 用了两个 LEFT JOIN把预约单和教职工信息连出来方便保安直接看到要找谁。滞留提醒在 SSM 里可以用 Spring 的定时任务实现在配置类或 XML 开启 task 命名空间后方法上写 Scheduled 注解Component public class StuckVisitorTask { Autowired private VisitLogMapper visitLogMapper; Scheduled(cron 0 0 8 * * ?) public void checkStuck() { ListVisitLog stuckList visitLogMapper.findStuckVisitors(); if (stuckList ! null !stuckList.isEmpty()) { // 推送提醒给保安端或生成待处理消息 } } }cron 表达式的意思是每天早上 8 点整执行一次。注意这里的“8 小时”阈值要放到配置项里不要写死在代码中。不同学校的校门开放时间不同有的学校晚上 10 点封校那这个阈值可能得改成 4 小时。定时任务里只做查询和推送不做写操作避免同一批滞留访客在多个任务实例里被重复处理。4.4 后台报表今日访客、部门访问量两张统计图完整访客系统还需要给管理员一点统计能力哪怕只是两张简单的表。今日访客数用这个 SQL 就能拿到SELECT COUNT(*) AS today_count FROM visit_log WHERE enter_time CURDATE() AND enter_time DATE_ADD(CURDATE(), INTERVAL 1 DAY);部门统计可以按 visit_log 关联预约单和教职工表按 dept_name 分组计数再用 ECharts 画个柱状图。这里不需要做复杂的报表引擎MySQL 的实时聚合足够。演示 PPT 里放这两张图比放十张列表页截图更说明问题尤其能体现“系统能回答管理者的提问”而不只是能增删改查。5. 排查与避坑SSM 访客系统最常见的 5 个踩坑点这一章也是血泪经验。自己在部署和演示这个项目时翻过几次车每一条都对应一个明确的根源。下面的现象、原因、解决三步照着排错比看异常栈乱猜快得多。5.1 MySQL 8 连接失败驱动名、时区、公钥三项查一遍现象Tomcat 启动时报java.sql.SQLException: Unable to load authentication plugin caching_sha2_password或者能加载驱动但连接超时。原因分三种驱动类名还是 com.mysql.jdbc.Driver、URL 缺少 serverTimezone、MySQL 8 默认认证插件与旧驱动不兼容。解决把驱动改成 com.mysql.cj.jdbc.DriverURL 加上 serverTimezoneAsia/Shanghai并配置 useSSLfalse 和 allowPublicKeyRetrievaltrue。如果本机同时装了 MySQL 5 和 8注意看端口连到 3306 的到底是哪一台。检验是否连通的命令是mysql -uroot -p -h127.0.0.1 -P3306能进就说明服务和端口没问题问题在应用配置。5.2 中文乱码建库、连接串、页面三层必须一致现象插入访客姓名后MySQL 里显示“???”或“鍚?”页面读出来是乱码。原因数据库是 utf8 或 latin1连接串 characterEncoding 没设置JSP 页面没有声明 UTF-8三层任一层掉链子都会乱。解决第一步用下面语句把表转换过来ALTER TABLE visitor CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;第二步保证连接串里带 characterEncodingutf8mb4第三步在 JSP 顶部写% page pageEncodingUTF-8 %同时把 Tomcat 的 URIEncoding 设为 UTF-8。三个地方都对齐后还乱码就用 MySQL Workbench 或 Navicat 打开表看看底层字符集是哪个直接排查最底层的事实别在页面层反复试。5.3 身份证号唯一索引把演示数据整懵了现象为了演示多次进校准备了三组访客数据导入第二次时报Duplicate entry xxx for key uk_id_card。原因visitor 表的 id_card 唯一索引生效演示数据里同一个身份证号被当成新访客插入了两次。这在逻辑上是对的但演示脚本没考虑幂等。解决初始化演示数据的 SQL 要按“存在则更新不存在则插入”来写用 MySQL 的 ON DUPLICATE KEY UPDATEINSERT INTO visitor (name, id_card, phone) VALUES (张三, 110101199001011234, 13800000000) ON DUPLICATE KEY UPDATE phone VALUES(phone);第二次执行就不再报错只更新手机号主键不变。后面 visit_log 插入时复用这个 visitor_id就能做出“同一个老访客多次进校”的效果。演示数据脚本要能重复执行这是答辩前最重要的检查项。5.4 统计“今日访客”把没签离的历史数据算进去了现象酒店顶层页的“今日访客”数字越来越大明明是今天的统计昨天没签离的访客全被算进来。原因SQL 写成WHERE DATE(enter_time) CURDATE()只看进入日期没有限定签离状态。昨天进来今天还没走的人进入日期是昨天DATEDIFF 计算错误。解决把 SQL 拆成两块已签离的按 leave_time 归属到相应日期未签离的按 enter_time 归属并作为“在访”单独计数-- 今日已签离 SELECT COUNT(*) FROM visit_log WHERE leave_time CURDATE() AND leave_time DATE_ADD(CURDATE(), INTERVAL 1 DAY); -- 当前在校 SELECT COUNT(*) FROM visit_log WHERE leave_time IS NULL;这段 SQL 把“发生于今天”“当前状态为在校”这两个概念分开逻辑上不打架。统计报表的 SQL 写完后我习惯用已知数据手工验一遍比如上午登记 3 人签离 2 人预期今天签离数就是 2。别迷信聚合结果。5.5 连接池耗尽界面卡死重启 Tomcat 才恢复现象系统运行一小时后突然卡死后续请求全部等待日志出现waiting for connection重启 Tomcat 又能撑一阵。原因连接没有归还连接池。最典型的是查询方法误加 Transactional事务未提交导致连接不释放或者是 Mapper 查询耗时长把连接占满。解决先检查所有 Service 方法删掉查询方法上的 Transactional再检查事务是不是在 try-catch 里被吞掉事务拦截器只有在异常传播到代理时才会回滚并释放连接。Druid 的监控页能直接看到活跃连接数和泄露数量建议临时打开stat-view-servlet万不得已时用removeAbandonedtrue兜底把超过时间未归还的连接强杀。这一步是黑匣子变透明的关键。6. 答辩演示前的最后一步准备演示数据集和验收脚本演示日和日常使用是两回事。答辩现场只有十分钟不要让评委看你自己手忙脚乱敲数据。我习惯在演示前把流程跑成一套可重复的“演示剧本”对应三条数据线新访客现场登记、老访客二次进校、已预约访客到校核验。三条线各自准备一条 SQL 初始化数据演示前一键重置到初始状态。给这个项目准备验收清单比具体代码更重要。按功能维度自测一遍能避免现场翻车功能点测试输入预期结果新访客登记身份证未在库中自动建档并生成 visit_log老访客登记身份证已在库中不重复建档只新增 visit_log预约核验预约单状态为已通过自动带出被访人不可改无效预约拦截预约单状态为已拒绝提示无有效预约签离点签离按钮leave_time 写入当前时间滞留查询修改 enter_time 为 9 小时前出现在滞留名单再往下走一步这些新功能点也是论文里“功能测试”章节的现成素材把预期结果和截图放进去比堆十页代码截图有说服力。做完这套系统后我会再看一眼 Spring BootSSM 的 Controller、Service、Mapper 分层照搬过去只把 XML 换掉就能变成 Spring Boot 项目简历上两种写法都能聊。SSM 让我看清了请求怎么流转、事务怎么生效它适合当第一块完整项目的垫脚石。希望帮到你。本文还有配套的精品资源点击获取
返回列表