struts2实现带进度条的文件上传

原理:

利用Ajax在客户端一直查询服务器端的上传进度,取得进度的状态文本信息(xml,json格式的文本等),然后利用JS解析,显示在前台。

Struts2. 0中,框架事先已经定义一种监听器:ProgressListener(进度监听器),里面有一个update(long readedBytes, long totalBytes, int currentItem)方法,其中,readedBytes是已经上传到服务器的位数,而totalBytes是上传文件总位数.当文件已二进制的方式上传时,每上传一部分数据,就会调用这个方法一次。故要实现监听进度,必须实现这个接口,并实现update方法,在update方法中保存这个进度到session。当客服端需要进度的信息时,只需要访问某个action,在这个action中读取session中保存的进度状态就可以了.

上传文件可大致分为两个阶段:1. 上传到服务器上,在临时目录中 2.从临时目录中把文件移到指定目录(由自己写的action处理),struts2.的监听器只监听

第一阶段实现:

第一步:

    实现ProgressListener接口,实现update( )方法,详情见action包中的FileUploadListener.java 文件,里面有一个自定义的类:State ,它描述的是进度的状态,详情请看State注释。Update方法要做的就是不断地更新session中的state对象

 

第二步:

   将监听器注入到struts2.0MultiPartRequest封装类中,客户端发送request到服务器,struts2.0会将request封装成MultiPartRequest。因此必须将监听器注入到MultiPartRequest中。只需要在MultiPartRequest中加入以下两句:

 

FileUploadListener progressListener = new FileUploadListener(servletRequest);

upload.setProgressListener(progressListener);//添加自己的监听器

 

所以重新写一个新类MyMultiPartRequest代替MultiPartRequest ,代码与org.apache.struts2.dispatcher.multipart.MultiPartRequest 一样,在方法

private List<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir)  中加入监听器.

 

   struts.xml中重新指定MultiPartRequest:

 <bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="requestParser"

        class="action.MyMultiPartRequest" scope="default" optional="true" />

  <constant name="struts.multipart.handler" value="requestParser" />

到这里,基本完成大部分工作.

附录:

State.java

[java]  view plain copy print ?
  1. public class State {  
  2.         private long readedBytes = 0L;  
  3.     private long totalBytes = 0L;  
  4.     private int currentItem = 0;  
  5.     private int rate=0;  
  6.             public long getReadedBytes() {  
  7.         return readedBytes;  
  8.     }  
  9.       
  10.     public void setReadedBytes(long readedBytes) {  
  11.         this.readedBytes = readedBytes;  
  12.     }  
  13.       
  14.     public long getTotalBytes() {  
  15.         return totalBytes;  
  16.     }  
  17.       
  18.     public void setTotalBytes(long totalBytes) {  
  19.         this.totalBytes = totalBytes;  
  20.     }  
  21.     public int getCurrentItem() {  
  22.         return currentItem;  
  23.     }  
  24.       
  25.     public void setCurrentItem(int currentItem) {  
  26.         this.currentItem = currentItem;  
  27.     }  
  28.   
  29.     public int getRate() {  
  30.         return rate;  
  31.     }  
  32.     public void setRate(int rate) {  
  33.         this.rate = rate;  
  34.     }  
  35. }  

FileUploadListener.java

[java]  view plain copy print ?
  1. import javax.servlet.http.HttpServletRequest;  
  2. import javax.servlet.http.HttpSession;  
  3. import org.apache.commons.fileupload.ProgressListener;  
  4. import cn.com.order.model.State;  
  5.   
  6. public class FileUploadListener implements ProgressListener {  
  7.     private HttpSession session;  
  8.     public FileUploadListener(HttpServletRequest request) {  
  9.         session = request.getSession();  
  10.         State state = new State();  
  11.         session.setAttribute("state", state);  
  12.     }  
  13.     @Override  
  14.     public void update(long readedBytes, long totalBytes, int currentItem) {  
  15.       
  16.         System.out.println("update:" + readedBytes + ";" + totalBytes + ";" + (int)(((float)readedBytes/(float)     ?           totalBytes)*100) + ";" + currentItem);  
  17.         State state = (State) session.getAttribute("state");  
  18.         state.setReadedBytes(readedBytes);  
  19.         state.setTotalBytes(totalBytes);  
  20.         state.setCurrentItem(currentItem);  
  21.     }  
  22. }  

