spring-boot - spring/hibernate 验证 -> 错误消息未传递给调用者?

标签 spring-boot spring-restcontroller hibernate-validator controller-advice jsr380

我正在使用org.springframework.boot:spring-boot-starter-validation:2.7.0(它又使用hibernate验证器)来验证其余 Controller 的用户输入。
我正在使用带有 @RestController 注释的基于 Spring Boot Web Starter (2.7.0) 的项目 我的 @GetMapping 方法如下 -

@GetMapping(path = "/abcservice")
public Object abcService(
            @RequestParam(value = "accountId", required = true) String accountId,
            @Valid @RequestParam(value = "offset", required = false, defaultValue = "0") int offset,
            @Valid @RequestParam(value = "limit", required = false, defaultValue = "10000") int limit
    ) throws Exception {

我的问题是 - 我希望用户了解任何输入验证错误,以便他们可以更正并重试。但框架只是给出 400 状态代码和以下消息。

{
    "timestamp": "2022-08-03T16:10:14.554+00:00",
    "status": 400,
    "error": "Bad Request",
    "path": "/somepath/abcservice"
}

在服务器端,请求被记录在warn中。

2022-08-03 21:40:14.535 WARN 98866 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "0s"]

我想要上面的错误消息 --> 无法将类型“java.lang.String”的值转换为所需类型“int”;嵌套异常是 java.lang.NumberFormatException: For input string: "0s" 也将传递给用户。有没有一种简单的基于配置的方法来实现。
我想我可以添加一个 ControllerAdvice 来处理此异常,并将此消息包含在处理程序方法的响应中。但这将是几行代码。有没有比 ControllerAdvice 方法更简单的方法。

同样,如果客户端未传递强制 accountId 参数,则客户端只会收到与上述相同的 400 响应。没有向客户端提供关于他们做错了什么或如何修复它的详细信息或提示..但在服务器端我可以看到下面的警告日志。

2022-08-03 21:59:20.195 WARN 235 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter 'accountId' for method parameter type String is not present]

我希望客户知道这个错误/异常。这里没有什么 secret 可隐藏(至少就我而言)。

编辑 - 找到此配置 -

server.error.include-message=always

现在的问题是,错误的请求以 500 状态码发送,我希望它们以 400 发送。然后这个问题就解决了。
@Valid 进行的验证返回 500 状态代码。是否有办法告诉服务器在验证失败时返回 400 响应(不使用 ControllerAdvice)。

如果你想测试--你可以尝试-->
使用@Validated注释 Controller 。
执行下面的方法,您将看到 500 错误,但希望这是 400。

@GetMapping("/test")
public void test(@Valid @RequestParam(value = "studentId", required = false)
                         @Min(value=0, message="Can not be less than 0") @Max(value=200, message="Can not be above 200") Long studentId ) {

        System.out.println("hit: ");
    }

然后点击 - http://localhost:9099/test?studentId=400

最佳答案

没有全局异常处理程序且配置最少的 Spring 内置解决方案是通过在 application.properties 中添加以下属性。

server.error.include-binding-errors=always

上述属性可以有三个值:

  1. 始终 ----> 应用中的所有 api 将始终返回明确定义的验证错误消息响应。
  2. on-param ----> 应用中的所有 api 将根据输入请求参数字段“errors”有条件地返回明确定义的验证错误消息响应
  3. 从不 ---> 禁用此功能。

Example Github Project Reference

Demo Test:

package com.example.demo;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @PostMapping("/test")
    public void test(@Valid @RequestBody Student student) {
        System.out.println("studentData: " + student);
    }

}

class Student {

    @NotNull(message = "firstName cannot be null")
    private String firstName;
    private String lastName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return "Student [firstName=" + firstName + ", lastName=" + lastName + "]";
    }

}

请求:

{
    "firstName": null,
    "lastName" : "sai"
}

响应:(HTTP 响应代码 = 400)

{
    "timestamp": "2022-08-04T05:23:58.837+00:00",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "NotNull.student.firstName",
                "NotNull.firstName",
                "NotNull.java.lang.String",
                "NotNull"
            ],
            "arguments": [
                {
                    "codes": [
                        "student.firstName",
                        "firstName"
                    ],
                    "arguments": null,
                    "defaultMessage": "firstName",
                    "code": "firstName"
                }
            ],
            "defaultMessage": "firstName cannot be null",
            "objectName": "student",
            "field": "firstName",
            "rejectedValue": null,
            "bindingFailure": false,
            "code": "NotNull"
        }
    ],
    "path": "/test"
}

关于spring-boot - spring/hibernate 验证 -> 错误消息未传递给调用者?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73224720/

相关文章:

java - 使用 LocalDate 类型参数发送请求

java - Spring MVC : Not able to connect to Rest service

java - 将异常捕获到 Spring Job 中

Spring Rest请求方法 'GET '不支持

java - 找不到类型 : java. lang.Short 的 validator

java - Hibernate Validator、自定义 ResourceBundleLocator 和 Spring

Hibernate validator 单元测试

java - 使用配置文件设置不同的上下文路径

java - 如何将javascript数组传递给Spring Data Rest

spring - 如何在 Spring Controller 中返回纯文本?