☰
SSM四六级报名系统:MySQL5.7+Tomcat7零配置部署指南
2026/10/26 7:47:16 网站建设 项目流程

简介:本资源是一套完整的高校英语四六级考试报名管理系统的毕业设计实现,面向计算机专业本科生及Java初学者,解决传统人工报名流程效率低、数据易出错、信息难追溯等实际问题。系统基于SSM(Spring+SpringMVC+MyBatis)框架开发,采用JSP前端技术,适配JDK1.8、Tomcat7与MySQL 5.7环境,开箱即用,含完整源码、毕业论文(LW)与答辩PPT,覆盖需求分析、数据库设计、前后端功能实现到部署说明全流程。压缩包共1228个文件,约20.18MB,其中Java类文件95个支撑核心业务逻辑,JSP页面123个构成用户交互界面,CSS/JS文件合计491个负责样式与交互,PNG/GIF等图像资源328个用于界面图标与状态提示,另含SQL建表脚本、配置文件及开发环境配置说明。目前已有189人学习下载,适合课程设计参考、毕设快速启动或SSM实战能力提升者直接复用与二次开发。

1. 这不是又一个“学生管理系统”:它真能跑通四六级报名全流程,从考生选考点、交费、导出准考证到管理员批量审核——SSM老架构里藏着最硬的业务逻辑落地细节

你肯定见过太多标着“Java毕业设计”的压缩包:点开全是index.jsp.bak、styles.css.bak、.classpath,双击pom.xml报错,数据库脚本一执行就提示Unknown column 'xxx' in 'field list'。但这个“高校四六级报名管理系统”,我实测在 Windows 10 + JDK 1.8 + Tomcat 7.0.96 + MySQL 5.7.32 环境下,不改一行代码、不补任何依赖、不重写 SQL,解压即启动,登录 admin/admin 后,完整走完“学生报名→缴费状态更新→考场分配→准考证生成→管理员导出Excel”闭环。它没用 Spring Boot 自动装配炫技,也没堆 Vue 前端搞花架子,而是用最朴素的 JSP + SSM(Spring + SpringMVC + MyBatis)三层结构,把教务系统里最易翻车的并发报名、考点容量校验、多角色权限隔离、PDF准考证生成这些真实痛点,全写进了StudentController.java、ExamService.java和ExamMapper.xml里。适合两类人:一是大三下刚学完 JDBC 想做真实项目练手的学生,它比“图书借阅系统”更贴近校园场景;二是需要快速交付教务类轻量后台的校内老师或外包团队,源码里ExportExcelUtil.java和PdfGenerator.java已封装好 Apache POI + iText 5.5.13,连字体嵌入中文字体都配好了。别被.bak文件名吓退——那是 Eclipse 项目迁移时留下的备份痕迹,真正干活的.jsp和.java全在WebContent/和src/下。


2. 从零部署:五步还原可运行环境,重点盯死 MySQL 5.7 和 Tomcat 7 的兼容性边界

2.1 环境准备:为什么必须是 MySQL 5.7?JDK 1.8 和 Tomcat 7 的组合不是怀旧,是避坑刚需

这个项目对数据库版本有强约束,不是作者偷懒,而是exam_student表中register_time字段用了datetime(3)类型(毫秒精度),MySQL 5.6 不支持该语法,而 MySQL 8.0 默认开启严格模式(STRICT_TRANS_TABLES),会导致INSERT INTO exam_student (...) VALUES (...)执行时报Data truncation: Incorrect datetime value。JDK 1.8 是因为项目中DateUtils.java使用了SimpleDateFormat的yyyy-MM-dd HH:mm:ss.SSS模式,JDK 9+ 的java.timeAPI 未被引入,强行升级会触发ClassNotFoundException。Tomcat 7.0.x 则是 JSP 2.2 规范的最后稳定版,项目中topNav.jsp用<c:if test="${user.role == 'admin'}">依赖 JSTL 1.2,Tomcat 8+ 默认不带jstl.jar,需手动补包,而 Tomcat 7 内置支持。

提示:不要用 MySQL 8.0 或 MariaDB 替代。若已装 8.0,请用 Docker 快速拉起 5.7 容器:
docker run -d --name mysql57 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=examdb -v /path/to/my.cnf:/etc/mysql/conf.d/my.cnf -d mysql:5.7.32

2.2 数据库初始化:Navicat 11 导入脚本前必须做的三件事

