【 苍穹外卖笔记day02】第二节 -- 员工分页查询
本文总结了苍穹外卖项目第二天开发内容,重点讲解了员工分页查询功能的实现过程。主要步骤包括: 需求分析与接口设计,明确了分页查询的业务规则 创建了EmployeePageQueryDTO数据传输对象和PageResult分页结果封装类 代码开发采用分层架构: Controller层接收请求参数并返回统一格式结果 Service层使用PageHelper插件实现分页逻辑 Mapper层通过XML编写动
苍穹外卖笔记day2
第二天 员工管理、分类管理
第二节 – 员工分页查询
一、 需求分析和设计
产品原型:
业务规则:
- 根据页码展示员工信息
- 每页展示10条数据
- 分页查询是可以更具需要,输入员工姓名进行查询
接口设计
data的里面有:tatal总的数据和recaords分页数据,分页数据下就是单表查询的内容。
二、代码开发
根据分页查询设计的DTO
位置:sky-pojo/src/main/java/com/sky/dto/EmployeePageQueryDTO.java
@Data
public class EmployeePageQueryDTO implements Serializable {
//员工姓名
private String name;
//页码
private int page;
//每页显示记录数
private int pageSize;
}
后面所有的分页查询,统一都封装成PageResult对象
位置:sky-common/src/main/java/com/sky/result/PageResult.java
/** * 封装分页查询结果 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult implements Serializable {
private long total; //总记录数 private List records; //当前页数据集合
}
再把PageResult对象统一封装成Result对象,然后把Result转成Json格式,返回
给前端。数据格式:

代码实现:
- 在Ctroller层
sky-server/src/main/java/com/sky/controller/admin/EmployeeController.java新增page方法。
/**
* 员工模块 - 分页查询接口
* 请求方式:GET
* 请求路径:/admin/employee/page
* 请求参数:EmployeePageQueryDTO 中的字段(如 page、pageSize、name 等)会以 URL 查询字符串形式自动封装
* 返回结果:Result<PageResult> 统一包装类,里面包含总记录数、当前页数据列表
*/
@GetMapping("/page") // 1. 只接受 GET 请求,映射路径 /page
public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO) {
// 2. 打印请求参数,方便线上排查问题;使用 slf4j 的占位符写法,避免字符串拼接
log.info("员工分页查询:参数为:{}", employeePageQueryDTO);
// 3. 调用业务层 pageQuery 方法,拿到封装好的分页结果(总条数 + 当前页数据)
PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);
// 4. 使用统一返回包装类 Result 返回成功结果,前端拿到 json 结构:
// {"code":1,"msg":null,"data":{"total":100,"records":[...]}}
return Result.success(pageResult);
}
- 在service接口层
sky-server/src/main/java/com/sky/service/EmployeeService.java写pageQuery分页查询方法
/**
* 员工分页查询
* @param employeePageQueryDTO
* @return
*/
PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO);
3.在ServiceImpl实现类
一般我们查数据:select * from employee limit 0,10,但是我们已经封装好了Page为DTO,这样我们可以使用一些已经有的插件:PageHelper,我们只需要在pom.xml中导入即可:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper}</version>
</dependency>
ServiceImpl实现类sky-server/src/main/java/com/sky/service/impl/EmployeeServiceImpl.java
/**
* 员工分页查询业务实现
* 1. 利用 PageHelper 拦截下一次 SQL 执行,自动拼 LIMIT
* 2. 调用 Mapper 进行条件查询,返回 MyBatis 的 Page 对象(继承自 ArrayList)
* 3. 把 Page 对象里的 total/records 封装成自定义 PageResult 返回
*
* @param employeePageQueryDTO 封装了 page、pageSize、name 等查询条件
* @return PageResult 统一分页结果(总条数 + 当前页数据)
*/
@Override
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
// 1. 对 MyBatis 说:“接下来的第一条 SQL 要分页”
// ThreadLocal 里存了一个 Page 对象,记录页码、每页条数
PageHelper.startPage(employeePageQueryDTO.getPage(),
employeePageQueryDTO.getPageSize());
// 2. 执行 SQL,返回的 page 就是“装了 10 条数据 + 总条数”的盒子
// 底层:MyBatis 拦截器把你的 SQL 后面自动拼上 LIMIT ?, ?
Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);
// 3. 从盒子里拿标签
long total = page.getTotal(); // 总记录数 287
List<Employee> records = page.getResult(); // 本页数据 10 条
// 4. 装进我们自己的统一返回对象
return new PageResult(total, records);
}
- Mapper层,/要获取动态sql,就不适用注解插入sql,可以写到映射文件里面去
sky-server/src/main/java/com/sky/mapper/EmployeeMapper.java
/**
* 员工分页查询
* @param employeePageQueryDTO
* @return
*/
// 要获取动态sql,就不适用注解插入sql,写到映射文件里面去
Page<Employee> pageQuery(EmployeePageQueryDTO employeePageQueryDTO);
映射文件:sky-server/src/main/resources/mapper/EmployeeMapper.xml
<!-- 员工分页 + 条件查询 SQL 映射
id:与 Mapper 接口中的方法名 pageQuery 一一对应
resultType:查询结果直接封装成 com.sky.entity.Employee 实体 -->
<select id="pageQuery" resultType="com.sky.entity.Employee">
SELECT * FROM employee
<!-- <where> 标签会自动处理多余的 AND/OR,并生成 WHERE 关键字 -->
<where>
<!-- 只有当 name 不为 null 且不为空字符串时才拼接模糊查询条件 -->
<if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
</where>
<!-- 按创建时间倒序,保证最新创建的员工排在前面 -->
ORDER BY create_time DESC
<!-- 注意:分页语句 LIMIT ?,? 由 PageHelper 拦截器自动追加,这里不需要手写 -->
</select>
能否扫描到映射文件?在yml文件里面,已经配置好了classpath:mapper/*.xml就可以扫描到。
三、功能测试
可以通过swagger接口文档进行测试,也可以进行前后端联调测试,最后操作视角字段展示有问题,如下:
通过Swagger接口文档测试:
- 运行项目,debug运行,在员工分页查询(http://localhost:8080/doc.html#/default/员工接口文档/pageUsingGET)接口文档 →调试 →请求参数下,输入page值和pageSize值,点击发送。

- 我们在响应内容暂时没有,我们需要到控制台查看,因为有log.info,但是我们也没有看到,接口文档中的响应内容报401

- 原因:我们jwt令牌的有效时间是7200秒=2小时,所以2小时后jwt令牌的token会失效。

- 解决方法:在员工登录处,重新登录一下,复制新生成的令牌

- 然后在 文档管理 →全局参数设置中粘贴刚刚我们复制的jwt临牌的token值过去,然后再关闭所有标签

- 重新进入 员工相关接口 → 员工分页查询 →调试 →请求参数,点击发送,获取到分页内容。

四、功能完善
问题1:时间格式:数组
前端时间格式不直观,不符合我们可读格式,这里格式呈现的是数组格式。
解决方法:
方式一:在属性上加入注释,对日期进行格式化


重启项目,在接口文档重新发送分页信息,查看显示的时间,对比,添加了注解的和没有添加注解的
方式二:在WebMvcConfiguration中扩展Spring MVC的消息转换器,统一对日期类型进行格式化处理(本项目推荐)
- 在我们的
sky-server/src/main/java/com/sky/config/WebMvcConfiguration.java文件中 WebMvcConfiguration继承了WebMvcConfigurationSupport父类,我们只需要重写WebMvcConfigurationSupport的一个方法:extendMessageConverters扩展消息转换器
/**
* 扩展Spring MVC框架的消息转换器(JSON 刷子)
* 目标:统一返回格式、时间转字符串、中文不乱码、null 也显示
* @param converters
*/
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
// 1. 创建一个消息转换器对象:造一把“新刷子”——专门刷 JSON 的转换器
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
// 2. 需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象转化为json数据
// 给刷子装上“定制笔芯”——我们写好的 JacksonObjectMapper
// JacksonObjectMapper 里已经配好:
// • 日期格式 yyyy-MM-dd HH:mm:ss
converter.setObjectMapper(new JacksonObjectMapper());
// 3. 将自己的消息转换器加入容器中
// 把新刷子插到工具箱最前面(索引 0)
// Spring 会按顺序找转换器,找到我们的就直接用,不再用默认老刷子
converters.add(0, converter);
}

2. 这个JacksonObjectMapper类在我们的sky-common/src/main/java/com/sky/json/JacksonObjectMapper.java中,规定日期格式
/**
* 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
*/
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
//public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public JacksonObjectMapper() {
super();
//收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化时,属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//注册功能模块 例如,可以添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}
- 自己创建的消息转换器需要加入到转换器里面才会生效
converters.add(0, converter);
验证:添加断点,运行后,查看converters,size为8,共有8个消息转换器,我们继续单步运行到90行
可以看到,我们刚刚新增的消息转换器加入到了容器中,位置在0,共有9个消息转换器。
- 放行,启动完成后,在员工接口文档→员工分页查询页面,再次点击发送。我们可以看到我们的响应内容,已经符合我们的可读格式

在前端我们也可以看到,时间符合我们的可读格式。
🙋 学习知识,内容讲解
1. 先搞懂 下面的核心概念
名词 作用 HttpMessageConverter Spring 的“数据翻译器”——把 Java 对象 ⇄ JSON(前后端互相能看懂)。 MappingJackson2HttpMessageConverter 官方提供的“JSON 翻译官”,底层靠 Jackson。 ObjectMapper Jackson 的“大管家”:负责 序列化/反序列化 规则 JacksonObjectMapper 我们自己继承 ObjectMapper并写好配置的“翻译官笔芯”。是自定义的词典(规定日期格式、遇到未知字段别报错等)。extendMessageConverters SpringMVC 专门留给用户的“插刷子”口子;只要添加就会优先使用。 2. 自定义词典里写了啥(
JacksonObjectMapper)
规则 作用 例子 FAIL_ON_UNKNOWN_PROPERTIES = falseJSON 里多出来的字段不报错 前端多传了 "xxx":123"也能接受注册 SimpleModule告诉 Jackson 如何翻译 LocalDateTime / LocalDate / LocalTime 日期统一格式 yyyy-MM-dd HH:mm加序列化器 & 反序列化器 出→ Java 变 JSON 用 LocalDateTimeSerializer
入→ JSON 变 Java 用LocalDateTimeDeserializer避免写成时间戳
- 不写会怎么样?
| 不写 | 写了 |
| ---------- | --------------------------- |
| 时间戳 long | 可读字符串 “2024-06-18 12:00:00” |
| null 字段被忽略 | null 字段也返回,前端不报错 |
| 可能出现中文乱码 | 强制 UTF-8,中文正常 |
| 全局格式不统一 | 整个项目返回 JSON 风格一致 |
员工分页查询的完整流程:
| 阶 段 | 位置(文件/类 ) | 关键代码/动作 | 输入→输出 | 时间格式 处理说明 |
|---|---|---|---|---|
| 1. 浏览器发请求 | 前端JS | axios.get('/admin/employee/page', {params:{name:'',page:1,pageSize:2}}) |
仅分页参数page=1 &pageSize=2 |
不传时间;createTime/updateTime由后端直接返回数组 |
| 2. 接收参数 | EmployeeController | page(EmployeePageQueryDTO dto) |
QueryString→DTO字段 | 无,普通字符串/数字 |
| 3. 查询入口 | EmployeeController → EmployeeService |
employeeService.pageQuery(dto) |
DTO→PageResult | 日期字段未上传, 使用数据库值 |
| 4. 分页插件 | EmployeeServiceImpl | PageHelper.startPage(dto.getPage(),dto.getPageSize()) |
设置LIMIT | 无时间处理 |
| 5. 条件查询 | EmployeeMapper.xml | <select id="pageQuery"><if test="name!=null and name!=''"> |
SQL带模糊查询 | 无时间参数 |
| 6. 结果封装 | EmployeeMapper → EmployeeServiceImpl |
Page<Employee> page=employeeMapper.pageQuery(dto) |
数据库行→List<Employee> |
数据库DateTime字段被MyBatis自动映射成Java LocalDateTime |
| 7. 返回前端 | EmployeeServiceImpl → EmployeeController |
return new PageResult(page.getTotal(),page.getResult()) |
Java对象→JSON | 对象里已是LocalDateTime |
| 8. 统一序列化 | WebMvcConfiguration + JacksonObjectMapper |
LocalDateTimeSerializer |
LocalDateTime→"2025-11-09 16:46" |
Jackson按yyyy-MM-dd HH:mm把LocalDateTime转成字符串输出 |
| 9. 浏览器收到 | 前端表格组件 | res.data.records |
JSON字符串→表格列 | 时间从数组变为"yyyy-MM-dd HH:mm"直观格式 |
时序图(简化)
提交代码
Git →commit,输入“员工分页查询业务代码开发”,点击Commit and Push…
然后Push
显示已提交,提交完成
gitee上刷新,显示刚刚push的文件。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)