Раствор 1 Если вы хотите отправить ваши данные в точности как структура, которую вы упомянули, вы должны преобразовать содержимое файлов в Base64
, обернуть их в сериализуемый класс и опубликовать в виде тела. Вот пример класса оболочки:
data class AnswerExerciceBase64(val state: String, val medias: List<Media>) : Serializable
data class Media(val file: Base64File) : Serializable
class Base64File(file: File) : Serializable {
val name: String
val content: String
init {
name = file.name
content = Base64.encodeToString(FileInputStream(file).readBytes(), Base64.DEFAULT)
}
}
И ваш Api
выглядит следующим образом:
@POST("api/exercice/{id}")
fun submitExercice(
@Path("id") id: Int,
@Header("Authorization") token: String,
@Body data: AnswerExerciceBase64
): Call<Void>
Тогда отправленные данные на сервер будут выглядеть так:
{
"state": "this is state",
"medias": [{
"file": {
"content": "Base64 file content",
"name": "f1.txt"
}
}, {
"file": {
"content": "Base64 file content",
"name": "f2.txt"
}
}, {
"file": {
"content": "Base64 file content",
"name": "f3.txt"
}
}]
}
Этот подход настолько близок к тому, что вы хотите, но вы должны знать, что вы должны самостоятельно декодировать содержимое файлов на стороне сервера, поэтому вам нужно больше усилий на стороне сервера. Решение 2 Лучше использовать multipart/form-data
для загрузки файлов и данных. На основании «Возможно ли иметь вложенный MultipartEntities или FormBodyPart в составном POST?» вопрос и ответ на него, multipart/form-data
имеет плоскую структуру и отсутствует иерархия, поэтому вы не можете иметь желаемый структура данных, но вы все равно можете передавать все входные данные в Api
через один объект.
Согласно этой статье , вы можете отправлять несколько файлов в списке, поэтому, если ваш Api
будет как это
@Multipart
@POST("post")
fun submitExercice(@Part data: List<MultipartBody.Part>): Call<ResponseBody>
тогда вы сможете загружать несколько файлов. Вам просто нужно создать список MultipartBody.Part
и добавить в него свои файлы, как показано ниже:
list.add(MultipartBody.Part.createFormData(name, fileName, RequestBody.create(mediaType, file)))
Теперь вы должны добавить параметр state
в этот список. Вы можете сделать это так:
list.add(MultipartBody.Part.createFormData("state", state))
Я разработал класс, который обрабатывает все эти вещи. Вы можете использовать его.
class AnswerExerciceList(state: String) : ArrayList<MultipartBody.Part>() {
init {
add(MultipartBody.Part.createFormData("state", state))
}
fun addFile(name: String, fileName: String, mediaType: MediaType?, file: File) {
add(MultipartBody.Part.createFormData(name, fileName,
RequestBody.create(mediaType, file)))
}
}
Вы можете создать экземпляр этого класса, добавить свои файлы и затем передать его в метод submitExercice
Api в качестве входных данных. Обновление Этот ответ основан на вашей документации Api. Я проверил мой ответ и пример, который вы упомянули в своем вопросе через https://postman-echo.com
, и результат был таким же. Попробуйте следующий фрагмент кода: Api
@Multipart
@POST("api/exercice/{id}")
fun submitExercice(@Path("id") id: Int,
@Header("Authorization") authorization: String,
@Part("answer") answer: String,
@Part medias: List<MultipartBody.Part>,
@Part("state") state: String): Call<ResponseBody>
Media Class
data class Media(val urlVidel: String, val file: File?, val mediaType: MediaType?) {
companion object {
fun mediaListToMultipart(mediaList: List<Media>): List<MultipartBody.Part> {
val list = ArrayList<MultipartBody.Part>()
for (i in mediaList.indices) {
mediaList[i].let {
if (!TextUtils.isEmpty(it.urlVidel))
list.add(MultipartBody.Part.createFormData("medias[$i][urlVideo]", it.urlVidel))
if (it.file != null) {
val requestFile = RequestBody.create(
it.mediaType,
it.file
)
list.add(MultipartBody.Part.createFormData("medias[$i][file]", it.file.getName(), requestFile))
}
}
}
return list
}
}
}
и затем вызовите Api следующим образом:
ApiHelper.Instance.submitExercice(1, "Authorization Token", "Answer", Media.mediaListToMultipart(mediaList), "State").enqueue(callback)