管理系统-部门

YangeIT大约 30 分钟SpringBoot数据库MybatisSpringBoot

管理系统-部门

今日目标

  1. 完成部门通过id查询(回显)
  2. 完成部门修改
  3. 完成员工分页查询
  4. 完成员工分页查询之分页插件
  5. 完成条件查询(动态sql)

知识储备

  1. springboot项目参数接受
  2. mybatis集成
  3. sql语句的书写

1. 部门模块

1.1 修改部门

前言

对于任何业务的修改功能来说,一般都会分为两步进行:查询回显、修改数据。

image-20231130205835988

查询回显

需求分析

当我们点击 "编辑" 的时候,需要根据ID查询部门数据,然后用于页面回显展示。

image-20231130210023866
image-20231130210023866

明确了根据ID查询部门的需求之后,再来梳理一下实现该功能时,三层架构每一层的职责:

image-20231130210148744

了解了需求之后,我们再看看接口文档中,关于根据ID查询部门的接口的描述,然后根据接口文档进行服务端接口的开发 。

image-20231130210450314

代码操作

路径参数接收

/depts/1/depts/2 这种在url中传递的参数,我们称之为路径参数。 那么如何接收这样的路径参数呢 ?

路径参数:通过请求URL直接传递参数,使用{…}来标识该路径参数,需要使用 @PathVariable 获取路径参数。如下所示:

image-20231130210741252
image-20231130210741252
/**
* 根据ID查询部门数据
* @return
*/
@GetMapping("/{id}")
public Result getInfo(@PathVariable Integer id){
    System.out.println("根据ID查询部门数据: " + id);
    return Result.success();
}

思考

在url中是否可以携带多个路径参数呢 ,如:/depts/1/0 。是可以这么传递的,具体的接收方式如下:

@GetMapping("/depts/{id}/{sta}")
public Result getInfo(@PathVariable Integer id, @PathVariable Integer sta){
	//...
}

总结

课堂作业

  1. @RequestBody@RequestParam 以及@PathVariable 注解区别?🎤🎤

1.2 修改数据

前言

1. 需求分析

查询回显回来之后,就可以对部门的信息进行修改了,修改完毕之后,点击确定,此时,就需要根据ID修改部门的数据。

image-20231130212115531

了解了需求之后,我们再看看接口文档中,关于修改部门的接口的描述,然后根据接口文档进行服务端接口的开发 。

image-20231130212221771

2. 思路分析

参照接口文档,梳理三层架构每一层的职责:

image-20231130212248232

通过接口文档,我们可以看到前端传递的请求参数是json格式的请求参数,在Controller的方法中,我们可以通过 @RequestBody 注解来接收,并将其封装到一个对象中。

代码操作

1). Controller层

DeptController 中增加 update 方法,具体代码如下:

/**
 * 修改部门数据
 */
@PutMapping
public Result update(@RequestBody Dept dept){
    System.out.println("修改部门数据: " + dept);
    deptService.update(dept);
    return Result.success();
}

2). Service层

DeptServiceImpl 中增加 update 方法。 由于是修改操作,每一次修改数据,都需要更新updateTime。所以,具体代码如下:

@Override
public void update(Dept dept) {
    dept.setUpdateTime(LocalDateTime.now());
    deptMapper.update(dept);
}

3). Mapper层

DeptMapper 中增加 update 方法,具体代码如下:

/**
 * 根据ID更新部门数据
 */
@Update("update dept set name = #{name}, update_time = #{updateTime} where id = #{id}")
void update(Dept dept);

代码编写完毕之后,我们就可以启动服务,进行测试了。

image-20231130212620460
image-20231130212620460

修改完成之后,我们可以看到最新的数据,如下:

image-20231130212658555
image-20231130212658555

1.3 功能优化

功能优化

@RequestMapping

到此呢,关于基本的部门的增删改查功能,我们已经实现了。 我们会发现,我们在 DeptController 中所定义的方法,所有的请求路径,都是 /depts 开头的,只要操作的是部门数据,请求路径都是 /depts 开头。

那么这个时候,我们其实是可以把这个公共的路径 /depts 抽取到类上的,那在各个方法上,就可以省略了这个 /depts 路径。 代码如下:

image-20231130213238682
image-20231130213238682

一个完整的请求路径,应该是类上的 @RequestMapping 的value属性 + 方法上的 @RequestMapping的value属性。

2. 日志技术

日志技术

什么时日志?

日志就好比生活中的日记,可以随时随地记录你生活中的点点滴滴。

程序中的日志,是用来记录应用程序的运行信息、状态信息、错误信息的。

  • 为什么要在程序中记录日志呢?

    • 便于追踪应用程序中的数据信息、程序的执行过程。
    • 便于对应用程序的性能进行优化。
    • 便于应用程序出现问题之后,排查问题,解决问题。
    • 便于监控系统的运行状态。
    • ... ...
  • 之前我们编写程序时,也可以通过 System.out.println(...) 来输出日志,为什么我们还要学习单独的日志技术呢?

    这是因为,如果通过 System.out.println(...) 来记录日志,会存在以下几点问题:

    • 硬编码。所有的记录日志的代码,都是硬编码,没有办法做到灵活控制,要想不输出这个日志了,只能删除掉记录日志的代码。
    • 只能输出日志到控制台。
    • 不便于程序的扩展、维护。

所以,在现在的项目开发中,我们一般都会使用专业的日志框架,来解决这些问题。

代码操作

Slf4j(酸辣粉使用教程)

几个常用的 lombok 注解:

  1. @Data:注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法
  2. @Setter:注解在属性上;为属性提供 setting 方法
  3. @Getter:注解在属性上;为属性提供 getting 方法
  4. @SneakyThrows:无需在签名处显式抛出异常
  5. @Log4j注解在类上;为类提供一个 属性名为log 的 log4j 日志对像,用作日志输出的,一般会在项目每个类的开头加入该注解
  6. @Slf4j: 同上
  7. @NoArgsConstructor:注解在类上;为类提供一个无参的构造方法
  8. @AllArgsConstructor:注解在类上;为类提供一个全参的构造方法

为什么使用@Slf4j?

为了能够少写两行代码,不用每次都在类的最前边写上: private static final Logger logger = LoggerFactory.getLogger(this.XXX.class);

使用步骤:

1. 在springboot项目下的pom.xml 导入下列依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.28</version>
</dependency>

2. 在类名上加上注解 @Slf4j

@SpringBootTest
@Slf4j
public class Slf4jTest {
    @Test
    public void test(){
        log.info("测试日志info");
        log.warn("测试日志warn");
        log.error("测试日志error");
        log.debug("测试日志debug");
        log.trace("测试日志trace");
    }
}

运行结果:

2024-04-15 21:26:02.557  INFO 21708 --- [           main] cn.yangeit.Slf4jTest                     : 测试日志info
2024-04-15 21:26:02.557  WARN 21708 --- [           main] cn.yangeit.Slf4jTest                     : 测试日志warn
2024-04-15 21:26:02.557 ERROR 21708 --- [           main] cn.yangeit.Slf4jTest                     : 测试日志error

3. 占位符 {} 非常好用

//占位符:日志输出中{}很好用
@Test
public void test2(){
    log.info("测试日志info:{}","yangeit");
    log.warn("测试日志warn:{},{}",1,6);
}

运行结果: image

3. 员工模块

3.1 员工列表查询(单表版本)

员工列表查询

那接下来,我们要来完成的是员工列表的查询功能实现。 具体的需求如下:

image-20231203124813695

在查询员工列表数据时,既要考虑搜索栏中的查询条件,还要考虑对查询的结果进行分页处理。

在查询员工列表数据时,既需要查询 员工的基本信息,还需要查询员工所属的部门名称,所以这里呢,会涉及到多表查询的操作。本章节,只进行单表操作!!

