文件上传简介
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.创建DiskFileItemFactory
DiskFileItemFactory 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.创建ServletFileUpload
ServletFileUpload 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); // 设置文件总大小为10M
try {
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' οnclick='removeFile(this)'></div>";
}
function removeFile(btn) {
document.getElementById("content").removeChild(btn.parentNode);
}
</script>
</head>
<body>
<input type="button" value="add File" οnclick="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.创建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);
// 判断是否是上传操作(即检测encType是否为"multipart/form-data")
boolean flag = upload.isMultipartContent(request);
if (flag) {
// 解决上传文件中文名称乱码
// 注意:也可以使用request.setCharacterEncoding("utf-8"); 不建议使用
upload.setHeaderEncoding("utf-8");
// 设置上传文件大小
// upload.setSizeMax(1024*1024*10); // 设置文件总大小为10M
try {
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--设置下载文件的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("下载资源不存在");
}
}
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.txt
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(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.得到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 {
}
} 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.创建DiskFileItemFactory
DiskFileItemFactory factory = new DiskFileItemFactory();
// 2.创建ServletFileUpload
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置上传中文名称乱码
upload.setHeaderEncoding("utf-8");
// upload.isMultipartContent(request);
// 3.得到所有的FileItem
try {
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();
}
}
// 将数据封装到JavaBean
Resource r = new Resource();
BeanUtils.populate(r, map);
// 调用service完成保存数据到db
ResourceService 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><a
href="${pageContext.request.contextPath }/download?id=${r.id}">下载</a></td>
</tr>
</c:forEach>
</table>
</body>
</html>
打开发布后的文件夹
OK
注意:此网盘文件内容是保存在项目中的 如果重新部署项目 文件就会丢失
在重新部署项目之前需要将upload文件夹进行备份