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.classMyPojo.class需要MyPojoSuper.class作为其父代,才能正确处理。

07-26 02:53