Search code examples
javaangularjsdocxjhipster

Send .docx file from server to client in jhipster application


I am using Jhipster.

I am using docx4j to create a .docx file.

I want to download this .docx file from server to client.

But The file I download is corrupted.

On server side:

I generate my file and put it in a byte[]

WordprocessingMLPackage p = null;
...
File f = new File(filePath);
p.save(f);
byte[] stream = Files.readAllBytes(f.toPath());

I have tried to send it to the client in different format:

byte[]

byte[] encoded Base64

String

String encoded Base64

An example of what's look like my method:

// send back as String encoded in Base64
public ResponseEntity<FileDTO> getFile(@PathVariable Long id) throws URISyntaxException, IOException {
    FileDTO result = fillRepository.findOne(id);
    byte[] stream = FileUtil.getFile(id) // retrieve file as byte[]
    byte[] encoded = Base64.encodeBase64(stream);
    String encodedString = new String(encoded, "UTF-8");
    result.setFile(encodedString);
    return ResponseUtil.wrapOrNotFound(Optional.ofNullable(result));
}

On client side:

I retrieve my file as byte[] or String and I put it in a blob to be downloaded.

FileService.get({id: id}, function(result) {
    var res = result.file;
    // var res = Base64.decode(result.file);
    vm.blob = new Blob([res], {type: 'data:attachment;charset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document'});
    vm.url = (window.URL || window.webkitURL).createObjectURL(vm.blob);
});

My service is declared like this:

(function() {
    'use strict';
    angular
        .module('myApp')
        .factory('FileService', FileService);
    FileService.$inject = ['$resource', 'DateUtils'];
    function FileService($resource, DateUtils) {
        var resourceUrl =  'api/file/:id/generate';
        return $resource(resourceUrl, {}, {
            'get': {
                method: 'GET',
                responseType:'arraybuffer'
}});}})();

When I download the file word say:

"We're sorry. We can't open file.docx because we found a problem with its content."

And when I compare my original file and the one downloaded in notepad++ for example I see that binary content is not exactly the same like there was encode/decode issues...

Also the size are not the same:

Original file 13Ko

Downloaded file 18Ko

Could you help me on knowing how and why the file downloaded is corrupted.


Solution

  • I finally found a solution:

    I directly send back the binary without convertion in the response. And access it with a window.location

    I a new Rest Controller without annotation:@RequestMapping("/api")

    @RestController
    public class FileGenerationResource {
        ...
        @GetMapping("/file/{id}")
        @Timed
        public void getFile(@PathVariable Long id, HttpServletResponse response) throws URISyntaxException, IOException {
            FileInputStream stream = fileService.getFile(id);
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            response.setHeader("Content-disposition", "attachment; filename=test.docx");
            IOUtils.copy(stream,response.getOutputStream());
            stream.close();
        }
    }
    

    The controller content:

    (function() {
        'use strict';
    
        angular
            .module('myApp')
            .controller('MyController', MyController);
    
        MyController.$inject = ['$timeout', '$scope', '$stateParams', '$uibModalInstance'];
    
        function MyController ($timeout, $scope, $stateParams, $uibModalInstance) {
            var vm = this;
            vm.clear = clear;
            vm.dwl = dwl;
    
            function dwl (id) {
                window.location = "http://localhost:8080/file/"+id;
                vm.clear();
            }
    
            function clear () {
                $uibModalInstance.dismiss('cancel');
            }
        }
    })();