17

我有一个网络应用程序。我正在使用java和spring。应用程序可以创建一个文件并将其发送到浏览器,这工作正常。我这样做的方式是:

我在 Services 类中创建文件,该方法将地址返回给控制器。然后控制器发送文件,并正确下载。控制器方法的代码是这样的。

@RequestMapping("/getFile")
public @ResponseBody
FileSystemResource getFile() {

    String address = Services.createFile();
    response.setContentType("application/vnd.ms-excel");
    return new FileSystemResource(new File (address));
}

问题是文件保存在服务器中,经过多次请求后会有很多文件。我必须手动删除它们。问题是:发送后如何删除此文件?或者有没有办法发送文件而不将其保存在服务器中?

4

5 回答 5

29

不要使用@ResponseBody. 让 Spring 注入HttpServletResponse并直接写入其OutputStream.

@RequestMapping("/getFile")
public void getFile(HttpServletResponse response) {
    String address = Services.createFile();
    File file = new File(address);
    response.setContentType("application/vnd.ms-excel");
    response.setHeader("Content-disposition", "attachment; filename=" + file.getName());

    OutputStream out = response.getOutputStream();
    FileInputStream in = new FileInputStream(file);

    // copy from in to out
    IOUtils.copy(in,out);

    out.close();
    in.close();
    file.delete();
}

我没有添加任何异常处理。我把它留给你。

FileSystemResourceis 实际上只是FileInputStreamSpring 使用的包装器。

或者,如果您想成为铁杆,您可以FileSystemResource使用自己的方法创建自己的实现,该getOutputStream()方法返回您自己的实现,FileOutputStream当您调用close()它时删除底层文件。

于 2013-07-29T20:29:15.033 回答
10

所以我决定采纳 Sotirious 的建议,采用“硬核”方式。这很简单,但有一个问题。如果该类的用户打开输入流一次以检查并关闭它,它将无法再次打开它,因为文件在关闭时被删除。Spring 似乎没有这样做,但是您需要在每次版本升级后进行检查。

public class DeleteAfterReadeFileSystemResource extends FileSystemResource {
    public DeleteAfterReadeFileSystemResource(File file) {
        super(file);
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return new DeleteOnCloseFileInputStream(super.getFile());
    }

    private static final class DeleteOnCloseFileInputStream extends FileInputStream {

        private File file;
        DeleteOnCloseFileInputStream(File file) throws FileNotFoundException    {
            super(file);
            this.file = file;
        }

        @Override
        public void close() throws IOException {
            super.close();
            file.delete();
        }
    }
}
于 2016-05-19T14:23:12.313 回答
9

对这个答案的小改动。

使用 aInputStreamResource而不是FileSystemResource会使它更短一些。

public class CleanupInputStreamResource extends InputStreamResource {
    public CleanupInputStreamResource(File file) throws FileNotFoundException {
        super(new FileInputStream(file) {
            @Override
            public void close() throws IOException {
                super.close();
                Files.delete(file.toPath());
            }
        });
    }
}
于 2018-07-17T18:51:02.150 回答
2

您可以使用匿名类编写 Mag 的解决方案,如下所示:

new FileSystemResource(file) {
    @Override
    public InputStream getInputStream() throws IOException {
        return new FileInputStream(file) {
            @Override
            public void close() throws IOException {
                super.close();
                Files.delete(file.toPath());
            }
        };
    }
}
于 2021-04-08T06:21:25.107 回答
0

使用了这个答案并添加了一些修改。工作至今。由于我的知识有限,我无法为我的自定义 inputStream 创建动态代理。

import static org.apache.commons.io.FileUtils.deleteQuietly;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;

import org.springframework.core.io.FileSystemResource;

import lombok.RequiredArgsConstructor;

public final class AutoDeleteFileSystemResource extends FileSystemResource {

    public AutoDeleteFileSystemResource(Path filePath) {
        super(filePath);
    }

    @RequiredArgsConstructor
    private static final class AutoDeleteStream extends InputStream {

        private final File file;
        private final InputStream original;

        @Override
        public int read() throws IOException {
            return original.read();
        }

        @Override
        public void close() throws IOException {
            original.close();
            deleteQuietly(file);
        }

        @Override
        public int available() throws IOException {
            return original.available();
        }

        @Override
        public int read(byte[] b) throws IOException {
            return original.read(b);
        }

        @Override
        public int read(byte[] b, int off, int len) throws IOException {
            return original.read(b, off, len);
        }

        @Override
        public long skip(long n) throws IOException {
            return original.skip(n);
        }

        @Override
        public boolean equals(Object obj) {
            return original.equals(obj);
        }

        @Override
        public int hashCode() {
            return original.hashCode();
        }

        @Override
        public synchronized void mark(int readlimit) {
            original.mark(readlimit);
        }

        @Override
        public boolean markSupported() {
            return original.markSupported();
        }

        @Override
        public synchronized void reset() throws IOException {
            original.reset();
        }

        @Override
        public String toString() {
            return original.toString();
        }
    }

    /**
     * @see org.springframework.core.io.FileSystemResource#getInputStream()
     */
    @Override
    public InputStream getInputStream() throws IOException {
        return new AutoDeleteStream(getFile(), super.getInputStream());
    }
}
于 2021-12-25T15:42:23.927 回答