标签:
文档版本 | 开发工具 | 测试平台 | 工程名字 | 日期 | 作者 | 备注 |
---|---|---|---|---|---|---|
V1.0 | 2016.06.05 | lutianfei | none |
<context-param>
servletContext的初始化参数.问题:什么是文件上传?为什么使用文件上传?
文件上传的本质:就是IO流的操作。
实现web开发中的文件上传功能,需完成如下二步操作:
如何在web页面中添加上传输入项?
<input type=“file”>
标签用于在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工具.<form action="${pageContext.request.contextPath}/upload2" method="post" encType="multipart/form-data">
<input type="file" name="f"><br>
<input type="submit" value="上传">
</form>
DiskFileItemFactory factory=new DiskFileItemFactory();
ServletFileUpload upload=new ServletFileUpload(factory);
List<FileItem> items = upload.parseRequest(request);
3.遍历items集合,集合中的每一项,就是一个上传数据
isFormField
(); getFieldName
(); 组件名称
<input name="">
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<FileItem>
setFileSizeMax
(long fileSizeMax) 设置单个文件上传大小 setSizeMax
(long sizeMax) 设置总文件上传大小 setHeaderEncoding
(java.lang.String encoding) 设置编码集 解决上传文件名乱码 setProgressListener
(ProgressListener pListener)实时监听文件上传状态3、FileItem
表示文件上传表单中 每个数据部分,用来表示文件上传表单中的一个上传文件对象或者普通表单对象
isFormField
() 判断该数据项是否为文件上传项,true 不是文件上传 false 是文件上传 getFieldName
() 获得普通表单对象的name属性<input 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+="<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>
<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<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);
// 注意:随机目录可能不存在,需要创建.
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.bmp</a><br>
<a href=‘${pageContext.request.contextPath}/upload/a.doc‘>a.doc</a><br>
<a href=‘${pageContext.request.contextPath}/upload/a.txt‘>a.txt</a><br>
<a href=‘${pageContext.request.contextPath}/upload/tk.mp3‘>tk.mp3</a><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.bmp</a><br>
<a href=‘${pageContext.request.contextPath}/download?filename=a.doc‘>a.doc</a><br>
<a href=‘${pageContext.request.contextPath}/download?filename=a.txt‘>a.txt</a><br>
<a href=‘${pageContext.request.contextPath}/download?filename=tk.mp3‘>tk.mp3</a><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.关于下载时中文名称资源查找不到
<a href=‘${pageContext.request.contextPath}/download?filename=天空.mp3‘>天空.mp3</a>
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<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=‘/day22_2"+p+"‘>"+f.getName()+"</a><br>");
}
}
%>
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.编码实现上传
<a href=‘${pageContext.request.contextPath}/upload.jsp‘>上传</a><br>
method=post
encType="multipart/form-data"
<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.上传操作
* commons-fileupload
* 1.DiskFileItemFactory
* 2.ServletFileUpload
* 3.FileItem
* 2.将数据封装,存储到数据库.
* 问题:怎样将数据封装到javaBean?
* 手动创建一个Map<String,String[]>将数据封装到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<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);
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.下载操作
<a href="${pageContext.request.contextPath}/showDownload">下载</a>
List<Resource> rs = service.findAll();
2.在download.jsp,点击下载时,传递的是要下载文件的id。
<a href=‘${pageContext.request.contextPath}/download?id=${r.id}‘>下载</a>
3.创建一个DownloadServlet
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();
}
}
标签:
原文地址:http://blog.csdn.net/lutianfeiml/article/details/51611210