commons-fileupload實現上傳進度條的顯示


  本文將使用   apache fileupload   ,spring MVC   jquery 實現一個帶進度條的多文件上傳, 由於fileupload 的局限,暫不能實現每個上傳文件都顯示進度條,只能實現一個總的進度條

優點:不用引入第三方的組件(如js框架,flash等)

缺點:如果同時上傳多個文件,由於apache fileupload API的限制,只能顯示一個總的進度條

1.引入環境所需要的jar包

引入上傳工具類jar包

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>            

引入mvc處理json數據jar包(@requestbody&@responsebody)

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.5.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.5.1</version>
</dependency> 

 

2.jsp頁面

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<link rel="stylesheet" href="http://jqueryui.com/resources/demos/style.css">
<script type="text/javascript">  
$(document).ready(function(){  
     $('#subbut').bind('click',  
            function(){         
                $('#fForm').submit();  
                
                var eventFun = function(){  
                    $.ajax({  
                        type: 'GET',  
                        url: '${pageContext.request.contextPath}/test/process.action',  
                        data: {},  
                        dataType: 'json',  
                        success : function(data){  
                                $("#fff").html("上傳進度:"+data.show);
                                $( "#proBar" ).progressbar({
                                    value: data.rate
                                  });
                                if(data.rate == 100){  
                                    window.clearInterval(intId);  
                                    alert("上傳完成");
                                }     
                }});};  
                var intId = window.setInterval(eventFun,100);  
    });             
});  
</script>  
<title>Insert title here</title>
</head>
<body>
      <form id='fForm'   action="${pageContext.request.contextPath}/test/testbar.action" encType="multipart/form-data"  method="post" target="uploadf">  
                         <div>  
                            <label>上傳文件:</label>  
                            <div>  
                                <input type="file"  name="file" style="width:550">  
                            </div>  
                          
                            <label id="fff"></label>  
                            <div>  
                                <div style="width:50%">  
                                    <div  id = 'proBar'></div>  
                                </div>  
                            </div>  
                        </div>  
                         <div >  
                            <div >  
                            <button type="button" id="subbut" >submit</button>  
                            </div>  
                        </div>  
    </form>  
    <iframe name="uploadf" style="display:none"></iframe>   
</body>
</html>

 

 

這里注意需要引入js和css,如果需要更換進度條的樣式,可以引入其他的css(如bootstarp等)

3.后台的實現

 

import java.io.File;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
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 org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/test")
public class FileUploadController {
    
    private final    Logger log = Logger.getLogger(FileUploadController.class);  
    
    /** 
     * upload  上傳文件 
     */  
    @RequestMapping(value = "/testbar.action", method = RequestMethod.POST)  
    public ModelAndView upload(HttpServletRequest request,HttpServletResponse response) throws Exception {  
        final HttpSession hs = request.getSession();  
        ModelAndView mv = new ModelAndView();  
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);  
        if(!isMultipart){  
            return mv;  
        }  
        // Create a factory for disk-based file items  
        FileItemFactory factory = new DiskFileItemFactory();  
  
        // Create a new file upload handler  
        ServletFileUpload upload = new ServletFileUpload(factory);  
        //解決上傳文件名的中文亂碼
        upload.setHeaderEncoding("UTF-8"); 
        
        upload.setProgressListener(new ProgressListener(){  
               public void update(long pBytesRead, long pContentLength, int pItems) {  
                   ProcessInfo pri = new ProcessInfo();  
                   pri.itemNum = pItems;  
                   pri.readSize = pBytesRead;  
                   pri.totalSize = pContentLength;  
                   pri.show = pBytesRead+"/"+pContentLength+" byte";  
                   pri.rate = Math.round(new Float(pBytesRead) / new Float(pContentLength)*100);  
                   hs.setAttribute("proInfo", pri);  
               }  
            });  
        //     Parse the request  
        List items = upload.parseRequest(request);  
      //   Process the uploaded items  
      Iterator iter = items.iterator();  
      while (iter.hasNext()) {  
          FileItem item = (FileItem) iter.next();  
          if (item.isFormField()) {  
              String name = item.getFieldName();  
              String value = item.getString("utf-8");  
              System.out.println("this is common feild!"+name+"="+value);  
          } else {  
              System.out.println("this is file feild!");  
               String fieldName = item.getFieldName();  
                  String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1);;  
                  String contentType = item.getContentType();  
                  boolean isInMemory = item.isInMemory();  
                  long sizeInBytes = item.getSize();  
                  File uploadedFile = new File("c://"+fileName);  
                  item.write(uploadedFile);  
                 
          }  
      }  
    
        return mv;  
    }  
      
      
    /** 
     * process 獲取進度 
     */  
    @RequestMapping(value = "/process.action", method = RequestMethod.GET)    
    public @ResponseBody Object process(HttpServletRequest request,HttpServletResponse response) throws Exception {  
        return ( ProcessInfo)request.getSession().getAttribute("proInfo");  
    }   
    //精度條pojo
    class ProcessInfo{  
        public long totalSize = 1;  
        public long readSize = 0;  
        public String show = "";  
        public int itemNum = 0;  
        public int rate = 0;  
    }  
}

 

 

 

4.SpringMVC中servletFileUpload.parseRequest(request)解析為空獲取不到數據問題

問題產生的原因

先看一下springmvc中上傳的配置

  <bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
            <property name="defaultEncoding" value="UTF-8" />  
            <property name="maxUploadSize" value="2000000000" />  
  </bean>  

 

 再看看controller中使用

方式一

 public void upload2(HttpServletRequest request) {  
            // 轉型為MultipartHttpRequest  
            try {  
                MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;  
                List<MultipartFile> fileList = multipartRequest.getFiles("file");  
                for (MultipartFile mf : fileList) {  
                    if(!mf.isEmpty()){  
                          
                    }  
                }  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
              
        }  

 

方式二

 public String upload(HttpServletRequest request,  
                @RequestParam(value = "file") MultipartFile[] files) {  
            try {  
                for (MultipartFile mf : files) {  
                    if(!mf.isEmpty()){  
                          
                    }  
                }  
      
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
            return "upload";  
        }  

 

 

這里springMVC 都為我們封裝好成自己的文件對象了,轉換的過程就在我們所配置的CommonsMultipartResolver這個轉換器里面.他的轉換器里面就是調用common-fileupload的方式解析,然后再使用parseFileItems()方法封裝成自己的文件對象.大家應該發現了上面的這句代碼,已經使用過fileUpload解析過request了,你在Controller里面接收到的request都已經是解析過的,你再次使用upload進行解析獲取到的肯定是空,這個就是問題的所在

 

解決方式一(以上案例就是用此解決方法)

1.刪除mvc里面上傳的配置

<!--         <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> -->
<!--          指定所上傳文件的總大小不能超過200KB。注意maxUploadSize屬性的限制不是針對單個文件,而是所有文件的容量之和 -->   
<!--         <property name="maxUploadSize" value="200000"/>   -->
<!--         </bean> -->

 

 2.在控制器里面自己完成request的解析(當然上面spring MVC提供的兩種方法是不能用的,所有上傳的地方都需要自己做處理)

public void upload3(HttpServletRequest request) {  
            DiskFileItemFactory factory = new DiskFileItemFactory();  
            ServletFileUpload upload = new ServletFileUpload(factory);  
            try {  
                List<FileItem> list = upload.parseRequest(request);  
                for(FileItem item : list){  
                    if(item.isFormField()){  
                          
                    }else{  
                        //item.write(new File(""));  
                    }  
                }  
            } catch (FileUploadException e) {  
                e.printStackTrace();  
            }  
              
        }  

 

 

解決方式二(重寫listener)

 1.創建狀態pojo

public class Progress {
    
     public long totalSize = 1;  
     public long readSize = 0;  
     public String show = "";  
     public int itemNum = 0;  
     public int rate = 0;
     
    
    public void setTotalSize(long totalSize) {
        this.totalSize = totalSize;
    }
    
    public void setReadSize(long readSize) {
        this.readSize = readSize;
    }
    public String getShow() {
        return readSize+"/"+totalSize+" byte";
    }
    
    public int getItemNum() {
        return itemNum;
    }
    public void setItemNum(int itemNum) {
        this.itemNum = itemNum;
    }
    public int getRate() {
        return Math.round(new Float(readSize) / new Float(totalSize)*100);
    }
}

 

2.寫自己的listener

import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.ProgressListener;

public class FileUploadListener implements ProgressListener{

    
        private HttpSession session;  
      
        public void setSession(HttpSession session){  
            this.session=session;  
           Progress status = new Progress();  
            session.setAttribute("status", status);  
        }  
      
        /*  
         * pBytesRead 到目前為止讀取文件的比特數 pContentLength 文件總大小 pItems 目前正在讀取第幾個文件  
         */  
        public void update(long pBytesRead, long pContentLength, int pItems) {  
            Progress status = (Progress) session.getAttribute("status");                         
            status.setReadSize(pBytesRead);
            status.setTotalSize(pContentLength);
            status.setItemNum(pItems);
        } 

}

 

 

3.寫自己的resolver

public class CommonsMultipartResolverExt extends CommonsMultipartResolver{

     @Override  
        protected MultipartParsingResult parseRequest(HttpServletRequest request)  
                throws MultipartException {  
            FileUploadListener listener = new FileUploadListener();  
            listener.setSession(request.getSession());
            String encoding = determineEncoding(request);  
            FileUpload fileUpload = prepareFileUpload(encoding);  
            fileUpload.setProgressListener(listener);  
            try {  
                List<FileItem> fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);  
                return parseFileItems(fileItems, encoding);  
            }  
            catch (FileUploadBase.SizeLimitExceededException ex) {  
                throw new MaxUploadSizeExceededException(fileUpload.getSizeMax(), ex);  
            }  
            catch (FileUploadException ex) {  
                throw new MultipartException("Could not parse multipart servlet request", ex);  
            }  
        }   
}

 

 

4.配置上傳resolver

    <bean id="multipartResolver" class="com.fyh.www.common.CommonsMultipartResolverExt"></bean>

 

 

5.測試

@Controller
@RequestMapping("/test2")
public class FileUploadController2 {
    
    private final    Logger log = Logger.getLogger(FileUploadController2.class);  
    
    /** 
     * upload  上傳文件 
     */  
    @RequestMapping(value = "/testbar.action", method = RequestMethod.POST)  
    public ModelAndView upload(HttpServletRequest request,HttpServletResponse response) throws Exception {  
        ModelAndView mv = new ModelAndView();
        MultipartHttpServletRequest multipartRequest=(MultipartHttpServletRequest) request;
        MultipartFile file = multipartRequest.getFile("file");
        
        InputStream inputStream = file.getInputStream();
        
        FileUtils.copyInputStreamToFile(inputStream, new File("e://"+file.getOriginalFilename()));
        
        
    
        return mv;  
    }  
      
      
    /** 
     * process 獲取進度 
     */  
    @RequestMapping(value = "/process.action", method = RequestMethod.GET)    
    public @ResponseBody Object process(HttpServletRequest request,HttpServletResponse response) throws Exception {  
        return ( Progress)request.getSession().getAttribute("status");  
    }   
  
}

 

 

此方案在獲取監控進度的同時並不因影響mvc原有上傳方法的使用

 

解決方式三(需要用到進度條的上傳時,寫獨立的servlet,servlet+apache uploadfile  與springmvc互不干預)不建議用此方法

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM