Retrofit之多文件多参数上传

来源:互联网 发布:webpack 优化 编辑:程序博客网 时间:2024/05/22 13:11

Android 移动开发当中免不了要访问网络,访问网络的方式相信每个人都会有自己不同的方法,你可以自己封装网络请求,也可以用网上别人开源的框架。如果开源的框架当中,目前最受欢迎的可要数Retrofit了,而使用Retrofit中最麻烦也就是上传图片或者文件了,本文就对如何使用Retrofit同时上传多参数和多图片文件做详细的演示,并贴出相应实例代码。

在正式本文的讲解之前,先说明一下,基于现在RxJava也火得不要不要的,所以本文就结合RxJava和Retrofit一起来说明他的用法。

1.第一步:导包
现在的导包方式基本都使用Maven自动导包了,所以我们选择下面的方式而不用再去下载jar然后再导入。在Module的build.gradle文件中添加如下的依赖
compile ‘io.reactivex:rxjava:1.2.9’
compile ‘io.reactivex:rxandroid:1.2.1’
compile ‘com.squareup.retrofit2:adapter-rxjava:2.0.0’
compile ‘com.squareup.retrofit2:retrofit:2.2.0’
compile ‘com.squareup.retrofit2:converter-gson:2.2.0’
compile ‘com.squareup.okhttp3:okhttp:3.6.0’

2.第二步:构造你的Retrofit公共管理者
package com.yuanyi.logistics.manager;

import com.yuanyi.logistics.constant.Constants;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
* Created by AHuan on 2017/4/24.
*/

public class RetrofitManager {
private static RetrofitManager mRetrofitManager;
private Retrofit mRetrofit;

private RetrofitManager(){    initRetrofit();}//获取同步静态对象public static synchronized RetrofitManager getInstance(){    if(mRetrofitManager==null){        mRetrofitManager=new RetrofitManager();    }    return mRetrofitManager;}private void initRetrofit(){    HttpLoggingInterceptor httpLoggingInterceptor=new HttpLoggingInterceptor();    httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);    OkHttpClient.Builder builder=new OkHttpClient.Builder();    //添加过滤器    builder.addInterceptor(httpLoggingInterceptor);    //设置连接超时时间    builder.connectTimeout(15, TimeUnit.SECONDS);    //设置读取超时时间    builder.readTimeout(20,TimeUnit.SECONDS);    //设置写超时时间    builder.writeTimeout(20,TimeUnit.SECONDS);    //设置超时重连    builder.retryOnConnectionFailure(true);    OkHttpClient client=builder.build();    mRetrofit=new Retrofit.Builder()            .baseUrl(Constants.BASE_URL)            .addConverterFactory(GsonConverterFactory.create())            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())            .client(client)            .build();}public <T> T creatReq(Class<T> reqServer){    return mRetrofit.create(reqServer);}

}

3.编写请求接口
package com.yuanyi.logistics.network.api;

import com.yuanyi.logistics.bean.AppUpdateBean;
import com.yuanyi.logistics.bean.ResponseBean;
import com.yuanyi.logistics.bean.StorageBean;
import com.yuanyi.logistics.bean.TaskBean;
import com.yuanyi.logistics.bean.User;

import java.util.List;
import java.util.Map;

import okhttp3.RequestBody;
import retrofit2.http.Field;
import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.PartMap;
import retrofit2.http.Query;
import rx.Observable;

/**
* Created by AHuan on 2017/4/22.
*/

public interface TaskApi {
//获取司机的任务列表

/** * 使用post方法,查询参数声明字段是userId * @param userId * @return */@FormUrlEncoded@POST("vehicleInspectionApi/find")Observable<TaskBean> getTask(@Field("userId") String userId );//获取正在任务中的司机列表@POST("billListApi/getBydriverUserId")Observable<List<User>> getDrivers();//提交问题操作接口/** * 实现多参数post请求 * @param dataMap * @return */@FormUrlEncoded@POST("billListApi/ updateProblemGoods")Observable<ResponseBean> updateProblemGoods(@FieldMap Map<String,String> dataMap);//检测版本更新信息@POST("editionApi/editionNo")Observable<AppUpdateBean> getUpdateInfo();//获取搬仓的货物信息@FormUrlEncoded@POST("subaru_Parts/storageCarry/getByStorage")Observable<StorageBean> getStorageInfo(@Field("partNo") String partNo);//提交搬仓上传的货物信息@FormUrlEncoded@POST("subaru_Parts/storageCarry/update")Observable<ResponseBean> submitStorage(@FieldMap Map<String,String> dataMap);//上传加油数据/** * 实现多图片文件多参数上传 * @param params * @return */@Multipart@POST("vehicleInspectionApi/updateOliApi")Observable<ResponseBean> uploadAddOil(@PartMap Map<String, RequestBody> params);/** * get方法,@Query("Id")表示在Url后面追加字段是id的内容,后面的如此类推 * @param id * @param passwords * @param Pass * @return */@FormUrlEncoded@GET("userApi/updateApiPass")Observable<ResponseBean> changePw(@Query("id") int id, @Query("passwords") String passwords, @Query("Pass") String Pass);

}

4.编写工具类
编写一个专门用来生成Map的工具类。
我们以上面中的 Observable uploadAddOil();这个方法为例。

package com.yuanyi.logistics.utils;

import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import okhttp3.MediaType;
import okhttp3.RequestBody;

/**
* Created by AHuan on 2017/12/11.
* 生成Retrofit的多参数和多文件多图片的构造参数map
*/

public class RetrofitRequestBodyUtil {
/**

 *使用的时候传进来的Map的构造为Map<String,Object>,如果传的是普通字符串参数的话,就往map里面put<String,String> *如果传递的是图片或者的话,就put<String,File[]>, key对应的是服务端所要的参数字段名,File[] 所对应的是上传的文件数组 * 例如服务器需要的是下面的参数  @RequestParam(value = "files") MultipartFile[] postedFiles * 我们的map中就需要put("files",File[]); * @param resourceMap * @return */public static Map<String, RequestBody> getRequestBodyMap(Map<String,Object> resourceMap){    Map<String, RequestBody> params=new HashMap<>();    Iterator iterator=resourceMap.entrySet().iterator();    while (iterator.hasNext()){        Map.Entry entry= (Map.Entry) iterator.next();        if(entry.getValue() instanceof String){            //判断值如果是String的话就直接put进去            RequestBody body=RequestBody.create(MediaType.parse("text/plain;charset=UTF-8"),(String)entry.getValue());            params.put((String)entry.getKey(),body);        }else if(entry.getValue() instanceof File){            //判断当前值是单个文件的话就把key设置成服务端所要的参数子端名加文件名,具体格式可以看下面的            RequestBody body=RequestBody.create(MediaType.parse("multipart/form-data;charset=UTF-8"),(File)entry.getValue());            params.put((String)entry.getKey()+"\";filename=\""+((File)entry.getValue()).getName()+"",body);        }else if(entry.getValue() instanceof File[]){            //判断当前的值是文件数组的话,要把一个个文件拆开再put进去            File[] files= (File[]) entry.getValue();            if(files!=null && files.length>0){                for(File f : files){                    RequestBody body=RequestBody.create(MediaType.parse("multipart/form-data;charset=UTF-8"),f);                    params.put((String)entry.getKey()+"\";filename=\""+f.getName()+"",body);                }            }        }    }    return params;}

}

5.下面针对上传加油数据接口贴出我的服务端代码
/**
* 添加启程
* 第一个参数为VehicleInspectionVo对象里面的属性,第二个参数是多图片文件上传
* @param vo
* @return
*/

@RequestMapping(value = "/add", method = RequestMethod.POST)public ApiResult add(VehicleInspectionVo vo, @RequestParam(value = "file") MultipartFile[] postedFiles) {    ApiResult result = new ApiResult();    String fileName = "";// 返回的图片名称 用,号隔开    // 服务器路径    String path = "/upload/images/vehicleinspection/";    // 物理路径    String realPath = PathUtil.getRealPath(request, path);    // 添加    fileName = fileUploaderController.imageupload(postedFiles, realPath);    vo.setFileName(fileName);    String msg = vehService.addApi(vo);    result.setMsg(msg);     if(result.getMsg().equals("录入成功")){         result.setSuccess(true);     }else{         result.setSuccess(false);     }    return result;}

6.贴出android端的调用代码(针对上传加油数据接口实现多图片文件多参数上传)

    File[] files=new File[2];    final String[] fileNames=new String[2];    for(int i=0;i<2;i++){        fileNames[i]= CreatFileUtil.createFileAndComp(imgList[i]);        files[i]=new File(fileNames[i]);    }    final Map<String,Object> params=new HashMap<>();    params.put("id",task_id+"");    params.put("oilMiles",start_km);    params.put("oil",add_oil_number);    params.put("gasStationAddress",address);    params.put("longitude",mLongitude+"");    params.put("latitude",mLatitude+"");    params.put("file",files);    Map<String, RequestBody> requestBodyMap = RetrofitRequestBodyUtil.getRequestBodyMap(params);    showLoading("信息正在提交");    RetrofitManager.getInstance().creatReq(TaskApi.class)            .uploadAddOil(requestBodyMap)            .subscribeOn(Schedulers.io())            .observeOn(AndroidSchedulers.mainThread())            .subscribe(new Subscriber<ResponseBean>() {                @Override                public void onCompleted() {                    closeLoading();                }                @Override                public void onError(Throwable e) {                    closeLoading();                    UIUtil.show("网络出错,数据已缓存至本地");                    params.remove("file");                    String content=UIUtil.convertRequest(params);                    String filePaths="";                    for(int i=0;i<fileNames.length;i++){                        filePaths=filePaths+";"+fileNames[i];                    }                    filePaths=filePaths.substring(1,filePaths.length());                    UploadBean uploadBean=new UploadBean(Constants.ADD_OIL,content,filePaths);                    UploadRequestUtil.saveRequest(uploadBean);                }                @Override                public void onNext(ResponseBean responseBean) {                    if (responseBean.success) {                        UIUtil.show("加油成功");                        finish();                    }else{                        UIUtil.show(responseBean.msg);                    }                }            });
原创粉丝点击