AJAX+JSF組件實現高效能的檔案上傳(2)

來源:互聯網
上載者:User
ajax|js|效能 我們將實現一個具有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結束
}


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.