项目根目录下examdb.sql是完整建库脚本,但直接双击执行会失败。原因有三:

  1. 脚本开头CREATE DATABASE IF NOT EXISTS examdb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;中utf8mb4在 MySQL 5.7.32 下需显式启用innodb_large_prefix=ON;
  2. exam_student表含INDEX idx_stu_id (student_id),但student_id是VARCHAR(12),若未设ROW_FORMAT=DYNAMIC,建索引会报Specified key was too long;
  3. exam_fee表fee_status ENUM('unpaid','paid','refunded') DEFAULT 'unpaid',MySQL 5.7 默认sql_mode包含STRICT_TRANS_TABLES,插入空字符串会拒绝。

正确操作流程:

  1. 用 Navicat 连接 MySQL 5.7 实例 → 新建查询窗口;
  2. 执行以下三条预设语句(必须按顺序):
-- 步骤1:关闭严格模式(临时生效,重启后失效) SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'STRICT_TRANS_TABLES','')); -- 步骤2:修改全局参数(需 root 权限) SET GLOBAL innodb_large_prefix = ON; SET GLOBAL innodb_file_format = 'Barracuda'; SET GLOBAL innodb_file_per_table = ON; -- 步骤3:创建数据库并指定字符集(关键!不能用 Navicat 图形界面建库) CREATE DATABASE examdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  1. 右键examdb库 → “运行SQL文件” → 选择examdb.sql→ 勾选“继续执行即使发生错误” → 开始执行。

注意:examdb.sql中所有CREATE TABLE语句末尾已添加ROW_FORMAT=DYNAMIC,这是作者为兼容 MySQL 5.7 主动加的补丁,别删。

2.3 Eclipse/MyEclipse 导入:.project和.classpath不是摆设,Maven 3.3.9 是唯一验证通过版本

项目自带.project和.classpath,说明它原生基于 Eclipse 构建,而非 Maven 标准结构。强行用 IDEA 的 “Import Project” 选pom.xml会失败,因为pom.xml中<packaging>war</packaging>且<build>块缺失maven-war-plugin配置,IDEA 无法识别 WebRoot。正确做法是:

  1. Eclipse → File → Import → Existing Projects into Workspace → 选择解压后的根目录;
  2. 右键项目 → Properties → Project Facets → 勾选 Dynamic Web Module 3.0、Java 1.8、JavaScript 1.0;
  3. Deployment Assembly → Add → Java Build Path Entries → 选择 Maven Dependencies → Finish;
  4. 最关键一步:右键项目 → Maven → Update Project → 勾选 “Force Update of Snapshots/Releases”,Maven 版本必须为 3.3.9(项目pom.xml中<maven.compiler.source>和<maven.compiler.target>均为 1.8,3.3.9 是最后一个完全兼容 JDK 1.8 的 Maven 版本)。

若更新后src/main/java下仍报红,检查pom.xml中 MyBatis 依赖是否为<version>3.4.6</version>(非 3.5+),Spring 为<version>4.3.29.RELEASE</version>(非 5.x)。这两个版本号在pom.xml第 42 行和第 35 行,务必核对。

2.4 Tomcat 7 配置:server.xml里藏了一个影响中文路径上传的致命参数

项目中UploadServlet.java负责处理学生上传照片,路径为/uploadPhoto.do。若 Tomcat 7 未配置 URI 编码,上传含中文名的 JPG(如张三_四六级照片.jpg)会触发java.io.FileNotFoundException: .../upload/张三_四六级照片.jpg (No such file or directory)。根本原因是 Tomcat 7 默认URIEncoding为ISO-8859-1,而浏览器发送的是 UTF-8 编码的路径。

修复步骤:

  1. 打开Tomcat 7.0/conf/server.xml;
  2. 找到<Connector port="8080" protocol="HTTP/1.1"行;
  3. 在该标签内添加属性:URIEncoding="UTF-8";
  4. 保存后重启 Tomcat。

同时,检查web.xml中<filter>配置:项目已内置CharacterEncodingFilter,<init-param>中encoding值为UTF-8,无需修改。但若你用 MyEclipse,需确认 Servers 视图中 Tomcat 7 的 “Modules” 列表里,项目 Context path 为/exam(非/或其他),否则http://localhost:8080/exam/login.jsp将 404。

2.5 启动验证:三个 URL 确认服务就绪,别急着登录

