Загрузка списка изображений на загрузочный сервер Java Spring с помощью Retrofit

Итак, я создаю простое приложение для Android и пытаюсь загрузить список изображений на загрузочный сервер Spring с помощью модернизации. Модернизация выполняется на стороне клиента Kotlin. Поэтому я сначала выбираю изображения из галереи телефона и показываю их на экране. Они показаны хорошо. Второй шаг — загрузить их на сервер, и именно здесь возникает проблема. Сначала я конвертирую imageUrls в объекты MultipartBody.Part здесь:

class FormDataContainer(context: Context): AppContainer {
    private val baseUrl = "http://192.168.246.6:8080/pManager/"
    private val retrofit = Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    private val retrofitService: PMangerApiService by lazy {
        retrofit.create(PMangerApiService::class.java)
    }

    override val pMangerApiRepository: PMangerApiRepository by lazy {
        NetworkPManagerApiRepository(retrofitService)
    }
}

Затем я вызываю API и передаю изображения вместе с некоторыми другими данными в этот код:

viewModelScope.launch {
            try {
                Log.i("UPLOAD_PROPERTY", "Before making network request")

                val response = pManagerApiRepository.createProperty(
                    token = "Bearer ${userDetails.token}",
                    userId = userDetails.userId.toString(),
                    property = property,
                    images = imageParts
                )

                if (response.isSuccessful) {
                    val responseBody = response.body()
                    if (responseBody != null) {
                        Log.i("CREATE_PROPERTY_RESPONSE", "Status Code: ${responseBody.statusCode}, Message: ${responseBody.message}")
                    } else {
                        Log.i("CREATE_PROPERTY_RESPONSE", "Response body is null")
                    }
                } else {
                    Log.e("CREATE_PROPERTY_RESPONSE", "Unsuccessful response: ${response.code()}")
                }
            } catch (e: Exception) {
                Log.e("CREATE_PROPERTY_EXCEPTION", "Exception: ${e.message}")
            }
        }

for(part in imageParts) {
            Log.i("IMAGE_PARTS", part.toString())
        }

Я попытался загрузить два изображения, поэтому они parts выглядят так:

okhttp3.MultipartBody$Part@c8aade3okhttp3.MultipartBody$Part@89963e0

Это конечная точка клиентского API для отправки всех данных:

@Multipart
    @POST("api/property/userId = {id}/create")
    suspend fun uploadPropertyDetails(
        @Header("Authorization") token: String,
        @Path("id") userId: String,
        @Part("data") property: Property,
        @Part imageFiles: List<MultipartBody.Part>
    ): Response<PropertyUploadResponse>

И вот как я строю модернизацию:

class DefaultContainer(context: Context): AppContainer {
    private val json = Json { ignoreUnknownKeys = true }

    private val baseUrl = "http://192.168.246.6:8080/pManager/"
    private val retrofit = Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
        .build()

    private val retrofitService: PMangerApiService by lazy {
        retrofit.create(PMangerApiService::class.java)
    }
    override val pMangerApiRepository: PMangerApiRepository by lazy {
        NetworkPManagerApiRepository(retrofitService)
    }

}

Конечная точка API на стороне сервера:

@PostMapping(value = "property/userId = {userId}/create", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    public ResponseEntity<Response> addProperty(@RequestPart(value = "data") @Valid PropertyDTO propertyDTO,@PathVariable int userId,
                                                @RequestParam (value = "imageFiles", required = false) MultipartFile[] imageFiles) throws IOException {
        System.out.println("RESPONSE");
        System.out.println();
        System.out.println(propertyDTO.toString());
        System.out.println();
        System.out.println("IMAGE FILES:");
        for(MultipartFile file : imageFiles) {
            System.out.println(file);
        }

        System.out.println();
        return buildResponse("property",propertyService.createProperty(propertyDTO, imageFiles, userId), "Created successfully", HttpStatus.CREATED);
    }

Я получаю эту ошибку в консоли сервера:

java.lang.NullPointerException: Cannot read the array length because "<local4>" is null

и imageFiles равен нулю

property публикуется успешно, но изображения при этом не работают, сообщение об ошибке указано выше.

Однако когда я вызываю ту же конечную точку от почтальона, изображения загружаются успешно. imageFiles это:

org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@3eb7d8a7org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@3a9c47fc

Итак, в основном я пытаюсь загрузить данные формы на загрузочный сервер Spring. Данные публикуются успешно, если они сделаны почтальоном. Однако запрос не выполняется, если он выполнен из мобильного приложения. На самом деле не отправляются только фотографии, потому что property успешно опубликован.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
1
0
88
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это сработало, когда я обновил эту строку:

imageParts.add(MultipartBody.Part.createFormData(name = "image", file.name, requestFile))

Новая линия:

imageParts.add(MultipartBody.Part.createFormData(name = "imageFiles", file.name, requestFile))

По сути, параметр namecreateFormData на стороне клиента Kotlin должен соответствовать параметру value аннотации @RequestPart для части images (imageFiles) в конечной точке Java Spring Boot API. Это конечная точка загрузки Spring:

@PostMapping(value = "property/userId = {userId}/create", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    public ResponseEntity<Response> addProperty(@RequestPart(value = "data") @Valid PropertyDTO propertyDTO,@PathVariable int userId,
                                                @RequestPart (value = "imageFiles", required = false) MultipartFile[] imageFiles) throws IOException {

        System.out.println();
        return buildResponse("property",propertyService.createProperty(propertyDTO, imageFiles, userId), "Created successfully", HttpStatus.CREATED);
    } 

А это клиентский код для создания объектов MultipartBody.Part:

var imageParts = ArrayList<MultipartBody.Part>()
        _imagesUiState.value.images.forEach {file ->
            Log.i("IMAGE_PATH", file.path)
            val imageFile = File(file.path)
            val requestFile = imageFile.asRequestBody("image/*".toMediaTypeOrNull())
            val imagePart = MultipartBody.Part.createFormData("imageFiles", imageFile.name, requestFile)
            imageParts.add(imagePart)
        }

Другие вопросы по теме