spring - 找不到可接受的文件下载表示

标签 spring angular spring-boot spring-data-jpa angular6

我想使用这个 Angular 6 代码实现文件下载:

休息API:

private static final Logger LOG = LoggerFactory.getLogger(DownloadsController.class);

private static final String EXTERNAL_FILE_PATH = "/Users/test/Documents/blacklist_api.pdf";

@GetMapping("export")
public ResponseEntity<FileInputStream> export() throws IOException {
    File pdfFile = Paths.get(EXTERNAL_FILE_PATH).toFile();

    HttpHeaders headers = new HttpHeaders();
    headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
    headers.add("Pragma", "no-cache");
    headers.add("Expires", "0");

    return ResponseEntity.ok().headers(headers).contentLength(pdfFile.length())
            .contentType(MediaType.parseMediaType("application/pdf"))
            .body(new FileInputStream(pdfFile));
}

服务:
import {Injectable} from '@angular/core';
import {HttpClient, HttpParams} from "@angular/common/http";
import {Observable} from "rxjs/index";
import {environment} from "../../../environments/environment";
import {HttpUtils} from "../common/http-utils";
import { map } from 'rxjs/operators';
import {Http, ResponseContentType} from '@angular/http';


@Injectable({
  providedIn: 'root'
})
export class DownloadService {

  constructor(private http: HttpClient) {
  }

  downloadPDF(): any {
    return this.http.get(environment.api.urls.downloads.getPdf, {
        responseType: 'blob'
      })
      .pipe(
        map((res: any) => {
          return new Blob([res.blob()], {
            type: 'application/pdf'
          })
        })
      );
    }  
}

成分:
import {Component, OnInit} from '@angular/core';
import {DownloadService} from "../service/download.service";
import {ActivatedRoute, Router} from "@angular/router";
import {flatMap} from "rxjs/internal/operators";
import {of} from "rxjs/index";
import { map } from 'rxjs/operators';

@Component({
  selector: 'app-download',
  templateUrl: './download.component.html',
  styleUrls: ['./download.component.scss']
})
export class DownloadComponent implements OnInit {

  constructor(private downloadService: DownloadService,
              private router: Router,
              private route: ActivatedRoute) {
  }

  ngOnInit() {   
  }

  export() {               
    this.downloadService.downloadPDF().subscribe(res => {
      const fileURL = URL.createObjectURL(res);
      window.open(fileURL, '_blank');
    });         
  } 
}

该文件存在于目录中,但是当我尝试下载它时出现错误:
18:35:25,032 WARN  [org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver] (default task-2) Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]

你知道我该如何解决这个问题吗?
我是否需要添加其他配置才能通过 Angular Web UI 下载文件?

我使用 spring-boot-starter-parent 版本 2.1.0.RELEASE

最佳答案

文件保护程序 npmjs.com/package/ngx-filesaver是 Angular6 中最好的文件下载库,但它在 ios 设备中存在各种问题。我们通过编写自己的方法并有条件地处理它来修复它。

成分

download() {
    this.downloadService.downloadPDF().subscribe(async (res: Blob) => {
      if (this.isIOSMobileDevice) {
        const file = new File([res], fileName, { type: 'application/pdf' });
        const dataStringURL: any = await this.fileService.readFile(file);
        this.hrefLink = this.sanitizer.bypassSecurityTrustUrl(dataStringURL);
      } else {
        saveFile(res, fileName);
      }
    });
  }

export const saveFile = (blobContent: Blob, fileName) => {
        const isIOS = (!!navigator.platform.match(/iPhone|iPod|iPad/)) || (navigator.userAgent.match(/Mac/) && navigator.maxTouchPoints && navigator.maxTouchPoints > 2);
        const blob = new Blob([blobContent], { type: 'application/pdf' });
        if (window.navigator && window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveOrOpenBlob(blob, fileName);
        } else {
            const url = window.URL.createObjectURL(blob);
            const link = document.createElement('a');
            document.body.appendChild(link);
            link.href = url;
            link.target = '_self';
            link.download = fileName;
            link.click();
            document.body.removeChild(link);
        }
    };

文件服务
async readFile(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = () => {
                resolve(reader.result);
            };
            reader.onerror = reject;
            reader.readAsDataURL(file);
        });
    }

HTML代码
<a *ngIf="isIOSMobileDevice" [href]="hrefLink"
              target="_blank">Download</a>
            <a *ngIf="!isIOSMobileDevice" href="javascript:;" (click)="download"
              target="_blank">Download</a>

对于 ios 移动设备,必须在先决条件中调用下载方法,以便我们获得 hrefLink。

关于spring - 找不到可接受的文件下载表示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53241079/

相关文章:

java - 计算 SpringEL 表达式时出现异常 - 由于集合而出错?

java - Spring Boot不读取application.properties

java - Fiddler 未捕获 Spring STS 的结果

java - WebSocket 握手期间出错 : Unexpected response code: 403

java - 如何在 mongo 中加入 DBRef 对象

angular - 喷油器错误 "Provider parse errors: Cannot instantiate cyclic dependency!"

angular - 如何在 Jest 中模拟 router.navigate 方法

spring - Spring中的自定义约束验证器不起作用

java - 无法实例化 Json 对象 org.springframework.http.converter.HttpMessageNotReadableException

angular - RxJs中的 "new Observable()"和 "of()"有什么区别