【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 显式映射即可解决。

相关推荐
开开心心就好2 小时前
多份文档怎么批量打印?支持多种格式
java·服务器·开发语言·pdf·ocr·散列表·启发式算法
Want5952 小时前
Python炫酷烟花①
开发语言·python
Pniubi2 小时前
模拟一个充值送token怎么保证幂等?一致性?原子性?
java
企业数字化笔记3 小时前
多租户配额怎么控制?用量口径、并发预留与超额处理的实现方法
java·数据库·spring boot
roman_日积跬步-终至千里3 小时前
【数据Agent论文·查询与语义|06】RAT-SQL:怎样把问题、表和字段真正关联起来?
数据库·sql·数据分析
星夜离尘563 小时前
MATLAB 线性去趋势为何损伤低频正弦:联合最小二乘估计幅相与漂移
开发语言·matlab
巴勒个啦3 小时前
Prompt Engineering 实战:5 个让 AI 生成生产级业务代码的工程模式
java·前端
倚楼听风语3 小时前
Kotlin 协程与 suspend 原理详解
java·算法·kotlin
程序员清风3 小时前
双指针与滑动窗口:高效处理连续区间
开发语言·算法
开开心心就好4 小时前
文件被占用删不掉?解锁工具强制删除
java·运维·服务器·开发语言·前端·pdf·ocr