【问题标题】:spark java: how to handle multipart/form-data input?spark java:如何处理多部分/表单数据输入?
【发布时间】:2015-06-05 01:51:35
【问题描述】:

我正在使用spark 开发一个网络应用程序;当我要上传文件时出现问题:

public final class SparkTesting
{
    public static void main(final String... args)
    {
        Spark.staticFileLocation("/site");

        Spark.port(8080);

        Spark.post("/upload", (request, response) -> {
            final Part uploadedFile = request.raw().getPart("uploadedFile");
            final Path path = Paths.get("/tmp/meh");
            try (final InputStream in = uploadedFile.getInputStream()) {
                Files.copy(in, path);
            }

            response.redirect("/");
            return "OK";
        });
    }
}

但我收到此错误:

[qtp509057984-36] ERROR spark.webserver.MatcherFilter - 
java.lang.IllegalStateException: No multipart config for servlet
    at org.eclipse.jetty.server.Request.getPart(Request.java:2039)
    at javax.servlet.http.HttpServletRequestWrapper.getPart(HttpServletRequestWrapper.java:361)
    at com.github.fge.grappa.debugger.web.SparkTesting.lambda$main$0(SparkTesting.java:20)
    at com.github.fge.grappa.debugger.web.SparkTesting$$Lambda$1/920011586.handle(Unknown Source)
    at spark.SparkBase$1.handle(SparkBase.java:264)
    at spark.webserver.MatcherFilter.doFilter(MatcherFilter.java:154)
    at spark.webserver.JettyHandler.doHandle(JettyHandler.java:60)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:179)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:136)
    at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:52)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
    at org.eclipse.jetty.server.Server.handle(Server.java:451)
    at org.eclipse.jetty.server.HttpChannel.run(HttpChannel.java:252)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:266)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.run(AbstractConnection.java:240)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:596)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:527)
    at java.lang.Thread.run(Thread.java:745)

即使我尝试明确指定类型,如下所示:

Spark.post("/upload", "multipart/form-data", etc etc)

它仍然会失败。

我可能会找到一个库来解析 multipart/form-data,获取整个内容并自己解析,但那将是一种浪费。

我可以配置 spark 来处理这种情况吗?

【问题讨论】:

    标签: java jetty spark-java


    【解决方案1】:

    我在这里找到了完整的例子: https://github.com/tipsy/spark-file-upload/blob/master/src/main/java/UploadExample.java

    import spark.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.*;
    import java.nio.file.*;
    import static spark.Spark.*;
    import static spark.debug.DebugScreen.*;
    
    public class UploadExample {
    
        public static void main(String[] args) {
            enableDebugScreen();
    
            File uploadDir = new File("upload");
            uploadDir.mkdir(); // create the upload directory if it doesn't exist
    
            staticFiles.externalLocation("upload");
    
            get("/", (req, res) ->
                      "<form method='post' enctype='multipart/form-data'>" // note the enctype
                    + "    <input type='file' name='uploaded_file' accept='.png'>" // make sure to call getPart using the same "name" in the post
                    + "    <button>Upload picture</button>"
                    + "</form>"
            );
    
            post("/", (req, res) -> {
    
                Path tempFile = Files.createTempFile(uploadDir.toPath(), "", "");
    
                req.attribute("org.eclipse.jetty.multipartConfig", new MultipartConfigElement("/temp"));
    
                try (InputStream input = req.raw().getPart("uploaded_file").getInputStream()) { // getPart needs to use same "name" as input field in form
                    Files.copy(input, tempFile, StandardCopyOption.REPLACE_EXISTING);
                }
    
                logInfo(req, tempFile);
                return "<h1>You uploaded this image:<h1><img src='" + tempFile.getFileName() + "'>";
    
            });
    
        }
    
        // methods used for logging
        private static void logInfo(Request req, Path tempFile) throws IOException, ServletException {
            System.out.println("Uploaded file '" + getFileName(req.raw().getPart("uploaded_file")) + "' saved as '" + tempFile.toAbsolutePath() + "'");
        }
    
        private static String getFileName(Part part) {
            for (String cd : part.getHeader("content-disposition").split(";")) {
                if (cd.trim().startsWith("filename")) {
                    return cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
                }
            }
            return null;
        }
    
    }
    

    请注意,在此示例中,为了遍历所有文件,请使用 javax.servlet.http.HttpServletRequest#getParts。同样在此示例中,您可以使用javax.servlet.http.Part#getSubmittedFileName 简单地获取它,而不是解析文件名。并且不要忘记关闭您获得的流。如果需要,还可以使用javax.servlet.http.Part#delete 删除文件

    【讨论】:

      【解决方案2】:

      凯耀提供的答案是正确的,除了使用时:

      request.raw().setAttribute("org.eclipse.multipartConfig", multipartConfigElement);
      

      改用这个:

      request.raw().setAttribute("org.eclipse.jetty.multipartConfig", multipartConfigElement);
      

      【讨论】:

        【解决方案3】:

        我使用 apache commons-fileupload 来处理这个问题。

        post("/upload", (req, res) -> {
        final File upload = new File("upload");
        if (!upload.exists() && !upload.mkdirs()) {
            throw new RuntimeException("Failed to create directory " + upload.getAbsolutePath());
        }
        
        // apache commons-fileupload to handle file upload
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setRepository(upload);
        ServletFileUpload fileUpload = new ServletFileUpload(factory);
        List<FileItem> items = fileUpload.parseRequest(req.raw());
        
        // image is the field name that we want to save
        FileItem item = items.stream()
                        .filter(e -> "image".equals(e.getFieldName()))
                        .findFirst().get();
        String fileName = item.getName();
        item.write(new File(dir, fileName));
        halt(200);
        return null;
        });
        

        https://github.com/perwendel/spark/issues/26#issuecomment-95077039

        【讨论】:

          【解决方案4】:

          通过添加几行代码来添加多部分配置,您可以在没有外部库的情况下处理多部分/表单数据:

          public Object handle(Request request, Response response) {
              MultipartConfigElement multipartConfigElement = new MultipartConfigElement("/tmp");
              request.raw().setAttribute("org.eclipse.multipartConfig", multipartConfigElement);
              ....
              Part file = request.raw().getPart("file"); //file is name of the upload form
          }
          

          来源:http://deniz.dizman.org/file-uploads-using-spark-java-micro-framework/

          【讨论】:

          • 如何将此类图片上传到 src/main/resources 中,我可以访问它?
          猜你喜欢
          • 2012-11-17
          • 1970-01-01
          • 2010-11-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-02-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多