Webwork 實作檔案上傳下載程式碼詳解_javascript技巧
本文主要從三個面向跟大家介紹webwork檔案上傳下載知識,包括以下三個面向:
1. 包裝 Request 請求
2. 取得檔案上傳的解析類別
3. 專案實戰配置與使用
Web上傳和下載應該是很普遍的一個需求,無論是小型網站還是大並發訪問的交易網站。 WebWork 當然也提供了很友好的攔截器來實現對文件的上傳,讓我們可以專注與業務邏輯的設計和實現,在實現上傳和下載時順便關注了下框架上傳下載的實現。
1. 包裝 Request 請求
•每次客戶端請求 Action 時,都會呼叫 WebWork 調度類別 ServletDispatcher.service()方法。
具體流程請參考:詳解Webwork中Action 呼叫的方法
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException { try { if (encoding != null) { try { request.setCharacterEncoding(encoding); } catch (Exception localException) { } } if (locale != null) { response.setLocale(locale); } if (this.paramsWorkaroundEnabled) { request.getParameter("foo"); } request = wrapRequest(request); //封装 request请求 serviceAction(request, response, getNameSpace(request), getActionName(request), getRequestMap(request), getParameterMap(request), getSessionMap(request), getApplicationMap()); } catch (IOException e) { String message = "Could not wrap servlet request with MultipartRequestWrapper!"; log.error(message, e); sendError(request, response, 500, new ServletException(message, e)); } }
先來看看 wrapRequest 方法做了什麼:
protected HttpServletRequest wrapRequest(HttpServletRequest request) throws IOException { if ((request instanceof MultiPartRequestWrapper)) { return request; } if (MultiPartRequest.isMultiPart(request)) { request = new MultiPartRequestWrapper(request, getSaveDir(), getMaxSize()); } return request; }
• 首先判斷了傳進來的 request 是不是已經被封裝好的 MultiPartRequestWrapper,如果是就直接回傳。
• 否則再判斷 request 的頭資訊裡面的 ContentType 是不是多型參數 (multipart/formdata)的請求,如果就把 request 包裝成 WebWork 自己的 MultiPartRequestWrapper 類型,該類型繼承HttpServletRequestWrapper 。
MultiPartRequest.isMultiPart() 方法實作如下:
public static boolean isMultiPart(HttpServletRequest request){ String content_type = request.getHeader("Content-Type"); return content_type != null && content_type.startsWith("multipart/form-data"); }
•在 webwork.properties 裡面設定檔的暫存目錄、還有最大上傳大小,其實就是在這個時候發揮作用的。
•建立 MultiPartRequestWrapper 物件的時候傳入的參數是由 getSaveDir() 和 getMaxSize() 方 法 取得 得 的 。
•在方法裡會尋找配置裡面的 webwork.multipart.saveDir、webwork.multipart.maxSize 屬性,找到則使用該屬性指定的臨時目錄和上傳的最大內容,沒找到就使用環境的臨時目錄。
具體實現如下:
protected String getSaveDir() { String saveDir = Configuration.getString("webwork.multipart.saveDir").trim(); if (saveDir.equals("")) { File tempdir = (File) getServletConfig().getServletContext().getAttribute("javax.servlet.context.tempdir"); log.info("Unable to find 'webwork.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir"); if (tempdir != null) { saveDir = tempdir.toString(); } } else { File multipartSaveDir = new File(saveDir); if (!multipartSaveDir.exists()) { multipartSaveDir.mkdir(); } } if (log.isDebugEnabled()) { log.debug("saveDir=" + saveDir); } return saveDir; }
2. 取得檔案上傳的解析類別
再來看一下 MultiPartRequestWrapper 的建構子使如何包裝 request 的:
public MultiPartRequestWrapper(HttpServletRequest request, String saveDir, int maxSize) throws IOException { super(request); if ((request instanceof MultiPartRequest)) { this.multi = ((MultiPartRequest) request); } else { String parser = ""; parser = Configuration.getString("webwork.multipart.parser"); if (parser.equals("")) { log.warn("Property webwork.multipart.parser not set. Using com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest"); parser = "com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest"; } else if (parser.equals("pell")) { parser = "com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest"; } else if (parser.equals("cos")) { parser = "com.opensymphony.webwork.dispatcher.multipart.CosMultiPartRequest"; } else if (parser.equals("jakarta")) { parser = "com.opensymphony.webwork.dispatcher.multipart.JakartaMultiPartRequest"; } try { Class baseClazz = MultiPartRequest.class; Class clazz = Class.forName(parser); if (!baseClazz.isAssignableFrom(clazz)) { addError("Class '" + parser + "' does not extend MultiPartRequest"); return; } Constructor ctor = clazz.getDeclaredConstructor(new Class[] { Class.forName("javax.servlet.http.HttpServletRequest"), String.class, Integer.TYPE }); Object[] parms = { request, saveDir, new Integer(maxSize) }; this.multi = ((MultiPartRequest) ctor.newInstance(parms)); } catch (ClassNotFoundException e) { addError("Class: " + parser + " not found."); } catch (NoSuchMethodException e) { addError("Constructor error for " + parser + ": " + e); } catch (InstantiationException e) { addError("Error instantiating " + parser + ": " + e); } catch (IllegalAccessException e) { addError("Access errror for " + parser + ": " + e); } catch (InvocationTargetException e) { addError(e.getTargetException().toString()); } } }
• 首先它判斷了傳入的 request 是不是 MultiPartRequest 抽象類別的子類,如果是就直接把自身的 MultiPartRequest 類型的變數引用 request。
• 否則讀取 WebWork 設定 的webwork.multipart.parser 屬性,該屬性決定 Webwork 內部以什麼實作檔案上傳。 如果沒有指定,則預設使用 PellMultiPartRequest 的實作。
•找到配置的類別後,WebWork 透過 Java 反射建立該類別的實例。所有支援的類別都是從 MultiPartRequest 繼承而來,創建該實例後向上轉型,並賦予 MultiPartRequestWrapper 的成員multi。
• WebWork 的檔案上傳封裝了幾款通用的 FileUpload lib,並不是自己實作的。
•它包括了pell,cos,apache common 三種實現,WebWork 對這三個包進行封裝,提供了一 個通用的訪問接口 MultiPartRequest,細節實現分別是 PellMultiPartRequest、 CosMultiPartRequest 、JakartaMultiPartRequest 。
• jakarta 支援多個檔案使用同一個HTTP參數名稱。如果直接使用WebWork 的FileUpload 攔截器,建議使用pell,因為當你上傳中文檔案名稱的檔案的時候,只有pell 套件會正確的獲得中文檔案名稱,apache common會將檔案名稱改為xxx.tmp這樣的文件名,而cos會亂碼, 因此我們唯一的選擇只有pell。
•cos 的功能比較強大,WebWork 的封裝卻使它喪失了許多的功能,cos 需要設定 request 的character encoding。 WebWork的封裝沒有設置,所以就導致了cos的亂碼問題,當然如果你單獨 使用cos,則會避免此類問題。
3. 專案實戰配置與使用
• 設定檔
action 配置:
<action name="uploadAttach" class=".....attach.action.uploadAttach" caption="上传附件"> <result name="success" type="dispatcher"> <param name="location">/result.jsp</param> </result> <result name="error" type="dispatcher"> <param name="location">/result.jsp</param> </result> <interceptor-ref name="defaultStack" /> <interceptor-ref name="fileUploadStack" /> //webwok 上传所需要的拦截栈 </action> //拦截栈的定义 <interceptor-stack name="fileUploadStack"> <interceptor-ref name="fileUpload"/> <interceptor-ref name="params"/> </interceptor-stack> //拦截栈对应的拦截器 <interceptor name="fileUpload" class="com.opensymphony.webwork.interceptor.FileUploadInterceptor"/> <interceptor name="params" class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/>
•前端使用比較穩定、功能比較強大的 Ajaxupload這裡就不多說了,有官方網址:jQuery AjaxUpload 上傳圖片代碼
•透過對 Webwork 上傳請求的封裝和解析類別的獲取,所有的前戲都已經準備妥當,上傳攔截器裡面具體實現如下:
public String intercept(ActionInvocation invocation) throws Exception {if (!(ServletActionContext.getRequest() instanceof MultiPartRequestWrapper)) { if (log.isDebugEnabled()) { log.debug("bypass " + invocation.getProxy().getNamespace() + "/" + invocation.getProxy().getActionName()); } return invocation.invoke(); } Action action = invocation.getAction(); ValidationAware validation = null; if ((action instanceof ValidationAware)) { validation = (ValidationAware) action; } MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) ServletActionContext.getRequest(); if (multiWrapper.hasErrors()) { Collection errors = multiWrapper.getErrors(); Iterator i = errors.iterator(); while (i.hasNext()) { String error = (String) i.next(); if (validation != null) { validation.addActionError(error); } log.error(error); } } Enumeration e = multiWrapper.getFileParameterNames(); while ((e != null) && (e.hasMoreElements())) { String inputName = (String) e.nextElement(); String[] contentType = multiWrapper.getContentTypes(inputName); String[] fileName = multiWrapper.getFileNames(inputName); File[] file = multiWrapper.getFiles(inputName); if (file != null) { for (int i = 0; i < file.length; i++) { log.info("file " + inputName + " " + contentType[i] + " " + fileName[i] + " " + file[i]); } } if (file == null) { if (validation != null) { validation.addFieldError(inputName, "Could not upload file(s). Perhaps it is too large?"); } log.error("Error uploading: " + fileName); } else { invocation.getInvocationContext().getParameters().put(inputName, file); invocation.getInvocationContext().getParameters().put(inputName + "ContentType", contentType); invocation.getInvocationContext().getParameters().put(inputName + "FileName", fileName); } } String result = invocation.invoke(); for (Enumeration e1 = multiWrapper.getFileParameterNames(); e1 != null && e1.hasMoreElements();) { String inputValue = (String) e1.nextElement(); File file[] = multiWrapper.getFiles(inputValue); for (int i = 0; i < file.length; i++) { File f = file[i]; log.info("removing file " + inputValue + " " + f); if (f != null && f.isFile()) f.delete(); } } return result; }
•首先判斷目前請求是否為 包含多媒體請求,如果是則記錄日誌,並執行 Action。
•接著判斷在檔案上傳過程 MultiPartRequestWrapper 是否含有錯誤,將錯誤訊息,傳回給客戶端,不在繼續呼叫 Action。
•如果上面的判斷條件都沒有進行,開始遍歷 MultiPartRequestWrapper 中的上傳檔案的參數,並將其中的檔案名稱、檔案內容類型放入Action 參數 map 中,供後面的業務類別進行操作。
•在WebWork 的fileupload 攔截器功能中,它提供的File只是一個臨時文件,Action 執行之後就會被自動刪除,你必須在Action中自己處理文件的儲存問題,或者寫到伺服器的某個目錄,或者儲存到資料庫中。如果你準備寫到伺服器的某個目錄下面的話,你必須自己面臨著處理檔案同名的問題,但是實際上cos套件已經提供了 檔案重名的自動重命名規則。
透過以上程式碼介紹了Webwork 實作檔案上傳下載的相關知識,希望對大家有幫助。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Python提供以下選項開啟下載檔案:open()函數:使用指定路徑和模式(如'r'、'w'、'a')開啟檔案。 Requests函式庫:使用其download()方法自動指派名稱並直接開啟檔案。 Pathlib函式庫:使用write_bytes()和read_text()方法寫入和讀取檔案內容。

實現Workerman文件中的文件上傳與下載,需要具體程式碼範例引言:Workerman是一款高效能的PHP非同步網路通訊框架,具備簡潔、高效、易用等特點。在實際開發中,文件上傳和下載是常見的功能需求,本文將介紹如何使用Workerman框架實現文件的上傳和下載,並給出具體的程式碼範例。一、檔案上傳:檔案上傳是指將本機上的檔案傳輸至伺服器端的操作。下面是使用

如何使用PHP函數進行郵件傳送和接收的附件上傳和下載?隨著現代通訊技術的快速發展,電子郵件已成為人們日常溝通和訊息傳遞的重要途徑。在Web開發中,經常會遇到需要發送和接收帶有附件的郵件的需求。 PHP作為一種強大的伺服器端腳本語言,提供了豐富的函數和類別庫,可以簡化郵件的處理過程。本文將介紹如何使用PHP函數進行郵件傳送和接收的附件上傳和下載。郵件發送首先,我們

如何利用Laravel實現文件上傳和下載功能Laravel是一個流行的PHPWeb框架,提供了豐富的功能和工具,使得開發Web應用程式更加簡單和有效率。其中一個常用的功能就是檔案上傳和下載。本文將介紹如何利用Laravel實作檔案上傳和下載功能,並提供具體的程式碼範例。文件上傳文件上傳是指將本機的文件上傳到伺服器上儲存。在Laravel中,我們可以使用檔案上傳

Laravel中的檔案上傳與處理:管理使用者上傳的檔案引言:在現代Web應用程式中,檔案上傳是很常見的功能需求。在Laravel框架中,文件上傳和處理變得非常簡單和有效率。本文將介紹如何在Laravel中管理使用者上傳的文件,包括文件上傳的驗證、儲存、處理和顯示。一、文件上傳文件上傳是指將文件從客戶端上傳到伺服器端。在Laravel中,檔案上傳非常容易處理。首先,

如何用PHP實作FTP檔案上傳進度條一、背景介紹在網站開發中,檔案上傳是常見的功能。而對於大檔案的上傳,為了提高使用者體驗,我們常常需要向使用者顯示一個上傳進度條,讓使用者知道檔案上傳的進程。本文將介紹如何使用PHP實作FTP檔案上傳進度條的功能。二、FTP檔案上傳進度條的實現方法基本思路FTP檔案上傳的進度條實現,通常是透過計算上傳的檔案大小和已上傳檔案大小

現如今,許多應用程式允許用戶進行檔案的上傳和下載。例如,抄襲檢測工具允許使用者上傳一個包含一些文字的文件檔案。然後,它會檢查抄襲並產生報告,用戶可以下載該報告。每個人都知道使用inputtypefile來建立一個上傳檔案按鈕,但是很少有開發者知道如何使用JavaScript/JQuery來建立一個檔案下載按鈕。本教學將教導點擊HTML按鈕或JavaScript時觸發檔案下載的各種方法。使用HTML的<a>標籤和download屬性,在按鈕點擊時觸發檔案下載每當我們給<a>標

如何解決Java檔案上傳異常(FileUploadException)上傳檔案在網路開發中經常會遇到的一個問題是FileUploadException(檔案上傳例外)。它可能會因各種原因而出現,例如檔案大小超過限制、檔案格式不符或伺服器配置不正確等。本文將介紹一些解決這些問題的方法,並提供相應的程式碼範例。限制上傳檔案的大小在大多數場景下,限製檔案大小
