如何自定义spring @Valid验证的默认错误消息?

Dis*_*Hay 31 spring json

DTO:

public class User {

    @NotNull
    private String name;

    @NotNull
    private String password;

    //..
}
Run Code Online (Sandbox Code Playgroud)

控制器:

@RequestMapping(value = "/user", method = RequestMethod.POST)
public ResponseEntity<String> saveUser(@Valid @RequestBody User user) {
    //..
    return new ResponseEntity<>(HttpStatus.OK);
}
Run Code Online (Sandbox Code Playgroud)

默认的json错误:

{"timestamp":1417379464584,"status":400,"error":"Bad Request","exception":"org.springframework.web.bind.MethodArgumentNotValidException","message":"Validation failed for argument at index 0 in method: public org.springframework.http.ResponseEntity<demo.User> demo.UserController.saveUser(demo.User), with 2 error(s): [Field error in object 'user' on field 'name': rejected value [null]; codes [NotNull.user.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.name,name]; arguments []; default message [name]]; default message [may not be null]],"path":"/user"}
Run Code Online (Sandbox Code Playgroud)

我想为每个错误发生我的自定义json.我该如何做到这一点?

Kam*_*kol 40

如果要完全控制每个控制器中的响应消息,请写入a ControllerAdvice.例如,该示例转换MethodArgumentNotValidException为自定义json对象:

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.ArrayList;
import java.util.List;

import static org.springframework.http.HttpStatus.BAD_REQUEST;

/**
 * Kudos http://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-adding-validation-to-a-rest-api/
 *
 */
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class MethodArgumentNotValidExceptionHandler {

    @ResponseStatus(BAD_REQUEST)
    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Error methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        BindingResult result = ex.getBindingResult();
        List<org.springframework.validation.FieldError> fieldErrors = result.getFieldErrors();
        return processFieldErrors(fieldErrors);
    }

    private Error processFieldErrors(List<org.springframework.validation.FieldError> fieldErrors) {
        Error error = new Error(BAD_REQUEST.value(), "validation error");
        for (org.springframework.validation.FieldError fieldError: fieldErrors) {
            error.addFieldError(fieldError.getField(), fieldError.getDefaultMessage());
        }
        return error;
    }

    static class Error {
        private final int status;
        private final String message;
        private List<FieldError> fieldErrors = new ArrayList<>();

        Error(int status, String message) {
            this.status = status;
            this.message = message;
        }

        public int getStatus() {
            return status;
        }

        public String getMessage() {
            return message;
        }

        public void addFieldError(String path, String message) {
            FieldError error = new FieldError(path, message);
            fieldErrors.add(error);
        }

        public List<FieldError> getFieldErrors() {
            return fieldErrors;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Mat*_*ish 23

我知道这是一个老问题,

但我刚刚遇到它,我发现了一些非常好的文章,它在github中也有一个完美的例子.

基本上它使用@ControllerAdviceSpring文档建议.

因此,例如,通过覆盖一个函数可以实现捕获400错误:

@ControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
        logger.info(ex.getClass().getName());
        //
        final List<String> errors = new ArrayList<String>();
        for (final FieldError error : ex.getBindingResult().getFieldErrors()) {
            errors.add(error.getField() + ": " + error.getDefaultMessage());
        }
        for (final ObjectError error : ex.getBindingResult().getGlobalErrors()) {
            errors.add(error.getObjectName() + ": " + error.getDefaultMessage());
        }
        final ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), errors);
        return handleExceptionInternal(ex, apiError, headers, apiError.getStatus(), request);
    }
}
Run Code Online (Sandbox Code Playgroud)

(ApiError类是一个保存状态,消息,错误的简单对象)


ksw*_*ghs 22

您可以使用Errors/BindingResult对象执行验证.将Errors参数添加到控制器方法,并在发现错误时自定义错误消息.

下面是示例示例,errors.hasErrors()在验证失败时返回true.

@RequestMapping(value = "/user", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<String> saveUser(@Valid @RequestBody User user, Errors errors) {
    if (errors.hasErrors()) {
        return new ResponseEntity(new ApiErrors(errors), HttpStatus.BAD_REQUEST);
    }
    return new ResponseEntity<>(HttpStatus.OK);
}
Run Code Online (Sandbox Code Playgroud)

  • @ksaughs什么是ApiErrors类? (4认同)
  • 方法仍然不够好。我发现让异常被抛出并使用 ExceptionHandling 管理它更方便,就像在 JHipster 中完成的一样(MethodArgumentNotValidException):https://github.com/jgasmi/jhipster/blob/master/src/main/java /com/mycompany/app/web/rest/errors/ExceptionTranslator.java (3认同)
  • @kswaughs,我到处搜索ApiErrors,但找不到任何地方。我还在maven中包括了spring-context依赖项,找不到任何东西。唯一的网络结果是此stackoverflow页面的答案。你能帮忙吗? (2认同)
  • @user6123723 ApiError 类是一个自定义类,它具有您希望客户端接收的消息的数据结构,例如带有状态、代码、异常、错误和时间戳的 json,仅此而已。 (2认同)

Foo*_*ish 6

一种方法是在@NotNull批注中添加消息。

DTO:

public class User {

    @NotNull(message = "User name cannot be empty")
    private String name;

    @NotNull(message = "Password cannot be empty")
    private String password;

    //..
}
Run Code Online (Sandbox Code Playgroud)

控制器:

@RequestMapping(value = "/user", method = RequestMethod.POST)
public ResponseEntity<String> saveUser(@Valid @RequestBody User user) {
    //..
    return new ResponseEntity<>(HttpStatus.OK);
}
// Add one 
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<List<YourErrorResponse>> handleException(MethodArgumentNotValidException ex) {
// Loop through FieldErrors in ex.getBindingResult();
// return *YourErrorReponse* filled using *fieldErrors*
}
Run Code Online (Sandbox Code Playgroud)

  • 指定消息也可用于其他验证,例如“@”模式、“@”min、“@”max。抱歉,我不能说 @ + 某事,因为 stackoverflow 认为我正在尝试指定另一个 stackoverflow 用户。 (2认同)

小智 6

@ControllerAdvice(annotations = RestController.class)
public class GlobalExceptionHandler implements ApplicationContextAware {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ApplicationError validationException(MethodArgumentNotValidException e) {

        e.printStackTrace();
        return new ApplicationError(SysMessageEnum.MSG_005, e.getBindingResult().getAllErrors().get(0).getDefaultMessage());

    }

}
Run Code Online (Sandbox Code Playgroud)


Ash*_*mar 6

要自定义 JSON 格式的错误消息,请执行以下步骤。

- 创建一个名为CommonErrorHandler的@Component

@Component
public class CommonErrorHandler {
public  Map<String,Object> getFieldErrorResponse(BindingResult result){

        Map<String, Object> fielderror = new HashMap<>();
        List<FieldError>errors= result.getFieldErrors();
        for (FieldError error : errors) {
            fielderror.put(error.getField(), error.getDefaultMessage());
        }return fielderror;
    }

     public ResponseEntity<Object> fieldErrorResponse(String message,Object fieldError){
        Map<String, Object> map = new HashMap<>();
        map.put("isSuccess", false);
        map.put("data", null);
        map.put("status", HttpStatus.BAD_REQUEST);
        map.put("message", message);
        map.put("timeStamp", DateUtils.getSysDate());
        map.put("filedError", fieldError);
        return new ResponseEntity<Object>(map,HttpStatus.BAD_REQUEST);
    }
}
Run Code Online (Sandbox Code Playgroud)

-- 添加 InvalidException 类

public class InvalidDataException extends RuntimeException {

/**
 * @author Ashok Parmar
 */
    private static final long serialVersionUID = -4164793146536667139L;

    private BindingResult result;

    public InvalidDataException(BindingResult result) {
        super();
        this.setResult(result);
    }

    public BindingResult getResult() {
        return result;
    }

    public void setResult(BindingResult result) {
        this.result = result;
    }

}
Run Code Online (Sandbox Code Playgroud)

- 引入@ControllerAdvice类

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

@ExceptionHandler(InvalidDataException.class)
    public ResponseEntity<?> invalidDataException(InvalidDataException ex, WebRequest request) {

        List<FieldError> errors = ex.getResult().getFieldErrors();
        for (FieldError error : errors) {
            logger.error("Filed Name ::: " + error.getField() + "Error Message :::" + error.getDefaultMessage());
        }
        return commonErrorHandler.fieldErrorResponse("Error", commonErrorHandler.getFieldErrorResponse(ex.getResult()));
    }
    }
Run Code Online (Sandbox Code Playgroud)

-- 在控制器中使用 @Valid 并抛出异常

public AnyBeans update(**@Valid** @RequestBody AnyBeans anyBeans ,
            BindingResult result) {
        AnyBeans resultStr = null;
        if (result.hasErrors()) {
            **throw new InvalidDataException(result);**
        } else {
                resultStr = anyBeansService.(anyBeans );
                return resultStr;
        }
    }
Run Code Online (Sandbox Code Playgroud)

-- 输出将以 JSON 格式

{
  "timeStamp": 1590500231932,
  "data": null,
  "message": "Error",
  "isSuccess": false,
  "status": "BAD_REQUEST",
  "filedError": {
    "name": "Name is mandatory"
  }
}
Run Code Online (Sandbox Code Playgroud)

希望这会起作用。:-D