改造2档文件下载/上传

N4z*_*oth 28 upload android download retrofit

我正在尝试使用改进2来下载/上传文件,但找不到任何有关如何操作的教程示例.我的下载代码是:

@GET("documents/checkout")
public Call<File> checkout(@Query(value = "documentUrl") String documentUrl, @Query(value = "accessToken") String accessToken, @Query(value = "readOnly") boolean readOnly);
Run Code Online (Sandbox Code Playgroud)

Call<File> call = RetrofitSingleton.getInstance(serverAddress)
                .checkout(document.getContentUrl(), apiToken, readOnly[i]);
call.enqueue(new Callback<File>() {
        @Override
        public void onResponse(Response<File> response,
                Retrofit retrofit) {
            String fileName = document.getFileName();
            try {
                System.out.println(response.body());
                long fileLength = response.body().length();
                InputStream input = new FileInputStream(response.body());
                File path = Environment.getExternalStorageDirectory();
                File file = new File(path, fileName);
                BufferedOutputStream output = new BufferedOutputStream(
                        new FileOutputStream(file));
                byte data[] = new byte[1024];

                long total = 0;
                int count;
                while ((count = input.read(data)) != -1) {
                    total += count;
                    output.write(data, 0, count);
                }

                output.flush();

                output.close();
            } catch (IOException e) {
                String logTag = "TEMPTAG";
                Log.e(logTag, "Error while writing file!");
                Log.e(logTag, e.toString());
            }
        }
        @Override
        public void onFailure(Throwable t) {
            // TODO: Error handling
            System.out.println(t.toString());
        }
    });
Run Code Online (Sandbox Code Playgroud)

我尝试过Call和Call,但似乎没有任何效果.

在正确设置标头和mime类型之后,服务器端代码将文件的字节写入HttpServletResponse的输出流.

我究竟做错了什么?

最后,上传代码:

@Multipart
@POST("documents/checkin")
public Call<String> checkin(@Query(value = "documentId") String documentId, @Query(value = "name") String fileName, @Query(value = "accessToken") String accessToken, @Part("file") RequestBody file);
Run Code Online (Sandbox Code Playgroud)

RequestBody requestBody = RequestBody.create(MediaType.parse(document.getMimeType()), file);

            Call<String> call = RetrofitSingleton.getInstance(serverAddress).checkin(documentId, document.getFileName(), apiToken, requestBody);
            call.enqueue(new Callback<String>() {
                @Override
                public void onResponse(Response<String> response, Retrofit retrofit) {
                    System.out.println(response.body());
                }

                @Override
                public void onFailure(Throwable t) {
                    System.out.println(t.toString());
                }
            });
Run Code Online (Sandbox Code Playgroud)

谢谢!

编辑:

在答案之后,下载只会产生一个损坏的文件(没有@Streaming),上传也不会.当我使用上面的代码时,服务器返回400错误.将其更改为

RequestBody requestBody = RequestBody.create(MediaType.parse(document.getMimeType()), file);
            MultipartBuilder multipartBuilder = new MultipartBuilder();
            multipartBuilder.addFormDataPart("file", document.getFileName(), requestBody);

            Call<String> call = RetrofitSingleton.getInstance(serverAddress).checkin(documentId, document.getFileName(), apiToken, multipartBuilder.build());
Run Code Online (Sandbox Code Playgroud)

,请求执行但后端似乎没有收到文件.

后端代码:

@RequestMapping(value = "/documents/checkin", method = RequestMethod.POST)
public void checkInDocument(@RequestParam String documentId,
        @RequestParam String name, @RequestParam MultipartFile file,
        @RequestParam String accessToken, HttpServletResponse response)
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?我能够使用Apache HttpClient从普通Java的后端:

    MultipartEntityBuilder builder = MultipartEntityBuilder.create();
    builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
    builder.addBinaryBody("file", new File("E:\\temp\\test.jpg"));
    HttpEntity httpEntity = builder.build();
    System.out.println("HttpEntity " + EntityUtils.toString(httpEntity.));
    HttpPost httpPost = new HttpPost(uri);
    httpPost.setEntity(httpEntity);
Run Code Online (Sandbox Code Playgroud)

编辑v2

对于任何感兴趣的人,现在上下班工作:这些是解决方案:

服务:

