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();
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();
}
Versuchen Sie es mit der @ResponseBody-Anmerkung für Ihren Exceptionhandler. z.B:
public @ResponseBody ResponseEntity<ExceptionResponse> itemNotFEx(WebRequest webRequest, Exception exception) {... }
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.
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.