zessi
zessi

Reputation: 13

Spring REST uploading and handling multiple files

I am trying to learn how to upload and handle multiple files from a spring consumer (RestTemplate) to a spring rest controller.

The Consumer

    public static List<FileVerification> consume_post_multiple_files_upload(List<Path> paths) {
        final String subAddress = "post_multiple_files_upload";
        final HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        final MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        int counter = 1;
        for (Path path : paths) {
            final FileSystemResource fileSystemResource = new FileSystemResource(path.toString());
            map.add("file_" + (counter++), fileSystemResource);
        }
        final HttpEntity<MultiValueMap<String, Object>> requestFilesEntity = new HttpEntity<MultiValueMap<String, Object>>(map, headers);
        final RestTemplate restTemplate = new RestTemplate();
        final ResponseEntity<List> listResponseEntity = restTemplate.postForEntity(CONSUMER_UPLOAD_TO_SERVER_ADDRESS + subAddress, requestFilesEntity, List.class);
        return listResponseEntity.getBody();
    }

The Controller

    @RequestMapping(value = "post_multiple_files_upload", method = RequestMethod.POST)
    public ResponseEntity<List<FileVerification>> post_multipleFilesUpload(@RequestParam(name = "file_1") MultipartFile multipartFile) throws IOException, NoSuchAlgorithmException {
        GeneralConfig.createServerFileDirectory();
        final List<FileVerification> serverFileVerificationsList = new ArrayList<>();

        FileUtils.getMultipartFileInformation("post_multiple_files_upload", multipartFile).forEach(System.out::println);
        final Path serverFile = GeneralConfig.getServerFileDirectoryPath().resolve(multipartFile.getOriginalFilename());
        FileUtils.createFileAndWriteData(serverFile, multipartFile.getBytes());
        serverFileVerificationsList.add(Factory.getFileVerification(serverFile));


        final HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);

        GeneralConfig.deleteServerFileDirectory();
        System.out.println();
        return new ResponseEntity<List<FileVerification>>(serverFileVerificationsList, headers, HttpStatus.OK);
    }

Test and Utility Code

    @Test
    public void test_consume_post_multiple_files_upload() throws IOException, NoSuchAlgorithmException {
        final int fileCount = 10;
        final List<Path> filesPaths = new ArrayList<>(fileCount);
        final List<FileVerification> clientFileVerifications = new ArrayList<>(fileCount);
        try {
            for (int i = 0; i < fileCount; i++) {
                final Path path = FileUtils.createRandomFileInClient();
                filesPaths.add(path);
                clientFileVerifications.add(Factory.getFileVerification(path));
            }
            final List<FileVerification> serverFileVerifications = consume_post_multiple_files_upload(filesPaths);
            assertArrayEquals(clientFileVerifications.toArray(new FileVerification[0]), serverFileVerifications.toArray(new FileVerification[0]));
            for (int i = 0; i < fileCount; i++) {
                System.out.println("clientFileVerification#" + i + " = " + clientFileVerifications.get(i));
                System.out.println("serverFileVerification#" + i + " = " + serverFileVerifications.get(i));
            }
        } finally {
            for (Path filePath : filesPaths) {
                Files.deleteIfExists(filePath);
            }
        }
    }

-

import java.util.Arrays;

public class FileVerification {

    private String fileName;
    private byte[] digest_SHA256;

    public FileVerification setFileName(String fileName) {
        this.fileName = fileName;
        return this;
    }

    public FileVerification setDigest_SHA256(byte[] digest_SHA256) {
        this.digest_SHA256 = digest_SHA256;
        return this;
    }

    public String getFileName() {
        return this.fileName;
    }

    public byte[] getDigest_SHA256() {
        return this.digest_SHA256;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        FileVerification that = (FileVerification) o;
        return this.fileName.equals(that.fileName) && Arrays.equals(this.digest_SHA256, that.digest_SHA256);
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder();
        for (byte b : digest_SHA256) {
            builder.append(String.format("%02X", b));
        }
        final String digest_SHA256_representation = builder.toString();
        return "FileVerification{fileName='" + this.fileName + '\'' + ", digest_SHA256='" + digest_SHA256_representation + '\'' + '}';
    }
}

-

    public static FileVerification getFileVerification(Path path) throws NoSuchAlgorithmException, IOException {
        final MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
        if (Files.notExists(path)) throw new IllegalArgumentException("file doesn't exist");
        final byte[] digest = messageDigest.digest(Files.readAllBytes(path));
        final String name = path.getFileName().toString();
        return new FileVerification().setFileName(name).setDigest_SHA256(digest);
    }

The Question What changes should be made to the consumer and/or the controller to allow for multiple files to be uploaded to the server?

Update : Problem solved, ill post the answer soon.

Upvotes: 0

Views: 3326

Answers (2)

zessi
zessi

Reputation: 13

The Controller

    @RequestMapping(value = "post_multiple_files_upload", method = RequestMethod.POST)
    public ResponseEntity<List<FileVerification>> post_multipleFilesUpload(@RequestParam(name = "files") List<MultipartFile> multipartFiles) throws IOException, NoSuchAlgorithmException {
        GeneralConfig.createServerFileDirectory();
        final List<FileVerification> serverFileVerificationsList = new ArrayList<>();

        int counter = 1;
        for (MultipartFile multipartFile : multipartFiles) {
            FileUtils.getMultipartFileInformation("post_multiple_files_upload#" + (counter++), multipartFile).forEach(System.out::println);
            final Path serverFile = GeneralConfig.getServerFileDirectoryPath().resolve(multipartFile.getOriginalFilename());
            FileUtils.createFileAndWriteData(serverFile, multipartFile.getBytes());
            serverFileVerificationsList.add(Factory.getFileVerification(serverFile));
        }

        final HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);

        GeneralConfig.deleteServerFileDirectory();
        System.out.println();
        return new ResponseEntity<List<FileVerification>>(serverFileVerificationsList, headers, HttpStatus.OK);
    }

The Consumer

    public static List<FileVerification> consume_post_multiple_files_upload(List<Path> paths) {
        final String subAddress = "post_multiple_files_upload";
        final HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        final MultiValueMap<String, FileSystemResource> map = new LinkedMultiValueMap<>();
        int counter = 1;
        final List<FileSystemResource> fileSystemResourcesList = new ArrayList<FileSystemResource>();
        for (Path path : paths) {
            fileSystemResourcesList.add(new FileSystemResource(path.toString()));
        }
        map.put("files", fileSystemResourcesList);
        final HttpEntity<MultiValueMap<String, FileSystemResource>> requestFilesEntity = new HttpEntity<MultiValueMap<String, FileSystemResource>>(map, headers);
        final RestTemplate restTemplate = new RestTemplate();
        final ResponseEntity<List<FileVerification>> fileVerificationListResponse = restTemplate.exchange(CONSUMER_UPLOAD_TO_SERVER_ADDRESS + subAddress, HttpMethod.POST, requestFilesEntity, new ParameterizedTypeReference<List<FileVerification>>() {
        });
        return fileVerificationListResponse.getBody();
    }

Upvotes: 0

Paul Warren
Paul Warren

Reputation: 2479

Change you Controller.post_multipleFilesUpload to:

public ResponseEntity<List<FileVerification>> post_multipleFilesUpload(@RequestParam(name = "file") List<MultipartFile> multipartFiles) throws IOException, NoSuchAlgorithmException {

Correspondingly, update consume_post_multiple_files_upload to send all files with the same key (file) by modifying the code to map.add("file", filesystemResourceList) instead of adding each resource under its own separate key.

Upvotes: 1

Related Questions