Java dynamic display file upload progress implementation code

  • 2020-06-03 06:21:13
  • OfStack

This article is an example of the implementation of file upload progress display, let's first look at what problems we have to solve.

Progress tracking of uploaded data processing
2. Display of progress data on user page

So just two questions,
The first problem is the selection of components
Components that must support data processing for listening or notification. Of course, I will only use my own components. The basic principle is

1 Use ES12en. getContentLength() to read the total length of the processed data. Note that this length is not equal to the length of the file, because the encoding like Base64 will increase the amount of data.

2 Notits our progress tracker of the number of bytes read per 1 part read (e.g., 1 line, or 64K, or the number of bytes you customize). I named it UploadListener and the code is as follows


/*
*  Notification to process attachment uploads. 

*  You can inherit from this class to implement your own special handling.  
* 
* @author  author  www.java2000.net 
*/ 
 public class UploadListener ... { 
 //  Debug mode will print out at the console 1 Some of the data  
 private boolean debug;

 //  Total number of data bytes  
 private int total;

 //  The number of bytes of data currently processed  
 private int totalCurrent = 0 ;

 //  Delay, used for debugging, in case the speed is too fast, the card can't see the progress  
 private int delay = 0 ;

  /** */ /** 
 *  Methods for processing data notifications. 

 *  Save the data that has been processed. And in the 1 Set the proportion to delay. The default for each 1%

 *  If you don't need delay, you can get rid of the internal code and speed it up.  
 * 
 * @param size  The number of bytes added  
  */ 
  public void increaseTotalCurrent( long size) ... { 
  this .totalCurrent += size; 
  try ... { 
  currentRate = totalCurrent * 100 / total; 
   if (currentRate > lastRate) ... { 
   if (delay > 0 ) ... { 
   Thread.sleep(delay); 
   } 
   if (debug) ... { 
   System.out.println( " rate= " + totalCurrent + " / " + total + " / " + (totalCurrent * 100 / total)); 
   } 
   lastRate = currentRate; 
  } 
  } catch (Exception e) ... { 
  e.printStackTrace(); 
  } 
 } 

  /** */ /** 
 *  Read all its own Numbers  
 * 
 * @return 
  */ 
  public int getTotal() ... { 
  return total; 
 } 

  /** */ /** 
 *  Reads the number of bytes that have been processed  
 * 
 * @return 
  */ 
  public int getTotalCurrent() ... { 
  return totalCurrent; 
 } 

 private long lastRate = 0 ;

 private long currentRate = 0 ;

  public int getDelay() ... { 
  return delay; 
 } 

  public void setDelay( int delay) ... { 
  this .delay = delay; 
 } 

  public void setTotal( int total) ... { 
  this .total = total; 
 } 

  public boolean isDebug() ... { 
  return debug; 
 } 

  public void setDebug( boolean debug) ... { 
  this .debug = debug; 
 } 
}

3 Now let's look at the processing part of the upload


 Upload upload = new Upload(request); 
 //  Added code to listen for progress  
 UploadListener uploadListener = new UploadListener(); 
 //  We'll talk about that later, but that's the point  
 session.setAttribute( " uploadListener " ,uploadListener); 
 uploadListener.setDelay( 0 ); 
 uploadListener.setDebug( true ); 
 upload.setUploadListener(uploadListener); 
 upload.parse(); 
 //  This is equally important, and we will discuss it later  
 session.setAttribute( " uploadListener " , null );

4 Let's look at the uploaded form again


