关于Tlias智能学习辅助系统班级学员管理和数据统计管理接口开发(java后端)的复盘,手把手教你根据接口文档规范开发接口(上)!

需求:班级管理

需要开发如下几个接口,且开发的时候建议按照如下顺序开发 :

准备工作

ClazzController控制层

import com.itheima.service.ClazzService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("/clazzs")
public class ClazzController {

    @Autowired
    private ClazzService clazzService;

 ClazzService业务接口层

package com.itheima.service;

import com.itheima.pojo.Clazz;
import com.itheima.pojo.ClazzQueryParam;
import com.itheima.pojo.PageResult;

import java.time.LocalDate;
import java.util.List;

public interface ClazzService {

 ClazzServiceImpl业务实现类

package com.itheima.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.exception.BusinessException;
import com.itheima.mapper.ClazzMapper;
import com.itheima.mapper.StudentMapper;
import com.itheima.pojo.Clazz;
import com.itheima.pojo.ClazzQueryParam;
import com.itheima.pojo.PageResult;
import com.itheima.service.ClazzService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

@Service
public class ClazzServiceImpl implements ClazzService {
    @Autowired
    private ClazzMapper clazzMapper;
    @Autowired
    private StudentMapper studentMapper;

记得添加注入翻转,控制依赖的注解,实现这个功能 

  1. 条件分页查询接口

参照接口文档 班级管理 -> 班级列表查询

注意:班级状态,显示为:未开班、已结课、在读中 这三种。

如果:

  • 当前时间 > 结课时间:状态未 已结课

  • 当前时间 < 开课时间:状态未 未开班

  • 否则,就是 在读中

  1. 班级列表查询

  1. 基本信息

请求路径:/clazzs

请求方式:GET

接口描述:该接口用于班级列表数据的条件分页查询

  1. 请求参数

参数格式:queryString

参数说明:

参数名称是否必须示例备注
name黄埔一期班级名称
begin2023/1/1范围匹配的开始时间(结课时间)
end2023/5/1范围匹配的结束时间(结课时间)
page1分页查询的页码,如果未指定,默认为1
pageSize10分页查询的每页记录数,如果未指定,默认为10

请求数据样例:/clazzs?name=java&begin=2023-01-01&end=2023-06-30&page=1&pageSize=5

  1. 响应数据

参数格式:application/json

参数说明:

名称类型是否必须备注其他信息
codenumber必须响应码, 1 成功 , 0 失败
msgstring非必须提示信息
dataobject必须返回的数据
|- totalnumber必须总记录数
|- rowsobject []必须数据列表item 类型: object
|- idnumber非必须id
|- namestring非必须班级名称
|- roomstring非必须班级教室
|- beginDatestring非必须开课时间
|- endDatestring非必须结课时间
|- masterIdnumber非必须班主任(员工ID)
|- masterNamestring非必须班主任姓名(员工姓名)
|- createTimestring非必须创建时间
|- updateTimestring非必须更新时间
|- statusstring非必须状态 (未开班、已开班、已结课)

响应数据样例:

{
  "code": 1,
  "msg": "success",
  "data": {
    "total": 6,
    "rows": [
      {
        "id": 7,
        "name": "黄埔四期",
        "room": "209",
        "beginDate": "2023-08-01",
        "endDate": "2024-02-15",
        "masterId": 7,
        "createTime": "2023-06-01T17:51:21",
        "updateTime": "2023-06-01T17:51:21",
        "masterName": "纪晓芙",
        "status": "已开班"
      },
      {
        "id": 6,
        "name": "JavaEE就业166期",
        "room": "105",
        "beginDate": "2023-07-20",
        "endDate": "2024-02-20",
        "masterId": 20,
        "createTime": "2023-06-01T17:46:10",
        "updateTime": "2023-06-01T17:46:10",
        "masterName": "陈友谅",
        "status": "未开班"
      }
    ]
  }
}

我们先将分页查询需要的对象单独封装到一个对象类中

ClazzQueryParam
package com.itheima.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;

import java.time.LocalDate;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ClazzQueryParam {
    private Integer page=1;
    private Integer pageSize=10;
    private String name;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate begin;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate end;
}

我们分页查询的几个范围和条件就是根据班级名称,起始时间,结束时间进行查询,日期则是按照年月日的格式去查询 ,实体类如上,接下来我们看接口

首先是Get方法,不需要额外写路径,

  • GET方法:数据在URL中,Spring自动绑定到对象属性

参数也不需要再去加注解

在响应数据样例中需要返回total和班级集合List,我们可以再把这两个封装到pageresult中

ClazzController
@GetMapping
    public Result page(ClazzQueryParam clazzQueryParam){
        log.info("分页查询,参数{}",clazzQueryParam);
        PageResult pageResult = clazzService.page(clazzQueryParam);
        return Result.success(pageResult);
    }

pageresult 

package com.itheima.pojo;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageResult<T> {
    private Long total;
    private List<T> rows;
}

 我们具体来看实现类中的方法

@Override
    public PageResult page(ClazzQueryParam clazzQueryParam) {
        // 1. 使用 PageHelper 设置分页参数(当前页码和每页大小)
        PageHelper.startPage(clazzQueryParam.getPage(), clazzQueryParam.getPageSize());

        // 2. 调用 Mapper 层的 list 方法,查询符合条件的班级列表
        //    查询结果是一个经过增强的 List,实际类型为 Page<Clazz>
        List<Clazz> dataList = clazzMapper.list(clazzQueryParam);

        // 3. 将查询结果强转为 Page 类型,以提取分页相关的元数据
        Page<Clazz> p = (Page<Clazz>) dataList;

        // 4. 封装分页结果并返回
        //    PageResult 包含总记录数(p.getTotal())和当前页的数据列表(p.getResult())
        return new PageResult(p.getTotal(), p.getResult());
    }

 由于 Page 类继承自 ArrayList 实现了 List 接口,所以从类型兼容性来看,PageList 的子类,可以安全向下转型,前提是确实使用了 PageHelper 且紧跟分页查询操作。

我们再来看mapper层的list方法是怎么实现的

我们在xml中配置mybatis完整动态sql查询

 <select id="list" resultType="com.itheima.pojo.Clazz">
        select
        c.*,
        e.name masterName,
        (case when begin_date > now() then '未开班'
        when now() > end_date then '已结课'
        else '在读中' end) status
        from clazz c
        left join emp e on c.master_id = e.id
        <where>
            <if test="name != null and name != ''">
                c.name like concat('%',#{name},'%')
            </if>
            <if test="begin != null and end != null">
                and c.end_date between #{begin} and #{end}
            </if>
        </where>
        order by c.update_time desc
    </select>
  • 如果 <where> 标签内的第一个条件成立,它会去掉条件前面的 AND 或 OR
  • 如果所有条件都不成立,它会完全忽略 WHERE 子句
  • concat() 是 SQL 函数,用于连接多个字符串,避免 SQL 注入攻击。直接拼接字符串(如 like '%'+name+'%')容易导致安全问题

  1. 查询所有员工接口

那其实,对于培训机构来说,班主任就是这个企业的员工。所以,班主任下拉列表中展示的就是所有的员工数据。

参照接口文档 员工管理 -> 查询全部员工

  1. 查询全部员工

  1. 基本信息

请求路径:/emps/list

请求方式:GET

接口描述:该接口用于查询全部员工信息

  1. 请求参数

  1. 响应数据

参数格式:application/json

参数说明:

名称类型是否必须备注
codenumber必须响应码, 1 成功 , 0 失败
msgstring非必须提示信息
dataobject[]必须返回的数据
|- idnumber必须id
|- usernamestring必须用户名
|- namestring必须姓名
|- passwordstring非必须密码
|- entryDatestring非必须入职日期
|- gendernumber非必须性别 , 1 男 ; 2 女
|- imagestring非必须图像
|- jobnumber非必须职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师
|- salarynumber非必须薪资
|- deptIdnumber非必须部门id
|- createTimestring非必须创建时间
|- updateTimestring非必须更新时间

响应数据样例:

{
  "code": 1,
  "msg": "success",
  "data": [
    {
      "id": 21,
      "username": "zcc",
      "password": "123456",
      "name": "周星驰",
      "gender": 1,
      "image": "https://web-65.oss-cn-beijing.aliyuncs.com/99c143e9-0241-41f3-bc55-dd5e4e0824f4.jpg",
      "job": 1,
      "salary": 8000,
      "entryDate": "2023-04-23",
      "deptId": 2,
      "createTime": "2023-05-26T17:25:01",
      "updateTime": "2023-06-04T19:25:15"
    },
    {
      "id": 6,
      "username": "xiaozhao",
      "password": "123456",
      "name": "小昭",
      "gender": 2,
      "image": "https://web-65.oss-cn-beijing.aliyuncs.com/da94dc38-f165-480c-b8b7-0b3f4bcd1602.jpg",
      "job": 3,
      "salary": 8000,
      "entryDate": "2013-09-05",
      "deptId": 1,
      "createTime": "2023-04-07T11:16:00",
      "updateTime": "2023-04-14T08:22:41"
    }
  ]
}

 来看控制层

/**
     * 查询所有的员工
     */
    @GetMapping("/list")
    public Result list(){
        log.info("查询所有的员工");
        List<Emp> list = empService.list();
        return Result.success(list);
    }

路径如上 ,不需要请求参数,所以不需要参数

返回的响应数据样例是集合,集合里面包含了每个员工的详细信息,所以我们用List<Emp>来储存返回信息

最后result需要响应结果

serviceImpl层

 @Override
    public List<Emp> list() {
        return empMapper.findAll();
    }

mapper层

 @Select("select * from emp")
    List<Emp> findAll();
  1. 新增班级信息接口

参照接口文档 班级管理 -> 添加班级

  1. 添加班级

  1. 基本信息

请求路径:/clazzs

请求方式:POST

接口描述:该接口用于添加班级信息

  1. 请求参数

参数格式:application/json

参数说明:

名称类型是否必须备注
namestring必须班级名称
roomstring必须班级教室
beginDatestring必须开课时间
endDatestring必须结课时间
masterIdnumber非必须班主任
subjectnumber必须学科, 1:java, 2:前端, 3:大数据, 4:Python, 5:Go, 6:嵌入式

请求数据样例:

{
  "name": "JavaEE就业166期",
  "room": "101",
  "beginDate": "2023-06-01",
  "endDate": "2024-01-25",
  "masterId": 7,
  "subject": 1
}

  1. 响应数据

参数格式:application/json

参数说明:

参数名类型是否必须备注
codenumber必须响应码,1 代表成功,0 代表失败
msgstring非必须提示信息
dataobject非必须返回的数据

响应数据样例:

{
    "code":1,
    "msg":"success",
    "data":null
}

 为Post请求,需要将请求数据封装到Clazz实体类中,所以要用@ResquestBody注解,响应数据的data为null,所以不需要将service层的处理方法返回给实体类

/**
     * 新增班级
     */
    @PostMapping
    public Result save(@RequestBody Clazz clazz){
        log.info("新增班级,数据:{}",clazz);
        clazzService.save(clazz);
        return Result.success();
    }

 注意涉及到新增或者修改的时候都要顺带修改创建时间和更新时间

@Override
    public void save(Clazz clazz) {
        clazz.setCreateTime(LocalDateTime.now());
        clazz.setUpdateTime(LocalDateTime.now());
        clazzMapper.insert(clazz);
    }

 在进行insert方法的时候,不需要去给id赋值,因为id是自增的,如下即可

 @Insert("insert into clazz VALUES (null,#{name},#{room},#{beginDate},#{endDate},#{masterId}, #{subject},#{createTime},#{updateTime})")
    void insert(Clazz clazz);
  1. 根据ID查询班级接口

参照接口文档 班级管理 -> 根据ID查询

  1. 根据ID查询

  1. 基本信息

请求路径:/clazzs/{id}

请求方式:GET

接口描述:该接口用于根据主键ID查询班级的信息

  1. 请求参数

参数格式:路径参数

参数说明:

参数名类型是否必须备注
idnumber必须班级ID

请求参数样例:/clazzs/8

  1. 响应数据

参数格式:application/json

参数说明:

名称类型是否必须备注
codenumber必须响应码, 1 成功 , 0 失败
msgstring非必须提示信息
dataobject必须返回的数据
|- idnumber必须id
|- namestring必须班级名称
|- roomstring必须班级教室
|- beginDatestring必须开课时间
|- endDatestring必须结课时间
|- masterIdnumber必须班主任(员工ID)
|- subjectnumber非必须学科, 1:java, 2:前端, 3:大数据, 4:Python, 5:Go, 6:嵌入式
|- createTimestring必须创建时间
|- updateTimestring必须更新时间

响应数据样例:

{
  "code": 1,
  "msg": "success",
  "data": {
    "id": 8,
    "name": "JavaEE就业166期",
    "room": "101",
    "beginDate": "2023-06-01",
    "endDate": "2024-01-25",
    "masterId": 7,
    "subject": 1,
    "createTime": "2023-06-04T17:37:45",
    "updateTime": "2023-06-04T17:37:45"
  }
}

 根据id查询,路径需要增加id,我们需要将路径中的id获取下来作为参数,需要用@PathVariable注解

/**
     * 根据id查询
     */
    @GetMapping("/{id}")
    public Result getInfo(@PathVariable Integer id){
        log.info("根据id查询班级:{}",id);
        Clazz clazz = clazzService.getInfo(id);
        return Result.success(clazz);
    }
 @Override
    public Clazz getInfo(Integer id) {
        return clazzMapper.getInfo(id);
    }

    @Select("select * from clazz where  id = #{id}")
    Clazz getInfo(Integer id);
  1. 修改班级信息接口

参照接口文档 班级管理 -> 修改班级

  1. 修改班级

  1. 基本信息

请求路径:/clazzs

请求方式:PUT

接口描述:该接口用于修改班级的数据信息

  1. 请求参数

参数格式:application/json

参数说明:

名称类型是否必须备注
idnumber必须id
namestring必须班级名称
roomstring必须班级教室
beginDatestring必须开课时间
endDatestring必须结课时间
masterIdnumber必须班主任ID(员工ID)
subjectnumber非必须学科, 1:java, 2:前端, 3:大数据, 4:Python, 5:Go, 6:嵌入式

请求数据样例:

{
  "id": 8,
  "name": "JavaEE就业166期",
  "room": "101",
  "beginDate": "2023-06-01",
  "endDate": "2024-01-25",
  "masterId": 7,
  "subject": 1
}
  1. 响应数据

参数格式:application/json

参数说明:

参数名类型是否必须备注
codenumber必须响应码,1 代表成功,0 代表失败
msgstring非必须提示信息
dataobject非必须返回的数据

响应数据样例:

{
    "code":1,
    "msg":"success",
    "data":null
}

/**
     * 更新班级信息
     */
    @PutMapping
    public Result update(@RequestBody Clazz clazz){
        log.info("更新班级信息:{}",clazz);
        clazzService.update(clazz);
        return Result.success();
    }

   @Override
    public void update(Clazz clazz) {
        clazz.setUpdateTime(LocalDateTime.now());
        clazzMapper.update(clazz);
    }

 在修改班级的功能中,我们需要通过动态sql进行mapper层中的数据处理,因为我们修改的数据可以是一个,几个或者全部,动态sql可以更好的处理这些情况

 <set>标签可以处理最后一个更新语句最后一个逗号的情况,代码如下

<!--动态更新班级信息-->
    <update id="update">
        update clazz
        <set>
            <if test="name != null and name != ''">
                name = #{name},
            </if>
            <if test="room != null and room != ''">
                room = #{room},
            </if>
            <if test="beginDate != null">
                begin_date = #{beginDate},
            </if>
            <if test="endDate != null">
                end_date = #{endDate},
            </if>
            <if test="masterId != null">
                master_id = #{masterId},
            </if>
            <if test="subject != null">
                subject = #{subject},
            </if>
            <if test="updateTime != null">
                update_time = #{updateTime}
            </if>
        </set>
        where id = #{id}
    </update>

注意如果我们需要查询回显,需要写一个查询全部班级的接口,不然无法将所有班级的信息显示在前端

博主因为这个调了一个小时,发现哪里都没问题才想到少写了这个接口

/**
     * 查询全部班级
     */
    @GetMapping("/list")
    public Result findAll(){
        List<Clazz> clazzList = clazzService.findAll();
        return Result.success(clazzList);
    }
  @Override
    public List<Clazz> findAll() {
        return clazzMapper.findAll();
    }

    @Select("select * from clazz")
    List<Clazz> findAll();
  1. 删除班级信息接口

参照接口文档 班级管理 -> 删除班级

注意:在页面原型中,要求如果该班级下关联的有学生,是不允许删除的,并提示错误信息:"对不起, 该班级下有学生, 不能直接删除"。 (提示:可以通过自定义异常 + 全局异常处理器实现)

  1. 删除班级

  1. 基本信息

请求路径:/clazzs/{id}

请求方式:DELETE

接口描述:该接口用于删除班级信息

  1. 请求参数

参数格式:路径参数

参数说明:

参数名类型示例是否必须备注
idnumber1必须班级的ID

请求参数样例:/clazzs/5

  1. 响应数据

参数格式:application/json

参数说明:

参数名类型是否必须备注
codenumber必须响应码,1 代表成功,0 代表失败
msgstring非必须提示信息
dataobject非必须返回的数据

响应数据样例:

{
    "code":1,
    "msg":"success",
    "data":null
}

 我们还是一步一步来看,从控制层

    /**
     * 根据id删除班级
     */
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id){
        log.info("根据id删除班级:{}",id);
        clazzService.deleteById(id);
        return Result.success();
    }

 因为需要查询班级下是否有学员,我们在开发的过程中可以先将这一部分留到学员管理开发的时候一起完成,这里因为是已经开发完的完整版本,我就不省略啦

   @Override
    public void deleteById(Integer id) {
        //1. 查询班级下是否有学员
        Integer count = studentMapper.countByClazzId(id);
        if(count > 0){
            throw new BusinessException("班级下有学员, 不能直接删除~");
        }
        clazzMapper.deleteById(id);
    }

然后在这里我们定义了一个 自定义异常 + 全局异常处理器

package com.itheima.exception;

public class BusinessException extends RuntimeException{
    public BusinessException(String message) {
        super(message);
    }
}

继承了RuntimeException并提供了一个接收错误消息的构造方法 

将其引入到全局异常处理器中

    /**
     * 声明异常处理的方法 - BusinessException
     */
    @ExceptionHandler
    public Result handleBuinessException(BusinessException businessException) {
        log.error("服务器异常", businessException);
        return Result.error(businessException.getMessage());
    }

    @Delete("delete from clazz where id = #{id}")
    void deleteById(Integer id);

到此,关于班级管理的增删改查功能,我们就已经全部实现了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值