spring - 在 HttpSession 中存储 MultipartFile

标签 spring spring-mvc spring-boot thymeleaf

我正在尝试创建一个 Spring Boot 应用程序,该应用程序上传文件并将其存储在 HttpSession 中以供将来使用(仅用于教育目的)。我的文件MultipartFile getSize()有问题。它在 POST 处理程序方法中返回非零值,并且每次我在 GET 处理程序方法中从 HttpSession 获取它们时都返回零。同时getOriginalFileName()返回正确的名称。因此,我的“已加载文件:”表正确显示文件名,但大小为零。

也许我尝试在 HttpSession 中存储 MultipartFile 在概念上是错误的?

我使用 Thymeleaf 作为模板。

这是一个模板:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      lang="en">
<head>
    <title>File Uploader</title>
</head>
<body>
<form method="POST" action="upload" enctype="multipart/form-data">
    <input type="file" name="files" id="files" multiple="multiple"/> <br/>
    <input type="submit" value="Upload" name="upload" id="upload"/>
    <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
</form>
<h3>Loaded files:</h3>
<table border="1px">
    <thead>
    <tr>
        <td>File name</td>
        <td>Size</td>
    </tr>
    </thead>
    <tr th:each="file : ${uploadedFiles}">
        <td th:text="${file.originalFilename}"/>
        <td th:text="${file.size}"/>
    </tr>
</table>
<form method="POST" action="confirm">
    <input type="submit" value="Confirm" name="confirm" id="confirm"/>
    <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
</form>
</body>
</html>

这是一个 Controller :

@Controller
public class IndexController {
    @RequestMapping("/")
    public String index(Model model, HttpSession httpSession) {
        List<MultipartFile> uploadedFiles = (List<MultipartFile>) httpSession.getAttribute("uploadedFiles");
        model.addAttribute("uploadedFiles", uploadedFiles);
        return "index";
    }

    @RequestMapping(value = "upload", method = RequestMethod.POST)
    public String index(@RequestParam("files") MultipartFile[] files, HttpSession httpSession) {
        List<MultipartFile> uploadedFiles = (List<MultipartFile>) httpSession.getAttribute("uploadedFiles");
        if (uploadedFiles != null) {
            uploadedFiles.addAll(Arrays.asList(files));
        } else {
            uploadedFiles = Arrays.asList(files);
        }
        httpSession.setAttribute("uploadedFiles", uploadedFiles);
        return "redirect:";
    }
}

最佳答案

经过一番调查,我发现只有当Tomcat处理请求时,临时目录中才存在MultipartFile。响应后立即删除文件。这就是大小为零的原因。可以使用自定义结构将此数据存储在内存中、数据库中或其他位置。

这是一个例子:

public class UploadedFile {
    private final String originalFilename;
    private final byte[] data;

    public UploadedFile(String fileName, byte[] data) {
        this.originalFilename = fileName;
        this.data = data.clone();
    }

    public String getOriginalFilename() {
        return originalFilename;
    }

    public byte[] getData() {
        return data.clone();
    }

    public int getSize() {
        return data.length;
    }
}

如果是内存存储,可以使用 MultipartFile 类。如果文件未存储在 HDD 上,只要您有引用,它就会存在于内存中。

以下是 application.properties 文件的示例:

multipart.file-size-threshold=10Mb
multipart.max-file-size=10Mb
multipart.max-request-size=10Mb

multipart.file-size-threshold 强制将所有上传的最大 10MB 的文件存储在内存中而不是 HDD 中。默认为0,所有文件都存储在HDD上。

我还发现使用 HttpSession 并不是一个明智的决定。 @SessionAttributes 注释与 Model 一起使这个解决方案变得相当清晰。

这是更新后的 Controller :

@Controller
@SessionAttributes(value = {"uploadedFiles"})
public class IndexController {
    @ModelAttribute("uploadedFiles")
    public List<UploadedFile> initUploadedFiles() {
        return new ArrayList<>();
    }

    @RequestMapping("/")
    public String index() {
        return "index";
    }

    @RequestMapping(value = "upload", method = RequestMethod.POST)
    public String index(Model model, @RequestParam MultipartFile[] files, @ModelAttribute("uploadedFiles") List<UploadedFile> uploadedFiles) {
        for (MultipartFile file : files) {
            try {
                uploadedFiles.add(new UploadedFile(file.getOriginalFilename(), file.getBytes()));
            } catch (IOException e) {
                throw new RuntimeException("Can't read file " + file.getOriginalFilename(), e);
            }
        }
        model.addAttribute("uploadedFiles", uploadedFiles);
        return "redirect:";
    }
}

关于spring - 在 HttpSession 中存储 MultipartFile,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34386350/

相关文章:

java - 我们可以编写自定义 Spring 事务管理器吗?

mysql - 为什么我的 Spring Batch 任务使用相同的 JOB_INSTANCE_ID 启动多个作业执行?

java - 我们可以为 .NET 应用程序调用使用 Spring REST 支持创建的 RESTful Web 服务吗?

java - Spring - 无法为返回 ByteArrayResource 的 API 发送错误消息

java - Spring MVC 匹配通配符严格错误

spring-boot - 同步调用多个api,spring boot webflux

java - 在 Spring Controller 中执行 jsp 并获取响应 html

java - 通过构造函数创建 bean 时出错 Bean 实例化失败

java - 当 spring-boot 运行时 IntelliJ 进程以退出代码 0 完成

java - Spring Boot 2 kerberos 身份验证