DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> Webwork 實現文件上傳下載代碼詳解
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 的頭信息裡面的 Content­Type 是不是多類型參數 (multipart/form­data)的請求,如果是就把 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 實現文件上傳下載的相關知識,希望對大家有所幫助。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved