stu01:老师接口实现

This commit is contained in:
awin-x 2025-12-14 20:48:45 +08:00
parent c2c9cc4e50
commit 9f388da5c7
11 changed files with 354 additions and 9 deletions

View File

@ -12,17 +12,17 @@
所有操作均基于下方《学生管理系统(测试用例适配)开发任务计划表》,每次会话需携带该计划表的最新版本(含已完成任务标注):
阶段 任务 ID 任务名称 核心目标 关键提示词 完成状态 备注(仅保留执行结果和后续影响)
1. 项目初始化与环境搭建 1.1 创建 SpringBoot 后端基础项目 搭建后端工程骨架,引入核心依赖 SpringBoot、MySQL 驱动、MyBatis、JWT、lombok 已完成 Spring Boot 3.4.12,包名 top.awinx.stu01Java 25依赖MyBatis-Plus 3.5.15、JJWT 0.13.0;启动方式:./mvnw spring-boot:run
1. 项目初始化与环境搭建 1.3 设计 MySQL 数据库表结构 设计核心实体表 用户表、学生表、教师表、课程表、学分表 已完成 数据库 stu01_dbMariaDB用户 stu01/123456核心表含 sys_user预置 admin/stu001/tea001密码 123456字段约束学号 / 教师编号 8 位纯数字,专业限 3 类,课程名 2-20 字符,分数 0-100
1. 项目初始化与环境搭建 1.3 设计 MySQL 数据库表结构 设计核心实体表 用户表、学生表、教师表、课程表、学分表 已完成 数据库 stu01_dbMariaDB用户 stu01/123456核心表结构更新teacher 表移除 major/title仅保留 tea_no/name/user_id外键关联 sys_user.id预置测试数据teacher 表 tea001 关联 user_id=3tea001
1. 项目初始化与环境搭建 1.4 后端基础配置 配置数据库、跨域、JWT 参数 application.yml、跨域、JWT 密钥 已完成 数据库连接正常;跨域允许 5173 端口(独立 CorsConfigJWT32 位密钥、1 小时过期context-path=/api端口 8080MyBatis-Plus 开启下划线转驼峰、SQL 日志
2. 用户登录模块开发 2.1 后端用户登录核心逻辑 实现账号密码校验 合法账号、缺少账号 / 密码、错误账号密码 已完成 接口POST /api/login校验逻辑空值 + 存在性 + 密码匹配返回格式Resultcode/message/data
2. 用户登录模块开发 2.2 JWT 令牌生成与校验 生成 token、校验 token、令牌刷新 合法 token、token 拦截、令牌刷新 已完成 接口:① POST /api/login返回 token+user② GET /api/login/refresh刷新 tokenJWT 拦截器放行登录 / 刷新接口,拦截其他 /api/**token 载荷含 user_type1 - 学生 / 2 - 教师 / 3 - 管理员)
2. 用户登录模块开发 2.4 登录异常处理 统一异常返回格式,明确异常信息 缺少账号 / 密码、错误账号密码、token 无效 / 过期 已完成 全局异常处理器捕获业务 / 参数 / 系统异常;返回统一 Result 格式:业务异常 code=400、系统异常 code=500支持空参数、账号密码错误、token 异常等场景,提示信息简洁
2. 用户登录模块开发 2.5 多用户登录性能基础支持 支持高并发请求 多用户登陆性能测试 已完成 依赖 Spring Boot 3.x 默认线程池
3. 学生信息模块开发 3.1 后端学生基础 CRUD 实现学生添加 / 查询接口(支持模糊查询) 学生添加、学生查询(学号 / 姓名 / 专业筛选) 已完成 1. 接口:① POST /api/student/add添加校验学号唯一② GET/POST/api/student/query查询学号精确、姓名 / 专业模糊2. 依赖 JWT 拦截器,需携带合法 token3. 返回格式统一为 Result兼容全局异常处理4. 支持组合条件筛选
3. 学生信息模块开发 3.2 学生添加参数校验 校验学号、专业合法性 缺少学号、不合法学号、非法专业 已完成 学号规则8 位纯数字、非空、唯一;专业限计算机 / 数学 / 英语;用 3.x 参数校验注解
3. 学生信息模块开发 3.3 学生查询参数校验 校验 ID 合法性、防 SQL 注入 合法 ID、非法 ID、SQL 注入拦截 未完成 防注入MyBatis-Plus 参数绑定ID 校验:非负整数 + 存在性
3. 学生信息模块开发 3.2 学生添加参数校验 校验学号、专业合法性 缺少学号、不合法学号、非法专业 已完成 学号规则8 位纯数字、非空、唯一;专业限计算机 / 数学 / 英语;用 3.x 参数校验注解;添加 spring-boot-starter-validation 依赖,修复 Long 类型 @Pattern 注解误用问题,校验正常触发
3. 学生信息模块开发 3.3 学生查询参数校验 校验 ID 合法性、防 SQL 注入 合法 ID、非法 ID、SQL 注入拦截 已完成 1. 跳过分组校验设计留作软件测试工程实践报告素材后续忽略2. 仅保留基础校验ID 非负整数 + 存在性、MyBatis-Plus 参数预编译防 SQL 注入3. 简化代码,无分组相关逻辑
3. 学生信息模块开发 3.5 学生并发测试基础支持 支持添加 / 查询接口并发请求 学生查询 / 添加并发测试 未完成 依赖 3.x 默认配置
4. 教师信息模块开发 4.1 后端教师基础 CRUD 实现教师添加 / 更新 / 删除接口 教师添加、更新、删除 未完成 接口路径POST /api/teacher/add、PUT /api/teacher/update、DELETE /api/teacher/delete
4. 教师信息模块开发 4.1 后端教师基础 CRUD 实现教师添加 / 更新 / 删除接口 教师添加、更新、删除 已完成 1. 适配新数据库结构teacher 表移除 major/title仅保留 tea_no/name/user_id外键关联 sys_user.id2. 校验逻辑:教师编号 8 位纯数字 + 唯一、姓名非空、关联 userId 存在且为教师类型user_type=23. 仅支持更新教师姓名4. 接口路径POST /api/teacher/add、PUT /api/teacher/update、DELETE /api/teacher/delete/{id}5. 依赖 JWT 拦截器,需携带合法 token
4. 教师信息模块开发 4.2 教师删除关联拦截 教师关联课程 / 学分时拦截删除 删除关联拦截 未完成 校验逻辑:查询 course 表关联关系,存在则拦截;可选 @Transactional 事务处理
4. 教师信息模块开发 4.3 教师查询防 SQL 注入 校验查询参数、防 SQL 注入 教师查询、SQL 注入拦截 未完成 接口:/api/teacher/query防注入MyBatis-Plus 参数绑定
4. 教师信息模块开发 4.5 教师查询并发基础支持 确保教师查询接口支持并发请求 老师查询接口并发测试 未完成 依赖 3.x 默认配置
@ -32,10 +32,5 @@
5. 课程与学分模块开发 5.5 课程查询并发基础支持 确保课程查询接口支持并发请求 课程查询并发测试 未完成 依赖 3.x 默认配置
6. 权限控制模块开发 6.1 JWT 权限标识 令牌中添加用户类型 访问权限 - 未登录、权限标识 已完成 用户类型1 - 学生、2 - 教师、3 - 管理员JWT 载荷已包含 user_type
6. 权限控制模块开发 6.2 后端接口权限拦截 拦截未登录请求、越权访问请求 越权访问 - 学生 - 老师、学生 - 管理员、老师 - 管理员 未完成 基于 JWT 的 user_type 判断权限;拦截器扩展:学生禁访 /api/teacher/、/api/admin/,教师禁访 /api/admin/**
7. 测试适配与代码精简 7.1 测试用例全覆盖核对 逐一核对测试用例,确保功能点无遗漏 用例全覆盖、功能校验 未完成 核对类别:登录 / 学生 / 教师 / 课程学分 / 权限 / 并发 / 注入;适配 3.x、MariaDB
7. 测试适配与代码精简 7.2 代码精简 移除冗余逻辑,仅保留测试必需功能 代码简洁、无冗余 未完成 删除冗余代码,简化逻辑;移除无用配置依赖;统一异常处理逻辑
7. 测试适配与代码精简 7.3 基础联调 确保后端接口通信正常,核心功能可运行 联调、接口通联 未完成 测试核心接口(登录、增删改查、权限、刷新);前后端跨域正常;数据库读写正常
三、执行反馈模块(每次会话必填)
问题解决核心是添加了一个springboot的关于validation的starter依赖。
确认3.2完成开始3.3

View File

@ -0,0 +1,56 @@
package top.awinx.stu01.controller;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.awinx.stu01.common.Result;
import top.awinx.stu01.dto.TeacherAddDTO;
import top.awinx.stu01.dto.TeacherUpdateDTO;
import top.awinx.stu01.entity.Teacher;
import top.awinx.stu01.service.TeacherService;
/**
* 教师CRUD控制器
*/
@RestController
@RequestMapping("/teacher")
public class TeacherController {
@Resource
private TeacherService teacherService;
/**
* 添加教师
* POST /api/teacher/add
*/
@PostMapping("/add")
public Result<Teacher> addTeacher(@RequestBody TeacherAddDTO addDTO) {
Teacher teacher = teacherService.addTeacher(addDTO);
return Result.success("添加教师成功", teacher);
}
/**
* 更新教师
* PUT /api/teacher/update
*/
@PutMapping("/update")
public Result<Boolean> updateTeacher(@RequestBody TeacherUpdateDTO updateDTO) {
boolean success = teacherService.updateTeacher(updateDTO);
return Result.success("更新教师成功", success);
}
/**
* 删除教师
* DELETE /api/teacher/delete/{id}
*/
@DeleteMapping("/delete/{id}")
public Result<Boolean> deleteTeacher(@PathVariable Long id) {
boolean success = teacherService.deleteTeacher(id);
return Result.success("删除教师成功", success);
}
}

View File

@ -0,0 +1,24 @@
package top.awinx.stu01.dto;
import lombok.Data;
/**
* 教师添加请求DTO适配新数据库结构
*/
@Data
public class TeacherAddDTO {
/**
* 教师编号8位纯数字
*/
private String teaNo;
/**
* 教师姓名非空
*/
private String name;
/**
* 关联用户ID外键关联sys_user.id非空且存在
*/
private Long userId;
}

View File

@ -0,0 +1,19 @@
package top.awinx.stu01.dto;
import lombok.Data;
/**
* 教师更新请求DTO仅支持更新姓名
*/
@Data
public class TeacherUpdateDTO {
/**
* 教师ID必传非空且存在
*/
private Long id;
/**
* 教师姓名可选非空
*/
private String name;
}

View File

@ -0,0 +1,36 @@
package top.awinx.stu01.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;
/**
* 课程实体类匹配stu01_db.course表结构用于教师删除关联校验
*/
@Data
@TableName("course")
public class Course {
/**
* 课程ID主键自增
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 课程名称2-20字符中文/数字/字母
*/
private String courseName;
/**
* 关联教师ID外键关联teacher.id
*/
private Long teaId;
/**
* 创建时间数据库默认CURRENT_TIMESTAMP
*/
private LocalDateTime createTime;
}

View File

@ -0,0 +1,41 @@
package top.awinx.stu01.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;
/**
* 教师实体类严格匹配stu01_db.teacher表结构
*/
@Data
@TableName("teacher")
public class Teacher {
/**
* 主键ID自增
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 教师编号8位纯数字唯一
*/
private String teaNo;
/**
* 教师姓名
*/
private String name;
/**
* 关联用户ID外键关联sys_user.id
*/
private Long userId;
/**
* 创建时间数据库默认CURRENT_TIMESTAMP
*/
private LocalDateTime createTime;
}

View File

@ -0,0 +1,12 @@
package top.awinx.stu01.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import top.awinx.stu01.entity.Course;
/**
* 课程Mapper仅用于查询教师关联的课程记录
*/
@Mapper
public interface CourseMapper extends BaseMapper<Course> {
}

View File

@ -0,0 +1,12 @@
package top.awinx.stu01.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import top.awinx.stu01.entity.Teacher;
/**
* 教师MapperMyBatis-Plus基础CRUD
*/
@Mapper
public interface TeacherMapper extends BaseMapper<Teacher> {
}

View File

@ -0,0 +1,26 @@
package top.awinx.stu01.service;
import com.baomidou.mybatisplus.extension.service.IService;
import top.awinx.stu01.dto.TeacherAddDTO;
import top.awinx.stu01.dto.TeacherUpdateDTO;
import top.awinx.stu01.entity.Teacher;
/**
* 教师Service接口
*/
public interface TeacherService extends IService<Teacher> {
/**
* 添加教师
*/
Teacher addTeacher(TeacherAddDTO addDTO);
/**
* 更新教师
*/
boolean updateTeacher(TeacherUpdateDTO updateDTO);
/**
* 删除教师
*/
boolean deleteTeacher(Long id);
}

View File

@ -0,0 +1,117 @@
package top.awinx.stu01.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import top.awinx.stu01.dto.TeacherAddDTO;
import top.awinx.stu01.dto.TeacherUpdateDTO;
import top.awinx.stu01.entity.Course;
import top.awinx.stu01.entity.SysUser;
import top.awinx.stu01.entity.Teacher;
import top.awinx.stu01.exception.BusinessException;
import top.awinx.stu01.mapper.CourseMapper;
import top.awinx.stu01.mapper.SysUserMapper;
import top.awinx.stu01.mapper.TeacherMapper;
import top.awinx.stu01.service.TeacherService;
import java.time.LocalDateTime;
/**
* 教师Service实现类新增删除关联拦截逻辑
*/
@Service
public class TeacherServiceImpl extends ServiceImpl<TeacherMapper, Teacher> implements TeacherService {
@Resource
private SysUserMapper sysUserMapper;
// 新增注入CourseMapper用于关联校验
@Resource
private CourseMapper courseMapper;
@Override
public Teacher addTeacher(TeacherAddDTO addDTO) {
// 1. 基础参数非空+格式校验
if (addDTO.getTeaNo() == null || !addDTO.getTeaNo().matches("^\\d{8}$")) {
throw new BusinessException("教师编号必须为8位纯数字");
}
if (addDTO.getName() == null || addDTO.getName().trim().isEmpty()) {
throw new BusinessException("教师姓名不能为空");
}
if (addDTO.getUserId() == null || addDTO.getUserId() < 0) {
throw new BusinessException("关联用户ID不能为空且为非负整数");
}
// 2. 教师编号唯一性校验
LambdaQueryWrapper<Teacher> teaWrapper = new LambdaQueryWrapper<>();
teaWrapper.eq(Teacher::getTeaNo, addDTO.getTeaNo());
if (this.count(teaWrapper) > 0) {
throw new BusinessException("教师编号" + addDTO.getTeaNo() + "已存在");
}
// 3. 关联用户ID存在性校验外键约束前置校验
SysUser sysUser = sysUserMapper.selectById(addDTO.getUserId());
if (sysUser == null) {
throw new BusinessException("关联的用户ID" + addDTO.getUserId() + "不存在sys_user表无此记录");
}
// 额外校验关联用户类型必须是教师user_type=2
if (sysUser.getUserType() != 2) {
throw new BusinessException("关联的用户ID" + addDTO.getUserId() + "不是教师类型user_type必须为2");
}
// 4. DTO转实体createTime由数据库默认值填充也可手动设置
Teacher teacher = new Teacher();
teacher.setTeaNo(addDTO.getTeaNo());
teacher.setName(addDTO.getName());
teacher.setUserId(addDTO.getUserId());
teacher.setCreateTime(LocalDateTime.now()); // 与数据库CURRENT_TIMESTAMP保持一致
this.save(teacher);
return teacher;
}
@Override
public boolean updateTeacher(TeacherUpdateDTO updateDTO) {
// 1. 校验教师ID存在性
if (updateDTO.getId() == null || !this.existsById(updateDTO.getId())) {
throw new BusinessException("教师ID不存在更新失败");
}
// 2. 校验更新的姓名非空
if (updateDTO.getName() != null && updateDTO.getName().trim().isEmpty()) {
throw new BusinessException("教师姓名不能为空");
}
// 3. 构建更新实体仅更新姓名
Teacher teacher = new Teacher();
teacher.setId(updateDTO.getId());
if (updateDTO.getName() != null) {
teacher.setName(updateDTO.getName());
}
return this.updateById(teacher);
}
@Override
public boolean deleteTeacher(Long id) {
// 1. 基础校验教师ID存在性
if (id == null || !this.existsById(id)) {
throw new BusinessException("教师ID不存在删除失败");
}
// 2. 新增关联课程校验核心拦截逻辑
LambdaQueryWrapper<Course> courseWrapper = new LambdaQueryWrapper<>();
courseWrapper.eq(Course::getTeaId, id); // 匹配course表中关联的教师ID
long relatedCourseCount = courseMapper.selectCount(courseWrapper);
if (relatedCourseCount > 0) {
throw new BusinessException("教师ID" + id + "关联了" + relatedCourseCount + "门课程,禁止删除");
}
// 3. 无关联课程时执行物理删除
return this.removeById(id);
}
private boolean existsById(Long id) {
return this.count(new LambdaQueryWrapper<Teacher>().eq(Teacher::getId, id)) > 0;
}
}

View File

@ -5,19 +5,26 @@
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/config/WebMvcConfig.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/controller/LoginController.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/controller/StudentController.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/controller/TeacherController.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/controller/TestController.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/dto/LoginRequest.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/dto/StudentAddDTO.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/dto/StudentQueryDTO.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/dto/TeacherAddDTO.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/dto/TeacherUpdateDTO.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/entity/Student.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/entity/SysUser.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/entity/Teacher.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/exception/BusinessException.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/exception/GlobalExceptionHandler.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/interceptor/JwtInterceptor.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/mapper/StudentMapper.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/mapper/SysUserMapper.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/mapper/TeacherMapper.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/service/StudentService.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/service/SysUserService.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/service/TeacherService.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/service/impl/StudentServiceImpl.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/service/impl/SysUserServiceImpl.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/service/impl/TeacherServiceImpl.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/utils/JwtUtil.java