这篇文章将为大家详细讲解有关Retrofit2.0怎么实现图文上传,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

创新互联建站主要企业基础官网建设,电商平台建设,移动手机平台,小程序开发等一系列专为中小企业按需制作网站产品体系;应对中小企业在互联网运营的各种问题,为中小企业在互联网的运营中保驾护航。
最近项目里用到了类似图文上传的功能,以前都是封装OkHttp的文件上传功能,这次想换个姿势,想用Retrofit2.0实现这样的功能,本来以为挺简单的,没想到进入了深坑,连续调整了好几种姿势都报了同一个错,接着网上类似的文章找了一大推,讲得都是模棱两可,或者对多参数格式不够友好,最后还是去看了相关的源码,自己把这个问题提出来解决了,在这里记录一下。
一、定义网络请求接口
public interface GoodsReturnApiService {
@Multipart
@POST(Compares.GOODS_RETURN_POST) //这里是自己post文件的地址
Observable postGoodsReturnPostEntitys(@PartMap Map map, @Part List parts);
} 上面定义了一个接口用于上传文件请求,有几个注解需要说明一下, @Multipart这是Retrofit专门用于文件上传的注解,需要配合@POST一起使用。
方法postGoodsReturnPostEntitys(@PartMap Map
在类型Map
第二个参数使用注解@Part用于文件上传,多文件上传使用集合类型List
这里着重说明一下,postGoodsReturnPostEntitys(@PartMap Map
二、初始化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 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 fileList = new ArrayList<>();
fileList.add(new File(path2));
fileList.add(new File(path3));
List partList = filesToMultipartBodyParts(fileList);
HttpRequestClient.getRetrofitHttpClient().create(GoodsReturnApiService.class)
.postGoodsReturnPostEntitys(params,partList)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@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 ListfilesToMultipartBodyParts(List files) { List 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怎么实现图文上传”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。