AJAX與JSF實現帶進度條的批量上傳文件實例

轉載於:http://blog.csdn.net/Adali/archive/2007/08/27/1761028.aspx

一。NetBeans 5.5.1 中的樣例:

NetBeans 5.5.1中自帶了一個“文件上載“的例子,使用這個例子,請先下載並安裝以下軟件:

  1. JAVA SE 5 (JDK 1.5) 及以上版本http://java.sun.com/javase/downloads/index.jsp

  2. NetBeans 5.5.1http://zh-cn.netbeans.org/index_zh_CN.html

  3. Sun Application Server 9.0https://glassfish.dev.java.net/ 

2+3可以下載“NetBeans IDE 5.5.1 with Java EE Application Server 9.0 U1 Patch 1 bundle ”http://www.netbeans.info/downloads/index.php?rs=22&p=3

NetBeans中,選擇菜單“新建項目”-〉“類別”中選擇“樣例”-〉“Java BluePrint Solution” ->AJAX編程模型。項目中選擇“文件上載”。項目名缺省爲“fileupload”

運行項目“fileupload”, 並且選擇幾個上傳文件,文件類型可以多種多樣,比如pdf, jar, ra, zip, jpeg, gif等等。可以看到如下界面。


傳輸完畢,可以看到如下結果。



顯示了上傳文件開始,結束的的時間,上傳文件總的字節數目等等。

項目“fileupload”/web/docs/下有一個fileupload.html 的文檔,解釋了這個上傳文件的參數及使用(English)。文件上載是一個JSF控件,開發者需要了解的除了如何在服務器端處理請求中的參數,如何在客戶端顯示響應信息外,所需要了解的僅僅是一些參數的設置。如這個例子中的代碼所示:

參數如下:

id

文件上載JSF控件的標識

serverLocationDir

文件上載的目標目錄。在示範例子中未給出這個參數的應用。缺省的情況下,文件會上載到Sun application Server domains/domain1/lib/upload目錄下。

retFunction

JavaScript 的回調函數,用於客戶端出來服務器返回的響應信息。

retMimeType

服務器端返回響應信息的類型,缺省的是“text/xml ”

postProcessingMethod

服務器端用來處理請求信息的方法。

progressBarDivId

進度條的Id

progressBarSubmitId

和進度條關聯的觸發文件上載的id。示範例子中是“submit”按鈕

progressBarSize

進度條的大小

二。使用FileUpload控件建立實例PhotoAlbum

下面給出另外一個使用這個上傳文件的小例子PhotoAlbum,最主要是爲了說明如何提取上傳後的文件名,以及如何用AJAX技術來部分刷新上傳頁面。另外想借這個例子用 NetBeans開發JSF程序的一般流程。

1NetBeans中選擇菜單“新建項目”。“類別“中選擇“Web”, 項目中選擇“Web應用程序”。

2。“新建Web應用程序”窗口中,輸入及選擇以下內容:

項目名稱:PhotoAlbum

源代碼結構:Java BluePrints

服務器:Sun Java System Application Server 9

Java EE 版本:Java EE 5



注意:如果服務器選擇中沒有出現“Sun Java System Application Server 9”。請在NetBeans中,選擇菜單” 窗口”->“ 運行時”. 在”運行環境”窗口中,鼠標右鍵選擇”服務器”, 點擊”添加服務器”。在”平臺文件夾位置”中選擇安裝”Sun Java System Application Server 9”的目錄。在下一個窗口中,輸入服務器的管理用戶名和密碼(缺省管理用戶名和密碼是“ admin/adminadmin”)。 

3。下一個窗口中,選擇“Java Server Faces”框架。點擊“完成”



4。選擇項目“PhotoAlbum”中的庫,右鍵選擇“添加jar/文件夾”,加入文件上載所需要的幾個jar文件。在NetBeans安裝目錄下,例如C:/Java/netbeans-5.5.1/enterprise3/modules/ext/blueprints,加入以下五個jar文件

shale-remoting.jar

bp-ui-5.jar

commons-logging-1.1.jar

commons-io-1.2.jar

commons-fileupload-1.1.1.jar

需要注意的是: 爲了完成下面的例子,有兩個jar文件需要比較新的版本,並且需要加入庫rome-0.8.jar. 爲方便起見,本文給出下載的jar文件,

最後的庫文件爲六個:

             shale-remoting-1.0.4.jar (http://download.csdn.net/source/236129)

bp-ui-5-0.8.jar (http://download.csdn.net/source/236127)

rome-0.8.jar (http://download.csdn.net/source/236128)

commons-logging-1.1.jar

commons-io-1.2.jar

commons-fileupload-1.1.1.jar 

5。在項目“PhotoAlbum”中的Web目錄下,手工創建一個目錄images. 如果PhotoAlbum的工作目錄是e:/mymodules/PhotoAlbum, 那麼這個目錄的絕對路徑是:E:/mymodules/PhotoAlbum/web/images.

6。創建JSF Bean, 鼠標右鍵點擊項目“PhotoAlbum”中,選擇“新建文件/文件夾”。在類別中選擇“Web”, 在“文件類型”中選擇“JSF受管Bean”



7。“新建JSF受管Bean”窗口中,輸入:

類名:FileUploadBackBean

包:com.sun.sdn.demo.jsf



這步創建完之後,可以查看項目“PhotoAlbum”中“配置文件“下的“faces-config.xml”, 可以看到剛創建的“FileUploadBackBean”已經自動加入到配置文件中。

 

        <managed-bean>
            
<managed-bean-name>FileUploadBackBean</managed-bean-name>
            
<managed-bean-class>com.sun.sdn.demo.jsf.FileUploadBackBean</managed-bean-class>
            
<managed-bean-scope>request</managed-bean-scope>
        
</managed-bean>


8。在 FileUploadBackBean 加入如下代碼:

 

/*
 * FileUploadBackBean.java
 *
 * Created on 2007年8月27日, 下午2:48
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 
*/


package com.sun.sdn.demo.jsf;
import java.util.Enumeration;
import java.util.Hashtable;
import java.io.IOException;

import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.servlet.ServletContext;
import org.apache.shale.remoting.faces.ResponseFactory;

import com.sun.javaee.blueprints.components.ui.fileupload.FileUploadStatus;
/**
 *
 * 
@author Ada Li
 
*/

public class FileUploadBackBean {
    
/**
     * <p>Factory for response writers that we can use to construct the
     * outgoing response.</p>
     
*/

    
private static ResponseFactory factory = new ResponseFactory();
    
private String serverLocationDir = "E:/mymodules/PhotoAlbum/build/web/images";
    String imageRootUrl 
= "../images";
    
    
/** Creates a new instance of FileUploadBackBean */
    
public FileUploadBackBean() {
    }

    
public void postProcessingMethod(FacesContext context, Hashtable htUpload, FileUploadStatus status) {
        
// set custom return enabled so Phaselistener knows not to send default response
        status.enableCustomReturn();
        
// Acquire a response containing these results
        ResponseWriter writer = factory.getResponseWriter(context, "text/xml");
        
try {
            writer.startElement(
"response"null);
            
            String imageFileLocation 
= "";
            
for (Enumeration e = htUpload.keys() ; e.hasMoreElements() ;) {
                String key 
= (String)e.nextElement();
                
//System.out.println(key.substring(0, 13));
                if (key.substring(013).equals("fileLocation_")){
                    imageFileLocation 
= (String)htUpload.get(key);
                    String fileName 
= imageFileLocation.replaceFirst(getServerLocationDir(), "");
                    String imageFileUrl 
= imageRootUrl + fileName;
                    writer.startElement(
"imageFileUrl"null);
                    writer.write(imageFileUrl);
                    writer.endElement(
"imageFileUrl");
                }

            }

            writer.endElement(
"response");
            writer.flush();
        }
 catch (IOException iox) {
            System.out.println(
"FileUploadPhaseListener error writting AJAX response : " + iox);
        }

    }

    
public String getServerLocationDir() {
        
return serverLocationDir;
    }

    
public void setServerLocationDir(String serverLocationDir) {
        
this.serverLocationDir = serverLocationDir;
    }
    
}

FileUploadBackBean中有兩個參數需要根據情況設定,即 serverLocationDir imageRootUrl 。因爲PhotoAlbum缺省部署完成後,項目在應用服務器中的部署位置就是/build目錄。在這個例子中,文件上載到/build/images目錄下,因此還需要手工在PhotoAlbumweb目錄下建立一個images目錄,PhotoAlbum部署完成後,在/build/目錄下自動會建立images目錄。

上載後的文件放在/build/images目錄下,通過瀏覽器訪問的話,URLhttp://localhost:8080/PhotoAlbum/images/XXXX.jpg, 因此,獲得上傳的文件名之後,之前要加上相對路徑“../images”.

文件中方法 postProcessingMethod 的主要作用是提取上傳文件名,並生成xml格式的響應信息。信息的格式如下:

 

<response>
    
<imageFileUrl>../images/Bike.jpg</imageFileUrl>
    
<imageFileUrl>../images/Bungee.jpg</imageFileUrl>
    
<imageFileUrl>../images/Duke.in.City.jpg</imageFileUrl>
    
<imageFileUrl>../images/Pointing.jpg</imageFileUrl>
    
<imageFileUrl>../images/Thiniing.jpg</imageFileUrl>
</response>

9。現在開始寫JSP頁面。在PhotoAlbum項目中,加入JSF框架之後,項目中自動加入了一個WelcomJSF.jsp頁面。修改後的WelcomJSF.jsp代碼如下:

 

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@taglib uri="http://java.sun.com/blueprints/ui" prefix="ui" %>
<html>
<head>
<title>AJAX與JSF實現帶進度條的批量文件上載</title>
<script>

    function props(namex) 
{
        var listx
="";
        var ob
=dojo.byId(namex);
        
for(xx in ob) {
            listx 
+= xx + " = " + ob[xx] + "<br/>"
        }

        
//document.write(listx);
        alert(listx);
    }

    
    function testRetFunction(type, data, evt)
{
        
// handle successful response here
        var photoAlbum = document.getElementById("photo_album");
        var resultx 
= data.getElementsByTagName("response")[0];
        
if(resultx) {
            var photoAlbum 
= document.getElementById("photo_album");

            var tb 
= document.createElement("table");
            tb.setAttribute(
"border"1);
            var tbody 
= document.createElement("tbody");
            var tr 
= document.createElement("tr"); 
            tb.insertBefore(tbody, 
null);
            tbody.insertBefore(tr, 
null);                  
            photoAlbum.insertBefore(tb, 
null); 
            
            var imageUrls 
= resultx.getElementsByTagName("imageFileUrl");
            
for (var i=0; i<imageUrls.length; i++){
                var td 
= document.createElement("td");
                td.setAttribute(
"width""20%");
                td.setAttribute(
"valigh""top");
            
                var url 
= imageUrls[i].childNodes[0].nodeValue;
                var image 
= document.createElement("img");
                image.setAttribute(
"src", url);
                image.setAttribute(
"width""100");

                td.insertBefore(image, 
null);
                tr.insertBefore(td, 
null);
            }

        }

    }

    
</script>
</head>
<body>
    
<h1>AJAX與JSF實現帶進度條的批量文件上載</h1>
    
    
<f:view>

        
<table border="1" colspacing="5" colpadding="5">
            
<tr>
                
<td>
                    
<br/>
                    
<ui:fileUploadTag id="TestFileuploadForm0" 
                    serverLocationDir
="#{FileUploadBackBean.serverLocationDir}" 
                        retFunction
="testRetFunction" retMimeType="text/xml" 
                        postProcessingMethod
="#{FileUploadBackBean.postProcessingMethod}"
                        progressBarDivId
="progress1x" progressBarSubmitId="submit1x" progressBarSize="40">
                        
<input type="file" size="40" name="fileToUpload0" id="fileToUpload0Id"/><br/>
                        
<input type="file" size="40" name="fileToUpload1" id="fileToUpload1Id"/><br/>
                        
<input type="file" size="40" name="fileToUpload2" id="fileToUpload2Id"/><br/>
                        
<input type="file" size="40" name="fileToUpload3" id="fileToUpload3Id"/><br/>
                        
<input type="file" size="40" name="fileToUpload4" id="fileToUpload4Id"/><br/>
                        
<input type="submit" id="submit1x" name="submit1x" value="Submit"/><br/>
                        
<div id="progress1x"></div><br/>                    
                    
</ui:fileUploadTag>
                
</td>
            
</tr>
        
</table>
        
<br><br>
        
<div id="photo_album"></div>
    
</f:view>
</body>
</html>

welcomeJSF.jsp頁面中,重點就是JavaScript函數 testRetFunction(), 它作爲AJAX中客戶端的回調函數, 接受來自服務器端的響應信息後,通過DOM技術, 在原有頁面上,動態地創建了tableimg 對象,來顯示上傳的圖像.

FileUploadBackBean 聲明瞭屬性 serverLocationDir ,並且有對這個屬性的setget方法,那麼在JSF中,對這個屬性的調用可以直接是#{FileUploadBackBean.serverLocationDir}

10。運行的結果如下



三。小結

JSF(JavaServer Faces)主要的目的是把表示和動作分開。在通常的JSP開發中, Http請求映射到事件處理器,在服務器端操作頁面控件,都不是很方便。而JSF技術分離了動作和表示,可以讓開發者更專注於自己的領域,而把一些映射的工作或者底層的工作交給框架來實現。

JSF提供了大量的tab library, 前面的文件上載的控件就是其中之一。在使用這個控件的時候,可以注意到,編寫Bean時,並不需要直接從HttpRequest中讀取參數值,並且在返回響應信息時候,也並沒有在代碼中直接指定具體的頁面。AJAXJSF的應用中,體現在增加了JavaScript回調函數的接口,就是WelcomJSF.jsp中的函數testRetFunction()

PhotoAlbum作爲一個示例,代碼中缺少一些必要的環節,比如對文件類型的判斷,比如返回出錯信息給客戶端。這些留給讀者來完成吧。AJAX應用在JSF上感興趣的朋友,可以參考開源軟件Java[TM] BluePrints Solutions Catalog for Java EE 5 https://blueprints.dev.java.net/bpcatalog/ee5/index.html

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章