SpringBoot学生成绩管理系统实战:从零到一构建Java Web项目

📅 2026/7/22 9:07:01
SpringBoot学生成绩管理系统实战:从零到一构建Java Web项目
每到期末课程设计、大作业、毕业设计接踵而至你是不是也在为找一个“能跑起来、技术栈主流、文档齐全、最好还能写到简历里”的Java项目而焦头烂额网上项目千千万要么技术栈老旧要么代码残缺跑不起来要么就是纯CRUD毫无亮点。今天要聊的这个基于SpringBoot的学生成绩管理系统可能就是你的“期末救星”。但别急着去搜源码我们先得搞清楚一个关键问题一个“好”的课程设计项目和网上随手下载的“源码包”核心区别到底在哪里很多人以为课程设计就是下载个代码改改页面交差了事。但如果你真这么做了很可能在答辩时被老师问得哑口无言或者在未来面试时这段经历根本加不了分。真正的价值不在于代码本身而在于你能否清晰地说出为什么用SpringBoot而不是SSHMyBatis-Plus比原生MyBatis好在哪里Thymeleaf模板引擎解决了JSP的什么痛点整个项目的分层架构是如何设计的本文将带你深度拆解一个典型的SpringBoot学生成绩管理系统。我们不止提供可运行的源码和数据库文末会说明更重要的是我会为你剖析从零到一的完整设计思路、技术选型背后的原因、每个层级的代码实现以及那些新手最容易栽进去的“坑”。无论你是用于期末大作业、课程设计还是作为SpringBoot的入门实战这篇文章都能让你不仅“做出来”更能“讲明白”。1. 为什么学生成绩管理系统是SpringBoot入门的最佳实战你可能觉得“学生成绩管理”太普通了但恰恰是它的业务简单、需求明确使其成为学习企业级开发框架的绝佳沙盒。它几乎涵盖了后端开发最核心的CRUD增删改查并自然地引申出用户权限、数据关联、事务处理等进阶概念。使用SpringBoot来构建对比传统的SSHStruts2 Spring Hibernate或SSMSpringMVC Spring MyBatis架构优势是颠覆性的零配置起步传统SSM需要大量繁琐的XML配置。SpringBoot通过自动装配和约定大于配置的原则让你用几个注解就能跑起一个Web应用。内嵌容器无需额外安装和配置Tomcat。一个main方法就能启动java -jar一键部署简化了开发和部署流程。技术栈现代且统一本项目常集成的MyBatis-Plus、Thymeleaf、Druid等都是当前企业开发的主流选择学习它们对求职有直接帮助。生态丰富SpringBoot拥有庞大的Starter生态需要什么功能如安全、缓存、消息队列引入对应依赖即可极大地提升了开发效率。所以这个项目的目标不仅仅是完成一个管理系统而是通过一个具体的业务场景打通SpringBoot Maven MyBatis-Plus Thymeleaf MySQL Ajax这一整套现代Java Web开发技术栈。2. 核心功能与业务模块设计在动手写代码之前我们必须先理清业务。一个完整的学生成绩管理系统通常包含以下核心模块系统管理模块用户登录/注销不同角色如管理员、教师、学生拥有不同权限。角色与权限管理RBAC控制菜单访问和操作权限如学生只能查成绩教师能录成绩。基础数据管理模块学生信息管理对学生信息的增、删、改、查。教师信息管理对教师信息的维护。课程信息管理管理学校开设的课程。核心业务模块选课管理学生选择课程教师教授课程。这里涉及学生、课程、教师三者的关联。成绩管理教师录入、修改所授课程的学生成绩学生查询自己的成绩。这是系统的核心。统计与查询模块成绩统计按课程、班级、个人统计平均分、最高/最低分等。综合查询多条件组合查询学生、成绩等信息。数据库设计ER图核心思想 这是项目的基石。主要实体及关系如下sys_user系统用户表包含登录名、密码、角色等字段。student_info学生信息表包含学号、姓名、班级等。与sys_user可关联如通过用户ID。teacher_info教师信息表。course_info课程信息表包含课程号、课程名、学分等。student_course学生选课表。这是一个关联表包含student_id,course_id用于表示多对多关系一个学生可选多门课一门课可被多个学生选。score_info成绩表。这是最复杂的一张表通常包含id,student_course_id或同时包含student_id和course_idscore成绩teacher_id录入教师等字段。它关联了学生、课程和教师。清晰的数据库设计是后面所有编码工作的前提。3. 环境准备与项目初始化开发环境清单JDK1.8 或 11推荐LTS版本如11IDEIntelliJ IDEA社区版即可或 Eclipse需安装Spring Tools插件项目管理Apache Maven 3.6数据库MySQL 5.7 或 8.0浏览器Chrome 或 Firefox用于测试使用Spring Initializr快速初始化项目 这是SpringBoot官方提供的项目生成工具能避免手动配置的繁琐。访问 start.spring.io 。按以下选择进行配置Project: MavenLanguage: JavaSpring Boot: 选择稳定的版本如 2.7.x 或 3.x注意3.x需JDK17Project Metadata:Group:com.yourname(例如com.example)Artifact:score-managementName:score-managementPackage name: 自动生成Packaging: JarJava: 选择与你JDK匹配的版本添加依赖在Dependencies区域搜索并添加Spring Web(用于构建Web应用)Thymeleaf(模板引擎)MyBatis Framework(或直接搜索MyBatis Plus但Initializr可能没有需后续手动添加)MySQL Driver(数据库驱动)Lombok(简化实体类代码强烈推荐)点击Generate按钮下载生成的ZIP包解压后用IDEA打开。手动补充关键依赖pom.xml Spring Initializr可能没有MyBatis-Plus我们需要手动在pom.xml的dependencies部分添加!-- MyBatis-Plus 增强版ORM框架 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version !-- 请检查并使用最新稳定版 -- /dependency !-- Druid 数据库连接池性能强大自带监控 -- dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-starter/artifactId version1.2.16/version /dependency !-- 可选Hutool 工具类库提高开发效率 -- dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.8.22/version /dependency添加后IDEA会自动下载依赖。如果速度慢请检查Maven配置的镜像是否为国内源如阿里云镜像。4. 项目架构与核心配置详解一个结构清晰的SpringBoot项目目录如下src/main/java └── com.example.scoremanagement ├── ScoreManagementApplication.java // 主启动类 ├── config // 配置类包 │ ├── MybatisPlusConfig.java // MyBatis-Plus配置 │ ├── WebMvcConfig.java // 静态资源、拦截器配置 │ └── DruidConfig.java // 数据源监控配置 ├── controller // 控制层 ├── service // 业务逻辑层 │ └── impl // 业务逻辑实现层 ├── mapper // 数据访问层Dao层MyBatis的Mapper接口 ├── entity // 实体类对应数据库表 ├── dto // 数据传输对象用于前后端交互 ├── vo // 视图对象用于页面展示 └── utils // 工具类包 src/main/resources ├── application.yml // 主配置文件推荐YAML格式 ├── static // 静态资源css, js, images ├── templates // 模板文件Thymeleaf HTML └── mapper // MyBatis XML映射文件如果用XML方式核心配置文件application.yml YAML格式比properties更清晰支持层级结构。server: port: 8080 servlet: context-path: / # 项目上下文路径可为空或 /api等 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/score_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: your_password # 请替换为你的数据库密码 type: com.alibaba.druid.pool.DruidDataSource # 指定使用Druid连接池 druid: initial-size: 5 min-idle: 5 max-active: 20 web-stat-filter: enabled: true stat-view-servlet: enabled: true url-pattern: /druid/* # 开启Druid监控访问 http://localhost:8080/druid login-username: admin login-password: admin thymeleaf: prefix: classpath:/templates/ suffix: .html mode: HTML encoding: UTF-8 cache: false # 开发时关闭缓存修改HTML后立即生效 mvc: static-path-pattern: /static/** # 静态资源访问路径 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印SQL便于调试 map-underscore-to-camel-case: true # 自动将下划线命名转为驼峰命名 global-config: db-config: id-type: auto # 主键策略数据库自增 logic-delete-field: deleted # 全局逻辑删除字段名如果表中有此字段 logic-delete-value: 1 # 逻辑已删除值 logic-not-delete-value: 0 # 逻辑未删除值 mapper-locations: classpath*:/mapper/**/*.xml # XML映射文件位置配置类示例MybatisPlusConfig.javapackage com.example.scoremanagement.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class MybatisPlusConfig { /** * 添加MyBatis-Plus插件 * 分页插件是必须的否则分页功能不生效 */ Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); // 添加分页插件并指定数据库类型为MYSQL interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 还可以添加其他插件如乐观锁插件 // interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } }5. 实体类、Mapper与Service层代码实现我们以Student学生实体为例展示各层级的代码编写。5.1 实体类 (Entity) -Student.java使用Lombok注解极大简化代码。package com.example.scoremanagement.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.time.LocalDateTime; Data // Lombok注解自动生成getter, setter, toString, equals, hashCode等方法 TableName(student_info) // 指定对应的数据库表名 public class Student { /** * 主键ID使用数据库自增策略 */ TableId(type IdType.AUTO) private Long id; /** * 学号唯一标识 */ private String studentNumber; /** * 学生姓名 */ private String name; /** * 性别 */ private String gender; /** * 所属班级 */ private String className; /** * 联系电话 */ private String phone; /** * 电子邮箱 */ private String email; /** * 入学日期 */ private LocalDateTime enrollmentDate; /** * 创建时间 */ private LocalDateTime createTime; /** * 更新时间 */ private LocalDateTime updateTime; }5.2 Mapper接口 (DAO层) -StudentMapper.javaMyBatis-Plus的Mapper接口只需继承BaseMapper即可获得大量通用CRUD方法无需编写XML简单查询。package com.example.scoremanagement.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.scoremanagement.entity.Student; import org.apache.ibatis.annotations.Mapper; Mapper // 标识为MyBatis的MapperSpring会自动扫描 public interface StudentMapper extends BaseMapperStudent { // 如果需要复杂的自定义SQL可以在这里定义方法并在对应的XML文件中实现 // 例如ListStudent selectStudentsByCondition(Param(name) String name, Param(className) String className); }5.3 Service层 -StudentService.java与StudentServiceImpl.javaService层定义业务逻辑接口Impl类是实现。同样可以继承MyBatis-Plus的IService来获得增强的Service层CRUD方法。// StudentService.java package com.example.scoremanagement.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.scoremanagement.entity.Student; import java.util.List; public interface StudentService extends IServiceStudent { // 可以在此定义更复杂的业务方法不局限于CRUD ListStudent getStudentsByClassName(String className); boolean saveStudent(Student student); boolean updateStudent(Student student); boolean deleteStudentById(Long id); }// StudentServiceImpl.java package com.example.scoremanagement.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.scoremanagement.entity.Student; import com.example.scoremanagement.mapper.StudentMapper; import com.example.scoremanagement.service.StudentService; import org.springframework.stereotype.Service; import java.util.List; Service // 标识为Spring的Service组件 public class StudentServiceImpl extends ServiceImplStudentMapper, Student implements StudentService { Override public ListStudent getStudentsByClassName(String className) { // 使用MyBatis-Plus的Lambda查询构造器避免SQL注入写法优雅 return this.lambdaQuery() .eq(Student::getClassName, className) // where class_name #{className} .orderByAsc(Student::getStudentNumber) // order by student_number asc .list(); } Override public boolean saveStudent(Student student) { // 这里可以添加业务逻辑例如学号唯一性校验 if (student.getStudentNumber() null || student.getStudentNumber().isEmpty()) { throw new RuntimeException(学号不能为空); } // 设置创建时间 student.setCreateTime(LocalDateTime.now()); return this.save(student); } Override public boolean updateStudent(Student student) { // 设置更新时间 student.setUpdateTime(LocalDateTime.now()); return this.updateById(student); } Override public boolean deleteStudentById(Long id) { // 物理删除 // return this.removeById(id); // 逻辑删除需要实体类有deleted字段并配置了逻辑删除 return this.removeById(id); } }6. Controller层与Thymeleaf页面交互Controller负责接收请求、调用Service、返回响应页面或JSON。6.1 Controller -StudentController.javapackage com.example.scoremanagement.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.example.scoremanagement.entity.Student; import com.example.scoremanagement.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; Controller RequestMapping(/student) // 类级别的请求映射所有方法路径都以/student开头 public class StudentController { Autowired private StudentService studentService; /** * 分页查询学生列表 * param pageNum 当前页码默认为1 * param pageSize 每页条数默认为10 * param name 学生姓名查询条件 * param className 班级名称查询条件 * param model 传递给页面的模型数据 * return 学生列表页面 */ GetMapping(/list) public String list(RequestParam(value pageNum, defaultValue 1) Integer pageNum, RequestParam(value pageSize, defaultValue 10) Integer pageSize, RequestParam(value name, required false) String name, RequestParam(value className, required false) String className, Model model) { // 1. 构建分页对象 PageStudent page new Page(pageNum, pageSize); // 2. 构建查询条件 LambdaQueryWrapperStudent queryWrapper new LambdaQueryWrapper(); if (name ! null !name.trim().isEmpty()) { queryWrapper.like(Student::getName, name.trim()); // 模糊查询姓名 } if (className ! null !className.trim().isEmpty()) { queryWrapper.eq(Student::getClassName, className.trim()); // 精确查询班级 } queryWrapper.orderByDesc(Student::getCreateTime); // 按创建时间倒序 // 3. 执行分页查询 PageStudent studentPage studentService.page(page, queryWrapper); // 4. 将数据放入Model供Thymeleaf渲染 model.addAttribute(pageInfo, studentPage); model.addAttribute(name, name); model.addAttribute(className, className); return student/list; // 返回 templates/student/list.html 页面 } /** * 跳转到新增学生页面 */ GetMapping(/add) public String toAddPage() { return student/add; } /** * 执行新增学生操作 * param student 前端表单提交的学生数据Spring MVC自动绑定 * return 重定向到列表页 */ PostMapping(/add) public String add(Student student) { studentService.saveStudent(student); return redirect:/student/list; // 使用重定向防止表单重复提交 } /** * 跳转到编辑学生页面 * param id 学生ID * param model * return */ GetMapping(/edit/{id}) public String toEditPage(PathVariable(id) Long id, Model model) { Student student studentService.getById(id); model.addAttribute(student, student); return student/edit; } /** * 执行更新学生操作 */ PostMapping(/update) public String update(Student student) { studentService.updateStudent(student); return redirect:/student/list; } /** * 删除学生 */ GetMapping(/delete/{id}) public String delete(PathVariable(id) Long id) { studentService.deleteStudentById(id); return redirect:/student/list; } /** * RESTful API 风格接口示例返回JSON数据供Ajax调用 */ GetMapping(/api/{id}) ResponseBody // 此注解表示返回JSON而不是视图名 public Student getStudentApi(PathVariable(id) Long id) { return studentService.getById(id); } }6.2 Thymeleaf页面示例 -list.html(片段)Thymeleaf语法自然直接在HTML中嵌入动态数据。!DOCTYPE html html langzh xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 title学生列表/title link relstylesheet th:href{/static/css/bootstrap.min.css} /head body div classcontainer mt-4 h2学生信息管理/h2 !-- 查询表单 -- form classform-inline mb-3 th:action{/student/list} methodget input typetext classform-control mr-2 namename th:value${name} placeholder学生姓名 input typetext classform-control mr-2 nameclassName th:value${className} placeholder班级 button typesubmit classbtn btn-primary查询/button a th:href{/student/add} classbtn btn-success ml-2新增学生/a /form !-- 学生列表表格 -- table classtable table-bordered table-hover thead tr thID/th th学号/th th姓名/th th性别/th th班级/th th操作/th /tr /thead tbody !-- th:each 循环遍历列表 -- tr th:eachstudent : ${pageInfo.records} td th:text${student.id}/td td th:text${student.studentNumber}/td td th:text${student.name}/td td th:text${student.gender}/td td th:text${student.className}/td td a th:href{/student/edit/{id}(id${student.id})} classbtn btn-sm btn-warning编辑/a a th:href{/student/delete/{id}(id${student.id})} classbtn btn-sm btn-danger onclickreturn confirm(确定删除吗)删除/a !-- Ajax调用示例按钮 -- button classbtn btn-sm btn-info onclickgetStudentDetail(${student.id})查看详情(Ajax)/button /td /tr /tbody /table !-- 分页组件 -- nav ul classpagination li classpage-item th:classappend${pageInfo.current 1} ? disabled : a classpage-link th:href{/student/list(pageNum1, pageSize${pageInfo.size}, name${name}, className${className})}首页/a /li li classpage-item th:classappend${pageInfo.current 1} ? disabled : a classpage-link th:href{/student/list(pageNum${pageInfo.current - 1}, pageSize${pageInfo.size}, name${name}, className${className})}上一页/a /li !-- 页码遍历这里简化显示 -- li classpage-item th:eachi : ${#numbers.sequence(1, pageInfo.pages)} th:classappend${i pageInfo.current} ? active : a classpage-link th:href{/student/list(pageNum${i}, pageSize${pageInfo.size}, name${name}, className${className})} th:text${i}/a /li li classpage-item th:classappend${pageInfo.current pageInfo.pages} ? disabled : a classpage-link th:href{/student/list(pageNum${pageInfo.current 1}, pageSize${pageInfo.size}, name${name}, className${className})}下一页/a /li li classpage-item th:classappend${pageInfo.current pageInfo.pages} ? disabled : a classpage-link th:href{/student/list(pageNum${pageInfo.pages}, pageSize${pageInfo.size}, name${name}, className${className})}尾页/a /li /ul div当前第 span th:text${pageInfo.current}/span 页共 span th:text${pageInfo.pages}/span 页总计 span th:text${pageInfo.total}/span 条记录/div /nav /div script th:src{/static/js/jquery-3.6.0.min.js}/script script // 简单的Ajax调用示例 function getStudentDetail(studentId) { $.get(/student/api/ studentId, function(data) { alert(学生详情 JSON.stringify(data)); }); } /script /body /html7. 核心业务成绩管理的关联查询实现成绩管理是系统的核心涉及多表关联查询学生、课程、成绩。这里展示如何使用MyBatis-Plus进行复杂的关联查询。7.1 创建成绩视图对象VO -ScoreVO.javaVO用于封装前端页面需要的复杂数据它可能来自多张表。package com.example.scoremanagement.vo; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; Data public class ScoreVO { // 成绩信息 private Long scoreId; private BigDecimal score; // 使用BigDecimal处理精确小数 private LocalDateTime examTime; // 学生信息 private Long studentId; private String studentNumber; private String studentName; private String className; // 课程信息 private Long courseId; private String courseNumber; private String courseName; private BigDecimal credit; // 教师信息录入者 private String teacherName; }7.2 编写自定义Mapper方法与XML在ScoreMapper.java中定义方法package com.example.scoremanagement.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.example.scoremanagement.entity.Score; import com.example.scoremanagement.vo.ScoreVO; import org.apache.ibatis.annotations.Param; Mapper public interface ScoreMapper extends BaseMapperScore { /** * 多表关联分页查询成绩详情 * param page 分页参数MyBatis-Plus会自动处理 * param studentName 学生姓名模糊查询 * param courseName 课程名称模糊查询 * return 分页的ScoreVO列表 */ PageScoreVO selectScoreDetailPage(PageScoreVO page, Param(studentName) String studentName, Param(courseName) String courseName); }在resources/mapper/ScoreMapper.xml中编写SQL?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.example.scoremanagement.mapper.ScoreMapper select idselectScoreDetailPage resultTypecom.example.scoremanagement.vo.ScoreVO SELECT s.id as scoreId, s.score, s.exam_time, stu.id as studentId, stu.student_number, stu.name as studentName, stu.class_name as className, c.id as courseId, c.course_number, c.name as courseName, c.credit, t.name as teacherName FROM score_info s LEFT JOIN student_info stu ON s.student_id stu.id LEFT JOIN course_info c ON s.course_id c.id LEFT JOIN teacher_info t ON s.teacher_id t.id WHERE 11 if teststudentName ! null and studentName ! AND stu.name LIKE CONCAT(%, #{studentName}, %) /if if testcourseName ! null and courseName ! AND c.name LIKE CONCAT(%, #{courseName}, %) /if ORDER BY s.exam_time DESC /select /mapper7.3 在Service和Controller中调用在ScoreService和ScoreServiceImpl中定义对应方法然后在ScoreController中像之前一样调用并返回给页面。这个过程清晰地展示了如何从简单的单表CRUD过渡到复杂的多表业务查询这是项目从“玩具”走向“实用”的关键一步。8. 项目运行、测试与部署8.1 数据库初始化在MySQL中创建数据库CREATE DATABASE score_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;运行项目resources目录下的SQL脚本需自行根据实体类编写或使用MyBatis-Plus的代码生成器逆向生成创建表并插入测试数据。8.2 启动项目在IDEA中找到主启动类ScoreManagementApplication右键点击Run ScoreManagementApplication。 或在项目根目录下使用Maven命令mvn spring-boot:run看到控制台输出类似Started ScoreManagementApplication in X.XXX seconds的信息即表示启动成功。8.3 访问系统打开浏览器访问http://localhost:8080。你需要先实现一个简单的登录页面和控制器。登录后即可访问学生、课程、成绩等管理页面。8.4 打包部署# 在项目根目录下执行Maven打包命令会生成一个可执行的Jar文件 mvn clean package -DskipTests # 打包完成后在target目录下找到 score-management-0.0.1-SNAPSHOT.jar # 使用java命令运行 java -jar target/score-management-0.0.1-SNAPSHOT.jar你可以通过--server.port8081参数指定端口或使用nohup命令在后台运行。9. 常见问题与排查指南QA问题现象可能原因排查方式解决方案启动时报Failed to configure a DataSource数据库连接配置错误或数据库服务未启动。1. 检查application.yml中的url,username,password。2. 检查MySQL服务是否运行 (netstat -angrep 3306)。br3. 检查驱动类名是否正确MySQL 8 使用com.mysql.cj.jdbc.Driver。访问页面报Whitelabel Error Page(404)请求路径不存在或Controller未正确映射。1. 检查浏览器地址栏URL是否正确。2. 检查Controller的RequestMapping和GetMapping/PostMapping注解路径。3. 检查方法返回值是否是存在的Thymeleaf模板路径。核对请求路径与Controller映射关系。页面显示${...}而不是数据Thymeleaf模板引擎未正确解析。1. 检查HTML文件开头是否声明了Thymeleaf命名空间xmlns:thhttp://www.thymeleaf.org。2. 检查是否引入了spring-boot-starter-thymeleaf依赖。3. 检查application.yml中Thymeleaf缓存是否关闭开发时。确保Thymeleaf配置正确语法无误。插入中文到数据库变成乱码数据库、连接字符串或应用字符集不统一。1. 检查数据库、表、字段的字符集是否为utf8mb4。2. 检查JDBC连接URL是否包含参数?useUnicodetruecharacterEncodingutf8。3. 检查IDE和文件编码是否为UTF-8。统一设置为UTF-8推荐utf8mb4。MyBatis-Plus分页不生效未配置分页插件。检查是否在配置类中注入了PaginationInnerInterceptor。参考第4部分的MybatisPlusConfig配置类。Autowired依赖注入失败报Bean找不到Service或Mapper未被Spring扫描到。1. 检查启动类是否在根包下或其SpringBootApplication注解能扫描到组件。2. 检查Service类是否有ServiceMapper接口是否有Mapper或启动类上有MapperScan。确保组件注解正确包路径在扫描范围内。10. 项目扩展与进阶建议让你的作业脱颖而出完成基础CRUD只是第一步。要让你的项目在答辩或简历中更有分量可以考虑以下扩展方向引入权限控制Spring Security或Shiro实现管理员、教师、学生三种角色的登录和菜单权限控制。这是企业级应用的标配。前端与后端分离将Thymeleaf模板替换为Vue.js或React前端项目后端Controller提供纯JSON API使用RestController。这能体现你对现代架构的理解。添加数据校验在实体类字段上使用NotNull,Size等注解或在Controller方法参数中使用Valid注解进行后端校验提高系统健壮性。全局异常处理使用ControllerAdvice和ExceptionHandler定义全局异常处理器统一返回友好的JSON错误信息而不是暴露堆栈信息。接口文档化使用Swagger或Knife4j自动生成API文档方便前后端协作。缓存优化对不常变动的数据如课程列表使用Spring Cache如Redis进行缓存提升性能。日志记录使用SLF4J Logback记录详细的业务操作日志和异常日志。单元测试为Service层关键方法编写JUnit单元测试体现工程化思维。这个基于SpringBoot的学生成绩管理系统项目就像一副完整的“骨架”。本文为你详细讲解了每一块“骨骼”技术组件如何搭建、如何连接以及它们协同工作的原理。真正的学习价值在于你能否基于这副骨架填充“肌肉”业务逻辑和“血液”设计思想并最终让它“活”起来解决实际问题。建议你按照本文的步骤亲手搭建一遍。过程中遇到的每一个错误都是加深理解的机会。完成基础版本后尝试选择一个扩展方向进行实践。当你不仅能运行它还能向别人清晰地阐述为什么这么设计、如何优化时这个项目才真正成为了你的能力证明。