【Android-upload】Android使用Retrofit上传文件

潘阳舒
2023-12-01

基本用法

文件1:请求返回的实体类

public class UploadBean {

    private String imageUrl;
    private String textFile;

    public String getImageUrl() { return imageUrl; }
    public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
    public String getTextFile() { return textFile; }
    public void setTextFile(String textFile) { this.textFile = textFile; }
}

文件2:定义请求接口

public interface UploadService {

    // [途径A]文件上传使用MultipartBody.Part对象
    @Multipart
    @POST("/file/image")
    Call<UploadBean> uploadDouble(@Part MultipartBody.Part file1,
                                    @Part MultipartBody.Part file2,
                                    @Part("username") RequestBody username,
                                    @Part("password") RequestBody password);
}

文件3:具体调用的地方

    /**
     * 上传文件
     *
     * @param filePathName1 文件1路径及文件名
     * @param filePathName2 文件2路径及文件名
     */
    public void uploadFile(String filePathName1, String filePathName2) {
        // 生成Retrofit
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://192.168.1.6:8080/upload/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        // 生成Service
        UploadService uploadService = retrofit.create(UploadService.class);

        // 要上传的文件
        File file1 = new File(filePathName1);
        File file2 = new File(filePathName2);

        // 创建 RequestBody,用于封装构建MultipartBody.Part。设置MediaType:application/octet-stream(一说:multipart/form-data,待检验)
        RequestBody requestBody1 = RequestBody.create(MediaType.parse("application/octet-stream"), file1);
        RequestBody requestBody2 = RequestBody.create(MediaType.parse("application/octet-stream"), file2);
        // MultipartBody.Part  和后端约定好Key,这里的partName暂时用"file_key_*"
        MultipartBody.Part partFile1 = MultipartBody.Part.createFormData("file_key_1", file1.getName(), requestBody1);
        MultipartBody.Part partFile2 = MultipartBody.Part.createFormData("file_key_2", file2.getName(), requestBody2);
        // 添加参数用户名和密码,并且是文本类型,设置MediaType为文本类型(一说:multipart/form-data,待检验)
        RequestBody userName = RequestBody.create(MediaType.parse("text/plain"), "username");
        RequestBody password = RequestBody.create(MediaType.parse("text/plain"), "password");

        // 执行请求
        Call<UploadBean> call = uploadService.uploadDouble(partFile1, partFile2, userName, password);
        call.enqueue(new Callback<UploadBean>() {
            @Override
            public void onResponse(Call<UploadBean> call, Response<UploadBean> response) {
                Log.e("TAG", response.body().getImageUrl());
            }

            @Override
            public void onFailure(Call<UploadBean> call, Throwable t) {
                t.printStackTrace();
            }
        });
    }

 

解析

上述基本用法使用的是上传有限确定个文件,此种方式还可以简化,另外还可以上传任意个文件,一并总结如下:

1. 上传有限确定个文件(MultipartBody.Part参数)

    // [方式A]优先确定个文件上传使用MultipartBody.Part对象
    @Multipart
    @POST("/file/image")
    Call<UploadBean> uploadDouble(@Part MultipartBody.Part file1,
                                  @Part MultipartBody.Part file2,
                                  @Part("username") RequestBody username,
                                  @Part("password") RequestBody password);

注意:此处 @Part 如果使用 MultipartBody.Part 作为参数类型,@Part 不能携带参数,空参数如上述格式。
如果携带参数,写成:@Part("image") MultipartBody.Part file1
则报错:@Part parameters using the MultipartBody.Part must not include a part name in the annotation

调用处使用 MultipartBody.Part 来构造一个Part对象参数

        // 要上传的文件
        String filePathName1 = Environment.getExternalStorageDirectory() + File.separator + "sample_01.jpg";
        String filePathName2 = Environment.getExternalStorageDirectory() + File.separator + "sample_02.jpg";
        File file1 = new File(filePathName1);
        File file2 = new File(filePathName2);

        // 创建 RequestBody,用于封装构建MultipartBody.Part。设置MediaType为:multipart/form-data
        RequestBody requestBody1 = RequestBody.create(MediaType.parse("multipart/form-data"), file1);
        RequestBody requestBody2 = RequestBody.create(MediaType.parse("multipart/form-data"), file2);
        // MultipartBody.Part  和后端约定好Key,这里的partName暂时用"file_key_*"
        MultipartBody.Part partFile1 = MultipartBody.Part.createFormData("file_key_1", file1.getName(), requestBody1);
        MultipartBody.Part partFile2 = MultipartBody.Part.createFormData("file_key_2", file2.getName(), requestBody2);
        // 添加参数用户名和密码,并且是文本类型,设置MediaType为:multipart/form-data
        RequestBody userName = RequestBody.create(MediaType.parse("multipart/form-data"), "username");
        RequestBody password = RequestBody.create(MediaType.parse("multipart/form-data"), "password");

        // 执行请求
        Call<UploadBean> call = uploadService.uploadDouble(partFile1, partFile2, userName, password);

2. 上传有限确定个文件(RequestBody)

    // [方式B]文件上传使用RequestBody对象
    @Multipart
    @POST("/file/image")
    Call<UploadBean> uploadDouble(@Part("pic01\"; filename=\"sample_01.png") RequestBody file1,
                                  @Part("pic02\"; filename=\"sample_01.png") RequestBody file2,
                                  @Part("username") RequestBody username,
                                  @Part("password") RequestBody password);

注意:此处 @Part 如果使用 RequestBody 作为参数类型,@Part 其必须携带参数,参数如上述格式。
如果未携带参数,写成:@Part RequestBody file1
则报错:@Part annotation must supply a name or use MultipartBody.Part parameter type. (parameter #1)

注意:如果此处 @Part 如果使用 RequestBody 作为参数类型,@Part 携带的参数不如上述格式,目的为了上传文件。
如果携带参数,写成:@Part("image") RequestBody file1
则服务端识别不出来这是一个文件,会当做一个参数上传的例子,所以参数格式要正确

调用处使用直接使用 RequestBody 来构造一个RequestBody对象参数

        // 添加要上传的文件,设置MediaType为:multipart/form-data
        RequestBody requestBody1 = RequestBody.create(MediaType.parse("multipart/form-data"), file1);
        RequestBody requestBody2 = RequestBody.create(MediaType.parse("multipart/form-data"), file2);
        
        // 添加其他参数,设置MediaType为:multipart/form-data
        RequestBody userName = RequestBody.create(MediaType.parse("multipart/form-data"), "username");
        RequestBody password = RequestBody.create(MediaType.parse("multipart/form-data"), "password");

        // 执行请求
        Call<UploadBean> call = uploadService.uploadDouble(requestBody1, requestBody2, userName, password);

 

3. 上传任意个文件(使用@Part实现)

接口

    // [方式C]文件上传使用@Part + List<MultipartBody.Part>对象的方式
    @Multipart
    @POST("/file/image")
    Call<UploadAurora> uploadMulti(@Part List<MultipartBody.Part> parts,
                                   @Part("username") RequestBody username,
                                   @Part("password") RequestBody password);

调用

// 要上传的文件
        String filePathName1 = Environment.getExternalStorageDirectory() + File.separator + "sample_01.jpg";
        String filePathName2 = Environment.getExternalStorageDirectory() + File.separator + "sample_02.jpg";
        File file1 = new File(filePathName1);
        File file2 = new File(filePathName2);

        // 添加要上传的文件,设置MediaType为:multipart/form-data
        RequestBody requestBody1 = RequestBody.create(MediaType.parse("multipart/form-data"), file1);
        RequestBody requestBody2 = RequestBody.create(MediaType.parse("multipart/form-data"), file2);
        // MultipartBody.Part  和后端约定好Key,这里的partName暂时用"file_key_*"
        MultipartBody.Part partFile1 = MultipartBody.Part.createFormData("file_key_1", file1.getName(), requestBody1);
        MultipartBody.Part partFile2 = MultipartBody.Part.createFormData("file_key_2", file2.getName(), requestBody2);
        // 添加其他参数,设置MediaType为:multipart/form-data
        RequestBody userName = RequestBody.create(MediaType.parse("multipart/form-data"), "username");
        RequestBody password = RequestBody.create(MediaType.parse("multipart/form-data"), "password");

        // 添加任意MultipartBody.Part对象进List,集中处理
        List<MultipartBody.Part> partList = new ArrayList<>();
        partList.add(partFile1);
        partList.add(partFile2);

        // 执行请求
        Call<UploadAurora> call = uploadService.uploadMulti(partList, userName, password);

 

4. 上传任意个文件(使用@PartMap实现)

接口

    // [方式C]文件上传使用@PartMap + RequestBody对象的方式
    @Multipart
    @POST("/file/image")
    Call<UploadAurora> uploadMulti(@PartMap Map<String, RequestBody> requestBodyMap,
                                   @Part("username") RequestBody username,
                                   @Part("password") RequestBody password);

调用

        // 要上传的文件
        String filePathName1 = Environment.getExternalStorageDirectory() + File.separator + "sample_01.jpg";
        String filePathName2 = Environment.getExternalStorageDirectory() + File.separator + "sample_02.jpg";
        File file1 = new File(filePathName1);
        File file2 = new File(filePathName2);

        // 添加要上传的文件,设置MediaType为:multipart/form-data
        RequestBody requestBody1 = RequestBody.create(MediaType.parse("multipart/form-data"), file1);
        RequestBody requestBody2 = RequestBody.create(MediaType.parse("multipart/form-data"), file2);
        
        // 添加其他参数,设置MediaType为:multipart/form-data
        RequestBody userName = RequestBody.create(MediaType.parse("multipart/form-data"), "username");
        RequestBody password = RequestBody.create(MediaType.parse("multipart/form-data"), "password");

        // 添加任意RequestBody对象进Map,集中处理
        Map<String, RequestBody> requestBodyMap = new HashMap<>();
        requestBodyMap.put("image\"; filename=\"" + file1.getName(), requestBody1);      //这里的key必须这么写,否则服务端无法识别
        requestBodyMap.put("image\"; filename=\"" + "sample_02.jpg", requestBody2);      //这里的key必须这么写,否则服务端无法识别

        // 执行请求
        Call<UploadAurora> call = uploadService.uploadMulti(requestBodyMap, userName, password);

 

 

参考:https://www.jianshu.com/p/74b7da380855 | Retrofit学习之文件和参数上传

参考:https://www.cnblogs.com/zhujiabin/p/7601658.html | Android Retrofit 2.0文件上传
参考:https://blog.csdn.net/jdsjlzx/article/details/52246114 | Android Retrofit 实现(图文上传)文字(参数)和多张图片一起上传
参考:https://www.jianshu.com/p/acfefb0a204f | Retrofit 2.0 超能实践(三),轻松实现多文件/图片上传/Json字符串/表单
参考:https://blog.csdn.net/sk719887916/article/details/51755427 | Retrofit 2.0 超能实践(三),轻松实现文件/多图片上传/Json..
参考:https://blog.csdn.net/qq_32090185/article/details/86573530 | Android上传单文件和多文件(后台使用MultipartFile)

 类似资料: