如何使用jsp/servlet将文件上传到服务器?

jjhzyzn0  于 2021-07-13  发布在  Java
关注(0)|答案(9)|浏览(418)

如何使用jsp/servlet将文件上传到服务器?我试过这个:

  1. <form action="upload" method="post">
  2. <input type="text" name="description" />
  3. <input type="file" name="file" />
  4. <input type="submit" />
  5. </form>

但是,我只得到文件名,而不是文件内容。当我加上 enctype="multipart/form-data"<form> ,那么 request.getParameter() 退货 null .
在研究过程中,我偶然发现了apache公共文件上传。我试过这个:

  1. FileItemFactory factory = new DiskFileItemFactory();
  2. ServletFileUpload upload = new ServletFileUpload(factory);
  3. List items = upload.parseRequest(request); // This line is where it died.

不幸的是,servlet抛出了一个没有明确消息和原因的异常。下面是stacktrace:

  1. SEVERE: Servlet.service() for servlet UploadServlet threw exception
  2. javax.servlet.ServletException: Servlet execution threw an exception
  3. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:313)
  4. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  5. at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
  6. at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
  7. at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
  8. at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
  9. at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
  10. at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
  11. at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
  12. at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
  13. at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
  14. at java.lang.Thread.run(Thread.java:637)
ia2d9nvy

ia2d9nvy1#

导言

要浏览并选择要上载的文件,您需要一个html <input type="file"> 窗体中的字段。如html规范所述,您必须使用 POST 方法和步骤 enctype 窗体的属性必须设置为 "multipart/form-data" .

  1. <form action="upload" method="post" enctype="multipart/form-data">
  2. <input type="text" name="description" />
  3. <input type="file" name="file" />
  4. <input type="submit" />
  5. </form>

提交这样的表单后,二进制多部分表单数据在请求主体中的格式与 enctype 未设置。
在Servlet3.0之前,ServletAPI本机不支持 multipart/form-data . 它只支持enctype的默认形式 application/x-www-form-urlencoded . 这个 request.getParameter() 所有的配偶都会回来 null 使用多部分表单数据时。这就是著名的apachecommons文件上传出现的地方。

不要手动解析!

理论上,您可以根据 ServletRequest#getInputStream() . 然而,这是一个精确和繁琐的工作,需要对rfc2388的准确知识。你不应该试着自己做这件事,或者复制粘贴一些在互联网上其他地方找到的没有库的代码。许多在线资源在这方面都失败了,比如roseindia.net。另请参见上载pdf文件。您更应该使用一个真正的库,它被使用(并且隐式地测试!)被数百万用户使用多年。这样一个库已经证明了它的健壮性。

当您已经使用Servlet3.0或更新版本时,请使用本机api

如果您至少使用Servlet3.0(Tomcat7、Jetty9、JBossas6、GlassFish3等),那么您可以使用提供的标准api HttpServletRequest#getPart() 收集单个的多部分表单数据项(大多数Servlet3.0实现实际上是在封面下使用ApacheCommonsFileUpload)。此外,标准格式字段也可以通过 getParameter() 通常的方式。
首先用 @MultipartConfig 为了让它认可和支持 multipart/form-data 请求,从而获得 getPart() 要工作:

  1. @WebServlet("/upload")
  2. @MultipartConfig
  3. public class UploadServlet extends HttpServlet {
  4. // ...
  5. }

然后,实施 doPost() 具体如下:

  1. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2. String description = request.getParameter("description"); // Retrieves <input type="text" name="description">
  3. Part filePart = request.getPart("file"); // Retrieves <input type="file" name="file">
  4. String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
  5. InputStream fileContent = filePart.getInputStream();
  6. // ... (do your job here)
  7. }

注意 Path#getFileName() . 这是一个关于获取文件名的msie修复程序。此浏览器错误地沿名称而不是仅沿文件名发送完整文件路径。
万一你有 <input type="file" name="file" multiple="true" /> 对于多文件上传,请按以下方式收集它们(不幸的是,没有如下方法) request.getParts("file") ):

  1. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2. // ...
  3. List<Part> fileParts = request.getParts().stream().filter(part -> "file".equals(part.getName()) && part.getSize() > 0).collect(Collectors.toList()); // Retrieves <input type="file" name="file" multiple="true">
  4. for (Part filePart : fileParts) {
  5. String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
  6. InputStream fileContent = filePart.getInputStream();
  7. // ... (do your job here)
  8. }
  9. }

当您还没有使用Servlet3.1时,请手动获取提交的文件名

请注意 Part#getSubmittedFileName() 在Servlet3.1中引入(Tomcat8、Jetty9、wildfly 8、glassfish 4等)。如果您还没有使用Servlet3.1,那么您需要一个额外的实用程序方法来获取提交的文件名。

  1. private static String getSubmittedFileName(Part part) {
  2. for (String cd : part.getHeader("content-disposition").split(";")) {
  3. if (cd.trim().startsWith("filename")) {
  4. String fileName = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
  5. return fileName.substring(fileName.lastIndexOf('/') + 1).substring(fileName.lastIndexOf('\\') + 1); // MSIE fix.
  6. }
  7. }
  8. return null;
  9. }
  1. String fileName = getSubmittedFileName(filePart);

注意msie修复程序获取文件名。此浏览器错误地沿名称而不是仅沿文件名发送完整文件路径。

如果您还没有使用Servlet3.0,请使用ApacheCommonsFileUpload

如果您还没有使用Servlet3.0(是不是该升级了?),通常的做法是使用ApacheCommonsFileUpload来解析multpart表单数据请求。它有一个很好的用户指南和常见问题解答(仔细阅读两者)。还有o'reilly(“cos”) MultipartRequest ,但它有一些(小)错误,多年来不再积极维护。我不建议用它。ApacheCommonsFileUpload仍在积极维护,目前非常成熟。
为了使用apachecommons fileupload,您的webapp中至少需要有以下文件 /WEB-INF/lib :
commons-fileupload.jar commons-io.jar 您最初的尝试很可能失败了,因为您忘记了commons io。
下面是一个启动示例 doPost() 你的 UploadServlet 使用apache commons fileupload时可能会出现以下情况:

  1. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  2. try {
  3. List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
  4. for (FileItem item : items) {
  5. if (item.isFormField()) {
  6. // Process regular form field (input type="text|radio|checkbox|etc", select, etc).
  7. String fieldName = item.getFieldName();
  8. String fieldValue = item.getString();
  9. // ... (do your job here)
  10. } else {
  11. // Process form file field (input type="file").
  12. String fieldName = item.getFieldName();
  13. String fileName = FilenameUtils.getName(item.getName());
  14. InputStream fileContent = item.getInputStream();
  15. // ... (do your job here)
  16. }
  17. }
  18. } catch (FileUploadException e) {
  19. throw new ServletException("Cannot parse multipart request.", e);
  20. }
  21. // ...
  22. }

重要的是你不要打电话 getParameter() , getParameterMap() , getParameterValues() , getInputStream() , getReader() 等的要求。否则servlet容器将读取并解析请求主体,因此apachecommonsfileupload将获得一个空的请求主体。另请参见a.o.servletfileupload#parserequest(request)返回空列表。
注意 FilenameUtils#getName() . 这是一个关于获取文件名的msie修复程序。此浏览器错误地沿名称而不是仅沿文件名发送完整文件路径。
或者,你也可以把这一切都 Package 在一个 Filter 它会自动解析所有内容,并将这些内容放回请求的parametermap中,以便您可以继续使用 request.getParameter() 通常的方式和检索上传的文件 request.getAttribute() . 你可以在这篇博客文章中找到一个例子。

getparameter()的glassfish3 bug仍返回null的解决方法

请注意,早于3.1.2的glassfish版本有一个bug,其中 getParameter() 仍然返回 null . 如果您的目标是这样一个容器,并且无法升级它,那么您需要从中提取值 getPart() 借助此实用方法:

  1. private static String getValue(Part part) throws IOException {
  2. BufferedReader reader = new BufferedReader(new InputStreamReader(part.getInputStream(), "UTF-8"));
  3. StringBuilder value = new StringBuilder();
  4. char[] buffer = new char[1024];
  5. for (int length = 0; (length = reader.read(buffer)) > 0;) {
  6. value.append(buffer, 0, length);
  7. }
  8. return value.toString();
  9. }
  1. String description = getValue(request.getPart("description")); // Retrieves <input type="text" name="description">

保存上传的文件(不要使用getrealpath()或part.write()!)

请参阅下面的答案,以了解有关正确保存所获取数据的详细信息 InputStream (the) fileContent 变量(如以上代码段所示)到磁盘或数据库:
在servlet应用程序中保存上载文件的推荐方法
如何上传图片并保存到数据库中?
如何将part转换成blob,这样我就可以在mysql中存储它了?

提供上载的文件

有关如何将保存的文件从磁盘或数据库返回到客户端的详细信息,请参阅以下答案:
使用<h:graphicimage>或标记从webapps/webcontext/deploy文件夹外部加载图像
如何在jsp页面中从数据库检索和显示图像?
在javaweb应用程序中从应用服务器外部提供静态数据的最简单方法
支持http缓存的静态资源servlet的抽象模板

将形式化

下面是如何使用ajax(和jquery)上传的答案。请注意,收集表单数据的servlet代码不需要为此更改!只有响应的方式可能会改变,但这相当简单(即,不转发到jsp,只需打印一些json或xml甚至纯文本,这取决于负责ajax调用的脚本所期望的内容)。
如何使用jsp/servlet和ajax将文件上传到服务器?
通过xmlhttprequest以多部分形式发送文件
html5文件上传到java servlet
希望这些都有用:)

展开查看全部
b1payxdu

b1payxdu2#

如果您碰巧使用了springmvc,那么下面是:(我把这个放在这里,以防有人发现它有用)。
使用带有 enctype 属性设置为“ multipart/form-data “(与巴卢斯克的回答相同)

  1. <form action="upload" method="post" enctype="multipart/form-data">
  2. <input type="file" name="file" />
  3. <input type="submit" value="Upload"/>
  4. </form>

在控制器中,Map请求参数 fileMultipartFile 类型如下:

  1. @RequestMapping(value = "/upload", method = RequestMethod.POST)
  2. public void handleUpload(@RequestParam("file") MultipartFile file) throws IOException {
  3. if (!file.isEmpty()) {
  4. byte[] bytes = file.getBytes(); // alternatively, file.getInputStream();
  5. // application logic
  6. }
  7. }

您可以使用 MultipartFilegetOriginalFilename() 以及 getSize() .
我已经用spring版本测试过了 4.1.1.RELEASE .

展开查看全部
mzmfm0qo

mzmfm0qo3#

在tomcat6o7中没有组件或外部库
在web.xml文件中启用上载:
http://joseluisbz.wordpress.com/2014/01/17/manually-installing-php-tomcat-and-httpd-lounge/#enabling%20文件%20上传。

  1. <servlet>
  2. <servlet-name>jsp</servlet-name>
  3. <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
  4. <multipart-config>
  5. <max-file-size>3145728</max-file-size>
  6. <max-request-size>5242880</max-request-size>
  7. </multipart-config>
  8. <init-param>
  9. <param-name>fork</param-name>
  10. <param-value>false</param-value>
  11. </init-param>
  12. <init-param>
  13. <param-name>xpoweredBy</param-name>
  14. <param-value>false</param-value>
  15. </init-param>
  16. <load-on-startup>3</load-on-startup>
  17. </servlet>

如你所见:

  1. <multipart-config>
  2. <max-file-size>3145728</max-file-size>
  3. <max-request-size>5242880</max-request-size>
  4. </multipart-config>

使用jsp上传文件。文件夹:
在html文件中

  1. <form method="post" enctype="multipart/form-data" name="Form" >
  2. <input type="file" name="fFoto" id="fFoto" value="" /></td>
  3. <input type="file" name="fResumen" id="fResumen" value=""/>

在jsp文件或servlet中

  1. InputStream isFoto = request.getPart("fFoto").getInputStream();
  2. InputStream isResu = request.getPart("fResumen").getInputStream();
  3. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  4. byte buf[] = new byte[8192];
  5. int qt = 0;
  6. while ((qt = isResu.read(buf)) != -1) {
  7. baos.write(buf, 0, qt);
  8. }
  9. String sResumen = baos.toString();

根据servlet要求编辑代码,比如最大文件大小、最大请求大小和其他可以设置的选项。。。