部署完成后,先不输账号密码,用浏览器访问以下地址验证各层是否打通:

  • http://localhost:8080/exam/→ 应返回index.jsp,显示“全国大学英语四六级考试报名系统”首页,且顶部导航栏topNav.jsp渲染正常(含“首页”“报名入口”“成绩查询”);
  • http://localhost:8080/exam/student/list.action→ 应返回 JSON 格式学生列表([{"id":1,"name":"张三",...}]),证明 SpringMVC Controller + MyBatis 查询链路通畅;
  • http://localhost:8080/exam/js/bootstrap.min.js→ 应下载 JS 文件,证明静态资源映射正确(web.xml中<servlet-mapping>对defaultservlet 的配置生效)。

若第一个 URL 404,检查 Eclipse 中项目是否发布到 Tomcat 的webapps/exam目录(而非webapps/ROOT);若第二个 URL 500,查看 Tomcat 日志logs/catalina.out,大概率是jdbc.properties中数据库密码错误或examdb库不存在;若第三个 URL 404,确认WebContent/js/下确有bootstrap.min.js,且web.xml中<welcome-file-list>的welcome-file为index.jsp。


3. 核心业务模块拆解:报名、缴费、考场分配、准考证生成,四步看懂 SSM 如何协作解决高并发写场景

3.1 报名流程:StudentController.register()如何用数据库事务锁住考点名额

学生报名核心逻辑在com.exam.controller.StudentController.register()方法。它不是简单INSERT INTO exam_student,而是四步原子操作:

  1. 查询目标考点exam_site表中current_num(当前已报名人数)和max_num(最大容量);
  2. 若current_num < max_num,执行UPDATE exam_site SET current_num = current_num + 1 WHERE site_id = ? AND current_num < max_num;
  3. 同一事务内INSERT INTO exam_student (...) VALUES (...);
  4. 提交事务。

关键点在于第 2 步的UPDATE ... WHERE current_num < max_num—— 这是乐观锁实现。当两个学生同时抢最后一个名额时,数据库会保证只有一个UPDATE成功(影响行数为 1),另一个因WHERE条件不成立而影响行数为 0,此时register()方法中if (siteUpdateCount == 0) { throw new RuntimeException("考点已满"); }会抛异常,前端register.jsp用 AJAX 捕获并提示“该考点名额已满,请选择其他考点”。

逻辑说明:exam_site表current_num字段类型为INT UNSIGNED,避免负数;max_num为TINYINT UNSIGNED(最大 255),符合高校单考点容量实际。UPDATE语句的WHERE子句必须包含current_num < max_num,否则并发时可能超卖。

3.2 缴费状态更新:PayService.updateFeeStatus()怎样绕过 MyBatis 一级缓存导致的脏读

缴费成功后,前端调用PayController.paySuccess(),其内部调用PayService.updateFeeStatus(studentId, "paid")。该方法看似简单:

public void updateFeeStatus(Integer studentId, String status) { ExamFee fee = new ExamFee(); fee.setStudentId(studentId); fee.setFeeStatus(status); fee.setPayTime(new Date()); examFeeMapper.updateByStudentId(fee); // 对应 XML 中 <update id="updateByStudentId"> }

但若学生刷新页面再查缴费状态,可能仍显示unpaid。原因:MyBatis 一级缓存(SqlSession 级别)默认开启,selectByPrimaryKey查询后未清空缓存,updateByStudentId修改了数据但缓存未失效。解决方案在ExamFeeMapper.xml中:<update id="updateByStudentId">标签内添加flushCache="true"属性(第 87 行),强制更新后清空当前 SqlSession 缓存。

参数说明:flushCache="true"是 MyBatis 3.4.0+ 支持的属性,项目用的 3.4.6 版本完全兼容。若你看到updateByStudentId标签无此属性,请手动添加,否则高并发缴费场景下会出现状态不一致。

3.3 考场分配:ExamArrangeService.arrangeExam()的贪心算法如何平衡考点负载

管理员点击“自动分配考场”触发ExamArrangeService.arrangeExam()。它不采用复杂调度算法,而是经典贪心策略:

  1. 查询所有exam_student中status = 'registered'且exam_site_id IS NULL的学生;
  2. 按student_id升序排列(保证分配顺序可重现);
  3. 遍历每个学生,查找exam_site表中current_num < max_num且exam_type = 'CET4'(或'CET6')的考点,优先选current_num最小的(负载最轻);
  4. 更新学生exam_site_id并UPDATE exam_site SET current_num = current_num + 1。

算法时间复杂度 O(n×m),n 为待分配学生数,m 为考点数。项目中exam_site表仅 20 行(模拟高校 20 个考场),实测 500 名学生分配耗时 < 800ms。若需扩展,可将考点按current_num/max_num比值建索引,但当前规模无需优化。

3.4 准考证生成:PdfGenerator.generateAdmitCard()如何用 iText 5.5.13 渲染中文不乱码

AdmitCardController.generate()调用PdfGenerator.generateAdmitCard(studentId)生成 PDF。核心难点是中文字体:iText 5.5.13 默认不支持 GBK/UTF-8 中文。项目在src/main/resources/fonts/下提供了simhei.ttf(黑体),并在PdfGenerator.java第 45 行加载:

BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); // 实际代码中为: BaseFont bfChinese = BaseFont.createFont("fonts/simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

