文档版本 | 开发工具 | 测试平台 | 工程名字 | 日期 | 作者 | 备注 |
---|---|---|---|---|---|---|
V1.0 | 2016.06.05 | lutianfei | none |
servletContext的初始化参数.问题:什么是文件上传?为什么使用文件上传?
文件上传的本质:就是IO流的操作。
实现web开发中的文件上传功能,需完成如下二步操作:
如何在web页面中添加上传输入项?
标签用于在web页面中添加文件上传输入项,设置文件上传输入项时须注意: multipart/form-data
。设置该值后,浏览器在上传文件时,将把文件数据附带在http请求消息体中,并使用MIMIE协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理。如何在Servlet中读取文件上传数据,并保存到本地硬盘中?
Commons-fileupload
),该组件性能优异,并且其API使用极其简单,可以让开发人员轻松实现web文件上传功能,因此在web开发中实现文件上传功能,通常使用Commons-fileupload
组件实现。使用Commons-fileupload组件
实现文件上传,需要导入该组件相应的支撑jar包:Commons-fileupload
和commons-io
。
commons-io
不属于文件上传组件的开发jar文件,但Commons-fileupload
组件从1.1 版本开始,它工作时需要commons-io包
的支持。commons-fileupload-1.2.1.jar
: 文件上传commons-io-1.4.jar
: 它是提供的io工具.
DiskFileItemFactory factory=new DiskFileItemFactory();
ServletFileUpload upload=new ServletFileUpload(factory);
List items = upload.parseRequest(request);
3.遍历items集合,集合中的每一项,就是一个上传数据
isFormField
(); getFieldName
(); 组件名称
getName
(); C:\Users\Administrator\Desktop\a.txt
a.txt
item.getInputStream();
它是用于读取上传文件内容的输入流。IOUtils.copy(item.getInputStream(), fos);
fileupload组件工作流程
获取temp目录部署到tomcat后的绝对磁盘路径的技巧
File file = new File(this.getServletContext().getRealPath("/temp"));
1.DiskFileItemFactory
磁盘文件项工厂类,是创建 FileItem
对象的工厂:
DiskFileItemFactory
(); DiskFileItemFactory
(int sizeThreshold, File repository) delete方法
删除 2.ServletFileUpload
文件上传核心类 ,负责处理上传的文件数据,并将表单中每个输入项封装成一个 FileItem 对象中。常用方法有:
isMultipartContent
(javax.servlet.http.HttpServletRequest request) 判断是否是上传,即判断request的编码方式是否为multipart/form-dataparseRequest
(javax.servlet.http.HttpServletRequest request) 解析request,将请求体每个部分封装 FileItem对象,返回List
setFileSizeMax
(long fileSizeMax) 设置单个文件上传大小 setSizeMax
(long sizeMax) 设置总文件上传大小 setHeaderEncoding
(java.lang.String encoding) 设置编码集 解决上传文件名乱码 setProgressListener
(ProgressListener pListener)实时监听文件上传状态3、FileItem
表示文件上传表单中 每个数据部分,用来表示文件上传表单中的一个上传文件对象或者普通表单对象
isFormField
() 判断该数据项是否为文件上传项,true 不是文件上传 false 是文件上传 getFieldName
() 获得普通表单对象的name属性
getString
(String encoding) 获得普通表单对象的value属性,可以用encoding进行编码设置getName
() 获得上传文件的文件名(有些浏览器会携带客户端路径) getInputStream
() 获得上传文件的输入流delete
() 在关闭FileItem输入流后,删除临时文件总结:关于文件上传时的乱码问题:
if(fileItem.isFormField()){
// 不是上传项
java.lang.String getFieldName() 获得普通表单项name属性
java.lang.String getString() / java.lang.String getString(java.lang.String encoding) 获得普通表单项value属性 传入编码集用来解决输入value乱码
}else{
// 是上传项
java.lang.String getName() 获得上传文件名 (注意IE6存在路径)
java.io.InputStream getInputStream() 获得上传文件内容输入流
// 上传文件
void delete() 删除临时文件(删除时,必须要管理输入输出流)
}
multipart/form-data
与传统url
编码不同,所有getParameter 方法不能使用 setCharacterEncoding 无法解决输入项乱码问题。this.parentNode.parentNode.removeChild(this.parentNode);
<script type="text/javascript">
function addFile(){
var div=document.getElementById("content");
div.innerHTML+="";
}
function removeFile(btn){
document.getElementById("content").removeChild(btn.parentNode);
}
script>
<body>
<input type="button" value="add File" onclick="addFile();">
<br>
<br>
<form action="${pageContext.request.contextPath}/upload4" method="post" encType="multipart/form-data">
<input type="file" name="f"><br>
<div id="content">
div>
<input type="submit" value="上传">
form>
body>
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
// 1.创建 DiskFileItemFactory
File file = new File(this.getServletContext().getRealPath("/temp"));// 获取temp目录部署到tomcat后的绝对磁盘路径
DiskFileItemFactory factory = new DiskFileItemFactory(1024 * 100, file); // 使用默认的.
// 2.创建ServletFileUpload
ServletFileUpload upload = new ServletFileUpload(factory);
boolean flag = upload.isMultipartContent(request); // 用于判断是否是上传操作.
if (flag) {
// 解决上传文件名称中文乱码
upload.setHeaderEncoding("utf-8");
// 设置上传文件大小
// upload.setSizeMax(1024 * 1024 * 10);// 总大小为10m
try {
List items = upload.parseRequest(request);// 解决request,得到所有的上传项FileItem
// 3.得到所有上传项
for (FileItem item : items) {
if (!item.isFormField()) {
// 上传组件
String name = item.getName(); // 上传文件名称
// 得到上传文件真实名称
String filename = FileUploadUtils.getRealName(name);
// 得到随机名称
String uuidname = FileUploadUtils
.getUUIDFileName(filename);
// 得到随机目录
String randomDirectory = FileUploadUtils
.getRandomDirectory(filename);
// 注意:随机目录可能不存在,需要创建.
String parentPath = this.getServletContext()
.getRealPath("/upload");
File rd = new File(parentPath, randomDirectory);
if (!rd.exists()) {
rd.mkdirs();
}
IOUtils.copy(item.getInputStream(),
new FileOutputStream(new File(rd, uuidname)));
// 删除临时文件
item.delete();
}
}
} catch (FileUploadException e) {
// e.printStackTrace();
response.getWriter().write(e.getMessage());
return;
}
} else {
response.getWriter().write("不是上传操作");
return;
}
}
1.保存在可以被浏览器直接访问的位置
2.保存在不能被浏览器直接访问的位置
META-INF
、WEB-INF
目录及其子目录如果文件重名,后上传文件就会覆盖先上传文件,在开发中解决这个问题,可以给上传文件起随机名称。
文件名 UUID
filename = UUID.randomUUID().toString() + "_" + filename;
为了防止同一个目录下方上传文件数量过多 —- 必须采用目录分离算法
public static String generateRandomDir(String uuidFileName) {
// 获得唯一文件名的hashcode
int hashcode = uuidFileName.hashCode();
// 获得一级目录
int d1 = hashcode & 0xf;
// 获得二级目录
int d2 = (hashcode >>> 4) & 0xf;
return "/" + d2 + "/" + d1;// 共有256目录l
}
对于浏览器识别格式的文件,通过另存为进行下载
客户端访问服务器静态资源文件时,静态资源文件是通过 缺省Servlet返回的,在tomcat配置文件conf/web.xml
找到 org.apache.catalina.servlets.DefaultServlet
eg:超连接下载
download1.jsp
<a href='${pageContext.request.contextPath}/upload/a.bmp'>a.bmpa><br>
<a href='${pageContext.request.contextPath}/upload/a.doc'>a.doca><br>
<a href='${pageContext.request.contextPath}/upload/a.txt'>a.txta><br>
<a href='${pageContext.request.contextPath}/upload/tk.mp3'>tk.mp3a><br>
MIME
协议 response.setContentType(getServletContext().getMimeType(filename));
response.setHeader("Content-Disposition", "attachment;filename=" + filename); // 以附件形式打开,不管格式浏览器是否识别
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?"
+ base64Encoder.encode(filename.getBytes("utf-8"))
+ "?=";
} else if (agent.contains("Chrome")) {
// google浏览器
filename = URLEncoder.encode(filename, "utf-8");
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
<a href='${pageContext.request.contextPath}/download?filename=a.bmp'>a.bmpa><br>
<a href='${pageContext.request.contextPath}/download?filename=a.doc'>a.doca><br>
<a href='${pageContext.request.contextPath}/download?filename=a.txt'>a.txta><br>
<a href='${pageContext.request.contextPath}/download?filename=tk.mp3'>tk.mp3a><br>
// 1.得到要下载 的文件名称
String filename = request.getParameter("filename");
//2.判断文件是否存在
File file = new File("d:/upload/" + filename);
if (file.exists())
//3.进行下载
原理:就是通过response获取一个输出流,将要下载的文件内容写回到浏览器端就可以了.
注意:要想通过编程的方式,实现文件下载
总结:服务器端编程下载:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.得到要下载 的文件名称
String filename = request.getParameter("filename");
filename = new String(filename.getBytes("iso8859-1"), "utf-8");// 解决中文乱码
// 2.在d:/upload目录下查找这个文件是否存在
File file = new File("d:/upload/" + filename);
if (file.exists()) {
// /文件存在,完成下载
// 下载注意事项1--设置下载文件的mimeType
String mimeType = this.getServletContext().getMimeType(filename);
response.setContentType(mimeType);
String agent = request.getHeader("user-agent");
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?"
+ base64Encoder.encode(filename.getBytes("utf-8"))
+ "?=";
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
// 下载注意事项2--永远是下载
response.setHeader("content-disposition", "attachment;filename="
+ filename);
FileInputStream fis = new FileInputStream(file); // 读取要下载文件的内容
OutputStream os = response.getOutputStream(); // 将要下载的文件内容通过输出流写回到浏览器端.
int len = -1;
byte[] b = new byte[1024 * 100];
while ((len = fis.read(b)) != -1) {
os.write(b, 0, len);
os.flush();
}
os.close();
fis.close();
} else {
throw new RuntimeException("下载资源不存在.");
}
}
1.关于下载时中文名称资源查找不到
天空.mp3
String filename = request.getParameter("filename");
filename = new String(filename.getBytes("iso8859-1"),"utf-8");
2.下载文件显示时的中文乱码问题
response.setHeader("content-disposition", "attachment;filename="+filename);
IE:要求filename必须是utf-8码
firefox:要求filename必须是base64编码.
问题:怎样判断浏览器?
String agent=request.getHeader("user-agent");
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?"
+ base64Encoder.encode(filename.getBytes("utf-8"))
+ "?=";
}else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
<%
String path = "D:\\java1110\\workspace\\day22_2\\WebRoot\\upload";
File uploadDirectory = new File(path);
//创建一个队列
Queue queue = new LinkedList();
queue.offer(uploadDirectory);
while (!queue.isEmpty()) { //如果队列不为空
File f = queue.poll(); //从队列中获取一个File
if(f.isDirectory()){//是目录,将目录下所有文件遍历出来,存储到队列中
File[] fs = f.listFiles();
for (int i = 0; i < fs.length; i++) {
queue.offer(fs[i]);
}
}else{
String absolutePath=(f.getAbsolutePath());
String p=absolutePath.substring(absolutePath.lastIndexOf("\\upload"));
out.println(""+f.getName()+"
");
}
}
%>
create database day23
create table resources(
id int primary key auto_increment,
uuidname varchar(100) unique not null,
realname varchar(40) not null,
savepath varchar(100) not null,
uploadtime timestamp ,
description varchar(255)
);
2.导入jar包和配置文件
3.编码实现上传
上传
method=post
encType="multipart/form-data"
* 3.创建UploadServlet
* 1.上传操作
* commons-fileupload
* 1.DiskFileItemFactory
* 2.ServletFileUpload
* 3.FileItem
* 2.将数据封装,存储到数据库.
* 问题:怎样将数据封装到javaBean?
* 手动创建一个Map将数据封装到map集合,通过BeanUtils完成数据封装
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Map<String, String[]> map = new HashMap<String, String[]>();
// 1.创建DiskFileItemFactory
DiskFileItemFactory factory = new DiskFileItemFactory();
// 2.创建ServletFileUpload
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置上传文件中文名称乱码
upload.setHeaderEncoding("utf-8");
// upload.isMultipartContent(request)
// 3.得到所有的FileItem
try {
List items = upload.parseRequest(request);
// 遍历items,得到所有的上传信息
for (FileItem item : items) {
if (item.isFormField()) {
// 不是上传组件
map.put(item.getFieldName(),
new String[] { item.getString("utf-8") }); // 封装非上传组件信息
} else {
// 是上传组件
// 得到上传文件名称
String filename = item.getName();
filename = FileUploadUtils.getRealName(filename);
map.put("realname", new String[] { filename }); // 封装上传文件真实名称
// 得到随机名称
String uuidname = FileUploadUtils.getUUIDFileName(filename);
map.put("uuidname", new String[] { uuidname });// 封装上传文件随机名称
// 得到随机目录
String randomDirectory = FileUploadUtils
.getRandomDirectory(filename);
String uploadPath = this.getServletContext().getRealPath(
"/WEB-INF/upload");
File parentDirectory = new File(uploadPath, randomDirectory);
if (!parentDirectory.exists()) {
parentDirectory.mkdirs();
}
map.put("savepath", new String[] { uploadPath
+ randomDirectory });// 封装上传文件保存路径
IOUtils.copy(item.getInputStream(), new FileOutputStream(
new File(parentDirectory, uuidname)));
item.delete();
}
}
// /将数据封装到javaBean
Resource r = new Resource();
BeanUtils.populate(r, map);
// 调用service完成保存数据到db。
ResourceService service = new ResourceService();
service.save(r);
response.sendRedirect(request.getContextPath() + "/index.jsp");
} catch (FileUploadException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
4.下载操作
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.得到id
String id = request.getParameter("id");
// 2.调用service,得到Resource对象.
ResourceService service = new ResourceService();
try {
Resource r = service.findById(id);
File file = new File(r.getSavepath(), r.getUuidname());
if (file.exists()) {
// 资源存在
String filename = r.getRealname();
// 下载注意事项1--设置下载文件的mimeType
String mimeType = this.getServletContext()
.getMimeType(filename);
response.setContentType(mimeType);
String agent = request.getHeader("user-agent");
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?"
+ base64Encoder.encode(filename.getBytes("utf-8"))
+ "?=";
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
// 下载注意事项2--永远是下载
response.setHeader("content-disposition",
"attachment;filename=" + filename);
byte[] b = FileUtils.readFileToByteArray(file); // 将指定文件读取到byte[]数组中.
response.getOutputStream().write(b);
} else {
throw new RuntimeException("资源不存在");
}
} catch (SQLException e) {
e.printStackTrace();
}
}