Spring蛇案和验证错误响应

时间:2018-08-23 08:00:13

标签: java spring spring-boot

我在使用Spring Boot的API构建的json映射中使用了蛇形外壳。 spring使您可以使用以下命令在application.properties文件中轻松定义它:

spring.jackson.property-naming-strategy=SNAKE_CASE

这很好。但是,如果我添加验证并且尝试发布无效的json正文,则响应消息中包含驼峰大小写的缺少字段。这是我的控制器和传输对象:

import javax.validation.constraints.NotNull;

public class MyObject {
    @NotNull
    String camelCasedField;

    public MyObject() {}

    public String getCamelCasedField() {
        return camelCasedField;
    }

    public void setCamelCasedField(String camelCasedField) {
        this.camelCasedField = camelCasedField;
    }
}

控制器:

import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@RestController
@RequestMapping("/api/test")
public class MyController {    
    @PostMapping
    public void createTenant(@RequestBody @Valid MyObject myObject) {}
}

如果我发布以下json主体,则一切正常: _     {“ camel_cased_field”:“测试”}

如果我发布一个空的json正文,则会收到预期的错误,但字段名称是驼峰大小写而不是蛇形大小写:

{
    "timestamp": "2018-08-23T07:43:18.987+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "NotNull.myObject.camelCasedField",
                "NotNull.camelCasedField",
                "NotNull.java.lang.String",
                "NotNull"
            ],
            "arguments": [
                {
                    "codes": [
                        "myObject.camelCasedField",
                        "camelCasedField"
                    ],
                    "arguments": null,
                    "default_message": "camelCasedField",
                    "code": "camelCasedField"
                }
            ],
            "default_message": "must not be null",
            "object_name": "myObject",
            "field": "camelCasedField", // should be camel_cased_field
            "rejected_value": null,
            "binding_failure": false,
            "code": "NotNull"
        }
    ],
    "message": "Validation failed for object='myObject'. Error count: 1",
    "path": "/api/test"
}

是否有一种方法可以针对Spring应用程序的所有端点进行修复?

1 个答案:

答案 0 :(得分:0)

默认情况下,javax.validation框架将使用Bean字段框,通常是Java Bean字段的驼峰框。

但是有一种改变方式。这不是一个简单的方法,但是有一种方法。

  • 定义一个RestControllerAdvice来处理项目中的异常。 (通常是大多数spring应用程序的一部分)
  • MethodArgumentNotValidExceptionConstraintViolationException异常添加处理程序。一种用于POST正文违规,另一种用于路径/查询字符串验证违规。
  • MethodArgumentNotValidException公开了一个BindingResult字段,该字段具有FieldError对象的列表,并且每个字段错误对象都有一个名为“ field”的字段。您需要使用反射将此字段的值从骆驼肠衣设置为所需的任何肠衣。
  • 类似地,ConstraintViolationException公开了一个您可以操纵的名为“ propertyPath”的字段。

请注意,如果您未在http 400响应中原样发出MethodArgumentNotValidException,则可以避免反射和避免很多痛苦。通常,人们处理此异常并提取字段名称和消息,然后在http 400(或422 :))响应中将这些消息作为列表发出。如果这样做,则只需转换字段名称,而不会弄乱FieldError对象内部的私有值。

以下是示例:

@RestControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ExceptionResolver {

  @ExceptionHandler(MethodArgumentNotValidException.class)
  @ResponseStatus(value = HttpStatus.UNPROCESSABLE_ENTITY)
  public ErrorResponse handleMethodArgumentNotValidException(HttpServletRequest request,
                 MethodArgumentNotValidException ex) {

    final List<String> errorMessages = new ArrayList<>();
    final BindingResult bindingResult = ex.getBindingResult();

    if (bindingResult.hasErrors()) {

      final List<FieldError> fieldErrorList = bindingResult.getFieldErrors();

      for (FieldError fieldError : fieldErrorList) {
        String kebabFieldName = YOUR_METHOD_TO_CONVERT_CAMEL_TO_KEBAB(fieldError.getField());
        // use kebabFieldName and message to construct your response.
      }
    }
  }
}

如果您使用google-guava帮助器jar,则是YOUR_METHOD_TO_CONVERT_CAMEL_TO_KEBAB的示例。

String kebab = com.google.common.base.CaseFormat.LOWER_CAMEL
                    .to(CaseFormat.LOWER_UNDERSCORE, fieldError.getField());

如果您找到更简单的方法,请告诉我!干杯。