Java Spring引导自定义异常处理
我的要求是,如果post请求的JSON无效,我将需要发送400个HTTP响应代码,如果任何字段不可解析,返回状态代码将为422。post请求的示例可以是:Java Spring引导自定义异常处理,java,spring-boot,rest,Java,Spring Boot,Rest,我的要求是,如果post请求的JSON无效,我将需要发送400个HTTP响应代码,如果任何字段不可解析,返回状态代码将为422。post请求的示例可以是: { "amount": "12.3343", "timestamp": "2018-07-17T09:59:51.312Z" } Dto类提供如下: @Data @Builder @NoArgsConstructo
{
"amount": "12.3343",
"timestamp": "2018-07-17T09:59:51.312Z"
}
Dto类提供如下:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TransactionDto {
@NotNull
@Min(0)
private BigDecimal amount;
@NotNull
private LocalDateTime timestamp;
}
这是具有POST请求的控制器
@Slf4j
@RestController
@RequestMapping("/")
@Validated
public class TransactionController {
@Autowired
private TransactionService transactionService;
@Operation(description = "create a transaction using the provided JSON data")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "Create transaction", content = {
@Content(mediaType = "application/json", schema = @Schema(implementation = Transaction.class))}),
@ApiResponse(responseCode = "204", description = "Transaction is older than 60 seconds", content = @Content(mediaType = "application/json")),
@ApiResponse(responseCode = "500", description = MessageConstant.INTERNAL_SERVER_ERROR_MSG, content = @Content)})
@PostMapping(value = "/transactions")
public ResponseEntity<Object> createProperty(@RequestBody @Valid TransactionDto transactionDto) {
try {
final LocalDateTime transactionTimestamp = transactionDto.getTimestamp();
final LocalDateTime localDateTimeNow = LocalDateTime.now(ZoneOffset.UTC);
final long secondsDuration = Duration.between(transactionTimestamp, localDateTimeNow).toSeconds();
final boolean isFuture = transactionTimestamp.isAfter(localDateTimeNow);
if (isFuture) {
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.UNPROCESSABLE_ENTITY,
"Transaction is in future"), new HttpHeaders(), HttpStatus.ACCEPTED);
}
if (secondsDuration > 60) {
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.NO_CONTENT,
"Transaction is older than 60 seconds"), new HttpHeaders(), HttpStatus.NO_CONTENT);
}
final Transaction transaction = transactionService.createTransaction(transactionDto);
return new ResponseEntity<>(transaction, new HttpHeaders(), HttpStatus.CREATED);
} catch (Exception ex) {
log.error(MessageConstant.INTERNAL_SERVER_ERROR_MSG + ex.getMessage());
return new ResponseEntity<>(ApiResponseMessage.getInternalServerError(), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
@Slf4j
@RestController
@请求映射(“/”)
@验证
公共类事务控制器{
@自动连线
私人交易服务交易服务;
@操作(description=“使用提供的JSON数据创建事务”)
@ApiResponses(值={
@ApiResponse(responseCode=“201”,description=“创建事务”,内容={
@内容(mediaType=“application/json”,schema=@schema(implementation=Transaction.class))}),
@ApiResponse(responseCode=“204”,description=“事务超过60秒”,content=@content(mediaType=“application/json”),
@ApiResponse(responseCode=“500”,description=MessageConstant.INTERNAL\u SERVER\u ERROR\u MSG,content=@content)})
@后映射(value=“/transactions”)
public ResponseEntity createProperty(@RequestBody@Valid TransactionDto TransactionDto){
试一试{
final LocalDateTime transactionTimestamp=transactionDto.getTimestamp();
最终LocalDateTime localDateTimeNow=LocalDateTime.now(ZoneOffset.UTC);
final long SecondDuration=Duration.between(transactionTimestamp,localDateTimeNow).toSeconds();
最终布尔值isFuture=transactionTimestamp.isAfter(localDateTimeNow);
如果(未来){
返回新的ResponseEntity(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE,HttpStatus.UNPROCESSABLE_实体,
“交易在未来”),新的HttpHeaders(),HttpStatus.ACCEPTED);
}
如果(秒持续时间>60){
返回新的ResponseEntity(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE,HttpStatus.NO_内容,
“事务已超过60秒”),新的HttpHeaders(),HttpStatus.NO_内容);
}
最终事务=transactionService.createTransaction(transactionDto);
返回新的ResponseEntity(事务,新的HttpHeaders(),HttpStatus.CREATED);
}捕获(例外情况除外){
log.error(MessageConstant.INTERNAL_SERVER_error_MSG+ex.getMessage());
返回新的ResponseEntity(ApiResponseMessage.getInternalServerError(),new HttpHeaders(),HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
如果“金额”是,比如说,“sfdfd”,这不是大小数,我们应该提供422。但如果“金额”为“-12.3343”,则这是约束验证错误,但数据有效且可分析。所以我们不能用422
这是我的异常处理类
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@Override
@Nonnull
protected ResponseEntity<Object> handleMissingServletRequestParameter(
MissingServletRequestParameterException ex,
@Nonnull HttpHeaders headers,
@Nonnull HttpStatus status,
@Nonnull WebRequest request
) {
String error = ex.getParameterName() + " parameter is missing";
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.BAD_REQUEST,
error), new HttpHeaders(), HttpStatus.BAD_REQUEST);
}
@Override
@Nonnull
protected ResponseEntity<Object> handleHttpMediaTypeNotSupported(
@Nonnull HttpMediaTypeNotSupportedException ex,
@Nonnull HttpHeaders headers,
@Nonnull HttpStatus status,
@Nonnull WebRequest request
) {
String message = prepareMessageFromException(ex, (ServletWebRequest) request);
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.UNSUPPORTED_MEDIA_TYPE,
" media type is not supported. Supported media types "), new HttpHeaders(), HttpStatus.UNSUPPORTED_MEDIA_TYPE);
}
@Override
@NonNull
protected ResponseEntity<Object> handleMethodArgumentNotValid(
@NonNull MethodArgumentNotValidException ex,
@NonNull HttpHeaders headers,
@NonNull HttpStatus status,
@NonNull WebRequest request
) {
String message = prepareMessageFromException(ex, (ServletWebRequest) request);
ApiErrorResponse apiError = new ApiErrorResponse(BAD_REQUEST);
apiError.setMessage("Validation error");
apiError.addValidationErrors(ex.getBindingResult().getFieldErrors());
apiError.addValidationError(ex.getBindingResult().getGlobalErrors());
return buildResponseEntity(apiError);
}
@ExceptionHandler(ConstraintViolationException.class)
protected ResponseEntity<Object> handleConstraintViolation(ConstraintViolationException ex) {
ApiErrorResponse apiError = new ApiErrorResponse(BAD_REQUEST);
apiError.setMessage("Validation error");
apiError.addValidationErrors(ex.getConstraintViolations());
return buildResponseEntity(apiError);
}
@ExceptionHandler(Exception.class)
@ResponseBody
public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
ServletWebRequest req = (ServletWebRequest) request;
String message = prepareMessageFromException(ex, (ServletWebRequest) request);
log.info("{} to {}", req.getHttpMethod(), req.getRequest().getServletPath());
log.error(message, ex);
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.BAD_REQUEST,
message), new HttpHeaders(), HttpStatus.BAD_REQUEST);
}
@Override
@Nonnull
protected ResponseEntity<Object> handleHttpMessageNotReadable(
@Nonnull HttpMessageNotReadableException ex,
@Nonnull HttpHeaders headers,
@Nonnull HttpStatus status,
@Nonnull WebRequest request
) {
String message = prepareMessageFromException(ex, (ServletWebRequest) request);
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, BAD_REQUEST,
message), new HttpHeaders(), HttpStatus.BAD_REQUEST);
}
private String prepareMessageFromException(Exception ex, ServletWebRequest request) {
String message = ex.getMessage();
log.info("{} to {}", request.getHttpMethod(), request.getRequest().getServletPath());
log.error(message);
if (message != null && !message.isEmpty()) {
message = message.split(":")[0];
}
return message;
}
@Override
@Nonnull
protected ResponseEntity<Object> handleHttpMessageNotWritable(
@Nonnull HttpMessageNotWritableException ex,
@Nonnull HttpHeaders headers,
@Nonnull HttpStatus status,
@Nonnull WebRequest request
) {
String error = "Error writing JSON output";
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.INTERNAL_SERVER_ERROR,
"Internal server error. please contact support !!"), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
}
@Override
@Nonnull
protected ResponseEntity<Object> handleNoHandlerFoundException(
NoHandlerFoundException ex,
@Nonnull HttpHeaders headers,
@Nonnull HttpStatus status,
@Nonnull WebRequest request
) {
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.BAD_REQUEST,
String.format("Could not find the %s method for URL %s", ex.getHttpMethod(), ex.getRequestURL())), new HttpHeaders(), HttpStatus.BAD_REQUEST);
}
private ResponseEntity<Object> buildResponseEntity(ApiErrorResponse apiError) {
return new ResponseEntity<>(apiError, apiError.getStatus());
}
@ExceptionHandler(EntityNotFoundException.class)
protected ResponseEntity<Object> handleEntityNotFound(EntityNotFoundException ex) {
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.NOT_FOUND,
"Resource not found: "), new HttpHeaders(), HttpStatus.NOT_FOUND);
}
@ExceptionHandler(DataIntegrityViolationException.class)
protected ResponseEntity<Object> handleDataIntegrityViolation(DataIntegrityViolationException ex, WebRequest request) {
if (ex.getCause() instanceof ConstraintViolationException) {
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.CONFLICT,
"Database error"), new HttpHeaders(), HttpStatus.CONFLICT);
}
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.INTERNAL_SERVER_ERROR,
"Internal server error. please contact support !!" + ex.getMessage()), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
protected ResponseEntity<Object> handleMethodArgumentTypeMismatch(MethodArgumentTypeMismatchException ex, WebRequest request) {
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.BAD_REQUEST,
String.format("The parameter '%s' of value '%s' could not be converted to type '%s'", ex.getName(), ex.getValue(), ex.getRequiredType())), new HttpHeaders(), HttpStatus.BAD_REQUEST);
}
}
@Slf4j
@控制器建议
公共类GlobalExceptionHandler扩展了ResponseEntityExceptionHandler{
@凌驾
@非空
受保护的ResponseEntity handleMissingServletRequestParameter(
缺少ServletRequestParameterException ex,
@非空HttpHeaders,
@非空HttpStatus状态,
@非空WebRequest请求
) {
字符串错误=例如getParameterName()+“缺少参数”;
返回新的ResponseEntity(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE,HttpStatus.BAD_请求,
错误),新的HttpHeaders(),HttpStatus.BAD_请求);
}
@凌驾
@非空
受保护的响应handleHttpMediaTypeNotSupported(
@非Null HttpMediaTypeNotSupportedException ex,
@非空HttpHeaders,
@非空HttpStatus状态,
@非空WebRequest请求
) {
字符串消息=prepareMessageFromException(例如,(ServletWebRequest)请求);
返回新的ResponseEntity(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE,HttpStatus.UNSUPPORTED_MEDIA_TYPE,
“不支持媒体类型。支持的媒体类型”),新的HttpHeaders(),HttpStatus。不支持的媒体类型);
}
@凌驾
@非空
受保护的响应句柄方法无效(
@非Null MethodArgumentNotValidException ex,
@非空HttpHeaders,
@非空HttpStatus状态,
@非空WebRequest请求
) {
字符串消息=prepareMessageFromException(例如,(ServletWebRequest)请求);
ApiErrorResponse apiError=新的ApiErrorResponse(错误的请求);
setMessage(“验证错误”);
addValidationErrors(例如getBindingResult().getFieldErrors());
apiError.addValidationError(例如getBindingResult().getGlobalErrors());
返回buildResponseEntity(apiError);
}
@ExceptionHandler(ConstraintViolationException.class)
受保护的响应性句柄约束约束约束约束(约束约束约束异常ex){
ApiErrorResponse apiError=新的ApiErrorResponse(错误的请求);
setMessage(“验证错误”);
apierro.addValidationErrors(例如getConstraintViolations());
返回buildResponseEntity(apiError);
}
@ExceptionHandler(Exception.class)
@应答器
公共最终响应处理异常(异常,例如WebRequest请求){
ServletWebRequest req=(ServletWebRequest)请求;
字符串消息=prepareMessageFromException(例如,(ServletWebRequest)请求);
log.info(“{}到{}”,req.getHttpMethod(),req.getRequest().getServletPath());
日志错误(消息,ex);
返回新的ResponseEntity(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE,HttpStatus.BAD_请求,
消息),新的HttpHeaders(),HttpStatus.BAD_请求);
}
@凌驾
@非空
受保护的响应可处理HttpMessageTreadable(
@非Null HttpMessageTreadableException ex,
@非空HttpHeaders,
@非空HttpStatus状态,
@Override
@Nonnull
protected ResponseEntity<Object> handleHttpMessageNotReadable(
@Nonnull HttpMessageNotReadableException ex,
@Nonnull HttpHeaders headers,
@Nonnull HttpStatus status,
@Nonnull WebRequest request
) {
String message = prepareMessageFromException(ex, (ServletWebRequest) request);
final Throwable throwableCause = ex.getCause();
if (throwableCause instanceof InvalidFormatException) {
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.UNPROCESSABLE_ENTITY,
message), new HttpHeaders(), HttpStatus.UNPROCESSABLE_ENTITY);
}
return new ResponseEntity<>(ApiResponseMessage.getGenericApiResponse(Boolean.FALSE, HttpStatus.BAD_REQUEST,
message), new HttpHeaders(), HttpStatus.BAD_REQUEST);
}