学习笔记 : Java web之文件的上传与下载
文件上传
如何实现文件上传
Apache
组织提供了一个开源组件Commons-FileUpload
( 依赖于common-io
),该组件可以方便地将multipart/form-data
类型请求中的各种表单解析出来,并实现一个或多个文件的上传,同时也可以限制上传文件的大小等内容..并且性能优异,使用简单. FileUpload组件是通过Servlet来实现文件上传功能的,其工作流程如下图所示.
文件上传相关API
FileItem Interface
FileItem
接口用于封装单个表单字段元素的数据,一个表单字段元素对应一个FileItem对象.
DiskFileItemFactory Class
DiskFileItemFactory
类用于将请求的消息实体中的每一个文件封装成单独的FileItem
对象.如果上传的文件比较小,将直接保存在内存中,如果上传的文件比较大,则会以临时文件的形式,保存在磁盘的临时文件中,默认情况下,文件保存在内存/磁盘临时文件夹的临界值为10240,既10KB.
ServletFileUpload Class
ServletFileUpload
类是Apache组件处理文件上传的核心高级类,通过使用parseRequest(HttpServletRequest)
方法可以将HTML中每个表单提交的数据封装成一个FileItem
对象,然后以List列表的形式返回.
文件上传案例
JSP页面代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<meta charset="UTF-8">
<title>file</title>
</head>
<body>
<h3 align="center">upload the specified the file</h3>
<hr>
<form action="UploadServlet2" method="post" enctype="multipart/form-data">
<div align="center">
<table>
<tr>
<td>学号</td>
<td><input type="text" name="id"/>
</tr>
<tr>
<td>姓名</td>
<td><input type="text" name="name"/></td>
</tr>
<tr>
<td>照片</td>
<td><input type="file" name="image"/></td>
</tr>
<tr>
<td>
<%-- 文件上传结果 --%>
<%
String result = (String)request.getAttribute("result");
if(result!=null){
out.println("<script>alert(' "+result+" ')</script>");
}
%>
</td>
</tr>
</table>
<input type="submit" value="上传"/>
</div>
</form>
</body>
</html>Servlet类 : 获取表单及其上传文件的信息..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108package pers.huangyuhui.file.servlet;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
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.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.filefilter.SuffixFileFilter;
public class UploadServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
public UploadServlet2() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String message = "上传失败 !";// 上传结果
// FileItemFactory fileItemFactory = new DiskFileItemFactory();
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
fileItemFactory.setSizeThreshold(1024 * 1024);// // 设置将上传的文件以临时文件的形式保存在磁盘的临界值
// 默认情况下,采用的是系统默认的临时文件路径,可以通过该方式获取: System.getProperty("java.io.tmpdir");
fileItemFactory.setRepository(new File("D:\\Java web\\temporary files"));// 将上传的文件以临时文件的形式保存在指定的目录下
// 判断请求消息中的内容是否是: multipart/form-data类型
if (ServletFileUpload.isMultipartContent(request)) {
// 文件上传的核心高级类
ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
servletFileUpload.setSizeMax(1024 * 20); // 设置请求消息实体内容(既上传数据)的最大尺寸限制: 20KB
try {
// 将HTML中每个表单提交的数据封装成一个FileItem对象,然后以List列表的形式返回
List<FileItem> fileItems = servletFileUpload.parseRequest(request);
// 限制上传的文件类型
String[] suffixs = new String[] { ".exe", ".bat", ".c", ".java", ".sh", "html", ".css", ".js" };
SuffixFileFilter suffixFileFilter = new SuffixFileFilter(suffixs);
// 遍历集合
File file = null;
String sno = null;
String sname = null;
String fileName = null;
for (FileItem fileItem : fileItems) {
String item = fileItem.getFieldName();
if (fileItem.isFormField()) {// 普通文本表单字段
if (item.equals("id")) {
sno = fileItem.getString();
} else if (item.contentEquals("name")) {
sname = fileItem.getString();
} else {
System.out.println("others value ..");
}
} else {// 文件表单字段
fileName = fileItem.getName();
file = new File(request.getSession().getServletContext().getRealPath("/upload/" + fileName));
if (suffixFileFilter.accept(file)) {
message = "禁止上传此类型文件 !";
} else {
file.getParentFile().mkdirs();// 创建目录
fileItem.write(file);// 上传文件
message = "success to upload !";
System.out.println("id: " + sno + "\nname: " + sname + "\nthe file name: " + fileName
+ "\nthe file path: " + file.getAbsolutePath()); // 上传者及文件信息
}
}
}
} catch (FileNotFoundException e) {
message = "error : please choose the specified file !";
} catch (SizeLimitExceededException e) {
message = "error : the file size exceeds limit !";
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
// 将提示信息保留在request对象中
request.setAttribute("result", message);
request.getRequestDispatcher("upload.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}程序运行结果 : 略..
文件下载
文件下载程序流程
浏览器通常会直接处理响应的实体内容,这时需要在HTTP
响应消息中设置两个响应消息头字段,指定接收程序处理数据内容的方式为下载方式,当点击”下载”超链接时,系统将请求提交到对应的Servlet
.在该Servlet中,程序流程如下 :
- 根据该地址创建文件字节输入流.
- 通过该流读取下载文件的内容.
- 将读取的内容通过输出流写到目标文件中.
HTTP
中设置两个响应消息头,具体如下.1
2
3
4//设定接收程序处理数据的方式
Content-Disposition: attachment;filename=
//设定实体内容的MIME类型
Content-Type: application/x-msdownload
文件下载案例
JSP页面代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html" charset="UTF-8">
<title>down the file</title>
</head>
<body>
<h3 align="center"></h3>
<a href="DownloadServlet?filename=文件.png">
Click to download this file ..
</a>
</body>
</html>Servlet类 : 设置所要下载的文件以及文件在浏览器中打开的方式.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64package pers.huangyuhui.file.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.codec.binary.Base64;
public class DownloadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public DownloadServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
// 获取需要下载的文件名
String fileName = request.getParameter("filename");
// 设定接收程序处理数据的方式( MIME type : application/octet-stream )
response.addHeader("Content-Type", "application/octet-stream");
/*
* 根据不同浏览器进行不同的编码处理,以防乱码
*/
// User-Agent: 首部包含了一个特征字符串,用来让网络协议的对端来识别发起请求的用户代理软件的应用类型、操作系统、软件开发商以及版本号.
String agent = request.getHeader("User-Agent");
if (agent.toLowerCase().indexOf("firefox") != -1) {
response.addHeader("Content-Disposition", "attachment;filename==?UTF-8?B?"
+ new String(Base64.encodeBase64(fileName.getBytes("UTF-8"))) + "?=");
} else {
// 设定实体内容的MIME类型并使用encode(String s, Charset charset)解决乱码问题: Google Chrome,Microsoft Eage ..
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
}
// 读取文件
InputStream inputStream = getServletContext().getResourceAsStream("/resource/" + fileName);
// 获取response对象的输出流
OutputStream outputStream = response.getOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
outputStream.close();
inputStream.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}程序运行结果 : 略..
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Comment