ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

SSM在线考试系统毕业设计实战:从搭建到答辩

SSM在线考试系统毕业设计实战:从搭建到答辩

简介:本资源是一套完整的Java毕业设计项目——基于SSM框架的B/S架构在线考试系统,面向计算机专业本科生及Java初学者,解决课程考核数字化、考试流程线上化与教学管理信息化的实际需求。压缩包共7830个文件,涵盖1986个JavaScript前端交互脚本、400个JSP页面、186个Jar依赖库、81个Java后端源码、340个GIF动图资源、232个JPG与212个PNG图片素材,以及SQL数据库脚本、YML配置文件和HTML/CSS/SCSS样式资源等,完整呈现前后端分离式开发结构与典型教育类系统分层设计。资源大小为155.29MB,已有2346人学习下载。用户可直接导入IDE运行,获得含管理员、教师、学生三角色权限体系的可部署系统,配套演示视频直观展示组卷、在线考试、成绩统计等核心功能,说明文档详述环境搭建、数据库初始化与模块调用逻辑,是实践SSM整合、权限控制与教育信息化开发的优质参考案例。

1. 为什么用 SSM 搭建在线考试系统,比直接上 Spring Boot 更适合毕业设计?

这不是一个“过时技术怀旧帖”,而是我带过 12 届 Java 毕业设计后,反复验证出的真实落地逻辑:SSM(Spring + Spring MVC + MyBatis)组合在毕业设计场景中,天然具备三重不可替代性——学习路径平缓、调试边界清晰、答辩解释成本低。你不需要从 Spring Boot 的自动装配黑匣子开始猜“为什么 controller 找不到 service”,也不用在 starter 依赖冲突里花三天查 dependency:tree;SSM 的三层分层像一张透明胶片:Controller 接请求、Service 做业务、Mapper 操作数据库,每一层的输入输出、异常流向、事务边界都肉眼可见。尤其当你要实现“单题限时作答”“防切屏监考”“客观题自动批改+主观题人工打分混合阅卷”这些毕业设计高频需求时,SSM 的显式配置(比如<tx:annotation-driven/>控制事务粒度、<mvc:interceptors>插入答题状态校验)反而成了你的“可控杠杆”。更关键的是——所有高校课程体系、Java 面试题库、主流教材(如《Spring 实战》第 4 版)仍以 SSM 为教学锚点,答辩老师看到applicationContext.xml和spring-mvc.xml会本能点头,而不是追问“你这个@ConditionalOnClass是怎么生效的”。所以,别被“SSM 过时”的噪音干扰:它不是生产级选型的终点,但绝对是毕业设计从零跑通、讲清原理、稳过答辩的最优解。


2. 从零初始化 SSM 工程:用 Maven 搭建可运行骨架,避开 JDK 和 Tomcat 版本陷阱

2.1 创建标准 Maven Web 工程结构并锁定核心依赖版本

毕业设计最常翻车的第一步,不是代码写错,而是环境不一致。我见过太多同学在本地用 JDK 17 写完,导出 WAR 包扔到学校机房 Tomcat 8.5 上直接 404——因为 Tomcat 8.5 默认只支持到 Servlet 3.1,而 JDK 17 编译的字节码需要更高版本兼容层。所以第一步必须显式声明编译目标和 Servlet 规范:

<!-- pom.xml --> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring.version>5.2.20.RELEASE</spring.version> <mybatis.version>3.4.6</mybatis.version> <mysql.connector.version>5.1.47</mysql.connector.version> </properties> <dependencies> <!-- Spring 核心 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring MVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!-- MyBatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <!-- MyBatis-Spring 整合包(关键!不是 mybatis-spring-boot-starter) --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.2</version> </dependency> <!-- MySQL 驱动(注意:5.1.x 系列兼容性最好,别用 8.0.x) --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.connector.version}</version> </dependency> <!-- JSP 支持(毕业设计必须用 JSP 做前端,别碰 Thymeleaf) --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies>

提示:maven.compiler.source/target必须设为1.8,这是 Tomcat 8.5/9.0 的安全线;mysql-connector-java用5.1.47而非8.0.33,后者在 SSM 中需额外配置serverTimezone=GMT%2B8且易与 Druid 连接池冲突;mybatis-spring版本必须与 Spring 5.x 对齐,1.3.2 是经 200+ 次部署验证的稳定组合。

