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

使用@ControllerAdvice全局异常处理器仍输出时间戳问题

问题描述
  • 已配置禁用WRITE_DATES_AS_TIMESTAMPS的ObjectMapper,但全局异常处理器(@ControllerAdvice)返回的响应中,timestamp字段仍输出时间戳格式
  • 但如果在Controller内部使用@ExceptionHandler处理异常,返回的时间格式是正常的字符串格式

相关代码

全局异常处理器

@ControllerAdvice
public class GlobalExceptionHandlerAdvice extends ResponseEntityExceptionHandler {

    @Override
    public ResponseEntity<Object> handleServletRequestBindingException(
            ServletRequestBindingException servletRequestBindingException, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return ErrorResponse.builder(e, status, errorMessage)
                .property("code", String.valueOf(applicationError.getCode()))
                .property("timestamp", OffsetDateTime.now())
                .build();
    }
}

MockMvc配置代码

MockMvc mock = MockMvcBuilders.standaloneSetup(myController)
                .setMessageConverters(new MappingJackson2HttpMessageConverter(createObjectMapper()))
                .setHandlerExceptionResolvers(createExceptionResolver())
                .build();

private ExceptionHandlerExceptionResolver createExceptionResolver() {
    ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
        @Override
        protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
            Method method = new ExceptionHandlerMethodResolver(GlobalExceptionHandlerAdvice.class).resolveMethod(exception);
            return new ServletInvocableHandlerMethod(new GlobalExceptionHandlerAdvice(), method);
        }
    };
    exceptionResolver.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
    exceptionResolver.afterPropertiesSet();
    return exceptionResolver;
}

public ObjectMapper createObjectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new JavaTimeModule());
    objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
    objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    return objectMapper;
}
问题原因

你在createExceptionResolver方法中,给异常解析器添加的是默认的MappingJackson2HttpMessageConverter(未传入自定义ObjectMapper),而非你配置好的、禁用了时间戳序列化的转换器。全局异常处理器的响应通过异常解析器的转换器序列化,而Controller内的异常处理器用的是setMessageConverters设置的自定义转换器,因此两者表现不一致。

解决方案

修改createExceptionResolver方法,使用自定义ObjectMapper创建转换器,替换默认添加逻辑:

private ExceptionHandlerExceptionResolver createExceptionResolver() {
    ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
        @Override
        protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
            Method method = new ExceptionHandlerMethodResolver(GlobalExceptionHandlerAdvice.class).resolveMethod(exception);
            return new ServletInvocableHandlerMethod(new GlobalExceptionHandlerAdvice(), method);
        }
    };
    // 使用自定义ObjectMapper创建转换器
    exceptionResolver.getMessageConverters().add(new MappingJackson2HttpMessageConverter(createObjectMapper()));
    exceptionResolver.afterPropertiesSet();
    return exceptionResolver;
}

如果担心多个转换器冲突,可先清空默认转换器再添加自定义的:

private ExceptionHandlerExceptionResolver createExceptionResolver() {
    ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
        @Override
        protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
            Method method = new ExceptionHandlerMethodResolver(GlobalExceptionHandlerAdvice.class).resolveMethod(exception);
            return new ServletInvocableHandlerMethod(new GlobalExceptionHandlerAdvice(), method);
        }
    };
    // 清空默认转换器,避免冲突
    exceptionResolver.getMessageConverters().clear();
    exceptionResolver.getMessageConverters().add(new MappingJackson2HttpMessageConverter(createObjectMapper()));
    exceptionResolver.afterPropertiesSet();
    return exceptionResolver;
}

修改后,全局异常处理器的响应会使用配置好的ObjectMapper,将OffsetDateTime序列化为字符串格式而非时间戳。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 00:55:04