目前文件上傳的(框架)組件:Apache----fileupload 、Orialiy – COS – 2008() 、Jsp-smart-upload – 200M。
用fileupload上傳文件:
需要導入第三方包:
Apache-fileupload.jar – 文件上傳核心包。
Apache-commons-io.jar – 這個包是fileupload的依賴包。同時又是一個工具包。
核心類:
DiskFileItemFactory – 設置磁盤空間,保存臨時文件。只是一個具類。
ServletFileUpload - 文件上傳的核心類,此類接收request,並解析reqeust
ServletFileUpload.parseRequest(request); --List<FileItem> 解析request
一個FileItem就是一個標識分隔符開始 到結束。如下圖:
查看DiskFileItemFactory源代碼,可知
If not otherwise configured, the default configuration values are as follows: Size threshold is 10KB. Repository is the system default temp directory, as returned by System.getProperty("java.io.tmpdir")
可知,如果不設置臨時目錄,會保存在默認的臨時目錄- System.getProperty("java.io.tmpdir");這個目錄正是windows系統的臨時文件存放目錄,通過環境變量,可找到這個目錄
這里存放着許多臨時文件。
單文件上傳Servlet:
package com.lhy.upload; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.List; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; 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; @WebServlet(name="Up2Servlet",urlPatterns="/Up2Servlet") public class Up2Servlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTf-8"); //獲取tomcat下的up目錄的路徑 String path = getServletContext().getRealPath("/up"); //臨時文件目錄 String tmpPath = getServletContext().getRealPath("/tmp"); //檢查我們是否有文件上傳請求 boolean isMultipart = ServletFileUpload.isMultipartContent(req); //1,聲明DiskFileItemFactory工廠類,用於在指定磁盤上設置一個臨時目錄 DiskFileItemFactory disk = new DiskFileItemFactory(1024*10,new File(tmpPath)); //2,聲明ServletFileUpload,接收上邊的臨時文件。也可以默認值 ServletFileUpload up = new ServletFileUpload(disk); //3,解析request try { List<FileItem> list = up.parseRequest(req); //如果就一個文件, FileItem file = list.get(0); //獲取文件名: String fileName = file.getName(); //獲取文件的類型: String fileType = file.getContentType(); //獲取文件的字節碼: InputStream in = file.getInputStream(); //文件大小 int size = file.getInputStream().available(); //聲明輸出字節流 OutputStream out = new FileOutputStream(path+"/"+fileName); //文件copy byte[] b = new byte[1024]; int len = 0; while((len=in.read(b))!=-1){ out.write(b, 0, len); } out.flush(); out.close(); //刪除上傳生成的臨時文件 file.delete(); //顯示數據 resp.setContentType("text/html;charset=UTF-8"); PrintWriter pw = resp.getWriter(); pw.println("文件名:"+fileName); pw.println("文件類型:"+fileType); pw.println("<br/>文件大小(byte):"+size); } catch (FileUploadException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
from:
<form action="<%=basePath%>Up2Servlet" method="post" enctype="multipart/form-data"> File1:<input type="file" name="txt"><br/> <input type="submit"/> </form>
臨時文件:
服務端:
響應:
實際項目中都是有文件服務器的,公司一般都提供了上傳到文件服務器接口,有的是上傳一個file類型,有的是流。
多文件上傳Servlet:
package com.lhy.upload; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; 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; import org.apache.commons.io.FileUtils; @WebServlet(name="Up3Servlet",urlPatterns="/Up3Servlet") public class Up3Servlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTf-8"); String path = getServletContext().getRealPath("/up"); //臨時文件目錄 String tmpPath = getServletContext().getRealPath("/tmp"); //聲明disk DiskFileItemFactory disk = new DiskFileItemFactory(); disk.setSizeThreshold(1024*1024); disk.setRepository(new File(tmpPath)); //聲明解析requst的servlet ServletFileUpload up = new ServletFileUpload(disk); try{ //解析requst List<FileItem> list = up.parseRequest(req); //聲明一個list<map>封裝上傳的文件的數據 List<Map<String,String>> ups = new ArrayList<Map<String,String>>(); for(FileItem file:list){ Map<String,String> mm = new HashMap<String, String>(); //獲取文件名 String fileName = file.getName(); fileName = fileName.substring(fileName.lastIndexOf("\\")+1); String fileType = file.getContentType(); InputStream in = file.getInputStream(); int size = in.available(); //使用工具類 // FileUtils.copyInputStreamToFile(in,new File(path+"/"+fileName)); //file 的方法可以直接寫出文件 file.write(new File(path+"/"+fileName)); mm.put("fileName",fileName); mm.put("fileType",fileType); mm.put("size",""+size); ups.add(mm); file.delete(); } req.setAttribute("ups",ups); //轉發 req.getRequestDispatcher("/jsps/show.jsp").forward(req, resp); }catch(Exception e){ e.printStackTrace(); } } }
表單:
<form name="xx" action="<%=basePath%>Up3Servlet" method="post" enctype="multipart/form-data"> <table id="tb" border="1"> <tr> <td> File: </td> <td> <input type="file" name="file"> <button onclick="_del(this);">刪除</button> </td> </tr> </table> <br/> <input type="button" onclick="_submit();" value="上傳"> <input onclick="_add();" type="button" value="增加"> </form>
js
<script type="text/javascript"> function _add(){ var tb = document.getElementById("tb"); //寫入一行 var tr = tb.insertRow(); //寫入列 var td = tr.insertCell(); //寫入數據 td.innerHTML="File:"; //再聲明一個新的td var td2 = tr.insertCell(); //寫入一個input td2.innerHTML='<input type="file" name="file"/><button onclick="_del(this);">刪除</button>'; } function _del(btn){ var tr = btn.parentNode.parentNode; //alert(tr.tagName); //獲取tr在table中的下標 var index = tr.rowIndex; //刪除 var tb = document.getElementById("tb"); tb.deleteRow(index); } function _submit(){ //遍歷所的有文件 var files = document.getElementsByName("file"); if(files.length==0){ alert("沒有可以上傳的文件"); return false; } for(var i=0;i<files.length;i++){ if(files[i].value==""){ alert("第"+(i+1)+"個文件不能為空"); return false; } } document.forms['xx'].submit(); } </script>
show.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <p>以下是你上傳的文件</p> <c:forEach items="${ups}" var="mm"> 文件名:${mm.fileName}<br/> 類型:${mm.fileType}<br/> 大小:${mm.size}(bytes) <hr/> </c:forEach> </body> </html>
測試,上傳3張圖片:
up目錄L:
響應:
多文件上傳,如果是同一個文件,會覆蓋以前的,需要重命名,具體自己實現吧,如用uuid
//獲取擴展
String extName = fileName.substring(fileName.lastIndexOf("."));//.jpg
//UUID
String uuid = UUID.randomUUID().toString().replace("-", "");
//新名稱
String newName = uuid+extName;
限制只能上傳圖片:
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); String path = getServletContext().getRealPath("/up"); //項目里建的臨時目錄,存放臨時文件,linux適用 String tmpPath = getServletContext().getRealPath("/tmp"); DiskFileItemFactory disk = new DiskFileItemFactory(1024*10,new File(tmpPath)); ServletFileUpload up = new ServletFileUpload(disk); try{ List<FileItem> list = up.parseRequest(req); //只接收圖片*.jpg-iamge/jpege.,bmp/imge/bmp,png, List<String> imgs = new ArrayList<String>(); for(FileItem file :list){ if(file.getContentType().contains("image/")){ String fileName = file.getName(); //如果是原始方式Servlet上傳,IE:c:\\xxx\\aa.jpg,但是用框架ie也是aa.jpg,這句沒啥用好似 fileName = fileName.substring(fileName.lastIndexOf("\\")+1); //獲取擴展 String extName = fileName.substring(fileName.lastIndexOf("."));//.jpg //UUID String uuid = UUID.randomUUID().toString().replace("-", ""); //新名稱 String newName = uuid+extName; FileUtils.copyInputStreamToFile(file.getInputStream(), new File(path+"/"+newName)); //放到list imgs.add(newName); } file.delete(); } req.setAttribute("imgs",imgs); req.getRequestDispatcher("/jsps/imgs.jsp").forward(req, resp); }catch(Exception e){ e.printStackTrace(); } }
imgs.jsp:顯示上傳的圖片
<body> <p>圖片是:</p> <c:forEach items="${imgs}" var="img"> <img src="<c:url value='/up/${img}'/>"></img> </c:forEach> </body>
處理表單域中普通的input:
指定表單的enctype="multipart/form-data" 后,表單將會以二進制請求,普通的input 用request.getParameter("xxx");為null,fileupload能很方便處理普通表單域:
FileItem接口方法:
|
|
|
|
|
|
getContentType() 獲取文檔的類型 |
||
getFieldName() 獲取字段的名稱,即name=xxxx <input type=”file” name=”img”/> |
||
getInputStream() |
||
getName() 獲取文件名稱。 如果是在IE獲取的文件為 c:\aaa\aaa\xxx.jpg –即完整的路徑。 非IE;文件名稱只是 xxx.jpg |
||
|
|
|
long |
getSize() 獲取文件大小 相當於in.avilivable(); |
|
如果你上傳是一普通的文本元素,則可以通過以下方式獲取元素中的數據 <form enctype=”multipart/form-data”> <input type=”text” name=”name”/> |
||
getString() 用於獲取普通的表單域的信息。 |
||
getString(String encoding) 可以指定編碼格式 |
||
void |
write(File file) 直接將文件保存到另一個文件中去。 |
|
以下文件用判斷一個fileItem是否是file(type=file)對象或是text(type=text|checkbox|radio)對象: |
||
|
|
Servlet:
package com.lhy.upload; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; 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; @WebServlet(name="UpDescServlet",urlPatterns="/UpDescServlet") public class UpDescServlet extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //可以獲取中文的文件名 request.setCharacterEncoding("UTF-8"); //項目真實路徑 String path = getServletContext().getRealPath("/up"); //聲明disk DiskFileItemFactory disk = new DiskFileItemFactory(); disk.setRepository(new File("D:/tmp"));//臨時文件目錄 try{ //聲明解析requst的servlet ServletFileUpload up = new ServletFileUpload(disk); //解析requst List<FileItem> list = up.parseRequest(request); //聲明一個map用於封裝信息 Map<String,Object> img = new HashMap<String, Object>(); for(FileItem file:list){ //第一步:判斷是否是普通的表單項 if(file.isFormField()){ //可以讀取多個普通的input String fileName = file.getFieldName();//<input type="text" name="desc">=desc String value = file.getString("UTF-8");//默認以ISO方式讀取數據 System.err.println(fileName+"="+value); //放入圖片的說明 img.put(fileName,value); }else{//說明是一個文件 String fileName = file.getName();//以前的名稱 //處理文件名 fileName = fileName.substring(fileName.lastIndexOf("\\")+1); img.put("oldName",fileName); //修改名稱 String extName = fileName.substring(fileName.lastIndexOf(".")); String newName = UUID.randomUUID().toString().replace("-", "")+extName; //保存新的名稱 img.put("newName",newName); file.write(new File(path+"/"+newName)); System.err.println("文件名是:"+fileName); System.err.println("文件大小是:"+file.getSize()); img.put("size",file.getSize()); file.delete(); } } //將img=map放到req request.setAttribute("img",img); //轉發 request.getRequestDispatcher("/jsps/desc.jsp").forward(request, response); }catch(Exception e){ e.printStackTrace(); } } }
form表單:
<form action="<c:url value='/UpDescServlet'/>" method="post" enctype="multipart/form-data"> 你的圖片:<input type="file" name="img"><br /> 說明:<input type="text" name="desc"/><br/> 說明2:<input type="text" name="desc2"/><br/> <input type="submit" /> </form>
desc.jsp:
<body> <p>請選擇圖片:名稱(以前的名稱oldName),顯示這張圖片newName。圖片大小size,圖片的說明desc</p> ${img.oldName}<br/> ${img.size}<br/> ${img.desc}<br/> ${img.desc2} <br/> <img width="300" height="300" src="<c:url value='/up/${img.newName}'/>"></img> <hr/> <p>url:http://localhost:8080/day22/jsps/desc.jsp <img width="300" height="300" src="<c:url value='/up/8.jpg'/>"/> </body> </html>
性能提升?使用FileItemIterator上傳:
package com.lhy.upload; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileItemStream; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.FileUtils; @WebServlet(name="FastServlet",urlPatterns="/FastServlet") public class FastServlet extends HttpServlet{ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { long start = new Date().getTime(); req.setCharacterEncoding("UTF-8"); String path = getServletContext().getRealPath("/up"); DiskFileItemFactory disk = new DiskFileItemFactory(); try { ServletFileUpload up = new ServletFileUpload(disk); //迭代器模式 FileItemIterator iter = up.getItemIterator(req); while(iter.hasNext()){ FileItemStream item = iter.next(); String fileName = item.getName(); fileName = fileName.substring(fileName.lastIndexOf("\\")+1); InputStream in = item.openStream(); FileUtils.copyInputStreamToFile(in, new File(path+"/"+fileName)); } } catch (Exception e) { e.printStackTrace(); } long end = new Date().getTime(); System.out.println(end - start); } }
不知道能不能提升性能,我分別用這個和上邊的上傳了一個myeclipse2014安裝包1.1G,用上傳前后的毫秒差計算,結果顯示這個耗時100930,上邊的方法耗時54240,並沒有提升性能反而滿了,迭代器模式不知道能不能提升性能,。。
限制上傳文件的大小:
ServletFileUpload類的方法:
1:限制總文件的大小 。 如 上傳10文件,設置最多總上傳大小為100M。
|
|
2:設置第每一個文件的大小 ,如果設置每 一個文件大小10M。
|
|
兩者一般設置一個就行了,可以catch到這個異常給提示信息。
ServletFileUpload up = new ServletFileUpload(disk); //限制總文件的大小,如果上傳多個文件 up.setSizeMax(1024*1024*100);//限制上傳最大100M //設置第每一個文件的大小 兩者有一個即可 // up.setFileSizeMax(1024*1024);
有些上傳插件,如插件fileuploadify 在頁面就可以限制上傳文件。