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 추가하기
댓글
댓글 쓰기