webentwicklung-frage-antwort-db.com.de

ResponseEntity mit Ausnahmedetails kann nicht im Frühjahr zurückgegeben werden

Ich habe eine Spring Restful Service- und Spring MVC-Anwendung erstellt.

Restful Service :: Restful Service gibt eine Entität zurück, wenn diese in der DB vorhanden ist. Wenn es nicht vorhanden ist, wird eine benutzerdefinierte Ausnahme in ResponseEntity-Objekt zurückgegeben.

Es funktioniert wie erwartet mit Postman getestet.

@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;
}

Wenn die angeforderte Entität nicht vorhanden ist, kehrt der Restful Service unten zurück.

@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;
}

Wenn ich jedoch den oben genannten Dienst von einer Spring-MVC-Anwendung mit RestTemplate anrufe, gibt er ein gültiges Objekt zurück, falls vorhanden.

Wenn das angeforderte Objekt nicht vorhanden ist, gibt der Restful-Service die Ausnahmeinformationen zurück, erreicht jedoch nicht die aufrufende (Spring-MVC-) Anwendung.

Die Spring MVC-Anwendung ruft den Restful-Webdienst mit der Restvorlage auf

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
Abdul

Dies ist erwartetes Verhalten. Die Restvorlage löst eine Ausnahme aus, wenn der http-Status ein Clientfehler oder ein Serverfehler ist, und gibt die Antwort zurück, wenn der http-Status kein Fehlerstatus ist.

Sie müssen eine Implementierung bereitstellen, um Ihren Fehlerbehandler verwenden zu können, die Antwort auf die Antwortentität zuzuordnen und die Ausnahme auszulösen.

Erstellen Sie eine neue Fehlerausnahmeklasse mit dem Feld ResponseEntity.

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

Benutzerdefinierter Fehlerhandler, der die Fehlerantwort auf ResponseEntity zurückgibt.

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-Konfiguration - Sie müssen den errorHandler von RestTemplate auf ResponseEntityErrorHandler setzen. 

@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;
   }
}

Aufrufmethode

@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();
}
3
Veeram

Versuchen Sie es mit der @ResponseBody-Anmerkung für Ihren Exceptionhandler. z.B:

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

Ich habe Ihre Bewerbung gestartet und funktioniert einwandfrei.

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>

Die Controller-Klasse ist:

@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;
    }
}

und der Test:

@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());
    }
}

Sind Sie sicher, dass die URL, die Sie mit RestTemplate verwenden möchten, korrekt ist?

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

Ihre get-Methode lautet @GetMapping (value = "/ validate/{itemId}" 

Wenn Sie kein Request-Mapping auf Controller-Ebene haben, sollte die URL folgendermaßen lauten:

 http://localhost:8080/validate/1

Ein weiterer Unterschied ist der fehlende @ResponseBody auf Ihrer Controller-Methode.

0
Adina

Sie sollten den benutzerdefinierten Ausnahmehandler verwenden, um Ihren Fall zu beheben. Es sieht aus wie das

@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);
    }

}

Und dein Code sollte eine Ausnahme auslösen, zB:

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

Wenn Sie diesen Fall wieder an anderer Stelle erhalten, werfen Sie einfach eine Ausnahme wie oben. Ihr Handler kümmert sich um den Rest.

Ich hoffe das hilft.

0
David Pham