I need to upload a very heavy file and that's why the progress bar on the same page. I have searched a lot and the interceptor execAndWait
does not work for me because it puts the progress bar on an intermediate page. So I developed my own idea, which is this:
uploadNominate.jsp file
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ taglib prefix="sj" uri="/struts-jquery-tags" %>
<%@ taglib prefix="sb" uri="/struts-bootstrap-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<s:head />
<sj:head jqueryui="true" jquerytheme="cupertino" />
<sb:head/>
<link rel="stylesheet" type="text/css" href="vista/css/subirArchivos.css">
<script type="text/javascript" src="vista/js_libs/bootstrap-filestyle.js"></script>
<script type="text/javascript" src="vista/js/subirArchivoNomina.js"></script>
<title><s:property value="%{getText('conciliacion.de.nomina')}"/></title>
</head>
<body>
<s:form id="form" action="procesarNomina" cssClass="form-horizontal" method="post" enctype="multipart/form-data">
<div class="row">
<div class="col-md-4">
<s:file type="file" class="filestyle" data-buttonBefore="true" id="fileNomina" name="fileNomina" data-text="%{getText('examinar')}" ></s:file>
</div>
<div class="col-md-3">
<sj:progressbar id="progressbarchange" value="21" onChangeTopics="mychangetopic"/> <br />
<sj:a href="#" onClickTopics="myclicktopic" cssClass="buttonlink ui-state-default ui-corner-all">
<span class="ui-icon ui-icon-refresh"></span>change value</sj:a>
</div>
</div>
<div class="row">
<div class="col-md-10">
<s:submit id="btn_subir" button="true" value="%{getText('subir.archivos')}" class="simple ui-button ui-corner-all ui-widget" />
</div>
</div>
</body>
</html>
uploadNomina.js file
$(document).ready( function(){
$(":file").filestyle();
$("#btn_subir").on('click', function(event) {
event.preventDefault();
console.log("llegue");
idInterval=setInterval(function(){
$.ajax({
url: "corriendo",
//data: formData,
type: "POST",
processData: false,
contentType: false
}).done(function (data, textStatus, jqXHR) {
console.log(data);//siempre es 0//always is 0
$("#progressbarchange").progressbar( 'value' , parseInt( data ) );
}).fail(function (jqXHR, textStatus, errorThrown) {
//alert("error\njqXHR=" + jqXHR + "\nstatus=" + textStatus + "\nerror=" + errorThrown);
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
}).always(function(dataORjqXHR, textStatus, jqXHR_ORerrorThrown) {
//alert( "complete" );
});
}, 500*10);
var formData = new FormData();
var archivo = document.getElementsByName("fileNomina");
formData.append("fileNomina", archivo[0].files[0]);
console.log("action="+$("#form").attr("action"));
$.ajax({
url: $("#form").attr("action"),
data: formData,
type: "POST",
processData: false,
contentType: false
}).done(function (data, textStatus, jqXHR) {
clearInterval(idInterval);
console.log(data);
}).fail(function (jqXHR, textStatus, errorThrown) {
alert("error\njqXHR=" + jqXHR + "\nstatus=" + textStatus + "\nerror=" + errorThrown);
}).always(function(dataORjqXHR, textStatus, jqXHR_ORerrorThrown) {
//alert( "complete" );
});
});
$.subscribe('mychangetopic', function(event,data){
console.log("progressbar= "+$("#progressbarchange").progressbar('option', 'value'));
});
$.subscribe('myclicktopic', function(event,data) {
$("#progressbarchange").progressbar( 'value' , parseInt( Math.random() * ( 90 ) ) );
});
});
Here is the main idea: from javascript I execute an action corriendo
which will tell me what percentage has been uploaded from the file, so it is in setInterval
because it should be executed periodically, then with another ajax I upload the file.
struts.xml
//...
<action name="procesarNomina" class="mx.unam.patronato.conciliacion.actions.SubirNominaAction">
<interceptor-ref name="fileUpload">
<param name="maximumSize">52428800</param><!-- 50 MB por archivo-->
<param name="allowedTypes">text/plain, application/rtf, application/msword</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
<result name="success" type="tiles">.subirNominaSinMenu</result>
<result name="input" type="tiles">.subirNominaSinMenu</result>
</action>
<action name="corriendo" class="mx.unam.patronato.conciliacion.actions.SubirNominaAction" method="getStreamPorcentaje">
<result type="stream">
<param name="contentType">text/plain</param>
</result>
</action>
//...
uploadNominaAction.java
public class SubirNominaAction extends ActionSupport implements SessionAware,ServletRequestAware {
private SessionMap<String, Object> sessionMap;
private String fechaInicio,fechaFin;
private HttpServletRequest request;
private List<File> fileNomina=new ArrayList<File>();
private List<String> fileNominaContentType=new ArrayList<String>();
private List<String> fileNominaFileName=new ArrayList<String>();
private Double porcentaje;
private InputStream inputStream;
public SubirNominaAction() {
setPorcentaje(0.0);
}
//getters y setters
public String getStreamPorcentaje() {
inputStream = new ByteArrayInputStream(getPorcentaje().toString().getBytes(StandardCharsets.UTF_8));
return SUCCESS;
}
@Override
public String execute() throws Exception {
//System.out.println("entre:"+fechaInicio);
System.out.print("\n\n---------------------------------------");
int i=0;
for (File file : fileNomina){
double tamanoArchivo=(int)file.length();
double bytesLine=0;
int k=0;
try (Stream<String> lines = Files.lines(Paths.get(file.toURI()), StandardCharsets.ISO_8859_1)){
for(String line : (Iterable<String>) lines::iterator){
bytesLine+=line.getBytes().length;
setPorcentaje(bytesLine/tamanoArchivo*100);
//System.out.println(getPorcentaje());
System.out.println(k+"\t"+line);
//System.out.println(line.getBytes().length);
k++;
}
}catch (Exception e) {
e.printStackTrace();
}
System.out.print("\nFile ["+i+"] ");
System.out.print("; name:" + fileNominaFileName.get(i));
System.out.print("; contentType: " + fileNominaContentType.get(i));
System.out.print("; length: " + file.length());
i++;
}
System.out.println("\n---------------------------------------\n");
return SUCCESS;
}
}
In uploadNominaAction.java I read the total of the file and then read line by line to calculate the porcentaje
that it carries. The file uploads correctly and the percentage is also calculated correctly, I know by console impressions that I made. The problem is that in the setInterval
you declare that you invoke the action corriendo
and that it in turn invokes getStreamPorcentaje
always returns 0 . And that's the value I need to update the progress bar:
console.log(data);//siempre es 0//always is 0
$("#progressbarchange").progressbar( 'value' , parseInt( data ) );
Does anyone have any idea how to correct it? It seems that each time the action class is invoked a new instance is created and it does not use the one that is already running.