struts2實現文件上傳進度條(前端JS+Java)(收藏)

步驟如下:

1.重寫、自定義JakartaMultiPartRequest類

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 {  
            //什麼也不做  
		
    }  	 
}

原因:

    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文件,找到以下項,添加紅色部分的代碼 <ConnectorURIEncoding="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("出錯了");
							}
						}
					)  
				});

頁面代碼(紅色部分爲必須寫的地方):
<form id="GuideForm" name="guideForm" action=""
	οnsubmit="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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章