Retrofit uploading a picture

2019-04-10 13:47发布

问题:

I'm using Retrofit v.2.2.0 to upload a picture to my server but the server returns a null value stating no image has been uploaded. The logs shows the image is uploaded and the file name is correct when uploaded. What can be the problem yet it works in postman?

UploadProfilePicture.java

public class UploadProfilePicture extends ContextWrapper {

private GetOnUpload onUpload;
private File imageFile,filesDir,file;
private Uri fileUri;
private String profilePic = "profile_pic";
private String fileName;
private ParcelFileDescriptor parcelFileDescriptor;
private FileDescriptor fileDescriptor;
private  Bitmap profileImage;
private OutputStream os;
private OkHttpLogClientAPI okHttpLogClientAPI;
private GetOnUpload mInterfaceService;


public UploadProfilePicture(Context base) {
    super(base);

    okHttpLogClientAPI = new OkHttpLogClientAPI(getBaseContext());


    mInterfaceService = okHttpLogClientAPI.logger().create(GetOnUpload.class);

}




public void uploadPic(Uri fileUri,String fileName, final OnSetUploadProfilePic setOnUpload) {
    //Build Req estBodies for the map object and a MultipartBody.Part to encapsulate the prof_pic_drawer

    this.fileUri = fileUri;
    this.fileName = fileName;
    try {
        getBitmapFromUri();
    } catch (IOException e) {
        e.printStackTrace();
    }
    file = persistImage();


    RequestBody finalRequestBody = builder.build();
    RequestBody requestFile =
            RequestBody.create(MediaType.parse("multipart/form-data"), getBytesFromBitmap(profileImage));

    // MultipartBody.Part is used to send also the actual file name
    MultipartBody.Part body =
            MultipartBody.Part.createFormData("file", "avatar.jpg", requestFile);
        Call<ResponseUserModel> call = mInterfaceService.upload(body);

        call.enqueue(new Callback<ResponseUserModel>() {

            @Override
            public void onResponse(Call<Response> call, Response<Response> response) {


                if (response.isSuccessful()) {
                    setOnUpload.uploadMessage(response.body());


                } else {
                    Toast.makeText(getBaseContext(), getString(R.string.failed_to_upload), Toast.LENGTH_SHORT).show();
                }

            }

            @Override
            public void onFailure(Call<Response> call, Throwable t) {

                Toast.makeText(getBaseContext(), getString(R.string.failed_to_upload), Toast.LENGTH_SHORT).show();

            }
        });
    }
}

public static byte[] getBytesFromBitmap(Bitmap bitmap) {
    if (bitmap!=null) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 70, stream);
        return stream.toByteArray();
    }
    return null;
}


private MultipartBody.Part prepareFilePart() {

    //TODO: Use FileUtils to get the actual file by uri


    try {
        getBitmapFromUri();
        file = persistImage();


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


    try {
        RequestBody requestFile = RequestBody.create(
                MediaType.parse(getBaseContext().getContentResolver().getType(fileUri)), file);
            return MultipartBody.Part.createFormData("file", file.getName(), requestFile);

    } catch (NullPointerException e) {

        Toast.makeText(getBaseContext(), "" + e.getMessage(), Toast.LENGTH_SHORT).show();

        return null;
    }

}

private RequestBody createPartFromString(String descriptionString) {
    return RequestBody.create(MultipartBody.FORM, descriptionString);
}


private void getBitmapFromUri() throws IOException {
    profileImage = MediaStore.Images.Media.getBitmap(this.getContentResolver(), fileUri);
}

private File persistImage() {
    filesDir = getFilesDir();
     imageFile = new File(filesDir, fileName + ".jpg");

    OutputStream os;
    try {
        os = new FileOutputStream(imageFile);
        profileImage.compress(Bitmap.CompressFormat.JPEG, 70, os);
        os.flush();
        os.close();
    } catch (Exception e) {
        Log.e(getClass().getSimpleName(), "Error writing bitmap", e);
    }

    return imageFile;
}}

GetOnUpload.java

public interface GetOnUpload {
 @Multipart
@POST(Constants.UPLOAD_URL)
Call<Response> upload(@Part MultipartBody.Part file);}

Log

http://local.com/api/v1/avatar http/1.1 11-14 18:40:02.742 8851-9593/com.local.test D/OkHttp: Content-Type: multipart/form-data; boundary=d43da080-f2c3-4743-8cfd-9526cc0bd2f7 11-14 18:40:02.742 8851-9593/com.local.test D/OkHttp: Content-Length: 12424 11-14 18:40:02.743 8851-9593/com.local.test D/OkHttp: --d43da080-f2c3-4743-8cfd-9526cc0bd2f7 11-14 18:40:02.743 8851-9593/com.local.test D/OkHttp: Content-Disposition: form-data; name="file"; filename="avatar.jpg" 11-14 18:40:02.743 8851-9593/com.local.test D/OkHttp: Content-Type: multipart/form-data 11-14 18:40:02.743 8851-9593/com.local.test D/OkHttp: Content-Length: 12201 11-14 18:40:02.743 8851-9593/com.local.test D/OkHttp: 11-14 18:40:02.744 8851-9593/com.local.test D/OkHttp: --d43da080-f2c3-4743-8cfd-9526cc0bd2f7-- 11-14 18:40:02.744 8851-9593/com.local.test D/OkHttp: --> END POST (12424-byte body)

11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: <-- 200 OK http://local.com/api/v1/avatar (587ms) 11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: Server: nginx/1.10.3 (Ubuntu) 11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: Content-Type: application/json 11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: Transfer-Encoding: chunked 11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: Connection: keep-alive 11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: Cache-Control: no-cache, private 11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: Date: Tue, 14 Nov 2017 15:40:03 GMT 11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: X-RateLimit-Limit: 60 11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: X-RateLimit-Remaining: 59 11-14 18:40:03.333 8851-9593/com.local.test D/OkHttp: {"user":"Failed","status":"Image file not uploaded"}

回答1:

This example worked for me

//My data manager                                        
public void doUpload(
    Context context,
    String url) {

    Uri uri = Uri.parse(url);
    File file = new File(getPath(context, uri));
    RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), file);
    MultipartBody.Part body = MultipartBody.Part.createFormData("imageParameterName", file.getName(), reqFile);

    uploadService(body)

}

//REST service
@Multipart
@POST("upload.aspx")
Call<DefaultDTO> uploadService(@Part MultipartBody.Part image);


回答2:

It seems there is a problem with OKHttp so when posting a file and data to the server with retrofit use this format

 file = new File(fileUri.getPath());
        RequestBody fileBody = RequestBody.create(MediaType.parse("image/*"),file);
        RequestBody dataBody = RequestBody.create(MediaType.parse("text/plain"), "id");
        Call<Response> call = mInterfaceService.upload(fileBody,dataBody);

        call.enqueue(new Callback<Response>() {

            @Override
            public void onResponse(Call<Response> call, Response<Response> response) {


                if (response.isSuccessful()) {
                    setOnUpload.uploadMessage(response.body());

                    if(file.exists())
                        file.delete();
                } else {
                    Toast.makeText(getBaseContext(), getString(R.string.failed_to_upload), Toast.LENGTH_SHORT).show();
                }

            }

public interface GetOnUpload {

@Multipart
@POST(Constants.UPLOAD_URL)

Call<Response> upload(@Part("file\";filename=\"avatar.jpg\" ") RequestBody file,@Part("id")RequestBody user);


 }


回答3:

ImageFilePath

@SuppressLint("NewApi")
@TargetApi(Build.VERSION_CODES.KITKAT)
public class ImageFilePath {

    /**
     * Method for return file path of Gallery image
     *
     * @param context
     * @param uri
     * @return path of the selected image file from gallery
     */
    static String nopath = "Select Video Only";

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @SuppressLint("NewApi")
    public static String getPath(final Context context, final Uri uri) {

        // check here to KITKAT or new version
        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {

            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/"
                            + split[1];
                }
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {

                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"),
                        Long.valueOf(id));

                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[] { split[1] };

                return getDataColumn(context, contentUri, selection,
                        selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {

            // Return the remote address
            if (isGooglePhotosUri(uri))
                return uri.getLastPathSegment();

            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }

        return nopath;
    }

    /**
     * Get the value of the data column for this Uri. This is <span id="IL_AD2"
     * class="IL_AD">useful</span> for MediaStore Uris, and other file-based
     * ContentProviders.
     *
     * @param context
     *            The context.
     * @param uri
     *            The Uri to query.
     * @param selection
     *            (Optional) Filter used in the query.
     * @param selectionArgs
     *            (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     */
    public static String getDataColumn(Context context, Uri uri,
                                       String selection, String[] selectionArgs) {

        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = { column };

        try {
            cursor = context.getContentResolver().query(uri, projection,
                    selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return nopath;
    }

    /**
     * @param uri
     * The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri
                .getAuthority());
    }

    /**
     * @param uri
     *            The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     */
    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri
                .getAuthority());
    }

    /**
     * @param uri
     *            The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     */
    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri
                .getAuthority());
    }

    /**
     * @param uri
     *            The Uri to check.
     * @return Whether the Uri authority is Google Photos.
     */
    public static boolean isGooglePhotosUri(Uri uri) {
        return "com.google.android.apps.photos.content".equals(uri
                .getAuthority());
    }
}

ChooseImg

  private void openChooseImgDialog() {
        Intent getIntent = new Intent(Intent.ACTION_GET_CONTENT);
        getIntent.setType("image/*");

        Intent pickIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        pickIntent.setType("image/*");

        Intent chooserIntent = Intent.createChooser(getIntent, "Select Image");
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[]{pickIntent});

        startActivityForResult(chooserIntent, PICK_IMAGE);

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case PICK_IMAGE:
                if (resultCode == Activity.RESULT_OK) {
                    uri = data.getData();
                    File_Path = ImageFilePath.getPath(getActivity(), data.getData());

                    // File_Path = RealPathUtil.getRealPathFromURI_API19(getActivity(), data.getData());

                    //    String filename = uri.getLastPathSegment();

                    Log.d("displayfiletypes","****  "+data.getData() + "         "+File_Path);
                    tv_feedbackfilename.setText(File_Path.substring(File_Path.lastIndexOf("/")+1));

                    try {
                        Bitmap bitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), uri);
                        // Log.d(TAG, String.valueOf(bitmap));

                        // mImgView.setImageBitmap(bitmap);

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } else {
                    Toast.makeText(getActivity(), "Something Went Wrong", Toast.LENGTH_SHORT).show();
                }
                break;

        }
    }

Interface

@Multipart
@POST("url")
Call<ResponseBody> add_feedback(@Part MultipartBody.Part file);

Add this code in your Activity

 Retrofit adapter = new Retrofit.Builder()
                    .baseUrl(Constandapi.ROOT_URL)
                    .build();


   RequestBody requestBody = RequestBody.create(MediaType.parse("*/*"), file);

            MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("your php file key", file.getName(), requestBody);
      Call<ResponseBody> adding_feedback = addfeedback.add_feedback(auth_key_sent, subjectstring_sent, feedbackmsg_sent, fileToUpload);


       adding_feedback.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (response.isSuccessful())
                {
                    progressDialog.dismiss();

                    String result = null;

                    try{
                        result = response.body().string();
                        Log.d("createddates","responce"+result);
                                           }catch (IOException e){
                        e.printStackTrace();
                    }catch (JSONException jsone){
                        jsone.printStackTrace();
                    }
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Toast.makeText(getActivity(), "Please try after sometime", Toast.LENGTH_SHORT).show();

                Log.d("printmessages","***  "+call.toString() + "  "+t.toString());
                progressDialog.dismiss();

            }
        });