【Tilas|第七篇】学员管理实现

前言

今天我们来学习学员管理模块的实现。

相比前面已经完成的班级管理,学员管理这一部分会更复杂一些。因为它不仅要实现基础的增删改查,还要完成条件分页查询、班级名称关联显示、违纪处理以及后续统计功能的预留。


一、学员管理模块实现

1. 学员条件分页查询

1.1 功能需求

学员列表页需要支持:

  • 按姓名模糊查询
  • 按学历筛选
  • 按班级筛选
  • 分页查询
  • 展示班级名称

1.2 Controller 层实现

java 复制代码
@GetMapping
public Result getStudent(studentQueryParam studentqueryparam){
    log.info("条件分页查询学生信息");
    PageResult<Student> pageResult = studentservice.getbytime(studentqueryparam);
    return Result.success(pageResult);
}

1.3 Service 层实现

java 复制代码
@Override
public PageResult<Student> getbytime(studentQueryParam studentqueryparam) {
    if (studentqueryparam.getPage() == null) {
        studentqueryparam.setPage(1);
    }
    if (studentqueryparam.getPageSize() == null) {
        studentqueryparam.setPageSize(10);
    }
    PageHelper.startPage(studentqueryparam.getPage(), studentqueryparam.getPageSize());
    List<Student> list = studentMapper.getbytime(studentqueryparam);
    Page<Student> p = (Page<Student>) list;
    return new PageResult<>(p.getTotal(), p.getResult());
}

1.4 Mapper 层实现

xml 复制代码
<select id="getbytime" resultType="com.heimait.pojo.Student">
    SELECT s.*, c.name clazzName
    FROM student s
    LEFT JOIN clazz c ON s.clazz_id = c.id
    ORDER BY s.violation_count DESC
    <where>
        <if test="name != null and name != ''">
            AND s.name LIKE CONCAT('%', #{name}, '%')
        </if>
        <if test="degree != null">
            AND s.degree = #{degree}
        </if>
        <if test="clazzId != null">
            AND s.clazz_id = #{clazzId}
        </if>
    </where>
</select>

1.5 文字说明

学员分页查询和班级分页查询的整体思路是一样的,只不过这次多了两个查询条件:

  • 学历
  • 班级 ID

同时通过 LEFT JOIN clazz 把班级名称 clazzName 一起查出来,方便前端直接展示。

1.6 涉及知识点

1. 查询参数对象复用

studentQueryParam 这个类同时承担了班级和学员的部分查询参数封装职责。

这种做法虽然能复用,但从规范角度来看,后续如果项目继续扩大,最好拆成更独立的参数类。

2. 关联查询补充显示字段

clazzName 和数据库表字段不是一一对应的,它是关联查询补出来的扩展字段。


2. 新增学员

2.1 Controller 层实现

java 复制代码
@PostMapping
public Result add(@RequestBody Student student){
    log.info("添加学生信息");
    studentservice.add(student);
    return Result.success();
}

2.2 Service 层实现

java 复制代码
@Override
public void add(Student student) {
    student.setCreateTime(LocalDateTime.now());
    student.setUpdateTime(LocalDateTime.now());

    if (student.getViolationCount() == null) {
        student.setViolationCount((short) 0);
    }
    if (student.getViolationScore() == null) {
        student.setViolationScore((short) 0);
    }
    if (student.getGender() == null) {
        student.setGender(0);
    }
    if (student.getIsCollege() == null) {
        student.setIsCollege(0);
    }
    if (student.getDegree() == null) {
        student.setDegree(0);
    }
    if (student.getClazzId() == null) {
        student.setClazzId(0);
    }
    studentMapper.insert(student);
}

2.3 Mapper 层实现

xml 复制代码
<insert id="insert">
    INSERT INTO student (name, no, gender, phone, id_card, is_college, address, degree, graduation_date,
                         clazz_id, violation_count, violation_score, create_time, update_time)
    VALUES (#{name}, #{no}, #{gender}, #{phone}, #{idCard}, #{isCollege}, #{address}, #{degree},
            #{graduationDate}, #{clazzId}, #{violationCount}, #{violationScore}, #{createTime}, #{updateTime})
</insert>

2.4 文字说明

新增学员时,这里除了补时间,还做了一件很重要的事:给很多字段设置默认值。

原因很简单,前端有些字段可能不传,如果后端不兜底,就可能导致数据库插入时报错。

我当时写的时候气炸了,为什么要传那么多,因为建立数据库表的时候规定了不能空

比如:

  • violationCount
  • violationScore

这些字段在业务上很明显应该默认是 0

2.5 涉及知识点

1. Service 层做默认值兜底

前端参数并不一定总是完整可靠,所以一些默认值处理放在 Service 层非常有必要。

2. 为什么不能完全依赖前端

因为前端校验是"用户体验层面"的校验,而后端校验才是"真正保证数据安全"的校验。


3. 根据 ID 查询学员详情

3.1 Controller 层实现

java 复制代码
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id){
    log.info("根据id查询学生信息");
    Student student = studentservice.getById(id);
    return Result.success(student);
}

3.2 Service 层实现

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

3.3 Mapper 层实现

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

3.4 文字说明

这个功能和班级详情查询类似,主要用于学员编辑前的数据回显。


4. 修改学员

4.1 Controller 层实现

java 复制代码
@PutMapping
public Result update(@RequestBody Student student){
    log.info("修改学生信息");
    studentservice.update(student);
    return Result.success();
}

4.2 Service 层实现

java 复制代码
@Override
public void update(Student student) {
    student.setUpdateTime(LocalDateTime.now());
    studentMapper.update(student);
}

4.3 Mapper 层实现

xml 复制代码
<update id="update">
    Update student
    set name=#{name}, no=#{no}, gender=#{gender}, phone=#{phone}, id_card=#{idCard},
        is_college=#{isCollege}, address=#{address}, degree=#{degree},
        graduation_date=#{graduationDate}, clazz_id=#{clazzId},
        violation_count=#{violationCount}, violation_score=#{violationScore},
        update_time=#{updateTime}
    where id=#{id}
</update>

4.4 文字说明

修改学员信息时,本质上还是标准的更新逻辑。

不过这里也能看出来,当前这个更新语句会把违纪次数和违纪扣分一起更新,所以前端在提交修改时要注意数据完整性。


5. 删除学员

5.1 Controller 层实现

java 复制代码
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id){
    log.info("删除学生信息");
    studentservice.delete(id);
    return Result.success();
}

