`
hzl7652
  • 浏览: 118005 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

Struts2 Ajax 上传文件,显示进度

阅读更多

 Struts2 Ajax 上传文件,显示进度

 大家可能以前用ajax上传文件时,是把form提交到<iframe></iframe>,HTML代码如下:

<form action="uploadAction.action"  enctype="multipart/form-data" id="fileform" name="fileform" method="post"
     target="upload-target">
<input type="file" value="浏览" name="upload" />
<input type="submit" value="提交"/>
</form>
<iframe id="upload-target"></iframe>

  这样不用跳转页面就可以实现文件的上传,Action的代码如下:

public class UploadAction extends ActionSupport {
            //上传的文件
	private File upload;
	//上传文件的类型
	private String uploadContentType;
	上传文件的文件名
	private String uploadFileName;
	
	
	
	//getter setter
	@Override
	public String execute() throws Exception {
		System.out.println(upload.length());
		FileOutputStream fos = new FileOutputStream(ServletActionContext.getServletContext().getRealPath("/") + uploadFileName);
		FileInputStream fis = new FileInputStream(upload);
		byte[] buffer = new byte[10240];
		int len = 0;
		double temp = 0;
		int total = fis.available();
		while((len = fis.read(buffer)) > 0){
			fos.write(buffer, 0, len);
			fos.flush();
			
		}
		fis.close();
		fos.close();
		return SUCCESS;
	}
 

 这样就可以在一个页面上上传文件了。但怎么显示上传文件的进度呢。一开始我的想法是在Action增加一个perc属性,该属性存放着上传的进度,再增加一个方法,输出perc的值.

     private double perc;

public String ajaxGetPerc() throws Exception{
	
		HttpServletResponse response = ServletActionContext.getResponse();
		PrintWriter writer = null;
		writer = response.getWriter();
		writer.println(perc);
		writer.flush();
		writer.close();
		return null;
	}

  最后试验了一下,发现该方法行不通,能上传文件,使用ajax返回的进度值始终是0;

  想想第二种方法,使用线程的方式上传文件,并把进度值保存在session中, 并且要使用两个页面,一个页面负责文件的上传,一个负责显示进度。详细代码如下:

upload.jsp负责文件的上传,是一个很普通的HTML页面

<body>
<h1>文件上传</h1>
<form action="uploadAction.action"  enctype="multipart/form-data" id="fileform" name="fileform" method="post"
    >
<input type="file" value="浏览" name="upload" />
<input type="submit" value="提交"/>
</form>
</body>

  showPerc.jsp使用ajax间隔的查询进度值

<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	String path = request.getContextPath();
 %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="<%=path %>/js/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
var xmlHttp ;
function createXMLHttp(){
    if(window.ActiveXObject){
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    else{
        xmlHttp = new XMLHttpRequest() ;
    }
}

function ajaxSend(){
    createXMLHttp() ;
    
    var url ="<%=path %>/getUploadPerc.action?random=" + Math.random(); ;
    xmlHttp.onreadystatechange = handler ;
    xmlHttp.open("GET",url,true) ;
    //xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
    xmlHttp.send(null) ;
}
function handler(){
 if(xmlHttp.readyState == 4)     {
  if(xmlHttp.status == 200)      {
        var percent = xmlHttp.responseText ;
        document.getElementById('pre').innerHTML = percent;
        var t = setTimeout("ajaxSend()",100) ;
       
        if(percent == 100){
            alert('上传完成');
        	clearTimeout(t);
        }
  }
 }
 return true;
}

window.onload = function(){
	ajaxSend();	
}
</script>
<title>文件上传</title>
</head>
<body>
<h1>进度条</h1>
<div id="pre"></div>
</body>
</html>

 Action代码

package com.struts.action;

import java.io.*;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class UploadAction extends ActionSupport {

	private String title;
	
	private File upload;
	
	private String uploadContentType;
	
	private String uploadFileName;
	
	private String savePath;

	private double perc;
	
	public double getPerc() {
		return perc;
	}

	public void setPerc(double perc) {
		this.perc = perc;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public File getUpload() {
		return upload;
	}

	public void setUpload(File upload) {
		this.upload = upload;
	}

	public String getUploadContentType() {
		return uploadContentType;
	}

	public void setUploadContentType(String uploadContentType) {
		this.uploadContentType = uploadContentType;
	}

	public String getUploadFileName() {
		return uploadFileName;
	}

	public void setUploadFileName(String uploadFileName) {
		this.uploadFileName = uploadFileName;
	}

	public String getSavePath() {
		return savePath;
	}

	public void setSavePath(String savePath) {
		this.savePath = savePath;
	}
	
	@Override
	public String execute() throws Exception {
		System.out.println(upload.length());
		File toFile = new File(ServletActionContext.getServletContext().getRealPath("/") + uploadFileName);
		HttpSession session = ServletActionContext.getRequest().getSession();
		session.setAttribute("perc", 0);
		UploadThread uploadThread = new UploadThread(upload,toFile,session);
		Thread thread = new Thread(uploadThread);
		thread.start();
		return SUCCESS;
	}
	
	public String ajaxGetPerc() throws Exception{
		HttpSession session = ServletActionContext.getRequest().getSession();
		System.out.println("session perc------" + session.getAttribute("perc"));
		//ServletActionContext.getResponse().getOutputStream().println((String)session.getAttribute("perc"));
		HttpServletResponse response = ServletActionContext.getResponse();
		PrintWriter writer = null;
		writer = response.getWriter();
		int perc = (Integer)session.getAttribute("perc");
		writer.println(perc);
		writer.flush();
		writer.close();
		return null;
	}
}

/**
 * 
 * 
 * 因为原本文件上传完才能跳转,故在一个线程中上传文件,加速跳转到showPerc.jsp去显示进度.
 *
 */
class UploadThread implements Runnable {
	//在当前线程中上传的文件.
	private File from ;
	//保存到服务器硬盘上的位置.
	private File to ;
	//HttpSession需要传递过来,直接以ServletActionContext.getRequest.getSession将会抛出NullPointerException.
	private HttpSession httpSession;
	//构造方法,用来传址.
	public UploadThread(File from, File to , HttpSession httpSession) {
		this.from = from;
		this.to = to;
		this.httpSession = httpSession;
	}
	//线程中处理上传.
	@Override
	public void run() {
		copy(from, to , httpSession);
	}
	
	//自己实现的上传方法,因为需要计算进度,所以无法使用IOUtils.copy(InputStream in , OutputStream out)方法了.
	/**
	 * @param from           需要上传的文件.
	 * @param to             保存到服务器上的位置.
	 * @param httpSession    得到当前窗口的session.
	 */
	public void copy(File from, File uploadFile , HttpSession httpSession) {
		InputStream fis;
		try {
			fis = new FileInputStream(from);
		
		OutputStream fos = new FileOutputStream(uploadFile);
		byte[] buffer = new byte[10240];
		int len = 0;
		double temp = 0;
		int perc = 0;
		int total = fis.available();
		while((len = fis.read(buffer)) > 0){
			fos.write(buffer, 0, len);
			fos.flush();
			temp += len;
			
			perc = (int)(temp / total * 100);
			//System.out.println(perc + "----------------" + total);
			httpSession.setAttribute("perc", perc);
			Thread.sleep(200);
		}
		fis.close();
		fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
}

  struts.xml配置文件

 <action name="uploadAction" class="com.struts.action.UploadAction">
<result>/showloadbar.jsp</result>
<result name="input">/upload.jsp</result>
<interceptor-ref name="fileUpload">
<param name="allowedTypes">image/bmp,image/png,image/gif,image/jpeg</param>
<param name="maximumSize">20000000000</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
</action>
<action name="getUploadPerc" class="com.struts.action.UploadAction" method="ajaxGetPerc">
</action>
 

  在这里我设置只能上传图片文件.

  可以上传文件,并能显示进度。但这里使用session存取进度值,会加重服务器的负担。各位有什么好的方法可以告诉我。谢谢

 

 

分享到:
评论
13 楼 hzl7652 2012-10-19  
kisbo110 写道
这文章要不就是你从别的地方抄的,要不就是你不厚道,都不写明白,进度条那个页面也没有,并且根本就上传不上去 upload "Jzyl02.jpg" "upload__6a7bbadb_13a76aadd56__8000_00000006.tmp"  鄙视!

看看http://blog.csdn.net/garryyrc/archive/2010/04/18/5499113.aspx
12 楼 kisbo110 2012-10-19  
这文章要不就是你从别的地方抄的,要不就是你不厚道,都不写明白,进度条那个页面也没有,并且根本就上传不上去 upload "Jzyl02.jpg" "upload__6a7bbadb_13a76aadd56__8000_00000006.tmp"  鄙视!
11 楼 hzl7652 2011-09-23  
gao911111 写道
我原封不动的将你这个弄下来啦 不行啊 求源码  我的邮箱gaomingqing@foxmail.com谢谢啦

我这个实现得有点问题你可以参考这个:
http://blog.csdn.net/garryyrc/archive/2010/04/18/5499113.aspx

10 楼 gao911111 2011-09-22  
我原封不动的将你这个弄下来啦 不行啊 求源码  我的邮箱gaomingqing@foxmail.com谢谢啦
9 楼 hzl7652 2011-04-29  
moneyprosper 写道
我个人觉得这个东西用flash做好些,用js做太麻烦,而且功能不好

楼上说得对,我现在在项目上传的东西基本都用 jquery uploadify来实现上传文件。
8 楼 moneyprosper 2011-04-28  
我个人觉得这个东西用flash做好些,用js做太麻烦,而且功能不好
7 楼 hzl7652 2010-09-08  
hunnuxiaobo 写道
看来楼主还是要把原理性东西搞明白啊~

一江春水邀明月 写道
参考http://blog.csdn.net/garryyrc/archive/2010/04/18/5499113.aspx。

一江春水邀明月 写道
jungle1171 写道
我最近正好也在研究这个烦人的东西。。。baidu过来拜访了~~
我觉得你的进度条的实现有根本性的错误。
struts2的上传是在表单submit之后,先把<s:form 中绑定的<input type="file"控件中的文件以"upload_4c0e8ffc_1235ab6ec22__8000_00000003.tmp"名称上传到设定的临时目录,之后才进入Action。
也就是说,实际上UploadThread.copy()中的源文件已经是在服务器硬盘上了~~~

最耗时间的过程恰恰是从客户端上载到Server上~~~

这里有真空。。。犯难~~~
有啥思路,还请交流下。


这个需要改写MultiPartRequest 的实现类, 为你的ServletFileUpload 制定一个你自定义的listener, 在这个listener里面, 去更新设置一个读文件的百分比到session里面去
而你的前台做ajax call 周期去查询session里面的这个变量并且显示在页面上就OK了。

感谢大家的回复,当时写时,确实是原理没想明白,感谢大伙正确的回复
6 楼 hunnuxiaobo 2010-08-31  
看来楼主还是要把原理性东西搞明白啊~
5 楼 一江春水邀明月 2010-08-23  
参考http://blog.csdn.net/garryyrc/archive/2010/04/18/5499113.aspx。
4 楼 一江春水邀明月 2010-08-21  
jungle1171 写道
我最近正好也在研究这个烦人的东西。。。baidu过来拜访了~~
我觉得你的进度条的实现有根本性的错误。
struts2的上传是在表单submit之后,先把<s:form 中绑定的<input type="file"控件中的文件以"upload_4c0e8ffc_1235ab6ec22__8000_00000003.tmp"名称上传到设定的临时目录,之后才进入Action。
也就是说,实际上UploadThread.copy()中的源文件已经是在服务器硬盘上了~~~

最耗时间的过程恰恰是从客户端上载到Server上~~~

这里有真空。。。犯难~~~
有啥思路,还请交流下。


这个需要改写MultiPartRequest 的实现类, 为你的ServletFileUpload 制定一个你自定义的listener, 在这个listener里面, 去更新设置一个读文件的百分比到session里面去
而你的前台做ajax call 周期去查询session里面的这个变量并且显示在页面上就OK了。
3 楼 gfdice 2010-04-29  
特别是续传,是不是HTTP的RFC里根本就没有能支持续传的request header?
2 楼 gfdice 2010-04-29  
想知道现在各种web框架和体系中(什么Java的、Ruby的),哪种不是把整个上传的文件保存成一个tmpfile之后调用程序员编写的代码的?
或者说目前http上传文件的容错(比如续传)、用户交互方面是不是很难做?
1 楼 jungle1171 2009-08-27  
我最近正好也在研究这个烦人的东西。。。baidu过来拜访了~~
我觉得你的进度条的实现有根本性的错误。
struts2的上传是在表单submit之后,先把<s:form 中绑定的<input type="file"控件中的文件以"upload_4c0e8ffc_1235ab6ec22__8000_00000003.tmp"名称上传到设定的临时目录,之后才进入Action。
也就是说,实际上UploadThread.copy()中的源文件已经是在服务器硬盘上了~~~

最耗时间的过程恰恰是从客户端上载到Server上~~~

这里有真空。。。犯难~~~
有啥思路,还请交流下。

相关推荐

Global site tag (gtag.js) - Google Analytics