简体   繁体   English

使用带有 Retrofit2 的 Multipart 和 JSON 键值对上传文件

[英]Upload file using both Multipart and JSON Key value pairs with Retrofit2

Currently we are uoloading files (Video, Audio, Text etc..) by converting String bytes with simple JSON including some other values with their Key-Value pairs.目前,我们正在通过使用简单的 JSON 转换String bytes来加载文件(视频、音频、文本等),其中包括一些其他值及其键值对。 Just like below:就像下面一样:

Some header values:一些标头值:

{
    "header": {
        "geoDate": {
            "point": {
                "longitude": 77.56246948242188,
                "latitude": 12.928763389587403
            },
            "date": "2020-02-25T18:26:00Z"
        },
        "version": "1.35.00.001",
        "businessId": "178"
    }
}

and files info:和文件信息:

    JSONObject data = new JSONObject();
    data.put("name", params.name);
    data.put("mimeType", params.mimeType);
    data.put("fileSize", params.fileSize);
    data.put("inputData", params.data);

    requestJSON.put("data", data);

Here params.data is a simple conversion of bytes String bytes = Base64.encodeToString(bos.toByteArray(), Base64.DEFAULT);这里params.data是一个简单的字节转换String bytes = Base64.encodeToString(bos.toByteArray(), Base64.DEFAULT);

It's working but we want to do it through Retrofit by sending the files through MultiPart to the server and which will improve the performance as well.它正在工作,但我们希望通过将文件通过 MultiPart 发送到服务器来通过 Retrofit 来实现,这也将提高性能。 But the problem is as it was in the JSON structure, the server can't change its program and we (app) only have to do something which sends the file using Retrofit Multipart including other values and keys( inputData also).但问题在于它在 JSON 结构中,服务器无法更改它的程序,我们(应用程序)只需要做一些使用 Retrofit Multipart 发送文件的事情,包括其他值和键( inputData )。

I am searching for a way to do that.我正在寻找一种方法来做到这一点。 And I am wondering if we are able to send also, is the server has to change anything for the API structure like currently its accepting String for the bytes and we are going to change it to file for inputData .而且我想知道我们是否也可以发送,服务器是否必须更改 API 结构的任何内容,例如当前它接受的字节字符串,我们要将其更改为用于inputData文件。

Works fine for me (it's my code, just adapt it to your business logic):对我来说很好用(这是我的代码,只需使其适应您的业务逻辑):

Interface:界面:

@Multipart
@POST("{projectName}/log")
Call<LogRp> uploadFile(
        @Path("projectName") String project,
        @PartMap Map<String, RequestBody> mp,
        @Part MultipartBody.Part file
        );

Service:服务:

private MultipartBody.Part buildFilePart(File file, FileType type) {
    return MultipartBody.Part.createFormData("file", file.getName(),
            RequestBody.create(MediaType.parse(type.value.get()), file));
}

private Map<String, RequestBody> buildJsonPart(LogRq logRq) throws JsonProcessingException {
    return Collections.singletonMap("json_request_part", RequestBody.create(
            MediaType.parse("application/json"),
            new ObjectMapper().writeValueAsString(logRq))
    );
}

And then simply:然后简单地:

client.uploadFile(
                        project,
                        buildJsonPart(logRq),
                        buildFilePart(file, type)
                )

LogRp and LogRq are Response and Request POJOs. LogRp 和 LogRq 是响应和请求 POJO。 ping me if help needed.如果需要帮助,请联系我。

You can use VolleyMultipartRequest to upload File with text.您可以使用 VolleyMultipartRequest 上传带有文本的文件。

VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.PUT, url, new Response.Listener<NetworkResponse>() {
            @Override
            public void onResponse(NetworkResponse response) {


                String resultResponse = new String(response.data);
                try {
                    JSONObject result = new JSONObject(resultResponse);

                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {

                NetworkResponse networkResponse = error.networkResponse;
                String errorMessage = "Unknown error";
                if (networkResponse == null) {
                    if (error.getClass().equals(TimeoutError.class)) {
                        errorMessage = "Request timeout";
                    } else if (error.getClass().equals(NoConnectionError.class)) {
                        errorMessage = "Failed to connect server";
                    }
                } else {
                    String result = new String(networkResponse.data);
                    try {
                        JSONObject response = new JSONObject(result);
                        String status = response.getString("status");
                        String message = response.getString("message");

                        Log.e("Error Status", status);
                        Log.e("Error Message", message);

                        if (networkResponse.statusCode == 404) {
                            errorMessage = "Resource not found";
                        } else if (networkResponse.statusCode == 401) {
                            errorMessage = message + " Please login again";
                        } else if (networkResponse.statusCode == 400) {
                            errorMessage = message + " Check your inputs";
                        } else if (networkResponse.statusCode == 500) {
                            errorMessage = message + " Something is getting wrong";
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
                Log.i("Error", errorMessage);
                error.printStackTrace();
            }
        }) {
            @Override
            protected Map<String, String> getParams() {
                Map<String, String> params = new HashMap<>();
                params.put("Some_text", "text");

                return params;
            }

            @Override
            protected Map<String, DataPart> getByteData() {
                Map<String, DataPart> params = new HashMap<>();
                // file name could found file base or direct access from real path
                // for now just get bitmap data from ImageView
                params.put("pofile_pic", new DataPart("file_avatar.jpg", getFileDataFromDrawable(bitmap), "image/jpeg"));
                return params;
            }
        };
        VolleySingleton.getInstance(getActivity()).addToRequestQueue(multipartRequest);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM