【问题标题】:okhttp multipart image upload with file nameokhttp 带文件名的多部分图片上传
【发布时间】:2014-11-12 13:20:50
【问题描述】:

我正在尝试将图像从 Android 手机上传到服务器。这就是我到目前为止所做的事情

  OkHttpClient client = new OkHttpClient();
            MultipartBuilder builder = new MultipartBuilder();


builder.type(MultipartBuilder.FORM).addPart(RequestBody.create(MediaType.parse("application/json; charset=utf-8"), requestPackage.getJsonParam().toString()));
            for (int i = 0; i < requestPackage.getPics().size(); i++) {
                builder.addPart(RequestBody.create(MediaType.parse("image/png"/* + i*/), new File(URI.create(requestPackage.getPics().get(i)))));
            Log.i("image to upload",URI.create(requestPackage.getPics().get(i)).toString());
            }
            requestBody = builder.build();
     Request request = new Request.Builder().url(requestPackage.getUri()).post(requestBody).build();
            try {
                response = client.newCall(request).execute();
                if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
    //            System.out.println(response.body().string());
                return response.body().string();
            } catch (IOException e) {
                e.printStackTrace();
            }

我如何为不同的部分添加名称。因为如果它们没有名称(键),那么服务器端的人将如何存储它?

【问题讨论】:

  • 您首先必须询问“服务器端的人”他的期望。一个名字?一个“文件名”?一个“文件名”?一个“上传的文件名”?
  • 让我们说图像部分应该是 image1,image2... 我如何在 okhttp 中添加它?

标签: android http mobile okhttp


【解决方案1】:

获取 OkHttp 2.1,并使用MultipartBuilder.addFormDataPart(),它将文件名作为参数。

【讨论】:

  • 只是想知道为什么github.com/square/okhttp/wiki/Recipes 的文档不推荐 addFormDataPart?我按照配方步骤操作,服务器没有将请求识别为 multipartFile。 (Spring 无法将字符串转换为 multipartFile)。但是, addFormDataPart 有效。查看addFormDataPart的源码,在disposition字符串中添加了“filename”。
  • 这是一个差距。向我们发送 PR,(但请先确认示例代码仍然有效)。
【解决方案2】:

自之前的答案以来,语法似乎发生了一些变化。我正在使用 OkHttp 3.2.0。

public void upload(String url, File file) throws IOException {
    RequestBody formBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("file", file.getName(),
            RequestBody.create(MediaType.parse("image/png"), file))
        .addFormDataPart("other_field", "other_field_value")
        .build();
    Request request = new Request.Builder().url(url).post(formBody).build();
    Response response = this.client.newCall(request).execute();
}

