文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Retrofit2.0怎么实现图文上传

2023-05-30 22:19

关注

这篇文章将为大家详细讲解有关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, RequestBody> map, @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, RequestBody> map, @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 path2 = Environment.getExternalStorageDirectory() + File.separator + "test1.jpg";    String path3 = Environment.getExternalStorageDirectory() + File.separator + "test1.jpg";    List<File> fileList = new ArrayList<>();    fileList.add(new File(path2));    fileList.add(new File(path3));    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("multipartFiles", file.getName(), requestBody);      parts.add(part);    }    return parts;  }

关于“Retrofit2.0怎么实现图文上传”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