本文用到的jar包:
文件上传:commons-fileupload-1.2.1.jar;
commons-io-1.4.jar;
本文需要掌握的知识:html+dom
1 文件的上传概述;
1.1 用户把本地的文件储存到服务器上,就是文件的上传;
1.2 实现文件的上传(目前而言要使用第三方jar包);
1.2.1 jspSmartupload;
适用范围:应用在jsp的模型一里(嵌入执行上传下载操作的JSP文件中) ;
1.2.2 fileUpload;
来源:Apache commons下面的开源,免费项目(谢谢老板);
适用范围:(mvc模式);
1.3 要使用文件的上传,需要满足三个要求:
①表单数据提交,提交方式为post提交;
②在表单里有一个文件的上传想<input type=”file” name=”filename”/>
③在form里面,要设置一个属性值,enctype,设置为multipart/form-data(必须设置,不然只有一个文件名之类的)
2 文件上传的原理分析:
从请求响应信息可知;
Content-Type:multipart/form-data;
通过请求正文可以得到结论:
①找到分割线;
②根据分割线区别不同的项;
③普通输入项得到的是值;
④文件上传项,得到文件的内容,把内容写到服务器里面一个文件中;
⑤使用输入流得到文件上传的内容,使用输出流把文件的内容写到服务器上;
3,文件上传的代码实现的步骤(固定步骤,照着写就可以了);
3.1 :创建磁盘文件工厂;
new DiskFileItemFactory();
3.2:创建核心上传类;
new ServletFileUpload(FileItemFactory fileItemFactory);
3.3:使用核心上传类解析request对象;
parseRequest(-----request(全类名就不写了));
返回的是一个List集合,集合中有多个FileItem,泛型为<FileItem>;
3.4:遍历list集合,得到每个FileItem;
3.5:判断是普通输入项还是文件上传项;
Boolean isFormField();
3.6:如果是普通输入项;如果是文件上传项编写文件上传的代码;
普通输入项:
getField():得到普通输入项name的值;
getString():得到普通输入项里面输入的值;
文件上传项:
得到通过表单提交的文件的输入流,getInputStream;
创建输出流,写出文件到服务器的相应的位置(输出位置要带有盘符,通过
getServletContext().getRealPath(相对路径)可以获取.为什么要这样做,是因为项目在别的服务器上真实路径就不一定一致了,所以要通过相对路径获取到真实路径);
4,核心API的学习(主要是一些重要的方法);
4.1 DiskFileItemFactory(磁盘文件项工厂)(核心上传类,重点在于构造);
构造方法;
DiskFileItemFactory(int sizeThreshold,java.io.File repository);
两个参数:
第一个参数设置上传文件缓冲区的大小;
第二个参数.如果上传文件超出了缓冲区,产生临时文件,设置临时文件路径
(可以看做是先用一个等大小的临时文件做占位,然后数据一步步填充);
DiskFileItemFactory() 无参构造,也可以设置缓冲区;
setSizeThreadshold(int sizeThreadshold):设置上传文件的缓冲区(单位是字节byte);
setRepository(java.io.File repository):设置临时文件路径;
4.2 ServletFileUpload:核心上传类;
构造方法;
ServletFileUpload(FileItemFactory fileItemFactory);
重要方法:;
parseRequest(javax.servlet.HttpServletRequest request):解析request对象;
返回一个list<FileItem>集合,每一个元素都是一个FileItem;
在他的父类中还有一个很重要的方法;
setHeaderEncoding(java.lang.String encoding);设置上传文件名称的编码;
setFileSizeMax(long filesizeMax)”:设置单个文件的大小;
setSIzeMax(long sizeMax): 设置单个文件的总大小;
4.3 FileItem:文件项
Boolea isFormField():判断是否是普通输入项;
getFieldName():得到普通输入项.name的属性值;
getString():得到普通输入项的文本值;
getString(encoding):设置输入项中文本的编码;
getName():得到上传文件的名称(但是有些浏览器得到的带路径的名称,所以要进行截取操作,哭);
getInputStream():得到表单提交的文件输入流;
Delete():删除临时文件(要在关闭流之后删除);
5 JS控制多文件的上传
5.1 需求:在上传的表单里面有两个按钮,一个是上传文件的按钮,一个是增加的按钮,增加上传项.
点击增加按钮之后,增加一行,一个上传输入项和一个删除的按钮
点击删除按钮之后,删除该行
点击上传按钮之后,把当前的文件上传到服务器里面去
5.2 使用js增加一行和删除一行
<script type="text/javascript">
//增加一行
function addFile(){
//在table里面增加一行
var table = document.getElementsByTagName("table")[0];
table.innerHTML+="<tr><td><input type='file' name='filename'/></td><td><input type='button' value='删除' onclick='dele(this)'/><td/><tr/> ";
}
//删除一行
function dele(who){
//获取当前点击的删除按钮所在的tr
var tr=who.parentNode.parentNode;
//拿到爸爸
var table=tr.parentNode;
//通过爸爸删除儿子
table.removeChild(tr);
}
</script>
5.3 使用button提交表单的方法
//通过按钮提交表单实现上传
function uploadFile(){
var form =document.getElementsByTagName("form")[0];
form.submit();
}
5.4 常见问题的解决:
5.4.1 当已经存在名字重复的文件,再次上传会新文件覆盖原文件
解决方式:在上传的文件名称里添加一个随机的唯一的字符串,保证每个文件都是唯一的值(可以通过uuid生成,也可以使用毫秒数,不过推荐用uuid更加保险
//生成一个随机的唯一的id值
String id = UUID.randomUUID().toString();
JSP页面(为什么我没找到jsp代码选择)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <form action="${pageContext.request.contextPath }/servlet/Upload2" method="post" enctype="multipart/form-data"> <input type="button" value="上传" onclick="uploadFile()"/> <input type="button" value="增加" onclick="addFile()"/><hr/> <table> </table> <%-- <input type="file" name="filename"/><input type="button" value="删除"/> --%></form> </body> <script type="text/javascript"> //通过按钮提交表单实现上传 function uploadFile(){ var form =document.getElementsByTagName("form")[0]; form.submit(); } //增加一行 function addFile(){ //在table里面增加一行 var table = document.getElementsByTagName("table")[0]; table.innerHTML+="<tr><td><input type='file' name='filename'/></td><td><input type='button' value='删除' onclick='dele(this)'/><td/><tr/> "; } //删除一行 function dele(who){ //获取当前点击的删除按钮所在的tr var tr=who.parentNode.parentNode; //拿到爸爸 var table=tr.parentNode; //通过爸爸删除儿子 table.removeChild(tr); } </script> </html>
servlet处理页面(对应的图片文件就不放上来了)
package com.zzx.upload; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; 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.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class Upload2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { //1,創建磁盤文件工廠 DiskFileItemFactory dff = new DiskFileItemFactory(); //2,創建核心上傳類 ServletFileUpload fileupload = new ServletFileUpload(dff); fileupload.setHeaderEncoding("utf-8"); //3,解析对应的请求数据 List<FileItem> fl = fileupload.parseRequest(request); for (FileItem fileItem : fl) { //判断是否是普通输入项 if(fileItem.isFormField()){ //如果是普通输入项,就得到普通输入项name的属性值,和输入的值 String name = fileItem.getFieldName(); String value = fileItem.getString(); System.out.println(name + ":" + value); }else{ //如果是文件上传项 //获取上传的文件名称,但是有的浏览器里面带的是带路径的名称 String filename = fileItem.getName(); //优化,判断是否带/,如果带"/"就进行截取,否则就直接用 int lens=filename.lastIndexOf("/"); if(lens!=-1){ filename=filename.substring(lens+1); } //获取文件上传的输入流 InputStream is =fileItem.getInputStream(); //得到文件夹带盘符的路径 String path = getServletContext().getRealPath("/upload"); //输出流 OutputStream os =new FileOutputStream(path + "/" + filename); //流对接 int len=0; byte[]arr =new byte[1024*8]; while((len = is.read(arr))!=-1){ os.write(arr,0,len); } //关流 is.close(); os.close(); } } } catch (Exception e) { e.printStackTrace(); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
6 文件的下载:
6.1 把服务器上文件保存到本地硬盘,这个过程称为文件的下载
6.2 文件下载的实现方式:
6.2.1: 实现超链接的文件下载
弊端:有的文件无法实现下载,而是显示在页面上(比如图片)
6.2.2: 通过代码实现文件下载
无论什么格式的文件都可以下载
实现步骤:
第0步:设置要下载的文件MIME类型(可选)
第一步:设置头信息,Content-Disposition,无论什么格式,都是以下载的方法打开
第二步:服务器得到文件的输入流
第三步:创建输出流,写出到浏览器
第四步:流对接
具体代码:
6.3 常见问题:
6.3.1 当文件名携带中文的时候(中文名称会乱码,不显示之类的问题)
6.3.2 原因:不同浏览器编码不同
ie浏览器采用的是url编码,
火狐浏览器采用的是base64编码,
6.3. 3 ① 区分不同的浏览器
通过请求头 User-Agent,得到当前浏览器的请求类型
②根据不同的浏览器设置不同的编码(IE,谷歌解决方式一致)
这里是文件下载的页面
package com.zzx.down; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; 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; import com.sun.xml.internal.messaging.saaj.util.Base64; /* * 这个页面是实现文件的下载 */ public class DownServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //0,得到文件的路径 String path = getServletContext().getRealPath("/down/图片.jpg"); //得到文件名 //这里寻找"/"要注意使用"\"才能正确的截取 String filename = path.substring(path.lastIndexOf("\")+1); //得到请求的浏览器类型 String agent = request.getHeader("User-Agent"); //判断浏览器类型 System.out.println(agent); if(agent.contains("Firefox")){ //如果是火狐,进行base64编码 filename = "=?UTF-8?B?"+new BASE64Encoder().encode(filename.getBytes("utf-8")) + "?="; }else{ //url编码,谷歌,IE都可以通过这样设置 filename=URLEncoder.encode(filename, "UTF-8"); } //1,设置文件的mime类型 //先得到文件的mime类型 String type = getServletContext().getMimeType(filename); //设置 response.setContentType(type); response.setHeader("Content-Disposition", "attachment;filename=" + filename); //得到输入流 InputStream is = new FileInputStream(path); //得到输出流 OutputStream os = response.getOutputStream(); //2,流对接 int a=0; byte[]arr =new byte[1024*8]; while((a = is.read(arr))!=-1){ os.write(arr,0,a); } //3,关流 os.close(); //会自动关闭,不过要养成关流的习惯 is.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }