Retrofit 2多部分图像上传及数据传输

17

大家好,我想通过Retrofit2发布图像和其他数据。我正在发送带有一张图片的数据。

所有其他信息都在存储,但我的图片没有存储。当我使用Postman进行测试时,它可以工作。

enter image description here

请指导我在代码中哪些地方有不足之处

这是可以正常工作的Postman代码片段

OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW");
RequestBody body = RequestBody.create(mediaType, "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"email\"\r\n\r\ntest6@gmail.com\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"password\"\r\n\r\n123456\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nTest\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"phone\"\r\n\r\n1234567890\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"image\"; filename=\"03.JPG\"\r\nContent-Type: image/jpeg\r\n\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--");
Request request = new Request.Builder()
  .url("https://"url"/api/v1/sign-up")
  .post(body)
  .addHeader("content-type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW")
  .addHeader("cache-control", "no-cache")
  .addHeader("postman-token", "2dd038d9-5f52-fcd0-9331-445eaf35c230")
  .build();

Response response = client.newCall(request).execute();

以下是Postman请求的图片:

enter image description here

这是我的Retrofit API

    @Multipart
    @POST("sign-up")
    Call<SignUpResponse> getSignUpResponse(
            @Part("email") RequestBody email,
            @Part("password") RequestBody password,
            @Part("name") RequestBody name,
            @Part("phone") RequestBody phone,
            @Part MultipartBody.Part image
            //@Part("image") RequestBody image // i have thried them both but they didnt work
            //@Part("image\"; filename=\"pp.jpg\" ") RequestBody image
    );

这是我的客户区:
private RetrofitClient() {

    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
    httpClient.addInterceptor(logging);  // <-- this is the important line!

    retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(httpClient.build())
            .build();
}

这是我发出请求的部分:
RequestBody namePart = RequestBody.create(MultipartBody.FORM, "nameasd");
RequestBody emailPart = RequestBody.create(MultipartBody.FORM, "emailasd@gmai.com");
RequestBody mobilePart = RequestBody.create(MultipartBody.FORM, "123456623");
RequestBody passwordPart = RequestBody.create(MultipartBody.FORM, "123456123");
//String filepath = "/storage/0403-0201/DCIM/Camera/20180926_203219.jpg"; this is the image source
File file = new File(filepath);
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
//RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("image",file.getName(),reqFile);

Call<SignUpResponse> call = RetrofitClient.getInstance().getApi().getSignUpResponse(emailPart, passwordPart, namePart, mobilePart, body);
                call.enqueue(new Callback<SignUpResponse>() {
                    @Override
                    public void onResponse(Call<SignUpResponse> call, Response<SignUpResponse> response) {
                        progressDialog.dismiss();
                        Log.d(TAG, "onResponse: "+response.body());
                        Log.d(TAG, "onResponse: meta: " + response.body().getMeta().getStatus());
                    }
                    @Override
                    public void onFailure(Call<SignUpResponse> call, Throwable t) {
                        Toast.makeText(SignupActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
                        Log.d(TAG, "onFailure: "+t.getMessage());
                    }
                });

这是我获取数据的代码{{code}}

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // get selected images from selector
        if (requestCode == REQUEST_CODE) {
            if (resultCode == RESULT_OK) {

                mResults = data.getStringArrayListExtra(SelectorSettings.SELECTOR_RESULTS);
                imagePath = mResults.get(0);
                Glide.with(SignupActivity.this)
                        .load(mResults.get(0))
                        .into(profileImage);
              }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

我甚至将其设置为视图,这也有效果...

文件路径中是否包含图像? - Bhuvaneshwaran Vellingiri
是的,它有一张图片... - Wasi Sadman
检查文件是否为空或有价值?如果(文件!= null) - Bhuvaneshwaran Vellingiri
String path = Environment.DIRECTORY_DCIM + "/Camera/IMG_20180928_071551.jpg"; path 可以像这样使用。 - Bhuvaneshwaran Vellingiri
请将图像更改为多部分。RequestBody reqFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); 这样应该可以工作。 - Bhuvaneshwaran Vellingiri
5个回答

31

我们在Postman中测试API… 因此我的Create Post回答包括(全部动态)

  • 头文件
  • 简单字符串
  • 单张图片
  • 图片数组
  • 类别数组
  • 特性数组

几乎所有的事情

以下是用于API测试的Postman图像... 您将获得请求的清晰概念

  • 头文件图像

输入图像描述

因此,对于这个… 以下是我的API...

@POST("post-create")
    Call<PostCreateResponse> getPostCreateBodyResponse(
            @Header("Accept") String accept,
            @Header("Authorization") String authorization,
            @Body RequestBody file
    );

现在进入Retrofit客户端区域--->
private Retrofit retrofit;

// This is Client
private RetrofitClient() {

        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

        httpClient.connectTimeout(100, TimeUnit.SECONDS);
        httpClient.readTimeout(100,TimeUnit.SECONDS);
        httpClient.writeTimeout(100,TimeUnit.SECONDS);
        httpClient.addInterceptor(logging);  // <-- this is the important line!

        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .client(httpClient.build())
                .build();
    }

这是我发送请求的方式...
/*
     * -------------- Retrofit post Create single featured Image Working with MultipartBody -----------
     * */

    progressDialog.show();

    MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);

    builder.addFormDataPart("title", "3 room Current Free")
            .addFormDataPart("location", "Dhaka")
            .addFormDataPart("latitude", "23.7515")
            .addFormDataPart("longitude", "90.3625")
            .addFormDataPart("condition", "1")
            .addFormDataPart("rent_amount", "123456")
            .addFormDataPart("is_negotiable", "0")
            .addFormDataPart("available_from", "2018-10-15");

    // Categories
    for (int categoryId : categories) {
        builder.addFormDataPart("categories[]", String.valueOf(categoryId));
    }
    // Features
    for (Integer featureId : features) {
        builder.addFormDataPart("features[]", String.valueOf(featureId));
    }

    // featured Image
    if (photoPaths.get(0) != null) {
        File featured_image = new File(photoPaths.get(0));
        if (featured_image.exists()) {

// If you want to use Bitmap then use this

            Bitmap bmp = BitmapFactory.decodeFile(featured_image.getAbsolutePath());
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            bmp.compress(Bitmap.CompressFormat.JPEG, 30, bos);

            builder.addFormDataPart("featured_photo", featured_image.getName(), RequestBody.create(MultipartBody.FORM, bos.toByteArray()));


// If you want to use direct file then use this ( comment out the below part and comment the above part )

            //builder.addFormDataPart("featured_photo", featured_image.getName(), RequestBody.create(MultipartBody.FORM, featured_image));
        }
    }

    // Images
    for (String photoPath : photoPaths) {
        if (photoPath != null) {
            File images = new File(photoPath);
            if (images.exists()) {
                builder.addFormDataPart("images[]", images.getName(), RequestBody.create(MultipartBody.FORM, images));
            }
        }
    }

    RequestBody requestBody = builder.build();
    Call<PostCreateResponse> call = RetrofitClient.getInstance().getApi().getPostCreateBodyResponse(Accept, Authorization, requestBody);
    call.enqueue(new Callback<PostCreateResponse>() {
        @Override
        public void onResponse(Call<PostCreateResponse> call, Response<PostCreateResponse> response) {
            progressDialog.dismiss();
            Log.d(TAG, "onResponse: response code: retrofit: " + response.code());
        }

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

        }
    });

    /*
     * ---------------- Retrofit post Create single featured Image Working with MultipartBody----------------
     * */

希望这能帮助到大家...谢谢


1
@Body参数不能与表单或多部分编码一起使用。 - Ibrahim Sušić
请问您能否解释一下为什么它不能与表单或多部分编码一起使用?@IbrahimSušić - Wasi Sadman
1
对不起,我的错误。我在 @Multipart 网络中实现了它,这让我遇到了问题。谢谢您的回答 :) - Ibrahim Sušić

3
获取图片的方法如下:
Uri mImageUri = data.getData();

// Get the cursor
Cursor cursor = getContentResolver().query(mImageUri, 
    filePathColumn, null, null, null);
// Move to first row
cursor.moveToFirst();

int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
imageURI = cursor.getString(columnIndex);
cursor.close(); 

File file = new File(mImageUri.getPath())
RequestBody reqFile = RequestBody.create(okhttp3.MediaType.parse("image/*"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("image",
    file.getName(), reqFile);

我认为在我的情况下,“companyLogo”应该改成“image”? - Wasi Sadman
1
我已经尝试过"multipart/form-data"了...但对我来说不起作用... - Wasi Sadman
字符串 filepath = "/storage/0403-0201/DCIM/Camera/20180926_203219.jpg"; 我已经硬编码了文件路径。这样做有问题吗? - Wasi Sadman
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); 我已经尝试过了,但它没有起作用 @BhuvaneshwaranVellingiri - Wasi Sadman
使用okhttp3在MediaType中。 - Archu Mohan
显示剩余2条评论

2
这��我的活动代码,我正在使用multipart来显示图片,请按照以下代码操作:
public void uploadimage()
{
    String filePath = getRealPathFromURIPath(uri1, DriverDetails.this);
    Log.d("hanish123456","File path->  "+filePath);
    file1 = new File(filePath);
    Log.d("uploadimage", "Filename " + profileimage1);
    Bitmap bmp = BitmapFactory.decodeFile(file1.getAbsolutePath());
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    bmp.compress(Bitmap.CompressFormat.JPEG, 30, bos);

    MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("image", profileimage1,
            RequestBody.create(MediaType.parse("image/*"), bos.toByteArray()));
    RequestBody filename = RequestBody.create(MediaType.parse("text/plain"), profileimage1);

    OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(3, TimeUnit.MINUTES)
            .readTimeout(3,TimeUnit.MINUTES)
            .writeTimeout(3,TimeUnit.MINUTES).build();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(SERVER_PATH)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    ApiService uploadImage = retrofit.create(ApiService.class);

    Log.d("uploadimage", fileToUpload+"   "+filename);
    Call<ProfileResponse> fileUpload = uploadImage.uploadFile(fileToUpload, filename);
    fileUpload.enqueue(new Callback<ProfileResponse>() {
        @Override
        public void onResponse(Call<ProfileResponse> call, Response<ProfileResponse> response) {
            if(response.isSuccessful()){
                Toast.makeText(DriverDetails.this,"Successful  "+ response.raw().message(), Toast.LENGTH_LONG).show();
            }
            else {
                Toast.makeText(DriverDetails.this, response.raw().message(), Toast.LENGTH_LONG).show();
            }
            // Toast.makeText(MainActivity.this, "Success " + response.body().getSuccess(), Toast.LENGTH_LONG).show();
            Log.d("uploadimage", "No Error ");
        }
        @Override
        public void onFailure(Call<ProfileResponse> call, Throwable t) {
            if (t instanceof SocketTimeoutException) {
                Log.d("uploadimage", "Error occur " + t.getMessage());
            }
        }
    });
}

在Postman中进行检查,只需添加您的基本URL,然后跟随Api服务POST请求。在Postman正文中添加键值以获取此格式的数据 { "id":"1", "user_type":"1" } - s.j
Log.d("uploadimage", "Filename " + profileimage1); 你的profileimage1是什么?它是路径还是文件? - Wasi Sadman
它的变量在活动中定义,用于获取图像。 - s.j
请问 uploadImage.uploadFile(fileToUpload, filename); 这个方法在哪里? - kallis

1

还有一种更简单的方法可以发送其他数据,您可以发送Hashmap<String,String>

@Multipart
    @POST("sign-up")
    Call<SignUpResponse> getSignUpResponse(@Part MultipartBody.Part file, @PartMap() Map<String, String> partMap); 

如何发送包含图像和字符串的ArrayList对象? - sanjana
@sanjana,你得到答案了吗?你用了哪个库,Retrofit还是Volley? - Rahul Pandey

-1

MultipartBody.Part.createFormData("file","fileName",RequestBody.create(okhttp3.MediaType.parse("image/*"), file))


3
请记住,Stack Overflow 不仅旨在解决当前的问题,还要帮助未来的读者找到类似问题的解决方案,这需要理解底层代码。对于我们社区中的初学者和不熟悉语法的成员来说,这尤其重要。鉴于此,您能否编辑您的答案,包括您正在做什么的解释以及为什么您认为这是最好的方法? - Jeremy Caney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接