Не удалось вернуть ResponseEntity с деталями исключения весной - PullRequest
0 голосов
/ 05 сентября 2018

Я создал приложение Spring Restful Service и Spring MVC.

Restful Service :: Служба Restful возвращает сущность, если она существует в БД. Если он не существует, он возвращает пользовательскую информацию об исключении в объекте ResponseEntity.

Работает, как и ожидалось, протестировано с почтальоном.

@GetMapping(value = "/validate/{itemId}", produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
public ResponseEntity<MyItem> validateItem(@PathVariable Long itemId, @RequestHeader HttpHeaders httpHeaders) {

    MyItem myItem = myitemService.validateMyItem(itemId);
    ResponseEntity<MyItem> responseEntity = null;
    if (myItem == null) {
        throw new ItemNotFoundException("Item Not Found!!!!");
    }
    responseEntity = new ResponseEntity<MyItem>(myItem, headers, HttpStatus.OK);
    return responseEntity;
}

Если запрошенная сущность не существует, Restful Service возвращается ниже.

@ExceptionHandler(ItemNotFoundException.class)
public ResponseEntity<ExceptionResponse> itemNotFEx(WebRequest webRequest, Exception exception) {
    System.out.println("In CREEH::ItemNFE");
    ExceptionResponse exceptionResponse = new ExceptionResponse("Item Not Found Ex!!!", new Date(), webRequest.getDescription(false));
    ResponseEntity<ExceptionResponse> responseEntity = new ResponseEntity<ExceptionResponse>(exceptionResponse, HttpStatus.NOT_FOUND);
    return responseEntity;
}

Но когда я вызываю вышеуказанную службу из весеннего приложения MVC, используя RestTemplate, он возвращает действительный объект, если он существует.

Если запрошенный объект не существует, служба Restful возвращает информацию об исключении, но не достигает вызывающего приложения (spring MVC).

Приложение Spring MVC вызывает Restful Web Service с использованием шаблона Rest

String url = "http://localhost:8080/ItemServices/items/validate/{itemId}";
ResponseEntity<Object> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, Object.class, uriParms);
int restCallStateCode = responseEntity.getStatusCodeValue();

Ответы [ 4 ]

0 голосов
/ 28 сентября 2018

Это ожидаемое поведение. Шаблон Rest выдает исключение, когда http-статусом является ошибка клиента или сервера, и возвращает ответ, если http-статус не является ошибкой.

Вы должны предоставить реализацию для использования вашего обработчика ошибок, сопоставить ответ с сущностью ответа и выдать исключение.

Создайте новый класс исключений ошибок с полем ResponseEntity.

public class ResponseEntityErrorException extends RuntimeException {
  private ResponseEntity<ErrorResponse> errorResponse;
  public ResponseEntityErrorException(ResponseEntity<ErrorResponse> errorResponse) {
      this.errorResponse = errorResponse;
  }
  public ResponseEntity<ErrorResponse> getErrorResponse() {
      return errorResponse;
  }
}

Пользовательский обработчик ошибок, который отображает ответ об ошибке обратно в ResponseEntity.

public class ResponseEntityErrorHandler implements ResponseErrorHandler {

  private List<HttpMessageConverter<?>> messageConverters;

  @Override
  public boolean hasError(ClientHttpResponse response) throws IOException {
    return hasError(response.getStatusCode());
  }

  protected boolean hasError(HttpStatus statusCode) {
    return (statusCode.is4xxClientError() || statusCode.is5xxServerError());
  }

  @Override
  public void handleError(ClientHttpResponse response) throws IOException {
    HttpMessageConverterExtractor<ExceptionResponse> errorMessageExtractor =
      new HttpMessageConverterExtractor(ExceptionResponse.class, messageConverters);
    ExceptionResponse errorObject = errorMessageExtractor.extractData(response);
    throw new ResponseEntityErrorException(ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).body(errorObject));
  }

  public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
    this.messageConverters = messageConverters;
  }
}

Конфигурация RestTemplate. Необходимо установить ErrorHandler для RestTemplate равным ResponseEntityErrorHandler.

