#java #reactjs #spring
#java #reactjs #весна
Вопрос:
Я подключил приложения Spring к интерфейсу React, где мне нужно отобразить мои пользовательские исключения. Пользовательские исключения отлично работают в Spring, но интерфейс (React) получает только код ошибки (417) и ничего больше.
Я определил, что проблема заключается в том, что исключение не возвращается в формате JSON, потому что сообщение об ошибке отображается полностью, когда я использую Postman, но не в формате JSON.
Мое исследование показало, что, поскольку я использую @RestController (для моего основного контроллера) и @ControllerAdvice (для моего пользовательского обработчика исключений), он должен возвращаться в формате JSON. Я также попытался добавить компонент ResponseBody к конкретной функции, но это тоже не помогло.
Controller.java
package com.chess.controller;
import com.chess.board.*;
import com.chess.gameflow.Game;
import com.chess.gameflow.Move;
import com.chess.gameflow.Player;
import com.chess.gameflow.Status;
import com.chess.models.requests.BoardRequest;
import com.chess.models.requests.PlayerRequest;
import com.chess.models.requests.StatusRequest;
import com.chess.models.responses.MovesResponse;
import com.chess.models.responses.Response;
import com.chess.models.responses.StatusResponse;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@CrossOrigin(origins= "http://localhost:3000", maxAge=7200)
@RestController
@RequestMapping("/game")
public class Controller {
Game game;
Board board = Board.boardConstructor();
@PostMapping("/players")
public List<Response> createPlayer(@RequestBody PlayerRequest request){
game = new Game(request.getName1(), request.getName2());
List<Response> returnValue = board.returnBoard();
Player player1= Game.players[0];
StatusResponse status = new StatusResponse(Status.isActive(), Status.isCheck(), player1);
returnValue.add(status);
return returnValue;
}
@PostMapping
public List<Response> makeMove(@RequestBody BoardRequest boardRequest){
StatusResponse status = Game.run(boardRequest);
List<Response> returnValue = board.returnBoard();
returnValue.add(status);
return returnValue;
}
@PostMapping("/end")
public StatusResponse endGame(@RequestBody StatusRequest statusRequest){
Status.setActive(false);
Board board = Board.boardConstructor();
board.generateBoard();
if (statusRequest.isForfeit()){
StatusResponse statusResponse = new StatusResponse(statusRequest.getPlayerName() " declares defeat! Game Over!");
return statusResponse;
}
StatusResponse statusResponse = new StatusResponse("We have a draw! Good Game!");
return statusResponse;
}
@GetMapping("/moves")
public MovesResponse displayMoves(){
MovesResponse movesResponse = new MovesResponse(Move.returnMoveMessages());
return movesResponse;
}
}
CustomExceptionsHandler.java
package com.chess.exceptions;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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 org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@ControllerAdvice
public class CustomExceptionsHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = InvalidMoveException.class)
@ResponseBody //this line shouldn't be necessary as I am using a RestController but I added it anyways in one of my futile attempts and I don't think it should hurt
protected ResponseEntity<Object> resolveInvalidMove(InvalidMoveException e, WebRequest req) throws Exception {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.EXPECTATION_FAILED.value(),
HttpStatus.EXPECTATION_FAILED.getReasonPhrase(),
e.getMessage(),
req.getDescription(true));
return handleExceptionInternal(e, errorResponse.toString(), new HttpHeaders(), HttpStatus.EXPECTATION_FAILED, req);
@ExceptionHandler(value = MustDefeatCheckException.class)
protected ResponseEntity<Object> resolveCheckStatus(MustDefeatCheckException e, WebRequest req){
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.EXPECTATION_FAILED.value(),
HttpStatus.EXPECTATION_FAILED.getReasonPhrase(),
e.getMessage(),
req.getDescription(true));
return handleExceptionInternal(e, errorResponse, new HttpHeaders(), HttpStatus.EXPECTATION_FAILED, req);
}
}
ErrorResponse.java
package com.chess.exceptions;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "error")
public class ErrorResponse {
private int status;
private String errReason;
private String errMessage;
private String path;
public ErrorResponse(int status, String errReason, String errMessage, String path) {
this.status = status;
this.errReason = errReason;
this.errMessage = errMessage;
this.path = path;
}
@Override
public String toString(){
return "Status Code: " status " " errReason " Message: " errMessage " at " path;
}
}
InvalidMoveException.java
package com.chess.exceptions;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.EXPECTATION_FAILED, reason="Invalid Move")
public class InvalidMoveException extends RuntimeException {
public InvalidMoveException(String msg){ super(msg); }
}
Ответ №1:
Я решил половину проблемы. Вместо того, чтобы возвращать ResponseEntity с помощью handleExceptionInternal , я смог вернуть сам ErrorResponse, сделав его дочерним элементом Response, который является отцом всех моих обычных ответов.
Итак, теперь мой CustomExceptionsHandler.java выглядит так-
@RestControllerAdvice
public class CustomExceptionsHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = InvalidMoveException.class)
@ResponseStatus(HttpStatus.EXPECTATION_FAILED)
public ErrorResponse resolveInvalidMove(InvalidMoveException e, WebRequest req) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.EXPECTATION_FAILED.value(),
HttpStatus.EXPECTATION_FAILED.getReasonPhrase(),
e.getMessage(),
req.getDescription(true));
return errorResponse;
}
}
И я получаю исключение в формате JSON, когда я использую Postman. Однако моя ошибка в
Реакция не изменилась. Я все еще получаю только код состояния и никакой другой информации.
Board.js
DataService.makeMove(move)
.then(res => {
//console.log(res.data);
setIsWhite((prev) => !prev);
props.setTheBoard(res.data);
setStatus(res.data[64]);
updateMovesList();
})
.catch(err => {
console.log(err)
console.log(err.errMessage)
console.log(err.message)
console.log(err.status)
console.log(err.errReason)
})
DataService.js
makeMove(move){
return axios.post(`${url}`, move);
}
Я всегда думал, что перехватывать ошибки очень просто, но, видимо, я чего-то не хватает