Cannot download file: cannot be resolved to URL because it does not exist with Spring

Viewed 18288

I want to implement file download using this Angular 6 code:

Rest 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<InputStreamResource> export() throws IOException {
    ClassPathResource pdfFile = new ClassPathResource(EXTERNAL_FILE_PATH);

    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.contentLength())
            .contentType(MediaType.parseMediaType("application/pdf"))
            .body(new InputStreamResource(pdfFile.getInputStream()));
}

Service:

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');
    });         
  } 
}

Component:

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');
    });         
  } 
}

When I click download button I get this Spring error:

15:28:02,819 ERROR [org.springframework.boot.web.servlet.support.ErrorPageFilter] (default task-1) Forwarding to error page from request [/downloads/export] due to exception [class path resource [Users/test/Documents/blacklist_api.pdf] cannot be resolved to URL because it does not exist]: java.io.FileNotFoundException: class path resource [Users/test/Documents/blacklist_api.pdf] cannot be resolved to URL because it does not exist
    at deployment.test_admin.war//org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:195)

The file is present in the directory but looks like it's located outside of the war package and Wildly I can't access it. Is there any way to configure Java to access it and download it?

2 Answers

Since you are using ClasspathResource, you can only get files "within" the classpath.

If your file is outside of the classpath you can't get it in that way.

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<InputStreamResource> 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));
}

I changed the way you take the file, for a File and not a ClassPathResource.

I modified that piece of code on the fly, sorry if there's any mistake. I hope it can help

public static final String TEMPLATE_NAME = "filename.csv";

@Value("templates/" + TEMPLATE_NAME)
private ClassPathResource TEMPLATE;

@GetMapping(value = "/download/template", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void getTemplate(HttpServletResponse response) throws IOException {
    response.setHeader("Content-Disposition", "attachment; filename=" + TEMPLATE_NAME);
    IOUtils.copy(TEMPLATE.getInputStream(), response.getOutputStream());
    response.flushBuffer();
}
Related