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

如何从ConstraintViolationException中仅提取校验提示信息

问题描述

我编写了如下代码处理ConstraintViolationException,期望仅返回校验约束中的提示信息:

@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(BAD_REQUEST)
@ResponseBody
public final ResponseEntity<ErrorMessage> handleConstraintViolationException( ConstraintViolationException ex ) {

    ErrorMessage errorMessage = new ErrorMessage(ex.getMessage(), "400");

    return new ResponseEntity<>(errorMessage, BAD_REQUEST);
}

实体类代码如下:

package com.courses.restapi.entities.courses;

import com.courses.restapi.entities.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.math.BigDecimal;

@Entity
@Table(name = "courses")
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class Course extends BaseEntity {

    @NotNull
    @NotBlank(message = "title may not be blank")
    @Column( name = "title", length = 100)
    @Size(max = 100 ,message = " title may not be longer than 100 ")
    private String title;

    @NotNull
    @NotBlank(message = "description may not be blank")
    @Column( name = "description", length = 1000)
    @Size(max = 1000 ,message = " description may not be longer than 100 ")
    private String description;

    @NotNull(message = " price may not be null")
    @DecimalMin("1.00")
    private BigDecimal price;

}

当尝试添加描述为空的Course时,返回响应如下:

{
    "message": "Validation failed for classes [com.courses.restapi.entities.courses.Course] during persist time for groups [jakarta.validation.groups.Default, ]\nList of constraint violations:[\n\tConstraintViolationImpl{interpolatedMessage='description may not be blank', propertyPath=description, rootBeanClass=class com.courses.restapi.entities.courses.Course, messageTemplate='description may not be blank'}\n]",
    "code": "400"
}

我希望仅返回"description may not be blank"这类提示信息,尝试替换为Exception类型处理仍未解决问题,该如何实现?


解决方案

ConstraintViolationException本身包含所有校验失败的约束信息集合,无需直接使用ex.getMessage(),而是通过ex.getConstraintViolations()提取目标提示文本即可。

场景1:仅返回第一条错误提示

如果只需要展示第一个触发的校验错误,修改异常处理器如下:

import jakarta.validation.ConstraintViolation;
import java.util.stream.Collectors;

@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(BAD_REQUEST)
@ResponseBody
public final ResponseEntity<ErrorMessage> handleConstraintViolationException(ConstraintViolationException ex) {
    // 获取第一条违规提示,默认值为通用错误文本
    String errorMsg = ex.getConstraintViolations()
                        .stream()
                        .findFirst()
                        .map(ConstraintViolation::getMessage)
                        .orElse("参数校验失败");

    ErrorMessage errorMessage = new ErrorMessage(errorMsg, "400");
    return new ResponseEntity<>(errorMessage, BAD_REQUEST);
}

场景2:返回所有校验错误提示

如果存在多个校验失败(比如标题和描述同时为空),可以将所有提示拼接或返回列表:

拼接成字符串返回

import jakarta.validation.ConstraintViolation;
import java.util.stream.Collectors;

@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(BAD_REQUEST)
@ResponseBody
public final ResponseEntity<ErrorMessage> handleConstraintViolationException(ConstraintViolationException ex) {
    // 用分号拼接所有错误提示
    String errorMsg = ex.getConstraintViolations()
                        .stream()
                        .map(ConstraintViolation::getMessage)
                        .collect(Collectors.joining("; "));

    ErrorMessage errorMessage = new ErrorMessage(errorMsg, "400");
    return new ResponseEntity<>(errorMessage, BAD_REQUEST);
}

返回错误提示列表(需调整ErrorMessage结构)

如果你的ErrorMessage支持接收列表类型的消息字段,直接返回集合即可:

import jakarta.validation.ConstraintViolation;
import java.util.List;
import java.util.stream.Collectors;

@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(BAD_REQUEST)
@ResponseBody
public final ResponseEntity<ErrorMessage> handleConstraintViolationException(ConstraintViolationException ex) {
    List<String> errorMessages = ex.getConstraintViolations()
                                   .stream()
                                   .map(ConstraintViolation::getMessage)
                                   .collect(Collectors.toList());

    // 假设ErrorMessage有对应构造方法或setter接收列表参数
    ErrorMessage errorMessage = new ErrorMessage(errorMessages, "400");
    return new ResponseEntity<>(errorMessage, BAD_REQUEST);
}

核心说明

  • ConstraintViolation.getMessage()会直接返回你在校验注解中定义的自定义提示(比如@NotBlank(message = "description may not be blank")的内容)
  • 避免使用ex.getMessage(),它返回的是包含类信息、校验阶段的完整错误描述,并非简洁的业务提示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 08:13:27