HTML5拖放文件上传到Java Servlet

23

我目前使用Uploadify(Flash + Ajax)成功地将文件上传到Servlet(使用OWASP ESAPI覆盖的Commons Upload),但我想知道如何构建HTML5支持,或者更准确地说是带有Flash支持的HTML5。

我知道如何让HTML5拖放起作用,但我无法完全弄清Java Servlet连接和/或后端的机制。

2个回答

48
我知道如何让HTML5 DnD工作,但我无法完全理解Java Servlet连接和/或后端的机制。
这与使用常规的<form enctype="multipart/form-data">没有区别。你只需要让HTML5 / JS代码发送一个带有拖放文件的multipart/form-data请求,这与使用常规的<input type="file">字段发送的请求完全相同。我假设你只是不知道如何使用HTML5 / JS实现这一点。
你可以利用新的HTML5 File API,XHR2 FormDataXMLHttpRequestUpload API来实现此目的。
下面是一个示例,展示了你的drop事件处理程序应该是什么样子:
function dropUpload(event) {
    event.stopPropagation();
    event.preventDefault();

    var formData = new FormData();
    formData.append("file", event.dataTransfer.files[0]);

    var xhr = new XMLHttpRequest();
    xhr.open("POST", "uploadServlet");
    xhr.send(formData);
}

就是这样。此示例假定servlet映射在URL模式/uploadServlet上。在此示例中,文件以通常的方式作为具有字段名fileFileItem实例在Apache Commons FileUpload中可用。


如果您想了解更高级的内容,例如附加事件处理程序以监视进度等,请查看以下博客:

我已经使用以下SSCCE进行了一些测试:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>HTML5 drag'n'drop file upload with Servlet</title>
        <script>
            window.onload = function() {
                var dropbox = document.getElementById("dropbox");
                dropbox.addEventListener("dragenter", noop, false);
                dropbox.addEventListener("dragexit", noop, false);
                dropbox.addEventListener("dragover", noop, false);
                dropbox.addEventListener("drop", dropUpload, false);
            }

            function noop(event) {
                event.stopPropagation();
                event.preventDefault();
            }

            function dropUpload(event) {
                noop(event);
                var files = event.dataTransfer.files;

                for (var i = 0; i < files.length; i++) {
                    upload(files[i]);
                }
            }

            function upload(file) {
                document.getElementById("status").innerHTML = "Uploading " + file.name;

                var formData = new FormData();
                formData.append("file", file);

                var xhr = new XMLHttpRequest();
                xhr.upload.addEventListener("progress", uploadProgress, false);
                xhr.addEventListener("load", uploadComplete, false);
                xhr.open("POST", "uploadServlet", true); // If async=false, then you'll miss progress bar support.
                xhr.send(formData);
            }

            function uploadProgress(event) {
                // Note: doesn't work with async=false.
                var progress = Math.round(event.loaded / event.total * 100);
                document.getElementById("status").innerHTML = "Progress " + progress + "%";
            }

            function uploadComplete(event) {
                document.getElementById("status").innerHTML = event.target.responseText;
            }
        </script>
        <style>
            #dropbox {
                width: 300px;
                height: 200px;
                border: 1px solid gray;
                border-radius: 5px;
                padding: 5px;
                color: gray;
            }
        </style>
    </head>
    <body>
        <div id="dropbox">Drag and drop a file here...</div>
        <div id="status"></div>
    </body>
</html>

并且这个UploadServlet利用了新的Servlet 3.0 HttpServletRequest#getPart() API:

@MultipartConfig
@WebServlet("/uploadServlet")
public class UploadServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Part file = request.getPart("file");
        String filename = getFilename(file);
        InputStream filecontent = file.getInputStream();
        // ... Do your file saving job here.

        response.setContentType("text/plain");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write("File " + filename + " successfully uploaded");
    }

    private static String getFilename(Part part) {
        for (String cd : part.getHeader("content-disposition").split(";")) {
            if (cd.trim().startsWith("filename")) {
                String filename = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
                return filename.substring(filename.lastIndexOf('/') + 1).substring(filename.lastIndexOf('\\') + 1); // MSIE fix.
            }
        }
        return null;
    }
}

参见:


嘿,BalusC,感谢您的回答和奖励,但是您知道是否有一种方法可以使用新的HTML5文件API排队文件吗?我可以关闭自动上传,但似乎找不到一种从jquery动态排队文件并启动上传的方法...再次感谢。 - oberger
SSCCE 假设只有单个文件上传。将 if 检查替换为对 filesfor 循环。调用 xhr.open() 时,将第三个参数(async)设置为 false。它将同步运行。您只会错过进度条支持。我已编辑了示例。至于 jQuery,据我所知,它还没有 XHR2 支持。毕竟它只是 JavaScript,我不明白为什么上面的示例应该在 jQuery 中完成。也许元素选择器,但不包括其他任何内容。可能已经有 jQuery 插件支持新的 XHR2。 - BalusC
我该如何添加自定义变量到上传中?(我需要这个来验证用户是否已登录) - Thariama
这个很好用。不过,我正在为每个上传的文件使用不同的进度条(多个“状态”)。有没有办法告诉“uploadProgress()”更新哪个DOM元素(哪个“状态”)? - user1156544
这个链接很有帮助:https://dev59.com/DVnUa4cB1Zd3GeqPZVbw 但是我不喜欢内联函数。 - user1156544
显示剩余2条评论

-1

您需要多部分配置,例如:

@MultipartConfig(fileSizeThreshold = 1024 * 1024, 
                 maxFileSize = 1024 * 1024 * 5, 
                 maxRequestSize = 1024 * 1024 * 5 * 5)

在我的情况下,它只能使用这个配置工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接