Spring Boot中如何读写文件

Mar*_*icz 5 java spring thymeleaf spring-boot

我在保存文件并在生成 .war 文件后下载它们时遇到问题。在应用程序中管理员按下按钮后,我需要处理许多文件的生成。这些文件是使用使用 POST 方法发送的部分代码生成的,第二部分来自数据库。文件有数百/数千个,不可能手动完成。管理员不时生成文件。用户应该能够从应用程序下载这些文件。当我在 IntelliJ 中运行应用程序时,应用程序可以访问磁盘上的文件夹,因此以下代码有效:(后端类的一部分,负责将文件保存在路径中)

    private void saveTextToFile(String text, String fileName) {
        String filePathAndName = "/static/myFiles/" + fileName+ ".txt";
        ClassLoader classLoader = getClass().getClassLoader();
        File file = new File(classLoader.getResource(".").getFile() + filePathAndName );
        FileWriter fileWriter = null;
        try {
            fileWriter = new FileWriter(file);
            PrintWriter printWriter = new PrintWriter(fileWriter);
            printWriter.print(text);
            printWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
Run Code Online (Sandbox Code Playgroud)

该文件保存在文件夹中: C:\Users...\myProject\target\classes\static。(这是百里香中生成的文件的链接)

<html xmlns:th="http://www.thymeleaf.org">

<a th:href="@{|/myFiles/${thisIsMyFileName}|}">Download file</a>
</html>
Run Code Online (Sandbox Code Playgroud)

不幸的是,当我生成 .war 文件并运行它时,这些文件没有保存在应用程序的“资源”文件夹中。因此,用户无法通过 thymeleaf 生成的链接下载该文件。

tuc*_*uxi 3

一般来说,您不想将任何内容上传到应用程序的文件中 - 如果有人弄清楚如何覆盖应用程序的某些部分,它会给您带来许多安全问题,并且在大多数应用程序服务器中,它根本不可写。

更好的方法是有一个指定的服务器文件夹,您可以在其中写入内容。例如,您的配置中可以包含以下内容:

myapp.base-folder = /any/server/folder/you/want
Run Code Online (Sandbox Code Playgroud)

然后,在代码中,您将找到该文件夹​​,如下所示:

// env is an @AutoWired private Environment
File baseFolder = new File(env.getProperty("myapp.base-folder"));
Run Code Online (Sandbox Code Playgroud)

我发现这比使用数据库更好(正如 @Stultuske 在评论中建议的那样),因为数据库对于关系来说非常有用,但对于实际文件来说大多是过度的。可以从外部访问文件,而无需以最小的麻烦启动数据库,并且将它们分开可以使数据库更容易备份。

要生成文件的链接,只需创建一个链接,就像任何其他类型的请求一样

<a th:href="@{/file/${fileId}|}">Download file</a>
Run Code Online (Sandbox Code Playgroud)

-- 并在服务器中处理它,但返回文件的内容:

@GetMapping(value="/file/{id}")
public StreamingResponseBody getFile(@PathVariable long id) throws IOException {        
    File f = new File(baseFolder, ""+id); // numerical id prevents filesytem traversal
    InputStream in;
    if (f.exists()) {
        in = new BufferedInputStream(new FileInputStream(f));
    } else {
        // you could also signal error by returning a 404
        in = new BufferedInputStream(getClass().getClassLoader()
                .getResourceAsStream("static/img/unknown-id.jpg"));
    }
    return new StreamingResponseBody() {
        @Override
        public void writeTo(OutputStream os) throws IOException {
            FileCopyUtils.copy(in, os);
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢数字 ID 以避免路径遍历的麻烦- 但您可以轻松地使用字符串文件名,并通过仔细检查所请求文件的规范路径是否以您的规范路径开头来处理安全问题baseFolder