文件上传与下载
- 文件上传
- 要求
- commons-fileupload.jar
- 实现
- 文件下载
- 步骤
- API 说明
- 解决中文乱码问题
- 加载文件时的注意事项
- 实现
文件上传
要求
- 准备一个 form 表单,method=post。
- form 标签的 encType 属性值必须为 multipart/form-data 值。
- 在表单内使用 input type=file 添加上传的文件。
- 编写 Servlet 程序接收请求,处理上传的数据。
encType=multipart/form-data 表示提交的数据,以多段(每一个表单项一个数据段)的形式进行拼接,然后以二进制流的形式发送给服务器。
commons-fileupload.jar
文件上传需要导入两个包:commons-fileupload.jar、commons-io.jar
类 | 意义 |
ServletFileUpload 类 | 用于解析上传的数据 |
FileItem 类 | 表示每一个表单项 |
ServletFileUpload 类内的方法 | 意义 |
static boolean isMultipartContent(HttpServletRequest req) | 判断当前上传的数据格式是否为多段的格式 |
public List<FileItem> parseRequest(HttpServletRequest request) | 解析上传的数据 |
FileItem 类内的方法 | 意义 |
boolean isFormField() | 判断当前的表单项是普通的表单项,还是上传文件项,true 表示普通类型的表单项,false 表示上传文件 |
String getFieldName() | 获取表单项的 name 属性值 |
String getString() | 获取表单项的 value 属性值 |
String getName() | 获取上传文件的文件名 |
void write(file) | 将上传的文件写入参数 file 所指向的磁盘路径 |
实现
upload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!--
文件上传:
1、要有一个 form 标签,method=post 请求
2、form 标签的 encType 属性值必须为 multipart/form-data 值
3、在 form 标签中使用 input type=file 添加上传的文件
4、编写服务器代码(Servlet 程序)接收,处理上传的数据。
-->
<form action="http://localhost:8080/jspWeb/uploadServlet" method="post" enctype="multipart/form-data">
<!-- 普通表单项 -->
用户名:<input type="text" name="username"><br>
<!-- 上传文件项 -->
<input type="file" name="photo"><br>
<input type="submit" value="上传">
</form>
</body>
</html>
UploadServlet.java
package servlet;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
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.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* ServletFileUpload类:用于解析上传的数据
* boolean ServletFileUpload.isMultipartContent(HttpServletRequest request) 判断当前上传的数据格式是否是多段的格式。
* List<FileItem> parseRequest(HttpServletRequest request) 解析上传的数据
*
* FileItem类:表单项类
* boolean isFormField() 判断当前这个表单项,是普通的表单项,还是上传的文件类型
* true 表示普通类型的表单项
* false 表示上传的文件类型
* String getFieldName() 获取表单项的name属性的值
* String getString() 获取当前表单项的value值
* String getName() 获取上传文件的文件名
* void FileItem.write(File file) 将上传的文件写到file所指向的硬盘位置
* @author MCC
*
*/
public class UploadServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.判断提交的数据是否是多段数据,只有是多段数据才可能是上传的数据
if(ServletFileUpload.isMultipartContent(req)) {
//如果为true,代表是多段数据
//2.创建fileItemFactory接口实现类
FileItemFactory fileItemFactory = new DiskFileItemFactory();
//3.创建ServletFileUpload对象,以供解析上传的数据
ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
//4.解析数据
try {
List<FileItem> list = servletFileUpload.parseRequest(req);
//遍历list集合,对于普通表单项与上传的文件表单项进行不同的操作
for(FileItem item : list) {
if(item.isFormField()) {
//返回true代表item是普通表单项
System.out.println("表单项的name属性值:" + item.getFieldName());
System.out.println("表单项的value属性值:" + item.getString("UTF-8"));
} else {
//返回false代表item是上传数据的表单项
System.out.println("表单项的name属性值:" + item.getFieldName());
System.out.println("上传的文件名:" + item.getName());
//保存上传的文件
item.write(new File("C:\Users\MCC\Desktop\fileUpload\" + item.getName()));
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
} else {
//如果为false,代表不是多段数据
//...
}
}
}
文件下载
步骤
- 获取请求下载的资源名,这里假设为固定名称
- 获取资源类型,并将该类型告知浏览器
- 告诉浏览器该文件是用于下载的,不要直接显示在浏览器中
- 读取源文件
- 获取响应流
- 通过commons.io包下的工具类完成从输入流写入到输出流的工作
API 说明
ServletContext 类: 通过 getServletContext() 或 getServletConfig().getServletContext() 获取
方法 | 意义 |
getMimeType(String path) | 获取文件的类型 |
getResourceAsStream(String path) | 加载文件 |
Response类:
方法 | 意义 |
setContentType(String type) | 设置响应数据的类型 |
setHeader(“Content-Disposition”,“attachment; filename=”+“name”) | 设置响应数据的处理方式 |
其中,
- Content-Disposition:表示处理方式
- attachment:表示附件方式,用于下载
- filename=:设置下载时的文件名
common.io包:
方法 | 意义 |
IOUtils.copy(inputStream input, outputStream output) | 将输入流中的数据复制到输出流中 |
解决中文乱码问题
- URL编码:
方法 | 意义 |
URLEncoder.encode(String chineseName, Charset charset); | 将中文字符设置为URL编码,解决下载中文文件乱码问题 |
- Base64编码:火狐(fireFox)浏览器
方法 | 意义 |
Encoder encoder = Base64.getEncoder(); | 获取base64编码器 |
encoder.encode(byte[] b); | 编码 |
Decoder decoder = Base64.getDecoder(); | 获取base64解码器 |
encoder.decode(byte[] b); | 解码 |
加载文件时的注意事项
要使用如下代码加载源文件:
ServletContext context = getServletContext();
InputStream in = context.getResourceAsStream(String path);
不能使用如下代码加载源文件:
InputStream inputStream = DownloadServlet.class.getResourceAsStream(downloadFileName);
原因:不能用类的加载器加载文件,因为服务器解析地址时默认是在 http://localhost:8080/工程路径,对应工程的 WebContent 目录进行查找,而类的加载器默认是在 Java 工程目录下进行查找的,java 目录在 web 项目中是隐藏的,不能访问(访问Java文件时要配置 web.xml 文件)
实现
package servlet;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Base64;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
public class DownloadServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
/**
* 接收下载请求
*
* ServletContext类:
* getMimeType(String path) 获取文件的类型
* getResourceAsStream(String path) 加载文件
* Response类:
* setContentType(String type) 设置响应数据的类型
* setHeader("Content-Disposition", "attachment; filename="+"name") 设置响应数据的处理方式
* Content-Disposition 处理方式
* attachment 附件方式,用于下载
* filename= 设置下载时的文件名
* common.io包:
* IOUtils.copy(inputStream input, outputStream output) 将输入流中的数据复制到输出流中
*
* URL编码:
* URLEncoder.encode(String chineseName, Charset charset); 将中文字符设置为URL编码,解决下载中文文件乱码问题
* Base64编码:火狐浏览器使用
* Encoder encoder = Base64.getEncoder(); 获取base64编码器
* encoder.encode(byte[] b); 编码
* Decoder decoder = Base64.getDecoder(); 获取base64解码器
* encoder.decode(byte[] b); 解码
*
* InputStream inputStream = DownloadServlet.class.getResourceAsStream(downloadFileName);
*不能用类的加载器加载文件,因为服务器解析地址时默认是在http://localhost:8080/工程路径 对应工程的WebContent目录进行查找
*而类的加载器默认是在Java工程目录下进行查找的,java目录在web项目中是隐藏的,不能访问(访问Java文件时要配置web.xml文件)
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取请求下载的资源名,这里假设为固定名称
String downloadFileName = "/2020-11-24_215804.png";
//2.获取资源类型,并将该类型告知浏览器
ServletContext context = getServletContext();
String mimeType = context.getMimeType(downloadFileName);
resp.setContentType(mimeType);
//3.告诉浏览器该文件是用于下载的,不要直接显示在浏览器中
if(req.getHeader("User-Agent").contains("fireFox")) {//如果使用的是火狐浏览器,则使用Base64编码
resp.setHeader("Content-Disposition", "attachment; filename="
+ Base64.getEncoder().encode("张大仙.png".getBytes()));
} else {//如果是其他浏览器,则使用URL编码
// resp.setHeader("Content-Disposition", "attachment; filename="+System.currentTimeMillis()+".png");
resp.setHeader("Content-Disposition", "attachment; filename="
+ URLEncoder.encode("张大仙.png", "UTF-8"));
}
//4.读取源文件
InputStream inputStream = context.getResourceAsStream(downloadFileName);
//5.获取响应流
ServletOutputStream outputStream = resp.getOutputStream();
//6.通过commons.io包下的工具类完成从输入流写入到输出流的工作
IOUtils.copy(inputStream, outputStream);
}
}