今天用retrofit2和rxjava 完成了图片列表的上传,记录下
public interface ApiManager {
@Multipart
@POST("/user/addCarInfo")
void addCarInfo(@QueryMap Map
}
使用 Retrofit 2.X 上传
Retrofit 2.X上传文件
使用2.0,我们发现以前的TypedFile类型被私有化了 ,无法继续使用1.9的传方式,因此2.x提供了上传方案,可以MultipartBody.Part代替。
public interface FileUploadService {
@Multipart
@POST(“upload”)
Call upload(@Part(“description”) RequestBody description,
@Part MultipartBody.Part file);
}
具体用法。
先看一个基本的用法:
// 创建 RequestBody,用于封装构建RequestBody
RequestBody requestFile =
RequestBody.create(MediaType.parse(“multipart/form-data”), file);
// MultipartBody.Part 和后端约定好Key,这里的partName是用image
MultipartBody.Part body =
MultipartBody.Part.createFormData(“image”, file.getName(), requestFile);
// 添加描述
String descriptionString = “hello, 这是文件描述”;
RequestBody description =
RequestBody.create(
MediaType.parse(“multipart/form-data”), descriptionString);
// 执行请求
Call call = service.upload(description, body);
call.enqueue(new Callback() {
@Override
public void onResponse(Call call,
Response response) {
Log.v(“Upload”, “success”);
}
@Override
public void onFailure(Call call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
}
上报一张图片
@Multipart
@POST(“you methd url upload/”)
Call uploadFile(
@Part() RequestBody file);
或者 :
@Multipart
@POST()
Observable uploads(
@Url String url,
@Part() MultipartBody.Part file);
上报数量确定的多张图片
@POST(“upload/”)
Call uploadFiles(@Part(“filename”) String description,
@Part(“pic”; filename=“image1.png”) RequestBody imgs1,
@Part(“pic”; filename=“image2.png”) RequestBody imgs2,
@Part(“pic”; filename=“image3.png”) RequestBody imgs3,
@Part(“pic”; filename=“image4.png”) RequestBody imgs4);
如果图片数量不确定
@Multipart
@POST()
Observable uploadFiles(
@Url String url,
@PartMap() Map
图文同时上报
Part方式
@Multipart
@POST(“upload/”)
Call register(
@FieldMap Map
@Part(“avatar”; filename=“avatar.jpg”) RequestBody avatar,
);
扩展一下 将url动态化:
@Multipart
@POST
Observable uploadFileWithPartMap(
@Url() String url,
@PartMap() Map
@Part(“file”) MultipartBody.Part file);
注意如果你用retrofit2.0以上的版本请看下面姿势,否则会如下抛异常!MultipartBody.Part的参数不能指定part() 的Key。
java.lang.IllegalArgumentException: @Part parameters using the MultipartBody.Part must not include a part name in the annotation. (parameter #2)
@Multipart
@POST
Observable uploadFileWithPartMap(
@Url() String url,
@PartMap() Map
@Part MultipartBody.Part file);
java代码:
String token ="dsdsddadad244";
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), file);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
// create a map of data to pass along
RequestBody tokenBody = RequestBody.create(
MediaType.parse("multipart/form-data"), token);
HashMap map = new HashMap<>();
map.put("token", tokenBody);
Call call = service.uploadFileWithPartMap(url, requestBody );
// 执行
call.enqueue(new Callback() {
@Override
public void onResponse(Call call,
Response response) {
Log.v("Upload", "success");
}
@Override
public void onFailure(Call call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
更简单的用Body方式:
@POST()
Call upLoad(
@Url() String url,
@Body RequestBody Body);
如果支持RxJava就是:
@POST()
Observable upLoad(
@Url() String url,
@Body RequestBody Body);
````
Java代码:
//构建body
RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("name", name)
.addFormDataPart("psd", psd)
.addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/*"), file))
.build();
//如果和rxjava1.x , call就换成 Observable
Call call = service.upload(url, requestBody );
// 执行
call.enqueue(new Callback() {
@Override
public void onResponse(Call call,
Response response) {
Log.v("Upload", "success");
}
@Override
public void onFailure(Call call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
此种方式让你很好的解决了用户注册问题,包含用户全部的信息和头像,完美解决你想用表单一起将文字和图片一起提交的情况!
很多时候想用表单的方式:
@Multipart
@POST("upload/")
Call register(
@Body RequestBody body
);
Java代码:
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), file);
Call call = service.register(body);
Response response = call.execute();
##Json提交
上传Json
@POST("/uploadJson")
Observable uploadjson(
@Body RequestBody jsonBody);
upLoadJson 也可以具体指明Content-Type 为 “application/json”格式的
具体组装我们的RequestBody则可以这样:
RequestBody body=
RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), jsonString);
接着可以这样调用:
// 执行请求
Call call = service.uploadJson(description, body);
call.enqueue(new Callback() {
@Override
public void onResponse(Call call,
Response response) {
Log.v("Upload", "success");
}
@Override
public void onFailure(Call call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
}
至于服务器返回什么类型的model, 开发者可以自定义, 譬如你可以把APi 中的 ResponseBody 指定为你自己的javaBean
, 当然上层构建Call时候,Callback
也必须是 Call
@POST("/uploadJson")
Call uploadjson(
@Body RequestBody jsonBody);
仔细的朋友会发现有的地方用Call,有的地方用Observable,如果结合了RxJava就是用后者接收了,这里不关乎什么方式。
上面的代码片段中显示的代码初始化(RequestBody 和description), 以及如何使用文件上传API。正如刚开始已经提到的, 从OkHttp 的RequestBody类中,需要两个RequestBody.create()方法
除了Body描述, 必须将添加文件包装成MultipartBody的实例。这就是你需要使用适当的从客户端上传文件到服务端。此外, 您可以添加createFormData中的uploadFile(Uri fileUri)方法,适合相机拍照回来上传图片的场景。
public static File getFile(Context context, Uri uri) {
if (uri != null) {
String path = getPath(context, uri);
if (path != null && isLocal(path)) {
return new File(path);
}
}
return null;
}
通过以上代码片段,可以构造自己的file, 其他构建ResquestBody的步骤同上所示,以上案列总有一款适合你的web后端。
请注意设置的内容类型。如果你拦截底层OkHttp客户端和更改内容类型为application / json, 你的服务器可能反序列化过程出现的问题。请确保你没有自定义更改multipart/form-data。
upLoad图片也可以具体指明Content-Type 为 “image/jpg”格式的
RequestBody requestFile =
RequestBody.create(MediaType.parse("image/jpg"), mFile);
如果你已经有你的后端项目, 您可以依靠下面的示例代码。我们使用一个简单api 上传到服务器。此外我们告诉api 传入参数的请求, 因为我们使用的是Node.js
解析的回调函数,我们记录每个字段来显示其输出。
method: 'POST',
path: '/upload',
config: {
payload: {
maxBytes: 209715200,
output: 'stream',
parse: false
},
handler: function(request, reply) {
var multiparty = require('multiparty');
var form = new multiparty.Form();
form.parse(request.payload, function(err, fields, files) {
console.log(err);
console.log(fields);
console.log(files);
return reply(util.inspect({fields: fields, files: files}));
});
}}