【Tilas|第六篇】班级管理实现

前言

前面写完部门管理、员工管理之后,这一篇继续往下走,重点来实现 day-11 的班级管理功能

需求:

  • 班级条件分页查询
  • 班级新增、修改、删除、详情查询

一、班级管理模块实现

1. 班级条件分页查询

功能需求

班级列表页需要支持:

  • 按班级名称模糊查询
  • 按开课时间筛选
  • 按结课时间筛选
  • 分页展示结果
  • 额外显示班主任名称和班级状态

1.0准备-pojo层

css 复制代码
public class studentQueryParam {
    //封装条件查询参数
    private Integer page=1;
    private Integer pageSize=10;
    private String name;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate beginDate;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate endDate;

    private Integer degree;   // 学历
    private Integer clazzId;  // 班级ID
}

需要什么参数是看前端和数据库传递过来了什么内容

css 复制代码
public class PageResult<T> {
    private Long total;
    private List<T> rows;
}
css 复制代码
这里依旧是用于封装分页结果的,所以不用写,直接调用我们之前的即可

1.1 Controller 层实现

java 复制代码
@GetMapping
public Result get(studentQueryParam studentQueryParam) {
    log.info("条件查询参数:{}", studentQueryParam);
    PageResult<Clazz> pageResult = clazzService.getbytime(studentQueryParam);
    return Result.success(pageResult);
}

文字说明

这一层的职责很简单,就是接收前端传过来的分页和查询条件,然后调用业务层,最后把结果统一包装成 Result 返回给前端。

这里传入的不是一个个零散参数,而是 studentQueryParam 这个参数对象,这样代码会更整洁。


1.2 Service 层实现

java 复制代码
@Override
public PageResult getbytime(studentQueryParam studentparam) {
    PageHelper.startPage(studentparam.getPage(), studentparam.getPageSize());
    List<Clazz> list = empMapper.getbyDate(studentparam);
    Page<Clazz> p = (Page<Clazz>) list;
    return new PageResult(p.getTotal(), p.getResult());
}

文字说明

业务层这里主要做了两件事:

  1. 通过 PageHelper.startPage(...) 开启分页
  2. 调用 Mapper 查询数据,并把结果封装成分页对象返回

这里依旧像我们之前一样,调用pagehelper来实现分页的功能实现


1.3 Mapper 层实现