那么接下来,我们在实现这个功能时,将会分为三个部分来逐一实现:

  • 基本查询
  • 分页查询
  • 条件分页查询

代码操作

环境准备

1). 准备数据库表 emp(员工表) emp_expr(员工工作经历表)

-- 先删除这个2个表
drop table if exists emp;
drop table if exists emp_expr;

-- 员工表
create table emp(
                    id int unsigned primary key auto_increment comment 'ID,主键',
                    username varchar(20) not null unique comment '用户名',
                    password varchar(50) default '123456' comment '密码',
                    name varchar(10) not null comment '姓名',
                    gender tinyint unsigned not null comment '性别, 1:男, 2:女',
                    phone char(11) not null unique comment '手机号',
                    job tinyint unsigned comment '职位, 1 班主任, 2 讲师 , 3 学工主管, 4 教研主管, 5 咨询师',
                    salary int unsigned comment '薪资',
                    image varchar(300) comment '头像',
                    entry_date date comment '入职日期',
                    dept_id int unsigned comment '部门ID',
                    create_time datetime comment '创建时间',
                    update_time datetime comment '修改时间'
) comment '员工表';


INSERT INTO emp VALUES
                    (1,'shinaian','123456','施耐庵',1,'13309090001',4,15000,'5.png','2000-01-01',2,'2023-10-20 16:35:33','2023-11-16 16:11:26'),
                    (2,'songjiang','123456','宋江',1,'13309090002',2,8600,'01.png','2015-01-01',2,'2023-10-20 16:35:33','2023-10-20 16:35:37'),
                    (3,'lujunyi','123456','卢俊义',1,'13309090003',2,8900,'01.png','2008-05-01',2,'2023-10-20 16:35:33','2023-10-20 16:35:39'),
                    (4,'wuyong','123456','吴用',1,'13309090004',2,9200,'01.png','2007-01-01',2,'2023-10-20 16:35:33','2023-10-20 16:35:41'),
                    (5,'gongsunsheng','123456','公孙胜',1,'13309090005',2,9500,'01.png','2012-12-05',2,'2023-10-20 16:35:33','2023-10-20 16:35:43'),
                    (6,'huosanniang','123456','扈三娘',2,'13309090006',3,6500,'01.png','2013-09-05',1,'2023-10-20 16:35:33','2023-10-20 16:35:45'),
                    (7,'chaijin','123456','柴进',1,'13309090007',1,4700,'01.png','2005-08-01',1,'2023-10-20 16:35:33','2023-10-20 16:35:47'),
                    (8,'likui','123456','李逵',1,'13309090008',1,4800,'01.png','2014-11-09',1,'2023-10-20 16:35:33','2023-10-20 16:35:49'),
                    (9,'wusong','123456','武松',1,'13309090009',1,4900,'01.png','2011-03-11',1,'2023-10-20 16:35:33','2023-10-20 16:35:51'),
                    (10,'linchong','123456','林冲',1,'13309090010',1,5000,'01.png','2013-09-05',1,'2023-10-20 16:35:33','2023-10-20 16:35:53'),
                    (11,'huyanzhuo','123456','呼延灼',1,'13309090011',2,9700,'01.png','2007-02-01',2,'2023-10-20 16:35:33','2023-10-20 16:35:55'),
                    (12,'xiaoliguang','123456','小李广',1,'13309090012',2,10000,'01.png','2008-08-18',2,'2023-10-20 16:35:33','2023-10-20 16:35:57'),
                    (13,'yangzhi','123456','杨志',1,'13309090013',1,5300,'01.png','2012-11-01',1,'2023-10-20 16:35:33','2023-10-20 16:35:59'),
                    (14,'shijin','123456','史进',1,'13309090014',2,10600,'01.png','2002-08-01',2,'2023-10-20 16:35:33','2023-10-20 16:36:01'),
                    (15,'sunerniang','123456','孙二娘',2,'13309090015',2,10900,'01.png','2011-05-01',2,'2023-10-20 16:35:33','2023-10-20 16:36:03'),
                    (16,'luzhishen','123456','鲁智深',1,'13309090016',2,9600,'01.png','2010-01-01',2,'2023-10-20 16:35:33','2023-10-20 16:36:05'),
                    (17,'liying','12345678','李应',1,'13309090017',1,5800,'01.png','2015-03-21',1,'2023-10-20 16:35:33','2023-10-20 16:36:07'),
                    (18,'shiqian','123456','时迁',1,'13309090018',2,10200,'01.png','2015-01-01',2,'2023-10-20 16:35:33','2023-10-20 16:36:09'),
                    (19,'gudasao','123456','顾大嫂',2,'13309090019',2,10500,'01.png','2008-01-01',2,'2023-10-20 16:35:33','2023-10-20 16:36:11'),
                    (20,'ruanxiaoer','123456','阮小二',1,'13309090020',2,10800,'01.png','2018-01-01',2,'2023-10-20 16:35:33','2023-10-20 16:36:13'),
                    (21,'ruanxiaowu','123456','阮小五',1,'13309090021',5,5200,'01.png','2015-01-01',3,'2023-10-20 16:35:33','2023-10-20 16:36:15'),
                    (22,'ruanxiaoqi','123456','阮小七',1,'13309090022',5,5500,'01.png','2016-01-01',3,'2023-10-20 16:35:33','2023-10-20 16:36:17'),
                    (23,'ruanji','123456','阮籍',1,'13309090023',5,5800,'01.png','2012-01-01',3,'2023-10-20 16:35:33','2023-10-20 16:36:19'),
                    (24,'tongwei','123456','童威',1,'13309090024',5,5000,'01.png','2006-01-01',3,'2023-10-20 16:35:33','2023-10-20 16:36:21'),
                    (25,'tongmeng','123456','童猛',1,'13309090025',5,4800,'01.png','2002-01-01',3,'2023-10-20 16:35:33','2023-10-20 16:36:23'),
                    (26,'yanshun','123456','燕顺',1,'13309090026',5,5400,'01.png','2011-01-01',3,'2023-10-20 16:35:33','2023-11-08 22:12:46'),
                    (27,'lijun','123456','李俊',1,'13309090027',2,6600,'8.png','2004-01-01',2,'2023-10-20 16:35:33','2023-11-16 17:56:59'),
                    (28,'lizhong','123456','李忠',1,'13309090028',5,5000,'6.png','2007-01-01',3,'2023-10-20 16:35:33','2023-11-17 16:34:22'),
                    (30,'liyun','123456','李云',1,'13309090030',NULL,NULL,'01.png','2020-03-01',NULL,'2023-10-20 16:35:33','2023-10-20 16:36:31'),
                    (36,'linghuchong','123456','令狐冲',1,'18809091212',2,6800,'1.png','2023-10-19',2,'2023-10-20 20:44:54','2023-11-09 09:41:04');



-- 员工工作经历信息
create table emp_expr(
                         id int unsigned primary key auto_increment comment 'ID, 主键',
                         emp_id int unsigned comment '员工ID',
                         begin date comment '开始时间',
                         end  date comment '结束时间',
                         company varchar(50) comment '公司名称',
                         job varchar(50) comment '职位'
)comment '工作经历';

2). 准备与表结构对应的实体类 (资料中提供了, 直接引入到项目中)

/**
 * 员工信息
 */
@Data
public class Emp {
    private Integer id; //ID,主键
    private String username; //用户名
    private String password; //密码
    private String name; //姓名
    private Integer gender; //性别, 1:男, 2:女
    private String phone; //手机号
    private Integer job; //职位, 1:班主任,2:讲师,3:学工主管,4:教研主管,5:咨询师
    private Integer salary; //薪资
    private String image; //头像
    private LocalDate entryDate; //入职日期
    private Integer deptId; //关联的部门ID
    private LocalDateTime createTime; //创建时间
    private LocalDateTime updateTime; //修改时间

    //封装部门名称数
    private String deptName; //部门名称
}
/**
 * 工作经历
 */
@Data
public class EmpExpr {
    private Integer id; //ID
    private Integer empId; //员工ID
    private LocalDate begin; //开始时间
    private LocalDate end; //结束时间
    private String company; //公司名称
    private String job; //职位
}
image
image

3.2 员工分页查询(单表版本)

前言

需求分析

上述我们在Mapper接口中定义了接口方法,完成了查询所有员工及其部门名称的功能,是将数据库中所有的数据查询出来了。 试想如果数据库中的数据有很多(假设有几千几万条)的时候,将数据全部展示出来肯定不现实,那如何解决这个问题呢?

使用分页解决这个问题。每次只展示一页的数据,比如:一页展示10条数据,如果还想看其他的数据,可以通过点击页码进行查询。

而在员工管理的需求中,就要求我们进行分页查询,展示出对应的数据。 具体的页面原型如下:

image-20231203153042186

要想从数据库中进行分页查询,我们要使用LIMIT关键字,格式为:limit 开始索引 每页显示的条数

1). 查询第1页数据的SQL语句是:

select * from emp  limit 0,10;

2). 查询第2页数据的SQL语句是:

select * from emp  limit 10,10;

3). 查询第3页的数据的SQL语句是:

select * from emp  limit 20,10;

观察以上SQL语句,发现: 开始索引一直在改变 , 每页显示条数是固定的

开始索引的计算公式: 开始索引 = (当前页码 - 1) * 每页显示条数

我们继续基于页面原型,继续分析,得出以下结论:

  1. 前端在请求服务端时,传递的参数
    • 当前页码 page
    • 每页显示条数 pageSize
  2. 后端需要响应什么数据给前端
    • 所查询到的数据列表(存储到List 集合中)
    • 总记录数
image-20231203153321353

后台给前端返回的数据包含:List集合(数据列表)、total(总记录数)

而这两部分我们通常封装到PageBean对象中,并将该对象转换为json格式的数据响应回给浏览器。

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean {
	private Long total; //总记录数
	private List rows; //当前页数据列表
}

代码操作

接口文旦

员工列表查询

  • 基本信息

    请求路径:/emps
    请求方式:GET
    接口描述:该接口用于员工列表数据的条件分页查询
    
  • 请求参数

    • 参数格式:queryString
    • 参数说明:
    参数名称是否必须示例备注
    name姓名
    gender1性别 , 1 男 , 2 女
    begin2010-01-01范围匹配的开始时间(入职日期)
    end2020-01-01范围匹配的结束时间(入职日期)
    page1分页查询的页码,如果未指定,默认为1
    pageSize10分页查询的每页记录数,如果未指定,默认为10
    • 请求数据样例:
    /emps?name=&gender=1&begin=2007-09-01&end=2022-09-01&page=1&pageSize=10
    
  • 响应数据

    参数格式:application/json

    参数说明:

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

    响应数据样例:

    {
      "code": 1,
      "msg": "success",
      "data": {
        "total": 2,
        "rows": [
           {
            "id": 1,
            "username": "jinyong",
            "password": "123456",
            "name": "金庸",
            "gender": 1,
            "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-02-00-27-53B.jpg",
            "job": 2,
            "salary": 8000,
            "entryDate": "2015-01-01",
            "deptId": 2,
            "deptName": "教研部",
            "createTime": "2022-09-01T23:06:30",
            "updateTime": "2022-09-02T00:29:04"
          },
          {
            "id": 2,
            "username": "zhangwuji",
            "password": "123456",
            "name": "张无忌",
            "gender": 1,
            "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-02-00-27-53B.jpg",
            "job": 2,
            "salary": 6000,
            "entryDate": "2015-01-01",
            "deptId": 2,
            "deptName": "教研部",
            "createTime": "2022-09-01T23:06:30",
            "updateTime": "2022-09-02T00:29:04"
          }
        ]
      }
    }
    






     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     



目前我们只考虑分页查询,先不考虑查询条件,而上述的接口文档中,与分页查询相关的参数就两个,一个是page,一个是pageSize。


思路分析image-20231203153628217

代码实现:

通过查看接口文档:员工列表查询

请求路径:/emps

请求方式:GET

请求参数:跟随在请求路径后的参数字符串。 例:/emps?page=1&pageSize=10

响应数据:json格式

1). EmpController

@Slf4j
@RequestMapping("/emps")
@RestController
public class EmpController {

    @Autowired
    private EmpService empService;

    @GetMapping
    public Result page(@RequestParam(defaultValue = "1") Integer page ,
                       @RequestParam(defaultValue = "10") Integer pageSize){
        log.info("查询员工信息, page={}, pageSize={}", page, pageSize);
        PageBean pageBean = empService.page(page, pageSize);
        return Result.success(pageBean);
    }

}

@RequestParam(defaultValue="默认值") //设置请求参数默认值

3.3 员工分页查询之分页插件

分页插件

前面我们已经完了基础的分页查询,大家会发现:分页查询功能编写起来比较繁琐。 而分页查询的功能是非常常见的 ,我们查询员工信息需要分页查询,将来在做其他项目时,查询用户信息、订单信息、商品信息等等都是需要进行分页查询的。

分页查询的思路、步骤是比较固定的。 在Mapper接口中定义两个方法执行两条不同的SQL语句:

  1. 查询总记录数
  2. 指定页码的数据列表

在Service当中,调用Mapper接口的两个方法,分别获取:总记录数、查询结果列表,然后在将获取的数据结果封装到PageBean对象中。

大家思考下 :在未来开发其他项目,只要涉及到分页查询功能(例:订单、用户、支付、商品),都必须按照以上操作完成功能开发

结论:原始方式的分页查询,存在着"步骤固定"、"代码频繁"的问题

解决方案 :可以使用一些现成的分页插件完成。对于Mybatis来讲现在最主流的就是PageHelper

PageHelper是第三方提供的Mybatis框架中的一款功能强大、方便易用的分页插件,支持任何形式的单标、多表的分页查询。

官网:https://pagehelper.github.io/open in new window

那接下来,我们可以对比一下,使用PageHelper分页插件进行分页 与 原始方式进行分页代码实现的上的差别。

image-20231203155640765
  • Mapper接口层:
    • 原始的分页查询功能中,我们需要在Mapper接口中定义两条SQL语句。
    • PageHelper实现分页查询之后,只需要编写一条SQL语句,而且不需要考虑分页操作,就是一条正常的查询语句。
  • Service层:
    • 需要根据页码、每页展示记录数,手动的计算起始索引。
    • 无需手动计算起始索引,直接告诉PageHelper需要查询那一页的数据,每页展示多少条记录即可。

代码操作

当使用了PageHelper分页插件进行分页,就无需再Mapper中进行手动分页了。 在Mapper中我们只需要进行正常的列表查询即可。在Service层中,调用Mapper的方法之前设置分页参数,在调用Mapper方法执行查询之后,解析分页结果,并将结果封装到PageBean对象中返回。

1、在pom.xml引入依赖

<!--分页插件PageHelper-->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.4.7</version>
</dependency>

2、EmpMapper

/**
 * 查询所有的员工及其对应的部门名称
 */
@Select("select *from emp")
public List<Emp> list();

3、EmpServiceImpl

@Override
public PageBean page(Integer page, Integer pageSize) {
    //1. 设置分页参数
    PageHelper.startPage(page,pageSize);

    //2. 执行查询
    List<Emp> empList = empMapper.list();
    //将list转成分页插件中的Page  因为Page对象中有很多属性(总条目数,当前数据集)
    Page<Emp> p = (Page<Emp>) empList;

    //3. 封装结果
    return new PageBean(p.getTotal(), p.getResult());
}
测试

功能开发完成后,我们重启项目工程,打开Apifox,发起GET请求,访问 :http://localhost:8080/emps?page=1&pageSize=5open in new window

image-20231203160448506
image-20231203160448506

我们可以看到数据可以正常查询返回,是可以正常实现分页查询的。

3.4 员工分页条件查询(单表版本)

员工分页条件查询

上述代码,完成了分页查询,主要收获:

  1. 定义了PageBean,封装了前端的需要的结果(总条目数,当前页的数据集 )
  2. 熟悉了根据接口开发的,开发流程:接口文档---> controller-->service-->mapper-->sql-->apifox测试--->前端页面测试
  3. 知悉一个Service方法,可以调用多个Mapper方法,且分页查询需要执行2条语句(聚合函数,分页查询)

但是存在如下问题:

  1. 查询列表中,没有部门数据涉及到多表查询,后期在讲解
  2. 只能分页,不能条件查询
image
image

思路分析: 👇

我们看到页面原型及需求中描述,搜索栏的搜索条件有三个,分别是:

  • 姓名:模糊匹配
  • 性别:精确匹配
  • 入职日期:范围匹配
select e.* from emp e
where 
  e.name like concat('%','张','%')   -- 条件1:根据姓名模糊匹配
  and e.gender = 1                   -- 条件2:根据性别精确匹配
  and e.entry_date = between '2000-01-01' and '2010-01-01'  -- 条件3:根据入职日期范围匹配
order by update_time desc;

而且上述的三个条件,都是可以传递,也可以不传递的,也就是动态的

1). 如果用户仅输入了姓名,则SQL为:

select e.* from emp as e where e.name like ? 

2). 如果用户仅选择了性别,则SQL为:

select e.* from emp as e  where e.gender = ?

3). 如果用户输入了姓名 和 性别 , 则SQL为:

select e.* from emp as e  where e.name like ? and e.gender = ?

我们需要使用前面学习的Mybatis中的动态SQL 。

思路分析:

image-20231203162310879

接口文档

  • 通过查看接口文档:员工列表查询
  • 请求路径:/emps
  • 请求方式:GET
  • 请求参数
参数名称是否必须示例备注
name姓名
gender1性别 , 1 男 , 2 女
begin2010-01-01范围匹配的开始时间(入职日期)
end2020-01-01范围匹配的结束时间(入职日期)
page 1分页查询的页码,如果未指定,默认为1
pageSize 10分页查询的每页记录数,如果未指定,默认为10

在原有分页查询的代码基础上进行改造。

代码操作

1. Controller

方式一:在Controller方法中通过多个方法形参,依次接收这几个参数保守者,可以用这个,方便理解

@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {

    @Autowired
    private EmpService empService;

    @GetMapping
    public Result page(@RequestParam(defaultValue = "1") Integer page,
                       @RequestParam(defaultValue = "2") Integer pageSize,
                       String name, Integer gender,
                       @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
                       @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
        log.info("查询请求参数: {}, {}, {}, {}, {}, {}", page, pageSize, name, gender, begin, end);
        PageBean pageBean = null;  //empService.page(page, pageSize);
        return Result.success(pageBean);
    }
}

场景:如果参数个数比较少,建议直接接收即可。 如果参数个数比较多,这种接收方式不便于维护管理。

方式二:在Controller方法中通过实体对象封装多个参数。(实体属性与请求参数名保持一致)

1). 定义实体类

@Data
public class EmpQueryParam {

    private Integer page = 1; //页码
    private Integer pageSize = 10; //每页展示记录数
    private String name; //姓名
    private Integer gender; //性别
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate begin; //入职开始时间
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate end; //入职结束时间

}

2). Controller方法中通过实体类,封装多个参数

/**
* 条件分页查询
*/
@GetMapping
public Result page(EmpQueryParam param) {
    log.info("请求参数: {}", param);
    PageBean pageBean = empService.page(param);
    return Result.success(pageBean);
}

场景:请求参数比较多时,可以将多个参数封装到一个对象中。