Servlet的文件上传|下载
二、文件上传实现
2.1实现思路
- 需要使用到Commons-FileUpload组件
- 需要将jsp页面form表单的enctype属性值设置为“multipart/form-data”,
- Servlet中使用IO流实现文件的上传
2.2、实现过程
2.2.1新建web项目导入jar包
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
2.2.2、编写页面
在webapp下编写upload.jsp页面,用于提供文件上传的form表单,需要注意的是,form表单的enctype属性值要设置为“multipart/form-data”,method属性值要设置为“post”,并将action属性值设置为“upServlet”
<!--
文件上传
1.准备表单
2.设置表单的提交类型 method = "post"
3.设置表单类型为文件上传表单 enctype=“multipart/form-data”
4.设置文件提交的地址
5.准备表单元素
1.普通的表单项 type="text
2.文件项 type="file"
6.设置表单元素的name属性值(表单提交一定要设置表元素的name属性值,否则后台无法接收数据!)
-->
<form action="upServlet" method="post"
enctype="multipart/form-data">
<table width="600px">
<tr>
<td>上传者</td>
<td><input type="text" name="name" /></td>
</tr>
<tr>
<td>上传文件</td>
<td><input type="file" name="myfile"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="上传" /></td>
</tr>
</table>
</form>
2.2.3、创建Servlet
在web项目的java文件夹下创建包com.kdf.upload,在该包中新建一个名称为UploadServlet的类,用于获取表单及其上传文件的信息。
package com.kdf.upload;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import org.apache.commons.fileupload.*;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
//上传文件的Servlet类
@WebServlet(name = "UploadServlet",urlPatterns = "/upServlet")
//该注解用于标注文件上传的Servlet
@MultipartConfig
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request,
HttpServletResponse response)throws ServletException, IOException {
try {
//设置ContentType字段值
response.setContentType("text/html;charset=utf-8");
// 创建DiskFileItemFactory工厂对象
DiskFileItemFactory factory = new DiskFileItemFactory();
//设置文件缓存目录,如果该目录不存在则新创建一个
File f = new File("E:\\TempFolder");
if (!f.exists()) {
f.mkdirs();
}
// 设置文件的缓存路径
factory.setRepository(f);
// 创建 ServletFileUpload对象
ServletFileUpload fileupload = new ServletFileUpload(factory);
//设置字符编码
fileupload.setHeaderEncoding("utf-8");
// 解析 request,得到上传文件的FileItem对象
List<FileItem> fileitems = fileupload.parseRequest(request);
//获取字符流
PrintWriter writer = response.getWriter();
// 遍历集合
for (FileItem fileitem : fileitems) {
// 判断是否为普通字段
if (fileitem.isFormField()) {
// 获得字段名和字段值
String name = fileitem.getFieldName();
if(name.equals("name")){
//如果文件不为空,将其保存在value中
if(!fileitem.getString().equals("")){
String value = fileitem.getString("utf-8");
writer.print("上传者:" + value + "<br />");
}
}
} else {
// 获取上传的文件名
String filename = fileitem.getName();
//处理上传文件
if(filename != null && !filename.equals("")){
writer.print("上传的文件名称是:" + filename + "<br />");
// 截取出文件名
filename = filename.substring(filename.lastIndexOf("\\") + 1);
// 文件名需要唯一
filename = UUID.randomUUID().toString() + "_" + filename;
// 在服务器创建同名文件
String webPath = "/upload/";
//将服务器中文件夹路径与文件名组合成完整的服务器端路径
String filepath = getServletContext()
.getRealPath(webPath + filename);
// 创建文件
File file = new File(filepath);
file.getParentFile().mkdirs();
file.createNewFile();
// 获得上传文件流
InputStream in = fileitem.getInputStream();
// 使用FileOutputStream打开服务器端的上传文件
FileOutputStream out = new FileOutputStream(file);
// 流的拷贝
byte[] buffer = new byte[1024];//每次读取1个字节
int len;
//开始读取上传文件的字节,并将其输出到服务端的上传文件输出流中
while ((len = in.read(buffer)) > 0)
out.write(buffer, 0, len);
// 关闭流
in.close();
out.close();
// 删除临时文件
fileitem.delete();
writer.print("上传文件成功!<br />");
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
doGet(request, response);
}
}
启动项目,选择文件进行上传。
三、文件下载
3.1download.jsp
<a href=
"http://localhost:8080/DownloadServlet?filename=1.png">
文件下载</a>
</body>
3.2servlet
package com.kdf.upload;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet(name = "DownloadServlet",urlPatterns = "/DownloadServlet")
public class DownloadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
//设置ContentType字段值
response.setContentType("text/html;charset=utf-8");
//获取所要下载的文件名称
String filename = request.getParameter("filename");
//下载文件所在目录
String folder = "/download/";
// 通知浏览器以下载的方式打开
response.addHeader("Content-Type", "application/octet-stream");
response.addHeader("Content-Disposition",
"attachment;filename="+filename);
folder=folder+filename;
// 通过文件流读取文件
InputStream in = getServletContext().getResourceAsStream(folder);
// 获取response对象的输出流
OutputStream out = response.getOutputStream();
byte[] buffer = new byte[1024];
int len;
//循环取出流中的数据
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
doGet(request, response);
}
}
一、文件上传原理
要实现Web开发中的文件上传功能,通常需完成两步操作:
一是在Web项目的页面中添加上传输入项,
二是在Servlet中读取上传文件的数据,并保存到目标路径中。
由于大多数文件的上传都是通过表单的形式提交给服务器的,因此,要想在程序中实现文件上传功能,首先要创建一个用于提交上传文件的表单页面。在表单页面中,需要使用标签在jsp页面中添加文件上传输入项。
1.1、文件域
标签的使用。
- 必须要设置input输入项的name属性,否则浏览器将不会发送上传文件的数据。
- 必须把将表单页面的method属性设置为post方式,enctype属性设置为“multipart/form-data”类型。
<%--指定表单数据的enctype属性以及提交方式--%>
<form enctype="multipart/form-data" method="post">
<%--指定标记的类型和文件域的名称--%>
选择上传文件:<input type="file" name="myfile"/><br />
</form>
1.2、commons-fileUpload
当浏览器通过表单提交上传文件时,文件数据都附带在HTTP请求消息体中,并且采用MIME类型(多用途互联网邮件扩展类型)进行描述,在后台可以使用request对象提供的getInputStream()方法读取客户端提交过来的数据。
但由于用户可能会同时上传多个文件,而在Servlet端直接读取上传数据,并分别解析出相应的文件数据是一项非常麻烦的工作。为了方便处理用户上传的数据,Apache组织提供了一个开源组件Commons- FileUpload,该组件可以方便地将“multipart/form-data”类型请求中的各种表单域解析出来,并实现一个或多个文件的上传,文件上传的原理如下图所示。
1.3、FileItem接口
FileItem接口主要用于封装单个表单字段元素的数据,一个表单字段元素对应一个FileItem对象。Commons-FileUpload组件在处理文件上传的过程中,将每一个表单域(包括普通的文本表单域和文件域)封装在一个FileItem对象中。常用方法如下表所示:
方法声明 | 功能描述 |
---|---|
boolean isFormField() | isFormField()方法用于判断FileItem类对象封装的数据是一个普通文本表单字段,还是一个文件表单字段,如果是普通文本表单字段则返回true,否则返回false。 |
String getName() | getName()方法用于获取文件上传字段中的文件名。如果FileItem类对象对应的是普通文本表单字段,getName()方法将返回null,否则,只要浏览器将文件的字段信息传递给服务器,getName()方法就会返回一个字符串类型的结果,如C:\Sunset.jpg。 |
String getFieldName() | getFieldName()方法用于获取表单字段元素描述头的name属性值,也是表单标签name属性的值。例如“name=file1”中的“file1”。 |
void write(File file) | write()方法用于将FileItem对象中保存的主体内容保存到某个指定的文件中。如果FileItem对象中的主体内容是保存在某个临时文件中,那么该方法顺利完成后,临时文件有可能会被清除。另外,该方法也可将普通表单字段内容写入到一个文件中,但它主要用于将上传的文件内容保存到本地文件系统中。 |
String getString() | getString()方法用于将FileItem对象中保存的数据流内容以一个字符串形式返回。它有两个重载的定义形式:①public String getString()②public String getString(java.lang.String encoding)前者使用默认的字符集编码将主体内容转换成字符串,后者使用参数指定的字符集编码将主体内容转换成字符串。 |
String getContentType() | getContentType()方法用于获得上传文件的类型,即表单字段元素描述头属性“Content-Type”的值,如“image/jpeg”。如果FileItem类对象对应的是普通表单字段,该方法将返回null。 |
1.4、DiskFileItemFactory类
DiskFileItemFactory类用于将请求消息实体中的每一个文件封装成单独的FileItem对象。如果上传的文件比较小,将直接保存在内存中,如果上传的文件比较大,则会以临时文件的形式,保存在磁盘的临时文件夹中。默认情况下,不管文件保存在内存还是磁盘临时文件夹,文件存储的临界值是10240字节,即10KB。
方法声明 | 功能描述 |
---|---|
DiskFileItemFactory() | 采用默认临界值和系统临时文件夹构造文件项工厂对象 |
DiskFileItemFactory(int sizeThreshold,File repository) | 采用参数指定临界值和系统临时文件夹构造文件项工厂对象 |
DiskFileItemFactory(int sizeThreshold,File repository)构造方法传递两个参数,第一个参数sizeThreshold表示文件保存在内存还是磁盘临时文件夹中的临界值,第二个参数repository表示临时文件的存储路径。
1.5、ServletFileUpload类
ServletFileUpload类是Apache组件处理文件上传的核心高级类,通过调用parseRequest(HttpServletRequest) 方法可以将HTML中每个表单提交的数据封装成一个FileItem对象,然后以List列表的形式返回。
方法声明 | 功能描述 |
---|---|
ServletFileUpload() | 构造一个未初始化的ServletFileUpload实例对象 |
ServletFileUpload(FileItemFactory fileItemFactory) | 根据参数指定的FileItemFactory 对象创建一个ServletFileUpload对象 |