@Configuration
public class RestTemplateConfiguration {
  @Bean
  public RestTemplate restTemplate() {
      RestTemplate restTemplate = new RestTemplate();
      ResponseEntityErrorHandler errorHandler = new ResponseEntityErrorHandler();
      errorHandler.setMessageConverters(restTemplate.getMessageConverters());
      restTemplate.setErrorHandler(errorHandler); 
      return restTemplate;
   }
}

Метод вызова

@Autowired restTemplate

String url = "http://localhost:8080/ItemServices/items/validate/{itemId}";
try {
    ResponseEntity<Object> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, Object.class, uriParms);
    int restCallStateCode = responseEntity.getStatusCodeValue();
} catch (ResponseEntityErrorException re) {
    ResponseEntity<ErrorResponse> errorResponse = re.getErrorResponse();
}
0 голосов
/ 28 сентября 2018

Я запустил ваше приложение и отлично работает.

Maven:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

Класс контроллера:

@Controller
public class ValidationController {


    @GetMapping(value = "/validate/{itemId}")
    public @ResponseBody ResponseEntity<MyItem> validateItem(@PathVariable Long itemId) {
        if (itemId.equals(Long.valueOf(1))) {
            throw new ItemNotFoundException();
        }
        return new ResponseEntity<>(new MyItem(), HttpStatus.OK);
    }

    @ExceptionHandler(ItemNotFoundException.class)
    public ResponseEntity<ExceptionResponse> itemNotFEx(WebRequest webRequest, Exception exception) {
        System.out.println("In CREEH::ItemNFE");
        ExceptionResponse exceptionResponse = new ExceptionResponse("Item Not Found Ex!!!", new Date(), webRequest.getDescription(false));
        ResponseEntity<ExceptionResponse> responseEntity = new ResponseEntity<>(exceptionResponse, HttpStatus.NOT_FOUND);
        return responseEntity;
    }
}

и тест:

@RunWith(SpringRunner.class)
@WebMvcTest(value = ValidationController.class, secure = false)

public class TestValidationController {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testExpectNotFound() throws Exception {
        mockMvc.perform(get("/validate/1"))
                .andExpect(status().isNotFound());
    }

    @Test
    public void testExpectFound() throws Exception {
        mockMvc.perform(get("/validate/2"))
                .andExpect(status().isOk());
    }
}

Вы уверены, что URL, который вы пытаетесь использовать с RestTemplate, правильный?

 String url = "http://localhost:8080/ItemServices/items/validate/{itemId}";

Ваш метод get - @GetMapping (value = "/ validate / {itemId}"

Если у вас нет отображения запросов на уровне контроллера, URL должен быть:

 http://localhost:8080/validate/1

Другим отличием является отсутствие @ResponseBody в вашем методе контроллера.

0 голосов
/ 28 сентября 2018

Вы должны использовать Custom Exception Handler, чтобы исправить ваш случай. Похоже, это

@ControllerAdvice
public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

    public CustomResponseEntityExceptionHandler() {
        super();
    }
    // 404
    @ExceptionHandler(value = { EntityNotFoundException.class, ResourceNotFoundException.class })
    protected ResponseEntity<Object> handleNotFound(final RuntimeException ex, final WebRequest request) {      
        BaseResponse responseError = new BaseResponse(HttpStatus.NOT_FOUND.value(),HttpStatus.NOT_FOUND.name(),
                Constants.HttpStatusMsg.ERROR_NOT_FOUND);       
        logger.error(ex.getMessage());
        return handleExceptionInternal(ex, responseError, new HttpHeaders(), HttpStatus.NOT_FOUND, request);
    }

}

И ваш код должен выдать какое-то исключение, например:

if (your_entity == null) {
    throw new EntityNotFoundException("said something");
}

Если вы снова попадете в это дело, вы просто выбросите исключение, как описано выше. Ваш обработчик позаботится обо всем остальном.

Надеюсь, что это поможет.

0 голосов
/ 05 сентября 2018

Попробуйте использовать аннотацию @ResponseBody в вашем Exceptionhandler. например:

public @ResponseBody ResponseEntity<ExceptionResponse> itemNotFEx(WebRequest webRequest, Exception exception) {... }
...