1、应用场景
有这样一个需求:要实现附件与字符串参数同时提交请求。
附件可能是多个,字符串参数也可能是多个。
2、实现
2.1、api的声明写法
只实现多文件上传,处理方式如下:
@Multipart
@POST("api/uploadFile")
fun uploadFiles(
@Part parts: List<MultipartBody.Part>
): Call<ResponseBody>
实现多文件上传及多字符串参数组合形式,处理方式如下:
@Multipart
@POST("api/uploadRecord")
fun uploadRecord(
@PartMap inspectionBean: Map<String, @JvmSuppressWildcards RequestBody>,
@Part imgs: List<MultipartBody.Part>,
@Part videos: List<MultipartBody.Part>
): Call<ResponseBody>
2.2、实际调用
实现多文件上传及多字符串参数组合形式,实际调用如下:
//selectedImageFilePaths 组装文件对象列表
private var selectedImageFilePaths: ArrayList<File> = ArrayList()
private var selectedVideoFilePaths: ArrayList<File> = ArrayList()
val map = HashMap<String, RequestBody>()
map["id"] = toRequestBody(bean!!.id)
map["content"] = toRequestBody(bean!!.content)
val result :ResponseBody = uploadRecord(
map,
filesToMultipartBodyParts("imgs", selectedImageFilePaths)!!,
filesToMultipartBodyParts("videos", selectedVideoFilePaths)!!,
deleteFiles
)
//输出
val jsonStr = String(result.bytes())
println(jsonStr)
toRequestBody子函数:
private fun toRequestBody(value: String): RequestBody {
return RequestBody.create(MediaType.parse("text/plain"), value)
}
filesToMultipartBodyParts子函数(将File转成MultipartBody.Part):
private fun filesToMultipartBodyParts(
name: String,
files: List<File>
): List<MultipartBody.Part>? {
if (files == null) {
return null
}
val parts: MutableList<MultipartBody.Part> =
ArrayList(files.size)
for (file in files) {
val requestBody = RequestBody.create(MediaType.parse("*/*"), file)
val part =
MultipartBody.Part.createFormData(name, file.name, requestBody)
parts.add(part)
}
return parts
}
在api声明处我们需要的参数是RequestBody类型的,所以需要将字符串转成RequestBody类型,子函数作用也在于此。
3、总结
关键字:
@PartMap:
不支持直接与@FormUrlEncoded同时使用,所以需要单独注意字符串编码问题,主要是采用@PartMap是采用"binary"方式进行传输的。
支持多个ResponseBody方式传输。
@Part:单个ResponseBody方式传输。
RequestBody:存放请求信息的对象,如header等信息
MultipartBody.Part:多文件上传时要求的格式,继承RequestBody这个类。
@JvmSuppressWildcards:用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符,kotlin需要添加。