MyMultipartRequest.java

[java]  view plain copy print ?
  1. import com.opensymphony.xwork2.inject.Inject;  
  2. import com.opensymphony.xwork2.util.logging.Logger;  
  3. import com.opensymphony.xwork2.util.logging.LoggerFactory;  
  4. import org.apache.commons.fileupload.FileItem;  
  5. import org.apache.commons.fileupload.FileUploadException;  
  6. import org.apache.commons.fileupload.RequestContext;  
  7. import org.apache.commons.fileupload.disk.DiskFileItem;  
  8. import org.apache.commons.fileupload.disk.DiskFileItemFactory;  
  9. import org.apache.commons.fileupload.servlet.ServletFileUpload;  
  10. import org.apache.struts2.StrutsConstants;  
  11. import javax.servlet.http.HttpServletRequest;  
  12. import java.io.File;  
  13. import java.io.IOException;  
  14. import java.io.InputStream;  
  15. import java.io.UnsupportedEncodingException;  
  16. import java.util.ArrayList;  
  17. import java.util.Collections;  
  18. import java.util.Enumeration;  
  19. import java.util.HashMap;  
  20. import java.util.List;  
  21. import java.util.Map;  
  22. import org.apache.struts2.dispatcher.multipart.MultiPartRequest;  
  23.   
  24. public class MyMultiPartRequest implements MultiPartRequest{  
  25.     static final Logger LOG = LoggerFactory.getLogger(MultiPartRequest.class);  
  26.       
  27.     // maps parameter name -> List of FileItem objects  
  28.     protected Map<String,List<FileItem>> files = new HashMap<String,List<FileItem>>();  
  29.   
  30.     // maps parameter name -> List of param values  
  31.     protected Map<String,List<String>> params = new HashMap<String,List<String>>();  
  32.   
  33.     // any errors while processing this request  
  34.     protected List<String> errors = new ArrayList<String>();  
  35.       
  36.     protected long maxSize;  
  37.   
  38.     @Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)  
  39.     public void setMaxSize(String maxSize) {  
  40.         this.maxSize = Long.parseLong(maxSize);  
  41.     }  
  42.   
  43.     /** 
  44.      * Creates a new request wrapper to handle multi-part data using methods adapted from Jason Pell's 
  45.      * multipart classes (see class description). 
  46.      * 
  47.      * @param saveDir        the directory to save off the file 
  48.      * @param request the request containing the multipart 
  49.      * @throws java.io.IOException  is thrown if encoding fails. 
  50.      */  
  51.     public void parse(HttpServletRequest request, String saveDir) throws IOException {  
  52.         try {  
  53.             processUpload(request, saveDir);  
  54.         } catch (FileUploadException e) {  
  55.             LOG.warn("Unable to parse request", e);  
  56.             errors.add(e.getMessage());  
  57.         }  
  58.     }  
  59.   
  60.     private void processUpload(HttpServletRequest request, String saveDir) throws FileUploadException, UnsupportedEncodingException {  
  61.         for (FileItem item : parseRequest(request, saveDir)) {  
  62.             if (LOG.isDebugEnabled()) {  
  63.                 LOG.debug("Found item " + item.getFieldName());  
  64.             }  
  65.             if (item.isFormField()) {  
  66.                 processNormalFormField(item, request.getCharacterEncoding());  
  67.             } else {  
  68.                 processFileField(item);  
  69.             }  
  70.         }  
  71.     }  
  72.   
  73.     private void processFileField(FileItem item) {  
  74.         LOG.debug("Item is a file upload");  
  75.   
  76.         // Skip file uploads that don't have a file name - meaning that no file was selected.  
  77.         if (item.getName() == null || item.getName().trim().length() < 1) {  
  78.             LOG.debug("No file has been uploaded for the field: " + item.getFieldName());  
  79.             return;  
  80.         }  
  81.   
  82.         List<FileItem> values;  
  83.         if (files.get(item.getFieldName()) != null) {  
  84.             values = files.get(item.getFieldName());  
  85.         } else {  
  86.             values = new ArrayList<FileItem>();  
  87.         }  
  88.   
  89.         values.add(item);  
  90.         files.put(item.getFieldName(), values);  
  91.     }  
  92.   
  93.     private void processNormalFormField(FileItem item, String charset) throws UnsupportedEncodingException {  
  94.         LOG.debug("Item is a normal form field");  
  95.         List<String> values;  
  96.         if (params.get(item.getFieldName()) != null) {  
  97.             values = params.get(item.getFieldName());  
  98.         } else {  
  99.             values = new ArrayList<String>();  
  100.         }  
  101.   
  102.         // note: see http://jira.opensymphony.com/browse/WW-633  
  103.         // basically, in some cases the charset may be null, so  
  104.         // we're just going to try to "other" method (no idea if this  
  105.         // will work)  
  106.         if (charset != null) {  
  107.             values.add(item.getString(charset));  
  108.         } else {  
  109.             values.add(item.getString());  
  110.         }  
  111.         params.put(item.getFieldName(), values);  
  112.     }  
  113.   
  114.     private List<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException {  
  115.         DiskFileItemFactory fac = createDiskFileItemFactory(saveDir);  
  116.         ServletFileUpload upload = new ServletFileUpload(fac);  
  117.         upload.setSizeMax(maxSize);  
  118.         /*自己新建监听器*/  
  119.         FileUploadListener progressListener = new FileUploadListener(servletRequest);  
  120.         upload.setProgressListener(progressListener);//添加自己的监听器  
  121.           
  122.         return upload.parseRequest(createRequestContext(servletRequest));  
  123.     }  
  124.   
  125.     private DiskFileItemFactory createDiskFileItemFactory(String saveDir) {  
  126.         DiskFileItemFactory fac = new DiskFileItemFactory();  
  127.         // Make sure that the data is written to file  
  128.         fac.setSizeThreshold(0);  
  129.         if (saveDir != null) {  
  130.             fac.setRepository(new File(saveDir));  
  131.         }  
  132.         return fac;  
  133.     }  
  134.   
  135.     /* (non-Javadoc) 
  136.      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFileParameterNames() 
  137.      */  
  138.     public Enumeration<String> getFileParameterNames() {  
  139.         return Collections.enumeration(files.keySet());  
  140.     }  
  141.   
  142.     /* (non-Javadoc) 
  143.      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getContentType(java.lang.String) 
  144.      */  
  145.     public String[] getContentType(String fieldName) {  
  146.         List<FileItem> items = files.get(fieldName);  
  147.   
  148.         if (items == null) {  
  149.             return null;  
  150.         }  
  151.   
  152.         List<String> contentTypes = new ArrayList<String>(items.size());  
  153.         for (FileItem fileItem : items) {  
  154.             contentTypes.add(fileItem.getContentType());  
  155.         }  
  156.   
  157.         return contentTypes.toArray(new String[contentTypes.size()]);  
  158.     }  
  159.   
  160.     /* (non-Javadoc) 
  161.      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFile(java.lang.String) 
  162.      */  
  163.     public File[] getFile(String fieldName) {  
  164.         List<FileItem> items = files.get(fieldName);  
  165.   
  166.         if (items == null) {  
  167.             return null;  
  168.         }  
  169.   
  170.         List<File> fileList = new ArrayList<File>(items.size());  
  171.         for (FileItem fileItem : items) {  
  172.             File storeLocation = ((DiskFileItem) fileItem).getStoreLocation();  
  173.             if(fileItem.isInMemory() && storeLocation!=null && !storeLocation.exists()) {  
  174.                 try {  
  175.                     storeLocation.createNewFile();  
  176.                 } catch (IOException e) {  
  177.                     if(LOG.isErrorEnabled()){  
  178.                         LOG.error("Cannot write uploaded empty file to disk: " + storeLocation.getAbsolutePath(),e);  
  179.                     }  
  180.                 }  
  181.             }  
  182.             fileList.add(storeLocation);  
  183.         }  
  184.   
  185.         return fileList.toArray(new File[fileList.size()]);  
  186.     }  
  187.   
  188.     /* (non-Javadoc) 
  189.      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFileNames(java.lang.String) 
  190.      */  
  191.     public String[] getFileNames(String fieldName) {  
  192.         List<FileItem> items = files.get(fieldName);  
  193.   
  194.         if (items == null) {  
  195.             return null;  
  196.         }  
  197.   
  198.         List<String> fileNames = new ArrayList<String>(items.size());  
  199.         for (FileItem fileItem : items) {  
  200.             fileNames.add(getCanonicalName(fileItem.getName()));  
  201.         }  
  202.   
  203.         return fileNames.toArray(new String[fileNames.size()]);  
  204.     }  
  205.   
  206.     /* (non-Javadoc) 
  207.      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFilesystemName(java.lang.String) 
  208.      */  
  209.     public String[] getFilesystemName(String fieldName) {  
  210.         List<FileItem> items = files.get(fieldName);  
  211.   
  212.         if (items == null) {  
  213.             return null;  
  214.         }  
  215.   
  216.         List<String> fileNames = new ArrayList<String>(items.size());  
  217.         for (FileItem fileItem : items) {  
  218.             fileNames.add(((DiskFileItem) fileItem).getStoreLocation().getName());  
  219.         }  
  220.   
  221.         return fileNames.toArray(new String[fileNames.size()]);  
  222.     }  
  223.   
  224.     /* (non-Javadoc) 
  225.      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameter(java.lang.String) 
  226.      */  
  227.     public String getParameter(String name) {  
  228.         List<String> v = params.get(name);  
  229.         if (v != null && v.size() > 0) {  
  230.             return v.get(0);  
  231.         }  
  232.   
  233.         return null;  
  234.     }  
  235.   
  236.     /* (non-Javadoc) 
  237.      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameterNames() 
  238.      */  
  239.     public Enumeration<String> getParameterNames() {  
  240.         return Collections.enumeration(params.keySet());  
  241.     }  
  242.   
  243.     /* (non-Javadoc) 
  244.      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameterValues(java.lang.String) 
  245.      */  
  246.     public String[] getParameterValues(String name) {  
  247.         List<String> v = params.get(name);  
  248.         if (v != null && v.size() > 0) {  
  249.             return v.toArray(new String[v.size()]);  
  250.         }  
  251.   
  252.         return null;  
  253.     }  
  254.   
  255.     /* (non-Javadoc) 
  256.      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getErrors() 
  257.      */  
  258.     public List getErrors() {  
  259.         return errors;  
  260.     }  
  261.   
  262.     /** 
  263.      * Returns the canonical name of the given file. 
  264.      * 
  265.      * @param filename  the given file 
  266.      * @return the canonical name of the given file 
  267.      */  
  268.     private String getCanonicalName(String filename) {  
  269.         int forwardSlash = filename.lastIndexOf("/");  
  270.         int backwardSlash = filename.lastIndexOf("\\");  
  271.         if (forwardSlash != -1 && forwardSlash > backwardSlash) {  
  272.             filename = filename.substring(forwardSlash + 1, filename.length());  
  273.         } else if (backwardSlash != -1 && backwardSlash >= forwardSlash) {  
  274.             filename = filename.substring(backwardSlash + 1, filename.length());  
  275.         }  
  276.   
  277.         return filename;  
  278.     }  
  279.   
  280.     /** 
  281.      * Creates a RequestContext needed by Jakarta Commons Upload. 
  282.      * 
  283.      * @param req  the request. 
  284.      * @return a new request context. 
  285.      */  
  286.     private RequestContext createRequestContext(final HttpServletRequest req) {  
  287.         return new RequestContext() {  
  288.             public String getCharacterEncoding() {  
  289.                 return req.getCharacterEncoding();  
  290.             }  
  291.   
  292.             public String getContentType() {  
  293.                 return req.getContentType();  
  294.             }  
  295.   
  296.             public int getContentLength() {  
  297.                 return req.getContentLength();  
  298.             }  
  299.   
  300.             public InputStream getInputStream() throws IOException {  
  301.                 InputStream in = req.getInputStream();  
  302.                 if (in == null) {  
  303.                     throw new IOException("Missing content in the request");  
  304.                 }  
  305.                 return req.getInputStream();  
  306.             }  
  307.         };  
  308.     }  
  309. }  

UploadAction.java

[java]  view plain copy print ?
  1. import java.io.*;  
  2.   
  3. import javax.servlet.http.HttpSession;  
  4.   
  5. import org.apache.struts2.ServletActionContext;  
  6.   
  7. import com.opensymphony.xwork2.ActionSupport;  
  8.   
  9. public class FileProgressUploadAction extends ActionSupport{  
  10.         private File file;  
  11.     private String fileFileName;  
  12.     private String fileContentType;  
  13.     public File getFile() {  
  14.         return file;  
  15.     }  
  16.       
  17.     public void setFile(File file) {  
  18.         this.file = file;  
  19.     }  
  20.       
  21.   
  22.     public String getFileFileName() {  
  23.         return fileFileName;  
  24.     }  
  25.   
  26.     public void setFileFileName(String fileFileName) {  
  27.         this.fileFileName = fileFileName;  
  28.     }  
  29.   
  30.     public String getFileContentType() {  
  31.         return fileContentType;  
  32.     }  
  33.   
  34.     public void setFileContentType(String fileContentType) {  
  35.         this.fileContentType = fileContentType;  
  36.     }  
  37.       
  38.     @Override  
  39.     public String execute(){  
  40.          
  41.        try {  
  42.            System.out.println("file:"+file);  
  43.            InputStream is=new FileInputStream(file);  
  44.            String root=ServletActionContext.getRequest().getRealPath("/upload");  
  45.            System.out.println("root:"+root);  
  46.              
  47.            System.out.println("name:"+this.fileFileName);  
  48.            System.out.println("type:"+this.fileContentType);  
  49.            File destFile=new File(root,this.fileFileName);  
  50.              
  51.            OutputStream os=new FileOutputStream(destFile);    
  52.              
  53.            byte [] b=new byte[1024*1024*10];  
  54.            int length=0;                     
  55.            while(true){  
  56.                  length=is.read(b);  
  57.                  if(length<0)  
  58.                      break;  
  59.                  os.write(b,0,length);                     
  60.            }              
  61.   
  62.            is.close();  
  63.            os.close();  
  64.        }catch (Exception e) {  
  65.             // TODO Auto-generated catch block  
  66.             e.printStackTrace();  
  67.        }  
  68.       return "success";  
  69.    }  
  70. }  

