복붙노트

[SPRING] Angular2에서 REST API로 파일 업로드

SPRING

Angular2에서 REST API로 파일 업로드

사실, 저는 Angular 2로 코딩 된 인터페이스를 가진 Spring REST API에 대해 작업하고 있습니다.

내 문제는 Angular 2로 파일을 업로드 할 수 없다는 것입니다.

Java의 내 웹 리소스는 다음과 같습니다.

@RequestMapping(method = RequestMethod.POST, value = "/upload")
public String handleFileUpload(@RequestParam MultipartFile file) {
    //Dosomething 
}

그리고 그것은 Auth 헤더 등으로 URL 요청을 통해 호출 할 때 완벽하게 작동합니다 ...  (Chrome 용 고급 휴식 클라이언트 확장 프로그램 사용)

증명 : (모든 경우 잘 작동합니다)

나는

<bean id="multipartResolver"
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

Spring 설정 파일과 Pom 의존성

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.2</version>
</dependency>

그러나 웹 양식으로 같은 일을하려고 할 때 :

<input type="file" #files (change)="change(files)"/>
<pre>{{fileContents$|async}}</pre>

(변경) 메소드 사용 :

change(file) {
    let formData = new FormData();
    formData.append("file", file);
    console.log(formData);
    let headers = new Headers({
        'Authorization': 'Bearer ' + this.token,
        'Content-Type': 'multipart/form-data'
    });
    this.http.post(this.url, formData, {headers}).map(res => res.json()).subscribe((data) => console.log(data));
    /*
    Observable.fromPromise(fetch(this.url,
        {method: 'post', body: formData},
        {headers: this.headers}
    )).subscribe(()=>console.log('done'));
    */
}

내 웹 서비스는 tomcat 로그에 다음과 같은 오류 500을 반환합니다. http://pastebin.com/PGdcFUQb

나는 'Content-Type'을 시도했다 : 정의되지 않은 메소드도 성공했지만 성공하지 못했다. (웹 서비스는 415 에러를 리턴한다.

누군가 문제의 원인을 파악하는 데 도움을 줄 수 있습니까?

문제가 해결되면, 나중에이 코드를 내 코드로 업데이트 할 것이다. :) 그러나, 완벽하게 잘 작동하는 플 런커에 대해 살펴 보자. 감사.

해결법

  1. ==============================

    1.이것은 최종 릴리스에서 실제로 실제로 쉽습니다. 내가 만났던 대부분의 정보가 구식이기 때문에 내 머리를 감싸는 데 시간이 좀 걸렸다. 다른 사람들이이 문제로 어려움을 겪고있는 경우에 대비하여 여기에 내 솔루션을 게시하십시오.

    이것은 최종 릴리스에서 실제로 실제로 쉽습니다. 내가 만났던 대부분의 정보가 구식이기 때문에 내 머리를 감싸는 데 시간이 좀 걸렸다. 다른 사람들이이 문제로 어려움을 겪고있는 경우에 대비하여 여기에 내 솔루션을 게시하십시오.

    import { Component, ElementRef, Input, ViewChild } from '@angular/core';
    import { Http } from '@angular/http';
    
    @Component({
        selector: 'file-upload',
        template: '<input type="file" [multiple]="multiple" #fileInput>'
    })
    export class FileUploadComponent {
        @Input() multiple: boolean = false;
        @ViewChild('fileInput') inputEl: ElementRef;
    
        constructor(private http: Http) {}
    
        upload() {
            let inputEl: HTMLInputElement = this.inputEl.nativeElement;
            let fileCount: number = inputEl.files.length;
            let formData = new FormData();
            if (fileCount > 0) { // a file was selected
                for (let i = 0; i < fileCount; i++) {
                    formData.append('file[]', inputEl.files.item(i));
                }
                this.http
                    .post('http://your.upload.url', formData)
                    // do whatever you do...
                    // subscribe to observable to listen for response
            }
        }
    }
    

    다음과 같이 사용하십시오.

    <file-upload #fu (change)="fu.upload()" [multiple]="true"></file-upload>
    

    그게 전부입니다.

    또는 이벤트 객체를 캡처하고 srcElement에서 파일을 가져옵니다. 솔직히 말해서 어떤 방법이 다른 것보다 낫다면 확실하지 않습니다!

    FormData는 IE10 +이므로, IE9를 지원해야한다면 polyfill이 필요합니다.

    업데이트 2017-01-07

    여러 파일의 업로드를 처리 할 수 ​​있도록 업데이트 된 코드 또한 내 원래의 대답은 FormData에 관한 중요한 비트를 잃어 버렸습니다. (실제로 업로드 로직을 내 자신의 앱에서 별도의 서비스로 옮겼기 때문에 거기에서 처리하고있었습니다.)

  2. ==============================

    2.사실, 현재 Angular2 HTTP 지원의 게시, 삽입 및 패치 방법에 대해서만 문자열 입력을 제공 할 수 있습니다.

    사실, 현재 Angular2 HTTP 지원의 게시, 삽입 및 패치 방법에 대해서만 문자열 입력을 제공 할 수 있습니다.

    이를 지원하려면 아래에 설명 된대로 XHR 객체를 직접 활용해야합니다.

    import {Injectable} from 'angular2/core';
    import {Observable} from 'rxjs/Rx';
    
    @Injectable()
    export class UploadService {
      constructor () {
        this.progress$ = Observable.create(observer => {
          this.progressObserver = observer
        }).share();
      }
    
      private makeFileRequest (url: string, params: string[], files: File[]): Observable {
        return Observable.create(observer => {
          let formData: FormData = new FormData(),
            xhr: XMLHttpRequest = new XMLHttpRequest();
    
          for (let i = 0; i < files.length; i++) {
            formData.append("uploads[]", files[i], files[i].name);
          }
    
          xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
              if (xhr.status === 200) {
                observer.next(JSON.parse(xhr.response));
                observer.complete();
              } else {
                observer.error(xhr.response);
              }
            }
          };
    
          xhr.upload.onprogress = (event) => {
            this.progress = Math.round(event.loaded / event.total * 100);
    
            this.progressObserver.next(this.progress);
          };
    
          xhr.open('POST', url, true);
          xhr.send(formData);
        });
      }
    }
    

    자세한 내용은이 plunkr을 참조하십시오 : https://plnkr.co/edit/ozZqbxIorjQW15BrDFrg?p=info.

    Angular repo에는 문제와 관련하여 보류중인 PR이 있습니다.

  3. ==============================

    3.이것은 나를 위해 일했다 :

    이것은 나를 위해 일했다 :

    <input type="file" (change)="onChange($event)" required class="form-control " name="attach_file" id="attach_file">
    onChange(event: any) {
        let fileList: FileList = event.target.files;
    if(fileList.length > 0) {
        let file: File = fileList[0];
        let formData:FormData = new FormData();
        formData.append('degree_attachment', file, file.name);
        let headers = new Headers();
        headers.append('Accept', 'application/json');
        let options = new RequestOptions({ headers: headers });
        this.http.post('http://url', formData,options)
            .map(res => res.json())
            .catch(error => Observable.throw(error))
            .subscribe(
                data => console.log('success'),
                error => console.log(error)
            )
    }}
    
  4. ==============================

    4.이것은 나를 위해 일했습니다 : Angular 2는 파일 업로드에 대한 훌륭한 지원을 제공합니다 :

    이것은 나를 위해 일했습니다 : Angular 2는 파일 업로드에 대한 훌륭한 지원을 제공합니다 :

    <input type="file" (change)="fileChange($event)" placeholder="Upload file" accept=".pdf,.doc,.docx">
    
    fileChange(event) {
        let fileList: FileList = event.target.files;
        if(fileList.length > 0) {
            let file: File = fileList[0];
            let formData:FormData = new FormData();
            formData.append('uploadFile', file, file.name);
            let headers = new Headers();
            headers.append('Content-Type', 'multipart/form-data');
            headers.append('Accept', 'application/json');
            let options = new RequestOptions({ headers: headers });
            this.http.post(URL, formData, options)
                .map(res => res.json())
                .catch(error => Observable.throw(error))
                .subscribe(
                    data => console.log('success'),
                    error => console.log(error)
                )
        }
    }
    

    오류가 발생했습니다 : java.io.IOException : RESTEASY007550 : 다중 부분에 대한 경계를 가져올 수 없습니다.

    이 문제를 해결하려면 "Content-Type" "multipart / form-data"

  5. ==============================

    5.이 스레드는 매우 도움이되어 내 솔루션을 공유해야한다고 느꼈습니다. 우드로 형제의 대답은 나의 출발점이었습니다. 또한 Rob Gwynn-Jones의 "수동으로 Content-Type 헤더를 설정하지 않도록주의하십시오."라는 메시지에주의를 환기시키고 싶습니다.이 헤더는 매우 중요하며 시간을 많이 절약 해줍니다.

    이 스레드는 매우 도움이되어 내 솔루션을 공유해야한다고 느꼈습니다. 우드로 형제의 대답은 나의 출발점이었습니다. 또한 Rob Gwynn-Jones의 "수동으로 Content-Type 헤더를 설정하지 않도록주의하십시오."라는 메시지에주의를 환기시키고 싶습니다.이 헤더는 매우 중요하며 시간을 많이 절약 해줍니다.

    동일한 이름을 가진 여러 파일 (다른 폴더의 파일)은 함께 업로드 할 수 있지만 같은 파일은 업로드 목록에 두 번 추가되지 않습니다 (이것은 사소한 것이 아닙니다!).

    '@ angular / core'에서 {Component, ElementRef, Input, ViewChild}를 가져 오십시오; 가져 오기 {Http} '@ angular / http'에서; @구성 요소({     선택자 : '파일 업로드',     템플릿 : '' }) 수출 클래스 FileUploadComponent {     @Input () multiple : 부울 = 거짓;     @ViewChild ( 'fileInput') inputEl : ElementRef;     파일 : 배열 = [];     fileObjects : Array = [];     fileKeys : Array = [];     fileCount : 숫자 = 0;     생성자 (개인 http : http) {}     addFiles (콜백 : any) {         const inputEl : HTMLInputElement = this.inputEl.nativeElement;         const newCount : number = inputEl.files.length;         for (let i = 0; i

    'addFiles'의 콜백을 통해 구성 요소 외부에서 업로드가 수행 될 수 있습니다. 구성 요소는 다음과 같이 사용됩니다.

    <파일 업로드 #fu (변경) = "fu.addFiles (setFiles.bind (this))"[다중] = "true">

    'setFiles'는 콜백입니다. 이 컨텍스트에서 'this'는 상위 구성 요소입니다.

    setFiles (files : Array ) {this.files = files; }

    남아있는 것은 업로드 API (상위 구성 요소에도 있음)를 호출하기 전에 멀티 파트 페이로드를 첨부하는 것입니다.

    const formData = new FormData ();              for (let i = 0; i

    이것이 도움이되기를 바라며, 필요하다면 고칠 수있어서 기쁘다. 건배!

  6. ==============================

    6.간단한 솔루션을 찾고 코딩을 직접하고 싶지 않은 경우이 라이브러리를 사용하는 것이 좋습니다.

    간단한 솔루션을 찾고 코딩을 직접하고 싶지 않은 경우이 라이브러리를 사용하는 것이 좋습니다.

    https://www.npmjs.com/package/angular2-http-file-upload

  7. ==============================

    7.

    this.uploader.onBeforeUploadItem = function(item) {
      item.url = URL.replace('?', "?param1=value1");
    }
    
  8. ==============================

    8.

    fileUpload() {
      const formData = new FormData();
    
      const files = this.filesToUpload;
      for (let i = 0; i < files.length; i++) {
        formData.append('file', files.item(i));
        formData.append('Content-Type', 'application/json');
        formData.append('Accept', `application/json`);
      }
    
    
      this.http.post('http://localhost:8080/UploadFile', formData).subscribe(response => console.log(response));
    }
    

    그때:

    <form (ngSubmit)="upload()">
        <input type="file" id="file" multiple (change)="fileUpload($event.target.files)">
        <button type="submit">Upload</button>
    </form>
    
  9. from https://stackoverflow.com/questions/36352405/file-upload-with-angular2-to-rest-api by cc-by-sa and MIT license