角度文件上传

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&lt;boolean&gt; 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(() =&gt; return true; ) @GregorDoroschenko 对我来说不起作用。我在ws发帖:Content-Disposition: form-data; name="fileKey"; filename="file.docx" Content-Type: application/octet-stream &lt;file&gt; 使用 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.tsfileUploader 的末尾我有 ])].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'));

【讨论】:

以上是关于角度文件上传的主要内容,如果未能解决你的问题,请参考以下文章

使用角度4上传文件

上传文件角度[重复]

角度 Spring Boot 文件上传示例

以角度 8 上传 zip 文件

以角度上传多个文件

从春季启动以角度4发布上传文件?