如何在Java Android Spring中接收验证错误

如何在Java Android Spring中接收验证错误,java,android,spring,api,android-asynctask,Java,Android,Spring,Api,Android Asynctask,我正在使用Android(Java)中的Spring向后端API发送API请求。我的问题是如何在ex 400错误请求响应中接收验证错误到错误处理程序。这是我的密码: class RestTask extends AsyncTask<String,Void,ResponseEntity<ExpectedReturn>> { protected ResponseEntity<ExpectedReturn> doInBackground(S

我正在使用Android(Java)中的Spring向后端API发送API请求。我的问题是如何在ex 400错误请求响应中接收验证错误到错误处理程序。这是我的密码:

 class RestTask extends AsyncTask<String,Void,ResponseEntity<ExpectedReturn>>
    {
        protected ResponseEntity<ExpectedReturn> doInBackground(String... uri)
        {
            try{
                final String url = uri[0];
                RestTemplate restTemplate = new RestTemplate();
                restTemplate.setErrorHandler(subscriber.getErrorHandler());
                restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
                // set authentication tokens:
                ResponseEntity<ExpectedReturn> response = restTemplate.exchange(url,callMethod,httpEntity, expectedReturnClass);
                return response;
            }catch(Exception e)
            {
                System.out.println(e.getMessage());
            }
            return null;
        }

        @Override
        protected void onPostExecute(ResponseEntity<ExpectedReturn> result) {
            if(result !=null && result.getBody() !=null)
            {
                subscriber.getSubscriber().onComplete(result.getBody(),result.getStatusCode());
            }
        }
    }
class RestTask扩展了AsyncTask
{
受保护的响应性doInBackground(字符串…uri)
{
试一试{
最终字符串url=uri[0];
RestTemplate RestTemplate=新RestTemplate();
setErrorHandler(subscriber.getErrorHandler());
restemplate.getMessageConverters().add(新映射Jackson2HttpMessageConverter());
//设置身份验证令牌:
ResponseEntity response=restemplate.exchange(url、callMethod、httpEntity、expectedReturnClass);
返回响应;
}捕获(例外e)
{
System.out.println(e.getMessage());
}
返回null;
}
@凌驾
PostExecute上受保护的void(ResponseEntity结果){
if(result!=null&&result.getBody()!=null)
{
subscriber.getSubscriber().onComplete(result.getBody(),result.getStatusCode());
}
}
}
我的问题是,如果post数据未通过验证(不正确),API将作为JSON错误对象返回,并出现错误,例如:


在验证错误的情况下,将使用ClientHttpResponse对象作为参数调用错误处理程序。调用response.getBody()返回一个InputStream。我的问题是,是否有任何方法可以接收从JSON错误响应(如上所示)映射到错误处理程序的对象,或者将输入流转换为可读的内容(如hashmap),以便显示API返回的错误(例如:“Name is required”等)?

我已经测试了您的代码,如果有400个错误请求,catch块会收到一个
HttpClientErrorException
的实例,该实例有一个方法可以将错误主体获取为字符串:

private class HttpRequestTask extends AsyncTask<Void, Void, String> {
    @Override
    protected String doInBackground(Void... params) {
        try {
            final String url = "https://reqres.in/api/login";
            RestTemplate restTemplate = new RestTemplate();
            //Same result with restTemplate.exchange() too
            return restTemplate.postForObject(url, "{\n" +
                    "    \"email\": \"peter@klaven\"\n" +
                    "}", String.class);

        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
            if (e instanceof HttpClientErrorException) {
                String responseBodyAsString = ((HttpClientErrorException) e).getResponseBodyAsString();
                Log.e(TAG, "Validation error" + responseBodyAsString);
                //You can parse this with gson or jackson here
                return responseBodyAsString;
            }
        }

        return null;
    }

    @Override
    protected void onPostExecute(String result) {
        Log.d(TAG, "onPostExecute() called with: result = [" + result + "]");
    }

}
如果要使用无默认错误处理程序并设置自定义错误处理程序,可以通过以下方式将错误消息获取为字符串:

restTemplate.setErrorHandler(new ResponseErrorHandler() {
                @Override
                public boolean hasError(ClientHttpResponse response) throws IOException {
                    return response.getStatusCode().is4xxClientError();
                }

                @Override
                public void handleError(ClientHttpResponse response) throws IOException {
                    String errorResponse = new String(getResponseBody(response), getCharset(response).name());
                    Log.e(TAG, "handleError: called with: " + errorResponse);
                }
            });

private byte[] getResponseBody(ClientHttpResponse response) {
    try {
        InputStream responseBody = response.getBody();
        if (responseBody != null) {
            return FileCopyUtils.copyToByteArray(responseBody);
        }
    } catch (IOException ex) {
        // ignore
    }
    return new byte[0];
}

private Charset getCharset(ClientHttpResponse response) {
    HttpHeaders headers = response.getHeaders();
    MediaType contentType = headers.getContentType();
    return contentType != null ? contentType.getCharSet() : Charset.defaultCharset();
}
然后您可以使用Jackson或Gson解析错误响应,如下所示:

new Gson().fromJson(responseBodyAsString, ExpectedResponse.class);
注意,我刚刚做了与
DefaultResponseErrorHandler

编辑: 整个
AsyncTask
和Spring Android API都太过时了,下面是相同的改型示例:

        api.login(new BodyModel("peter@klaven"))
            .enqueue(new Callback<ExpectedModel>() {
                @Override
                public void onResponse(@NonNull Call<ExpectedModel> call, @NonNull Response<ExpectedModel> response) {
                    if (response.isSuccessful()) {
                        //Do what you got to do
                    } else {
                        Converter<ResponseBody, ErrorModel> converter = MainActivity.this.retrofit.responseBodyConverter(ErrorModel.class, new Annotation[0]);
                        ErrorModel errorModel = null;
                        try {
                            errorModel = converter.convert(response.errorBody());
                            Toast.makeText(MainActivity.this, errorModel.toString(), Toast.LENGTH_SHORT).show();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                }

                @Override
                public void onFailure(@NonNull Call<ExpectedModel> call, @NonNull Throwable t) {
                    t.printStackTrace();
                }
            })
api.login(新的BodyModel(“peter@klaven"))
.enqueue(新的回调函数(){
@凌驾
public void onResponse(@NonNull调用,@NonNull响应){
if(response.issusccessful()){
//做你该做的
}否则{
Converter Converter=MainActivity.this.Reformation.responseBodyConverter(ErrorModel.class,新注释[0]);
ErrorModel ErrorModel=null;
试一试{
errorModel=converter.convert(response.errorBody());
Toast.makeText(MainActivity.this,errorModel.toString(),Toast.LENGTH_SHORT.show();
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
@凌驾
public void onFailure(@NonNull Call Call,@NonNull Throwable t){
t、 printStackTrace();
}
})

您可以找到完整的

是否需要使用此库向服务器发送请求?如果不是,考虑使用改造和OKHTTP,这是Android中联网的标准工具集。谢谢…似乎有效,但转换后看起来非常粗糙。。。我希望能有一种更正式的传统方式。。SpringRestTemplate中是否有任何内置功能可以实现这一点?同样的例子在改型中会是什么样子?@DanielValland No spring resttemplate做得再好不过了,我已经编辑了我的帖子,看看改型示例。Reza非常感谢:)@DanielValland any time;)为了清楚起见,在您的改型示例中,改型自己处理线程,这样调用就不会挂起主线程了?谢谢
        api.login(new BodyModel("peter@klaven"))
            .enqueue(new Callback<ExpectedModel>() {
                @Override
                public void onResponse(@NonNull Call<ExpectedModel> call, @NonNull Response<ExpectedModel> response) {
                    if (response.isSuccessful()) {
                        //Do what you got to do
                    } else {
                        Converter<ResponseBody, ErrorModel> converter = MainActivity.this.retrofit.responseBodyConverter(ErrorModel.class, new Annotation[0]);
                        ErrorModel errorModel = null;
                        try {
                            errorModel = converter.convert(response.errorBody());
                            Toast.makeText(MainActivity.this, errorModel.toString(), Toast.LENGTH_SHORT).show();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                }

                @Override
                public void onFailure(@NonNull Call<ExpectedModel> call, @NonNull Throwable t) {
                    t.printStackTrace();
                }
            })