Tl; Dr;
我在Spring-Boot中有一个REST Controller ,返回MyPojo.class或RESTError.class。
然后,我从另一个带有RestTemplate的Spring Service调用此 Controller ,并想要获取MyPojo对象或RESTError对象。
除了检查原始String然后手动解析之外,还有其他方法吗?
详细说明
我有两个Spring Services。
我们称它们为“服务器服务”和“客户端服务”。 “客户端服务”必须从“服务器服务”中检索POJO。如果出现问题(无效参数,缺少参数等),则返回一个自定义错误对象,该对象将通过“开发人员消息”和更广泛的“用户消息”详细描述错误。
这样,如果发生错误,我将能够在ui中显示“用户消息”。
这仅是最后的手段。我当然应该先在“客户端服务”中进行验证,然后再调用“服务器服务”。但是,想象一下有人在我不知情的情况下更改了“服务器服务”。
“服务器服务”-代码
MyPojo
@Getter @Setter @Accessors(chain = true)
public class MyPojo extends MyPojoSuper{
private String someString;
//hashCode & equals & toString
}
RESTError
以下是自定义错误对象。对于普通用户,它具有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;
}
}
“客户端服务-代码”
调用“服务器服务” 的客户端方法
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解析一次,并且只能将其解析为一个Class(MyPojo.class或RESTError.class)。
因此,我可以解析为一个String,检查该String,然后将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);
}
我不喜欢这种解决方案,希望您能提出其他建议。
最佳答案
根据@Andrew S的评论,这是一个解决方案:
可以通过创建一个在自定义类中实现ResponseErrorHandler
的类并将其注册到ResponseErrorHandler
来注册RestTemplate
:
@Slf4j
public class MyCustomResponseErrorHandler implements ResponseErrorHandler {
private ObjectMapper mapper = new ObjectMapper();
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
if (response.getStatusCode() != HttpStatus.OK) {
log.info("loggin stuff");
return true;
}
return false;
}
@Override
public void handleError(ClientHttpResponse response) throws JsonParseException, JsonMappingException, IOException{
if (response.getStatusCode() != HttpStatus.OK) {
log.info("logging stuff");
throw new RestErrorExeption(mapper.readValue(response.getBody(), RESTError.class));
}
}
}
如所示,该类现在抛出一个自定义异常
RestErrorExeption
。它包含一个RESTError对象。然后,可以通过调用mapper.readValue(response.getBody(), RESTError.class)
在响应主体中解析JSON。 (映射程序是com.fasterxml.jackson.databind.ObjectMapper的实例)然后可以捕获该异常,并从
RestErrorExeption
中将解析的JSON作为POJO获取:public MyPojoSuper getMyPojo() {
restTemplate.setErrorHandler(new MyCustomResponseErrorHandler());
try {
return restTemplate.getForObject(getURLWithParams(), MyPojo.class);
} catch (RestErrorExeption e) {
log.info(e.getMessage());
return e.getRestError();
}
}
请注意,
RESTError.class
和MyPojo.class
需要MyPojoSuper.class
作为其父代,才能正确处理。