角度文件上传
Posted
技术标签:
【中文标题】角度文件上传【英文标题】:Angular File Upload 【发布时间】:2018-06-04 19:02:21 【问题描述】:我是 Angular 的初学者,我想知道如何创建 Angular 5 文件上传部分,我正在尝试查找任何教程或文档,但我在任何地方都看不到任何东西.有什么想法吗?我尝试了ng4-files,但它不适用于 Angular 5
【问题讨论】:
所以你想要拖放还是简单的Choose File
btn 上传?在这两种情况下,您只需使用FormData 上传
看看primeng,我已经用了一段时间了,它适用于angular v5。 primefaces.org/primeng/#/fileupload
只需要上传JSON到客户端的朋友,看看这个问题:***.com/questions/54971238/…
【参考方案1】:
这是一个将文件上传到 api 的工作示例:
第 1 步:HTML 模板 (file-upload.component.html)
定义file
类型的简单输入标签。向(change)
-event 添加一个函数来处理选择文件。
<div class="form-group">
<label for="file">Choose File</label>
<input type="file"
id="file"
(change)="handleFileInput($event.target.files)">
</div>
第 2 步:TypeScript 中的上传处理 (file-upload.component.ts)
为选定的文件定义一个默认变量。
fileToUpload: File | null = null;
创建您在文件输入标签的(change)
-event 中使用的函数:
handleFileInput(files: FileList)
this.fileToUpload = files.item(0);
如果你想处理多文件选择,你可以遍历这个文件数组。
现在通过调用 file-upload.service 创建文件上传功能:
uploadFileToActivity()
this.fileUploadService.postFile(this.fileToUpload).subscribe(data =>
// do something, if upload success
, error =>
console.log(error);
);
第 3 步:文件上传服务 (file-upload.service.ts)
通过 POST 方法上传文件,您应该使用FormData
,因为这样您就可以将文件添加到 http 请求中。
postFile(fileToUpload: File): Observable<boolean>
const endpoint = 'your-destination-url';
const formData: FormData = new FormData();
formData.append('fileKey', fileToUpload, fileToUpload.name);
return this.httpClient
.post(endpoint, formData, headers: yourHeadersConfig )
.map(() => return true; )
.catch((e) => this.handleError(e));
所以,这是一个非常简单的工作示例,我每天都会在工作中使用它。
【讨论】:
@GregorDoroschenko 我试图使用带有文件附加信息的模型,我必须这样做才能让它工作:const invFormData: FormData = new FormData(); invFormData.append('invoiceAttachment', invoiceAttachment, invoiceAttachment.name); invFormData.append('invoiceInfo', JSON.stringify(invoiceInfo));
控制器有两个相应的参数,但我必须解析控制器中的 JSON。我的 Core 2 控制器不会自动拾取参数中的模型。我最初的设计是一个具有文件属性的模型,但我无法让它工作
@GregorDoroschenko 我试过这个代码createContrat(fileToUpload: File, newContrat: Contrat): Observable<boolean> let headers = new Headers(); const endpoint = Api.getUrl(Api.URLS.createContrat)); const formData: FormData =new FormData(); formData.append('fileKey', fileToUpload, FileToUpload.name); let body newContrat.gup(this.auth.getCurrentUser().token); return this.http .post(endpoint, formData, body) .map(() => return true; )
@GregorDoroschenko 对我来说不起作用。我在ws发帖:Content-Disposition: form-data; name="fileKey"; filename="file.docx" Content-Type: application/octet-stream <file>
使用 Angular 5,这是行不通的。 formData 为空
$event.target.files
有什么用??【参考方案2】:
这样我在项目中实现了上传文件到web API。
我为谁担心。
const formData: FormData = new FormData();
formData.append('Image', image, image.name);
formData.append('ComponentId', componentId);
return this.http.post('/api/dashboard/UploadImage', formData);
一步一步
ASP.NET Web API
[HttpPost]
[Route("api/dashboard/UploadImage")]
public HttpResponseMessage UploadImage()
string imageName = null;
var httpRequest = HttpContext.Current.Request;
//Upload Image
var postedFile = httpRequest.Files["Image"];
//Create custom filename
if (postedFile != null)
imageName = new String(Path.GetFileNameWithoutExtension(postedFile.FileName).Take(10).ToArray()).Replace(" ", "-");
imageName = imageName + DateTime.Now.ToString("yymmssfff") + Path.GetExtension(postedFile.FileName);
var filePath = HttpContext.Current.Server.MapPath("~/Images/" + imageName);
postedFile.SaveAs(filePath);
html 表单
<form #imageForm=ngForm (ngSubmit)="OnSubmit(Image)">
<img [src]="imageUrl" class="imgArea">
<div class="image-upload">
<label for="file-input">
<img src="upload.jpg" />
</label>
<input id="file-input" #Image type="file" (change)="handleFileInput($event.target.files)" />
<button type="submit" class="btn-large btn-submit" [disabled]="Image.value=='' || !imageForm.valid"><i
class="material-icons">save</i></button>
</div>
</form>
使用 API 的 TS 文件
OnSubmit(Image)
this.dashboardService.uploadImage(this.componentId, this.fileToUpload).subscribe(
data =>
console.log('done');
Image.value = null;
this.imageUrl = "/assets/img/logo.png";
);
服务 TS
uploadImage(componentId, image)
const formData: FormData = new FormData();
formData.append('Image', image, image.name);
formData.append('ComponentId', componentId);
return this.http.post('/api/dashboard/UploadImage', formData);
【讨论】:
不发送标头的方法是什么?【参考方案3】:使用ng2-file-upload 是非常简单和最快的方法。
通过 npm 安装 ng2-file-upload。 npm i ng2-file-upload --save
首先在你的模块中导入模块。
import FileUploadModule from 'ng2-file-upload';
Add it to [imports] under @NgModule:
imports: [ ... FileUploadModule, ... ]
标记:
<input ng2FileSelect type="file" accept=".xml" [uploader]="uploader"/>
在您的组件中:
import FileUploader from 'ng2-file-upload';
...
uploader: FileUploader = new FileUploader( url: "api/your_upload", removeAfterUpload: false, autoUpload: true );
这是最简单的用法。要了解此功能的所有功能,请参阅demo
【讨论】:
图片上传后如何得到响应?会有什么反应,文档缺少这部分。 警告:ng2-file-upload 不使用 Angular 的 http 服务,因此 MSAL 拦截器不会接收调用,因此不会自动将访问令牌添加到 Authorization 标头中。跨度> 【参考方案4】:-
HTML
<div class="form-group">
<label for="file">Choose File</label><br /> <input type="file" id="file" (change)="uploadFiles($event.target.files)">
</div>
<button type="button" (click)="RequestUpload()">Ok</button>
-
ts 文件
public formData = new FormData();
ReqJson: any = ;
uploadFiles( file )
console.log( 'file', file )
for ( let i = 0; i < file.length; i++ )
this.formData.append( "file", file[i], file[i]['name'] );
RequestUpload()
this.ReqJson["patientId"] = "12"
this.ReqJson["requesterName"] = "test1"
this.ReqJson["requestDate"] = "1/1/2019"
this.ReqJson["location"] = "INDIA"
this.formData.append( 'Info', JSON.stringify( this.ReqJson ) )
this.http.post( '/Request', this.formData )
.subscribe(( ) =>
);
-
后端 Spring(java 文件)
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class Request
private static String UPLOADED_FOLDER = "c://temp//";
@PostMapping("/Request")
@ResponseBody
public String uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("Info") String Info)
System.out.println("Json is" + Info);
if (file.isEmpty())
return "No file attached";
try
// Get the file and save it somewhere
byte[] bytes = file.getBytes();
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
Files.write(path, bytes);
catch (IOException e)
e.printStackTrace();
return "Succuss";
我们必须在C盘创建一个文件夹“temp”,然后这段代码将在控制台打印Json并将上传的文件保存在创建的文件夹中
【讨论】:
我们如何检索该文件?你对此有什么指导吗? 另外,我的 spring 服务器在 8080 上运行,而 angular 在 3000 上运行。现在,当我将 server_url 标记为 localhost:8080/api/uploadForm 时,它说不允许使用 cors! byte[] bytes = file.getBytes();它将给出字节流..您可以将其转换为文件,对于 cors 问题您可以在 google 中找到解决方案 如果用户在没有选择任何文件之前直接点击“确定”按钮,是否有可能返回没有选择文件的警报?` @Siddharth 将此添加到您的弹簧控制器注释中:@CrossOrigin(origins = "localhost:8080")【参考方案5】:首先,您需要在 Angular 项目中设置 HttpClient。
打开src/app/app.module.ts文件,导入HttpClientModule,添加到模块的imports数组中,如下:
import BrowserModule from '@angular/platform-browser';
import NgModule from '@angular/core';
import AppRoutingModule from './app-routing.module';
import AppComponent from './app.component';
import HttpClientModule from '@angular/common/http';
@NgModule(
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
)
export class AppModule
接下来,生成一个组件:
$ ng generate component home
接下来,生成一个上传服务:
$ ng generate service upload
接下来打开src/app/upload.service.ts文件如下:
import HttpClient, HttpEvent, HttpErrorResponse, HttpEventType from '@angular/common/http';
import map from 'rxjs/operators';
@Injectable(
providedIn: 'root'
)
export class UploadService
SERVER_URL: string = "https://file.io/";
constructor(private httpClient: HttpClient)
public upload(formData)
return this.httpClient.post<any>(this.SERVER_URL, formData,
reportProgress: true,
observe: 'events'
);
接下来,打开 src/app/home/home.component.ts 文件,首先添加以下导入:
import Component, OnInit, ViewChild, ElementRef from '@angular/core';
import HttpEventType, HttpErrorResponse from '@angular/common/http';
import of from 'rxjs';
import catchError, map from 'rxjs/operators';
import UploadService from '../upload.service';
接下来,定义fileUpload和files变量并注入UploadService如下:
@Component(
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
)
export class HomeComponent implements OnInit
@ViewChild("fileUpload", static: false) fileUpload: ElementRef;files = [];
constructor(private uploadService: UploadService)
接下来,定义uploadFile()方法:
uploadFile(file)
const formData = new FormData();
formData.append('file', file.data);
file.inProgress = true;
this.uploadService.upload(formData).pipe(
map(event =>
switch (event.type)
case HttpEventType.UploadProgress:
file.progress = Math.round(event.loaded * 100 / event.total);
break;
case HttpEventType.Response:
return event;
),
catchError((error: HttpErrorResponse) =>
file.inProgress = false;
return of(`$file.data.name upload failed.`);
)).subscribe((event: any) =>
if (typeof (event) === 'object')
console.log(event.body);
);
接下来,定义uploadFiles()方法,可以用来上传多个图片文件:
private uploadFiles()
this.fileUpload.nativeElement.value = '';
this.files.forEach(file =>
this.uploadFile(file);
);
接下来,定义 onClick() 方法:
onClick()
const fileUpload = this.fileUpload.nativeElement;fileUpload.onchange = () =>
for (let index = 0; index < fileUpload.files.length; index++)
const file = fileUpload.files[index];
this.files.push( data: file, inProgress: false, progress: 0);
this.uploadFiles();
;
fileUpload.click();
接下来,我们需要创建图片上传 UI 的 HTML 模板。打开 src/app/home/home.component.html 文件,添加如下内容:
<div [ngStyle]="'text-align':center; 'margin-top': 100px;">
<button mat-button color="primary" (click)="fileUpload.click()">choose file</button>
<button mat-button color="warn" (click)="onClick()">Upload</button>
<input [hidden]="true" type="file" #fileUpload id="fileUpload" name="fileUpload" multiple="multiple" accept="image/*" />
</div>
看看这个tutorial和这个post
【讨论】:
【参考方案6】:好的,由于该线程出现在 google 的第一个结果中,并且对于其他有相同问题的用户,您不必像 trueboroda 所指出的那样重新启动***,有 ng2-file-upload 库可以简化此过程上传 Angular 6 和 7 的文件,您需要做的就是:
安装最新的 Angular CLI
yarn add global @angular/cli
然后出于兼容性考虑安装 rx-compat
npm install rxjs-compat --save
安装 ng2-file-upload
npm install ng2-file-upload --save
在您的模块中导入 FileSelectDirective 指令。
import FileSelectDirective from 'ng2-file-upload';
Add it to [declarations] under @NgModule:
declarations: [ ... FileSelectDirective , ... ]
在您的组件中
import FileUploader from 'ng2-file-upload/ng2-file-upload';
...
export class AppComponent implements OnInit
public uploader: FileUploader = new FileUploader(url: URL, itemAlias: 'photo');
模板
<input type="file" name="photo" ng2FileSelect [uploader]="uploader" />
为了更好地理解,您可以查看此链接: How To Upload a File With Angular 6/7
【讨论】:
感谢您的链接。上传在桌面上工作正常,但我不能在我的生活中让上传在 ios 等移动设备上工作。我可以从相机胶卷中选择一个文件,但是当我上传时它总是失败。有任何想法吗?仅供参考,在移动 safari 中运行,而不是在已安装的应用程序中运行。 嗨@ScottN,不客气,也许问题出在您使用的浏览器上?你用另一个测试过吗? 嗨@Mohamed Makkaoui 感谢您的回复。我确实在 iOS 上的 Chrome 中尝试过,结果仍然相同。我很好奇这是否是发布到服务器时的标题问题?我使用的是用 .Net 编写的自定义 WebAPI,而不是 AWS 仅供参考。 嗨@ScottN,在您使用此链接developers.google.com/web/tools/chrome-devtools/… 调试代码并查看您收到什么错误消息之前,我们无法知道这是否是标头问题。 另一方面,你不需要一个包来实现一个简单的文件上传。 API 应有尽有,您无需重新发明任何东西。【参考方案7】:我正在使用 Angular 5.2.11, 我喜欢 Gregor Doroschenko 提供的解决方案,但是我注意到上传的文件是零字节,我必须做一些小改动才能让它为我工作。
postFile(fileToUpload: File): Observable<boolean>
const endpoint = 'your-destination-url';
return this.httpClient
.post(endpoint, fileToUpload, headers: yourHeadersConfig )
.map(() => return true; )
.catch((e) => this.handleError(e));
以下行 (formData) 对我不起作用。
const formData: FormData = new FormData();
formData.append('fileKey', fileToUpload, fileToUpload.name);
https://github.com/amitrke/ngrke/blob/master/src/app/services/fileupload.service.ts
【讨论】:
【参考方案8】:就我个人而言,我在前端使用ngx-material-file-input,在后端使用Firebase。更准确地说是 Cloud Storage for Firebase 用于与 Cloud Firestore 结合的后端。下面的示例将文件限制为不大于 20 MB,并且仅接受某些文件扩展名。我也使用Cloud Firestore 来存储上传文件的链接,但你可以跳过这个。
contact.component.html
<mat-form-field>
<!--
Accept only files in the following format: .doc, .docx, .jpg, .jpeg, .pdf, .png, .xls, .xlsx. However, this is easy to bypass, Cloud Storage rules has been set up on the back-end side.
-->
<ngx-mat-file-input
[accept]="[
'.doc',
'.docx',
'.jpg',
'.jpeg',
'.pdf',
'.png',
'.xls',
'.xlsx'
]"
(change)="uploadFile($event)"
formControlName="fileUploader"
multiple
aria-label="Here you can add additional files about your project, which can be helpeful for us."
placeholder="Additional files"
title="Additional files"
type="file"
>
</ngx-mat-file-input>
<mat-icon matSuffix>folder</mat-icon>
<mat-hint
>Accepted formats: DOC, DOCX, JPG, JPEG, PDF, PNG, XLS and XLSX,
maximum files upload size: 20 MB.
</mat-hint>
<!--
Non-null assertion operators are required to let know the compiler that this value is not empty and exists.
-->
<mat-error
*ngIf="contactForm.get('fileUploader')!.hasError('maxContentSize')"
>
This size is too large,
<strong
>maximum acceptable upload size is
contactForm.get('fileUploader')?.getError('maxContentSize')
.maxSize | byteFormat
</strong
>
(uploaded size:
contactForm.get('fileUploader')?.getError('maxContentSize')
.actualSize | byteFormat
).
</mat-error>
</mat-form-field>
contact.component.ts(尺寸验证器部分)
import FileValidator from 'ngx-material-file-input';
import FormBuilder, FormGroup, Validators from '@angular/forms';
/**
* @constructor
* @description Creates a new instance of this component.
* @param formBuilder - an abstraction class object to create a form group control for the contact form.
*/
constructor(
private angularFirestore: AngularFirestore,
private angularFireStorage: AngularFireStorage,
private formBuilder: FormBuilder
)
public maxFileSize = 20971520;
public contactForm: FormGroup = this.formBuilder.group(
fileUploader: [
'',
Validators.compose([
FileValidator.maxContentSize(this.maxFileSize),
Validators.maxLength(512),
Validators.minLength(2)
])
]
)
contact.component.ts(文件上传器部分)
import AngularFirestore from '@angular/fire/firestore';
import
AngularFireStorage,
AngularFireStorageReference,
AngularFireUploadTask
from '@angular/fire/storage';
import catchError, finalize from 'rxjs/operators';
import throwError from 'rxjs';
public downloadURL: string[] = [];
/**
* @description Upload additional files to Cloud Firestore and get URL to the files.
* @param event - object of sent files.
* @returns void
*/
public uploadFile(event: any): void
// Iterate through all uploaded files.
for (let i = 0; i < event.target.files.length; i++)
const randomId = Math.random()
.toString(36)
.substring(2); // Create random ID, so the same file names can be uploaded to Cloud Firestore.
const file = event.target.files[i]; // Get each uploaded file.
// Get file reference.
const fileRef: AngularFireStorageReference = this.angularFireStorage.ref(
randomId
);
// Create upload task.
const task: AngularFireUploadTask = this.angularFireStorage.upload(
randomId,
file
);
// Upload file to Cloud Firestore.
task
.snapshotChanges()
.pipe(
finalize(() =>
fileRef.getDownloadURL().subscribe((downloadURL: string) =>
this.angularFirestore
.collection(process.env.FIRESTORE_COLLECTION_FILES!) // Non-null assertion operator is required to let know the compiler that this value is not empty and exists.
.add( downloadURL: downloadURL );
this.downloadURL.push(downloadURL);
);
),
catchError((error: any) =>
return throwError(error);
)
)
.subscribe();
storage.rules
rules_version = '2';
service firebase.storage
match /b/bucket/o
match /allPaths=**
allow read; // Required in order to send this as attachment.
// Allow write files Firebase Storage, only if:
// 1) File is no more than 20MB
// 2) Content type is in one of the following formats: .doc, .docx, .jpg, .jpeg, .pdf, .png, .xls, .xlsx.
allow write: if request.resource.size <= 20 * 1024 * 1024
&& (request.resource.contentType.matches('application/msword')
|| request.resource.contentType.matches('application/vnd.openxmlformats-officedocument.wordprocessingml.document')
|| request.resource.contentType.matches('image/jpg')
|| request.resource.contentType.matches('image/jpeg')
|| request.resource.contentType.matches('application/pdf')
|| request.resource.contentType.matches('image/png')
|| request.resource.contentType.matches('application/vnd.ms-excel')
|| request.resource.contentType.matches('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'))
【讨论】:
看起来不错,但为什么在contactForm声明中需要toString()
?
@trungk18 再次检查它,你是对的 toString()
没用,编辑了我的答案。对于那些会阅读此评论的人,在 contact.component.ts 中 fileUploader
的末尾我有 ])].toString())
。现在很简单:])])
.【参考方案9】:
使用 Angular 和 nodejs(express) 上传文件的完整示例
HTML 代码
<div class="form-group">
<label for="file">Choose File</label><br/>
<input type="file" id="file" (change)="uploadFile($event.target.files)" multiple>
</div>
TS 组件代码
uploadFile(files)
console.log('files', files)
var formData = new FormData();
for(let i =0; i < files.length; i++)
formData.append("files", files[i], files[i]['name']);
this.httpService.httpPost('/fileUpload', formData)
.subscribe((response) =>
console.log('response', response)
,
(error) =>
console.log('error in fileupload', error)
)
Node Js 代码
fileUpload API 控制器
function start(req, res)
fileUploadService.fileUpload(req, res)
.then(fileUploadServiceResponse =>
res.status(200).send(fileUploadServiceResponse)
)
.catch(error =>
res.status(400).send(error)
)
module.exports.start = start
使用 multer 上传服务
const multer = require('multer') // import library
const moment = require('moment')
const q = require('q')
const _ = require('underscore')
const fs = require('fs')
const dir = './public'
/** Store file on local folder */
let storage = multer.diskStorage(
destination: function (req, file, cb)
cb(null, 'public')
,
filename: function (req, file, cb)
let date = moment(moment.now()).format('YYYYMMDDHHMMSS')
cb(null, date + '_' + file.originalname.replace(/-/g, '_').replace(/ /g, '_'))
)
/** Upload files */
let upload = multer( storage: storage ).array('files')
/** Exports fileUpload function */
module.exports =
fileUpload: function (req, res)
let deferred = q.defer()
/** Create dir if not exist */
if (!fs.existsSync(dir))
fs.mkdirSync(dir)
console.log(`\n\n $dir dose not exist, hence created \n\n`)
upload(req, res, function (err)
if (req && (_.isEmpty(req.files)))
deferred.resolve( status: 200, message: 'File not attached', data: [] )
else
if (err)
deferred.reject( status: 400, message: 'error', data: err )
else
deferred.resolve(
status: 200,
message: 'File attached',
filename: _.pluck(req.files,
'filename'),
data: req.files
)
)
return deferred.promise
【讨论】:
httpService从何而来? @James httpService 是 Angular 的 http 模块,用于对服务器进行 http 调用。你可以使用任何你想要的 http 服务。import HttpClientModule from '@angular/common/http';【参考方案10】:在 Angular 7/8/9
来源Link
使用引导表单
<form>
<div class="form-group">
<fieldset class="form-group">
<label>Upload Logo</label>
imageError
<div class="custom-file fileInputProfileWrap">
<input type="file" (change)="fileChangeEvent($event)" class="fileInputProfile">
<div class="img-space">
<ng-container *ngIf="isImageSaved; else elseTemplate">
<img [src]="cardImageBase64" />
</ng-container>
<ng-template #elseTemplate>
<img src="./../../assets/placeholder.png" class="img-responsive">
</ng-template>
</div>
</div>
</fieldset>
</div>
<a class="btn btn-danger" (click)="removeImage()" *ngIf="isImageSaved">Remove</a>
</form>
在组件类
fileChangeEvent(fileInput: any)
this.imageError = null;
if (fileInput.target.files && fileInput.target.files[0])
// Size Filter Bytes
const max_size = 20971520;
const allowed_types = ['image/png', 'image/jpeg'];
const max_height = 15200;
const max_width = 25600;
if (fileInput.target.files[0].size > max_size)
this.imageError =
'Maximum size allowed is ' + max_size / 1000 + 'Mb';
return false;
if (!_.includes(allowed_types, fileInput.target.files[0].type))
this.imageError = 'Only Images are allowed ( JPG | PNG )';
return false;
const reader = new FileReader();
reader.onload = (e: any) =>
const image = new Image();
image.src = e.target.result;
image.onload = rs =>
const img_height = rs.currentTarget['height'];
const img_width = rs.currentTarget['width'];
console.log(img_height, img_width);
if (img_height > max_height && img_width > max_width)
this.imageError =
'Maximum dimentions allowed ' +
max_height +
'*' +
max_width +
'px';
return false;
else
const imgBase64Path = e.target.result;
this.cardImageBase64 = imgBase64Path;
this.isImageSaved = true;
// this.previewImagePath = imgBase64Path;
;
;
reader.readAsDataURL(fileInput.target.files[0]);
removeImage()
this.cardImageBase64 = null;
this.isImageSaved = false;
【讨论】:
能否请您告诉我文件是否保存在本地文件夹中? 老同学!好的!【参考方案11】:这是我上传 excel 文件的方法: 目录结构:
app
|-----uploadcomponent
|-----uploadcomponent.module.ts
|-----uploadcomponent.html
|-----app.module.ts
|-----app.component.ts
|-----app.service.ts
上传组件.html
<div>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input type="file" name="profile" enctype="multipart/form-data" accept=".xlsm,application/msexcel" (change)="onChange($event)" />
<button type="submit">Upload Template</button>
<button id="delete_button" class="delete_button" type="reset"><i class="fa fa-trash"></i></button>
</form>
</div>
上传组件.ts
import FormBuilder, FormGroup, ReactiveFormsModule from '@angular/forms';
import Component, OnInit from '@angular/core';
....
export class UploadComponent implements OnInit
form: FormGroup;
constructor(private formBuilder: FormBuilder, private uploadService: AppService)
ngOnInit()
this.form = this.formBuilder.group(
profile: ['']
);
onChange(event)
if (event.target.files.length > 0)
const file = event.target.files[0];
this.form.get('profile').setValue(file);
console.log(this.form.get('profile').value)
onSubmit()
const formData = new FormData();
formData.append('file', this.form.get('profile').value);
this.uploadService.upload(formData).subscribe(
(res) =>
this.response = res;
console.log(res);
,
(err) =>
console.log(err);
);
app.service.ts
upload(formData)
const endpoint = this.service_url+'upload/';
const httpOptions = headers: new HttpHeaders( <<<< Changes are here
'Authorization': 'token xxxxxxx')
;
return this.http.post(endpoint, formData, httpOptions);
在后端我使用 DJango REST 框架。 模型.py
from __future__ import unicode_literals
from django.db import models
from django.db import connection
from django_mysql.models import JSONField, Model
import uuid
import os
def change_filename(instance, filename):
extension = filename.split('.')[-1]
file_name = os.path.splitext(filename)[0]
uuid_name = uuid.uuid4()
return file_name+"_"+str(uuid_name)+"."+extension
class UploadTemplate (Model):
id = models.AutoField(primary_key=True)
file = models.FileField(blank=False, null=False, upload_to=change_filename)
def __str__(self):
return str(self.file.name)
views.py.
class UploadView(APIView):
serializer_class = UploadSerializer
parser_classes = [MultiPartParser]
def get_queryset(self):
queryset = UploadTemplate.objects.all()
return queryset
def post(self, request, *args, **kwargs):
file_serializer = UploadSerializer(data=request.data)
status = None
message = None
if file_serializer.is_valid():
file_serializer.save()
status = "Success"
message = "Success"
else:
status = "Failure"
message = "Failure!"
content = 'status': status, 'message': message
return Response(content)
serializers.py.
from uploadtemplate.models import UploadTemplate
from rest_framework import serializers
class UploadSerializer(serializers.ModelSerializer):
class Meta:
model = UploadTemplate
fields = '__all__'
urls.py.
router.register(r'uploadtemplate', uploadtemplateviews.UploadTemplateView,
base_name='UploadTemplate')
urlpatterns = [
....
url(r'upload/', uploadtemplateviews.UploadTemplateView.as_view()),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
MEDIA_URL 和 MEDIA_ROOT 在项目的 settings.py 中定义。
谢谢!
【讨论】:
【参考方案12】:试试这个
安装
npm install primeng --save
导入
import FileUploadModule from 'primeng/primeng';
HTML
<p-fileUpload name="myfile[]" url="./upload.php" multiple="multiple"
accept="image/*" auto="auto"></p-fileUpload>
【讨论】:
我厌倦了使用上面的例子。但我得到 ./upload.php not found. 你应该提供你的 URL 应该被加载而不是 upload.php @sandeep kamath @Vignesh 感谢您的回复。但是我发现我根本没有给出url属性它加载文件,应该是默认的。 如果我们用这种方法,你能解释一下如何在php中接收文件。【参考方案13】:create-profile.html
<body>
<h1 class="font-weight-bold" >Create Advertistment</h1>
<hr />
<form [formGroup]="form" (submit)="onSubmit()">
<div>
<label class="font-weight-bold">Insert Subject name</label>
<br>
<input formControlName="name" type="text" placeholder="Enter name..." />
</div>
<div>
<br>
<label class="font-weight-bold">Select the Advertistment</label>
<br>
<input (change)="onFileSelect($event)" type="file" />
</div>
<br>
<!--<div *ngIf="imageData">
<img [src]="imageData" [alt]="form.value.name" />
</div>-->
<div>
<label class="font-weight-bold">Upload the Advertistment</label>
<br>
<button type="submit" class="btn btn-success" >Upload Advertistment</button>
</div>
</form>
</body>
create-profile.ts
import Component, OnInit from "@angular/core";
import FormGroup, FormControl from "@angular/forms";
import Profile from "../../models/Profile";
import ProfileService from "src/app/services/profile.service";
@Component(
selector: "app-create-profile",
templateUrl: "./create-profile.component.html",
styleUrls: ["./create-profile.component.css"],
)
export class CreateProfileComponent implements OnInit
form: FormGroup;
profile: Profile;
imageData: string;
constructor(private profileService: ProfileService)
ngOnInit(): void
this.form = new FormGroup(
name: new FormControl(null),
image: new FormControl(null),
);
onFileSelect(event: Event)
const file = (event.target as HTMLInputElement).files[0];
this.form.patchValue( image: file );
const allowedMimeTypes = ["image/png", "image/jpeg", "image/jpg"];
if (file && allowedMimeTypes.includes(file.type))
const reader = new FileReader();
reader.onload = () =>
this.imageData = reader.result as string;
;
reader.readAsDataURL(file);
onSubmit()
this.profileService.addProfile(this.form.value.name, this.form.value.image);
this.form.reset();
this.imageData = null;
profile.service.ts
import Injectable from "@angular/core";
import HttpClient from "@angular/common/http";
import map from "rxjs/operators";
import Profile from "../models/Profile";
import Subject from "rxjs";
@Injectable(
providedIn: "root",
)
export class ProfileService
private profiles: Profile[] = [];
private profiles$ = new Subject<Profile[]>();
readonly url = "http://localhost:3000/api/profiles";
constructor(private http: HttpClient)
getProfiles()
this.http
.get< profiles: Profile[] >(this.url)
.pipe(
map((profileData) =>
return profileData.profiles;
)
)
.subscribe((profiles) =>
this.profiles = profiles;
this.profiles$.next(this.profiles);
);
getProfilesStream()
return this.profiles$.asObservable();
addProfile(name: string, image: File): void
const profileData = new FormData();
profileData.append("name", name);
profileData.append("image", image, name);
this.http
.post< profile: Profile >(this.url, profileData)
.subscribe((profileData) =>
const profile: Profile =
_id: profileData.profile._id,
name: name,
imagePath: profileData.profile.imagePath,
;
this.profiles.push(profile);
this.profiles$.next(this.profiles);
);
Profile.ts
export interface Profile
_id: string;
name: string;
imagePath: string;
【讨论】:
【参考方案14】:就我而言,我使用的是 http 拦截器,事情是默认情况下我的 http 拦截器将 content-type
标头设置为 application/json
,但对于文件上传,我使用的是 multer 库。
稍微改变一下我的 http.interceptor 就定义了请求正文是否是 FormData ,它会删除标头并且不会触及访问令牌。
这是部分代码,这让我很开心。
if (request.body instanceof FormData)
request = request.clone( headers: request.headers.delete('Content-Type', 'application/json') );
if (request.body instanceof FormData)
request = request.clone( headers: request.headers.delete('Accept', 'application/json'));
【讨论】:
以上是关于角度文件上传的主要内容,如果未能解决你的问题,请参考以下文章