DTO:
public class User {
@NotNull
private String name;
@NotNull
private String password;
//..
}
控制器:
@RequestMapping(value = "/user", method = RequestMethod.POST)
public ResponseEntity<String> saveUser(@Valid @RequestBody User user) {
//..
return new ResponseEntity<>(HttpStatus.OK);
}
默认的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"}
我想为每个错误发生我的自定义json。我该如何做到这一点?
答案 0 :(得分:34)
如果要完全控制每个控制器中的响应消息,请写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;
}
}
}
答案 1 :(得分:19)
您可以使用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);
}
答案 2 :(得分:17)
我知道这是一个老问题,
但是我遇到了它,我找到了一些非常好的article,它在github中也有一个完美的例子。
基本上它使用@ControllerAdvice
作为Spring文档建议。
因此,例如,通过覆盖一个函数来捕获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);
}
}
(ApiError类是一个保存状态,消息,错误的简单对象)
答案 3 :(得分:4)
一种方法是在@NotNull注释中添加消息。
DTO:
public class User {
@NotNull(message = "User name cannot be empty")
private String name;
@NotNull(message = "Password cannot be empty")
private String password;
//..
}
控制器:
@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*
}
答案 4 :(得分:2)
$_.DisplayRoot -match '\\\\'
答案 5 :(得分:2)
要自定义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);
}
}
-添加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;
}
}
-介绍@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()));
}
}
-在具有@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;
}
}
-输出将为JSON格式
{
"timeStamp": 1590500231932,
"data": null,
"message": "Error",
"isSuccess": false,
"status": "BAD_REQUEST",
"filedError": {
"name": "Name is mandatory"
}
}
希望这会起作用。 :-D
答案 6 :(得分:1)
@PayloadRoot(namespace = NAMESPACE, localPart = "getAmount")
@ResponsePayload
public JAXBElement<GetAmountResponse> getAmount(@RequestPayload JAXBElement<GetAmount> request) {
...
}
答案 7 :(得分:1)
也添加一些信息。
如果仅使用@Valid
,则需要捕获BindException
。如果您使用@Valid @RequestBody
抓住MethodArgumentNotValidException
某些来源:
HandlerMethodArgumentResolverComposite.getArgumentResolver(MethodParameter parameter):129
-搜索哪个HandlerMethodArgumentResolver支持此类参数
RequestResponseBodyMethodProcessor.supportsParameter(MethodParameter parameter)
-如果参数具有注释,则返回true @RequestBody
RequestResponseBodyMethodProcessor:139
-抛出MethodArgumentNotValidException
ModelAttributeMethodProcessor:164
-引发BindException
答案 8 :(得分:0)
{
"message": "string",
"errors": [
{
"field": "string",
"message": "string",
"error_code": "string"
}
],
"resource": "string",
"description": "string"
}
答案 9 :(得分:0)
您可以执行以下操作
@ExceptionHandler(value = MethodArgumentNotValidException.class)
protected ResponseEntity<Error> handleGlobalExceptions(MethodArgumentNotValidException ex,
WebRequest request) {
log.catching(ex);
return new ResponseEntity<>(createErrorResp(HttpStatus.BAD_REQUEST,
ex.getBindingResult().getFieldErrors().stream().map(err -> err.getDefaultMessage())
.collect(java.util.stream.Collectors.joining(", "))),
HttpStatus.BAD_REQUEST);
}