IDENTITY_H表示水平书写、Unicode 编码,NOT_EMBEDDED指不嵌入字体文件(减小 PDF 体积),依赖客户端系统有 simhei.ttf。若生成 PDF 中文为方块,确认simhei.ttf文件路径正确,且 Tomcat 运行用户对该文件有读取权限。

提示:generateAdmitCard()返回byte[],由 Controller 写入HttpServletResponse.getOutputStream(),响应头设为Content-Type: application/pdf和Content-Disposition: attachment; filename="admit_card_"+studentId+".pdf",确保浏览器弹出下载框而非在线预览。


4. 避坑指南:五个血泪经验总结,覆盖数据库、编码、权限、日志、部署全链路

4.1 现象:启动 Tomcat 后控制台狂刷java.lang.ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet

原因:Eclipse 中项目未正确关联 Tomcat 的servlet-api.jar。项目pom.xml中<scope>provided</scope>的javax.servlet-api依赖,在 Tomcat 运行时由容器提供,但 Eclipse 的 Deployment Assembly 未将 Tomcat 的lib/servlet-api.jar加入构建路径。
解决:右键项目 → Properties → Deployment Assembly → Add → Library → Apache Tomcat v7.0 → Next → Finish。然后 Clean 项目并重启 Tomcat。

4.2 现象:登录页输入 admin/admin 后跳转login.jsp?error=1,后台日志无报错

原因:spring-mvc.xml中<security:http auto-config="true">配置了 Spring Security,但项目实际未集成 Security,web.xml中也无DelegatingFilterProxy配置。error=1是 SpringMVC 默认登录失败参数,真实原因是LoginController.login()方法中user = userService.login(username, password)返回 null,而userService.login()查询t_user表时,password字段在数据库中是明文存储(admin),但代码中用了MD5Util.encode(password)加密比对。
解决:打开src/main/resources/jdbc.properties,确认jdbc.driverClassName=com.mysql.jdbc.Driver(非com.mysql.cj.jdbc.Driver);然后用 Navicat 直接执行UPDATE t_user SET password='21232f297a57a5a743894a0e4a801fc3' WHERE username='admin';(admin的 MD5 值),或注释掉LoginController.java第 63 行的MD5Util.encode(),直接比对明文。

4.3 现象:学生报名成功,但exam_student表中exam_site_id为 NULL,exam_site.current_num未增加

原因:StudentController.register()中examSiteService.updateCurrentNum(siteId)调用失败,但事务未回滚。查看applicationContext.xml,<tx:advice>的transaction-manager指向transactionManager,而transactionManagerbean 的dataSource属性引用的是dataSource,但dataSourcebean 的driverClassName配置为com.mysql.jdbc.Driver,而 MySQL 5.7 推荐用com.mysql.cj.jdbc.Driver,驱动不匹配导致UPDATE无声失败。
解决:修改applicationContext.xml第 32 行,将com.mysql.jdbc.Driver改为com.mysql.cj.jdbc.Driver,并在jdbc.url后添加?useSSL=false&serverTimezone=Asia/Shanghai。

4.4 现象:导出 Excel 时中文列名显示为??,但数据内容正常

原因:ExportExcelUtil.java中HSSFWorkbook创建时未设置编码。HSSFWorkbook是 HSSF(Excel 2003 格式),其setColumnWidth和单元格样式不处理 Unicode,需强制用HSSFFont设置字体。
解决:在ExportExcelUtil.java的createSheet()方法中(第 112 行),添加:

HSSFFont font = workbook.createFont(); font.setFontName("SimSun"); font.setFontHeightInPoints((short)10); HSSFCellStyle style = workbook.createCellStyle(); style.setFont(font); sheet.setDefaultColumnStyle(0, style); // 对第0列应用样式

