Vraag AngularJS $ http-post - converteer binair bestand naar excelbestand en download


Ik heb een applicatie gemaakt in Angular JS voor het downloaden van een Excel-werkboek via $ http-post.

In de onderstaande code geef ik de informatie door in de vorm van JSON en stuur ik deze naar de server REST-webservice (java) via een hoekige $ http-post. De webservice gebruikt de informatie van JSON en produceert een Excel-werkmap. In de reactie binnen het succes van $ http, krijg ik daar binaire gegevens van gegevens variabele, maar weet niet hoe het te converteren en te downloaden als een Excel-bestand.

Kan iemand me alsjeblieft een oplossing hiervoor vertellen voor het converteren van het binaire naar het Excel-bestand en downloaden?

Mijn code is zoals hieronder weergegeven:

$http({
        url: 'myweb.com/myrestService',
        method: "POST",
        data: json, //this is your json data string
        headers: {
           'Content-type': 'application/json'
        }
    }).success(function (data, status, headers, config) {

        // Here i'm getting excel sheet binary datas in 'data' 

    }).error(function (data, status, headers, config) {

    });

51
2018-03-17 06:08


oorsprong


antwoorden:


Ik heb gemerkt dat je het niet kunt gebruiken vanwege IE8 / 9, maar ik zal toch pushen ... misschien vindt iemand het nuttig

Dit kan eigenlijk via de browser worden gedaan, met behulp van blob. Let op de responseType en de code in de success belofte.

$http({
    url: 'your/webservice',
    method: "POST",
    data: json, //this is your json data string
    headers: {
       'Content-type': 'application/json'
    },
    responseType: 'arraybuffer'
}).success(function (data, status, headers, config) {
    var blob = new Blob([data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
    var objectUrl = URL.createObjectURL(blob);
    window.open(objectUrl);
}).error(function (data, status, headers, config) {
    //upload failed
});

Er zijn echter een aantal problemen mee zoals:

  1. Het ondersteunt niet IE 8 en 9:
  2. Er wordt een pop-upvenster geopend om de. Te openen objectUrl welke mensen mogelijk zijn geblokkeerd
  3. Genereert rare bestandsnamen

Het werkte!

blob De code aan de serverzijde in PHP waarmee ik dit heb getest ziet er als volgt uit. Ik weet zeker dat je vergelijkbare headers in Java kunt instellen:

$file = "file.xlsx";
header('Content-disposition: attachment; filename='.$file);
header('Content-Length: ' . filesize($file));
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate');
header('Pragma: public');
echo json_encode(readfile($file));

Bewerk 20.04.2016

Browsers maken het moeilijker om gegevens op deze manier op te slaan. Een goede optie is om te gebruiken filesaver.js. Het biedt een cross-browser implementatie voor saveAs, en het zou een deel van de code in de. moeten vervangen success beloven hierboven.


75
2018-03-17 07:11



Dit is hoe je het doet:

  1. Vergeet IE8 / IE9, het is de moeite niet waard en betaalt het geld niet terug.
  2. U moet de juiste HTTP-header gebruiken, Accepteer gebruiken in 'application / vnd.openxmlformats-officedocument.spreadsheetml.sheet' en u moet responseType ook plaatsen in 'arraybuffer' (ArrayBuffer maar ingesteld met kleine letters).
  3. HTML5 saveAs wordt gebruikt om de feitelijke gegevens in uw gewenste indeling op te slaan. Merk op dat het in dit geval nog steeds werkt zonder type toe te voegen.
$http({
    url: 'your/webservice',
    method: 'POST',
    responseType: 'arraybuffer',
    data: json, //this is your json data string
    headers: {
        'Content-type': 'application/json',
        'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    }
}).success(function(data){
    var blob = new Blob([data], {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    });
    saveAs(blob, 'File_Name_With_Some_Unique_Id_Time' + '.xlsx');
}).error(function(){
    //Some error log
});

Tip! Meng niet "en", blijf altijd gebruiken ", in een professionele omgeving moet je js-validatie doorgeven, bijvoorbeeld jshint, hetzelfde geldt voor het gebruik van === en niet ==, enzovoort, maar dat is een ander onderwerp :)

Ik zou de save excel in een andere service plaatsen, dus je hebt een zuivere structuur en de post is in een goede eigen service. Ik kan een JS-viool voor je maken, als je mijn voorbeeld niet werkt. Dan zou ik ook wat json-gegevens van u nodig hebben die u voor een volledig voorbeeld gebruikt.

Gelukkig coderen .. Eduardo


24
2017-08-22 08:53



Download het serverantwoord als een arraybuffer. Sla het op als een Blob met behulp van het inhoudstype van de server (wat zou moeten zijn application/vnd.openxmlformats-officedocument.spreadsheetml.sheet):

var httpPromise = this.$http.post(server, postData, { responseType: 'arraybuffer' });
httpPromise.then(response => this.save(new Blob([response.data],
    { type: response.headers('Content-Type') }), fileName));

Sla de blob op het apparaat van de gebruiker op:

save(blob, fileName) {
    if (window.navigator.msSaveOrOpenBlob) { // For IE:
        navigator.msSaveBlob(blob, fileName);
    } else { // For other browsers:
        var link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        link.download = fileName;
        link.click();
        window.URL.revokeObjectURL(link.href);
    }
}

8
2017-11-04 20:39



Heeft voor mij gewerkt -

$scope.downloadFile = function () {
        Resource.downloadFile().then(function (response) {
            var blob = new Blob([response.data], { type: "application/pdf" });
            var objectUrl = URL.createObjectURL(blob);
            window.open(objectUrl);
        },
        function (error) {
            debugger;
        });
    };

Welke roept het volgende op uit mijn grondstoffenfabriek-

  downloadFile: function () {
           var downloadRequst = {
                method: 'GET',
                url: 'http://localhost/api/downloadFile?fileId=dfckn4niudsifdh.pdf',
                headers: {
                    'Content-Type': "application/pdf",
                    'Accept': "application/pdf"
                },
                responseType: 'arraybuffer'
            }

            return $http(downloadRequst);
        }

Zorg ervoor dat uw API ook het inhoudstype van de header instelt -

        response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
        response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");

4
2017-10-05 14:04



Er is geen manier (voor zover mij bekend) om het downloadvenster in uw browser te activeren vanuit Javascript. De enige manier om dit te doen is om de browser om te leiden naar een URL die het bestand naar de browser streamt.

Als u uw REST-service kunt wijzigen, kunt u deze mogelijk oplossen door de POST-aanvraag niet te laten reageren met het binaire bestand, maar met een URL naar dat bestand. Daarmee krijgt u de URL in Javascript in plaats van de binaire gegevens en kunt u de browser omleiden naar die URL, die de download moet vragen zonder de oorspronkelijke pagina te verlaten.


3
2018-03-17 06:55



Antwoord nr. 5 werkte voor mij, suggestie voor ontwikkelaar die met een soortgelijk probleem worden geconfronteerd.

//////////////////////////////////////////////////////////
//Server side 
//////////////////////////////////////////////////////////
imports ***
public class AgentExcelBuilder extends AbstractExcelView {

protected void buildExcelDocument(Map<String, Object> model,
            HSSFWorkbook workbook, HttpServletRequest request,
            HttpServletResponse response) throws Exception {

        //poi code goes here ....

        response.setHeader("Cache-Control","must-revalidate");
        response.setHeader("Pragma", "public");
        response.setHeader("Content-Transfer-Encoding","binary");
        response.setHeader("Content-disposition", "attachment; filename=test.xls");

        OutputStream output = response.getOutputStream();

        workbook.write(output);
        System.out.println(workbook.getActiveSheetIndex());
        System.out.println(workbook.getNumberOfSheets());
        System.out.println(workbook.getNumberOfNames());
        output.flush();
        output.close(); 
}//method buildExcelDocument ENDS

//service.js at angular JS code
function getAgentInfoExcel(workgroup,callback){
        $http({
            url: CONTEXT_PATH+'/rest/getADInfoExcel',
            method: "POST",
            data: workgroup, //this is your json data string
            headers: {
               'Content-type': 'application/json'
            },
            responseType: 'arraybuffer'
        }).success(function (data, status, headers, config) {
            var blob = new Blob([data], {type: "application/vnd.ms-excel"});
            var objectUrl = URL.createObjectURL(blob);
            window.open(objectUrl);
        }).error(function (data, status, headers, config) {
            console.log('Failed to download Excel')
        });
    }
////////////////////////////////in .html 

<div class="form-group">`enter code here`
                                <a href="javascript:void(0)" class="fa fa-file-excel-o"
                                    ng-click="exportToExcel();"> Agent Export</a>
                            </div>

0
2018-01-19 10:29



Je kunt net zo goed een andere aanpak kiezen - je hoeft $ http niet te gebruiken, je hebt geen extra bibliotheken nodig en het zou in elke browser moeten werken.

Plaats gewoon een onzichtbaar formulier op uw pagina.

<form name="downloadForm" action="/MyApp/MyFiles/Download" method="post" target="_self">
    <input type="hidden" name="value1" value="{{ctrl.value1}}" />
    <input type="hidden" name="value2" value="{{ctrl.value2}}" />
</form>

En plaats deze code in uw hoekcontroller.

ctrl.value1 = 'some value 1';  
ctrl.value2 = 'some value 2';  
$timeout(function () {
    $window.document.forms['downloadForm'].submit();
});

Deze code verzendt je gegevens naar / MyApp / MyFiles / Download en je ontvangt een bestand in je map Downloads.
Het werkt met Internet Explorer 10.

Als u met een conventioneel HTML-formulier uw complexe object niet kunt plaatsen, heeft u twee opties:

1. Bepaal uw object en plaats het in een van de formuliervelden als een tekenreeks.

<input type="hidden" name="myObjJson" value="{{ctrl.myObj | json:0}}" />


2. Overweeg HTML JSON-formulieren: https://www.w3.org/TR/html-json-forms/


0
2018-05-26 13:59



Ik heb een dienst gecreëerd die dit voor je doet.

Geef een standaard door $http object en voeg wat extra parameters toe.

1) Een "type" parameter. Het type bestand opgeven dat u ophaalt. Standaard naar: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
2) Een "bestandsnaam" -parameter. Dit is verplicht en moet de extensie bevatten.

Voorbeeld:

httpDownloader({
  method : 'POST',
  url : '--- enter the url that returns a file here ---',
  data : ifYouHaveDataEnterItHere,
  type : 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // this is the default
  fileName : 'YourFileName.xlsx'
}).then(res => {}).catch(e => {});

Dat is alles wat je nodig hebt. Het bestand wordt zonder pop-up gedownload naar het apparaat van de gebruiker.

Dit is de git repo: https://github.com/stephengardner/ngHttpDownloader


0
2018-06-07 04:05



Ik stond voor hetzelfde probleem. Laat me je vertellen hoe ik het heb opgelost en heb bereikt wat je allemaal lijkt te willen.

Vereisten:

  1. Moet een knop (of link) naar een bestand hebben - (of een gegenereerde geheugenstream)
  2. Moet op de knop klikken en het bestand downloaden

In mijn dienst, (ik gebruik Asp.net Web API), heb ik een controller die een "HttpResponseMessage" retourneert. Ik voeg een "StreamContent" toe aan het veld response.Content, stel de headers in op "application / octet-stream" en voeg de gegevens toe als bijlage. Ik geef het zelfs een naam "myAwesomeFile.xlsx"

response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StreamContent(memStream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "myAwesomeFile.xlsx" };

Dit is de truc;)

Ik bewaar de basis-URL in een tekstbestand dat ik in een variabele lees in een variabele genaamd "apiRoot". Ik doe dit door het te declareren en het vervolgens in te stellen op de "run" -functie van de module, zoals zo:

app.value('apiRoot', { url: '' });
app.run(function ($http, apiRoot) {
    $http.get('/api.txt').success(function (data) {
        apiRoot.url = data;
    });
});

Op die manier kan ik de URL in een tekstbestand op de server plaatsen en hoef ik me geen zorgen te maken dat ik het "wegblaast" in een upload. (Je kunt het later altijd veranderen om veiligheidsredenen - maar dit neemt de frustratie uit de ontwikkeling;))

En NU de magie:

Het enige wat ik doe is een koppeling maken met een URL die direct mijn servicepunt raakt en het doel een "_blank" is.

<a ng-href="{{vm.getFileHref(FileId)}}" target="_blank" class="btn btn-default">&nbsp;Excel File</a>

de geheime saus is de functie die de href instelt. Ben je hier klaar voor?

vm.getFileHref = function (Id) {
    return apiRoot.url + "/datafiles/excel/" + Id;
}

Ja, dat is het. ;)

Zelfs in een situatie waarin u itereert over vele records die bestanden moeten downloaden, voert u eenvoudig de ID in de functie in en de functie genereert de URL naar het service-eindpunt dat het bestand levert.

Ik hoop dat dit helpt!


-2
2017-08-10 14:25