码迷,mamicode.com
首页 > 编程语言 > 详细

struts2实现文件上传进度条(前端JS+Java)(自我整理)

时间:2015-06-15 11:25:26      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:struts2

需要做一个文件上传进度的效果,结合网上资料和自己的实践后,这里做一个整理

步骤如下:

1.重写、自定义JakartaMultiPartRequest类

<span style="font-size:12px;">package com.hikvision.fileUploadProcess.interceptor;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest;

public class MyJakartaMultiPartRequest extends JakartaMultiPartRequest  {
    @Override  
    public void parse(HttpServletRequest servletRequest, String saveDir)  
            throws IOException {  
            //什么也不做  
		
    }  	 
}</span><strong style="font-size: 14px; ">
</strong>

原因:

    struts2默认的拦截器中有一个FileUploadInterceptor,它会拦截所有的MultipartRequest,并且将得到的File及相关信息传递给action,因此在action被调用之前,文件上传已经被处理完了,不能引入监听文件写入时文件进度;

    struts2处理文件上传使用的是commons-fileupload,因此我们可以使用ProgressListener。注意我们需要在解析请求的时候加入我们的监听器,我们首先想到的是替换掉FileUploadInterceptor,不幸的是 FileUploadInterceptor并不执行解析的任务,实际在FileUploadInterceptor被调用之前,MultipartRequest已经被解析了,文件上传的工作已经完成。而实际上对于所有的文件上传请求,struts2会为其生成一个MultiPartRequestWrapper进行包装,而它维护着一个 MultiPartRequest接口的实例。MultiPartRequest的实现类只有一个 JakartaMultiPartRequest,JakartaMultiPartRequest有一个方法parseRequest,此方法负责解析 request并生成FileItem,即对文件进行读写操作,因此我们可以重写此方法,添加ProgressListener。不幸的是,JakartaMultiPartRequest的很多方法都是private的,我们不能继承它然后重写parseRequest方法,JakartaMultiPartRequest实现了MultiPartRequest接口,我们可以编写一个类,实现 MultiPartRequest接口,替代JakartaMultiPartRequest类的代码全都拷贝过来,并修改parseRequest方法,完成文件的写入与进度的监听。

2.配置struts2.xml

<!-- 1配置自定义文件类myRequestParser,继承MultiPartRequest重写 -->
	<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest"
		name="myRequestParser" class="com.hikvision.fileUploadProcess.interceptor.MyJakartaMultiPartRequest"
		scope="default" optional="true" />
		
	<!-- 注意struts2.3.15.1以前版本这里为struts.multipart.handler, struts2.3.15.1(包含2.3.15.1)这里为struts.multipart.parser-->
	<constant name="struts.multipart.parser" value="myRequestParser" /> 
	
	<!-- 配置项目所上传文件的最大的Size为1000M -->
	<constant name="struts.multipart.maxSize" value="1048576000"/> 


3.定义文件上传进度信息的类

package com.hikvision.fileUploadProcess.entity;


/**
 * 上传文件进度信息
 * 
 * @author wanglei
 * @version 0.1
 */
public class FileUploadProgress {
	// 文件总长度(设置至少为1字节防止前台出现/0的情况)
	private long length = 1;
	// 已上传的文件长度
	private long currentLength = 0;
	// 上传是否完成
	private boolean isComplete = false;
	public long getLength() {
		return length;
	}
	public void setLength(long length) {
		this.length = length;
	}
	public long getCurrentLength() {
		return currentLength;
	}
	public void setCurrentLength(long currentLength) {
		this.currentLength = currentLength;
	}
	public boolean isComplete() {
		return isComplete;
	}
	public void setComplete(boolean isComplete) {
		this.isComplete = isComplete;
	}
	
	public FileUploadProgress() {
		super();
	}

	
}

4.实现ProgressListener接口

package com.hikvision.fileUploadProcess.impl;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.ProgressListener;

import com.hikvision.fileUploadProcess.entity.FileUploadProgress;

/**
 * 文件上传进度消息
 * @author hongchenjin
 *
 */
public class FileUploadListener implements ProgressListener {
	private HttpSession session;

	public FileUploadListener(HttpServletRequest request) {
		session = request.getSession();
		FileUploadProgress fileUploadProgress = new FileUploadProgress();
		fileUploadProgress.setComplete(false); 
		session.setAttribute("fileUploadProgress", fileUploadProgress);
	}

	
	//更新进度情况
	@Override
	public void update(long readedBytes, long totalBytes, int currentItem) { 
		//实现文件上传的核心方法
		Object attribute = session.getAttribute("fileUploadProgress");
		FileUploadProgress fileUploadProgress  = null;
		if(null == attribute){ 
			fileUploadProgress = new FileUploadProgress();
			fileUploadProgress.setComplete(false); 
			session.setAttribute("fileUploadProgress", fileUploadProgress);
		}else{
			 fileUploadProgress = (FileUploadProgress)attribute;
		}

		fileUploadProgress.setCurrentLength(readedBytes);
		fileUploadProgress.setLength(totalBytes); 
		if(readedBytes==totalBytes){
			fileUploadProgress.setComplete(true);
		}else{ 
			fileUploadProgress.setComplete(false);
		}
		 
		session.setAttribute("progress", fileUploadProgress);
	}
	
	
}
5.文件上传进度的action

package com.hikvision.modules.guide.action;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;

import com.hikvision.fileUploadProcess.entity.FileUploadProgress;
import com.hikvision.frame.entity.OperateResult;
import com.hikvision.modules.guide.entity.NameToLocalFile;
import com.hikvision.modules.guide.service.GuideService;
import com.hikvision.modules.guide.util.GetSharePathXml;
import com.hikvision.util.AjaxUtil;
import com.opensymphony.xwork2.ActionSupport;

public class GuideUploadAction extends ActionSupport {

	private GuideService guideService;



	public GuideService getGuideService() {
		return guideService;
	}

	public void setGuideService(GuideService guideService) {
		this.guideService = guideService;
	}

	
	
	//文件格式不支持
	public void typeNotSupport(){
		OperateResult result = new OperateResult(false,"");
		result.setResult(false);
		result.setMsg("上传文件最大不能超过100M;支持的格式为exe,png,jpg,gif,bmp,doc,docx,xls,rar,txt,zip,js,css,msi,pptx");
		AjaxUtil.ajaxWrite(result);
	}
	
	
	/**
     * 上传文件
     * 
     * @return
     */
    public void uploadfile() {
    	OperateResult result = new OperateResult(false,"");
        try {
        	HttpServletRequest request = ServletActionContext.getRequest();
        	//获取文件备注
        	String comments = request.getParameter("comments");
        	//文件上传
            UploadFile.upload(request, ServletActionContext.getResponse());
            //将文件名和文件的对应关系存进数据库里 
			NameToLocalFile nameToLocalFile = new NameToLocalFile();
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
			String time = sdf.format(new Date());
			nameToLocalFile.setCreatetime(time);
			//保存在服务器上的路径
			nameToLocalFile.setLocalpath("/" +  request.getParameter("variety") + "/" + request.getParameter("name"));
			nameToLocalFile.setName(request.getParameter("name")); 
			nameToLocalFile.setVariety(request.getParameter("variety"));
			nameToLocalFile.setComments(comments);
			guideService.saveOrUpdate(nameToLocalFile);
            result.setResult(true);
            result.setMsg("上传成功");
        } catch (IOException e) { 
            LOG.error("上传文件发生异常,错误原因 : " + e.getMessage()); 
            result.setMsg("上传文件最大不能超过100M;"); 
            result.setResult(false);
        } 
        AjaxUtil.ajaxWrite(result); 
    }
    
    /**
     * 修改文件
     */
    public void updateNameToLocalFile(){
    	OperateResult result = new OperateResult(false,"");
    	HttpServletRequest request = ServletActionContext.getRequest();
    	//种类
    	String variety = request.getParameter("variety");
    	//名称
		String name = request.getParameter("name");
		//文件备注
    	String comments = request.getParameter("comments");
		//是否上传了文件
		Boolean flag = Boolean.parseBoolean(request.getParameter("flag"));
		//id
		int id = Integer.parseInt(request.getParameterValues("ids")[0]);
		//根据id获取数据库的nameToLocalFileById
		NameToLocalFile nameToLocalFileById = guideService.getNameToLocalFileById(id);
		//分为两种情况,第一种为用户重新上传了文件,第二种是用户只修改了名字和种类
		if(flag){
			/**
			 * 用户重新上传文件的情况
			 */
			//删除原来文件
			String localpath = nameToLocalFileById.getLocalpath();
			String realPath = GetSharePathXml.getShareFolderPath() + localpath;
			File file = new File(realPath);
			//用户上传了文件
			try { 
				
				if(file.exists()){
					//删除原来文件(判断是否存在该文件,存在就删除)
					file.delete();
				}
		
				//文件上传
	            UploadFile.upload(request, ServletActionContext.getResponse());
				
				
				result.setResult(true);
				result.setMsg("修改成功");
			} catch (Exception e) {
				result.setResult(false);
				result.setMsg("修改失败");
			}
		}
		//将文件名和文件的对应关系存进数据库里
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		String time = sdf.format(new Date());
		nameToLocalFileById.setCreatetime(time);
		if(flag){
			//保存在服务器上的路径
			nameToLocalFileById.setLocalpath("/" +  variety + "/" + name);
			nameToLocalFileById.setName(name);
		}	   
		nameToLocalFileById.setVariety(variety);
		nameToLocalFileById.setComments(comments);
		guideService.saveOrUpdate(nameToLocalFileById);
		result.setResult(true);
		result.setMsg("修改成功"); 
		AjaxUtil.ajaxWrite(result);
		
    }
    /**
     * 显示上传文件进度进度
     * 
     * @return page view
     */
    public void progress() {
        // 新建当前上传文件的进度信息对象
        FileUploadProgress p = null;
        Object attribute = ServletActionContext.getRequest().getSession().getAttribute("fileUploadProgress");
        if(null == attribute){
        	p = new FileUploadProgress();
        	 // 缓存progress对象
            ServletActionContext.getRequest().getSession().setAttribute("fileUploadProgress", p);
        }else{
        	p = (FileUploadProgress)attribute;
        }
        
        ServletActionContext.getResponse().setContentType("text/html;charset=UTF-8");
        ServletActionContext.getResponse().setHeader("pragma", "no-cache");
        ServletActionContext.getResponse().setHeader("cache-control", "no-cache");
        ServletActionContext.getResponse().setHeader("expires", "0");  
        //以下方法为输出json(封装,可根据实际情况修改输出的方式)
        AjaxUtil.ajaxWriteObject(p);
    }
    
    /**
     * 清除session
     */
    public void clearProgressSession(){
    	ServletActionContext.getRequest().getSession().setAttribute("fileUploadProgress", null);
    }
}

6.UploadFile类(文件上传)

package com.hikvision.modules.guide.action;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.log4j.Logger;

import com.hikvision.fileUploadProcess.impl.FileUploadListener;
import com.hikvision.modules.guide.util.GetSharePathXml;
/**
 * upload file
 * 
 * @author scott.Cgi
 */
public class UploadFile {
    private static final Logger LOG = Logger.getLogger(UploadFile.class);
    /**
     * 上传文件
     * 
     * @param request
     *            http request
     * @param response
     *            htp response
     * @throws IOException
     *             IOException
     */
    @SuppressWarnings("unchecked")
    public static void upload(HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        if (request.getContentType() == null) {
            throw new IOException(
                    "the request doesn't contain a multipart/form-data stream");
        }

        // 上传临时路径
        String path = GetSharePathXml.getShareFolderPath();
        // 设置上传工厂
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setRepository(new File(path));
        // 阀值,超过这个值才会写到临时目录
        factory.setSizeThreshold(1024 * 1024 * 10);
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 最大上传限制
        upload.setSizeMax(1024 * 1024 * 1000);
        // 设置监听器监听上传进度
        upload.setProgressListener(new FileUploadListener(request)); 
        try {  
            List<FileItem> items = upload.parseRequest(request);
             
            //获取文件类型
            String variety = request.getParameter("variety");
            for (FileItem item : items) {
                
                // 非表单域
                if (!item.isFormField()) {
                    FileOutputStream fos = new FileOutputStream(path + "/"  + variety + "/" + item.getName());
                    // 文件全在内存中
                    if (item.isInMemory()) {
                        fos.write(item.get());
                    } else {
                        InputStream is = item.getInputStream();
                        byte[] buffer = new byte[1024];
                        int len;
                        while ((len = is.read(buffer)) > 0) {
                            fos.write(buffer, 0, len);
                        }
                        is.close();
                    }
                    fos.close(); 
                    LOG.info("完成上传文件!");
                    
                    item.delete();
                    LOG.info("删除临时文件!");
                    
                    LOG.info("更新progress对象状态为完成状态!");
                }
            }
        } catch (Exception e) {
            LOG.error("上传文件出现异常, 错误原因 : " + e.getMessage());

            request.getSession().removeAttribute("percent");
        }
    }
    


    
}

前台部分:点击上传,然后循环调用

//进度条显示
	var everylisten = function() {
		//显示进度条 
		$("#prosbar").parent("div").css({"display":"block"});
		$.ajax({
			url : 'http://127.0.0.1/guideUpload!progress.action',
			method : 'GET', 
			timeout : 120000,   
			contentType : "application/json; charset=utf-8",
			dataType : "json",
			success : function(result) {
				if(null != result) {
						if(result.complete) { 
							//将进度条长度设为0并隐藏
							$("#prosbar").css({"width":"0%"});   
							clearTimeout(everylisten);  
							//清除session 
							clearProgressSession();  
						}else{ 
							var width = result.currentLength * 100 / result.length + "%";
							$("#prosbar").css({"width": width});   
							setTimeout(everylisten, 500);      
						} 
				}else{
					alert(data.msg);  
				} 
			}
		});
	};   
清除进度条session

//清除session
	function clearProgressSession(){
		$.ajax({
			url : hik.guide.getContextPath() + '/guideUpload!clearProgressSession.action', 
			method : 'GET', 
			timeout : 120000,   
			contentType : "application/json; charset=utf-8",
			dataType : "json",
			success : function(result) {
 
			}
		});
	}  
点击文件上传时的js代码(PS:文件上传时相关参数写在路径里,不然后台接收不到(如果不写在路径里,测试时在浏览器调试发现参数确实传了,但在request里这个参数的值为空),因为请求地址是要经过tomcat的,为防止中文乱码的情况,在tomcat路径conf文件夹下找到server.xml文件,找到以下项,添加红色部分的代码 <Connector URIEncoding="UTF-8" connectionTimeout="20000" port="80" protocol="HTTP/1.1" redirectPort="8443"/> ,保存后重启tomcat)


$("#GuideForm").submit(function(){
					everylisten();
					return false;
					$.ajaxFileUpload 
					(  
						{
							url:'http://127.0.0.1/guideUpload!uploadfile.action?' 
							    + $("#GuideForm").serialize(),
							secureuri:false,    
							fileElementId:'upload',  
							dataType: 'json',    
							data:{},  
							success: function (data, status)
							{
								$(dialogEl).dialog('close');
								//上传成功后,提示用户上传成功
								if(data.success){
									alert("success");  
								}else{
									alert("false");
								} 
							},
							error: function (data, status, e) 
							{
								alert("出错了");
							}
						}
					)  
				});

页面代码(红色部分为必须写的地方):
<span style="color:#333333;"><form id="GuideForm" name="guideForm" action=""
	onsubmit="return false;"
	class="form-horizontal five-columns character5 padding-top8px"
	</span><span style="color:#cc0000;">enctype="multipart/form-data"</span><span style="color:#333333;"> method="post">  
	
	<div> 
		<input type="hidden" name="ids" >
		<div class="control-group five-columns">
	        <label class="control-label">文件名称:</label>
	        <div class="controls">
	          <input class="span4" type="text" name="name" maxlength="20" readonly="readonly"/>  
	        </div>
     	 </div>  
     	<div class="control-group five-columns">
			<label class="control-label">文件类型:</label>   
			<div class="controls"> 
				<select name="variety">
					<option value="tools">开发工具</option>
					<option value="ecliplse_plugin">Eclipse常用插件</option>
					<option value="svn">代码版本控制SVN</option>
					<option value="database">数据库</option> 
					<option value="other">其他</option>
				</select>
			</div>  
		</div> 
		<div class="control-group five-columns" style="display:none;">   
			<label class="control-label">文件路径:</label>
	        <div class="controls">  
	          <a name="path" style="color:blue"></a>   
	        </div>   
	        <div class="controls"> 
	          <input type="button" class="btn btn-primary uploadReset" value="重新上传" name="uploadReset">    
	        </div>
		</div> 
		<div class="control-group five-columns">
			<div class="controls">
			<label class="control-label">上传文件 :</label>
			<input class="span4" type="file"
				name="upload" maxlength="20" id="upload" />  
			</div> 
		</div> 
		<div class="control-group five-columns">
			<div class="controls">
			<label class="control-label">文件备注:</label>
				<textarea rows="" cols="" name="comments" maxLength="50"></textarea>
			</div> 
		</div> 
		<div class="progress progress-striped active" >    
  			<div class="bar" style="width: 0%;" id="prosbar"></div> 
		</div>
	</div>	 
	
	<!-- 上传进度条 --> 
</form></span>



struts2实现文件上传进度条(前端JS+Java)(自我整理)

标签:struts2

原文地址:http://blog.csdn.net/u011768325/article/details/46499987

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!