我有一个休息服务,在找不到资源时发送404错误。 这里是我的控制器的源代码和发送Http 404的异常。
@Controller
@RequestMapping("/site")
public class SiteController
{
@Autowired
private IStoreManager storeManager;
@RequestMapping(value = "/stores/{pkStore}", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public StoreDto getStoreByPk(@PathVariable long pkStore) {
Store s = storeManager.getStore(pkStore);
if (null == s) {
throw new ResourceNotFoundException("no store with pkStore : " + pkStore);
}
return StoreDto.entityToDto(s);
}
}
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException
{
private static final long serialVersionUID = -6252766749487342137L;
public ResourceNotFoundException(String message) {
super(message);
}
}
当我尝试使用RestTemplate使用此代码调用它时:
ResponseEntity<StoreDto> r = restTemplate.getForEntity(url, StoreDto.class, m);
System.out.println(r.getStatusCode());
System.out.println(r.getBody());
我收到此例外:
org.springframework.web.client.RestTemplate handleResponseError
ATTENTION: GET request for "http://........./stores/99" resulted in 404 (Introuvable); invoking error handler
org.springframework.web.client.HttpClientErrorException: 404 Introuvable
我在想我可以探索我的responseEntity对象并使用statusCode做一些事情。但例外是启动,我的应用程序停止运行。
是否有特定的配置让restTemplate不发送异常但填充我的ResponseEntity。
非常感谢您的帮助。
-
卢瓦克
答案 0 :(得分:32)
据我所知,您无法获得实际的ResponseEntity,但可以从异常中获取状态代码和正文(如果有):
try {
ResponseEntity<StoreDto> r = restTemplate.getForEntity(url, StoreDto.class, m);
}
catch (final HttpClientErrorException e) {
System.out.println(e.getStatusCode());
System.out.println(e.getResponseBodyAsString());
}
答案 1 :(得分:13)
REST模板在IMO这个领域非常缺乏。这里有一篇很好的博客文章,说明当你收到错误时如何提取回复正文:
截至今天,有一个杰出的JIRA请求,模板提供了提取响应主体的可能性:
https://jira.spring.io/browse/SPR-10961
蹲下贝尔斯答案的麻烦在于你必须查询catch区块内的状态代码,例如,如果你只是想要处理404&#39>
以下是我在上一个项目中解决这个问题的方法。可能有更好的方法,我的解决方案根本无法提取ResponseBody。
public class ClientErrorHandler implements ResponseErrorHandler
{
@Override
public void handleError(ClientHttpResponse response) throws IOException
{
if (response.getStatusCode() == HttpStatus.NOT_FOUND)
{
throw new ResourceNotFoundException();
}
// handle other possibilities, then use the catch all...
throw new UnexpectedHttpException(response.getStatusCode());
}
@Override
public boolean hasError(ClientHttpResponse response) throws IOException
{
return response.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR
|| response.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR;
}
ResourceNotFoundException和UnexpectedHttpException是我自己的未经检查的异常。
创建其余模板的时间:
RestTemplate template = new RestTemplate();
template.setErrorHandler(new ClientErrorHandler());
现在我们在提出请求时会得到稍微整洁的构造:
try
{
HttpEntity response = template.exchange("http://localhost:8080/mywebapp/customer/100029",
HttpMethod.GET, requestEntity, String.class);
System.out.println(response.getBody());
}
catch (ResourceNotFoundException e)
{
System.out.println("Customer not found");
}
答案 2 :(得分:7)
自2018年以来,我希望当人们说'春天&#34;他们实际上意味着&#34; Spring Boot&#34;至少,我想用较少尘埃覆盖的方法来扩展给定的答案。
之前答案中提到的所有内容都是正确的 - 您需要使用自定义ResponseErrorHandler
。
现在,在Spring Boot世界中,配置它的方式比以前简单一些。
有一个名为RestTemplateBuilder
的方便的类。如果您阅读其java文档的第一行,它会说:
可用于配置和创建RestTemplate的构建器。 提供方便的方法来注册转换器,错误处理程序 和UriTemplateHandlers。
它实际上只有一种方法:
new RestTemplateBuilder().errorHandler(new DefaultResponseErrorHandler()).build();
最重要的是,Spring们很久以前就意识到了传统RestTemplate
的缺点,以及它在测试中会如何特别痛苦。他们创建了一个方便的类TestRestTemplate
,它作为RestTemplate
的包装器,并将其errorHandler设置为空实现:
private static class NoOpResponseErrorHandler extends
DefaultResponseErrorHandler {
@Override
public void handleError(ClientHttpResponse response) throws IOException {
}
}
答案 3 :(得分:1)
您可以创建自己的RestTemplate包装器,它不会抛出异常,但会返回带有接收状态代码的响应。 (您也可以返回正文,但这样会停止对类型安全,因此在下面的代码中,正文只是null
。)
/**
* A Rest Template that doesn't throw exceptions if a method returns something other than 2xx
*/
public class GracefulRestTemplate extends RestTemplate {
private final RestTemplate restTemplate;
public GracefulRestTemplate(RestTemplate restTemplate) {
super(restTemplate.getMessageConverters());
this.restTemplate = restTemplate;
}
@Override
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException {
return withExceptionHandling(() -> restTemplate.getForEntity(url, responseType));
}
@Override
public <T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException {
return withExceptionHandling(() -> restTemplate.postForEntity(url, request, responseType));
}
private <T> ResponseEntity<T> withExceptionHandling(Supplier<ResponseEntity<T>> action) {
try {
return action.get();
} catch (HttpClientErrorException ex) {
return new ResponseEntity<>(ex.getStatusCode());
}
}
}
答案 4 :(得分:0)
最近有一个用例。我的解决方案:
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
答案 5 :(得分:0)
Spring框架中没有实现ResponseErrorHandler的类,所以我只声明了一个bean:
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplateBuilder()
.errorHandler(new DefaultResponseErrorHandler() {
@Override
public void handleError(ClientHttpResponse response) throws IOException {
//do nothing
}
})
.build();
}