JAVAWEB开发之文件的上传与下载(开源组件commons-fileupload的详细使用)
来源:互联网 发布:彩虹六号配件知乎 编辑:程序博客网 时间:2024/06/07 00:28
文件上传简介
1.method=post 只有post才可以携带大数据
2.必须使用<input type='file' name='f'>要有name属性
3.encType="multipart/form-data"
服务器端:
request对象是用于获取请求信息。
它有一个方法 getInputStream(); 可以获取一个字节输入流,通过这个流,可以读取到
所有的请求正文信息.
文件上传原理:
浏览器端注意上述三件事,在服务器端通过流将数据读取到,在对数据进行解析.
将上传文件内容得到,保存在服务器端,就完成了文件上传。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>My JSP 'index.jsp' starting page</title></head><body> <!-- encType 默认是application/x-www-form-urlencoded --><form action="${pageContext.request.contextPath }/upload1"method="POST" enctype="multipart/form-data"><input type="text" name="content"><br><input type="file" name="f"><br> <input type="submit"value="上传"></form></body></html>新建Upload1Servlet 路径:/upload1
package cn.itcast.web.servlet;import java.io.IOException;import java.io.InputStream;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class Upload1Servlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// System.out.println("upload1 servlet......");// 通过request获取一个字节输入流,将所有的请求正文信息读取到,打印到控制台InputStream is = request.getInputStream();byte[] b = new byte[1024];int len = -1;while ((len = is.read(b)) != -1) {System.out.println(new String(b, 0, len));}is.close();}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}在浏览器端访问信息如下:
文件上传概述
- 在web页面中添加上传输入项。
- 在Servlet中读取上传文件的数据,并保存在服务器硬盘中。
- 1、必须设置input输入项的name属性,否则浏览器将不会发送上传文件的数据。
- 2、必须把form的encType属性设为multipart/form-data 设置该值后,浏览器在上传文件时,并把文件数据附带在http请求消息体内,并使用MIME协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理。
- 3、表单的提交方式要设置为post。
- Request对象提供了一个getInputStream方法,通过这个方法可以读取到客户端提交过来的数据。但由于用户可能会同时上传多个文件,在servlet端编程直接读取上传数据,并分别解析出相应的文件数据是一项非常麻烦的工作,示例。
- 为方便用户处理文件上传数据,Apache 开源组织提供了一个用来处理表单文件上传的一个开源组件( Commons-fileupload ),该组件性能优异,并且其API使用极其简单,可以让开发人员轻松实现web文件上传功能,因此在web开发中实现文件上传功能,通常使用Commons-fileupload组件实现。
- 使用Commons-fileupload组件实现文件上传,需要导入该组件相应支撑jar包:Commons-fileupload和commons-io。commo-io不属于文件上传组件的开发jar文件,但Commons-fileupload组件从1.1版本开始,它工作时需要commons-io包的支持。
fileupload组件工作流程和文件上传步骤:
fileupload快速入门:
<form action="${pageContext.request.contextPath}/upload2" method="post" encType="multipart/form-data">
<input type="file" name="f"><br>
<input type="submit" value="上传">
</form>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>My JSP 'index.jsp' starting page</title></head><body> <!-- encType 默认是application/x-www-form-urlencoded --><form action="${pageContext.request.contextPath }/upload2"method="POST" enctype="multipart/form-data"><input type="text" name="content"><br><input type="file" name="f"><br> <input type="submit"value="上传"></form></body></html>创建Upload2Servlet 路径是 /upload2
package cn.itcast.web.servlet;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;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.FileUploadException;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;import org.apache.commons.io.IOUtils;public class Upload2Servlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 1.创建DiskFileItemFactoryDiskFileItemFactory factory = new DiskFileItemFactory();// 2.创建ServletFileUpload upload = new ServletFileUpload(factory);try {// 底层通过request获取数据,进行解析,将解析的数据封装到List<FileItem>List<FileItem> items = upload.parseRequest(request);// 3.遍历集合for (FileItem item : items) {if (item.isFormField()) {// 是表单组件 就得到了 <input type="text" name="content"> 这样的组件// String fieldName = item.getFieldName();// System.out.println(fieldName);// 上传文件的名称// String name = item.getName();// System.out.println(name);// String string = item.getString();// System.out.println(string);} else {// 不是表单组件 这就得到了<input type="file" name="f"> 这样的组件// String fieldName = item.getFieldName();// System.out.println("上传组件的名称: " + fieldName);// 上传文件的名称String name = item.getName();name = name.substring(name.lastIndexOf("\\") + 1);// System.out.println(name);//// String string = item.getString();// System.out.println(string);// 获取上传文件内容,完成文件上传操作// InputStream is = item.getInputStream();// byte[] b = new byte[1024];// int len = -1;FileOutputStream fos = new FileOutputStream("C:/Users/lx/Desktop/upload/" + name);// while ((len = is.read(b)) != -1) {// // System.out.println(new String(b, 0, len));// fos.write(b, 0, len);// }// fos.close();// is.close();IOUtils.copy(item.getInputStream(), fos);}}} catch (FileUploadException e) {e.printStackTrace();}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}deploy 访问upload2.jsp 上传文件 运行结果如下图所示:
在浏览器端查捕捉请求正文信息如下:
FileUpload核心API
DiskFileItemFactory
DiskFileItemFactory是创建FileItem对象的工厂
repository:临时文件存储位置
public void setRepository(java.io.File repository)
指定临时文件目录,默认值为System.getProperty("java.io.tmpdir").
ServletFileUpload
用于判断是否是上传.
可以简单理解,就是判断encType="multipart/form-data";
(4)设置上传文件大小
void setFileSizeMax(long fileSizeMax) 设置单个文件上传大小
void setSizeMax(long sizeMax) 设置总文件上传大小
(5)解决上传文件中文名称乱码
void setHeaderEncoding("utf-8");
注意:如果使用reqeust.setCharacterEncoding("utf-8")也可以,但不建议使用。
FileItem
用于判断是否是上传组件.
如果是<input type="file">返回的就是false,否则返回true.
(2)getFieldName();
返回值String,得到组件名称 <input name="">
(3)getName();
返回值是String,得到的是上传文件的名称.
注意:浏览器不同,它们得到的效果不一样。
1.包含全路径名称 例如: C:\Users\Administrator\Desktop\a.txt
2.只包含上传文件名称 例如:a.txt
(4)getString();
这个方法可以获取非上传组件的内容,相当于 getParameter方法作用。
问题:如果信息是中文,会出现乱码,解决方案 getString("utf-8");
如果是上传组件,上传的文件是文本文件,可以获取到文件文件的内容。
但是如果不是文件文件,例如:是一张图片,是二进制文件 就不合适了。
(5)获取上传文件的内容,保存到服务器端.
item.getInputStream();它是用于读取上传文件内容的输入流.
使用文件复制操作就可以完成文件上传。
(6)删除临时文件
item.delete();
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>My JSP 'index.jsp' starting page</title></head><body> <!-- encType 默认是application/x-www-form-urlencoded --><form action="${pageContext.request.contextPath }/upload3"method="POST" enctype="multipart/form-data"><input type="text" name="content"><br><input type="file" name="f"><br> <input type="submit"value="上传"></form></body></html>
package cn.itcast.web.servlet;import java.io.File;import java.io.FileOutputStream;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.FileUploadException;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;import org.apache.commons.io.IOUtils;//commons-fileupload api详解@SuppressWarnings("all")// 去除所有警告public class Upload3Servlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");// 1.创建DiskFileItemFactory// DiskFileItemFactory factory = new DiskFileItemFactory(); // 使用默认的File file = new File(this.getServletContext().getRealPath("/temp"));// 获取temp目录部署到tomcat后的绝对磁盘路径DiskFileItemFactory factory = new DiskFileItemFactory(1024 * 100, file);// 2.创建ServletFileUploadServletFileUpload upload = new ServletFileUpload(factory);// 判断是否是上传操作(即检测encType是否为"multipart/form-data")boolean flag = upload.isMultipartContent(request);if (flag) {// 解决上传文件中文名称乱码// 注意:也可以使用request.setCharacterEncoding("utf-8"); 不建议使用upload.setHeaderEncoding("utf-8");// 设置上传文件大小//upload.setSizeMax(1024*1024*10); // 设置文件总大小为10Mtry {List<FileItem> items = upload.parseRequest(request);// 解析request,得到所有上传项FileItem// 3.得到所有上传项for (FileItem item : items) {if (item.isFormField()) { // 判断是否是上传组件 如果是上传组件就返回false// 非上传组件System.out.println("组件名称:" + item.getFieldName());System.out.println("内容:" + item.getString("utf-8"));} else {// 上传组件System.out.println("非上传组件:" + item.getFieldName());System.out.println("上传文件名:" + item.getName());String name = item.getName(); // 上传文件名name = name.substring(name.lastIndexOf("\\") + 1);IOUtils.copy(item.getInputStream(),new FileOutputStream("c:/Users/lx/Desktop/upload/" + name));// 删除临时文件item.delete();}}} catch (FileUploadException e) {// e.printStackTrace();response.getWriter().write(e.getMessage());}} else {response.getWriter().write("不是上传操作");return;}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
多文件上传时的JS编码
每次动态增加一个文件上传输入框,都把它和删除按纽放置在一个单独的div中,并对删除按纽的onclick事件进行响应,使之删除删除按纽所在的div。
如:this.parentNode.parentNode.removeChild(this.parentNode);
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>多文件上传</title><script type="text/javascript">function addFile() {var div = document.getElementById("content");div.innerHTML += "<div><input type='file' name='f'><input type='button' value='remove file' onclick='removeFile(this)'></div>";}function removeFile(btn) {document.getElementById("content").removeChild(btn.parentNode);}</script></head><body><input type="button" value="add File" onclick="addFile();"><br><form action="${pageContext.request.contextPath }/upload3"method="POST" enctype="multipart/form-data"><input type="file" name="f"><br><div id="content"></div><input type="submit" value="上传"></form></body></html>运行结果如下:
关于文件上传的注意事项:
事项一:上传文件在服务器端保存位置问题
事项二:上传文件在同一目录重名问题
- 使用当前的毫秒值
- 或使用UUID工具类生成随机字符串
事项三:同一目录下文件过多
// 获得唯一文件名的hashcode
int hashcode = uuidFileName.hashCode();
// 获得一级目录
int d1 = hashcode & 0xf;
// 获得二级目录
int d2 = (hashcode >>> 4) & 0xf;
return "/" + d2 + "/" + d1;// 共有256目录l
}
package cn.itcast.utils;import java.io.File;import java.util.UUID;public class FileUploadUtils {// 得到上传文件真实名称 c:\a.txt a.txt// 如果参数为c:\a.txt 得到a.txt 如果为a.txt index=-1+1=0; 仍然正确public static String getRealName(String filename) {int index = filename.lastIndexOf("\\") + 1;return filename.substring(index);}// 获取随机名称public static String getUUIDFileName(String filename) {int index = filename.lastIndexOf(".");if (index != -1) {return UUID.randomUUID() + filename.substring(index);} else {return UUID.randomUUID().toString();}}// 目录分离算法public static String getRandomDirectory(String filename) {// 方式一:int hashcode = filename.hashCode();System.out.println(hashcode);// int数据类型在内存中占32位字节,转换成16进制数(4位),就得到8个16进制数String hex = Integer.toHexString(hashcode);System.out.println(hex);return "/" + hex.charAt(0) + "/" + hex.charAt(1);/* * 方式二: int hashcode = filename.hashCode(); * * System.out.println(Integer.toBinaryString(hashcode)); * * int a = hashcode & 0xf; * * hashcode = hashcode >>> 4; * * int b = hashcode & 0xf; * * return "/" + a + "/" + b; */}/* * public static void main(String[] args) { String path = * getRandomDirectory("a.txt"); * * File file = new File("C:/Users/lx/Desktop/upload"); File directory = new * File(file, path); if (!directory.exists()) { directory.mkdirs(); } } */}
package cn.itcast.web.servlet;import java.io.File;import java.io.FileOutputStream;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.FileUploadException;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;import org.apache.commons.io.IOUtils;import cn.itcast.utils.FileUploadUtils;public class Upload4Servlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");// 1.创建DiskFileItemFactoryFile file = new File(this.getServletContext().getRealPath("/temp"));// 获取temp目录部署到tomcat后的绝对磁盘路径DiskFileItemFactory factory = new DiskFileItemFactory(1024 * 100, file);// 2.创建ServletFileUploadServletFileUpload upload = new ServletFileUpload(factory);// 判断是否是上传操作(即检测encType是否为"multipart/form-data")boolean flag = upload.isMultipartContent(request);if (flag) {// 解决上传文件中文名称乱码// 注意:也可以使用request.setCharacterEncoding("utf-8"); 不建议使用upload.setHeaderEncoding("utf-8");// 设置上传文件大小// upload.setSizeMax(1024*1024*10); // 设置文件总大小为10Mtry {List<FileItem> 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);// 注意:随机目录可能不存在,需要创建File rd = new File("C:/Users/lx/Desktop/upload/",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());}} else {response.getWriter().write("不是上传操作");return;}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}运行如下:
文件下载
(1)超连接下载
download1.jsp<a href='${pageContext.request.contextPath}/upload/a.jpg'>a.jpg</a><br>
<a href='${pageContext.request.contextPath}/upload/a.docx'>a.docx</a><br>
<a href='${pageContext.request.contextPath}/upload/a.txt'>a.txt</a><br>
<a href='${pageContext.request.contextPath}/upload/就算没有如果.flac'>就算没有如果.flac</a><br>
注意:如果文件可以直接被浏览器解析,那么会在浏览器中直接打开,不能被浏览器直接解析,就是下载操作。
直接打开的要想下载 ,右键另存为。
超连接下载,要求下载 的资源,必须是可以直接被浏览器直接访问的。
客户端访问服务器静态资源文件时,静态资源文件是通过 缺省Servlet返回的,
在tomcat配置文件conf/web.xml 找到 --- org.apache.catalina.servlets.DefaultServlet
(2)在服务器端编程完成下载.
1.创建download2.jsp<a href='${pageContext.request.contextPath}/download?filename=a.jpg'>a.jpg</a><br>
<a href='${pageContext.request.contextPath}/download?filename=a.docx'>a.docx</a><br>
<a href='${pageContext.request.contextPath}/download?filename=a.txt'>a.txt</a><br>
<a href='${pageContext.request.contextPath}/download?filename=就算没有如果.flac'>就算没有如果.flac</a><br>
2.创建DownloadServlet
// 1.得到要下载 的文件名称
String filename = request.getParameter("filename");
//2.判断文件是否存在
File file = new File("d:/upload/" + filename);
if (file.exists())
//3.进行下载
原理:就是通过response获取一个输出流,将要下载的文件内容写回到浏览器端就可以了.
1.要设置mimetype类型
resposne.setContextType(String mimeType);
问题:怎样可以得到要下载文件的mimeType类型?
ServletContext.getMimeType(String filename);
如果设置了mimeType,浏览器能解析的就直接展示了,不能解析的,直接下载.
2.设置一个响应头,设置后的效果,就是无论返回的是否可以被浏览器解析,就是下载 。
response.setHeader("content-disposition","attachment;filename=下载文件名称");
总结:服务器端编程下载:
1.将下载的文件通过resposne.getOutputStream()流写回到浏览器端。
2.设置mimeType response.setContentType(getServletContext.getMimeType(String filename));
3.设置响应头,目的是永远是下载操作
response.setHeader("content-disposition","attachment;filename=下载文件名称");
(3)文件下载时的乱码问题:
下载乱码一:关于下载时中文名称资源查找不到
原因:<a href='${pageContext.request.contextPath}/download?filename=就算没有如果.flac'>就算没有如果.flac</a>这是get请求。
在服务器端需要做如下处理:
String filename = request.getParameter("filename");
解决: new String(filename.getBytes("iso8859-1"),"utf-8");
下载乱码二:下载文件显示时的中文乱码问题
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");
}
代码示例:浏览器端超链接下载
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> <a href='${pageContext.request.contextPath}/upload/a.jpg'>a.png</a><br><a href='${pageContext.request.contextPath}/upload/a.docx'>a.docx</a><br><a href='${pageContext.request.contextPath}/upload/a.txt'>a.txt</a><br><a href='${pageContext.request.contextPath}/upload/就算没有如果.flac'>就算没有如果.flac</a><br> </body></html>
代码示例:服务器端下载
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> <a href='${pageContext.request.contextPath}/download?filename=a.jpg'>a.jpg</a><br><a href='${pageContext.request.contextPath}/download?filename=a.docx'>a.docx</a><br><a href='${pageContext.request.contextPath}/download?filename=a.txt'>a.txt</a><br><a href='${pageContext.request.contextPath}/download?filename=就算没有如果.flac'>就算没有如果.flac</a><br> </body></html>新建DownloadServlet
package cn.liuxun.web.servlet;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.OutputStream;import java.net.URLEncoder;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import sun.misc.BASE64Encoder;public class DownloadServlet extends HttpServlet {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.在c:/Users/lx/Desktop/upload目录下查找这个文件是否存在File file = new File("c:/Users/lx/Desktop/upload", filename);if (file.exists()) {// 文件存在,完成下载// 下载注意事项1--设置下载文件的mimeTypeString 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("下载资源不存在");}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
遍历文件夹操作
<%@page import="java.io.File"%><%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>使用递归完成下载upload目录下的所有文件</title></head><body><!-- 使用递归操作 --><%!//声明一个方法public void getFile(File file) {if (file.isDirectory()) { //是目录File[] fs = file.listFiles();for (int i = 0; i < fs.length; i++) {getFile(fs[i]); //递归调用}} else if (file.isFile()) { //是文件System.out.println(file.getName()+" 路径:"+file.getPath());}}%><%String path = application.getRealPath("/upload");File uploadDirectory = new File(path);getFile(uploadDirectory);%></body></html>
在jdk中有一个接口Queue 它有一个实现类叫LinkedList它其时就是一个队列。
如果要使用队列,插入 offer 获取使用 poll
- 因为:递归操作可以理解成是纵向的遍历,如果目录层次比较多,在内存中存储的数据也多,会引起溢出。
- 使用队列,它是横向遍历,一层一层遍历,可以解决目录层次比较多问题。
- 因为使用队列,最多时候在内存中只存储了一层的信息
<%@page import="java.io.File"%><%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>使用队列来完成下载upload目录下所有文件</title> </head> <body> <!-- 使用队列操作 --> <% String path=application.getRealPath("/upload"); File uploadDirectory=new File(path); //创建一个队列 Queue<File> queue=new LinkedList<File>(); 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("<a href='"+application.getContextPath()+p+"'>"+f.getName()+"</a><br>"); } } %> </body></html>访问如下:
网盘系统(实例演示上传和下载)
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));
BeanUtils:commons-beanutils-1.8.3.jar、commons-logging-1.1.1.jar
DbUtils:commons-dbutils-1.4.jar
FileUpload:commons-fileupload-1.2.1.jar、commons-io-1.4.jar
JSTL:jstl.jar、standard.jar
MySQL驱动:mysql-connector-java-5.1.28-bin.jar
(3)编码实现上传
1.在index.jsp页面添加上传连接
<a href='${pageContext.request.contextPath}/upload.jsp'>上传</a><br>
2.创建upload.jsp页面
上传操作浏览器端三个注意事项:
1.method=post
2.encType="multipart/form-data"
3.要使用<input type="file" name='f'>
<form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
<input type="file" name="f"><br>
描述:<input type="text" name="description"><br>
<input type="submit" value="提交">
</form>
3.创建UploadServlet
1.完成上传操作
2.将数据封装,存储到数据库。
1.上传操作
commons-fileupload
1.DiskFileItemFactory
2.ServletFileUpload
3.FileItem
2.将数据封装,存储到数据库.
问题:怎样将数据封装到javaBean?
手动创建一个Map<String,String[]>将数据封装到map集合,
通过BeanUtils完成数据封装.
(4)下载操作
1.在index.jsp页面,下载连接会访问一个servlet,得到所有可以下载的数据,在页面上展示 .
1.index.jsp页面代码
<a href="${pageContext.request.contextPath}/showDownload">下载</a>
2.创建ShowDownloadServlet
在这个servlet中,查看db,得到所有可以下载的信息.
List<Resource> rs = service.findAll();
3.创建一个download.jsp页面,展示所有可以下载的信息.
2.在download.jsp,点击下载时,传递的是要下载文件的id。
<a href='${pageContext.request.contextPath}/download?id=${r.id}'>下载</a>
1.创建一个DownloadServlet
1.查询数据库,得到要下载的文件的相关信息
2.下载操作
该项目目录图如下:
---
具体代码如下:
添加数据源配置c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?><c3p0-config><default-config><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql:///mydb1</property><property name="user">root</property><property name="password">root</property></default-config></c3p0-config>新建工具类DataSourceUtils 获取连接池中的数据源
package cn.liuxun.utils;import java.sql.Connection;import java.sql.SQLException;import javax.sql.DataSource;import com.mchange.v2.c3p0.ComboPooledDataSource;public class DataSourceUtils {private static ComboPooledDataSource cpds = new ComboPooledDataSource();public static Connection getConnection() throws SQLException {return cpds.getConnection();}public static DataSource getDataSource() {return cpds;}}新建工具类FileUploadUtils获取 文件真实名称、随机名称以及 目录分离中的随机目录
package cn.liuxun.utils;import java.util.UUID;public class FileUploadUtils {// 得到上传文件真实名称 c:\a.txt a.txtpublic static String getRealName(String filename) {int index = filename.lastIndexOf("\\") + 1;return filename.substring(index);}// 获取随机名称public static String getUUIDFileName(String filename) {int index = filename.lastIndexOf(".");if (index != -1) {return UUID.randomUUID() + filename.substring(index);} else {return UUID.randomUUID().toString();}}// 目录分离算法public static String getRandomDirectory(String filename) {int hashcode = filename.hashCode();System.out.println(Integer.toBinaryString(hashcode));int a = hashcode & 0xf;hashcode = hashcode >>> 4;int b = hashcode & 0xf;return "/"+a+"/"+b;}}
新建Bean类Resource
package cn.liuxun.domain;import java.sql.Timestamp;public class Resource {// 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)private int id;private String uuidname;private String realname;private String savepath;private Timestamp uploadtime;private String description;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUuidname() {return uuidname;}public void setUuidname(String uuidname) {this.uuidname = uuidname;}public String getRealname() {return realname;}public void setRealname(String realname) {this.realname = realname;}public String getSavepath() {return savepath;}public void setSavepath(String savepath) {this.savepath = savepath;}public Timestamp getUploadtime() {return uploadtime;}public void setUploadtime(Timestamp uploadtime) {this.uploadtime = uploadtime;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}}
package cn.liuxun.dao;import java.sql.SQLException;import java.util.List;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.BeanHandler;import org.apache.commons.dbutils.handlers.BeanListHandler;import cn.liuxun.domain.Resource;import cn.liuxun.utils.DataSourceUtils;public class ResourceDao {public List<Resource> findAll() throws SQLException {QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());return runner.query("select * from resources",new BeanListHandler<Resource>(Resource.class));}public void save(Resource r) throws SQLException {String sql = "insert into resources values(null,?,?,?,null,?)";QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());runner.update(sql, r.getUuidname(), r.getRealname(), r.getSavepath(),r.getDescription());}public Resource findById(String id) throws SQLException {QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());return runner.query("select * from resources where id=?",new BeanHandler<Resource>(Resource.class), id);}}
新建service类 ResourceService类
package cn.liuxun.service;import java.sql.SQLException;import java.util.List;import cn.liuxun.dao.ResourceDao;import cn.liuxun.domain.Resource;public class ResourceService {public List<Resource> findAll() throws SQLException { return new ResourceDao().findAll();}public void save(Resource r) throws SQLException {new ResourceDao().save(r);}public Resource findById(String id) throws SQLException { return new ResourceDao().findById(id);}}
新建Servlet类DownloadServlet 用于下载网盘文件
package cn.liuxun.web.servlet;import java.io.File;import java.io.IOException;import java.net.URLEncoder;import java.sql.SQLException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.io.FileUtils;import sun.misc.BASE64Encoder;import cn.liuxun.domain.Resource;import cn.liuxun.service.ResourceService;public class DownloadServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 1.得到idString 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 -- 设置下载文件的mimeTypeString 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 {}} catch (SQLException e) {e.printStackTrace();}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
新建下载列表展示类ShowDownloadServlet
package cn.liuxun.web.servlet;import java.io.IOException;import java.sql.SQLException;import java.util.List;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import cn.liuxun.domain.Resource;import cn.liuxun.service.ResourceService;public class ShowDownloadServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {ResourceService service = new ResourceService();try {List<Resource> rs = service.findAll();request.setAttribute("rs", rs);request.getRequestDispatcher("/download.jsp").forward(request,response);} catch (SQLException e) {e.printStackTrace();}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
新建UploadServlet类 用于上传文件
package cn.liuxun.web.servlet;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.lang.reflect.InvocationTargetException;import java.sql.SQLException;import java.util.HashMap;import java.util.List;import java.util.Map;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.beanutils.BeanUtils;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;import org.apache.commons.io.IOUtils;import cn.liuxun.domain.Resource;import cn.liuxun.service.ResourceService;import cn.liuxun.utils.FileUploadUtils;public class UploadServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {Map<String, String[]> map = new HashMap<String, String[]>();// 1.创建DiskFileItemFactoryDiskFileItemFactory factory = new DiskFileItemFactory();// 2.创建ServletFileUploadServletFileUpload upload = new ServletFileUpload(factory);// 设置上传中文名称乱码upload.setHeaderEncoding("utf-8");// upload.isMultipartContent(request);// 3.得到所有的FileItemtry {List<FileItem> 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();}}// 将数据封装到JavaBeanResource r = new Resource();BeanUtils.populate(r, map);// 调用service完成保存数据到dbResourceService service = new ResourceService();service.save(r);} catch (FileUploadException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
新建JSP页面
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> <a href="${pageContext.request.contextPath }/upload.jsp">上传</a> <a href="${pageContext.request.contextPath }/showDownload">下载</a> </body></html>
upload.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>My JSP 'index.jsp' starting page</title></head><body><form action="${pageContext.request.contextPath }/upload" method="post"enctype="multipart/form-data"><input type="file" name="f"> <br>描述:<input type="text" name="description"><br> <input type="submit" value="提交"></form></body></html>
download.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>My JSP 'index.jsp' starting page</title></head><body><table border="1" align="center" width="65%"><tr><td>文件名称</td><td>文件描述</td><td>下载操作</td></tr><c:forEach items="${rs }" var="r"><tr><td>${r.realname }</td><td>${r.description }</td><td><ahref="${pageContext.request.contextPath }/download?id=${r.id}">下载</a></td></tr></c:forEach></table></body></html>
打开发布后的文件夹
OK
注意:此网盘文件内容是保存在项目中的 如果重新部署项目 文件就会丢失
在重新部署项目之前需要将upload文件夹进行备份
- JAVAWEB开发之文件的上传与下载(开源组件commons-fileupload的详细使用)
- java利用commons-fileupload组件实现文件的上传与下载
- 使用Commons-fileupload组件实现文件上传的注意细节
- 文件上传与下载(Commons-fileupload)
- ---JavaWeb文件上传(commons-fileupload-x.x.x.jar的使用)
- commons-fileupload上传文件的使用
- 使用commons-fileupload实现文件的上传
- 使用commons-fileupload的文件上传
- commons-fileupload的详细介绍与使用
- commons-fileupload的详细介绍与使用
- commons-fileupload的详细介绍与使用
- 使用Commons-fileupload组件实现文件上传
- 使用Commons-fileupload组件实现文件上传
- 使用commons-fileupload组件实现文件上传
- 使用commons-fileupload组件上传文件
- 使用Commons-fileupload组件实现文件下载
- Commons-fileupload 文件的上传
- 文件上传组件 FileUpload组件的使用
- Oracle存储过程实例
- UML建模之活动图介绍(Activity Diagram)
- 算法的力量万变不离其宗
- 银联接入--android热点问题解析
- ionic ng-model controller中取不到值(input)
- JAVAWEB开发之文件的上传与下载(开源组件commons-fileupload的详细使用)
- java的(PO,VO,TO,BO,DAO,POJO)解释
- 创建很多子窗口1,再在子窗口1创建子窗口2
- UML建模之状态图(Statechart Diagram)
- UML建模之部署图(Deployment Diagram)
- MySQL锁表解决方法
- Drupal—关于Drupal8的详细安装建站教程
- 48:Longest Common Prefix
- 百度有钱花陷“培训贷”漩涡 回应称将按法律要求解决纠纷