You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中如何记录带有@JsonIgnore注解的字段?

问题:带@JsonIgnore注解的字段无法被日志记录

使用Spring Boot 2.7.3、Java 17和Gradle,需要将所有数据库操作记录到日志文件中。目前其他字段日志输出正常,但UI记录类中带有@JsonIgnore注解的employeeCode和applicationNumber字段无法被记录。

切面类代码

@Aspect
@Component
public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

    @Pointcut("execution(public * org.mycomp.erp.service..*(..))")
    public void requestPointcut() {}

    @Before("requestPointcut()")
    public void requestLogger(JoinPoint joinPoint) throws JsonProcessingException {
        final ObjectMapper objectMapper = new ObjectMapper();

        final String methodName = joinPoint.getSignature().getName();
        final Object[] inputArguments = joinPoint.getArgs();

        final String logMessage = "Operation : " + methodName +
                " With Input Parameters : " + objectMapper.writeValueAsString(inputArguments);

        logger.info(logMessage);
    }
}

UI记录类代码

public record LeaveApplUx(
    @JsonIgnore String employeeCode,
    @JsonIgnore int applicationNumber,
    LocalDate startDate,
    LocalDate endDate,
    String leaveType) {
    public LeaveApplUx(

    @Size(min = 4, max = 5, message = "Employee Code Must Be Within 4 To 5 Character Long Or Blank")
    @JsonProperty("employeeCode") String employeeCode,

    @Range(min = 0, max = 9999, message = "Application Number Must Be Within 9999 Or Zero")
    @JsonProperty("applicationNumber") int applicationNumber,

    @NotNull(message = "Start Date Empty")
    @JsonSerialize(using = LocalDateSerializer.class)
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
    @JsonProperty("startDate") LocalDate startDate,

    @NotNull(message = "End Date Empty")
    @JsonSerialize(using = LocalDateSerializer.class)
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
    @JsonProperty("endDate") LocalDate endDate,

    @Size(min = 2, max = 2, message = "Leave Type Mis-Match")
    @JsonProperty("leaveType") String leaveType) {

        this.employeeCode = employeeCode;
        this.applicationNumber = applicationNumber;
        this.startDate = startDate;
        this.endDate = endDate;
        this.leaveType = leaveType;

    }
}

请求示例

DELETE http://localhost:8080/hr/leave/application/delete

请求体:

{
    "employeeCode": "E001",
    "applicationNumber": "1",
    "startDate": "01-04-2022",
    "endDate": "05-04-2022",
    "leaveType": "CL"
}

当前日志输出

2022-08-30 14:32:53,688 INFO  :  Operation : deleteLeaveApplication With Input Parameters : ["N","N",{"startDate":"01-04-2022","endDate":"05-04-2022","leaveType":"CL"}]

解决方法

问题根源是Jackson的ObjectMapper序列化时会识别并跳过带@JsonIgnore注解的字段,而日志切面正是用它来序列化入参,导致这两个字段未被记录。以下是三种可行方案:

方案1:为日志序列化单独配置ObjectMapper,忽略@JsonIgnore注解

修改切面类中的ObjectMapper初始化逻辑,通过MixIn机制让Jackson在日志序列化时重新识别这两个字段:

@Aspect
@Component
public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
    // 定义MixIn,覆盖原类的@JsonIgnore配置
    abstract static class LeaveApplUxLogMixIn {
        @JsonProperty String employeeCode;
        @JsonProperty int applicationNumber;
    }

    @Pointcut("execution(public * org.mycomp.erp.service..*(..))")
    public void requestPointcut() {}

    @Before("requestPointcut()")
    public void requestLogger(JoinPoint joinPoint) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper()
                .registerModule(new JavaTimeModule()) // 处理LocalDate类型
                .addMixIn(LeaveApplUx.class, LeaveApplUxLogMixIn.class);

        final String methodName = joinPoint.getSignature().getName();
        final Object[] inputArguments = joinPoint.getArgs();

        final String logMessage = "Operation : " + methodName +
                " With Input Parameters : " + objectMapper.writeValueAsString(inputArguments);

        logger.info(logMessage);
    }
}

方案2:使用Jackson视图(View)区分序列化场景

  1. 定义一个日志专用视图类:
public class LogView {}
  1. 修改LeaveApplUx的注解,保留@JsonIgnore同时添加日志视图注解:
public record LeaveApplUx(
    @JsonIgnore @JsonView(LogView.class) String employeeCode,
    @JsonIgnore @JsonView(LogView.class) int applicationNumber,
    LocalDate startDate,
    LocalDate endDate,
    String leaveType) {
    // 构造器代码不变
}
  1. 切面类中使用视图序列化:
ObjectMapper objectMapper = new ObjectMapper()
        .registerModule(new JavaTimeModule())
        .configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);

// 序列化时指定日志视图
String inputStr = objectMapper.writerWithView(LogView.class).writeValueAsString(inputArguments);

方案3:通过反射获取字段值(不依赖Jackson配置)

如果不想修改Jackson的序列化规则,可以通过反射遍历对象字段,手动拼接日志内容,示例如下:

private String getObjectLogStr(Object obj) throws IllegalAccessException {
    if (obj == null) return "null";
    StringBuilder sb = new StringBuilder("{");
    Field[] fields = obj.getClass().getDeclaredFields();
    for (Field field : fields) {
        field.setAccessible(true);
        sb.append(field.getName()).append(":").append(field.get(obj)).append(",");
    }
    if (sb.length() > 1) sb.deleteCharAt(sb.length()-1);
    sb.append("}");
    return sb.toString();
}

在切面类中调用这个方法处理入参里的LeaveApplUx对象即可。


内容的提问来源于stack exchange,提问作者Deep

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 16:06:28