【问题标题】:Programmatic access to MultiPartConfig in Servlet 3.0以编程方式访问 Servlet 3.0 中的 MultiPartConfig
【发布时间】:2012-12-26 18:45:30
【问题描述】:

我使用 Servlet 3 @MultiPartConfig 注释在我的应用程序中实现文件上传。我需要在运行时设置 multipart-config 位置参数(不是注释参数中的硬编码)。是否有任何 API 用于以编程方式访问 servlet 的 multipart-config?

谢谢

【问题讨论】:

    标签: java jakarta-ee multipartform-data servlet-3.0


    【解决方案1】:

    @MultiPartConfig 实际上只是容器的标记接口。当 servlet 初始化时,提供的注释值通过代理对象映射到它。当传入的请求是 multipart/form-data 时,上传的部分将映射到请求,并且容器根据注释中的值和请求中的部分执行必要的工作。您无法拦截此过程,因为这一切都发生在容器的内部。但是,还有一种选择。它需要第二次执行文件系统操作。由于您拥有所有部分,因此您可以重建文件并将其“重新上传”到您选择的位置。它可能看起来像下面的方法。请记住,尽管我在自己的 servlet 中对此进行了快速测试以演示概念,但显然还没有完成代码:

    @Override
    protected void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
            throws ServletException, IOException {
    
        httpServletResponse.setContentType("text/html");
        PrintWriter printWriter = httpServletResponse.getWriter();
    
        InputStream inputStream;
        FileOutputStream fileOutputStream;
    
        for (Part part : httpServletRequest.getParts()) {
    
            inputStream = httpServletRequest.getPart(part.getName()).getInputStream();
            int i = inputStream.available();
            byte[] b = new byte[i];
            inputStream.read(b);
            String fileName = "";
    
            for (String temp : part.getHeader("content-disposition").split(";")) {
                if (temp.trim().startsWith("filename")) {
                    fileName = temp.substring(temp.indexOf('=') + 1).trim().replace("\"", "");
                }
            }
    
            String uploadDir = "/temp";
            fileOutputStream = new FileOutputStream(uploadDir + "/" + fileName);
            fileOutputStream.write(b);
            inputStream.close();
            fileOutputStream.close();
    
            printWriter.write("Uploaded file " + uploadDir + "/" + fileName + ".");
        }
    }
    

    【讨论】:

    • 如果您使用 @MultiPartConfig 并且需要运行时文件位置,那么您别无选择,只能“重新上传”这些部分。
    【解决方案2】:

    我也遇到了同样的问题,解决方案很简单:标准 Servlet 3.0 文件上传是不够的:只需从 Apache FileUpload Commons 获取 jar 即可完成

    看看这个带有 Streaming API 的清晰示例

       ServletFileUpload upload = new ServletFileUpload();
    
       // Parse the request
        FileItemIterator iter = upload.getItemIterator(request);
        while (iter.hasNext()) {
          FileItemStream item = iter.next();
          String name = item.getFieldName();
          InputStream stream = item.openStream();
          if ( item.isFormField() == false) 
              System.out.println("File field " + name + " with file name "
                + item.getName() + " detected."); 
              FileOutputStream fos = new FileOutputStream("your_location"); 
              Streams.copy ( stream,  fos, true);
    
           }
        }
    

    【讨论】:

    • 问题是关于@MultiPartConfig 和文件上传,你没有解决。您还从已在请求中的项目(上传到内存中)进行流式传输,这意味着您只是再次“重新上传”阅读它。
    • @Brian Reindel 情况并非如此,我不会再次“重新上传”,使用 Streaming API 我所做的是直接解析请求,没有临时文件或缓存在内存中。事实上,这就是 Streaming API 的优势:内存效率更高,处理速度更快,请查看commons.apache.org/proper/commons-fileupload/streaming.html
    • 假设你在一个 Servlet 中,并且使用一个容器,文件项是如何得到请求的?字节已经加载到内存中。在上传内容时,您不会实时流式传输内容。您是正确的,您的方法优于 FileUpload 是因为在这种情况下,必须首先将文件写入文件系统。我不同意必须在磁盘上管理两个文件是有问题的。但是,问题是专门针对 @MultiPartConfig 注释和文件的运行时位置,而不是一般的简单文件上传。
    • 我同意你的看法:'但是,问题是专门针对 @MultiPartConfig 注释和文件的运行时位置,而不仅仅是一般的文件上传',我只是想指出是一种更好的做事方式。当您说:“字节已加载到内存中”时,我不同意您的看法,请查看我发布的 Stream API 的链接。
    • 请不要将 Commons FileUpload 传统 API 与 Streaming API 混淆。
    猜你喜欢
    • 2014-06-07
    • 2011-09-05
    • 1970-01-01
    • 2019-03-13
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多