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

如何在Quarkus+Hibernate Validator中自定义验证错误响应

在Quarkus中自定义Hibernate Validator校验错误响应格式

Quarkus中可以通过JAX-RS的ExceptionMapper来统一处理Hibernate Validator抛出的校验异常,从而实现自定义的紧凑响应格式,还能灵活添加额外信息,具体步骤如下:

1. 定义自定义错误响应DTO

先创建一个用于返回的错误响应类,按需设计字段,比如包含状态码、提示消息、字段错误列表、时间戳和自定义扩展字段:

import java.time.LocalDateTime;
import java.util.List;

public class ValidationErrorResponse {
    private int status;
    private String message;
    private LocalDateTime timestamp;
    private List<FieldError> fieldErrors;
    // 自定义额外字段,比如请求ID
    private String requestId;

    // 内部类存储单个字段的错误信息
    public static class FieldError {
        private String field;
        private String errorMsg;

        public FieldError(String field, String errorMsg) {
            this.field = field;
            this.errorMsg = errorMsg;
        }

        // 省略getter/setter,按需生成
        public String getField() { return field; }
        public void setField(String field) { this.field = field; }
        public String getErrorMsg() { return errorMsg; }
        public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; }
    }

    public ValidationErrorResponse(int status, String message, List<FieldError> fieldErrors, String requestId) {
        this.status = status;
        this.message = message;
        this.timestamp = LocalDateTime.now();
        this.fieldErrors = fieldErrors;
        this.requestId = requestId;
    }

    // 省略getter/setter,按需生成
}

2. 实现ExceptionMapper处理校验异常

编写一个带有@Provider注解的异常处理器,捕获Hibernate Validator抛出的ConstraintViolationException,将异常信息转换成自定义的响应格式:

import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;
import java.util.List;
import java.util.stream.Collectors;

@Provider
public class ValidationExceptionMapper implements ExceptionMapper<ConstraintViolationException> {

    @Override
    public Response toResponse(ConstraintViolationException exception) {
        // 提取所有字段的校验错误信息
        List<ValidationErrorResponse.FieldError> fieldErrors = exception.getConstraintViolations().stream()
                .map(violation -> new ValidationErrorResponse.FieldError(
                        violation.getPropertyPath().toString(), // 获取字段路径(如"user.username")
                        violation.getMessage() // 获取自定义校验提示
                ))
                .collect(Collectors.toList());

        // 构建自定义响应,可添加任意额外信息(这里示例生成一个简易请求ID)
        ValidationErrorResponse response = new ValidationErrorResponse(
                Response.Status.BAD_REQUEST.getStatusCode(),
                "参数校验失败",
                fieldErrors,
                "req-" + System.currentTimeMillis()
        );

        return Response.status(Response.Status.BAD_REQUEST)
                .entity(response)
                .build();
    }
}

3. 验证效果

假设你的REST端点和校验模型是这样的:

import jakarta.validation.Valid;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;

@Path("/users")
public class UserResource {

    public static class UserRequest {
        @NotBlank(message = "用户名不能为空")
        @Size(min = 2, max = 20, message = "用户名长度需在2-20之间")
        private String username;

        @Email(message = "邮箱格式不正确")
        private String email;

        // 省略getter/setter
    }

    @POST
    public Response createUser(@Valid UserRequest request) {
        return Response.ok("用户创建成功").build();
    }
}

当发送含无效数据的请求时,会返回如下紧凑格式的响应:

{
  "status": 400,
  "message": "参数校验失败",
  "timestamp": "2024-05-20T15:30:00",
  "fieldErrors": [
    {
      "field": "username",
      "errorMsg": "用户名不能为空"
    },
    {
      "field": "email",
      "errorMsg": "邮箱格式不正确"
    }
  ],
  "requestId": "req-1716209400000"
}

额外说明

  • 若需处理嵌套对象的校验(比如UserRequest里包含Address子对象),violation.getPropertyPath().toString()会返回类似address.zipCode的字段路径,可按需分割或保留。
  • 可以在ExceptionMapper中注入其他Quarkus Bean(比如请求上下文),获取真实的请求ID、用户信息等扩展数据。
  • Quarkus会自动扫描带有@Provider注解的处理器,无需额外配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 18:31:08