论坛首页 Web前端技术论坛

DWR3 文件上传显示进度条

浏览 16617 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-12-13   最后修改:2011-12-22
DWR
最近刚开始学dwr,发现使用起来确实方便多了。现在公司正好有需求要使用文件上传,所以就研究了一下dwr3的文件上传和下载。

上传很方便,但是要显示进度条,我没找到相关的接口,我觉得dwr3应该会提供一个方便的接口用来显示进度条,后来研究dwr3的源码,发现在上传文件时,发现有下面的一段代码
if (session != null)
        {
            fileUploader.setProgressListener(new SessionProgressListener(session));
            session.setAttribute(SessionProgressListener.CANCEL_UPLOAD, null);
            session.setAttribute(PROGRESS_LISTENER, fileUploader.getProgressListener());
        }


这里set了一个进度监听,并且放到session中,于是我就打算不断的从session中获取这个SessionProgressListener,然后使用dwr3推送技术,调用前台的js来改变进度条。

这就是我大概实现的思路,虽然我觉得这样很笨,但是我目前只能这样来获取上次的进度,不知道各位大侠有没有更好的办法。

下面是相关的代码:
1.前台:
<%@ page language="java" contentType="text/html; charset=GBK"
	pageEncoding="GBK"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
	<head>
		<%@ include file="/jsp/common/include.jsp"%>
		<meta http-equiv="Content-Type" content="text/html; charset=GBK">
		<title>DWR HELLO</title>
		<style type="text/css">
		.ProgressBar {
		    position: relative;
		    width: 350px;    /* 宽度 */
		    border: 1px solid #B1D632;
		    padding: 1px;
			text-align:left;
		}
		.ProgressBar div {
		    display: block;
		    position: relative;
		    background: #B1D632;
		    color: #333333;
		    height: 20px; /* 高度 */
		    line-height: 20px;  /* 必须和高度一致,文本才能垂直居中 */
			text-align:left;
		}
		.ProgressBar div span { 
		    position: absolute;
		    width: 350px; /* 宽度 */
		    text-align: center;
		    font-weight: bold;
		}
	</style>

		<script type='text/javascript' src='${contextPath }/dwr/engine.js'> </script>
		<script type='text/javascript' src='${contextPath }/dwr/util.js'> </script>
		<script type='text/javascript'
			src='${contextPath }/dwr/interface/FileUpload.js'> </script>
		<script type='text/javascript'
			src='${contextPath }/dwr/interface/UploadListener.js'> </script>

		<script type='text/javascript'
			src='${contextPath }/js/dwrjs/dwrHelper.js'> </script>
		<script type='text/javascript'
			src='${contextPath }/js/dwrjs/upload.js'> </script>
		<script type='text/javascript'
			src='${contextPath }/js/zdialog/zDrag.js'> </script>
		<script type='text/javascript'
			src='${contextPath }/js/zdialog/zDialog.js'> </script>

		<script type="text/javascript">
		
			function addFile(){  
				if($("#uploadFile").val()==null || $("#uploadFile").val().length <= 0){
					return ;
				}
			    var uploadFile = dwr.util.getValue("uploadFile"); 
				//初始化上传信息
				progressBarInit($("#uploadFile").val());  
				//显示上传进度信息
			    showDialog();
			    //DWR3 文件上传
			    FileUpload.upload(uploadFile, {
					callback : function(data){
						 Dialog.close();
				    	$("#file_list").html($("#file_list").html()+"<a href='javascript:void(0);' onclick='downloadFile(\"" + data + "\")'>" + data + "</a><br>");
				    }
				});
			    //开始监听上传数据 0.6秒推送一次
			    UploadListener.listener();
			}
			/**
			**只能下载小文件,寻求解决方法
			*/
			function downloadFile(data) {
				//alert(data);
		       	FileUpload.download(data, function(data) { 
		       		//alert(data); 
		       		dwr.engine.openInDownload(data);
		       	});
		   }
		   
			/**
			**利用弹出插件,显示进度
			*/
			function showDialog(){
				
				var diag = new Dialog();
				diag.Width = 400;
				diag.Height = 300;
				diag.Title = "上传信息";
				diag.InvokeElementId="upload_info" ;
				diag.ShowCloseButton = false ;
				//diag.OKEvent = function(){};//点击确定后调用的方法
				diag.show();
			}
		</script>
	</head>
	<body onload="reverseAjax();">
		<p>
			<input type="file" name="uploadFile" id="uploadFile" />

			<input type="button" onclick="addFile()" value="上传" />
		</p>
		 <table>
		 	<tr><td id="file_list"></td></tr>
		 </table>
		 <table id="upload_info" style="width:400px;text-align:left;display:none;">
		 	<tr>
		 		<td width="30%">上传文件名:</td>
		 		<td><span id="upload_file_name">&nbsp;</span></td>
		 	</tr>
		 	<tr>
		 		<td>文件总大小:</td>
		 		<td><span id="upload_file_size">0 KB</span></td>
		 	</tr>
		 	<tr>
		 		<td>上传用时:</td>
		 		<td><span id="upload_time">0 秒</span></td>
		 	</tr>
		 	<tr>
		 		<td>上传速度:</td>
		 		<td><span id="upload_speed">0 KB/s</span></td>
		 	</tr>
		 	<tr><td id="upload_text" colspan="2">文件上传中,请稍等……</td></tr>
		 	<tr>
		 		<td colspan="2">
				<div class="ProgressBar">
					<div id="progress_bar" style="width: 0%;">
						<span id="progress_percent">0%</span>
					</div>
				</div>
				</td>
			</tr>
		 </table>
	</body>
</html>



其中 upload.js 代码如下:
/**
* @zongb
*/
var $$ = function (id){return document.getElementById(id)} ;

function updateProgress(uploadInfo){
   
	var progressPercent = Math.ceil((uploadInfo.bytesRead / uploadInfo.totalSize) * 100);
    var secondsElapsed = Math.ceil(uploadInfo.deltaTime/1000);
    var speed = Math.ceil(uploadInfo.bytesRead / (uploadInfo.deltaTime/1000 * 1024));
    
   	 //$$('upload_file_name').innerHTML = uploadInfo.curFileName  ;
    
    $$('upload_file_size').innerHTML =Math.ceil(uploadInfo.totalSize/1024) + ' KB';
    
    $$('upload_time').innerHTML = secondsElapsed + " 秒" ;
    
    $$('upload_speed').innerHTML =  speed + " KB/s";

    $$('progress_bar').style.width = parseInt(progressPercent * 3.5) + 'px';
    
    $$('progress_percent').innerHTML = progressPercent + "%" ;
    
    if(progressPercent==100){
    	$$('upload_text').innerHTML =  "处理文件中,请稍后……";
    }else{
    	$$('upload_text').innerHTML =  "文件上传中,请稍等……";
    }
    
}
/**
* 初始化上传信息
*/
function progressBarInit(uploadFile){
	
	var filename = uploadFile.substring(uploadFile.lastIndexOf("\\")+1,uploadFile.length) ;
	
   	$$('upload_file_name').innerHTML = filename  ;
    
    $$('upload_file_size').innerHTML ='0 KB';
    
    $$('upload_time').innerHTML = "0 秒" ;
    
    $$('upload_speed').innerHTML =  "0 KB/s";

    $$('progress_bar').style.width = '0px';
    
    $$('progress_percent').innerHTML =  "0%" ;
}

function reverseAjax() {
	  dwr.engine.setActiveReverseAjax(true);
}




dwrHelper.js只是一个针对dwr3错误处理
zDrag.js 和 zDialog.js 是用的一个弹出框插件,附件中会列出的

2.然后是dwr3的配置文件(web.xml怎么配置的我就不写了)
    <create creator="new" javascript="FileUpload">
      <param name="class" value="com.method.dwr.Upload"/>
    </create>
    <create creator="new" javascript="UploadListener" scope="script">
      <param name="class" value="com.method.dwr.TestProgress"/>
    </create>
     <convert converter="bean" match="com.method.dwr.util.fileUpload.ProgressInfo"/>
    

记得在web.xml中加上下面这句,支持推送
<init-param>
	      <param-name>activeReverseAjaxEnabled</param-name>
	      <param-value>true</param-value>
	    </init-param>



3.java代码
供前台调用的类
package com.method.dwr;


import org.apache.log4j.Logger;
import org.directwebremoting.io.FileTransfer;

import com.method.dwr.util.exception.ExceptionValidate;
import com.method.dwr.util.fileUpload.FileUpload;
import com.method.dwr.util.fileUpload.ProgressInfo;


public class Upload {
	
	public static Logger log = Logger.getLogger(Upload.class) ;

	private ProgressInfo pi = null;
	
	private FileUpload upload = null ;
	/**
	 * 	DWR 单文件上传
	 *  页面编码必须使用GBK,否则上传文件名为中文时,会出现乱码
	 * @return
	 * @throws Exception 
	 */
	public String upload(FileTransfer fileTransfer) throws Exception {
		log.info("=======================") ;
		upload = new FileUpload();
		return upload.upload(fileTransfer,50,"/upload");
	}
	
	/**
	 * 文件下载
	 * 	在IE下,中文文件名会有乱码出现,待解决。
	 * @param fileName
	 * @return
	 * @throws Exception
	 */
	public FileTransfer download(String fileName)  throws Exception{
		upload = new FileUpload();
		return upload.download(fileName,"/upload");
	}
}




dwr3上传文件的类
package com.method.dwr.util.fileUpload;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;

import org.apache.log4j.Logger;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.io.FileTransfer;

import com.method.dwr.util.exception.ExceptionValidate;


public class FileUpload {
	
	public static Logger log = Logger.getLogger(FileUpload.class) ;

	private WebContext wctx = null;
	/**
	 * 	DWR 单文件上传
	 *  页面编码必须使用GBK,否则上传文件名为中文时,会出现乱码
	 * @param fileTransfer
	 * @param maxSizeWithM  允许上传的最大文件
	 * @param savePath		文件保存的路径(/upload)
	 * @return
	 * @throws Exception
	 */
	public String upload(FileTransfer fileTransfer,int maxSizeWithM,String savePath) throws Exception {
	
		if(maxSizeWithM != 0 && fileTransfer.getSize() > 1024*1024*maxSizeWithM){
			//throw new ExceptionValidate("提示:您上传的单个文件不能超过" + maxSizeWithM + "M !") ;
		}
		
		wctx = WebContextFactory.get();
				
        log.info("----------"+fileTransfer.getSize()) ;
		
        //存储的绝对路径
		String saveurl = wctx.getHttpServletRequest().getSession()
				.getServletContext().getRealPath(savePath);
		
		log.info("----------" + saveurl) ;
		
		String fileName = new String(fileTransfer.getFilename().getBytes(),"GBK");
		//文件名
		fileName = fileName.substring(fileName.lastIndexOf(java.io.File.separator)+1) ;
		
		log.info("-------fileName---" + fileName) ;
		
		File file = new File(saveurl + java.io.File.separator + fileName);
		
		if (!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		
		//开始读取文件
		byte[] bytes = new byte[1024*10];
		
        FileOutputStream foutput = new FileOutputStream(file);   
      
        BufferedOutputStream Buff = new BufferedOutputStream(foutput);
        
        InputStream fis = fileTransfer.getInputStream();

        int len=0;
        while((len=fis.read(bytes))>0)
        {
        	Buff.write(bytes,0,len); 
           
        }
        Buff.flush();
        Buff.close();
        foutput.close();   
        fis.close();    

		log.info("-----文件上传结束-----") ;
		return fileName;
	}
	
	/**
	 * 文件下载
	 * 	在IE下,中文文件名会有乱码出现,待解决。
	 * @param fileName
	 * @return
	 * @throws Exception
	 */
	public FileTransfer download(String fileName,String savePath)  throws Exception{
		
		
		wctx = WebContextFactory.get();
		// String realtivepath = webContext.getServletContext().getContextPath()
		// + "/upload/";

		log.info("-------fileName-1111--" + fileName) ;
		
		String saveurl = wctx.getHttpServletRequest().getSession()
				.getServletContext().getRealPath(savePath);
		if (fileName == null || fileName.length() == 0) {  
			fileName = "[BLANK]";  
        }  
        BufferedInputStream in;
		try {
			in = new BufferedInputStream(new FileInputStream(saveurl + java.io.File.separator + fileName));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			throw new ExceptionValidate("您要下载的文件:[" + fileName + "]不存在!");
		}
		
        ByteArrayOutputStream out = new ByteArrayOutputStream();  
        byte[] temp = new byte[1024*10];  
        int size = 0;    
        while ((size = in.read(temp)) != -1)  
        {  
        	out.write(temp, 0, size);  
        }

        //log.info(new String(out.toByteArray(),"ISO8859-1"));
        return new FileTransfer(new String(fileName.getBytes("UTF-8"),"ISO8859-1"),null,out.toByteArray());  
		
	}
}




这个是存储进度条信息的类

package com.method.dwr.util.fileUpload;

import java.util.ArrayList;


public class ProgressInfo
{
    private long totalSize = 0;
    private long bytesRead = 0;
    private int fileIndex = 0;
    private long startTime = System.currentTimeMillis();
    private long deltaTime = 0;
    private String uploadedFiles = "";
    
    private boolean isInProgress = true;
    private boolean isCompleted = false;
    
    private String curFileName = "";
    private String errorMsg = "";

    
	public String getErrorMsg() {
		return errorMsg;
	}

	public void setErrorMsg(String errorMsg) {
		this.errorMsg = errorMsg;
	}

	public String getCurFileName() {
		return curFileName;
	}

	public void setCurFileName(String curFileName) {
		this.curFileName = curFileName;
	}

	public String getUploadedFiles() {
		return uploadedFiles;
	}

	public void setUploadedFiles(String uploadedFiles) {
		this.uploadedFiles = uploadedFiles;
	}

	public long getStartTime() {
		return startTime;
	}

	public void setStartTime(long startTime) {
		this.startTime = startTime;
	}

	public void setDeltaTime(long deltaTime) {
		this.deltaTime = deltaTime;
	}

	public ProgressInfo()
    {
    }

    public long getTotalSize()
    {
        return totalSize;
    }

    public void setTotalSize(long totalSize)
    {
        this.totalSize = totalSize;
    }

    public long getBytesRead()
    {
        return bytesRead;
    }

    public void setBytesRead(long bytesRead)
    {
        this.bytesRead = bytesRead;
    }

    public long getDeltaTime()
    {
        return System.currentTimeMillis() - this.startTime;
    }

    public boolean isInProgress()
    {
        return isInProgress;
    }

    public int getFileIndex()
    {
        return fileIndex;
    }

    public void setFileIndex(int fileIndex)
    {
        this.fileIndex = fileIndex;
    }

	public boolean isCompleted() {
		return isCompleted;
	}

	public void setCompleted(boolean isCompleted) {
		this.isCompleted = isCompleted;
		this.isInProgress = false;
		
	}

	public void setInProgress(boolean isInProgress) {
		this.isInProgress = isInProgress;
	}
}



补充一下代码:
package com.method.dwr;

import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.directwebremoting.ScriptBuffer;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.event.SessionProgressListener;

import com.method.dwr.util.fileUpload.ProgressInfo;

/**
 * @author 宗波 E-mail:zongb@cntmi.com
 * @version 创建时间:2011-11-27 下午09:44:14 
 */
public class TestProgress {

	public static Logger log = Logger.getLogger(TestProgress.class) ;
	
	private static final String PROGRESS_LISTENER = org.directwebremoting.dwrp.CommonsFileUpload.PROGRESS_LISTENER ;
	/**
	 * 调用前台js的间隔时间,默认为600毫秒
	 */
	private static long SEND_MESSAGE_INTERVAL = 600 ;
	
	private ProgressInfo pi = null;

	private WebContext wctx = null;
	
	private SessionProgressListener sp = null  ;
	
	private HttpSession session = null ;
	
	private boolean _stop ;
	
	public TestProgress(){
		System.out.println("aaaaaaaaaaaaaa") ;
	}
	
	/**
	 * 监听上传文件的进度
	 * @param interval
	 */
	public void listener(long interval){
		log.info("==========test=========") ;
		_stop = false ;
		wctx = WebContextFactory.get();
		session = wctx.getHttpServletRequest().getSession() ;
        //保存文件的上传信息,用来显示进度条
        pi = new ProgressInfo();

        ScriptBuffer script = new ScriptBuffer();
        script.appendScript("updateProgress(")
              .appendData(pi)
              .appendScript(");");
        
        while(!_stop){
        	sp = (SessionProgressListener)session.getAttribute(PROGRESS_LISTENER) ;
			log.info("while-------"+getObj(sp)) ;
			if(sp!=null && sp.getContentLength() > 0){
				
				pi.setTotalSize(sp.getContentLength()) ;
				pi.setBytesRead(sp.getBytesRead()) ;
				
				if(sp.getBytesRead() >= sp.getContentLength()){
					log.info("upload finish------------"+getObj(sp)) ;
					pi.setBytesRead(sp.getContentLength()) ;
					//停止标识
					_stop = true ;
					//删除session中的记录,否则再次上传文件时开始获取的数据不正确
					session.removeAttribute(PROGRESS_LISTENER);
				}
				//调用客户端js
				wctx.getScriptSession().addScript(script);
								
			}
        	try {
				Thread.sleep(interval) ;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
        	
        }
        
    	pi = null;
    	sp = null  ;
    	session = null ;
    	wctx = null;
    	
	}
	
	/**
	 * 开始监听上传文件的进度
	 */
	public void listener(){
		listener(SEND_MESSAGE_INTERVAL);
	}
	
	private String getObj(SessionProgressListener sp){
		return sp==null?"blank":"{BytesRead=" + sp.getBytesRead() + ";ContentLength=" + sp.getContentLength() +";Item=" + sp.getItem()+"}" ;
	}
	
	public void getDataByclient(){
		
	}
	
}




ProgressInfo 传到前台了,在附件中的js使用的。


上面的方法中,有dwr3的下载方法,我的理解是,这个下载方法,是先把文件一次读取到内存中,再在页面中提供下载,这样有个问题:无法下载大文件,不知道各位有没有更好的方法

补充一下,这个进度条的显示,有时候会不太及时,开始怀疑是推送频繁的问题,但是推送频率调大了,还是会出现,不知道什么原因……


主要想了解下,大家有没有用过后台循环推送、或者 dwr3文件上传显示进度条?

如果大家有什么更好的建议,希望能提出来,大家一起分享

谢谢!
   发表时间:2011-12-19  
难道就没有使用dwr3 上传下载的???
0 请登录后投票
   发表时间:2011-12-19  
UploadListener 没介绍到;
ProgressInfo 没说明调用的地方

最主要的东西都没说, 楼主发贴有意思么
0 请登录后投票
   发表时间:2011-12-19  
kidd3166 写道
UploadListener 没介绍到;
ProgressInfo 没说明调用的地方

最主要的东西都没说, 楼主发贴有意思么

你误会了 楼主这个是 求·助 贴~~ 再就是官方哪里对于dwr的使用和介绍都很少,推送comet中我想找个util类的替换类都没找到资料(util被dwr新版本drop了)
不过话说 少用innerHTML 不是w3c标准的写法
0 请登录后投票
   发表时间:2011-12-19  
dwr这个项目都快夭折了,没想到还有人用
0 请登录后投票
   发表时间:2011-12-20  
,,,,最近在用dwr写客服聊天呢,用要用到他的推技术。

虽然js直接调用java挺方便,不过还感觉是有点麻烦。

你说的这个就不晓得咯。dwr的资料确实很少。官网的介绍,,,,,,
0 请登录后投票
   发表时间:2011-12-20  
能不能在客户端判断文件的大小?
0 请登录后投票
   发表时间:2011-12-20  
dafa1892 写道
能不能在客户端判断文件的大小?

沙箱原则是什么?
0 请登录后投票
   发表时间:2011-12-20  
我在上个东家做类似web im时有用到dwr,dwr说3会很方便支持推送,不知道现在出正式版没,当时有RC版.
0 请登录后投票
   发表时间:2011-12-21  
如果支持html5的话,可以轻松使用Ajax完成文件的上传,而且Ajax是可以有进度事件的。至于不支持html5的浏览器直接使用Flash也可以。这两种做法都可以在客户端得到进度。
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics