无法 return ResponseEntity 异常详细信息在 spring
Not able to return ResponseEntity with Exception Details in spring
我创建了 Spring Restful 服务和 Spring MVC 应用程序。
Restful服务::
Restful 服务 returns 一个实体,如果它存在于数据库中。如果不存在它 returns ResponseEntity 对象中的自定义异常信息。
使用 Postman 测试,它按预期工作。
@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 下面的服务 returns。
@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;
}
但是当我使用 RestTemplate 从 spring MVC 应用程序调用上述服务时,它返回一个有效对象(如果存在)。
如果请求的对象不存在Restful服务正在返回异常信息但它没有到达调用(spring MVC)应用程序。
Spring MVC 应用程序调用 Restful 使用 Rest 模板的 Web 服务
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();
尝试在异常处理程序上使用@ResponseBody 注释。例如:
public @ResponseBody ResponseEntity<ExceptionResponse> itemNotFEx(WebRequest webRequest, Exception exception) {... }
我已经启动了您的应用程序并且运行良好。
行家:
<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>
控制器 class 是:
@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());
}
}
您确定您尝试与 RestTemplate 一起使用的 url 是正确的吗?
String url = "http://localhost:8080/ItemServices/items/validate/{itemId}";
你的get方法是@GetMapping(value = "/validate/{itemId}"
如果您在控制器级别没有请求映射,url 应该是:
http://localhost:8080/validate/1
另一个区别是控制器方法中缺少@ResponseBody。
您应该使用自定义异常处理程序来解决您的问题。看起来像这样
@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");
}
如果你在其他地方再次遇到这种情况,你就像上面那样抛出异常。你的经纪人会处理剩下的事情。
希望对您有所帮助。
这是预期的行为。 Rest 模板在 http 状态为客户端错误或服务器错误时抛出异常,returns 当 http 状态不是错误状态时响应。
您必须提供实现才能使用您的错误处理程序,将响应映射到响应实体并抛出异常。
使用 ResponseEntity 字段创建新的错误异常 class。
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 配置 - 您必须将 RestTemplate 的 errorHandler 设置为 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();
}
我创建了 Spring Restful 服务和 Spring MVC 应用程序。
Restful服务:: Restful 服务 returns 一个实体,如果它存在于数据库中。如果不存在它 returns ResponseEntity 对象中的自定义异常信息。
使用 Postman 测试,它按预期工作。
@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 下面的服务 returns。
@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;
}
但是当我使用 RestTemplate 从 spring MVC 应用程序调用上述服务时,它返回一个有效对象(如果存在)。
如果请求的对象不存在Restful服务正在返回异常信息但它没有到达调用(spring MVC)应用程序。
Spring MVC 应用程序调用 Restful 使用 Rest 模板的 Web 服务
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();
尝试在异常处理程序上使用@ResponseBody 注释。例如:
public @ResponseBody ResponseEntity<ExceptionResponse> itemNotFEx(WebRequest webRequest, Exception exception) {... }
我已经启动了您的应用程序并且运行良好。
行家:
<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>
控制器 class 是:
@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());
}
}
您确定您尝试与 RestTemplate 一起使用的 url 是正确的吗?
String url = "http://localhost:8080/ItemServices/items/validate/{itemId}";
你的get方法是@GetMapping(value = "/validate/{itemId}"
如果您在控制器级别没有请求映射,url 应该是:
http://localhost:8080/validate/1
另一个区别是控制器方法中缺少@ResponseBody。
您应该使用自定义异常处理程序来解决您的问题。看起来像这样
@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");
}
如果你在其他地方再次遇到这种情况,你就像上面那样抛出异常。你的经纪人会处理剩下的事情。
希望对您有所帮助。
这是预期的行为。 Rest 模板在 http 状态为客户端错误或服务器错误时抛出异常,returns 当 http 状态不是错误状态时响应。
您必须提供实现才能使用您的错误处理程序,将响应映射到响应实体并抛出异常。
使用 ResponseEntity 字段创建新的错误异常 class。
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 配置 - 您必须将 RestTemplate 的 errorHandler 设置为 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();
}