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

Spring Validator校验重复后BindingResult返回null问题求助

问题分析与解决方案

问题描述

注册Sensor时遇到两个核心问题:

  1. 提交重复名称的Sensor,响应中message为null,无法返回校验器中设置的错误提示
  2. SensorDTO上标注的@Size(min=1)和@NotEmpty注解不生效,空名称的Sensor能直接通过校验

相关代码及现象

控制器方法

@PostMapping("/registration")
public ResponseEntity<HttpStatus> create(@RequestBody @Valid SensorDTO sensorDTO,
                                         BindingResult bindingResult){
    // 调用校验器后错误信息无法正常返回
    sensorValidator.validate(convertToSensor(sensorDTO), bindingResult);

    if (bindingResult.hasErrors()){
        StringBuilder errorMessage = new StringBuilder();
        List<FieldError> errors = bindingResult.getFieldErrors();
        for (FieldError error : errors){
            errorMessage.append(error.getDefaultMessage());
        }
        throw new SensorNotCreatedException(errorMessage.toString());
    }
    sensorService.save(convertToSensor(sensorDTO));
    return ResponseEntity.ok(HttpStatus.OK);
}

Sensor校验类

@Component
public class SensorValidator implements Validator {

    private final SensorService sensorService;

    @Autowired
    public SensorValidator(SensorService sensorService) {
        this.sensorService = sensorService;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return Sensor.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        Sensor sensor = (Sensor) target;
        if (sensorService.getName(sensor.getName()).isPresent())
            errors.rejectValue("name","45234","This name is already taken");
    }
}

错误响应示例

{
    "message": null,
    "timestamp": 1678379316410
}

控制台日志

org.springframework.validation.BeanPropertyBindingResult: 1 errors Field error in object 'sensorDTO' on field 'name': rejected value [Mega Cool sensor]; codes [45234.sensorDTO.name,45234.name,45234.java.lang.String,45234]; arguments []; default message [This name is already taken]

核心问题分析

  1. 异常类未正确封装错误信息:控制台已显示BindingResult中存在正确的错误消息,但响应返回message: null,说明SensorNotCreatedException的message字段未被正确赋值,或未提供有效的Getter方法供JSON序列化使用。
  2. DTO校验注解未生效:大概率是缺少Spring校验依赖,或注解未正确标记在SensorDTO的对应字段上。
  3. 校验对象与BindingResult绑定对象不匹配:校验器处理的是Sensor实体类,但BindingResult绑定的是SensorDTO,虽然字段名一致,但存在潜在的映射风险(控制台日志已显示映射成功,此点非当前核心问题)。

修复步骤

1. 修复SensorNotCreatedException类

确保异常类正确接收并暴露错误信息,示例如下:

public class SensorNotCreatedException extends RuntimeException {
    private String message;
    private long timestamp;

    public SensorNotCreatedException(String message) {
        super(message);
        this.message = message;
        this.timestamp = System.currentTimeMillis();
    }

    // 必须提供Getter方法,否则JSON序列化时无法读取字段值
    public String getMessage() {
        return message;
    }

    public long getTimestamp() {
        return timestamp;
    }
}

若使用Lombok的@Data注解,可自动生成Getter方法,避免手动编写遗漏。

2. 确保DTO校验注解生效

  • 确认已引入Spring校验依赖(Spring Boot项目需添加):
<!-- Maven依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
  • 检查SensorDTO的name字段注解是否正确配置:
public class SensorDTO {
    @NotEmpty(message = "传感器名称不能为空")
    @Size(min = 1, message = "传感器名称长度不能小于1")
    private String name;

    // 其他字段及Getter/Setter方法
}

3. 优化错误信息拼接逻辑

如果存在多个错误,建议添加分隔符提升可读性:

if (bindingResult.hasErrors()){
    StringBuilder errorMessage = new StringBuilder();
    List<FieldError> errors = bindingResult.getFieldErrors();
    for (int i = 0; i < errors.size(); i++) {
        FieldError error = errors.get(i);
        errorMessage.append(error.getDefaultMessage());
        // 多个错误时添加分号分隔
        if (i != errors.size() - 1) {
            errorMessage.append("; ");
        }
    }
    throw new SensorNotCreatedException(errorMessage.toString());
}

4. 可选:调整校验器直接校验SensorDTO

避免对象转换步骤,让校验器直接处理DTO,减少潜在问题:

@Component
public class SensorValidator implements Validator {

    private final SensorService sensorService;

    @Autowired
    public SensorValidator(SensorService sensorService) {
        this.sensorService = sensorService;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return SensorDTO.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        SensorDTO sensorDTO = (SensorDTO) target;
        if (sensorService.getName(sensorDTO.getName()).isPresent()) {
            errors.rejectValue("name","45234","This name is already taken");
        }
    }
}

控制器中直接传入DTO对象:

sensorValidator.validate(sensorDTO, bindingResult);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 17:22:24