首頁 >web前端 >js教程 >Webwork 實作檔案上傳下載程式碼詳解_javascript技巧

Webwork 實作檔案上傳下載程式碼詳解_javascript技巧

WBOY
WBOY原創
2016-05-16 15:16:271600瀏覽

本文主要從三個面向跟大家介紹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&#63;");
}
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 實作檔案上傳下載的相關知識,希望對大家有幫助。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn