DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> AJAX入門 >> AJAX詳解 >> AJAX+JSF組件實現高性能的文件上載(2)
AJAX+JSF組件實現高性能的文件上載(2)
編輯:AJAX詳解     
我們將實現一個具有AJax能力的組件——它不僅實現把文件上傳到服務器,而且"實時地"監視文件上傳的實際過程。   (四) ProgressMonitorFileItem類

public class ProgressMonitorFileItem extends DiskFileItem {
 private ProgressObserver observer;
 private long passedInFileSize;
 ...
 private boolean isFormFIEld;
 ...
 @Override
 public OutputStream getOutputStream() throws IOException {
  OutputStream baSEOutputStream = super.getOutputStream();
  if(isFormFIEld == false){
   return new BytesCountingOutputStream(baSEOutputStream);
  }else{return baSEOutputStream;}
 }
 ...
 private class BytesCountingOutputStream extends OutputStream{
  private long previousProgressUpdate;
  private OutputStream base;
  public BytesCountingOutputStream(OutputStream ous){ base = ous; }
  ...
  private void fireProgressEvent(int b){
   bytesRead += b;
   ...
   double progress = (((double)(bytesRead)) / passedInFileSize);
   progress *= 100.0
   observer.setProgress();
  }
 }
}
  ProgressMonitorFileItem把DiskFileItem的缺省OutputStream包裝到一個BytesCountingOutputStream中,這可以在每次讀取一定數目的字節後更新相關的ProgressObserver。

  (五) 支持AJax的JavaServer Faces(JSF)上傳組件

  這個組件負責生成Html文件上傳標簽,顯示一個進度條以監視文件上傳,並且生成一旦文件上傳成功需要被顯示的組件。使用JavaServer Faces實現這個組件的一個主要優點是,大多數復雜性被隱藏起來。開發人員只需要把組件標簽添加到JSP,而後由組件負責所有的AJax及相關的進度條監控細節問題。下面的JSP代碼片斷用於把上傳組件添加到頁面上。

<comp:fileUpload
 value="#{uploadPageBean.uploadedFile}"
 uploadIcon="images/upload.png"
 styleClass="progressBarDiv"
 progressBarStyleClass="progressBar"
 cellStyleClass="progressBarCell"
 activeStyleClass="progressBarActiveCell">
<%--下面是一旦文件上傳完成將成為可見的組件--%>
<h:panelGrid columns="2" cellpadding="2" cellspacing="0" width="100%">
<f:facet name="header">
<h:outputText styleClass="text"
value="文件上傳成功." />
</f:facet>
<h:panelGroup style="text-align:left;display:block;width:100%;">
<h:commandButton action="#{uploadPageBean.reset}"
image="images/reset.png"/>
</h:panelGroup>
<h:panelGroup style="text-align:right;display:block;width:100%;">
<h:commandButton action="#{uploadPageBean.nextPage}"
image="images/continue.png"/>
</h:panelGroup>
</h:panelGrid>
</comp:fileUpload>
  文件上傳組件的value屬性需要用一個擁有一個FileItem的屬性綁定到一個bean上。組件只有在該文件被服務器成功收到時才顯示。

  三、 實現AJax文件上傳組件

  實質上,上載組件或者生成一個完整的自已,或者在一個AJax請求的情況下,只生成部分XML以更新在頁面上進度條的狀態。為了防止JavaServer Faces生成完整的組件樹(這會帶來不必要的負荷),我們還需要實現一個PhaseListener(PagePhaseListener)以取消該faces的請求處理的其它部分-如果遇到一個AJax請求的話。我在本文中略去了所有的關於標准配置(faces-config.XML和標簽庫)的討論,因為它們相當直接且已經在以前討論過;而且這一切都包含在隨同本文的源碼中,你可以詳細分析。

  (一) AJax文件上傳組件生成器

  該組件和標簽類的實現比較簡單。大量的邏輯被包含到生成器中,具體地說,它負責以下:

  · 編碼整個的上傳組件(和完整的Html文件上傳標簽)、文件被上傳完成後要顯示的組件,還有實現AJax請求的客戶端JavaScript代碼。

  · 適當地處理部分AJax請求並且發送回必要的XML。

  · 解碼一個文件上傳並且把它設置為一個FileItem實例。

  (二) 編碼整個上傳組件

  前面已經提及,文件上傳組件由三個階段組成。在該組件的整個編碼期間,我們將詳細分析這三個階段的編碼。注意,在頁面上的該組件的可視化(使用CSS顯示)屬性將由AJax JavaScript來控制。

  (三) 階段一

  圖5顯示了該上傳組件的第一個階段。


