javaweb-檔案的上傳下載
本文用到的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);
}
}