【Java】关于控制台 SQL 日志显示查询有值但Swagger不显示字段问题

场景:做"操作日志 -> 获取操作人列表(姓名+职位)"接口时,控制台 MyBatis 日志能看到 position_name 有值,但 Swagger 响应 JSON 里只有 id/name,职位字段不见了。


1. 背景需求

操作日志页面有一个"操作人"筛选框/弹窗,需要后端提供一个人员列表接口,每条数据包含:

涉及三张表的逻辑外键关系:

  • staff.id ↔ staff_orginfo.staff_id
  • position.id ↔ staff_orginfo.position_id

并且列表要按创建时间倒序(最新的在上)。

对应后端接口(示例):

  • GET /sys/optlog/operators?pageIndex=1&pageSize=10&name=管理员

2. 问题现象(非常迷惑)

调用接口后:

  • 控制台 SQL 日志显示查询列里有 position_name,并且每行数据里职位也有值。
  • 但 Swagger 的响应 JSON 里 rows 只包含 id、name,没有 position_name。

也就是说:SQL 有值,但接口响应不展示该字段 。


3. 定位"问题在哪一层"

  1. SQL 层:数据库是否真的能查到字段?
  2. ORM 映射层:MyBatis 是否把列正确映射到 DTO 属性?
  3. JSON 序列化/Swagger 展示层:DTO 属性是否被序列化输出?

这次排查非常关键的一点是:

  • 控制台既然能打印出 Columns: id, name, position_name,并且 Row 里职位也有值
    → 说明 SQL 层没问题。
  • Swagger 响应里却没有职位字段
    → 极大概率是 ORM 映射层 或 序列化层 的问题。

4. 关键线索:MyBatis 下划线转驼峰映射

MyBatis(或 MyBatis-Plus)经常会开启一个全局配置:

  • mapUnderscoreToCamelCase=true

开启后,MyBatis 会把数据库列名自动做转换:

  • position_name → positionName
  • add_time → addTime

这就带来一个"坑":

如果 DTO 里字段写成了下划线风格:

java 复制代码
private String position_name;

而 SQL 返回的列名是 position_name,MyBatis 会尝试去找 positionName 来赋值,结果找不到,字段就一直是 null。

一旦 DTO 字段为 null,再结合项目常见的 JSON 序列化配置(不输出 null 字段),Swagger 里就会表现为:

"返回里根本没有这个字段"

这也是为什么明明 SQL 有值,Swagger 却像"没返回职位"。


5. 最终解决方案(两种任选其一)

方案 A(最简单):DTO 属性改成驼峰

把 DTO 的职位字段改为 positionName:

java 复制代码
public class OptlogOperatorDTO {
    private Long id;
    private String name;
    private String positionName;
}

然后 SQL 仍然用别名 position_name:

sql 复制代码
SELECT p.name AS position_name

这样 MyBatis 会自动把 position_name 映射到 positionName,字段就能正常出现在 Swagger 响应里。

你这次最终采用的就是这个方案,修改后立刻生效。

方案 B(更稳健):XML 显式 resultMap 强制映射

如果你希望 DTO 里依然用下划线字段名(不推荐,但有时前端字段历史包袱很大),可以在 mapper.xml 写 resultMap:

xml 复制代码
<resultMap id="OptlogOperatorDTOMap" type="com.xxx.OptlogOperatorDTO">
  <id column="id" property="id"/>
  <result column="name" property="name"/>
  <result column="position_name" property="position_name"/>
</resultMap>

<select id="selectOptlogOperators" resultMap="OptlogOperatorDTOMap">
  SELECT s.id, s.name, p.name AS position_name
  ...
</select>

这样映射行为就不依赖全局配置,最稳定。


总结

这次问题之所以"看起来像 SQL/联表错了",是因为:

  • SQL 的确查到了数据(控制台日志有值)
  • 但 MyBatis 映射层因为 下划线转驼峰 的规则,把 position_name 试图映射到 positionName
  • DTO 字段名若写成 position_name,就会映射失败,字段变 null

最终通过统一 DTO 命名(positionName)或 resultMap 显式映射即可解决。

相关推荐
IT枫斗者枫哥4 小时前
MyBatis一对多分页:LIMIT 20,为什么凑不齐20个订单?
java·数据库
代码方舟4 小时前
Java数据工程:利用天远全网运营商三要素优化线上实名认证合规体验
java·人工智能
BBmmo4 小时前
我的 Java 学习笔记 · 第 7 篇:泛型与通配符
java
独泪了无痕4 小时前
Hutool之RandomUtil:随机数生成的终极利器
java·后端
花开路口4 小时前
深入理解 Java/Kotlin 协变与逆变
java·kotlin
运行时异常4 小时前
【WMS 仓储系统集成 AI Agent 实战】第 7 讲:Vue3 前端工程化——Token 刷新锁、Markdown 渲染踩坑与权限体系
java
她的男孩4 小时前
开放接口限流从 20 改到 200 还是每分钟 20 次:拆完防重放+幂等+限流,我找到 5 个静默失效的坑
java·后端·架构
天天被压力4 小时前
【Python 量化取数指南 #13】Python 把行情落库:sqlite 一键存,回测随用随取
java·人工智能·python
天天被压力4 小时前
【Python 量化取数指南 #14】Python 清洗行情数据:复权停牌对齐,回测不翻车
java·人工智能·python
独泪了无痕4 小时前
开发利器Hutool之MapUtil的使用
java·后端