圖5.選擇文件上傳

  在第一階段中,我們需要生成Html文件Upload標簽和點擊Upload按鈕時相應的執行代碼。一旦用戶點擊了Upload按鈕,表單將被一個IFRAME(為防止頁面阻塞)提交並初始化第二個階段。下面是生成代碼的一部分:

//文件上傳組件
writer.startElement("input", component);
writer.writeAttribute("type", "file", null);
writer.writeAttribute("name", component.getClIEntId(context), "id");
writer.writeAttribute("id", component.getClIEntId(context),"id");
if(input.getValue() != null){
 //如果可用,則生成該文件名.
 FileItem fileData = (FileItem)input.getValue();
 writer.writeAttribute("value", fileData.getName(), fileData.getName());
}
writer.endElement("input");
String iconURL = input.getUploadIcon();
//生成圖像,並把JavaScript事件依附到其上.
writer.startElement("div", component);
writer.writeAttribute("style","display:block;width:100%;text-align:center;", "style");
writer.startElement("img", component);
writer.writeAttribute("src",iconURL,"src");
writer.writeAttribute("type","image","type");
writer.writeAttribute("style","cursor:hand;cursor:pointer;","style");
UIForm form = FacesUtils.getForm(context,component);
if(form != null) {
 String getFormJS = "document.getElementById('" + form.getClIEntId(context) + "')";
 String JSFriendlyClientID = input.getClIEntId(context).replace(":","_");
 //設置表單的編碼為multipart以用於文件上傳,並且通過一個IFRAME
 //來提交它的內容。該組件的第二個階段也在500毫秒後被初始化.
 writer.writeAttribute("onclick",getFormJS + ".encoding='multipart/form-data';" +
getFormJS + ".target='" + iframeName + "';" + getFormJS + ".submit();" +
getFormJS + ".encoding='application/x-www-form-urlencoded';" +
getFormJS + ".target='_self';" +
"setTimeout('refreshProgress" + JSFriendlyClIEntID + "();',500);",null);
}
...
writer.endElement("img");
//現在實現我們將要把該文件/表單提交到的IFRAME.
writer.startElement("iframe", component);
writer.writeAttribute("id", iframeName, null);
writer.writeAttribute("name",iframeName,null);
writer.writeAttribute("style","display:none;",null);
writer.endElement("iframe");
writer.endElement("div");
writer.endElement("div"); //階段1結束
  (四) 階段二

  第二階段是顯示當前百分比的進度條和標簽,如圖6所示。該進度條是作為一個具有100個內嵌span標簽的div標簽實現的。這些將由AJax JavaScript根據來自於服務器的響應進行設置。


圖6.上傳文件到服務器
writer.startElement("div",component);
writer.writeAttribute("id", input.getClIEntId(context) + "_stage2", "id");
...
writer.writeAttribute("style","display:none", "style");
String progressBarID = component.getClIEntId(context) + "_progressBar";
String progressBarLabelID = component.getClIEntId(context) + "_progressBarlabel";
writer.startElement("div", component);
writer.writeAttribute("id",progressBarID,"id");
String progressBarStyleClass = input.getProgressBarStyleClass();
if(progressBarStyleClass != null)
writer.writeAttribute("class",progressBarStyleClass,"class");
for(int i=0;i<100;i++){
 writer.write("<span> </span>");
}
writer.endElement("div");
writer.startElement("div",component);
writer.writeAttribute("id",progressBarLabelID,"id");
...
writer.endElement("div");
writer.endElement("div"); //階段2結束
  (五) 階段三

  最後,作為階段三,一旦文件成功上傳,需要被顯示的組件即被生成,見圖7。這些是在生成器的encodeChildren方法中實現的。


圖7.上傳完成
public void encodeChildren(FacesContext context,
UIComponent component) throws IOException {
 ResponseWriter writer = context.getResponseWriter();
 UIFileUpload input = (UIFileUpload)component;
 //一旦文件上傳成功,處理將被顯示的子結點
 writer.startElement("div", component);
 writer.writeAttribute("id", input.getClIEntId(context) + "_stage3", "id"); //階段3.
 if(input.getValue() == null){
  writer.writeAttribute("style","display:none;",null);
 }else{
  writer.writeAttribute("style","display:block",null);
 }
 List<UIComponent> children = input.getChildren();
 for(UIComponent child : children){
  FacesUtils.encodeRecursive(context,child);
 }
 writer.endElement("div"); //階段3結束
}
XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved