简体   繁体   English

spring boot中如何读写文件

[英]How to write and read file in spring boot

I have a problem with saving files and then downloading them after generating a .war file.我在保存文件然后在生成 .war 文件后下载它们时遇到问题。 I need to handle the generation of many files after pressing the button by admin in the application.在应用程序中按管理员按钮后,我需要处理许多文件的生成。 The files are generated using part of the code that was sent using the POST method and second part is from the database.这些文件是使用使用 POST 方法发送的部分代码生成的,第二部分来自数据库。 The files are hundreds / thousands and it is impossible to do it manually.文件成百上千​​,手动完成是不可能的。 Admin generates files from time to time.管理员不时生成文件。 The user should be able to download these files from the application.用户应该能够从应用程序下载这些文件。 When I run the application in IntelliJ, app has access to the folders on the disk, so the following code works: (part of backend class, responfible for saving files in path)当我在 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();
        }
    }

The file was saved in folder: C:\\Users...\\myProject\\target\\classes\\static .该文件保存在文件夹中: C:\\Users...\\myProject\\target\\classes\\static (and this is link to generated file in thymeleaf) (这是 thymeleaf 中生成文件的链接)

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

<a th:href="@{|/myFiles/${thisIsMyFileName}|}">Download file</a>
</html>

Unfortunately, when I generate the .war file and run it, the files are not saved in the application's "resources" folder.不幸的是,当我生成 .war 文件并运行它时,这些文件没有保存在应用程序的“资源”文件夹中。 As a result, the user cannot download this file via the link generated by thymeleaf.因此,用户无法通过 thymeleaf 生成的链接下载此文件。

In general, you do not want to upload anything into your application's files - it opens you to many security problems if someone figures out how to overwrite parts of the application, and in most application servers, it is simply not writable.通常,您不想将任何内容上传到应用程序的文件中 - 如果有人想出如何覆盖应用程序的某些部分,这会给您带来许多安全问题,并且在大多数应用程序服务器中,它根本不可写。

A much better approach is to have a designated server folder where you can write things.更好的方法是拥有一个指定的服务器文件夹,您可以在其中编写内容。 For example, you could have the following in your configuration:例如,您可以在配置中包含以下内容:

myapp.base-folder = /any/server/folder/you/want

And then, in the code, you would find that folder as follows:然后,在代码中,您会发现该文件夹如下:

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

I find this better than using a database (as @Stultuske suggested in comments), because databases are great for relations, but mostly overkill for actual files.我发现这比使用数据库更好(正如@Stultuske 在评论中建议的那样),因为数据库非常适合关系,但对于实际文件来说大多是矫枉过正。 Files can be accessed externally without firing up the database with minimal hassle, and having them separate keeps your database much easier to backup.文件可以从外部访问,而无需以最少的麻烦启动数据库,并且将它们分开可以使您的数据库更容易备份。

To generate links to the file, simply create a link as you would to any other type of request要生成指向文件的链接,只需像创建任何其他类型的请求一样创建一个链接

<a th:href="@{/file/${fileId}|}">Download file</a>

-- and to handle it in the server, but returning the contents of the file: -- 并在服务器中处理它,但返回文件的内容:

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

I prefer numerical IDs to avoid hassles with path traversal - but you can easily use string filenames instead, and deal with security issues by carefully checking that the canonical path of the requested file starts with the canonical path of your baseFolder我更喜欢使用数字 ID 来避免路径遍历的麻烦——但您可以轻松地使用字符串文件名,并通过仔细检查请求文件的规范路径是否以baseFolder的规范路径开头来处理安全问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM