Spring - download response as a file

前端 未结 7 717
無奈伤痛
無奈伤痛 2020-12-08 07:19

I am writing application using AngularJS and Spring. I would like to send request to the server and download response returned from controller as a file. In controller I hav

相关标签:
7条回答
  • 2020-12-08 07:24

    I have written comments below to understand code sample. Some one if using, they can follow it , as I named the files accordingly.

    1. IF server is sending blob in the response, then our client should be able to produce it.

    2. As my purpose is solved by using these. I can able to download files, as I have used type: 'application/*' for all files.

    3. Created "downloadLink" variable is just technique used in response so that, it would fill like some clicked on link, then response comes and then its href would be triggered.

    controller.js
    //this function is in controller, which will be trigered on download button hit.	
    
      $scope.downloadSampleFile = function() {
    //create sample hidden link in document, to accept Blob returned in the response from back end
        
    		var downloadLink = document.createElement("a");
    
    		document.body.appendChild(downloadLink);
    		downloadLink.style = "display: none";
    
    //This service is written Below how does it work, by aceepting necessary params
    		downloadFile.downloadfile(data).then(function (result) {
    
    			var fName = result.filename;
    			var file = new Blob([result.data], {type: 'application/*'});
    			var fileURL = (window.URL || window.webkitURL).createObjectURL(file);
    
              
    //Blob, client side object created to with holding browser specific download popup, on the URL created with the help of window obj.
              
    			downloadLink.href = fileURL;
    			downloadLink.download = fName;
    			downloadLink.click();
    		});
    	};
    
    
    
    
    services.js
    
    .factory('downloadFile', ["$http", function ($http) {
    	return {
    		downloadfile : function () {
    			return $http.get(//here server endpoint to which you want to hit the request
                  , {
    				responseType: 'arraybuffer',
    				params: {
    					//Required params
    				},
    			}).then(function (response, status, headers, config) {
    				return response;
    			});
    		},
    	};
    }])

    0 讨论(0)
  • 2020-12-08 07:37

    I've wrestled with this myself, trying to make it work from the server. Couldn't. Instead...

    1. To clarify on @dnc253's answer, $window.open(URL) is a method for having an Angular application open a given URL in another window. (It's really just a testable angular proxy for the universal window.open().) This is a great solution, preserves your history, and gets the file downloaded and possibly renders it in that fresh browser window if that's supported. But it often runs into popup blockers, which is a huge problem for reliability. Users often simply don't understand what's going on with them. So, if you don't mind immediately downloading the file with the current window, you can simply use the equally effective universal javascript method: location.href = "uriString", which works like a charm for me. Angular doesn't even realize anything has happened. I call it in a promise handler for once my POST/PUT operation has completed. If need be, have the POST/PUT return the URL to call, if you can't already infer it. You'll get the same behavior for the user as if it had downloaded in response to the PUT/POST. For example:

      $http.post(url, payload).then(function(returnData){
          var uriString = parseReturn(returnData);
          location.href="uriString"
      })
      
    2. You can, in fact, download something directly from an XHR request, but it requires full support for the HTML5 file API and is usually more trouble than it's worth unless you need to perform local transformations upon the file before you make it available to the user. (Sadly, I lack the time to provide details on that but there are other SO posts about using it.)

    0 讨论(0)
  • 2020-12-08 07:37

    Just in case you guys need it, Here a couple of links that can help you:

    1. download csv file from web api in angular js
    2. Export javascript data to CSV file without server interaction

    Cheers

    0 讨论(0)
  • 2020-12-08 07:39

    It's working for me :

    • Spring controller : DownloadController.java

      package com.mycompany.myapp.controller;
      
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import java.io.OutputStream;
      
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      
      import org.apache.commons.io.IOUtils;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.http.HttpStatus;
      import org.springframework.http.ResponseEntity;
      import org.springframework.web.bind.annotation.ExceptionHandler;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RequestMethod;
      import org.springframework.web.bind.annotation.RequestParam;
      import org.springframework.web.bind.annotation.RestController;
      
      import com.mycompany.myapp.exception.TechnicalException;
      
      
      @RestController
      public class DownloadController {
      
          private final Logger log = LoggerFactory.getLogger(DownloadController.class);
      
          @RequestMapping(value = "/download", method = RequestMethod.GET)
          public void download(@RequestParam ("name") String name, final HttpServletRequest request, final HttpServletResponse response) throws TechnicalException {
              log.trace("name : {}", name);
      
              File file = new File ("src/main/resources/" + name);
              log.trace("Write response...");
              try (InputStream fileInputStream = new FileInputStream(file);
                      OutputStream output = response.getOutputStream();) {
      
                  response.reset();
      
                  response.setContentType("application/octet-stream");
                  response.setContentLength((int) (file.length()));
      
                  response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
      
                  IOUtils.copyLarge(fileInputStream, output);
                  output.flush();
              } catch (IOException e) {
                  log.error(e.getMessage(), e);
              }
      
          }
      
      }
      
    • AngularJs Service : download.service.js

      (function() {
          'use strict';
      
          var downloadModule = angular.module('components.donwload', []);
      
          downloadModule.factory('downloadService', ['$q', '$timeout', '$window',
              function($q, $timeout, $window) {
                  return {
                      download: function(name) {
      
                          var defer = $q.defer();
      
                          $timeout(function() {
                                  $window.location = 'download?name=' + name;
      
                              }, 1000)
                              .then(function() {
                                  defer.resolve('success');
                              }, function() {
                                  defer.reject('error');
                              });
                          return defer.promise;
                      }
                  };
              }
          ]);
      })();
      
    • AngularJs config : app.js

      (function() {
          'use strict';
      
          var myApp = angular.module('myApp', ['components.donwload']);
         /* myApp.config([function () {
      
          }]);
          myApp.run([function () {
      
          }]);*/
      
      
      })();
      
    • AngularJs controller : download.controller.js

      (function() {
          'use strict';
      
          angular.module('myApp')
              .controller('DownloadSampleCtrl', ['downloadService', function(downloadService) {
                  this.download = function(fileName) {
                      downloadService.download(fileName)
                          .then(function(success) {
                              console.log('success : ' + success);
                          }, function(error) {
                              console.log('error : ' + error);
                          });
                  };
              }]);
      })();
      
    • index.html

      <!DOCTYPE html>
      <html ng-app="myApp">
      
      <head>
          <title>My App</title>
          <link rel="stylesheet" href="bower_components/normalize.css/normalize.css" />
          <link rel="stylesheet" href="assets/styles/main.css" />
          <link rel="icon" href="favicon.ico">
      </head>
      
      <body>
          <div ng-controller="DownloadSampleCtrl as ctrl">
              <button ng-click="ctrl.download('fileName.txt')">Download</button>
          </div>
      
          <script src="bower_components/angular/angular.min.js"></script>
      
          <!-- App config -->
          <script src="scripts/app/app.js"></script>
          <!-- Download Feature -->
          <script src="scripts/app/download/download.controller.js"></script>
          <!-- Components -->
          <script src="scripts/components/download/download.service.js"></script>
      </body>
      
      </html>
      
    0 讨论(0)
  • 2020-12-08 07:39

    //JAVA PART

    @RequestMapping(value = "/report-excel", method = RequestMethod.GET)
        public ResponseEntity<byte[]> getReportExcel(@RequestParam("bookingStatusType") String bookingStatusType,
                @RequestParam("endDate") String endDate, @RequestParam("product") String product, @RequestParam("startDate") String startDate)throws IOException, ParseException {
    
    //Generate Excel from DTO using any logic after that do the following
    byte[] body = wb.getBytes();
    HttpHeaders header = new HttpHeaders();
            header.setContentType(new MediaType("application", "xlsx"));
            header.set("Content-Disposition", "inline; filename=" + fileName);
            header.setCacheControl("must-revalidate, post-check=0, pre-check=0");
            header.setContentLength(body.length);
    
     return new ResponseEntity<byte[]>(body, header, HttpStatus.OK);
    }
    
    
    
    //HTML PART
    <html>
    <head>
    <title>Test</title>
    <meta http-equiv="content-type" content="application/x-www-form-urlencoded; charset=UTF-8">
    </head>
    <body>
      <form name="downloadXLS" method="get" action="http://localhost:8080/rest/report-excel" enctype="multipart/form-data">
        <input type="text" name="bookingStatusType" value="SALES"></input>
        <input type="text" name="endDate" value="abcd"></input>
        <input type="text" name="product" value="FLIGHT"></input>
        <input type="text" name="startDate" value="abcd"></input>
        <input onclick="document.downloadXLS.submit()" value="Submit"></input>
      </form>
    </body>
    </html>
    
    0 讨论(0)
  • 2020-12-08 07:40

    You can't download a file through an XHR request (which is how Angular makes it's requests). See Why threre is no way to download file using ajax request? You either need to go to the URL via $window.open or do the iframe trick shown here: JavaScript/jQuery to download file via POST with JSON data

    0 讨论(0)
提交回复
热议问题