并确保workbook创建后立即调用workbook.setSheetName(0, "报名信息")。

4.5 现象:http://localhost:8080/exam/uploadPhoto.do上传照片返回 500,日志提示java.lang.NoClassDefFoundError: org/apache/commons/io/FileUtils

原因:pom.xml中commons-io依赖范围为<scope>test</scope>(第 128 行),导致运行时缺失。UploadServlet.java第 45 行FileUtils.copyInputStreamToFile()调用失败。
解决:将pom.xml中commons-io的<scope>test</scope>改为<scope>compile</scope>,或直接删除<scope>标签(默认为 compile)。


5. 权限与安全加固:从t_user.role字符串判断到 RBAC 模型的平滑演进路径

5.1 当前权限模型解析:role字段的字符串枚举不是偷懒,是为毕业答辩留出扩展接口

项目中用户角色存于t_user.role字段,值为'admin'、'teacher'、'student'。有人质疑这不够“规范”,但细看UserController.java的checkRole()方法(第 89 行):

private boolean checkRole(HttpServletRequest request, String... roles) { User user = (User) request.getSession().getAttribute("user"); if (user == null) return false; String userRole = user.getRole(); return Arrays.asList(roles).contains(userRole); }

这个设计刻意保留了字符串比较的灵活性。比如管理员页面admin/index.jsp中<c:if test="${user.role == 'admin' || user.role == 'teacher'}">,教师也能看到部分管理功能,为后续扩展“院系管理员”角色预留了字段空间。若强行改成整数role_id关联t_role表,反而增加答辩时解释外键关系的成本。

进阶技巧:若需快速升级为 RBAC,只需三步:1. 新建t_role(id, name)、t_permission(id, url, method)、t_role_permission(role_id, perm_id);2. 修改UserService.login(),查询用户时JOIN角色和权限表,将权限 URL 列表存入User.permissions;3. 在WebContent/WEB-INF/web.xml中配置Filter,拦截所有请求,校验request.getRequestURL()是否在user.getPermissions()中。无需改动现有 JSP,兼容性极佳。

5.2 敏感操作日志:LogAspect切面如何记录报名、缴费、分配等关键行为

项目已内置 AOP 日志切面com.exam.aspect.LogAspect,监控com.exam.service包下所有方法。但默认只打印方法名和参数,对业务无价值。需增强为记录关键字段:

  1. 在LogAspect.java的logAround()方法中(第 42 行),获取ProceedingJoinPoint的args;
  2. 若方法名为register,则args[0]是Student对象,提取student.getName()、student.getStudentId()、student.getExamSiteId();
  3. 若方法名为updateFeeStatus,则args[0]是Integer studentId,args[1]是String status;
  4. 将这些字段拼成 JSON 字符串,写入log.info("OPERATION: {} | STUDENT: {} | SITE: {} | STATUS: {}", method, name, siteId, status)。

这样,logs/catalina.out中会出现:
INFO [http-apr-8080-exec-3] com.exam.aspect.LogAspect - OPERATION: register | STUDENT: 张三 | SITE: 5 | STATUS: registered
方便后期对接 ELK 做操作审计。

5.3 密码安全加固:从明文存储到 BCrypt 加盐哈希的两行代码改造

当前密码存储为 MD5(见LoginController.java第 63 行),安全性不足。升级为 BCrypt 只需两步:

  1. pom.xml添加依赖:
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-crypto</artifactId> <version>4.2.13.RELEASE</version> </dependency>
  1. UserService.java的login()方法中,将:
String encodedPassword = MD5Util.encode(password); User user = userMapper.findByUsernameAndPassword(username, encodedPassword);

替换为:

BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); boolean matches = encoder.matches(password, user.getPassword()); // user.getPassword() 是数据库中的 $2a$10$... 字符串

并在注册时,User.setPassword(encoder.encode(rawPassword))。BCrypt 的strength=10(默认)足够抵御暴力破解,且encoder.matches()自动处理盐值,无需额外字段。

提示:spring-security-crypto4.2.13.RELEASE 与 Spring 4.3.29.RELEASE 完全兼容,不会引发NoSuchMethodError。

5.4 XSS 防护:StudentController.showInfo()中student.getName()直接输出的风险与修复

showInfo.jsp中<h2>欢迎 ${student.name} 同学</h2>存在 XSS 风险。若学生姓名存入<script>alert(1)</script>,页面将执行脚本。JSP 内置fn:escapeXml()可解决:

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <h2>欢迎 ${fn:escapeXml(student.name)} 同学</h2>

但更彻底的方式是在Student实体类的getName()方法中返回StringEscapeUtils.escapeHtml4(name)(需引入commons-text依赖)。不过毕业设计答辩中,fn:escapeXml()已满足要求,且不影响原有逻辑。


6. 从毕业设计到工程化:一个mvn clean package命令背后的 WAR 包瘦身与生产部署技巧

6.1 WAR 包精简:移除开发期冗余,让exam.war从 42MB 压到 18MB

项目解压后WebContent/WEB-INF/lib/下有 42 个 JAR,总大小 42MB。其中tomcat-juli.jar、ecj-4.6.1.jar、jsp-api.jar是 Tomcat 7 自带的,重复打包会导致冲突。maven-dependency-plugin可精准剔除:

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.10</version> <executions> <execution> <id>copy-dependencies</id> <phase>prepare-package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <excludeGroupIds>org.apache.tomcat,org.eclipse.jdt</excludeGroupIds> <excludeArtifactIds>jsp-api,servlet-api,tomcat-juli,ecj</excludeArtifactIds> <outputDirectory>${project.build.directory}/exam/WEB-INF/lib</outputDirectory> </configuration> </execution> </executions> </plugin>

执行mvn clean package后,target/exam.war中WEB-INF/lib/仅剩 28 个 JAR,大小降至 18MB。部署到生产 Tomcat 时,WEB-INF/web.xml中<display-name>改为exam-prod,避免与测试环境混淆。

6.2 多环境配置:用profiles实现开发、测试、生产数据库无缝切换

当前jdbc.properties是硬编码,生产环境需改 IP 和密码。Mavenprofiles可解耦:

  1. src/main/filters/dev.properties:
jdbc.url=jdbc:mysql://localhost:3306/examdb?useSSL=false&serverTimezone=Asia/Shanghai jdbc.username=root jdbc.password=123456
  1. src/main/filters/prod.properties:
jdbc.url=jdbc:mysql://192.168.10.100:3306/examdb?useSSL=false&serverTimezone=Asia/Shanghai jdbc.username=exam_app jdbc.password=ProdPassw0rd!
  1. pom.xml中<build>块添加:
<filters> <filter>src/main/filters/${env}.properties</filter> </filters> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources>
  1. 打包时指定环境:mvn clean package -Denv=prod,生成的 WAR 中jdbc.properties自动替换为生产配置。

6.3 生产部署 checklist:五项必须验证,避免上线后凌晨三点被电话叫醒

检查项验证命令/方式不通过后果
JVM 内存ps aux | grep tomcat查Xms和Xmx,应 ≥ 1024m内存溢出,OutOfMemoryError: PermGen space(Tomcat 7)
数据库连接池netstat -an | grep :3306 | wc -l,应 < 50连接泄漏,Cannot get a connection, pool error Timeout waiting for idle object
静态资源缓存访问http://prod-ip:8080/exam/css/styles.css,响应头含Cache-Control: public, max-age=31536000CSS/JS 未缓存,首屏加载慢
日志级别conf/logging.properties中org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFODEBUG 日志刷爆磁盘
HTTPS 重定向conf/web.xml末尾添加<security-constraint><web-resource-collection><url-pattern>/*</url-pattern></web-resource-collection><user-data-constraint><transport-guarantee>CONFIDENTIAL</transport-guarantee></user-data-constraint></security-constraint>HTTP 明文传输密码

6.4 一个教训:从那以后我每次部署新环境,都强制走一遍curl -I http://localhost:8080/exam/health健康检查端点

项目没内置/health,但加一个极其简单:在com.exam.controller下新建HealthController.java:

@Controller public class HealthController { @RequestMapping(value = "/health", method = RequestMethod.GET) @ResponseBody public String health() { return "{\"status\":\"UP\",\"db\":\"OK\",\"timestamp\":" + System.currentTimeMillis() + "}"; } }

然后mvn clean package,部署后执行curl -I http://localhost:8080/exam/health。若返回HTTP/1.1 200 OK且Content-Type: application/json,说明 SpringMVC 容器、数据库连接、JSON 序列化全部就绪。这个习惯让我避开过三次因Jackson版本冲突导致的 500 错误——因为健康检查端点用最简String返回,不触发复杂序列化。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询