spark java:如何处理多部分/表单数据输入?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29373468/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 15:08:15  来源:igfitidea点击:

spark java: how to handle multipart/form-data input?

javajettyspark-java

提问by fge

I am using sparkto develop a web application; the problem occurs when I want to upload a file:

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

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

But I get this error:

但我收到此错误:

[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
Spark.post("/upload", "multipart/form-data", etc etc)
(SparkTesting.java:20) at com.github.fge.grappa.debugger.web.SparkTesting$$Lambda/920011586.handle(Unknown Source) at spark.SparkBase.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.run(QueuedThreadPool.java:527) at java.lang.Thread.run(Thread.java:745)

And even if I try and specify the type explicitly, as in:

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

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

it will still fail.

它仍然会失败。

I could probably find a library to parse multipart/form-data, grab the whole content and just parse myself, but that'd be a waste.

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

Can I configure spark to handle that case?

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

回答by HaiderAgha

The answer provided by Kai Yao is correct except that when using:

姚凯提供的答案是正确的,只是在使用时:

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

use this instead:

改用这个:

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
}

回答by Kai Yao

By adding a few lines of code to add the multipart config, you can handle multipart/form-data without an external library:

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

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

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

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

回答by shauvik

I used apache commons-fileupload to handle this.

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

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

}

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

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

回答by alex.b

I found complete example here: https://github.com/tipsy/spark-file-upload/blob/master/src/main/java/UploadExample.java

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

##代码##

Please note that in this example in order to iterate over all files use javax.servlet.http.HttpServletRequest#getParts. Also in this example instead of parsing file name you can simply get it using javax.servlet.http.Part#getSubmittedFileName. And also do not forget to close the stream you get. And also delete the file using javax.servlet.http.Part#deleteif needed

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