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

Spring Boot通用异常无法返回ErrorDTO问题的解决方法

问题修复方案

原因分析

出现HttpMediaTypeNotAcceptableException是因为数据完整性约束异常(比如字段超长)触发时,没有被Spring MVC全局异常处理器及时捕获,转而被容器默认错误机制接管,导致响应媒体类型协商失败,无法返回自定义ErrorDTO。另外也可能是异常处理器的匹配范围不足、ErrorDTO序列化配置有问题。

修复步骤

1. 扩展全局异常处理器的异常捕获范围

修改GlobalExceptionHandler,明确捕获JPA/Hibernate抛出的数据完整性违规异常:

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 捕获数据完整性约束异常
    @ExceptionHandler(DataIntegrityViolationException.class)
    public ResponseEntity<ErrorDTO> handleDataIntegrityViolation(DataIntegrityViolationException ex) {
        String errorMsg = "字段长度超出限制或违反数据完整性约束";
        // 解析底层SQL异常获取更具体信息
        if (ex.getCause() instanceof SQLException sqlEx) {
            errorMsg = sqlEx.getMessage();
        }
        ErrorDTO errorDTO = new ErrorDTO(HttpStatus.BAD_REQUEST.value(), errorMsg, LocalDateTime.now());
        return new ResponseEntity<>(errorDTO, HttpStatus.BAD_REQUEST);
    }

    // 保留通用异常处理
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorDTO> handleGenericException(Exception ex) {
        ErrorDTO errorDTO = new ErrorDTO(HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage(), LocalDateTime.now());
        return new ResponseEntity<>(errorDTO, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

2. 确保ErrorDTO可正常序列化

检查ErrorDTO的构造方法和getter/setter是否齐全,保证Jackson能正确序列化:

import java.time.LocalDateTime;

public class ErrorDTO {
    private int status;
    private String message;
    private LocalDateTime timestamp;

    // 必须包含无参构造方法
    public ErrorDTO() {}

    public ErrorDTO(int status, String message, LocalDateTime timestamp) {
        this.status = status;
        this.message = message;
        this.timestamp = timestamp;
    }

    // 所有字段的getter/setter
    public int getStatus() { return status; }
    public void setStatus(int status) { this.status = status; }
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
    public LocalDateTime getTimestamp() { return timestamp; }
    public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}

3. 禁用容器默认错误页面

在application.properties中添加配置,让Spring MVC优先使用自定义异常处理器:

server.error.whitelabel.enabled=false
spring.mvc.throw-exception-if-no-handler-found=true
spring.web.resources.add-mappings=false

4. 提前验证请求参数(可选优化)

在Controller层通过JSR-380注解提前校验字段长度,避免触发底层数据库异常:

@PostMapping("/v1/locations")
public ResponseEntity<Location> createLocation(@Valid @RequestBody LocationRequest request) {
    // 业务逻辑实现
}

// 请求参数DTO
public class LocationRequest {
    @Size(max = 10, message = "code字段长度不能超过10位")
    private String code;
    // 其他字段及getter/setter
}

同时在全局异常处理器中添加校验异常的处理:

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorDTO> handleValidationExceptions(MethodArgumentNotValidException ex) {
    String errorMsg = ex.getBindingResult().getFieldErrors().stream()
            .map(FieldError::getDefaultMessage)
            .collect(Collectors.joining(", "));
    ErrorDTO errorDTO = new ErrorDTO(HttpStatus.BAD_REQUEST.value(), errorMsg, LocalDateTime.now());
    return new ResponseEntity<>(errorDTO, HttpStatus.BAD_REQUEST);
}

验证修复

重启项目后,再次发送超长code字段的POST请求,此时会返回自定义的ErrorDTO格式响应,控制台也不会再出现HttpMediaTypeNotAcceptableException异常。

内容的提问来源于stack exchange,提问作者Sercan Noyan Germiyanoğlu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 06:09:19