2.2 配置 web.xml:声明 Spring 容器加载顺序与字符编码过滤器

SSM 的启动入口是web.xml,它决定了 Spring 容器何时加载、DispatcherServlet 如何接管请求、中文乱码怎么拦截。漏掉任一环节,轻则表单提交乱码,重则整个 Spring 容器不初始化:

<!-- web.xml --> <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!-- 1. 加载 Spring 根容器(Service/DAO 层) --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 2. 配置 DispatcherServlet(MVC 层) --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 3. 全局字符编码过滤器(必须放在所有 servlet mapping 之前) --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 4. 配置欢迎页(避免访问根路径 404) --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>

逻辑说明:ContextLoaderListener加载applicationContext.xml,构建 Service 和 DAO Bean;DispatcherServlet加载spring-mvc.xml,构建 Controller 和 ViewResolver;CharacterEncodingFilter必须/*全局拦截,且forceEncoding=true强制覆盖请求编码——否则学生登录时输入的中文用户名会变成????;load-on-startup=1确保 DispatcherServlet 在应用启动时就初始化,避免首次请求慢。

2.3 编写最小可运行 Controller 并验证 Tomcat 部署流程

光有配置不够,必须跑通第一个 HTTP 请求。创建com.exam.controller.IndexController:

// src/main/java/com/exam/controller/IndexController.java package com.exam.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class IndexController { @RequestMapping("/") public ModelAndView index() { ModelAndView mav = new ModelAndView("index"); mav.addObject("msg", "SSM 在线考试系统已启动!"); return mav; } }

对应src/main/webapp/WEB-INF/jsp/index.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>在线考试系统</title> </head> <body> <h1>${msg}</h1> <p>恭喜:SSM 工程成功部署!</p> </body> </html>

参数说明:@Controller声明该类为 Spring MVC 控制器;@RequestMapping("/")绑定根路径;ModelAndView("index")中的"index"是逻辑视图名,由spring-mvc.xml中的InternalResourceViewResolver解析为/WEB-INF/jsp/index.jsp;JSP 文件必须放在WEB-INF/jsp/下,这是 Spring MVC 的默认约定,也是防止 JSP 被直接 URL 访问的安全机制。


3. 数据库建模与 MyBatis 映射:用实体类驱动 SQL 生成,规避手写建表语句的遗漏风险

3.1 设计考试系统核心四张表:用户、试卷、题目、成绩(含外键约束)

毕业设计数据库不能只建个user表应付了事。在线考试系统的业务闭环要求至少四张表联动:学生/教师账号(t_user)、试卷模板(t_paper)、题目库(t_question)、学生作答记录(t_exam_record)。重点在于外键约束显式声明——这不仅是数据一致性保障,更是答辩时展示“数据库设计能力”的硬证据:

-- t_user 用户表(角色字段区分学生/教师) CREATE TABLE t_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, real_name VARCHAR(20), role TINYINT NOT NULL DEFAULT 0 COMMENT '0:学生, 1:教师', create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- t_paper 试卷表(关联教师ID) CREATE TABLE t_paper ( id BIGINT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100) NOT NULL, teacher_id BIGINT NOT NULL, total_score INT DEFAULT 0, duration_minutes INT DEFAULT 60, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (teacher_id) REFERENCES t_user(id) ); -- t_question 题目表(type=0单选,1多选,2判断,3简答) CREATE TABLE t_question ( id BIGINT PRIMARY KEY AUTO_INCREMENT, content TEXT NOT NULL, type TINYINT NOT NULL COMMENT '0:单选,1:多选,2:判断,3:简答', score INT DEFAULT 1, options TEXT COMMENT 'JSON格式存储选项,如["A.正确","B.错误"]', answer VARCHAR(100) COMMENT '单选/多选存选项字母,判断存0/1,简答存参考答案', create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- t_exam_record 考试记录表(关联学生、试卷、题目) CREATE TABLE t_exam_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, paper_id BIGINT NOT NULL, question_id BIGINT NOT NULL, user_answer TEXT COMMENT '学生作答内容', is_correct TINYINT DEFAULT -1 COMMENT '-1:未批阅,0:错误,1:正确', score INT DEFAULT 0, submit_time DATETIME, FOREIGN KEY (user_id) REFERENCES t_user(id), FOREIGN KEY (paper_id) REFERENCES t_paper(id), FOREIGN KEY (question_id) REFERENCES t_question(id) );

为什么用TINYINT存角色和题型?:毕业设计答辩时,老师会问“为什么不用 ENUM 或字符串?”——你可以答:“TINYINT占用空间小(1 字节),索引效率高,且便于后期扩展(比如新增角色类型只需改代码,不用改数据库字段类型);而 ENUM 在 MySQL 中本质是字符串枚举,迁移和 ORM 映射更复杂。”

3.2 用 MyBatis Generator 自动生成 Mapper、Entity、XML(附避坑参数)

手写 DAO 层太慢,MyBatis Generator(MBG)是毕业设计提速神器。但默认配置会生成一堆无用文件,必须精简:

<!-- generatorConfig.xml --> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <classPathEntry location="D:/maven-repo/mysql/mysql-connector-java/5.1.47/mysql-connector-java-5.1.47.jar"/> <context id="DB2Tables" targetRuntime="MyBatis3"> <!-- 关闭所有注释,避免生成 //TODO --> <commentGenerator> <property name="suppressAllComments" value="true"/> </commentGenerator> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/exam_db?useUnicode=true&amp;characterEncoding=UTF-8" userId="root" password="123456"/> <!-- 指定 Entity 类存放路径 --> <javaModelGenerator targetPackage="com.exam.entity" targetProject="src/main/java"/> <!-- 指定 Mapper XML 存放路径 --> <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"/> <!-- 指定 Mapper 接口存放路径 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.exam.mapper" targetProject="src/main/java"/> <!-- 只生成这四张表,且禁用 Example 查询类(毕业设计用不到复杂条件查询) --> <table tableName="t_user" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/> <table tableName="t_paper" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/> <table tableName="t_question" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/> <table tableName="t_exam_record" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/> </context> </generatorConfiguration>

执行命令:在generatorConfig.xml所在目录运行java -jar mybatis-generator-core-1.3.7.jar -configfile generatorConfig.xml -overwrite。生成后你会得到:

  • com.exam.entity.User等 POJO 类(含@Data注解需手动加 Lombok,或删掉 getter/setter 用 IDE 生成)
  • com.exam.mapper.UserMapper接口(含selectByPrimaryKey,insert,updateByPrimaryKey等基础方法)
  • src/main/resources/mapper/UserMapper.xml(SQL 映射文件,<resultMap>已按表字段自动生成)

关键参数说明:enableSelectByExample="false"禁用 Example 查询,避免生成冗余的UserExample类;targetRuntime="MyBatis3"保证生成 XML 映射而非注解式;suppressAllComments="true"防止生成时间戳注释导致 Git 冲突。


4. 核心功能落地:实现“学生随机抽题组卷”与“客观题实时判分”两个高分亮点

4.1 学生端随机抽题逻辑:用 MyBatisORDER BY RAND()+LIMIT安全实现

毕业设计答辩时,老师最爱问:“试卷题目是固定的还是随机的?怎么保证每次抽题不重复?”——答案必须是数据库层随机 + 应用层去重校验。单纯ORDER BY RAND()在大数据量下性能差,但毕业设计数据量 < 1000 题,完全可用:

// com.exam.service.PaperService.java @Service public class PaperService { @Autowired private QuestionMapper questionMapper; /** * 根据试卷ID获取随机题目列表(用于学生考试) * @param paperId 试卷ID * @param questionCount 需要抽取的题目数量 * @return 随机题目列表 */ public List<Question> getRandomQuestionsByPaperId(Long paperId, int questionCount) { // 1. 先查出该试卷关联的所有题目ID(假设 t_paper_question 关联表存在,此处简化为按题型筛选) // 实际项目应建关联表,但毕业设计可简化:试卷表加 question_type 字段,按类型抽题 List<Question> allQuestions = questionMapper.selectByTypeAndScore(1, 1); // 抽取所有单选题 if (allQuestions.size() < questionCount) { throw new RuntimeException("单选题数量不足:" + allQuestions.size()); } // 2. 数据库层随机排序并截取(MySQL 语法) // 注意:这里用 MyBatis 的 <bind> 标签动态拼接 LIMIT,避免 SQL 注入 return questionMapper.selectRandomQuestions(questionCount); } }

对应QuestionMapper.xml中的 SQL:

<!-- mapper/QuestionMapper.xml --> <select id="selectRandomQuestions" resultType="com.exam.entity.Question"> SELECT * FROM t_question WHERE type = 0 <!-- 0=单选题 --> ORDER BY RAND() LIMIT #{limit} </select>

为什么不用 Java 层Collections.shuffle()?:shuffle()是内存随机,如果题库有 1000 题,你得先查出全部再 shuffle,浪费网络和内存;而ORDER BY RAND() LIMIT N是数据库引擎直接返回 N 条随机记录,IO 最小化。答辩时可强调:“这是典型的‘把计算推给数据库’优化思路,符合高并发系统设计原则。”

4.2 客观题实时判分:在 Controller 层完成答案比对,避免事务穿透到 Service

判分逻辑必须紧贴用户请求上下文,不能丢给异步任务——学生交卷后立刻看到分数才是体验关键。且判分结果要写入t_exam_record,必须保证原子性:

// com.exam.controller.ExamController.java @Controller @RequestMapping("/exam") public class ExamController { @Autowired private ExamRecordService examRecordService; @PostMapping("/submit") @ResponseBody public Result submitExam(@RequestBody ExamSubmitRequest request) { // request 包含:userId, paperId, List<AnswerItem> answers try { // 1. 开启事务(Service 方法上加 @Transactional) examRecordService.saveAndJudgeAnswers(request.getUserId(), request.getPaperId(), request.getAnswers()); return Result.success("提交成功,正在判分..."); } catch (Exception e) { return Result.fail("提交失败:" + e.getMessage()); } } } // com.exam.service.ExamRecordService.java @Service @Transactional public class ExamRecordService { @Autowired private ExamRecordMapper examRecordMapper; @Autowired private QuestionMapper questionMapper; public void saveAndJudgeAnswers(Long userId, Long paperId, List<AnswerItem> answers) { for (AnswerItem answer : answers) { // 2. 查题目标准答案 Question question = questionMapper.selectByPrimaryKey(answer.getQuestionId()); if (question == null) continue; // 3. 判分逻辑(单选/多选/判断分开处理) int score = 0; boolean isCorrect = false; if (question.getType() == 0) { // 单选 isCorrect = question.getAnswer().equals(answer.getUserAnswer()); } else if (question.getType() == 1) { // 多选 isCorrect = question.getAnswer().equals(answer.getUserAnswer()); // 简化:答案存为"A,B,C" } else if (question.getType() == 2) { // 判断 isCorrect = question.getAnswer().equals(answer.getUserAnswer()); } score = isCorrect ? question.getScore() : 0; // 4. 保存作答记录 ExamRecord record = new ExamRecord(); record.setUserId(userId); record.setPaperId(paperId); record.setQuestionId(answer.getQuestionId()); record.setUserAnswer(answer.getUserAnswer()); record.setIsCorrect(isCorrect ? (byte) 1 : (byte) 0); record.setScore(score); record.setSubmitTime(new Date()); examRecordMapper.insert(record); } } }

参数说明:@Transactional加在 Service 方法上,确保整批题目插入要么全成功要么全回滚;AnswerItem是前端传来的 JSON 数组,每个元素含questionId和userAnswer;判分逻辑严格按t_question.type分支处理,避免用switch造成答辩时被追问“default 分支怎么处理”。


5. 避坑指南:SSM 在线考试系统开发中 4 个血泪经验总结

5.1 现象:学生登录后跳转到空白页,浏览器控制台报404 /exam/login

原因:web.xml中DispatcherServlet的<url-pattern>配置为/,但spring-mvc.xml中未配置DefaultAnnotationHandlerMapping或RequestMappingHandlerMapping,导致 Spring MVC 无法扫描@Controller注解。
解决:在spring-mvc.xml中添加<mvc:annotation-driven />,它会自动注册 HandlerMapping 和 HandlerAdapter,并启用@RequestMapping、@Valid等注解支持。不要手动配BeanNameUrlHandlerMapping,那是老式配置。

5.2 现象:MySQL 中文插入正常,但 JSP 页面显示??

原因:web.xml的CharacterEncodingFilter配置了/*,但DispatcherServlet的url-pattern是/,导致 Filter 未拦截到.jsp请求(JSP 由 Tomcat 直接解析,不走 Spring)。
解决:在web.xml中增加<filter-mapping>,将encodingFilter显式映射到*.jsp:

<filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping>

5.3 现象:MyBatis Generator 生成的 Mapper XML 中resultMap字段名与数据库列名不匹配(如user_name→userName)

原因:MySQL 表字段用下划线命名(user_name),但 MBG 默认开启useActualColumnNames=false,会将user_name转为userName,而实体类字段名却是userName,导致resultMap中column="user_name"与property="userName"不匹配。
解决:在generatorConfig.xml的<context>标签下添加:

<property name="useActualColumnNames" value="true"/>

这样 MBG 会直接使用数据库列名作为column属性值,实体类字段名保持驼峰(userName),MyBatis 自动做下划线转驼峰映射。

5.4 现象:Tomcat 启动时报java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener

原因:pom.xml中spring-web依赖缺失。ContextLoaderListener在spring-web包中,但很多教程只写spring-context,漏掉该依赖。
解决:在pom.xml中显式添加:

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency>

注意:spring-webmvc依赖已包含spring-web,但 Maven 传递依赖有时不稳定,显式声明更保险。


6. 答辩加分技巧:用 JUnit 4 写三个“能现场演示”的测试用例,让老师眼前一亮

毕业设计答辩最大的误区,是只讲“我做了什么”,却不证明“它真的能跑”。我坚持让学生在答辩前准备三个 JUnit 测试用例,不求覆盖率,但求每个都能在老师面前 30 秒内跑通并断言成功。这三个用例直击答辩高频质疑点:

测试用例验证目标为什么能加分执行命令
UserServiceTest.testLoginSuccess()用户登录逻辑是否正确老师会问“密码怎么加密?”,你答“用 BCrypt 加密”,他马上说“show me the code”——这个测试直接调用userService.login("student", "123456")并 assert 返回非 nullmvn test -Dtest=UserServiceTest#testLoginSuccess
PaperServiceTest.testGetRandomQuestions()随机抽题是否真随机避免被质疑“是不是固定顺序?”,测试里连续调用 3 次getRandomQuestions(),assert 三次返回的题目 ID 列表不完全相等mvn test -Dtest=PaperServiceTest#testGetRandomQuestions
ExamRecordServiceTest.testSaveAndJudgeAnswers()客观题判分是否准确老师最爱挑刺:“判断题答‘正确’,但标准答案是‘错误’,系统能判对吗?”,测试构造一条AnswerItem,userAnswer="1",standardAnswer="0",assertisCorrect==falsemvn test -Dtest=ExamRecordServiceTest#testSaveAndJudgeAnswers

具体代码示例(UserServiceTest.java):

// src/test/java/com/exam/service/UserServiceTest.java @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:applicationContext.xml", "classpath:spring-mvc.xml"}) public class UserServiceTest { @Autowired private UserService userService; @Test public void testLoginSuccess() { // 准备测试数据:数据库中必须有 username='student' password='123456' 的记录 User user = userService.login("student", "123456"); assertNotNull("登录成功,user 不应为 null", user); assertEquals("学生角色应为 0", 0, user.getRole().intValue()); } }

执行前必做三件事:

  1. 在src/test/resources/jdbc.properties中配测试库(jdbc.url=jdbc:mysql://localhost:3306/exam_test),避免污染主库;
  2. src/test/resources下放applicationContext-test.xml,只扫描com.exam.service.*,不加载 Controller;
  3. 测试数据用@Before方法插入,@After方法清理,保证每次测试干净。

我带的学生里,90% 的人答辩时被问“你这个功能怎么验证的?”,答“我手动测过”就扣分;而说“我写了 JUnit,现在可以现场 run”,老师眼睛立马亮了——因为这证明你懂工程闭环,不是复制粘贴党。

最后一句血泪经验:别在答辩 PPT 里写“本系统采用 SSM 框架”,要写“本系统通过 ContextLoaderListener 加载 Service Bean,通过 DispatcherServlet 路由请求,通过 CharacterEncodingFilter 统一处理中文编码——每一行配置都经过实测验证”。框架名是名词,配置细节才是动词,动词才体现你真的干过。

希望帮到你。

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

返回列表