JAVA EE-文件上傳
應該相信,自己是生活的戰勝者。 —— 雨果
文件下載
首先我們複習一下文件下載的內容
靜態下載
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1 準備工作
//設置content-type
response.setContentType(getServletContext().getMimeType("xxx.zip"));
//添加響應頭 content-disposition
response.setHeader("Content-Disposition", "attachment;filename=apache-tomcat-6.0.35.zip");
//2 獲得輸入流
InputStream is
= getServletContext().getResourceAsStream("/WEB-INF/apache-tomcat-6.0.35.zip");
//3 獲得輸出流
OutputStream os = response.getOutputStream();
//4 兩個流對接
IOUtils.copy(is, os);
}
}
根據用戶的選擇來獲取下載
JSP文件:
<body>
<a href="/day12-download/AServlet" >點擊下載</a><br>
<a href="/day12-download/BServlet?name=apache-tomcat-6.0.35.zip" >apache-tomcat-6.0.35.zip</a><br>
<a href="/day12-download/BServlet?name=激活軟件_v10.0.0.exe" >激活軟件_v10.0.0.exe</a><br>
</body>
業務處理的Servlet
public class BServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1 獲得參數,拿到用戶需要下載的文件名稱
String fileName = request.getParameter("name");
fileName = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");
//2 準備工作
//設置content-type
response.setContentType(getServletContext().getMimeType(fileName));
//添加響應頭 content-disposition
response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8"));
//2 獲得輸入流
InputStream is
= getServletContext().getResourceAsStream("/WEB-INF/"+fileName);
//3 獲得輸出流
OutputStream os = response.getOutputStream();
//4 兩個流對接
IOUtils.copy(is, os);
//關閉輸出流
is.close();
os.close();
}
}
下載的亂碼問題
客戶端的超連接中如果包含了中文,會出現get請求方式亂碼問題
<a href="${pageContext.request.contextPath}/download?filename=天空.mp3">下載王非天空.mp3</a>
String filename = request.getParameter("name"); // yog.rar / 她說.mp3
byte[] b = filename.getBytes("ISO-8859-1");
filename = new String(b,"UTF-8");
實際上Get提交時包含中文亂碼的解決。
如果下載文件名稱中出現了中文亂碼問題
<a href="${pageContext.request.contextPath}/download?filename=天空.mp3">下載王非天空.mp3</a>
String filename = request.getParameter("name"); // yog.rar / 她說.mp3
byte[] b = filename.getBytes("ISO-8859-1");
filename = new String(b,"UTF-8");
實際上Get提交時包含中文亂碼的解決。
文件上傳
爲什麼使用文件上傳?
- 例如社交網站需要提供用戶照片.
- 很多企業內部,商品網站維護時需要上傳一些文件
- 郵箱需要上傳附件….
文件上傳的操作
- 請求方式必須是post
- 需要使用組件
- 表單必須設置encType=”multipart/form-data”
- 上傳文件的input 中,name屬性必須要填寫,不然不會上傳.
這樣一來,通過request對象,獲取InputStream,可以將瀏覽器提交的所有請求正文讀取到.
文件上傳需要的插件
commons-fileupload 它是常用的一個文件上傳工具
使用時要導入兩個jar包
commons-fileupload-1.2.1.jar
commons-io-1.4.jar
一個上傳的瀏覽器端代碼
<body>
<!--
1.文件上傳,表單必須是post提交
2.文件上傳,還需要在表單上加上enctype屬性(提交請求正文的類型)
*application/x-www-form-urlencoded(默認取值,普通提交)
*multipart/form-data(多段式提交)
3. 文件上傳,使用<input type="file" name="photo" /> 標籤,並且必須有name屬性
-->
<form action="/day12-upload/BServlet" method="post" encType="multipart/form-data" >
用戶名:<input type="text" name="name" /><br>
個人近照:<input type="file" name="photo" /><br>
<input type="submit" value="上傳" />
</form>
</body>
下面演示如何使用第三方的jar包來優化文件上傳處理
public class BServlet extends HttpServlet {
//使用文件上傳工具類(第三方)
// 導包 => commons-fileupload-1.2.1.jar
// => commons-io-1.4.jar
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1 創建配置工廠
DiskFileItemFactory factory = new DiskFileItemFactory();
//2 根據配置工廠創建解析請求中文件上傳內容的解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//3 判斷當前請求是否是多段式提交
if(!upload.isMultipartContent(request)){
//普通表單提交
throw new RuntimeException("不是多段式提交!");
}
try {
//4 解析request對象
List<FileItem> list = upload.parseRequest(request);
if(list!=null){
for(FileItem item : list){
//判斷當前上傳段是普通字段,還是文件上傳
if(!item.isFormField()){//文件上傳段
String fName = item.getFieldName();
InputStream is = item.getInputStream();//獲得文件上傳段中,文件的流
FileOutputStream fos = new FileOutputStream("d://upload/xxx.jpg");
IOUtils.copy(is, fos);
fos.close();
}else{//普通字段段
String name = item.getFieldName();
String value = item.getString();
System.out.println(name+"==>"+value);
}
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
文件上傳段與普通表單段的區別如下
fileupload工具類詳解
public class CServlet extends HttpServlet {
//fileupload 工具類使用詳解
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1 創建配置工廠=> 有參的構造可以 直接設置下面兩個配置
DiskFileItemFactory factory = new DiskFileItemFactory();
//1.1 設置文件上傳臨時目錄 => 默認位置 => tomcat/temp
factory.setRepository(new File("d:/temp"));
//1.2 設置文件寫入硬盤的緩衝區大小=>默認值=>10k
factory.setSizeThreshold(10240);
//2 根據配置工廠創建解析器(解析request對象)
ServletFileUpload upload = new ServletFileUpload(factory);
//2.1 判斷當前請求是否是多段式提交
upload.isMultipartContent(request);
//2.2 設置多段中每段 段頭 在解析時,使用什麼碼錶解碼 => 當段頭中出現中文時,一定要調用該方式指定段頭碼錶
upload.setHeaderEncoding("UTF-8");
//2.3 設置文件最大上傳大小 (單位:字節)
upload.setSizeMax(1024*1024*10); //單次請求,總上傳大小限制 10兆
upload.setFileSizeMax(1024*1024);// 每個文件上傳段,大小限制 1兆
List<FileItem> list = null;
try {
//2.4 解析request,將每個分段中的內容封裝到FileItem中
list = upload.parseRequest(request);
} catch (FileUploadException e) {
e.printStackTrace();
}
if(list!=null){
for(FileItem item : list){
//3.1 item 判斷當前分段是否是普通表單段
boolean flag = item.isFormField();
//普通段
//3.2獲得 表單提交的鍵.(input元素,name屬性的值)
String fname = item.getFieldName();
//3.3 返回文件名稱
String name = item.getName();
//3.4 獲得文件上傳中的正文
//item.getInputStream();
//3.5 以字符串形式返回段體中的內容 注意:文件上傳段不建議使用該方法.
String content= item.getString();
//3.6 刪除上傳的臨時文件
item.delete();
System.out.println("是否是普通表單提交:"+flag+",表單提交的鍵:"+fname+",文件名稱:"+name+",文件內容:"+content);
}
}
}
}
關於亂碼問題的研究
當上傳的文件名中有中文時,如果碼錶不當就會造成亂碼問題的產生。
public class DServlet extends HttpServlet {
//上傳文件名稱是中文,亂碼問題
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1 創建配置工廠
DiskFileItemFactory factory = new DiskFileItemFactory();
//2 根據配置工廠創建解析請求中文件上傳內容的解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//解決文件名稱中文亂碼
upload.setHeaderEncoding("UTF-8");
//3 判斷當前請求是否是多段式提交
if(!upload.isMultipartContent(request)){
//普通表單提交
throw new RuntimeException("不是多段式提交!");
}
try {
//4 解析request對象
List<FileItem> list = upload.parseRequest(request);
if(list!=null){
for(FileItem item : list){
//判斷當前上傳段是普通字段,還是文件上傳
if(!item.isFormField()){//文件上傳段
String fileName = item.getName();
System.out.println(fileName);
}
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
設置上傳文件的最大大小
public class FServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1 創建配置工廠
DiskFileItemFactory factory = new DiskFileItemFactory();
//2 根據配置工廠創建解析請求中文件上傳內容的解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//設置文件上傳大小限制
upload.setFileSizeMax(1024);
try {
upload.parseRequest(request);
} catch (FileUploadException e) {
e.printStackTrace();
throw new RuntimeException("文件大小不能超過1kb!");
}
}
}
可以設置上傳文件大小,如果超過設置大小.將會拋出異常(默認沒有最大值)
void setFileSizeMax(long fileSizeMax) 設置單個文件上傳大小
void setSizeMax(long sizeMax) 設置總文件上傳大小
如何實現保存的文件名不會重複
public class GServlet extends HttpServlet {
//如果將文件全部保存 => 保證文件名稱不能重複
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1 創建配置工廠
DiskFileItemFactory factory = new DiskFileItemFactory();
//2 根據配置工廠創建解析請求中文件上傳內容的解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//3 判斷當前請求是否是多段式提交
if(!upload.isMultipartContent(request)){
//普通表單提交
throw new RuntimeException("不是多段式提交!");
}
try {
//4 解析request對象
List<FileItem> list = upload.parseRequest(request);
if(list!=null){
for(FileItem item : list){
//判斷當前上傳段是普通字段,還是文件上傳
if(!item.isFormField()){//文件上傳段
String fName = item.getFieldName();
InputStream is = item.getInputStream();//獲得文件上傳段中,文件的流
//保存之前,生成文件名稱( 保證永遠不重複)
//生成隨機字符串即可
String fileName = UUID.randomUUID().toString();
FileOutputStream fos = new FileOutputStream("d:/upload/"+fileName);
IOUtils.copy(is, fos);
fos.close();
}
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
如何防止同一個目錄之下上傳文件數量過多?
public class HServlet extends HttpServlet {
//如何將上傳文件分目錄保存
// 使用登錄用戶的用戶名 來創建不同的文件夾. 每個用戶上傳的文件就放到自己的文件夾中
// 按照日期分目錄=> d:/upload/2015/08/24/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1 創建配置工廠
DiskFileItemFactory factory = new DiskFileItemFactory();
//2 根據配置工廠創建解析請求中文件上傳內容的解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//3 判斷當前請求是否是多段式提交
if(!upload.isMultipartContent(request)){
//普通表單提交
throw new RuntimeException("不是多段式提交!");
}
try {
//4 解析request對象
List<FileItem> list = upload.parseRequest(request);
if(list!=null){
for(FileItem item : list){
//判斷當前上傳段是普通字段,還是文件上傳
if(!item.isFormField()){//文件上傳段
String fName = item.getFieldName();
InputStream is = item.getInputStream();//獲得文件上傳段中,文件的流
// 生成日期目錄
//1 獲得當前日期=>目錄結構 的 路徑
SimpleDateFormat format = new SimpleDateFormat("/yyyy/MM/dd/");
String datepath = format.format( new Date()); // /2015/08/24/
//拼接完整保存目錄路徑
String wholePath = "d:/upload"+datepath;// d:/upload/2015/08/24/
//確保文件夾存在
File directory = new File(wholePath);
if(!directory.exists()){//如果文件夾結構不存在
directory.mkdirs(); //創建文件夾結構
}
//保存之前,生成文件名稱( 保證永遠不重複)
//生成隨機字符串即可
String fileName = UUID.randomUUID().toString();
FileOutputStream fos = new FileOutputStream(wholePath+fileName);
IOUtils.copy(is, fos);
fos.close();
}
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}