展开查看全部
r7xajy2e

r7xajy2e4#

你需要 common-io.1.4.jar 要包含在您的 lib 目录,或者如果您在任何编辑器中工作,比如netbeans,那么您需要转到项目属性,只需添加jar文件就可以了。
为了得到 common.io.jar 文件只需google一下,或者直接访问apachetomcat网站,在那里你可以免费下载这个文件。但请记住一件事:如果您是windows用户,请下载二进制zip文件。

7gs2gvoe

7gs2gvoe5#

我对每个html表单使用公共servlet,不管它是否有附件。此servlet返回 TreeMap 其中键是jsp名称参数,值是用户输入,并将所有附件保存在固定目录中,然后您可以重命名您选择的目录。我想这对你有帮助

  1. public class ServletCommonfunctions extends HttpServlet implements
  2. Connections {
  3. private static final long serialVersionUID = 1L;
  4. public ServletCommonfunctions() {}
  5. protected void doPost(HttpServletRequest request,
  6. HttpServletResponse response) throws ServletException,
  7. IOException {}
  8. public SortedMap<String, String> savefilesindirectory(
  9. HttpServletRequest request, HttpServletResponse response)
  10. throws IOException {
  11. // Map<String, String> key_values = Collections.synchronizedMap( new
  12. // TreeMap<String, String>());
  13. SortedMap<String, String> key_values = new TreeMap<String, String>();
  14. String dist = null, fact = null;
  15. PrintWriter out = response.getWriter();
  16. File file;
  17. String filePath = "E:\\FSPATH1\\2KL06CS048\\";
  18. System.out.println("Directory Created ????????????"
  19. + new File(filePath).mkdir());
  20. int maxFileSize = 5000 * 1024;
  21. int maxMemSize = 5000 * 1024;
  22. // Verify the content type
  23. String contentType = request.getContentType();
  24. if ((contentType.indexOf("multipart/form-data") >= 0)) {
  25. DiskFileItemFactory factory = new DiskFileItemFactory();
  26. // maximum size that will be stored in memory
  27. factory.setSizeThreshold(maxMemSize);
  28. // Location to save data that is larger than maxMemSize.
  29. factory.setRepository(new File(filePath));
  30. // Create a new file upload handler
  31. ServletFileUpload upload = new ServletFileUpload(factory);
  32. // maximum file size to be uploaded.
  33. upload.setSizeMax(maxFileSize);
  34. try {
  35. // Parse the request to get file items.
  36. @SuppressWarnings("unchecked")
  37. List<FileItem> fileItems = upload.parseRequest(request);
  38. // Process the uploaded file items
  39. Iterator<FileItem> i = fileItems.iterator();
  40. while (i.hasNext()) {
  41. FileItem fi = (FileItem) i.next();
  42. if (!fi.isFormField()) {
  43. // Get the uploaded file parameters
  44. String fileName = fi.getName();
  45. // Write the file
  46. if (fileName.lastIndexOf("\\") >= 0) {
  47. file = new File(filePath
  48. + fileName.substring(fileName
  49. .lastIndexOf("\\")));
  50. } else {
  51. file = new File(filePath
  52. + fileName.substring(fileName
  53. .lastIndexOf("\\") + 1));
  54. }
  55. fi.write(file);
  56. } else {
  57. key_values.put(fi.getFieldName(), fi.getString());
  58. }
  59. }
  60. } catch (Exception ex) {
  61. System.out.println(ex);
  62. }
  63. }
  64. return key_values;
  65. }
  66. }
展开查看全部
dxxyhpgq

dxxyhpgq6#

对于springmvc,我已经尝试了几个小时来实现这一点,并设法得到了一个更简单的版本,用于获取表单输入数据和图像。

  1. <form action="/handleform" method="post" enctype="multipart/form-data">
  2. <input type="text" name="name" />
  3. <input type="text" name="age" />
  4. <input type="file" name="file" />
  5. <input type="submit" />
  6. </form>

要处理的控制器

  1. @Controller
  2. public class FormController {
  3. @RequestMapping(value="/handleform",method= RequestMethod.POST)
  4. ModelAndView register(@RequestParam String name, @RequestParam int age, @RequestParam MultipartFile file)
  5. throws ServletException, IOException {
  6. System.out.println(name);
  7. System.out.println(age);
  8. if(!file.isEmpty()){
  9. byte[] bytes = file.getBytes();
  10. String filename = file.getOriginalFilename();
  11. BufferedOutputStream stream =new BufferedOutputStream(new FileOutputStream(new File("D:/" + filename)));
  12. stream.write(bytes);
  13. stream.flush();
  14. stream.close();
  15. }
  16. return new ModelAndView("index");
  17. }
  18. }

希望有帮助:)

展开查看全部
zdwk9cvp

zdwk9cvp7#

如果您将geronimo与其嵌入的tomcat一起使用,则会出现此问题的另一个根源。在这种情况下,在多次迭代测试commons io和commons fileupload之后,问题来自处理commons jar的父类加载器。这是必须防止的。车祸总是发生在:

  1. fileItems = uploader.parseRequest(request);

请注意,fileitems的列表类型已随commons fileupload的当前版本而更改,具体如下: List<FileItem> 与以前的通用版本不同 List .
我将commons fileupload和commons io的源代码添加到我的eclipse项目中,以跟踪实际错误,并最终获得一些见解。首先,抛出的异常是throwable类型,不是声明的fileioexception,甚至不是exception(这些异常不会被捕获)。其次,错误消息是模糊的,因为它声明类找不到,因为axis2找不到commons io。axis2根本不在我的项目中使用,而是作为标准安装的一部分作为geronimo存储库子目录中的文件夹存在。
最后,我找到了一个地方,提出了一个有效的解决方案,成功地解决了我的问题。必须对部署计划中的父加载程序隐藏jar。这被放入geronimo-web.xml中,我的完整文件如下所示。

  1. Pasted from <http://osdir.com/ml/user-geronimo-apache/2011-03/msg00026.html>
  2. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  3. <web:web-app xmlns:app="http://geronimo.apache.org/xml/ns/j2ee/application-2.0" xmlns:client="http://geronimo.apache.org/xml/ns/j2ee/application-client-2.0" xmlns:conn="http://geronimo.apache.org/xml/ns/j2ee/connector-1.2" xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2" xmlns:ejb="http://openejb.apache.org/xml/ns/openejb-jar-2.2" xmlns:log="http://geronimo.apache.org/xml/ns/loginconfig-2.0" xmlns:name="http://geronimo.apache.org/xml/ns/naming-1.2" xmlns:pers="http://java.sun.com/xml/ns/persistence" xmlns:pkgen="http://openejb.apache.org/xml/ns/pkgen-2.1" xmlns:sec="http://geronimo.apache.org/xml/ns/security-2.0" xmlns:web="http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1">
  4. <dep:environment>
  5. <dep:moduleId>
  6. <dep:groupId>DataStar</dep:groupId>
  7. <dep:artifactId>DataStar</dep:artifactId>
  8. <dep:version>1.0</dep:version>
  9. <dep:type>car</dep:type>
  10. </dep:moduleId>
  11. <!--Don't load commons-io or fileupload from parent classloaders-->
  12. <dep:hidden-classes>
  13. <dep:filter>org.apache.commons.io</dep:filter>
  14. <dep:filter>org.apache.commons.fileupload</dep:filter>
  15. </dep:hidden-classes>
  16. <dep:inverse-classloading/>
  17. </dep:environment>
  18. <web:context-root>/DataStar</web:context-root>
  19. </web:web-app>
展开查看全部
de90aj5v

de90aj5v8#

下面是一个使用apache commons fileupload的示例:

  1. // apache commons-fileupload to handle file upload
  2. DiskFileItemFactory factory = new DiskFileItemFactory();
  3. factory.setRepository(new File(DataSources.TORRENTS_DIR()));
  4. ServletFileUpload fileUpload = new ServletFileUpload(factory);
  5. List<FileItem> items = fileUpload.parseRequest(req.raw());
  6. FileItem item = items.stream()
  7. .filter(e ->
  8. "the_upload_name".equals(e.getFieldName()))
  9. .findFirst().get();
  10. String fileName = item.getName();
  11. item.write(new File(dir, fileName));
  12. log.info(fileName);
l7wslrjt

l7wslrjt9#

首先必须设置的enctype属性

相关问题