< script. type = " text/javascript. " > 
 function checkForm() ... { 
 $( " SHOW_FRAME. " ).src = " link.jsp " ; 
 $( ' SUBMIT ' ).disabled = true ; 
 Ext.MessageBox.show( ... { 
  title: ' Please wait... ' , 
  msg: ' Initializing... ' , 
  width: 240 , 
  progress: true , 
  closable: false 
 } ); 
 $( " MAIN_FORM. " ).submit(); 
 return false ; 
} 
 function setUploadProcess(total,current) ... { 
 var rate = Number(current) / Number(total); 
 Ext.MessageBox.updateProgress(rate, ' Uploading... ' + current + " / " + total); 
  if (Number(current) >= Number(total)) ... { 
  closeUploadProcess(); 
 } 
} 
 function closeUploadProcess() ... { 
 Ext.MessageBox.hide(); 
} 
</ script. > 
< iframe. name = " ACTION_FRAME. " id = " ACTION_FRAME. " width = " 0 " height = " 0 " ></ iframe. > 
< iframe. name = " SHOW_FRAME. " id = " SHOW_FRAME. " width = " 0 " height = " 0 " ></ iframe. > 
< form. method = " OST " id = " MAIN_FORM. " nsubmit = " return checkForm() " enctype = " multipart/form-data " 
 action = " uploadFileSave.jsp " target = " ACTION_FRAME. " > 
 < input type = " file " size = " 50 " name = " file " > 
 < input type = " submit " ID = " SUBMIT " value = " Upload It " > 
</ form. >

The first iframe is for submitting the form data, and the second is for getting progress information on the processing data.
Submitting the form is simple, and target points to our first iframe.
So let's go to 1 JS
The first sentence in checkForm is the page with the key read progress information, which we get in iframe 2. Then the progress box pops up. I use Ext. Then I submit the upload form
setUploadProcess is used to update the data above the progress box. The first parameter is the total size of the data and the second parameter is the processed size.
closeUploadProcess closes the progress box

Finally, let's look at the page for reading progress information


<% @ page language = " java " contentType = " text/html; charset=utf-8 " pageEncoding = " utf-8 " %> 
<% @include file = " ../package.inc.jsp " %> 
<% 
 response.setHeader( " ragma " , " no-cache " ); 
 response.setHeader( " Cache-Control " , " no-cache " ); 
 response.setDateHeader( " Expires " , 0 ); 
 response.setBufferSize( 0 ); 
 UploadListener uploadListener = null ; 
  while (uploadListener == null || uploadListener.getTotalCurrent() <= 0 ) ... { 
  uploadListener = (UploadListener) session.getAttribute( " uploadListener " ); 
  out.print( " . " ); 
  out.flush(); 
  Thread.sleep( 10 ); 
 } 
 long total = uploadListener.getTotal(); 
 out.println(total); 
 long current; 
 out.flush(); 
  while ( true ) ... { 
  current = uploadListener.getTotalCurrent(); 
  if (current >= total) ... { 
  break ; 
  } 
  out.println( " <script. type='text/javascript'>parent.setUploadProcess(' " + total + " ',' " + current + " ');</script> " ); 
  out.flush(); 
  Thread.sleep( 10 ); 
 } 
%>< script. type = " text/javascript. " > parent.closeUploadProcess(); </ script. >

The preceding loop is used to determine whether the uploaded information has been generated, and if not, to wait.

Then read the uploaded information and calculate JS to generate the update progress bar calling the parent window. Please note that out.print must be followed by out.flush, otherwise the output will not continue to the client and you will not see continuous progress bar changes.

Conclusion:

The top section is a bit messy, so I'll summarize 1 of the key points here.

1, in the upload component, the total size and the current read size into a class, and continue to update until the processing is completed
2. The uploaded progress class is placed in session for reading the progress page
3. Read the page, get the data from session and return the result.

A couple of questions to explain 1.

1. As determined by the Http protocol, the output will not be returned until the processing of request is completed, so the processing progress cannot be displayed in the upload page. I did not test the file about 1M successfully, but I did not consider this problem. Therefore, a separate GET program must be used to read
2. Reading is a continuous process because uploading large files is slow!
3. If your application server has GZIP compressed enabled, which is container-managed, then unfortunately, because it is easy to get all of the data, at least 1 part of it, back, the few bytes we return are often intercepted, making it impossible to show the continuous process of uploading.

The solution

1) Turn off GZIP, which I don't think many people will do
2) Use custom GZIP compression to determine things (like URL) and not compress them


Related articles: