使用 Volley 发送带有 JSON 数据的 POST 请求

我想发送一个新的 JsonObjectRequest请求:

  • 我想接收 JSON 数据(来自服务器的响应) : 好的
  • 我希望将带有此请求的 JSON 格式的数据发送到服务器

    JsonObjectRequest request = new JsonObjectRequest(
    Request.Method.POST, "myurl.com", null,
    new Response.Listener<JSONObject>() {
    @Override
    public void onResponse(JSONObject response) {
    //...
    }
    },
    new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
    //...
    }
    })
    {
    @Override
    protected Map<String,String> getParams() {
    // something to do here ??
    return params;
    }
    
    
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
    // something to do here ??
    return params;
    }
    };
    

P.S. I use GSON library in my project too.

181248 次浏览

JsonObjectRequest actually accepts JSONObject as body.

From this blog article,

final String url = "some/url";
final JSONObject jsonBody = new JSONObject("{\"type\":\"example\"}");


new JsonObjectRequest(url, jsonBody, new Response.Listener<JSONObject>() { ... });

Here is the source code and JavaDoc (@param jsonRequest):

/**
* Creates a new request.
* @param method the HTTP method to use
* @param url URL to fetch the JSON from
* @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and
*   indicates no parameters will be posted along with request.
* @param listener Listener to receive the JSON response
* @param errorListener Error listener, or null to ignore errors.
*/
public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
Listener<JSONObject> listener, ErrorListener errorListener) {
super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
errorListener);
}
    final String url = "some/url";

instead of:

    final JSONObject jsonBody = "{\"type\":\"example\"}";

you can use:

  JSONObject jsonBody = new JSONObject();
try {
jsonBody.put("type", "my type");
} catch (JSONException e) {
e.printStackTrace();
}
new JsonObjectRequest(url, jsonBody, new Response.Listener<JSONObject>() { ... });
final Map<String,String> params = new HashMap<String,String>();
params.put("email", customer.getEmail());
params.put("password", customer.getPassword());
String url = Constants.BASE_URL+"login";


doWebRequestPost(url, params);




public void doWebRequestPost(String url, final Map<String,String> json){
getmDialogListener().showDialog();


StringRequest post = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
getmDialogListener().dismissDialog();
response....


} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d(App.TAG,error.toString());
getmDialogListener().dismissDialog();


}
}){
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> map = json;


return map;
}
};
App.getInstance().getRequestQueue().add(post);


}

I know that this thread is quite old, but I had this problem and I came up with a cool solution which can be very useful to many because it corrects/extended the Volley library on many aspects.

I spotted some not supported-out-of-box Volley features:

  • This JSONObjectRequest is not perfect: you have to expect a JSON at the end (see the Response.Listener<JSONObject>).
  • What about Empty Responses (just with a 200 status)?
  • What do I do if I want directly my POJO from the ResponseListener?

