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