【讨论】:

    【解决方案3】:

    大家可以在官方文档中找到:https://github.com/square/okhttp/wiki/Recipes

    特别是你会对Posting a multipart request的以下文章感兴趣:

    RequestBody requestBody = new MultipartBuilder()
        .type(MultipartBuilder.FORM)
        .addPart(
            Headers.of("Content-Disposition", "form-data; name=\"title\""),
            RequestBody.create(null, "Square Logo"))
        .addPart(
            Headers.of("Content-Disposition", "form-data; name=\"image\""),
            RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
        .build();
    

    【讨论】:

    • 所以服务器端的人在标题中获取文件名?
    • 您也可以将文件名作为表单数据发送。但请确保有人正在解码它们。
    • @greenapps 怎么解码呢?我可以将图像发送到服务器端,但不知道解码它。有什么帮助吗?
    【解决方案4】:

    这里有一个完整的解决方案,关于如何使用 okhttp3 上传文件。 首先,在您的代码中添加一个带有点击侦听器按钮的文件选择器,如下所示:

    选择文件的按钮:

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn_choose_file:
            showFileChooser();
            break;
        }
    }
    
    private String filePath = null;
    private File sourceFile;
    private static final int FILE_SELECT_CODE = 0;
    private void showFileChooser() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("*/*");
        intent.addCategory(Intent.CATEGORY_OPENABLE);
    
        try {
            startActivityForResult(
                    Intent.createChooser(intent, "Select a File to Upload"),
                    FILE_SELECT_CODE);
        } catch (android.content.ActivityNotFoundException ex) {
            Toast.makeText(this, "Please install a File Manager.",
                    Toast.LENGTH_SHORT).show();
        }
    }
    

    然后像这样处理onActivityResult:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case FILE_SELECT_CODE:
                if (resultCode == RESULT_OK) {
                    // Get the Uri of the selected file
                    Uri uri = data.getData();
    
                    File   file = new File(getCacheDir(), getFileName(uri));
    
                    int maxBufferSize = 1 * 1024 * 1024;
    
                    try {
                        InputStream inputStream = getContentResolver().openInputStream(uri);
                        Log.e("InputStream Size","Size " + inputStream);
                        int  bytesAvailable = inputStream.available();
                        int bufferSize = Math.min(bytesAvailable, maxBufferSize);
                        final byte[] buffers = new byte[bufferSize];
    
                        FileOutputStream outputStream = new FileOutputStream(file);
                        int read = 0;
                        while ((read = inputStream.read(buffers)) != -1) {
                            outputStream.write(buffers, 0, read);
                        }
                        Log.e("File Size","Size " + file.length());
                        inputStream.close();
                        outputStream.close();
    
                        file.getPath();
                        Log.e("File Path","Path " + file.getPath());
                        file.length();
                        Log.e("File Size","Size " + file.length());
    
                        if(file.length() > 0){
    
                            sourceFile = file;
                            filePath = sourceFile.getPath();
                        }
    
    
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (OutOfMemoryError e) {
                        e.printStackTrace();
                    }
    
    
    
                } else {
    
    
                }
    
                break;
        }
        super.onActivityResult(requestCode, resultCode, data);
    }
    
    
    private String getMimeType(String path) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String contentTypeFor = fileNameMap.getContentTypeFor(path);
        if (contentTypeFor == null)
        {
            contentTypeFor = "application/octet-stream";
        }
        return contentTypeFor;
    }
    
    
    public String getFileName(Uri uri) {
        String result = null;
        if (uri.getScheme().equals("content")) {
            Cursor cursor = getContentResolver().query(uri, null, null, null, null);
            try {
                if (cursor != null && cursor.moveToFirst()) {
                    result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
                }
            } finally {
                cursor.close();
            }
        }
        if (result == null) {
            result = uri.getPath();
            int cut = result.lastIndexOf('/');
            if (cut != -1) {
                result = result.substring(cut + 1);
            }
        }
        return result;
    }
    

    最后,处理文件上传以及其他所需信息,如下所示:

      try {
    
           UpdateInformation("yourEmailAddress", filePath, sourceFile);
    
          } catch (IOException e) {
                        e.printStackTrace();
          }
    
    
    private void UploadInformation(String email, final String _filePath, final File file) throws IOException {
    
    
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
    
    
            //show progress bar here
    
            }
        });
    
    
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .build();
    
    
    
    
    
        String mime = getMimeType(_filePath);
    
    
        RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart("file", file.getName(),
                        RequestBody.create(MediaType.parse(mime), file))
                .addFormDataPart("email", email)
                .build();
    
    
    
    
    
        okhttp3.Request request = new okhttp3.Request.Builder()
                .url("yourEndPointURL")
                .post(body)
                .addHeader("authorization", "yourEndPointToken")
                .addHeader("content-type", "application/json")
                .build();
    
    
    
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                call.cancel();
    
    
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
    
                    //hide progress bar here
    
                    }
                });
    
            }
    
            @Override
            public void onResponse(Call call, okhttp3.Response response) throws IOException {
    
    
                try {
    
                    final String myResponse = response.body().string();
    
    
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
    
                    //hide progress bar here
    
                    //Cont from here
                    //Handle yourEndPoint Response.
    
    
    
                        }
                    });
    
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
    
            }
    
    
    
        });
    }
    

    注意:不要忘记将此权限添加到清单文件中。

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    

    【讨论】:

      【解决方案5】:

      您可以使用如下所示的 multipart 在单个请求中发送多个值

              HttpPost    httppost = new HttpPost(mPostURL);
              MultipartEntity entity = new MultipartEntity();
              entity.addPart("value", new StringBody("upload", Charset.forName("UTF-8")));
              File myFile = new File(mFilePath);
              FileBody fileBody = new FileBody(filePath);
              entity.addPart("file", fileBody);
              entity.addPart("filename", new StringBody("fileName", Charset.forName("UTF-8")));
              httppost.setEntity(entity);
              HttpClient httpClient = new DefaultHttpClient();
      

      【讨论】:

      • 在okhttp中没有办法做到这一点
      猜你喜欢
      • 2021-01-19
      • 2016-06-29
      • 1970-01-01
      • 2016-06-07
      • 2015-07-16
      • 2015-02-22
      • 1970-01-01
      • 1970-01-01
      • 2019-03-24
      相关资源
      最近更新 更多