5.2 Service 层实现

java 复制代码
@Override
public void delete(Integer id) {
    studentMapper.delete(id);
}

5.3 Mapper 层实现

xml 复制代码
<delete id="delete">
    DELETE FROM student WHERE id = #{id}
</delete>

5.4 文字说明

这个功能比较直接,因为删除学生不需要像删除班级那样做额外关联校验。


6. 学员违纪处理

6.1 功能需求

学员违纪处理一次时:

  • 违纪次数 +1
  • 违纪扣分 +前端输入分数

6.2 Controller 层实现

java 复制代码
@PutMapping("/violation/{id}/{score}")
public Result violation(@PathVariable Integer id,@PathVariable Integer score){
    log.info("违纪处理扣分");
    studentservice.violation(id,score);
    return Result.success();
}

6.3 Service 层实现

java 复制代码
@Override
public void violation(Integer id, Integer score) {
    Student student = studentMapper.selectByKey(id);
    if (student == null) {
        throw new RuntimeException("对不起 没有找到该学员");
    }
    student.setViolationCount((short) (student.getViolationCount() + 1));
    student.setViolationScore((short) (student.getViolationScore() + score));
    student.setUpdateTime(LocalDateTime.now());
    studentMapper.update(student);
}

6.4 Mapper 层实现

这里没有单独写新的 SQL,而是复用了原有的更新方法:

xml 复制代码
<update id="update">
    Update student
    set name=#{name}, no=#{no}, gender=#{gender}, phone=#{phone}, id_card=#{idCard},
        is_college=#{isCollege}, address=#{address}, degree=#{degree},
        graduation_date=#{graduationDate}, clazz_id=#{clazzId},
        violation_count=#{violationCount}, violation_score=#{violationScore},
        update_time=#{updateTime}
    where id=#{id}
</update>

6.5 文字说明

这个功能很值得单独拿出来讲,因为它已经不是简单 CRUD 了,而是一个标准的"业务状态更新"。

处理过程是:

  1. 先根据 ID 查询学生是否存在
  2. 存在则把违纪次数 +1
  3. 再把违纪分数累加
  4. 最后更新时间并写回数据库

6.6 涉及知识点

1. 业务型更新接口

并不是所有更新都是前端传一个完整对象,后端直接 update

像违纪处理这种功能,本质上是围绕业务规则做状态变更。

2. 先查再改

这种写法的好处是逻辑清晰,容易理解。

后续如果要进一步优化,也可以考虑直接写成 SQL 累加。


三、统计功能实现

ClazzMapper 中,还预留了两个统计查询,非常适合后续对接图表展示。


1. 按学历统计学员数量

1.1 Mapper 层实现

xml 复制代码
<select id="countstudentbydegree" resultType="java.util.Map">
    SELECT
        CASE degree
            WHEN 1 THEN '初中'
            WHEN 2 THEN '高中'
            WHEN 3 THEN '大专'
            WHEN 4 THEN '本科'
            WHEN 5 THEN '硕士'
            WHEN 6 THEN '博士'
            ELSE '其他'
        END name,
        COUNT(*) AS value
    FROM student
    GROUP BY degree
</select>

1.2 文字说明

这个 SQL 会把数据库中的学历编码,直接转换成前端更容易展示的中文名称,同时统计每种学历的人数。

这种结果特别适合拿去做饼图、柱状图。


2. 按班级统计学员数量

2.1 Mapper 层实现

xml 复制代码
<select id="countstudentbyclass" resultType="java.util.Map">
    SELECT c.name, COUNT(*) AS value
    FROM student
    LEFT JOIN clazz c ON student.clazz_id = c.id
    GROUP BY c.name
</select>

2.2 文字说明

这个统计接口主要用于查看每个班级有多少学员。

本质上就是一个分组统计查询。

2.3 涉及知识点

分组统计 GROUP BY

统计类接口中,GROUP BY 是非常高频的 SQL 语法。

它可以把多条明细数据聚合成前端图表需要的结果。


总结

这一篇博客重点围绕学员管理模块展开,完整实现了:

  • 学员条件分页查询
  • 新增学员
  • 根据 ID 查询学员详情
  • 修改学员
  • 删除学员
  • 学员违纪处理
  • 学员统计接口预留

和基础 CRUD 相比,学员管理模块已经更贴近真实业务开发。

因为它不仅仅是在做简单的数据维护,还加入了:

  • 条件筛选
  • 分页查询
  • 班级关联显示
  • 默认值兜底
  • 业务型更新
  • 分组统计

所以这一部分内容,既能帮助我们继续理解三层架构,也能让我们进一步熟悉真实项目中的业务处理方式。


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

相关推荐
ouliten1 小时前
C++笔记:Lambda表达式
c++·笔记
问心无愧05131 小时前
ctf show web 入门38
笔记
程序猿乐锅1 小时前
【Tilas|第六篇】班级管理实现
java·笔记·tlias
吴声子夜歌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·开发语言