Spring Controller - Тестирование для получения вложенного dto с multipartfile внутри с почтальоном - PullRequest
1 голос
/ 31 мая 2019

Я работаю над сервисом, который принимает DTO в методе POST и создает объект на основе этого DTO. Внутри находится многокомпонентный файл, который будет изображением, используемым сущностью, которая будет создана.

Используя почтальон для проверки моего бэкэнда, я продолжаю получать, казалось бы, пустой DTO. Три лога внутри контроллера возвращают null, 0 и null соответственно.

Вот как я настраиваю свои данные, и я уверен, что проблема в этом:

postman-image

Я преобразовал свое изображение в строку base64, которая, насколько я знаю, является единственным способом публикации вложенного изображения.

Код

Контроллер

@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<InventoryComponentDto> create(@ModelAttributee InventoryComponentDto request) {

    System.out.println(request.getDescription());
    System.out.println(request.getMinimal_supply());
    System.out.println(request.getComponent());

    InventoryComponentDto result = inventoryComponentService.create(request);
    if (result == null) {
        return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
    }

    return ResponseEntity.ok(result);
}

InventoryComponentDto

public class InventoryComponentDto {

    private ComponentDto component;

    private String description;

    private Date createdAt;

    private Date updatedAt;

    private int minimal_supply;

    private int supply;

}

ComponentDto

public class ComponentDto {

    private Long id;

    private int number;

    private String name;

    private FileDto image;

}

FileDto

public class FileDto {

    private String name;

    private String type;

    private String url;

    private MultipartFile data;

}

Как бы я смог адекватно создать свой dto в почтальоне, включая изображение?

Обновление

"status": 400,
"error": "Bad Request",
"message": "JSON parse error: (was java.lang.NullPointerException); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.package.MCI.dto.InventoryComponentDto[\"component\"]->com.package.MCI.dto.ComponentDto[\"image\"])",
"trace": "org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: (was java.lang.NullPointerException); nested...

1 Ответ

1 голос
/ 01 июня 2019

Вам необходимо создать собственный десериализатор Джексона.

//CustomDeserializer

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItem;

import org.springframework.util.Base64Utils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

public class CustomDeserializer extends StdDeserializer<FileDTO> {

    public CustomDeserializer() {
        super(FileDTO.class);
    }

    protected CustomDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public FileDTO deserialize(JsonParser jsonParser,
            DeserializationContext deserializationContext)
            throws IOException, JsonProcessingException {

        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
        String name = node.get("name").asText();
        String url = node.get("url").asText();
        String type = "." + node.get("type").asText();
        String fileBase64 = node.get("data").asText();

        byte[] fileBytes = Base64Utils.decodeFromString(fileBase64);

        FileItem fileItem = new DiskFileItem(name, "image/jpg", false, name + type,
                fileBytes.length, null);
        fileItem.getOutputStream().write(fileBytes);
        fileItem.getOutputStream().flush();
        MultipartFile file = new CommonsMultipartFile(fileItem);
        fileItem.getOutputStream().close();

        FileDTO fileDTO = new FileDTO();
        fileDTO.setName(name);
        fileDTO.setUrl(url);
        fileDTO.setType(type);
        fileDTO.setData(file);

        return fileDTO;

    }

}

И используйте это как:

//FileDTO

@JsonDeserialize(using = CustomDeserializer.class)
public class FileDTO {

Вам нужны эти две зависимости:

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.5</version>
</dependency>
...