在Servlet中解析传入的multipart/form-data参数的便捷方式

68

有没有方便的方法可以从传入的请求中读取和解析数据。

例如,客户端发起POST请求。

URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
PrintWriter writer = null;
try {
    OutputStream output = connection.getOutputStream();
    writer = new PrintWriter(new OutputStreamWriter(output, charset), true); // true = autoFlush, important!
    // Send normal param.
    writer.println("--" + boundary);
    writer.println("Content-Disposition: form-data; name=\"param\"");
    writer.println("Content-Type: text/plain; charset=" + charset);
    writer.println();
    writer.println(param);

我无法使用request.getParameter("paramName") 获取参数。以下是代码:

BufferedReader reader = new BufferedReader(new InputStreamReader(
    request.getInputStream()));
  StringBuilder sb = new StringBuilder();
  for (String line; (line = reader.readLine()) != null;) {
   System.out.println(line);

  }

然而,对我来说显示了内容

-----------------------------29772313742745
Content-Disposition: form-data; name="name"
J.Doe
-----------------------------29772313742745
Content-Disposition: form-data; name="email"
abuse@spamcop.com
-----------------------------29772313742745

什么是解析传入请求的最佳方法?我不想编写自己的解析器,可能有现成的解决方案。

3个回答

83

multipart/form-data编码的请求在Servlet API 3.0版本之前默认不受支持。Servlet API默认使用application/x-www-form-urlencoded编码解析参数。当使用不同的编码时,request.getParameter()调用将返回null。如果您已经使用Servlet 3.0或更新版本(Glassfish 3, Tomcat 7, WildFly等,自2009年12月以来已经推出),则可以改用HttpServletRequest#getPart()。您可以在如何使用JSP/Servlet上传文件到服务器?中找到详细的示例。

在Servlet 3.0之前,解析multipart/form-data请求的事实上标准是使用Apache Commons FileUpload。你可能会在互联网上找到很多使用这个库的答案和代码示例,但是这已经不再需要超过10年了。现在只需使用标准的request.getPart(name)方法即可。

1
小心。Apache 网站上的一些文档是错误的。例如,他们说您可以在 FileItemFactory 对象上调用 setRepository(),但实际上任何实现 FileItemFactory 的对象都只有一个方法:createItem()。因此,请确保您也阅读了 javadocs。 - Cheruvim
2
getParts() 总是返回零项。为什么在 Java 和 Servlet 3.0 中检索多部分表单如此困难?简直不敢相信! - basZero
@basZero:重复问题的答案已经解释了什么情况下它会为空。 - BalusC
@BalusC,你有链接吗?这个页面上有很多信息。 - basZero

16

解决方案:

解决方案A:

  1. 下载 http://www.servlets.com/cos/index.html
  2. com.oreilly.servlet.MultipartRequest 上调用 getParameters()

解决方案B:

  1. 下载 http://jakarta.Apache.org/commons/fileupload/
  2. org.apache.commons.fileupload.MultipartStream 上调用 readHeaders()

解决方案C:

  1. 下载 http://users.boone.net/wbrameld/multipartformdata/
  2. 在 com.bigfoot.bugar.servlet.http.MultipartFormData 上调用 getParameter

解决方案D:

使用 Struts。Struts 1.1 自动处理此问题。

参考:http://www.jguru.com/faq/view.jsp?EID=1045507


9
请提供一些解决方案,因为这些链接可能在未来的任何时间都会过时。这将会招致负面评价。 - Jafar Ali

7

并不总是在上传之前都会有一个servlet(例如,我可以使用过滤器)。或者可能是同一个控制器(再次是过滤器或也可以是servlet)可以服务于许多操作,所以我认为依靠servlet配置来使用getPart方法(仅适用于Servlet API>= 3.0),我不知道,我不喜欢。

总的来说,我更喜欢独立的解决方案,能够独立存在,在这种情况下http://commons.apache.org/proper/commons-fileupload/就是其中之一。

List<FileItem> multiparts = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
    for (FileItem item : multiparts) {
        if (!item.isFormField()) {
            //your operations on file
        } else {
            String name = item.getFieldName();
            String value = item.getString();
            //you operations on paramters
        }
}

它只在有请求对象时才能工作。但是对于流对象或任何其他对象数据呢? - Ak S
流或任何其他对象数据将替换请求。因此,我将解析/读取流或任何其他对象以获取多部分表单数据。不管怎样,您有任何真实的例子吗? - Luca Rasconi

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