I more or less compiled a lot of solutions in a big generic class in order to have a solution for all the problem I quoted.

  /**
* Created by laurentmeyer on 25/07/15.
*/
public class GenericRequest<T> extends JsonRequest<T> {


private final Gson gson = new Gson();
private final Class<T> clazz;
private final Map<String, String> headers;
// Used for request which do not return anything from the server
private boolean muteRequest = false;


/**
* Basically, this is the constructor which is called by the others.
* It allows you to send an object of type A to the server and expect a JSON representing a object of type B.
* The problem with the #JsonObjectRequest is that you expect a JSON at the end.
* We can do better than that, we can directly receive our POJO.
* That's what this class does.
*
* @param method:        HTTP Method
* @param classtype:     Classtype to parse the JSON coming from the server
* @param url:           url to be called
* @param requestBody:   The body being sent
* @param listener:      Listener of the request
* @param errorListener: Error handler of the request
* @param headers:       Added headers
*/
private GenericRequest(int method, Class<T> classtype, String url, String requestBody,
Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> headers) {
super(method, url, requestBody, listener,
errorListener);
clazz = classtype;
this.headers = headers;
configureRequest();
}


/**
* Method to be called if you want to send some objects to your server via body in JSON of the request (with headers and not muted)
*
* @param method:        HTTP Method
* @param url:           URL to be called
* @param classtype:     Classtype to parse the JSON returned from the server
* @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server
* @param listener:      Listener of the request
* @param errorListener: Error handler of the request
* @param headers:       Added headers
*/
public GenericRequest(int method, String url, Class<T> classtype, Object toBeSent,
Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> headers) {
this(method, classtype, url, new Gson().toJson(toBeSent), listener,
errorListener, headers);
}


/**
* Method to be called if you want to send some objects to your server via body in JSON of the request (without header and not muted)
*
* @param method:        HTTP Method
* @param url:           URL to be called
* @param classtype:     Classtype to parse the JSON returned from the server
* @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server
* @param listener:      Listener of the request
* @param errorListener: Error handler of the request
*/
public GenericRequest(int method, String url, Class<T> classtype, Object toBeSent,
Response.Listener<T> listener, Response.ErrorListener errorListener) {
this(method, classtype, url, new Gson().toJson(toBeSent), listener,
errorListener, new HashMap<String, String>());
}


/**
* Method to be called if you want to send something to the server but not with a JSON, just with a defined String (without header and not muted)
*
* @param method:        HTTP Method
* @param url:           URL to be called
* @param classtype:     Classtype to parse the JSON returned from the server
* @param requestBody:   String to be sent to the server
* @param listener:      Listener of the request
* @param errorListener: Error handler of the request
*/
public GenericRequest(int method, String url, Class<T> classtype, String requestBody,
Response.Listener<T> listener, Response.ErrorListener errorListener) {
this(method, classtype, url, requestBody, listener,
errorListener, new HashMap<String, String>());
}


/**
* Method to be called if you want to GET something from the server and receive the POJO directly after the call (no JSON). (Without header)
*
* @param url:           URL to be called
* @param classtype:     Classtype to parse the JSON returned from the server
* @param listener:      Listener of the request
* @param errorListener: Error handler of the request
*/
public GenericRequest(String url, Class<T> classtype, Response.Listener<T> listener, Response.ErrorListener errorListener) {
this(Request.Method.GET, url, classtype, "", listener, errorListener);
}


/**
* Method to be called if you want to GET something from the server and receive the POJO directly after the call (no JSON). (With headers)
*
* @param url:           URL to be called
* @param classtype:     Classtype to parse the JSON returned from the server
* @param listener:      Listener of the request
* @param errorListener: Error handler of the request
* @param headers:       Added headers
*/
public GenericRequest(String url, Class<T> classtype, Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> headers) {
this(Request.Method.GET, classtype, url, "", listener, errorListener, headers);
}


/**
* Method to be called if you want to send some objects to your server via body in JSON of the request (with headers and muted)
*
* @param method:        HTTP Method
* @param url:           URL to be called
* @param classtype:     Classtype to parse the JSON returned from the server
* @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server
* @param listener:      Listener of the request
* @param errorListener: Error handler of the request
* @param headers:       Added headers
* @param mute:          Muted (put it to true, to make sense)
*/
public GenericRequest(int method, String url, Class<T> classtype, Object toBeSent,
Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> headers, boolean mute) {
this(method, classtype, url, new Gson().toJson(toBeSent), listener,
errorListener, headers);
this.muteRequest = mute;
}


/**
* Method to be called if you want to send some objects to your server via body in JSON of the request (without header and muted)
*
* @param method:        HTTP Method
* @param url:           URL to be called
* @param classtype:     Classtype to parse the JSON returned from the server
* @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server
* @param listener:      Listener of the request
* @param errorListener: Error handler of the request
* @param mute:          Muted (put it to true, to make sense)
*/
public GenericRequest(int method, String url, Class<T> classtype, Object toBeSent,
Response.Listener<T> listener, Response.ErrorListener errorListener, boolean mute) {
this(method, classtype, url, new Gson().toJson(toBeSent), listener,
errorListener, new HashMap<String, String>());
this.muteRequest = mute;


}


/**
* Method to be called if you want to send something to the server but not with a JSON, just with a defined String (without header and not muted)
*
* @param method:        HTTP Method
* @param url:           URL to be called
* @param classtype:     Classtype to parse the JSON returned from the server
* @param requestBody:   String to be sent to the server
* @param listener:      Listener of the request
* @param errorListener: Error handler of the request
* @param mute:          Muted (put it to true, to make sense)
*/
public GenericRequest(int method, String url, Class<T> classtype, String requestBody,
Response.Listener<T> listener, Response.ErrorListener errorListener, boolean mute) {
this(method, classtype, url, requestBody, listener,
errorListener, new HashMap<String, String>());
this.muteRequest = mute;


}




@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
// The magic of the mute request happens here
if (muteRequest) {
if (response.statusCode >= 200 && response.statusCode <= 299) {
// If the status is correct, we return a success but with a null object, because the server didn't return anything
return Response.success(null, HttpHeaderParser.parseCacheHeaders(response));
}
} else {
try {
// If it's not muted; we just need to create our POJO from the returned JSON and handle correctly the errors
String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
T parsedObject = gson.fromJson(json, clazz);
return Response.success(parsedObject, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
return null;
}


@Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}


private void configureRequest() {
// Set retry policy
// Add headers, for auth for example
// ...
}
}

It could seem a bit overkill but it's pretty cool to have all these constructors because you have all the cases:

(The main constructor wasn't meant to be used directly although it's, of course, possible).

  1. Request with response parsed to POJO / Headers manually set / POJO to Send
  2. Request with response parsed to POJO / POJO to Send
  3. Request with response parsed to POJO / String to Send
  4. Request with response parsed to POJO (GET)
  5. Request with response parsed to POJO (GET) / Headers manually set
  6. Request with no response (200 - Empty Body) / Headers manually set / POJO to Send
  7. Request with no response (200 - Empty Body) / POJO to Send
  8. Request with no response (200 - Empty Body) / String to Send

Of course, in order that it works, you have to have Google's GSON Lib; just add:

compile 'com.google.code.gson:gson:x.y.z'

to your dependencies (current version is 2.3.1).

final String URL = "/volley/resource/12";
// Post params to be sent to the server
HashMap<String, String> params = new HashMap<String, String>();
params.put("token", "AbCdEfGh123456");


JsonObjectRequest req = new JsonObjectRequest(URL, new JSONObject(params),
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
VolleyLog.v("Response:%n %s", response.toString(4));
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
VolleyLog.e("Error: ", error.getMessage());
}
});


// add the request object to the queue to be executed
ApplicationController.getInstance().addToRequestQueue(req);

refer

You can also send data by overriding getBody() method of JsonObjectRequest class. As shown below.

    @Override
public byte[] getBody()
{


JSONObject jsonObject = new JSONObject();
String body = null;
try
{
jsonObject.put("username", "user123");
jsonObject.put("password", "Pass123");


body = jsonObject.toString();
} catch (JSONException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}


try
{
return body.toString().getBytes("utf-8");
} catch (UnsupportedEncodingException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();


JSONObject JObj = new JSONObject();


try {
JObj.put("Id","1");
JObj.put("Name", "abc");


} catch (Exception e) {
e.printStackTrace();
}


params.put("params", JObj.toString());
// Map.Entry<String,String>
Log.d("Parameter", params.toString());
return params;
}