Servlet上传文件和下载文件的示例
在Java Web应用程序中,通过Servlet上传文件和下载文件是一项常见任务。由于最近我写了很多关于Java Servlet的内容,我想提供一个示例,展示如何通过Servlet将文件上传到服务器,然后从服务器下载到客户端。
Servlet 上传文件
我们的使用案例是提供一个简单的HTML页面,客户端可以在页面上选择本地文件上传到服务器。当用户提交上传文件的请求时,我们的servlet程序将把文件上传到服务器的一个目录中,并提供下载文件的URL供用户使用。出于安全原因,用户将不会直接获得下载文件的URL,而是会获得一个下载文件的链接,我们的servlet程序将处理该请求并将文件发送给用户。我们将在Eclipse中创建一个动态Web项目,项目结构如下图所示。让我们一起了解我们的Web应用程序的所有组件,并理解其实现方式。
Java上传文件到服务器的HTML页面
我们可以通过向服务器发送POST请求和提交表单来上传文件。我们不能使用GET方法来上传文件。另一个要注意的点是表单的enctype应该是multipart/form-data。为了从用户的文件系统中选择文件,我们需要使用type为file的input元素。所以我们可以有一个简单的HTML页面index.html来上传文件。
<html>
<head></head>
<body>
<form action="UploadDownloadFileServlet" method="post" enctype="multipart/form-data">
Select File to Upload:<input type="file" name="fileName">
<br>
<input type="submit" value="Upload">
</form>
</body>
</html>
文件上传的服务器文件位置
我们需要将文件存储到服务器的某个目录中,我们可以在程序中硬编码这个目录,但为了更好的灵活性,我们将在部署描述符上下文参数中将其配置为可配置。此外,我们将把我们的上传文件的HTML页面添加到欢迎文件列表中。我们的web.xml文件将如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>ServletFileUploadDownloadExample</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<context-param>
<param-name>tempfile.dir</param-name>
<param-value>tmpfiles</param-value>
</context-param>
</web-app>
文件上传位置的ServletContextListener
由于我们需要读取文件位置的上下文参数并创建一个文件对象,所以当上下文被初始化时,我们可以编写一个ServletContextListener来完成这个任务。我们可以设置绝对目录位置和文件对象作为上下文属性,以供其他servlet使用。我们的ServletContextListener实现代码如下所示。
package com.Olivia.servlet;
import java.io.File;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class FileLocationContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
String rootPath = System.getProperty("catalina.home");
ServletContext ctx = servletContextEvent.getServletContext();
String relativePath = ctx.getInitParameter("tempfile.dir");
File file = new File(rootPath + File.separator + relativePath);
if(!file.exists()) file.mkdirs();
System.out.println("File Directory created to be used for storing files");
ctx.setAttribute("FILES_DIR_FILE", file);
ctx.setAttribute("FILES_DIR", rootPath + File.separator + relativePath);
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
//do cleanup if needed
}
}
文件上传下载Servlet
更新:Servlet规范3在API中添加了对在服务器上上传文件的支持,因此我们不需要使用任何第三方API。请查看Servlet 3上传文件。对于文件上传,我们将使用Apache Commons FileUpload实用程序,对于我们的项目,我们使用的是1.3版本,FileUpload依赖于Apache Commons IO jar,因此我们需要将两者都放置在项目的lib目录中,如上图所示的项目结构。我们将使用提供一种方法来解析HttpServletRequest对象并返回FileItem列表的DiskFileItemFactory工厂。FileItem提供了一些有用的方法来获取需要上传的文件的文件名、表单中的字段名、大小和内容类型详细信息。要将文件写入目录,我们只需创建一个File对象并将其作为参数传递给FileItem write()方法。由于Servlet的整个目的是上传文件,我们将重写init()方法来初始化Servlet的DiskFileItemFactory对象实例。我们将在doPost()方法的实现中使用此对象来将文件上传到服务器目录中。文件成功上传后,我们将向客户端发送包含下载文件的URL的响应,由于HTML链接使用GET方法,我们将在URL中添加文件名的参数,我们可以利用同一个servlet的doGet()方法来实现文件下载过程。为了实现下载文件servlet,首先我们将打开文件的InputStream,并使用ServletContext.getMimeType()方法获取文件的MIME类型,并将其设置为响应的内容类型。我们还需要将响应的内容长度设置为文件的长度。为了确保客户端理解我们正在发送的是文件响应,我们需要设置“Content-Disposition”头,值为“attachment; filename=“fileName”。完成设置响应配置后,我们可以从InputStream中读取文件内容,将其写入ServletOutputStream,然后将输出刷新给客户端。我们的最终实现UploadDownloadFileServlet servlet如下所示。
package com.Olivia.servlet;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
@WebServlet("/UploadDownloadFileServlet")
public class UploadDownloadFileServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private ServletFileUpload uploader = null;
@Override
public void init() throws ServletException{
DiskFileItemFactory fileFactory = new DiskFileItemFactory();
File filesDir = (File) getServletContext().getAttribute("FILES_DIR_FILE");
fileFactory.setRepository(filesDir);
this.uploader = new ServletFileUpload(fileFactory);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String fileName = request.getParameter("fileName");
if(fileName == null || fileName.equals("")){
throw new ServletException("File Name can't be null or empty");
}
File file = new File(request.getServletContext().getAttribute("FILES_DIR")+File.separator+fileName);
if(!file.exists()){
throw new ServletException("File doesn't exists on server.");
}
System.out.println("File location on server::"+file.getAbsolutePath());
ServletContext ctx = getServletContext();
InputStream fis = new FileInputStream(file);
String mimeType = ctx.getMimeType(file.getAbsolutePath());
response.setContentType(mimeType != null? mimeType:"application/octet-stream");
response.setContentLength((int) file.length());
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
ServletOutputStream os = response.getOutputStream();
byte[] bufferData = new byte[1024];
int read=0;
while((read = fis.read(bufferData))!= -1){
os.write(bufferData, 0, read);
}
os.flush();
os.close();
fis.close();
System.out.println("File downloaded at client successfully");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if(!ServletFileUpload.isMultipartContent(request)){
throw new ServletException("Content type is not multipart/form-data");
}
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.write("<html><head></head><body>");
try {
List<FileItem> fileItemsList = uploader.parseRequest(request);
Iterator<FileItem> fileItemsIterator = fileItemsList.iterator();
while(fileItemsIterator.hasNext()){
FileItem fileItem = fileItemsIterator.next();
System.out.println("FieldName="+fileItem.getFieldName());
System.out.println("FileName="+fileItem.getName());
System.out.println("ContentType="+fileItem.getContentType());
System.out.println("Size in bytes="+fileItem.getSize());
File file = new File(request.getServletContext().getAttribute("FILES_DIR")+File.separator+fileItem.getName());
System.out.println("Absolute Path at server="+file.getAbsolutePath());
fileItem.write(file);
out.write("File "+fileItem.getName()+ " uploaded successfully.");
out.write("<br>");
out.write("<a href=\"UploadDownloadFileServlet?fileName="+fileItem.getName()+"\">Download "+fileItem.getName()+"</a>");
}
} catch (FileUploadException e) {
out.write("Exception in uploading file.");
} catch (Exception e) {
out.write("Exception in uploading file.");
}
out.write("</body></html>");
}
}
该项目的示范执行在下面的图片中展示出来。 de de .)
下载Servlet文件上传下载项目
您可以从以下网址下载Apache Commons IO jar和Apache Commons FileUpload jar。
https://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi
https://commons.apache.org/proper/commons-io/download_io.cgi
下载Servlet文件上传下载示例项目
请查看关于Servlet异常处理的系列文章中的下一篇文章。