如何使用JSP/Servlet上传文件到服务器?
我试了一下:
<form action="upload" method="post">
<input type="text" name="description" />
<input type="file" name="file" />
<input type="submit" />
</form>
但是,我只得到了文件名,而不是文件内容。当我添加enctype="multipart/form-data"到<form>时,request.getParameter()返回null。
在研究过程中,我偶然发现了Apache Common FileUpload。我试了一下:
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List items = upload.parseRequest(request); // This line is where it died.
不幸的是,servlet抛出了一个异常,没有明确的消息和原因。下面是stacktrace:
SEVERE: Servlet.service() for servlet UploadServlet threw exception
javax.servlet.ServletException: Servlet execution threw an exception
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:313)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:637)
如果您使用Geronimo及其嵌入式Tomcat,则会出现此问题的另一个来源。在本例中,经过多次测试Commons IO和Commons -fileupload后,问题产生于处理Commons -xxx JAR文件的父类加载器。这种情况必须加以防止。坠机通常发生在:
fileItems = uploader.parseRequest(request);
请注意,fileItems的List类型已经随着common -fileupload的当前版本而改变,具体为List<FileItem>,而不是以前的版本,它是一般的List。
I added the source code for commons-fileupload and Commons IO into my Eclipse project to trace the actual error and finally got some insight. First, the exception thrown is of type Throwable not the stated FileIOException nor even Exception (these will not be trapped). Second, the error message is obfuscatory in that it stated class not found because axis2 could not find commons-io. Axis2 is not used in my project at all, but it exists as a folder in the Geronimo repository subdirectory as part of standard installation.
最后,我找到了一个地方,提出了一个有效的解决方案,成功地解决了我的问题。您必须将JAR文件隐藏在部署计划中的父加载器中。它被放入geronimo-web.xml文件中,我的完整文件如下所示。
粘贴自http://osdir.com/ml/user-geronimo-apache/2011-03/msg00026.html:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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">
<dep:environment>
<dep:moduleId>
<dep:groupId>DataStar</dep:groupId>
<dep:artifactId>DataStar</dep:artifactId>
<dep:version>1.0</dep:version>
<dep:type>car</dep:type>
</dep:moduleId>
<!-- Don't load commons-io or fileupload from parent classloaders -->
<dep:hidden-classes>
<dep:filter>org.apache.commons.io</dep:filter>
<dep:filter>org.apache.commons.fileupload</dep:filter>
</dep:hidden-classes>
<dep:inverse-classloading/>
</dep:environment>
<web:context-root>/DataStar</web:context-root>
</web:web-app>
如果你碰巧使用Spring MVC,这是如何(我把它留在这里,以防有人发现它有用):
使用一个enctype属性设置为"multipart/form-data"的表单(与BalusC的答案相同):
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="Upload"/>
</form>
在控制器中,将请求参数文件映射为MultipartFile类型,如下所示:
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public void handleUpload(@RequestParam("file") MultipartFile file) throws IOException {
if (!file.isEmpty()) {
byte[] bytes = file.getBytes(); // alternatively, file.getInputStream();
// application logic
}
}
你可以使用MultipartFile的getOriginalFilename()和getSize()来获取文件名和大小。
我已经用Spring版本4.1.1.RELEASE测试了这个功能。
您可以使用JSP /servlet上传文件。
<form action="UploadFileServlet" method="post">
<input type="text" name="description" />
<input type="file" name="file" />
<input type="submit" />
</form>
另一方面,在服务器端,使用以下代码。
package com.abc..servlet;
import java.io.File;
---------
--------
/**
* Servlet implementation class UploadFileServlet
*/
public class UploadFileServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public UploadFileServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.sendRedirect("../jsp/ErrorPage.jsp");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
PrintWriter out = response.getWriter();
HttpSession httpSession = request.getSession();
String filePathUpload = (String) httpSession.getAttribute("path") != null ? httpSession.getAttribute("path").toString() : "" ;
String path1 = filePathUpload;
String filename = null;
File path = null;
FileItem item = null;
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
String FieldName = "";
try {
List items = upload.parseRequest(request);
Iterator iterator = items.iterator();
while (iterator.hasNext()) {
item = (FileItem) iterator.next();
if (fieldname.equals("description")) {
description = item.getString();
}
}
if (!item.isFormField()) {
filename = item.getName();
path = new File(path1 + File.separator);
if (!path.exists()) {
boolean status = path.mkdirs();
}
/* Start of code fro privilege */
File uploadedFile = new File(path + Filename); // for copy file
item.write(uploadedFile);
}
} else {
f1 = item.getName();
}
} // END OF WHILE
response.sendRedirect("welcome.jsp");
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
对于Spring MVC
我设法有一个更简单的版本,用于获取表单输入,包括数据和图像。
<form action="/handleform" method="post" enctype="multipart/form-data">
<input type="text" name="name" />
<input type="text" name="age" />
<input type="file" name="file" />
<input type="submit" />
</form>
要处理的控制器
@Controller
public class FormController {
@RequestMapping(value="/handleform",method= RequestMethod.POST)
ModelAndView register(@RequestParam String name, @RequestParam int age, @RequestParam MultipartFile file)
throws ServletException, IOException {
System.out.println(name);
System.out.println(age);
if(!file.isEmpty()){
byte[] bytes = file.getBytes();
String filename = file.getOriginalFilename();
BufferedOutputStream stream =new BufferedOutputStream(new FileOutputStream(new File("D:/" + filename)));
stream.write(bytes);
stream.flush();
stream.close();
}
return new ModelAndView("index");
}
}
如果您使用Geronimo及其嵌入式Tomcat,则会出现此问题的另一个来源。在本例中,经过多次测试Commons IO和Commons -fileupload后,问题产生于处理Commons -xxx JAR文件的父类加载器。这种情况必须加以防止。坠机通常发生在:
fileItems = uploader.parseRequest(request);
请注意,fileItems的List类型已经随着common -fileupload的当前版本而改变,具体为List<FileItem>,而不是以前的版本,它是一般的List。
I added the source code for commons-fileupload and Commons IO into my Eclipse project to trace the actual error and finally got some insight. First, the exception thrown is of type Throwable not the stated FileIOException nor even Exception (these will not be trapped). Second, the error message is obfuscatory in that it stated class not found because axis2 could not find commons-io. Axis2 is not used in my project at all, but it exists as a folder in the Geronimo repository subdirectory as part of standard installation.
最后,我找到了一个地方,提出了一个有效的解决方案,成功地解决了我的问题。您必须将JAR文件隐藏在部署计划中的父加载器中。它被放入geronimo-web.xml文件中,我的完整文件如下所示。
粘贴自http://osdir.com/ml/user-geronimo-apache/2011-03/msg00026.html:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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">
<dep:environment>
<dep:moduleId>
<dep:groupId>DataStar</dep:groupId>
<dep:artifactId>DataStar</dep:artifactId>
<dep:version>1.0</dep:version>
<dep:type>car</dep:type>
</dep:moduleId>
<!-- Don't load commons-io or fileupload from parent classloaders -->
<dep:hidden-classes>
<dep:filter>org.apache.commons.io</dep:filter>
<dep:filter>org.apache.commons.fileupload</dep:filter>
</dep:hidden-classes>
<dep:inverse-classloading/>
</dep:environment>
<web:context-root>/DataStar</web:context-root>
</web:web-app>