<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> </head> <body> <!-- 1. 表單提交方式post 2. 表單的enctype="multipart/form-data" 1. 表單要上傳文件輸入項type="file" --> <form method="post" enctype="multipart/form-data" action="/upload/upload"> 上傳人: <input type="text" name="name"><br/> 請上傳圖片:<input type="file" name="file"><br> <input type="submit" value="上傳"> </form> </body></html> 1.1.2編寫servlet處理提供的數(shù)據(jù)fileupload組件工作流程
```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.FileUploadException;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
完成文件上傳 */public class UploadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { / 由于form的enctype屬性原因,以下代碼獲取不了上傳數(shù)據(jù): String * name=request.getParameter("name"); String * file=request.getParameter("file"); ServletInputStream in = * request.getInputStream(); */
// apache提供了開源的commons-fileupload組件,只需要在工程中導(dǎo)入使用// 1.導(dǎo)入commons-fileupload-1.2.1.jar,commons-io-1.4.jar到lib// 2.拿到工廠DiskFileItemFactory factory = new DiskFileItemFactory();// 3.拿到解析器對象ServletFileUpload uploader = new ServletFileUpload(factory);// 4.關(guān)聯(lián)到requestList<FileItem> list;try { list = uploader.parseRequest(request); for (FileItem fileItem : list) { if (fileItem.isFormField()) { // 普通的輸入項 // 獲得普通輸入項字段的名稱 String fieldName = fileItem.getFieldName(); // 獲得普通輸入項字段的名稱對應(yīng)的值 String fieldValue = fileItem.getString(); } else { // 文件上傳輸入項 // 獲得上傳文件名字 String name = fileItem.getName(); // 獲得上傳文件輸入流 InputStream in = fileItem.getInputStream(); OutputStream out = new FileOutputStream("D://" + name); int len = 0; byte[] buf = new byte[1024]; while ((len = in.read(buf)) != -1) { out.write(buf, 0, len); } in.close(); out.close(); } }} catch (Exception e) { // TODO Auto-generated catch block e.PRintStackTrace();}}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response);}}
##### 1.2 文件上傳若干需要注意的細節(jié) 1. 文件上傳時普通的輸入項中文的亂碼問題java//這里使用UTF-8進行解碼String fieldValue=fileItem.getString("UTF-8");2. 上傳時中文文件名稱亂碼java//設(shè)置解析事,中文文件名解析的碼表uploader.setHeaderEncoding("UTF-8");3. 上傳的時候,表單必須設(shè)置三個值.判斷文件上傳的時候,提交的數(shù)據(jù)是否是文件上傳的表單java//判斷是否文件上傳的表單if(!ServletFileUpload.isMultipartContent(request)){ //說明不是文件上傳的表單,下面的代碼不再執(zhí)行 request.setAttribute("message", "對不起,您的表單不符合規(guī)范,請檢查表單屬性設(shè)置..."); request.getRequestDispatcher("/upload.jsp").forward(request, response); return;}4. 限定上傳文件的大小.java//限定上傳文件的大小uploader.setFileSizeMax(102410242);//以kb為單位,限制單個文件大小uploader.setSizeMax(1024102420);//限制總的文件大小20M當(dāng)超過大小限制時,就會拋出異常.就可以捕獲異常javacatch (FileUploadBase.FileSizeLimitExceededException e) { // 單個文件大小超過限制 request.setAttribute("message", "對不起,上傳單個文件大小超過限制..."); request.getRequestDispatcher("/upload.jsp").forward(request, response); } catch (FileUploadBase.SizeLimitExceededException e) { // 總的文件大小超過限制 request.setAttribute("message", "對不起,總的文件大小超過限制..."); request.getRequestDispatcher("/upload.jsp").forward(request, response); }5. 限制上傳的文件類型java//將允許的文件類型準(zhǔn)備好String[] extensions={".jpg",".bmp",".png"};如果不合法javaboolean flag = false;for (String ex : extensions) { if (name.endsWith(ex)) { flag = true; break; }}if (!flag) { // 文件類型不合法,需要給用戶友好信息 request.setAttribute("message", "對不起,文件類型不合法..."); request.getRequestDispatcher("/upload.jsp").forward( request, response); return;}6. 針對不同瀏覽器解決文件上傳名稱的問題javaString name = fileItem.getName();// 有些瀏覽器獲得的name是E:/1.bmp// 這個索引是最后一個/所在索引位置int lastIndex = name.lastIndexOf("/");if (lastIndex != -1) { name = name.substring(lastIndex + 1);}7. 解決文件上傳時,同名文件被覆蓋問題.為了解決這個問題,生成文件名字要唯一,可以使用java提供的UUID的類.生成一個隨機128值.java//生成不同名文件名,避免覆蓋問題 name=UUID.randomUUID().toString().replace("-", "")+"_"+name;8. 上傳的內(nèi)容是惡意內(nèi)容,網(wǎng)站被攻擊 將上傳文件放在一個特定文件夾下,不讓外界直接訪問.上傳文件放在WEB-INF目錄下保護起來.java//獲得WEB-INF目錄下upload文件夾的路徑 String filePath=getServletContext().getRealPath("/WEB-INF/upload"); InputStream in = fileItem.getInputStream(); FileOutputStream out = new FileOutputStream(new File(filePath,UUIDName));
9. 避免上傳文件夾文件過多,導(dǎo)致打開文件夾出現(xiàn)性能上問題,比如文件過多,打開較慢需要設(shè)計一套算法,保障上傳文件分散放在多級目錄1.每隔一段時間創(chuàng)建一個文件夾,然后放上傳的文件2.哈希算法,根據(jù)hash值二進制每隔4位的值創(chuàng)建一層目錄.javaprivate String generatedRandomDir(String filePath, String uUIDName) { int hashCode = uUIDName.hashCode(); int dir1 = hashCode & 0xf;// 一級目錄 int dir2 = (hashCode >> 4) & 0xf;// 二級目錄 String path = filePath + File.separator + dir1 + File.separator + dir2; File file = new File(path); if (!file.exists()) { file.mkdirs(); } return path; }10. 上傳時設(shè)置監(jiān)聽器監(jiān)聽上傳進度javaProgressListener progressListener = new ProgressListener() { private long megaBytes = -1;
public void update(long pBytesRead, long pContentLength, int pItems) { long mBytes = pBytesRead / 1000000; if (megaBytes == mBytes) { return; } megaBytes = mBytes; System.out.println("We are currently reading item " + pItems); if (pContentLength == -1) { System.out.println("So far, " + pBytesRead + " bytes have been read."); } else { System.out.println("So far, " + pBytesRead + " of " + pContentLength + " bytes have been read."); } } }; // 設(shè)置監(jiān)聽器一定在解析之前設(shè)置 uploader.setProgressListener(progressListener);11. 為了加快上傳速度,可以設(shè)置臨時緩沖區(qū)大小以及上傳時臨時文件存放位置.上傳完成后,臨時文件給刪掉.java//設(shè)置臨時緩存區(qū)大小factory.setSizeThreshold(102412042);//2M//設(shè)置上傳時,臨時文件的位置factory.setRepository(new File(getServletContext().getRealPath("/tmp")));java//刪除臨時文件,該方法放在流關(guān)閉之后fileItem.delete();
實現(xiàn)代碼import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.List;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.FileUploadBase;import org.apache.commons.fileupload.ProgressListener;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;
public class Upload2Servlet extends HttpServlet { /** * 文件上傳,需要注意的問題 */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 將允許的文件類型準(zhǔn)備好 String[] extensions = { ".jpg", ".bmp", ".png" };
// 判斷是否文件上傳的表單 if (!ServletFileUpload.isMultipartContent(request)) { // 說明不是文件上傳的表單,下面的代碼不再執(zhí)行 request.setAttribute("message", "對不起,您的表單不符合規(guī)范,請檢查表單屬性設(shè)置..."); request.getRequestDispatcher("/upload.jsp").forward(request, response); return; } try { DiskFileItemFactory factory = new DiskFileItemFactory(); //設(shè)置臨時緩存區(qū)大小 factory.setSizeThreshold(1024*1204*2);//2M //設(shè)置上傳時,臨時文件的位置 factory.setRepository(new File(getServletContext().getRealPath("/tmp"))); ServletFileUpload uploader = new ServletFileUpload(factory); // 限定上傳文件的大小 uploader.setFileSizeMax(1024 * 1024 * 2);// 以kb為單位,限制單個文件大小 uploader.setSizeMax(1024 * 1024 * 20);// 限制總的文件大小20M // 設(shè)置解析事,中文文件名解析的碼表 uploader.setHeaderEncoding("UTF-8"); // 設(shè)置監(jiān)聽器,監(jiān)聽上傳進度 // 這里的update方法不定時被解析器調(diào)用到, // pBytesRead:上傳文件已經(jīng)解析多少 // pContentLength:上傳單個文件總的大小 // pItems:當(dāng)前上傳的是第幾個Item ProgressListener progressListener = new ProgressListener() { private long megaBytes = -1; public void update(long pBytesRead, long pContentLength, int pItems) { long mBytes = pBytesRead / 1000000; if (megaBytes == mBytes) { return; } megaBytes = mBytes; System.out.println("We are currently reading item " + pItems); if (pContentLength == -1) { System.out.println("So far, " + pBytesRead + " bytes have been read."); } else { System.out.println("So far, " + pBytesRead + " of " + pContentLength + " bytes have been read."); } } }; // 設(shè)置監(jiān)聽器一定在解析之前設(shè)置 uploader.setProgressListener(progressListener); List<FileItem> list = uploader.parseRequest(request); for (FileItem fileItem : list) { if (fileItem.isFormField()) { String fieldName = fileItem.getFieldName(); // 這里使用UTF-8進行解碼 String fieldValue = fileItem.getString("UTF-8"); } else { String name = fileItem.getName(); // 有些瀏覽器獲得的name是E:/1.bmp.針對不同瀏覽器解決上傳時文件名稱問題 // 這個索引是最后一個/所在索引位置 int lastIndex = name.lastIndexOf("//"); if (lastIndex != -1) { name = name.substring(lastIndex + 1); } boolean flag = false; for (String ex : extensions) { if (name.endsWith(ex)) { flag = true; break; } } if (!flag) { // 文件類型不合法,需要給用戶友好信息 request.setAttribute("message", "對不起,文件類型不合法..."); request.getRequestDispatcher("/upload.jsp").forward( request, response); return; } // 獲得WEB-INF目錄下upload文件夾的路徑 String filePath = getServletContext().getRealPath( "/WEB-INF/upload"); // 生成不同名文件名,避免覆蓋問題 String UUIDName = UUID.randomUUID().toString() .replace("-", "") + "_" + name; // 生成隨機文件夾,保存上傳文件 filePath = generatedRandomDir(filePath, UUIDName); InputStream in = fileItem.getInputStream(); FileOutputStream out = new FileOutputStream(new File( filePath, UUIDName)); int len = 0; byte[] buf = new byte[1024]; while ((len = in.read(buf)) != -1) { out.write(buf, 0, len); } in.close(); out.close(); //刪除臨時文件,該方法放在流關(guān)閉之后 fileItem.delete(); } } } catch (FileUploadBase.FileSizeLimitExceededException e) { // 單個文件大小超過限制 request.setAttribute("message", "對不起,上傳單個文件大小超過限制..."); request.getRequestDispatcher("/upload.jsp").forward(request, response); } catch (FileUploadBase.SizeLimitExceededException e) { // 總的文件大小超過限制 request.setAttribute("message", "對不起,總的文件大小超過限制..."); request.getRequestDispatcher("/upload.jsp").forward(request, response); } catch (Exception e) { e.printStackTrace(); }}private String generatedRandomDir(String filePath, String uUIDName) { int hashCode = uUIDName.hashCode(); int dir1 = hashCode & 0xf;// 一級目錄 int dir2 = (hashCode >> 4) & 0xf;// 二級目錄 String path = filePath + File.separator + dir1 + File.separator + dir2; File file = new File(path); if (!file.exists()) { file.mkdirs(); } return path;}public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response);}public static void main(String[] args) { System.out.println(UUID.randomUUID().toString().replace("-", ""));}}
#### 2. 文件下載1. 告訴瀏覽器以下載方式打開要訪問的數(shù)據(jù)//設(shè)置content-diposition:attachement:filename=1.txt2. 將下載的文件當(dāng)作一個流與response.getOutputStream關(guān)聯(lián)起來.javaInputStream in=new FileInputStream("d:/aa/bb/1.txt");OutputStream out=response.getOutStream();----IO流拷貝```
要求:
步驟:

sql create database upload_download; use upload_download; create table upfiles ( id varchar(100) primary key, uuidname varchar(80), filename varchar(80), savepath varchar(150), uploadtime timestamp,//數(shù)據(jù)庫自動將當(dāng)前時間插入 description varchar(255), username varchar(10) );導(dǎo)入jar包
準(zhǔn)備封裝數(shù)據(jù)的javaBean java package com.domain; import java.sql.Timestamp; /** create table upfiles ( id varchar(100) primary key, uuidname varchar(80), filename varchar(80), savepath varchar(150), uploadtime timestamp, description varchar(255), username varchar(10) ); */ public class UpFile { private String id; private String uuidname;//上傳文件的名稱,文件的uuid名 private String filename;//上傳文件的真實名稱 private String savepath;//上傳文件的路徑 private Timestamp uploadtime;//上傳時間 private String description;//文件描述 private String username;//上傳人 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUuidname() { return uuidname; } public void setUuidname(String uuidname) { this.uuidname = uuidname; } public String getFilename() { return filename; } public void setFilename(String filename) { this.filename = filename; } public String getSavepath() { return savepath; } public void setSavepath(String savepath) { this.savepath = savepath; } public Timestamp getUploadtime() { return uploadtime; } public void setUploadtime(Timestamp uploadtime) { this.uploadtime = uploadtime; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } }
package com.web; import java.io.IOException; import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;import org.apache.commons.fileupload.servlet.ServletFileUpload; import service.UpfileService; import com.domain.UpFile;import com.utils.WebUtils; public class UploadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 判斷是否是文件上傳的request if (!ServletFileUpload.isMultipartContent(request)) { // 說明不是文件上傳的表單,下面的代碼不再執(zhí)行 request.setAttribute("message", "對不起,您的表單不符合規(guī)范,請檢查表單屬性設(shè)置..."); request.getRequestDispatcher("/upload.jsp").forward(request, response); return; } // 封裝一個方法,完成文件上傳 UpFile upFile; try { upFile = WebUtils.doFileUpload(request); } catch (FileSizeLimitExceededException e) { request.setAttribute("message", "對不起,上傳單個文件大小超過限制..."); request.getRequestDispatcher("/upload.jsp").forward(request, response); return; } catch (SizeLimitExceededException e) { request.setAttribute("message", "對不起,總的文件大小超過限制.....20M."); request.getRequestDispatcher("/upload.jsp").forward(request, response); return; } // 判斷upFile是否為空,為空不執(zhí)行后面語句 if (upFile == null) { return; } System.out.println(upFile); UpfileService ups = new UpfileService(); ups.upload(upFile); // 上傳成功,給用戶友好提示 response.setContentType("text/html;charset=utf-8"); response.getWriter().print( "上傳成功<a href='" + request.getContextPath() + "/upload.jsp'>再次上傳</a>"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }package com.utils; import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.List;import java.util.UUID; import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils;import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.FileUploadBase;import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;import org.apache.commons.fileupload.ProgressListener;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload; import com.domain.UpFile; public class WebUtils { public static UpFile doFileUpload(HttpServletRequest request) throws FileSizeLimitExceededException, SizeLimitExceededException { UpFile upFile = new UpFile(); try { // 拿到工廠 DiskFileItemFactory factory = new DiskFileItemFactory(); // 設(shè)置臨時緩存區(qū)大小 factory.setSizeThreshold(1024 * 1204 * 2);// 2M // 設(shè)置上傳時,臨時文件的位置 factory.setRepository(new File(request.getsession() .getServletContext().getRealPath("/tmp"))); ServletFileUpload uploader = new ServletFileUpload(factory); // 限定上傳文件的大小 uploader.setFileSizeMax(1024 * 1024 * 2);// 以kb為單位,限制單個文件大小 uploader.setSizeMax(1024 * 1024 * 20);// 限制總的文件大小20M // 設(shè)置解析事,中文文件名解析的碼表 uploader.setHeaderEncoding("UTF-8"); // 設(shè)置監(jiān)聽器,監(jiān)聽上傳進度 // 這里的update方法不定時被解析器調(diào)用到 // pBytesRead:上傳文件已經(jīng)解析多少 // pContentLength:上傳單個文件總的大小 // pItems:當(dāng)前上傳的是第幾個Item ProgressListener progressListener = new ProgressListener() { private long megaBytes = -1; public void update(long pBytesRead, long pContentLength, int pItems) { long mBytes = pBytesRead / 1000000; if (megaBytes == mBytes) { return; } megaBytes = mBytes; System.out.println("We are currently reading item " + pItems); if (pContentLength == -1) { System.out.println("So far, " + pBytesRead + " bytes have been read."); } else { System.out.println("So far, " + pBytesRead + " of " + pContentLength + " bytes have been read."); } } }; // 設(shè)置監(jiān)聽器一定在解析之前設(shè)置 uploader.setProgressListener(progressListener); List<FileItem> list = uploader.parseRequest(request); for (FileItem fileItem : list) { if (fileItem.isFormField()) { String fieldName = fileItem.getFieldName(); // 這里使用UTF-8進行解碼 String fieldValue = fileItem.getString("UTF-8"); // 使用beanUtils封裝java類 // beanUtils封裝數(shù)據(jù),要求目標(biāo)javaBean字段名稱與表單提交過來的數(shù)據(jù)的名稱一樣,否則封裝不上 BeanUtils.setProperty(upFile, fieldName, fieldValue); } else { String filename = fileItem.getName(); // 有些瀏覽器獲得的name是E:/1.bmp.針對不同瀏覽器解決上傳時文件名稱問題 // 這個索引是最后一個/所在索引位置 int lastIndex = filename.lastIndexOf("//"); if (lastIndex != -1) { filename = filename.substring(lastIndex + 1); } // 獲得WEB-INF目錄下upload文件夾的路徑 String savepath = request.getSession().getServletContext() .getRealPath("/WEB-INF/upload"); // 生成不同名文件名,避免覆蓋問題 String uuidname = UUID.randomUUID().toString() .replace("-", "") + "_" + filename; // 生成隨機文件夾,保存上傳文件,避免性能問題 savepath = generatedRandomDir(savepath, uuidname); InputStream in = fileItem.getInputStream(); FileOutputStream out = new FileOutputStream(new File( savepath, uuidname)); int len = 0; byte[] buf = new byte[1024]; while ((len = in.read(buf)) != -1) { out.write(buf, 0, len); } in.close(); out.close(); // 刪除臨時文件 fileItem.delete(); upFile.setFilename(filename); upFile.setId(UUID.randomUUID().toString()); upFile.setUuidname(uuidname); upFile.setSavepath(savepath); } } return upFile; } catch (FileUploadBase.FileSizeLimitExceededException e) { throw e; } catch (FileUploadBase.SizeLimitExceededException e) { throw e; } catch (Exception e) { e.printStackTrace(); return null; } } private static String generatedRandomDir(String savepath, String uuidname) { int hashCode = uuidname.hashCode(); int dir1 = hashCode & 0xf;// 一級目錄 int dir2 = (hashCode >> 4) & 0xf;// 二級目錄 String path = savepath + File.separator + dir1 + File.separator + dir2; File file = new File(path); if (!file.exists()) { file.mkdirs(); } return path; }} 新聞熱點
疑難解答