Search code examples
javaspring-bootmultipartform-dataresttemplate

Why Multipart form "restream" from gateway microservice isn't working and attached file isn't resent?


I have a controller in gateway microservice that accepts the MultipartFile and resends to the service behind it

   @PostMapping
    public ResponseEntity upload(@ApiParam(name = "file", value = "File", required = true) MultipartFile file)
            throws BaseException {
        if (Objects.isNull(file)){
            throw new CheckFieldException("file", MultipartFile.class);
        }

        if (megabyte * maxFileSize - file.getSize() < 0){
            return ResponseEntity.accepted().body(new DocumentResponseDTO(false, "File size exceeds " + maxFileSize + "MB"));
        }

        DiscoveryConfig.CashTracking config = discoveryConfig.getCashTracking();
        UriComponents uriStatementUpload = UriComponentsBuilder.newInstance().scheme(config.getScheme())
                .host(config.getHost()).port(config.getPort()).path(config.getExcelNominalOperationsPath()).build(true);
        try {
            HttpEntity<byte[]> fileEntity = new HttpEntity(file.getBytes());
            ResponseEntity<DocumentResponseDTO> entity = restTemplate.postForEntity(uriStatementUpload.toUri(), fileEntity, DocumentResponseDTO.class);
            return entity;
        } catch (HttpClientErrorException e) {
            return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsString());
        } catch (IOException e) {
            return ResponseEntity.status(500).body("IOException while getting bytes stream from file");
        }
    }

and in CashTracking service there is also file upload like that:

@PostMapping(value = "/upload")
public ResponseEntity uploadExcelNominalOperationsFile(@ApiParam(name = "file", value = "File", required = true) MultipartFile file) throws IOException {

    try (InputStream is = file.getInputStream()) {
        log.info("Processing incoming Excel file with nominal operations");
        Workbook workbook = new XSSFWorkbook(is);
        log.info("Processing workbook");
        Sheet sheet = workbook.getSheetAt(0);
        log.info("Processing the first sheet");
        List<NominalOperationVO> nominalOperationVOs = new ArrayList<>();
        List<String> fileHeaders = new ArrayList<>();

And when the file is actually uploaded to the gateway service, the service behind it starts processing the file upload, but the MultipartFile file is null. I have explicitly put it in the Entity I have sent to the service behind the gateway, the question, what I'm doing wrong if it is null? If I do upload to that microservice directly, it process the request correctly.


Solution

  • The main stuff I was missing was putting the Http headers per specific multipart form's parts. They should be identical to what has been sent to the gateway service.

       public ResponseEntity upload(@ApiParam(name = "file", value = "Файл", required = true) MultipartFile file)
                throws BaseException {
            if (Objects.isNull(file)){
                throw new CheckFieldException("file", MultipartFile.class);
            }
    
            if (megabyte * maxFileSize - file.getSize() < 0){
                return ResponseEntity.accepted().body(new DocumentResponseDTO(false, "File size exceeds " + maxFileSize + "MB"));
            }
    
            DiscoveryConfig.CashTracking config = discoveryConfig.getCashTracking();
            UriComponents uriStatementUpload = UriComponentsBuilder.newInstance().scheme(config.getScheme())
                    .host(config.getHost()).port(config.getPort()).path(config.getExcelNominalOperationsPath()).build(true);
            try {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.MULTIPART_FORM_DATA);
    
                MultipartBodyBuilder multipartBodyBuilder = new MultipartBodyBuilder();
                //here is the really needed stuff with 2 headers
                Resource resource = new ByteArrayResource(file.getBytes());
                multipartBodyBuilder.part("file", resource)
                        .header("Content-Type",file.getContentType())
                        .header("Content-Disposition","form-data; name=\"file\"; filename=\""+file.getOriginalFilename()+"\"");
    
                // multipart/form-data request body
                MultiValueMap<String, HttpEntity<?>> body = multipartBodyBuilder.build();
                HttpEntity<MultiValueMap<String, HttpEntity<?>>> requestEntity
                        = new HttpEntity<>(body, headers);
                ResponseEntity<DocumentResponseDTO> entity = restTemplate.postForEntity(uriStatementUpload.toUri(), requestEntity, DocumentResponseDTO.class);
                return entity;
            } catch (HttpClientErrorException e) {
                return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsString());
            } catch (IOException e) {
                return ResponseEntity.status(500).body("IOException while getting bytes stream from file");
            }
        }