Angular 로 파일 업로드 시 아래의 모듈을 많이 사용하는 것 같다.
1. ng2-file-upload
- https://github.com/valor-software/ng2-file-upload
2. ng2-fileupload
- https://github.com/thinkholic/ng2-fileupload
Angular 4
모듈이라는 개념에 맞게 순수하게 파일 업로드 기능만 들어있다.
저 모듈을 이용하게되면 우선 파일을 업로드 후 form submit 을 시켜야 할 것으로 보여진다.
서버 API 작업 시 multipart 로 text/file 파라메터를 동시에 받아 작업하는게 편한 경우가 있어 한번에 submit 시킬 수 있도록 작업을 했다.
작업환경: Angular 4
1004lucifer
multipart-form.service.ts
import {Injectable} from '@angular/core'; import {FormGroup} from '@angular/forms'; import {Headers, Http, Response} from '@angular/http'; import { Observable } from 'rxjs/Rx'; @Injectable() export class MultipartFormService { constructor( private http: Http ) { } /** * Form의 string / File 파라메터를 Multipart 로 묶어서 서버에 전송한다. * @param {string} url * @param {FormGroup} formGroup * @param {Array<{name: string; file: File}>} files - [{'name': 'fileKey1', 'file': this.file1}, ...] * @returns {Observable<Response>} */ sendMultipartForm(url: string, formGroup: FormGroup, files?: Array<{name: string, file: File}>): Observable<Response> { const formData = new FormData(); for (const key in formGroup.value) { if (formGroup.value.hasOwnProperty(key)) { formData.append(key, formGroup.value[key]); } } if (files) { files .filter((file) => file.name != null && file.file != null) // 정상적이지 않은 객체 Filter .forEach((file) => { formData.append(file.name, file.file); }); } const headers = new Headers({'enctype': 'multipart/form-data'}); return this.http.post(url, formData, { headers }); } }
사용 (실제 사용된 소스를 약간 수정했다.)
use.component.html
<div> <form [formGroup]="myForm" (ngSubmit)="onSubmit()"> <table class="tbl_w1 mrg_T20"> <colgroup> <col width="150"> <col width=""> </colgroup> <tr> <td>param1</td> <td><input formControlName="param1" type="text" class="white_grayline input_wmiddle back_gray"></td> </tr> <tr> <td>param2</td> <td><input formControlName="param2" type="text" class="white_grayline input_wmiddle back_gray"></td> </tr> <tr> <td>file1</td> <td><input #file1Name class="file_input_textbox2" readonly/> <div class="file_input_div"> <input type="button" value="찾아보기" class="file_input_button"/> <input (change)="file1 = extractFile($event); file1Name.value = extractFileName($event)" type="file" class="file_input_hidden"/> </div> </td> </tr> <tr> <td>file2</td> <td><input #file2Name class="file_input_textbox2" readonly/> <div class="file_input_div"> <input type="button" value="찾아보기" class="file_input_button"/> <input (change)="file2 = extractFile($event); file2Name.value = extractFileName($event)" type="file" class="file_input_hidden"/> </div> </td> </tr> </table> <p class="aln_c mrg_T20"> <button type="submit">확인</button> </p> </form> </div>
1004lucifer
use.component.ts
import {Component, Input, OnInit} from '@angular/core'; import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; import {FormControl, FormGroup} from '@angular/forms'; import {MultipartFormService} from './multipart-form.service'; @Component({ selector: 'use-selector', templateUrl: './use.component.html', styles: [] }) export class UseComponent implements OnInit { myForm: FormGroup; file1: File; file2: File; constructor( public activeModal: NgbActiveModal, private multipartFormService: MultipartFormService ) { this.myForm = new FormGroup({ 'param1': new FormControl(), 'param2': new FormControl() }); } ngOnInit() { } extractFile(event) { const files = event.target.files || event.srcElement.files; return files.length === 0 ? null : files[0]; } extractFileName(event) { const file = this.extractFile(event); return file ? file.name : ''; } onSubmit() { this.multipartFormService.sendMultipartForm( '/api/resourceName', this.myForm, // files 파라메터는 옵션으로 추가하지 않아도 된다. [{'name': 'fileKey1', 'file': this.file1}, {'name': 'fileKey2', 'file': this.file2}], ).subscribe( (response) => { console.log(response.json()); }, (response) => { console.log(response.json()); }); } /** onSubmit() { this.multipartFormService.sendMultipartForm( '/api/resourceName', this.myForm, ).subscribe( (response) => { console.log(response.json()); }, (response) => { console.log(response.json()); }); } */ }
use.module.ts
@NgModule({ imports: [ ReactiveFormsModule, ... ], declarations: [UseComponent], providers: [ MultipartFormService ], }) export class UseModule { }
참고
- http://nberserk.github.io/default/2017/02/12/angular-form-file.html
(사실상 위의 링크를 보고 만들었다.)
- https://www.angularjs4u.com/angularjs2/10-angular-2-file-upload-demos/
PS.
서버사이드를 Java Spring 을 사용하는데 위와같이 작업 시 이름이 같은 중복 파라메터는 보낼 수 없어 JSON 형식으로 객체를 보내는 방법으로 수정을 했는데 Content-Type 이슈로 인해 Spring 에서 JSON<=>객체 매핑이 제대로 되지 않았다.
아래와 같은 방법으로 Content-Type 헤더를 추가하여 이슈를 해결하였다.
링크: [Angular 2+] multipart 보낼 시 헤더에 Content-type 추가하기
댓글
댓글 쓰기