AJAX+JSF组件实现高性能的文件上载(3)

ajax|js|性能

四、处理AJAX请求

  AJAX请求的生成是在这个组件的解码方法中处理的。我们需要检查这是否是一个实际的AJAX请求(为了区别于正常的编译行为),然后基于由ProgressMonitorFileItemFactory类的SessionUpdatingProgressObserver实例设置在会话中的值把一个XML响应发送回客户端。

public void decode(FacesContext context, UIComponent component) {
 UIFileUpload input = (UIFileUpload) component;
 //检查是否这是一个上传进度请求,或是一个实际的上传请求.
 ExternalContext extContext = context.getExternalContext();
 Map parameterMap = extContext.getRequestParameterMap();
 String clientId = input.getClientId(context);
 Map requestMap = extContext.getRequestParameterMap();
 if(requestMap.get(clientId) == null){
  return;//什么也不做,返回
 }
 if(parameterMap.containsKey(PROGRESS_REQUEST_PARAM_NAME)){
  //这是一个在该文件请求中的得到进度信息的请求.
  //得到该进度信息并把它生成为XML
  HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getResponse();
  //设置响应的头信息
  response.setContentType("text/xml");
  response.setHeader("Cache-Control", "no-cache");
  try {
   ResponseWriter writer = FacesUtils.setupResponseWriter(context);
   writer.startElement("progress", input);
   writer.startElement("percentage", input);
   //从会话中获得当前进度百分数(由过滤器所设置).
   Double progressCount = (Double)extContext.getSessionMap().
   get("FileUpload.Progress." +input.getClientId(context));
   if(progressCount != null){
    writer.writeText(progressCount, null);
   }else{
    writer.writeText("1", null);//我们还没有收到上传
   }
   writer.endElement("percentage");
   writer.startElement("clientId", input);
   writer.writeText(input.getClientId(context), null);
   writer.endElement("clientId");
   writer.endElement("progress");
  } catch(Exception e){
   //做一些错误记录...
  }
  }else{
   //正常的译码请求.
  ...

  五、 正常的译码行为

  在正常的编译期间,文件上传生成器从请求属性中检索FileItem,正是在此处它被过滤器所设置,并且更新该组件的值绑定。然后,该会话中的进度被更新到100%,这样在页面上的JavaScript就可以把组件送入第3个阶段。

//正常的译码请求.
if(requestMap.get(clientId).toString().equals("file")){
try{
 HttpServletRequest request = (HttpServletRequest)extContext.getRequest();
 FileItem fileData = (FileItem)request.getAttribute(clientId);
 if(fileData != null) input.setSubmittedValue(fileData);
 //现在我们需要清除与该项相关的任何进度
 extContext.getSessionMap().put("FileUpload.Progress." + input.getClientId(context),new Double(100));
}catch(Exception e){
 throw new RuntimeException("不能处理文件上传" +" - 请配置过滤器.",e);
}
}

  客户端JavaScript负责向服务器发出进度请求并通过不同阶段来移动组件。为了简化处理所有的浏览器特定的XMLHttpRequest对象的问题,我选用了Matt Krause提供的AjaxRequest.js库。该库最大限度地减少我们需要编写的JavaScript代码的数量,同时可以使这个组件正常工作。也许把这部分JavaScript代码打包为该组件的一部分,然后从PhaseListener生成它更好一些,但是,我已经通过定义一个到JSP页面上的JavaScript库的链接来尽力使得它简单。

  组件中的getProgressBarJavaScript方法被调用以生成JavaScript。使JavaScript正常工作通常是实现AJAX组件最困难的部分;不过我想,下面的代码已经非常清晰易于理解了。尽管在我的示例中JavaScript是嵌入到Java代码中的,但是把它放到一个外部独立的文件中也许更好一些。在本文中,我只是想使问题更为简单些且只关心本文的主题。下面是一个将由组件生成的JavaScript的示例。其中假定,fileUpload1是被赋值到该文件组件的客户端JSF Id,而uploadForm是HTML表单的Id。

function refreshProgress(){
 // 假定我们正在进入到阶段2.
 document.getElementById('fileUpload1_stage1').style.display = 'none';
 document.getElementById('fileUpload1_stage2').style.display = '';
 document.getElementById('fileUpload1_stage3').style.display = 'none';
 //创建AJAX寄送
 AjaxRequest.post(
 {
  //指定正确的参数,以便
  //该组件在服务器端被正确处理
  'parameters':{ 'uploadForm':'uploadForm',
  'fileUpload1':'fileUpload1',
  'jsf.component.UIFileUpload':'1',
  'ajax.abortPhase':'4' } //Abort at Phase 4.
  //指定成功处理相应的回调方法.
  ,'onSuccess':function(req) {
  var xml = req.responseXML;
  if( xml.getElementsByTagName('clientId').length == 0) {
   setTimeout('refreshProgress()',200); return;
  }
  var clientId = xml.getElementsByTagName('clientId');
  clientId = clientId[0].firstChild.nodeValue + '_progressBar';
  //从XML获取百分比
  var percentage = xml.getElementsByTagName('percentage')[0].firstChild.nodeValue;
  var innerSpans = document.getElementById(clientId).getElementsByTagName('span');
  document.getElementById(clientId + 'label').innerHTML = Math.round(percentage) + '%';
  //基于当前进度,设置这些span的式样类。
  for(var i=0;i<innerSpans.length;i++){
   if(i < percentage){
    innerSpans[i].className = 'active';
   }else{
    innerSpans[i].className = 'passive';
   }
  }
  //如果进度不是100,我们需要继续查询服务器以实现更新.
  if(percentage != 100){
   setTimeout('refreshProgress()',400);
  } else {
   //文件上传已经完成,我们现在需要把该组件送入到第3个阶段.
   document.getElementById('fileUpload1_stage1').style.display = 'none';
   document.getElementById('fileUpload1_stage2').style.display = 'none';
   document.getElementById('fileUpload1_stage3').style.display = '';
  }
 }
});
}
return builder.toString();

  六、 结论

  我很希望,本文能够在有关如何使得文件上传更具有用户友好性,并且把AJAX和JavaServer Faces用于实现高级用户接口组件的可能性方面引发你的进一步思考。毫无疑问,本文中的方案比较冗长并且有可能得到进一步的改进。我希望你能详细地分析一下本文中所提供的完整的源代码来深入理解本文中所讨论的概念。

时间: 2024-10-01 21:38:30

AJAX+JSF组件实现高性能的文件上载(3)的相关文章

AJAX+JSF组件实现高性能的文件上载(2)

ajax|js|性能 我们将实现一个具有AJAX能力的组件--它不仅实现把文件上传到服务器,而且"实时地"监视文件上传的实际过程. (四) ProgressMonitorFileItem类 public class ProgressMonitorFileItem extends DiskFileItem { private ProgressObserver observer; private long passedInFileSize; ... private boolean isFo

AJAX+JSF组件实现高性能的文件上载(1)

ajax|js|性能 一. 引言 基于浏览器的文件上传,特别是对于通过<input type="file">标签包含到Web页面来实现上传的情况,还存在较严重的性能问题.我们知道,超过10MB的上传文件经常导致一种非常痛苦的用户体验.一旦用户提交了文件,在浏览器把文件上传到服务器的过程中,界面看上去似乎处于静止状态.由于这一切发生在后台,所以许多没有耐心的用户开始认为服务器"挂"了,因而再次提交文件,这当然使得情况变得更糟糕. 为了尽可能使得文件上传感觉

AJAX+JSF组件实现高性能的文件上载

一. 引言 基于浏览器的文件上传,特别是对于通过<input type="file">标签包含到Web页面来实现上传的情况,还存在较严重的性能问题.我们知道,超过10MB的上传文件经常导致一种非常痛苦的用户体验.一旦用户提交了文件,在浏览器把文件上传到服务器的过程中,界面看上去似乎处于静止状态.由于这一切发生在后台,所以许多没有耐心的用户开始认为服务器"挂"了,因而再次提交文件,这当然使得情况变得更糟糕. 为了尽可能使得文件上传感觉更友好些,一旦用户提交

AJAX+JSF组件 实现高性能的文件上传

一. 引言 基于浏览器的文件上传,特别是对于通过<input type="file">标签包含到Web页面来实现上传的情况,还存在较严重的性能问题.我们知道,超过10MB的上传文件经常导致一种非常痛苦的用户体验.一旦用户提交了文件,在浏览器把文件上传到服务器的过程中,界面看上去似乎处于静止状态.由于这一切发生在后台,所以许多没有耐心的用户开始认为服务器"挂"了,因而再次提交文件,这当然使得情况变得更糟糕. 为了尽可能使得文件上传感觉更友好些,一旦用户提交

QFaces1.2 --Ajax方式,带进度条的文件上传组件FileUpload(for JSF)

这是QFaces的第4个组件,Ajax方式带进度条的文件上传组件,我希望每一个重要组件都提升一个版本, 呵呵!这个版本同时修正了ie6下的ajax兼容问题.在介绍完这个组件之后,打算介绍一下如何利用QFaces自 定义自己的Ajax组件,希望这个增强框架能对喜欢JSF的人有一些帮助.后面版本的升级可能就不会这么快, 或者考虑兼容一下facelets,并修正一些可能出现的错误,还有开源计划,然后继续维护并增加一些比较常 用与实用的组件,关注一下JSF2.0的发展等等. 好了,下面介绍一下QFace

使用JSF和MyFaces实现文件上载

js Web浏览器为我们利用Web应用程序发送文件提供了一条简单的途径,但是当前版本的Java Web标准(servlets.JSP和JSF)却无法为我们提供任何帮助.幸运的是,有一些第三方框架组件(例如Apache Commons File Upload. Apache MyFaces和Oracle ADF Faces)实现了这种特性,它们都暴露了简单的API和定制的标记(tag). 本文的前面一部分介绍文件上载操作是如何实现的,解释了MyFaces和通用文件上载(前者在内部使用了后者).我们

利用DWR开发基于Ajax的文件上载portlet

简介 Web 门户为用户提供了访问各种资源和服务的中心网关.与此同时,它们还为用户提供了与其他用户进行资源共享的平台.从照片到音频.视频文件再到研究用的科学数据集,用户可以共享任何内容.因此,文件上载是 Web 门户的一种基本的必备功能. 当今的 Web 门户在很大程度上依赖于 Java portlet 技术.虽然很多使用 Ajax 的开发人员都给出了各种各样的文件上载进度条解决方案,但我们还没有听说过哪个是基于 portlet 的.本文展示了如何开发基于 Ajax 的文件上载 portlet,

ASP无组件上载,带进度条,多文件上载

无组件 Example.asp <%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%><!--#include file="SundyUpload.asp"--><%'此例子文档编码都是UTF-8,如果是其他编码的系统,请将编码转换为相应的编码,不然表单获取数据可能会乱码Dim objUpload,optDim xmlPathDim fileFormName,objFile,counter

无组件上载,带进度条,多文件上载一

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%> <!--#include file="SundyUpload.asp"--> <% \'\'此例子文档编码都是UTF-8,如果是其他编码的系统,请将编码转换为相应的编码,不然表单获取数据可能会乱码 Dim objUpload,opt Dim xmlPath Dim fileFormName,objFile,counter opt =