Retrofit2.0 实现图文(参数+图片)上传方法总结

Retrofit2.0 实现图文(参数+图片)上传方法总结,第1张

概述最近项目里用到了类似图文上传的功能,以前都是封装OkHttp的文件上传功能,这次想换个姿势,想用Retrofit2.0实现这样的功能,本来以为挺简单的,没想到进入了深坑,连续调整了好几种姿势都报了同一个错,接着网上类似

最近项目里用到了类似图文上传的功能,以前都是封装Okhttp的文件上传功能,这次想换个姿势,想用Retrofit2.0实现这样的功能,本来以为挺简单的,没想到进入了深坑,连续调整了好几种姿势都报了同一个错,接着网上类似的文章找了一大推,讲得都是模棱两可,或者对多参数格式不够友好,最后还是去看了相关的源码,自己把这个问题提出来解决了,在这里记录一下。

一、定义网络请求接口

public interface GoodsReturnAPIService {  @Multipart  @POST(Compares.GOODS_RETURN_POST)  //这里是自己post文件的地址  Observable<GoodsReturnPostEntity> postGoodsReturnPostEntitys(@PartMap Map<String,Requestbody> map,@Part List<Multipartbody.Part> parts);}

上面定义了一个接口用于上传文件请求,有几个注解需要说明一下, @Multipart这是Retrofit专门用于文件上传的注解,需要配合@POST一起使用。

方法postGoodsReturnPostEntitys(@PartMap Map<String,@Part List<Multipartbody.Part> parts)第一个参数使用注解@PartMap用于多参数的情况,如果是单个参数也可使用注解@Part。

在类型Map<String,Requestbody>中,Map第一个泛型String是服务器接收用于文件上传参数字段的Key,第二个泛型Requestbody是Okhttp3包装的上传参数字段的Value,这也是图文上传成功的关键所在。在后面会具体说到。

第二个参数使用注解@Part用于文件上传,多文件上传使用集合类型List<Multipartbody.Part>,单文件可以使用类型Multipartbody.Part,具体的使用同样后面讲。

这里着重说明一下,postGoodsReturnPostEntitys(@PartMap Map<String,@Part List<Multipartbody.Part> parts)方法参数这样写纯属个人习惯,你也可以直接使用一个参数postGoodsReturnPostEntitys(@PartMap Map<String,Requestbody> map),不过后面对Requestbody的处理方式也要跟着变化,这里就不详细说了,只会介绍上面这种简便清晰的方式。

二、初始化Retrofit

public class httpRequestClIEnt {  public static final String TAG = "httpRequestClIEntTAG";  private static Retrofit retrofit;  private static OkhttpClIEnt getokhttpClIEnt() {    //日志显示级别    httpLoggingInterceptor.Level level= httpLoggingInterceptor.Level.BODY;    //新建log拦截器    httpLoggingInterceptor loggingInterceptor=new httpLoggingInterceptor(new httpLoggingInterceptor.Logger() {      @OverrIDe      public voID log(String message) {        Log.d(TAG,message);      }    });    loggingInterceptor.setLevel(level);    //定制Okhttp    OkhttpClIEnt.Builder httpClIEntBuilder = new OkhttpClIEnt        .Builder();    //Okhttp进行添加拦截器loggingInterceptor    httpClIEntBuilder.addInterceptor(loggingInterceptor);    return httpClIEntBuilder.build();  }  public static Retrofit getRetrofithttpClIEnt(){    if(null == retrofit){      synchronized (httpRequestClIEnt.class){        if(null == retrofit){          retrofit = new Retrofit.Builder()              .clIEnt(getokhttpClIEnt())              .baseUrl(Compares.URL)              .addConverterFactory(GsonConverterFactory.create())              .addCallAdapterFactory(RxJava2CallAdapterFactory.create())              .build();        }      }    }    return retrofit;  }}

为了演示,Retrofit封装比较简陋,为的是查看网络拦截,就不详细说了。

三、发起文件上传请求

private voID postGoodsPicToServer(){    Map<String,Requestbody> params = new HashMap<>();    //以下参数是伪代码,参数需要换成自己服务器支持的    params.put("type",convertToRequestbody("type"));    params.put("Title",convertToRequestbody("Title"));    params.put("info",convertToRequestbody("info");    params.put("count",convertToRequestbody("count"));    //为了构建数据,同样是伪代码    String path1 = Environment.getExternalStorageDirectory() + file.separator + "test1.jpg";    String path2 = Environment.getExternalStorageDirectory() + file.separator + "test1.jpg";    List<file> fileList = new ArrayList<>();    fileList.add(new file(path1));    fileList.add(new file(path2));    List<Multipartbody.Part> partList = filesToMultipartbodyParts(fileList);    httpRequestClIEnt.getRetrofithttpClIEnt().create(GoodsReturnAPIService.class)        .postGoodsReturnPostEntitys(params,partList)        .subscribeOn(Schedulers.newThread())        .observeOn(AndroIDSchedulers.mainThread())        .subscribe(new Observer<GoodsReturnPostEntity>() {          @OverrIDe          public voID onSubscribe(@NonNull disposable d) {          }          @OverrIDe          public voID onNext(@NonNull GoodsReturnPostEntity goodsReturnPostEntity) {          }          @OverrIDe          public voID onError(@NonNull Throwable e) {          }          @OverrIDe          public voID onComplete() {          }        });}

上面的params和fileList都是构造的伪代码,需要根据自己项目的业务需求改变。

下面是上传文件成功第一个关键,对参数请求头(姑且叫这个名字,对应Retrofit上传文件时参数那部分请求头,下文件(图片)请求头同理,对应文件那部分请求头)的content-type赋值,使用convertToRequestbody()方法。

private Requestbody convertToRequestbody(String param){    Requestbody requestbody = Requestbody.create(MediaType.parse("text/plain"),param);    return requestbody;  }

因为GsonConverterFactory.create()转换器的缘故,会将参数请求头的content-type值默认赋值application/Json,如果没有进行这步转换 *** 作,就可以在OKhttp3的日志拦截器中查看到这样的赋值,这样导致服务器不能正确识别参数,导致上传失败,所以这里需要对参数请求头的content-type设置一个正确的值:text/plain。

下面是上传文件成功第二个关键的地方,将文件(图片)请求头的content-type使用方法filesToMultipartbodyParts()对其赋值"image/png",并返回Multipartbody.Part集合。

private List<Multipartbody.Part> filesToMultipartbodyParts(List<file> files) {    List<Multipartbody.Part> parts = new ArrayList<>(files.size());    for (file file : files) {      Requestbody requestbody = Requestbody.create(MediaType.parse("image/png"),file);      Multipartbody.Part part = Multipartbody.Part.createFormData("@R_301_2205@s",file.getname(),requestbody);      parts.add(part);    }    return parts;  }

说到底,还是对参数请求头和文件(图片)请求头的content-type属性赋值处理,不要让Retrofit 默认赋值,这里才是关键。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Retrofit2.0 实现图文(参数+图片)上传方法总结全部内容,希望文章能够帮你解决Retrofit2.0 实现图文(参数+图片)上传方法总结所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1144946.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存