標籤:java 設計模式 開發工具 繼承 類
在使用java開發檔案上傳時,網路上有很多不一樣的工具。但是每次如果都需要開發一次,對於使用者來說,這個過程是浪費時間的。所以我們有必要選取其中一個適合自己的檔案上傳組件,然後對其進一步分裝,形成自己的開發工具類。下面我針對自己的工程,對fileupload進行了封裝。
fileupload是apache的一個組件,要想使用fileupload,需要用到下面兩個jar:commons-fileupload-1.3.1.jar,commons-io-1.1.jar(版本不一樣,可能相關jar包不一致,大家根據最新來下載即可)。
下載好相關的jar包,使用eclipse建立一個Dynamic Web Project,然後將jar添加到WEB-INF/lib下面。
由於fileupload組件使用非常簡單,所以大家可以參考官網的api,這是學習fileupload最後的一種方式。相關連結:fileupload
下面給出我自己的類和代碼:
package net.itaem.servlet;import java.io.File;import java.io.IOException;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.UUID;import javax.servlet.ServletConfig;import javax.servlet.ServletContext;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;/** * 檔案上傳的基類,該類可以被繼承 * 在設定檔,必須要配置相關的上傳屬性 * 這是一個父類,主要處理檔案的儲存,但是對於普通的表單域,由子類來實現 * 每個子類必須實現processNormalField(FileItem fileItem)方法 * 這裡採用了模板設計模式... * * */public abstract class FileuploadServletBase extends HttpServlet {/** * */private static final long serialVersionUID = 1L;//儲存檔案檔案夾private static String saveDir = null;//緩衝大小private static int tempCachedSize = 20480;//允許上傳的檔案類型private static String[] permittedFileType = null;//單個檔案的大小private static int fileSize = 20480;//最大允許上傳的表達大小private static int maxSize = 204800; //儲存上傳檔案的檔案夾private String savePath;//儲存上傳檔案的mapprivate Map<String, String> uploadedMap = new HashMap<String, String>();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {doPost(req, resp);}@SuppressWarnings("rawtypes")@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {//設定編碼req.setCharacterEncoding("utf-8");resp.setCharacterEncoding("utf-8");//建立一個DiskFileItemFactoryDiskFileItemFactory factory = new DiskFileItemFactory();factory.setRepository(new File(savePath)); //配置儲存路徑factory.setSizeThreshold(tempCachedSize); //配置緩衝大小//建立一個ServletFileUploadServletFileUpload upload = new ServletFileUpload(factory);upload.setSizeMax(maxSize); //設定總體表單大小upload.setFileSizeMax(fileSize); //設定單個檔案大小//處理表單try {List<FileItem> items = upload.parseRequest(req);Iterator itemsIterator = items.iterator();while(itemsIterator.hasNext()){FileItem fileItem = (FileItem)itemsIterator.next();if(!fileItem.isFormField()){ //檔案域//去掉不支援上傳的檔案類型boolean uploadedFlag = false;for(int i=0; i<permittedFileType.length; i++){if(permittedFileType[i].contains(fileItem.getContentType())){uploadedFlag = true;break;}}//如果檔案允許上傳,那麼儲存檔案到指定上傳檔案夾中if(uploadedFlag){String type = fileItem.getName().substring(fileItem.getName().lastIndexOf("."));File uploadedFile = newFile(type);//save the filefileItem.write(uploadedFile);//put the file name in a mapuploadedMap.put(fileItem.getFieldName(), uploadedFile.getCanonicalPath());}}else{ //普通表單域processNormalField(fileItem); }}//上傳完畢,進行相關的操作,比如關聯資料庫,或者將上傳檔案名稱儲存在xml等檔案中finishedProcess();} catch (FileUploadException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}} /** * 獲得一個隨機字串,作為上傳檔案的檔案名稱,防止檔案被複寫了 * @return 返回一個唯一的隨機字串 * */public String getRandomFileName(){UUID fileNameUUID = UUID.randomUUID();return fileNameUUID.toString();}@Overridepublic void init() throws ServletException {super.init();}/** * 初始化servlet,讀取設定檔的參數 * */@Overridepublic void init(ServletConfig config) throws ServletException {if(config.getInitParameter("saveDir") == null){throw new RuntimeException("參數saveDir不可為空");}else{saveDir = config.getInitParameter("saveDir").trim();}if(config.getInitParameter("permittedFileType") == null){throw new RuntimeException("參數permittedFileType不可為空");}else{permittedFileType = config.getInitParameter("permittedFileType").trim().split(",");}if(config.getInitParameter("fileSize") == null){throw new RuntimeException("參數fileSize不可為空");}else{fileSize = Integer.parseInt(config.getInitParameter("fileSize").trim());}if(config.getInitParameter("maxSize") == null){throw new RuntimeException("參數maxSize不可為空");}else{maxSize = Integer.parseInt(config.getInitParameter("maxSize").trim());}if(config.getInitParameter("tempCachedSize") == null){throw new RuntimeException("參數tempCachedSize不可為空");}else{tempCachedSize = Integer.parseInt(config.getInitParameter("tempCachedSize").trim());}//建立檔案夾,如果檔案夾不存在saveDir = createSaveDir(config.getServletContext(), saveDir);}/** * 建立檔案夾 * @param context 請求上下文 * @param dirName 檔案夾名字 * @return 返迴文件夾在當前工程中的路徑 * */private String createSaveDir(ServletContext context, String dirName) {String contextPath = context.getRealPath("/"); //獲得工程的savePath = contextPath + dirName;File dir = new File(savePath);if(!dir.exists()){ //如果檔案不存在,建立檔案夾dir.mkdir(); return savePath;}else{if(dir.isDirectory()){ //檔案夾存在,並且已經是檔案夾了,直接返回return savePath;}else{ throw new RuntimeException("該檔案" + savePath + "已經存在,請重新設定儲存上傳檔案的檔案夾名稱");}}}/** * * 這是一個抽象類別,由基類實現,這個方法主要用來處理普通的表單 * 使用模板設計模式... * 處理普通的表單域 * @param fileItem 普通表單域 * */public abstract void processNormalField(FileItem fileItem);/** * @param type 檔案類型 * 穿件一個隨機檔案,檔案的尾碼有type決定 * @return 隨機檔案 * */public File newFile(String type){return new File(savePath + File.separator + getRandomFileName() + type);}/** * 將所有的檔案名稱作為一個map返回 * key:表單網域名稱 * value:上傳檔案名稱 * @return 返回所有上傳檔案的map * */public Map<String, String> getUploadedMap(){return uploadedMap;}/** * 通過表單域找到上傳檔案之後的檔案名稱 * @param filedName 表單網域名稱 * @return 上傳之後的檔案名稱 * */public String getUploadedName(String fieldName){if(fieldName == null) return null;return uploadedMap.get(fieldName);}/** * 表單處理完畢,接下來處理相關操作,比如將上傳之後的檔案名稱儲存到資料庫庫之類的操作d * 通常情況下都會進行相關關聯 * */public abstract void finishedProcess();}
從類的定義中,我們可以看到,這個類是一個抽象類別,使用了方法樣板設計模式。
下面給出一個簡單實作類別:
package net.itaem.servlet;import java.util.Map;import org.apache.commons.fileupload.FileItem;/** * 檔案上傳的一個類 * 這裡處理了普通表單域 * * * */public class GenericFileUploadServlet extends FileuploadServletBase{/** * */private static final long serialVersionUID = 155452356367458695L;@Overridepublic void processNormalField(FileItem fileItem) { System.out.println(fileItem.getFieldName() + "--->" + fileItem.getString()); // do something here}/** * 表單處理完畢,接下來處理相關操作,比如將上傳之後的檔案名稱儲存到資料庫庫之類的操作d * */@Overridepublic void finishedProcess() {Map<String, String> uploadedMap = super.getUploadedMap(); //列印出每個表單域對應的上傳檔案名稱for(String fieldName: uploadedMap.keySet()){System.out.println(fieldName + "--->" + uploadedMap.get(fieldName));}} }
總結:
在實作類別GenericFileuploadServlet中,我們可以對普通的表單域進行處理,也可以對上傳之後的檔案作出想過處理。所以有了這個設計之後,每次我們可以手動在配置servlet中配置:儲存檔案夾的名字,緩衝大小,支援上傳的類型,最大支援上傳大小,單個檔案大小的資訊。下面給出我自己的配置:
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name></display-name> <servlet> <servlet-name>fileupload</servlet-name> <servlet-class>net.itaem.servlet.GenericFileUploadServlet</servlet-class> <init-param> <param-name>tempSaveDir</param-name> <param-value>temp_upload</param-value> </init-param> <init-param> <param-name>saveDir</param-name> <param-value>upload</param-value> </init-param> <init-param> <param-name>tempCachedSize</param-name> <param-value>2048000</param-value> </init-param> <init-param> <param-name>permittedFileType</param-name> <param-value>text/html,application/octet-stream,video/mp4</param-value> </init-param> <init-param> <param-name>fileSize</param-name> <param-value>204800000</param-value> </init-param> <init-param> <param-name>maxSize</param-name> <param-value>20480000</param-value> </init-param> <load-on-startup>10</load-on-startup> </servlet> <servlet-mapping> <servlet-name>fileupload</servlet-name> <url-pattern>/fileupload.do</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list></web-app>
注意點:
上傳之後的檔案,儲存檔案時,注意檔案名稱要具備唯一性。這裡使用UUID工具類來產生,哈哈,這個類在java.util包中。