Spring Boot中金额校验异常处理:是否需自定义异常类?
问题描述
我需要比较两个字段,当余额小于转账金额时,抛出"Amount cannot be less than balance"异常。原本想使用MethodArgumentNotValidException,但这个异常没法直接传入自定义消息:
public void transfer(Request request) { if(sender.getBalance().compareTo(account.getAmount()) < 0) throw new MethodArgumentNotValidException(MESSAGE); // ... }
我已经有全局异常处理器GlobalExceptionHandler,还有处理"Element Not found"或"Element already exists"场景的自定义异常类。那我是否需要实现如下自定义异常?
public class CustomMethodArgumentNotValidException extends RuntimeException { public MethodArgumentNotValidException() { super(); } public NoSuchElementFoundException(String message) { super(message); } }
之后要不要把这个自定义异常加到全局异常处理器里?还是不用自定义,直接用现有方案?
更新内容
全局异常处理器代码
@RestControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { @Override @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY) protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode statusCode, WebRequest request) { ErrorResponse errorResponse = new ErrorResponse(HttpStatus.UNPROCESSABLE_ENTITY.value(), VALIDATION_ERROR); for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) { errorResponse.addValidationError(fieldError.getField(), fieldError.getDefaultMessage()); } return ResponseEntity.unprocessableEntity().body(errorResponse); } @ExceptionHandler(NoSuchElementFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public ResponseEntity<Object> handleNoSuchElementFoundException(NoSuchElementFoundException ex, WebRequest request) { return buildErrorResponse(ex, HttpStatus.NOT_FOUND, request); } @ExceptionHandler(InsufficientFundsException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public ResponseEntity<Object> handleMethodArgumentInvalidException(InsufficientFundsException ex, WebRequest request) { return buildErrorResponse(ex, HttpStatus.BAD_REQUEST, request); } @ExceptionHandler(AuthenticationException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) public ResponseEntity<Object> handleAuthenticationException(AuthenticationException ex, WebRequest request) { return buildErrorResponse(ex, HttpStatus.UNAUTHORIZED, request); } @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ResponseEntity<Object> handleAllUncaughtException(Exception ex, WebRequest request) { return buildErrorResponse(ex, UNKNOWN_ERROR, HttpStatus.INTERNAL_SERVER_ERROR, request); } private ResponseEntity<Object> buildErrorResponse(Exception ex, HttpStatusCode statusCode, WebRequest request) { return buildErrorResponse(ex, ex.getMessage(), statusCode, request); } private ResponseEntity<Object> buildErrorResponse(Exception ex, String message, HttpStatusCode statusCode, WebRequest request) { final ErrorResponse errorResponse = new ErrorResponse(statusCode.value(), message); if (printStackTrace && isTraceOn(request)) { errorResponse.setStackTrace(ExceptionUtils.getStackTrace(ex)); } return ResponseEntity.status(statusCode).body(errorResponse); } private boolean isTraceOn(WebRequest request) { String[] value = request.getParameterValues(TRACE); // TRACE from app properties return Objects.nonNull(value) && value.length > 0 && value[0].contentEquals("true"); } @Override public ResponseEntity<Object> handleExceptionInternal( Exception ex, Object body, HttpHeaders headers, HttpStatusCode statusCode, WebRequest request) { return buildErrorResponse(ex, statusCode, request); } }
自定义异常代码
public class InsufficientFundsException extends RuntimeException { public InsufficientFundsException() { super(); } public InsufficientFundsException(String message) { super(message); } public InsufficientFundsException(String message, Throwable cause) { super(message, cause); } }
解决方案
- 不要使用
MethodArgumentNotValidException:这个异常是Spring专门用于处理@Valid等注解触发的请求参数校验场景,并非业务逻辑校验。它的构造依赖BindingResult等参数,无法直接传入自定义消息,强行使用会混淆异常语义。 - 直接复用已定义的
InsufficientFundsException:这个异常语义明确(余额不足),完全匹配你的业务场景,且你已经在全局异常处理器中配置了对应的处理逻辑,会返回BAD_REQUEST状态码和自定义消息,完全满足需求。 - 修改业务代码:将抛出异常的逻辑替换为:
public void transfer(Request request) { if(sender.getBalance().compareTo(account.getAmount()) < 0) throw new InsufficientFundsException("Amount cannot be less than balance"); // ... }
- 无需额外自定义
CustomMethodArgumentNotValidException:现有InsufficientFundsException已适配全局处理器,无需重复实现。
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