xml 复制代码
<select id="getbyDate" resultType="com.heimait.pojo.Clazz">
    SELECT
        c.*,
        e.name masterName,
        CASE
            WHEN c.end_date > CURDATE() THEN '在读'
            WHEN c.end_date &lt;= CURDATE() THEN '已结课'
            ELSE '未开班'
        END status
    FROM clazz c
    LEFT JOIN emp e ON c.master_id = e.id
    <where>
        <if test="name != null and name != ''">
            AND c.name LIKE CONCAT('%', #{name}, '%')
        </if>
        <if test="beginDate != null">
            AND c.begin_date >= #{beginDate}
        </if>
        <if test="endDate != null">
            AND c.end_date &lt;= #{endDate}
        </if>
    </where>
    ORDER BY c.update_time DESC
</select>

文字说明

这里的 SQL 有几个关键点:

  • LEFT JOIN emp:把班主任姓名一起查出来
  • CASE WHEN:直接在 SQL 中计算班级状态
  • <where> + <if>:根据前端是否传值,动态拼接查询条件
  • ORDER BY c.update_time DESC:按修改时间倒序展示

因为这里用到模糊查询,所以我们用到where,if.

需求是显示三种开班状态,所以我们用case来判断


1.4 涉及知识点

1. PageHelper 分页插件

PageHelper.startPage(page, pageSize) 会在当前查询前生效,自动帮我们把普通查询变成分页查询。

2. 动态 SQL

MyBatis 中的 <if> 标签非常适合做条件查询。

谁有值就拼谁,没有值就不拼,避免手写大量字符串判断。

3. 左连接 LEFT JOIN

班级表中只存班主任 ID,不存班主任姓名。

所以查询时通过员工表补充 masterName,这就是关联查询的典型场景。

4. SQL 中计算业务字段

status 并不是数据库真实字段,而是查询时临时算出来的字段。

END:表示 CASE 表达式的结束

status:给这个 CASE 表达式起别名,结果集中的列名就是 status

这里补充一句:如果要完全严格实现"未开班、在读、已结课"三种状态,实际判断时最好同时结合 begin_dateend_date 两个字段。


2. 新增班级

功能需求

前端填写班级信息后,点击提交,将班级数据写入数据库。


2.1 Controller 层实现

java 复制代码
@PostMapping
public Result add(@RequestBody Clazz clazz) {
    log.info("添加班级参数:{}", clazz);
    clazzService.add(clazz);
    return Result.success(clazz);
}

2.2 Service 层实现

java 复制代码
@Override
public void add(Clazz clazz) {
    clazz.setCreateTime(LocalDateTime.now());
    clazz.setUpdateTime(LocalDateTime.now());
    empMapper.insert(clazz);
}

2.3 Mapper 层实现

xml 复制代码
<insert id="insert">
    INSERT INTO clazz (name, room,begin_date, end_date, master_id, subject,create_time, update_time)
    VALUES (#{name}, #{room}, #{beginDate}, #{endDate}, #{masterId}, #{subject}, now(), now())
</insert>

文字说明

新增班级时,Controller 接收前端传来的 JSON 数据,Service 层补齐创建时间和修改时间,最后 Mapper 执行插入。

这也是三层架构中很常见的一种分工方式:

  • Controller 只负责收参数
  • Service 负责补业务字段
  • Mapper 只管执行 SQL

涉及知识点

1. @RequestBody

用于接收前端传来的 JSON 请求体,并自动转换成 Clazz 对象。

2. 为什么时间字段放在 Service 层处理

因为时间字段属于业务规则的一部分。

如果写在 Controller 层,控制层就会参与业务;如果写在 Mapper 层,又会让 SQL 逻辑变重。

所以放在 Service 层最合适。


3. 根据 ID 查询班级详情

3.1 Controller 层实现

java 复制代码
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
    log.info("根据id查询班级信息:{}", id);
    Clazz clazz = clazzService.getById(id);
    return Result.success(clazz);
}

3.2 Service 层实现

java 复制代码
@Override
public Clazz getById(Integer id) {
    return empMapper.selectByKey(id);
}

3.3 Mapper 层实现

xml 复制代码
<select id="selectByKey" resultType="com.heimait.pojo.Clazz">
    SELECT *
    FROM clazz
    WHERE id = #{id}
</select>

文字说明

这个功能一般用于编辑回显。

前端点击"编辑"按钮后,会先根据班级 ID 查出当前班级的完整信息,然后回填到表单里。


涉及知识点

@PathVariable

@GetMapping("/{id}") 这种写法是 RESTful 风格中很常见的路径参数写法。

它表示从 URL 路径中提取参数,而不是从查询字符串中取值。


4. 修改班级

4.1 Controller 层实现

java 复制代码
@PutMapping
public Result update(@RequestBody Clazz clazz) {
    log.info("修改班级信息:{}", clazz);
    clazzService.update(clazz);
    return Result.success(clazz);
}

4.2 Service 层实现

java 复制代码
@Override
public void update(Clazz clazz) {
    clazz.setUpdateTime(LocalDateTime.now());
    empMapper.update(clazz);
}

4.3 Mapper 层实现

xml 复制代码
<update id="update">
    UPDATE clazz
    SET name = #{name},
        room = #{room},
        begin_date = #{beginDate},
        end_date = #{endDate},
        master_id = #{masterId},
        subject = #{subject},
        update_time = #{updateTime}
    WHERE id = #{id}
</update>

文字说明

修改和新增的写法其实很像,不同点主要在于:

  • 修改必须带 id
  • 新增要补创建时间和修改时间
  • 修改只需要更新 updateTime

5. 删除班级

功能需求

删除班级时,如果该班级下已经有关联学生,则不能直接删除。


5.1 Controller 层实现

把id传入

java 复制代码
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
    log.info("删除班级信息:{}", id);
    clazzService.delete(id);
    return Result.success();
}

5.2 Service 层实现

用主动抛异常形式实现不可删除id需求

java 复制代码
@Override
public void delete(Integer id) {
    Integer count = empMapper.checkStudentCount(id);
    if (count != null && count > 0) {
        throw new RuntimeException("对不起 该班级下有学生 不能直接删除");
    }
    empMapper.delete(id);
}

5.3 Mapper 层实现

xml 复制代码
<select id="checkStudentCount" resultType="java.lang.Integer">
    SELECT COUNT(*) FROM student WHERE clazz_id = #{clazzId}
</select>

<delete id="delete">
   delete from clazz where id = #{id}
</delete>

文字说明

这个功能不能只写一句 delete from clazz where id = #{id} 就结束。

因为班级和学生之间有关联关系,如果班级已经被学生引用,还直接删除,就会导致业务数据不一致。

所以这里先查数量:

  • 如果班级下有学生,抛出异常
  • 如果没有学生,再执行删除

涉及知识点

1. 业务删除校验

很多删除操作并不是"能删就删",而是要先判断关联数据是否存在。

这类校验通常应该写在 Service 层,而不是 Controller 层。

2. 自定义异常 / 全局异常处理

可以配合"自定义异常 + 全局异常处理器"实现。

这也是比较推荐的写法,因为这样可以把错误信息统一返回给前端,而不是让异常直接抛到页面。


6. 查询所有班级

6.1 Controller 层实现

java 复制代码
@GetMapping("/list")
public Result getAll() {
    log.info("查询所有班级信息");
    List<Clazz> clazzList = clazzService.getAll();
    return Result.success(clazzList);
}

6.2 Service 层实现

java 复制代码
@Override
public List<Clazz> getAll() {
    return empMapper.getAll();
}

6.3 Mapper 层实现

xml 复制代码
<select id="getAll" resultType="com.heimait.pojo.Clazz">
    SELECT * FROM clazz
</select>

总结

到这里,班级管理模块的核心接口基本就已经完成了,包括:

  • 班级条件分页查询
  • 新增班级
  • 根据 ID 查询班级详情
  • 修改班级信息
  • 删除班级
  • 查询所有班级

从三层架构的角度来看,这一部分已经把一个典型模块的开发流程完整走了一遍:

  • Controller 层负责接收请求和响应结果
  • Service 层负责处理业务逻辑和校验规则
  • Mapper 层负责执行数据库操作

而"查询所有班级"这个接口,其实也为后面的学员管理做好了铺垫。因为学员新增、学员修改时,都需要先拿到班级列表,用来做下拉选择。

我是新手程序猿乐锅。本次分享到此结束,感谢大家的观看与支持!如果本期内容对您有帮助,欢迎点赞、收藏,您的支持将是我持续创作的最大动力,谢谢!

相关推荐
吴声子夜歌1 小时前
Java——继承实现的基本原理
java·继承
Kiling_07041 小时前
Java集合进阶:Collection与List详解
java·windows·list
小新同学^O^1 小时前
简单学习 --> 数据加密
java·数据库·学习·数据加密
AOwhisky1 小时前
Docker 学习笔记:从生态系统到镜像构建
linux·运维·笔记·学习·docker·容器
XiYang-DING1 小时前
【Java】URL(Uniform Resource Locator)
java·开发语言
0xDevNull1 小时前
Java十道高频面试题
java·开发语言
Brilliantwxx1 小时前
【算法题】递归树+哈希表+分治异或+双指针
开发语言·c++·笔记·算法
aXin_ya1 小时前
微服务第十一天 MQ相关问题
java·微服务·架构
无限进步_1 小时前
【C++】智能指针族谱:auto_ptr、unique_ptr、shared_ptr
java·开发语言·数据结构·c++·算法