【发布时间】:2019-02-21 10:31:14
【问题描述】:
Tl;博士;
我在 Spring-Boot 中有一个 REST 控制器,要么返回 MyPojo.class,要么返回 RESTError.class。
然后,我使用 RestTemplate 从另一个 Spring 服务调用此控制器,并希望获取 MyPojo 对象或 RESTError 对象。
除了检查原始字符串然后手动解析之外,还有什么方法可以做到这一点?
详细说明
我有两个 Spring 服务。
让我们称它们为“服务器服务”和“客户端服务”。 “客户端服务”必须从“服务器服务”中检索 POJO。如果出现问题(无效参数、缺少参数等),则会返回一个自定义错误对象,该对象会通过“开发人员消息”和更广泛的“用户消息”详细说明错误。
这样,如果发生错误,我将能够在 ui 中显示“用户消息”。
这只是作为最后的手段。在调用“服务器服务”之前,我当然应该先在“客户端服务”中进行验证。然而,想象一下有人在我不知情的情况下更改了“服务器服务”......
"server-service" - 代码
MyPojo
@Getter @Setter @Accessors(chain = true)
public class MyPojo extends MyPojoSuper{
private String someString;
//hashCode & equals & toString
}
REST错误
以下是自定义错误对象。它有一般用户的errorMessage和开发者的developerMessage。
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter @Setter @Accessors(chain = true)
public class RESTError extends MyPojoSuper{
private String errorMessage, developerMessage;
//hashCode & equals & toString
}
@ControllerAdvice
ExceptionHandlerAdvice 类将处理所有抛出的异常并返回 RESTError。
@ControllerAdvice
@RequestMapping("/error")
@Slf4j
public class ExceptionHandlerAdvice {
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
public RESTError missingServletRequestParameterException(MissingServletRequestParameterException ex) {
log.info("A parameter['" + ex.getParameterName() +"'] is missing.", ex);
RESTError error = new RESTError();
error.setDeveloperMessage(ex.getMessage());
error.setErrorMessage("The parameter['" + ex.getParameterName() +"'] is missing.");
return error;
}
}
“客户服务-代码”
调用“server-service”的客户端方法
public MyPojo getMyPojo(){
restTemplate.setErrorHandler(new MyCustomResponseErrorHandler());
return restTemplate.getForObject(getURLWithParams(), MyPojo.class);
}
RESTError 客户端
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter @Setter @Accessors(chain = true)
public class RESTError extends MyPojoSuper{
private String errorMessage, developerMessage;
//hashCode & equals & toString
}
MyPojoSuper
@Getter @Setter @Accessors(chain = true)
public class MyPojoSuper{
public boolean error;
//equals & hashCode & toString
}
MyCustomResponseErrorHandler
@Slf4j
public class MyCustomResponseErrorHandler implements ResponseErrorHandler {
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
if (response.getStatusCode() != HttpStatus.OK) {
log.info("There was an error.");
return true;
}
return false;
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
if (response.getStatusCode() != HttpStatus.OK) {
log.info("There was an error.");
}
}
}
问题
如何处理我的自定义 RESTError?
通过使用 RestTemplate,我只能解析一次 JSON,并且只能将其解析为一个类(MyPojo.class 或 RESTError.class)。 因此,我可以解析为字符串,检查字符串,然后将 JSON 重新解析为所需的格式:
public MyPojoSuper getMyPojo() {
ObjectMapper mapper = new ObjectMapper();
restTemplate.setErrorHandler(new MyCustomResponseErrorHandler());
String res = restTemplate.getForObject(getURL(), String.class);
try {
if (res.contains("\"error\":true")) {
return mapper.readValue(res, RESTError.class);
} else {
return mapper.readValue(res, MyPojo.class);
}
} catch (IOException e) {
e.printStackTrace();
}
return new RESTResponse().setError(true);
}
我不喜欢这个解决方案,如果有任何其他建议,我将不胜感激。
【问题讨论】:
-
这是说
RestErr是SuperMyPojo。这是真的吗?似乎MyPojo偶尔有一个 错误。考虑组合而不是继承。 -
Composition 仍然不能解决我的选角问题(我认为)。如果您有一种组合对象的方法,可以解决我的问题,请继续并将其作为答案发布。
-
基于this,考虑让
MyCustomResponseErrorHandler在响应有错误时抛出异常。由于有错误,响应将有一个RESTErr,可以反序列化(在错误处理程序中)并包装在异常中。 -
@Andrew S 有效。我仍然不是 100% 满意,因为我希望得到这样的答案:restTemplate.getForObject(url, ResponseObject.class, ErrorObject.class);但是,嘿,你不可能拥有一切,对吧;)
标签: java spring rest spring-boot error-handling