@GET("documents/checkout")
public Call<ResponseBody> checkout(@Query(value = "documentUrl") String documentUrl, @Query(value = "accessToken") String accessToken, @Query(value = "readOnly") boolean readOnly);

@Multipart
@POST("documents/checkin")
public Call<String> checkin(@Query(value = "documentId") String documentId, @Query(value = "name") String fileName, @Query(value = "accessToken") String accessToken, @Part("file") RequestBody file);
Run Code Online (Sandbox Code Playgroud)

下载代码:

    Call<ResponseBody> call = RetrofitSingleton.getInstance(serverAddress)
                .checkout(document.getContentUrl(), apiToken, readOnly[i]);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Response<ResponseBody> response,
                    Retrofit retrofit) {
                String fileName = document.getFileName();

                try {
                    File path = Environment.getExternalStorageDirectory();
                    File file = new File(path, fileName);
                    FileOutputStream fileOutputStream = new FileOutputStream(file);
                    IOUtils.write(response.body().bytes(), fileOutputStream);
                } catch (IOException e) {
                    Log.e(logTag, "Error while writing file!");
                    Log.e(logTag, e.toString());
                }
            }

            @Override
            public void onFailure(Throwable t) {
                // TODO: Error handling
                System.out.println(t.toString());
            }
        });
Run Code Online (Sandbox Code Playgroud)

上传代码:

    Call<String> call = RetrofitSingleton
                    .getInstance(serverAddress).checkin(documentId,
                            document.getFileName(), apiToken,
                            multipartBuilder.build());
            call.enqueue(new Callback<String>() {
                @Override
                public void onResponse(Response<String> response,
                        Retrofit retrofit) {
                    // Handle response here
                }

                @Override
                public void onFailure(Throwable t) {
                    // TODO: Error handling
                    System.out.println("Error");
                    System.out.println(t.toString());
                }
            });
Run Code Online (Sandbox Code Playgroud)

iag*_*een 22

如需下载,您可以使用ResponseBody作为您的退货类型 -

@GET("documents/checkout")
@Streaming
public Call<ResponseBody> checkout(@Query("documentUrl") String documentUrl, @Query("accessToken") String accessToken, @Query("readOnly") boolean readOnly);
Run Code Online (Sandbox Code Playgroud)

你可以ResponseBody在你的回叫中获得输入流 -

Call<ResponseBody> call = RetrofitSingleton.getInstance(serverAddress)
            .checkout(document.getContentUrl(), apiToken, readOnly[i]);

call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Response<ResponseBody> response,
                Retrofit retrofit) {
            String fileName = document.getFileName();
            try {
                InputStream input = response.body().byteStream();
                //  rest of your code
Run Code Online (Sandbox Code Playgroud)

如果您的服务器正确处理多部分消息,您的上传看起来没问题.它有效吗?如果没有,你能解释失败模式吗?您也可以通过不使其成为多部分来简化.删除@Multipart注释并转换@Path@Body-

@POST("documents/checkin")
public Call<String> checkin(@Query("documentId") String documentId, @Query("name") String fileName, @Query("accessToken") String accessToken, @Body RequestBody file);
Run Code Online (Sandbox Code Playgroud)


小智 5

我正在使用改造 2.0.0-beta2 并且我在使用多部分请求上传图像时遇到了问题。我用这个答案解决了这个问题:https : //stackoverflow.com/a/32796626/2915075

对我来说,关键是使用标准 POST 和 MultipartRequestBody 而不是 @Multipart 注释请求。

这是我的代码:

改造服务类

@POST("photo")
Call<JsonElement> uploadPhoto(@Body RequestBody imageFile, @Query("sessionId"));
Run Code Online (Sandbox Code Playgroud)

活动中的用法,片段:

RequestBody fileBody = RequestBody.create(MediaType.parse("image/jpeg"), imageFile);
MultipartBuilder multipartBuilder = new MultipartBuilder();
multipartBuilder.addFormDataPart("photo", imageFile.getName(), fileBody);
RequestBody fileRequestBody = multipartBuilder.build();

//call
mRestClient.getRetrofitService().uploadProfilePhoto(fileRequestBody, sessionId);
Run Code Online (Sandbox Code Playgroud)

  • MultipartBuilder 现在是 okhttp3 中的 MultipartBody.Builder (6认同)