【本地对象存储】- Angular + ng-zorro实现文件上传

后端API接口项目,请参考local-server 项目,使用Spring boot框架实现本地存储服务。

前端使用Angular + ng-zorro实现,项目源码在这里Gitee

模型(model)

需要定义文件元数据(metadata)模型,描述文件信息, 在local.model.ts中定义

export class Metadata extends BaseEntity {
  createdBy!: string;
  createdDate!: Date;
  name!: string;
  path!: string;
  contentType!: string;
  size!: number;

  constructor(data?: Partial<Metadata>) {
    super(data);
    Object.assign(this, data);

    if (data?.createdDate != undefined) {
      this.createdDate = new Date(data.createdDate);
    }
  }
}

元数据ID在BaseEntity对象中定义。此模型定义了名称,路径,类型,大小等关键信息

服务(Service)

local.service.ts

@Injectable({ providedIn: 'root' })
export class LocalService {
  private baseFileUrl = '/oss/v1/files';
  private baseMetadataUrl = '/oss/v1/metadatas';

  private upload$ = new Subject<Metadata>();
  private remove$ = new Subject<Metadata>();

  constructor(private http: BaseHttpService) {}

  public get onUpload(): Observable<Metadata> {
    return this.upload$.asObservable();
  }

  public get onRemove(): Observable<Metadata> {
    return this.remove$.asObservable();
  }

  uploadEvent(formData: FormData): Observable<HttpEvent<any>> {
    return this.http
      .post<any>(`${this.baseFileUrl}/upload`, formData, null, {
        observe: 'events',
        reportProgress: true
      })
      .pipe(
        tap(e => {
          if (e instanceof HttpResponse) {
            this.upload$.next(new Metadata(e.body));
          }
        })
      );
  }

  upload(formData: FormData): Observable<Metadata> {
    return this.http.post<Metadata>(`${this.baseFileUrl}/upload/`, formData).pipe(
      map(e => new Metadata(e)),
      tap(e => {
        this.upload$.next(e);
      })
    );
  }

  download(metadataId: string): Observable<Blob> {
    return this.http.get(`${this.baseFileUrl}/download/${metadataId}`, null, { responseType: 'blob' });
  }

  downloads(metadataIds: string[]): Observable<Blob> {
    const queryParams = { metadataIds: metadataIds };
    return this.http.get(`${this.baseFileUrl}/downloads/`, queryParams, { responseType: 'blob' });
  }

  delete(metadataId: string): Observable<any> {
    const url = `${this.baseFileUrl}/${metadataId}`;
    return this.http.delete(url).pipe(
      tap(e => {
        this.remove$.next(new Metadata(e));
      })
    );
  }

  public getMetadataById(id: string): Observable<Metadata> {
    return this.http.get<Metadata>(`${this.baseMetadataUrl}/${id}`).pipe(map(data => new Metadata(data)));
  }

  public getMetadataByIds(ids: string[]): Observable<Metadata[]> {
    const queryParams = { ids: ids };
    return this.http
      .get<Metadata[]>(`${this.baseMetadataUrl}/ids`, queryParams)
      .pipe(map(data => data.map(e => new Metadata(e))));
  }

  public updateMetadataById(id: string, name: string): Observable<Metadata> {
    const queryParams = { name: name };
    return this.http.get<Metadata>(`${this.baseMetadataUrl}/${id}`, queryParams).pipe(map(e => new Metadata(e)));
  }
}

服务中有上传,下载,查询元数据的方法。

如何显示文件下载进度

在这里使用了HttpEvent返回对象,local-upload.component.ts文件部分类容:

    this.localSrc
      .uploadEvent(formData)
      .pipe(takeUntil(fileUploadInfo.onCancelRequest))
      .subscribe({
        next: (e: any) => {
          if (e.type === HttpEventType.UploadProgress) {
            fileUploadInfo.percent = Math.round((100 * e.loaded) / e.total);
          } else if (e instanceof HttpResponse) {
            fileUploadInfo.state = 'success';
            fileUploadInfo.isUpload = false;
            fileUploadInfo.metadata = new Metadata(e.body);

            this.uploadEvent.emit(fileUploadInfo.metadata);
          }
        },

        error: (err: any) => {
          fileUploadInfo.state = 'error';
          fileUploadInfo.isUpload = false;
        }
      });

if (e.type === HttpEventType.UploadProgress) 判断是否是进度消息

pipe(takeUntil(fileUploadInfo.onCancelRequest)) 实现上传文件过程取消功能

文件上传界面

界面使用ng-zorro的组件nz-upload实现,local-upload.component.html文件内容:

<nz-space>
  <nz-upload *nzSpaceItem [nzMultiple]="true" [nzBeforeUpload]="beforeUpload">
    <button nz-button>
      <span nz-icon nzType="upload"></span>
      选择上传文件...
    </button>
  </nz-upload>
</nz-space>
<nz-list nzGrid>
  <div nz-row nzGutter="8">
    <div nz-col nzXs="24" nzSm="24" nzMd="12" nzLg="6" nzXl="6" *ngFor="let item of fileUploadList">
      <nz-list-item>
        <nz-card [nzTitle]="titleTpl">
          <div *ngIf="item.metadata.id">
            <nz-descriptions [nzColumn]="1">
              <nz-descriptions-item nzTitle="名称">{{ item.metadata.name }}</nz-descriptions-item>
              <nz-descriptions-item nzTitle="大小">{{ item.metadata.size || 0 | bytes: 0 }}</nz-descriptions-item>
              <nz-descriptions-item nzTitle="类型">
                {{ item.metadata.contentType | shorten: 40:'...' }}
              </nz-descriptions-item>
              <nz-descriptions-item nzTitle="创建日期">
                {{ item.metadata.createdDate | date: 'yyyy-MM-dd HH:mm' }}
              </nz-descriptions-item>
            </nz-descriptions>
          </div>

          <div *ngIf="item.isUpload && !item.metadata.id">
            <nz-progress [nzPercent]="item.percent"></nz-progress>
          </div>

          <div nz-row nzJustify="center">
            <div *ngIf="item.isUpload" nz-col>
              <a (click)="cancel(item)">取消上传</a>
            </div>

            <div *ngIf="!item.isUpload && item.metadata.id === undefined">
              <a (click)="continue(item)">重新上传</a>
            </div>

            <div *ngIf="item.metadata.id">
              <a (click)="view(item)">查看</a>
              <nz-divider nzType="vertical"></nz-divider>
              <a (click)="rename(item)">重命名</a>
            </div>

            <div *ngIf="!item.isUpload">
              <nz-divider nzType="vertical"></nz-divider>
              <a (click)="delete(item)">删除</a>
            </div>
          </div>
        </nz-card>

        <ng-template #titleTpl>
          <nz-tag nzColor="warning" *ngIf="item.state === 'cancel'">
            <span nz-icon nzType="exclamation" *ngIf="item.state === 'cancel'"></span>
          </nz-tag>
          <nz-tag nzColor="success" *ngIf="item.state === 'success'">
            <span nz-icon nzType="check-circle"></span>
          </nz-tag>
          <nz-tag nzColor="processing" *ngIf="item.state === 'processing'">
            <span nz-icon nzType="sync"></span>
          </nz-tag>
          <nz-tag nzColor="error" *ngIf="item.state === 'error'">
            <span nz-icon nzType="close-circle"></span>
          </nz-tag>
          {{ item.file.name }}
        </ng-template>
      </nz-list-item>
    </div>
  </div>
  <nz-list-empty *ngIf="fileUploadList.length === 0"></nz-list-empty>
</nz-list>

功能截图

文件上传

 元数据查询 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Angular中,您可以使用ng-zorro-antd库中的`nz-date-picker`组件来创建一个带有日历和日期范围的日期选择器。以下是一个使用`nz-date-picker`的例子: 1. 首先,您需要在您的应用中安装和导入`ng-zorro-antd`库。 2. 在您的组件的HTML模板中添加一个`nz-date-picker`元素,并使用`nzMode`属性将其定义为日期选择器。 ```html <nz-date-picker nzMode="date"></nz-date-picker> ``` 3. 在您的组件中,您需要定义一个`nz-date-picker`对象,并将其与`nz-date-picker`元素相关联。您还可以使用`nzDisabledDate`属性来定义可选择的日期范围。 ```typescript import { Component } from '@angular/core'; import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'; @Component({ selector: 'app-date-picker', templateUrl: './date-picker.component.html', styleUrls: ['./date-picker.component.css'] }) export class DatePickerComponent { disabledDate = (current: Date): boolean => { const minDate = new Date(2020, 0, 1); const maxDate = new Date(2020, 11, 31); return current < minDate || current > maxDate; } constructor() { } } ``` 在这个例子中,我们定义了一个`disabledDate`函数来禁用不在2020年1月1日和2020年12月31日之间的日期。 4. 最后,您需要在`nz-date-picker`中使用`nzFormat`属性来定义日期的格式。 ```html <nz-date-picker nzMode="date" nzFormat="yyyy-MM-dd" [nzDisabledDate]="disabledDate"></nz-date-picker> ``` 在这个例子中,我们将日期格式定义为`yyyy-MM-dd`。 这就是如何在Angular中使用ng-zorro-antd库中的`nz-date-picker`组件创建一个带有日历和日期范围的日期选择器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值