ProgressAction.java(更新进度条进度的Action)注:jsp使用setInterval用Ajax技术定时访问该Action,就可以定时获取到上传进度

[java]  view plain copy print ?
  1. import org.apache.struts2.ServletActionContext;  
  2. import javax.servlet.http.HttpSession;  
  3.   
  4. import com.opensymphony.xwork2.ActionSupport;  
  5.   
  6. public class FileProgressAction extends ActionSupport{  
  7.     private State state;  
  8.           
  9.     public State getState() {  
  10.         return state;  
  11.     }  
  12.   
  13.     public void setState(State state) {  
  14.         this.state = state;  
  15.     }  
  16.   
  17.   
  18.     @Override  
  19.     public String execute() throws Exception {  
  20.         // TODO Auto-generated method stub  
  21.         HttpSession session=ServletActionContext.getRequest().getSession();  
  22.         this.state=(State)session.getAttribute("state");          
  23.         if(state==null){  
  24.             System.out.println("action is null");  
  25.             state=new State();  
  26.             state.setCurrentItem(0);  
  27.         }else{  
  28.               
  29.             Double a=Double.parseDouble(state.getReadedBytes()+"");  
  30.             Double b=Double.parseDouble(state.getTotalBytes()+"");            
  31.             double result=a/b*100;  
  32.             state.setRate((int)result);  
  33.             System.out.println("action:"+state.getRate());  
  34.         }  
  35.         return "success";  
  36.     }  
  37. }  

Upload.jsp(Ajax文件上传)需要下载ajaxfileupload.js,jquery-ui.js(显示进度条)插件

[java]  view plain copy print ?
  1. <%@ page language="java" contentType="text/html; charset=UTF-8"  
  2.     pageEncoding="UTF-8"%>  
  3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  4. <html>  
  5. <head>  
  6. <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">  
  7. <title>文件上传</title>  
  8. <link rel="stylesheet" href="js/jquery-ui-1.9.2.css" />    
  9. <script src="js/jquery-1.8.3.js"></script>    
  10. <script src="js/jquery-ui-1.9.2.js"></script>    
  11. <script type="text/javascript" src="js/ajaxfileupload.js"></script>  
  12. <script type="text/javascript">  
  13. var time = 0;  
  14. function ajaxFileUpload()  
  15. {  
  16.     $( "#progressbar" ).progressbar({        
  17.          value: 0    
  18.     });  
  19.     time = window.setInterval(progress,1000);  
  20.     $.ajaxFileUpload  
  21.     (  
  22.         {  
  23.             url:'hello.action',  
  24.             secureuri:false,  
  25.             fileElementId:'fileToUpload',//fileToUpload是input file 标签的id值  
  26.             dataType: 'multipart/form-data',  
  27.             success: function (data, status)  
  28.             {  
  29.                 if(typeof(data.error) != 'undefined')  
  30.                 {  
  31.                     if(data.error != '')  
  32.                     {  
  33.                         alert(data.error);  
  34.                     }else  
  35.                     {  
  36.                         alert(data.msg);  
  37.                     }  
  38.                 }  
  39.             },  
  40.             error: function (data, status, e)  
  41.             {  
  42.                 alert(e);  
  43.             }  
  44.         }  
  45.     )  
  46.     return false;  
  47. }  
  48.   
  49. function progress(){  
  50.     $.ajax({  
  51.         url:"progress.action",  
  52.         dataType: 'json',  
  53.         success:function(data){  
  54.             $("#loading").html(data.state.rate);  
  55.             $( "#progressbar" ).progressbar({        
  56.                  value: data.state.rate     
  57.             });  
  58.             if(data.state.rate == 100){  
  59.                 clearInterval(time);  
  60.             }  
  61.         },  
  62.         error:function(){  
  63.             alert("error");  
  64.         }  
  65.     });  
  66. }  
  67. </script>  
  68. </head>  
  69. <body>      
  70.     <form name="form" action="" method="POST" enctype="multipart/form-data">  
  71.       
  72.         <input type="file" id="fileToUpload" name="fileToUpload"/>  
  73.         <input type="text" name="username"/>  
  74.         <input type="button" value="上传" onclick="ajaxFileUpload()"/>  
  75.     </form>  
  76.     <div id="progressbar"></div>  
  77. </body>  
  78. </html>  

你可能感兴趣的:(struts2实现带进度条的文件上传)