文件上傳
附加知識:1.必須要設置input輸入項的name屬性,否則瀏覽器將不會發送上傳文件的數據。2.必須把form的enctype屬值設爲“multipart/form-data”2.必須把form的method屬性設置爲post方式。
application/x-www-form-urlencoded 在發送前編碼所有字符(默認)。multipart/form-data 不對字符編碼。在使用包含文件上傳控件的表單時,必須使用該值。text/plain 空格轉換爲 "+" 加號,但不對特殊字符編碼。
方式1:手動實現文件上傳
案例中上傳的文件a.txt
web頁面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>手動執行文件上傳</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">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<form action="${pageContext.request.contextPath }/TestServlet" method="post" enctype="multipart/form-data">
用戶名:<input type="text" name="userName"/><hr/>
文件:<input type="file" name="file1"/> <input type="submit" value="提交"/>
</form>
</body>
</html>
Servlet手動獲取上傳文件
package com.cn.servlet;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 手動獲取文件上傳
* @author liuzhiyong
*
*/
public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//獲取表單(POST)提交的數據流
ServletInputStream in = request.getInputStream();
//轉換流
InputStreamReader inStream = new InputStreamReader(in);
//緩衝流
BufferedReader reader = new BufferedReader(inStream);
//輸出數據
String str = null;
while((str=reader.readLine()) != null){
System.out.println(str);
}
//關閉
reader.close();
inStream.close();
in.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
效果:
方式2:文件上傳組件(FileUpload組件,推薦)
FileUpload組件使用步驟:
FileUpload組件API:
使用FileUpload組件測試:
web頁面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>手動執行文件上傳</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">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<form action="${pageContext.request.contextPath }/FileUpLoadServlet" method="post" enctype="multipart/form-data">
用戶名:<input type="text" name="userName"/><hr/>
文件:<input type="file" name="file1"/> <input type="submit" value="提交"/>
</form>
</body>
</html>
Servlet使用組件獲取數據
package com.cn.servlet;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
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.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* 文件上傳組件使用
* @author liuzhiyong
*
*/
public class FileUpLoadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.創建文件上傳工廠類
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
// fileItemFactory.setRepository(repository);//設置臨時目錄
//2.創建文件上傳核心類對象,可以獲取所有的FileItem對象
ServletFileUpload upload = new ServletFileUpload(fileItemFactory );
// upload.setFileSizeMax(fileSizeMax);//設置單個文件上傳最大值
// upload.setSizeMax(sizeMax);//設置總的文件最大大小
// upload.setHeaderEncoding(encoding);//設置上傳的文件名的編碼,相當於request.setCharacterEncoding(encoding);
//判斷當前表單是否爲文件上傳表單,如果是返回true
if(ServletFileUpload.isMultipartContent(request)){
//3.把請求數據轉換爲FileItem對象的集合
try {
List<FileItem> list = upload.parseRequest(request);//獲取所有文件上傳項FileItem
//遍歷,得到每一個上傳項
for(FileItem item : list){
//判斷是普通表單項,還是文件上傳表單項
if(item.isFormField()){//普通表單
String fieldName = item.getFieldName();//表單元素(這裏是文本框)名稱
String content = item.getString();//表單元素(這裏是文本框)值
// String content = item.getString("utf-8");//表單元素(這裏是文本框)值,並處理編碼
}else{//文件上傳表單
String fieldName = item.getFieldName();//表單元素名稱
String contentType = item.getContentType();//上傳文件類型
String name = item.getName();//文件名
InputStream in = item.getInputStream();//文件流
String content = item.getString();//文件內容
InputStreamReader inStream = new InputStreamReader(in);
//緩衝流
BufferedReader reader = new BufferedReader(inStream);
//輸出數據
String str = null;
while((str=reader.readLine()) != null){
System.out.println(str);
}
item.write(new File("d:/aa文件.txt"));//寫文件
item.delete();//刪除臨時文件
//關閉
reader.close();
inStream.close();
in.close();
}
}
} catch (Exception e) {
//測試
e.printStackTrace();
}
}else{
System.out.println("當前表單不是文件上傳表單,不處理!");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
效果:
文件的上傳下載完整案例
需求:
web開始頁面:index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>文件上傳與下載</title>
</head>
<body>
<a href="${pageContext.request.contextPath }/upload.jsp">文件上傳</a>
<hr/>
<a href="${pageContext.request.contextPath }/FileServlet?method=downList">文件下載列表</a>
</body>
</html>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>手動執行文件上傳</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/FileServlet?method=upload" method="post" enctype="multipart/form-data">
用戶名:<input type="text" name="userName"/><hr/>
文件:<input type="file" name="file1"/>
<input type="submit" value="提交"/>
</form>
<%-- 不提交文件上傳表單,測試 --%>
<a href="${pageContext.request.contextPath }/FileServlet?method=upload">訪問FileUploadServlet試試</a>
</body>
</html>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%-- 引入jstl核心標籤庫 --%>
<%@ 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 'downList.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">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<table>
<tr>
<th>序號</th>
<th>文件</th>
<th>操作</th>
</tr>
<c:forEach items="${requestScope.fileNameMap }" var="entry" varStatus="varStatus">
<tr>
<td>${varStatus.count }</td>
<td>${entry.value }</td>
<td>
<%-- 方式1 --%>
<%--<a href="${pageContext.request.contextPath}/FileServlet?method=download&fileName=${entry.key}">下載</a>--%>
<%-- 方式2:在JSP頁面中構造一個URL地址 。。注意context不寫,表示默認當前項目路徑下 --%>
<c:url var="url" value="/FileServlet" context="${pageContext.request.contextPath}">
<c:param name="method" value="download"></c:param>
<c:param name="fileName" value="${entry.key }"></c:param>
</c:url>
<%-- 使用上面的地址 --%>
<a href="${url }">下載</a>
</td>
</tr>
</c:forEach>
</table>
</body>
</html>
Servlet處理
package com.cn.servlet;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
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.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* 處理文件上傳與下載:
* 上傳功能:
1.設置單個文件不能超過30M
2.設置總文件大小不能超過50M
3.上傳目錄:上傳到項目資源目錄下的upload目錄
4.上傳文件不能覆蓋,解決上傳文件名的同名問題
下載功能:
下載文件
* @author liuzhiyong
*
*/
public class FileServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//獲取請求參數,區分不同的操作類型
String method = request.getParameter("method");
if("upload".equals(method)){
upload(request, response);
}else if("downList".equals(method)){
downList(request, response);
}else if("download".equals(method)){
download(request, response);
}
}
/**
* 進入下載劉表
* 思路:
* 先獲取upload目錄下所有文件的文件名,再保存,跳轉到downList.jsp列表展示
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void downList(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
//1.初始化map集合Map<包含唯一標記的文件名, 簡單文件名>
Map<String, String> fileNameMap = new HashMap<String, String>();
//2.獲取上傳目錄,及其下所有文件的文件名
String bathPath = this.getServletContext().getRealPath("/upload");
//上傳目錄
File file = new File(bathPath);
//獲取上傳目錄下,所有文件名
String[] list = file.list();//返回目錄下的文件或者目錄名,包含隱藏文件。
//遍歷,封裝
if(list!=null && list.length>0){
for(String str : list){
//全名
String fileName = str;
//獲取全名字符#後面的短名
String shortName = fileName.substring(fileName.lastIndexOf("#")+1);
//將全名和短命封裝到Map集合中
fileNameMap.put(fileName, shortName);
}
}
//3.保存到request域對象中
request.setAttribute("fileNameMap", fileNameMap);
//4.轉發到下載列表downList.jsp頁面
request.getRequestDispatcher("/downList.jsp").forward(request, response);
}
/**
* 處理下載
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void download(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
//獲取用戶下載的文件名稱(url地址後面追加的參數fileName的值,此參數是GET方式提交的,所以後面需要處理編碼問題)
String fileName = request.getParameter("fileName");
//處理編碼
fileName = new String(fileName.getBytes("iso-8859-1"), "utf-8");
//現獲取文件上傳的目錄路徑
String basePath = this.getServletContext().getRealPath("/upload");
//文件對象
File file = new File(basePath, fileName);
//獲取一個文件輸入字節流對象
FileInputStream in = new FileInputStream(file);
//如果文件名是中文,需要進行url編碼,不然下載後中文不顯示
fileName = URLEncoder.encode(fileName, "utf-8");
/**
程序實現下載需設置兩個響應頭:
設置Content-Type 的值爲:application/x-msdownload。Web 服務器需要告訴瀏覽器其所輸出的內容的類型不是普通的文本文件或 HTML 文件,而是一個要保存到本地的下載文件。
Web 服務器希望瀏覽器不直接處理相應的實體內容,而是由用戶選擇將相應的實體內容保存到一個文件中,這需要設置 Content-Disposition 報頭。該報頭指定了接收程序處理數據內容的方式,
在 HTTP 應用中只有 attachment 是標準方式,attachment 表示要求用戶干預。在 attachment 後面還可以指定 filename 參數,
該參數是服務器建議瀏覽器將實體內容保存到文件中的文件名稱。在設置 Content-Dispostion 之前一定要指定 Content-Type.
*/
//設置下載的響應頭
// response.setContentType("application/x-msdownload");//但是我發現這裏其實可以不加
response.setHeader("content-disposition", "attachment;fileName=" + fileName);
//獲取response字節流
OutputStream out = response.getOutputStream();//因爲要下載的文件可以是各種類型的文件,所以要將文件傳送給客戶端,其相應內容應該被當做二進制來處理,所以應該調用輸出字節流來向客戶端寫入文件內容。
//緩衝數組
byte[] buff = new byte[1024];
int len = -1;
while((len = in.read(buff)) != -1){
out.write(buff, 0, buff.length);
}
//關閉資源
out.close();
in.close();
}
/**
* 處理上傳
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void upload(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
try {
//1.創建文件上傳工廠類(把每一個請求表單項封裝爲一個個FileItem對象)
DiskFileItemFactory factory = new DiskFileItemFactory();
//2.創建文件上傳核心類對象(可以獲取所有的FileItem對象)
ServletFileUpload upload = new ServletFileUpload(factory);
// //【需求1:設置單個文件不能超過30M】
// upload.setFileSizeMax(30*1024*1024);//30M
// //【需求2:設置總文件大小不超過50M】
// upload.setSizeMax(50*1024*1024);//50M
//【需求1:設置單個文件不能超過200M】
upload.setFileSizeMax(200*1024*1024);//200M
//【需求2:設置總文件大小不超過300M】
upload.setSizeMax(300*1024*1024);//300M
upload.setHeaderEncoding("utf-8");//設置上傳的文件名的編碼,若果沒有設置編碼,當上傳文件名爲中文時,會出現亂碼。
/**
* ProgressListener顯示上傳進度
*/
ProgressListener progressListener = new ProgressListener(){
@Override
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("到現在爲止, " + pBytesRead/1024 + " KB已上傳,總大小爲 " + pContentLength/1024 + "KB");
}
};
upload.setProgressListener(progressListener);
//判斷:上傳表單是否爲multipart/form-data類型
if(ServletFileUpload.isMultipartContent(request)){
//3.把請求數據轉換爲FileItem的集合
List<FileItem> list = upload.parseRequest(request);
//遍歷list
for(FileItem item : list){
//判斷普通表單元素,或者文件元素
if(item.isFormField()){//普通表單元素
//獲取元素名稱
String fieldName = item.getFieldName();
//獲取元素名稱對應的值
String value = item.getString("utf-8");
System.out.println(fieldName + ":" + value);
}else{//文件上傳元素
//獲取上傳的文件名
String name = item.getName();
/**
* 問題:文件重命名,防止上傳後覆蓋
* 解決:給用戶添加一個唯一標記
*/
//隨機生成一個唯一標記
String uuid = UUID.randomUUID().toString().replace("-", "");
name = uuid + "#" + name;
//獲取上傳的目錄路徑
String basePath = this.getServletContext().getRealPath("/upload");// /斜槓代表當前服務器項目路徑下
//創建文件對象
File file = new File(basePath, name);
//寫文件
InputStream in = item.getInputStream();
item.write(file);
in.close();//關閉流
item.delete();//刪除臨時文件
}
}
}else{
System.out.println("不是文件上傳表單,不處理!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}