【问题标题】:Spring : Download file from REST controllerSpring:从 REST 控制器下载文件
【发布时间】:2019-01-02 06:55:24
【问题描述】:

我在一个 Spring 项目上工作以制作一个 Web 应用程序,因此有一个 Tomcat 服务器允许我使用我的 Web 应用程序午餐。
我在这个网络应用程序上有 2 个功能,第一个允许我在 Postgresql 数据库上上传文件(它工作正常)。但在那之后,我希望能够下载这个文件。

这是我的服务方法。

public byte[] download(Integer id){
    Line line = getById(Line.class, id);
    int blobLenght;
    byte[] fileToReturn = null;
    Blob file = line.getFile();
    blobLenght = (int)file.length();
    fileToReturn = file.getBytes(1,blobLenght);
    return fileToReturn;
}

在我的 RestController 上,我有一个带有 @RequestMapping 注释的方法。 并且此方法返回一个 ResponseEntity。在之后的方法中,lineService 在我的类的顶部注入(@Autowired)。

@RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity<?> download(@RequestParam("id" Integer id)
{
    byte[] fileToDownload = lineService.download(id);
    return new ResponseEntity<byte[]>(fileToDownload,HttpStatus.OK);
}

我已尽力简化方法。

这是我的问题。确实,我意识到一种方法,当我一个一个地提出一些请求时,它就可以工作。但是,服务器必须能够支持同时接收大量请求。现在,当我同时测试多个请求时,我得到了 OutOfMemoryError : Java heap space。
我试图在“下载”方法上实现 Stream,但我得到了同样的错误。我对流的实现做得不好。 我尝试了许多在互联网上找到的解决方案,这是我实施的最后一个:

public ResponseEntity<byte[]> download(Integer id){
    Line line = getById(Line.class, id);
    HttpHeaders headers = new HttpHeaders();
    InputStream is = line.getFile().getBinaryStream;
    byte[] fileToReturn = IOUtils.toByteArray(is);
    headers.setCacheControl(CacheControl.noCache().getHeaderValue());
    ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(fileToDownload,HttpStatus.OK);
    return responseEntity;
}

你知道我可以如何更新我的程序来回答项目的要求吗?
如果我在好的路上,你能告诉我我的错误在哪里,或者你有什么建议吗?

感谢您的帮助!

下午。

【问题讨论】:

    标签: java spring postgresql stream blob


    【解决方案1】:

    希望对你有所帮助。为我工作。

    import org.springframework.core.io.UrlResource;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import org.springframework.core.io.Resource;
    
    @RestController
    public class SomeClass{
    
    
        @GetMapping("/{fileName}")
        public ResponseEntity<Resource> getFile(@PathVariable String fileName, HttpServletRequest request, HttpServletResponse response) throws Exception {
            Resource file = getFileAsResource(fileName);
            HttpHeaders headers = prepareHeaderForFileReturn(fileName, request, response);
            return new ResponseEntity<Resource>(file, headers, HttpStatus.OK);
        }
    
        private HttpHeaders prepareHeaderForFileReturn(String fileName, HttpServletRequest request,
                                                       HttpServletResponse response) {
            HttpHeaders headers = new HttpHeaders();
            headers.set(HttpHeaders.CONTENT_TYPE, getContentTypeForAttachment(fileName));
            response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
            return headers;
        }
    
    
        public Resource getFileAsResource(String filename) throws FileNotFoundException {
            String filePath = path +  "/" + filename;
            Resource file = loadAsResource(filePath);
            return file;
        }
    
        private Resource loadAsResource(String filename) throws FileNotFoundException {
            try {
                Path file = Paths.get(filename);
                org.springframework.core.io.Resource resource = new UrlResource(file.toUri());
                if (resource.exists() || resource.isReadable()) {
                    return resource;
                } else {
                    log.error("Could not read file: " + filename);
                    throw new FileNotFoundException();
                }
            } catch (MalformedURLException e) {
                log.error("Could not read file: " + filename, e);
                throw new FileNotFoundException();
            }
        }
    
        //Obtains a content type for file by his extension.
    
        public String getContentTypeForAttachment(String fileName) {
            String fileExtension = com.google.common.io.Files.getFileExtension(fileName);
            if (fileExtension.equals("pdf")) return "application/pdf";
            else if (fileExtension.equals("doc")) return "application/msword";
            else if (fileExtension.equals("jpeg")) return "image/jpeg";
    
        }
    }
    

    【讨论】:

    • 如果我理解的话,您使用控制器获得的文件在本地。就我而言,它们位于数据库中,但我将尝试根据我的需要调整您的建议。我认为这很重要,因为您使用文件名及其路径,但对我来说,我只有一个 Blob 对象
    • 是的,你是对的。我从磁盘返回文件。您可以将 Blob 转换为 Resource 并尝试我的实现变体。
    • 我刚刚找到了解决方案。对不起,我没有使用你的作品,但谢谢。
    • 我发现这个答案很有用,但代码有点乱。您应该删除对 HttpServletRequest 和 HttpServletResponse 的明确提及,因为您不需要它们,而是使用 Spring 抽象。
    【解决方案2】:

    我用流修改了“下载”方法,它可以正常工作。

    public void download(Integer id, HttpServletResponse response){
        Line line = getById(Line.class, id);
        InputStream is = line.getFile().getBinaryStream;
        IOUtils.copy(is, response.getOutputStream());
        response.flushBuffer();
    }
    

    我的控制器就是这样的:

    public ResponseEntity<?> download(@RequestParam("id") Integer id, HttpServletResponse response)
    {
        lineService.download(id,response);
        return new ResponseEntity<>(HttpStatus.OK);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-11
      • 2022-01-12
      • 2011-08-06
      相关资源
      最近更新 更多