⬆️ ⬇️

RichFaces 3.0, File Shaping and Uploading, jQuery and Crutches





Greetings, dear reader! In this article I wanted to state one problem that I encountered while developing, as well as a way to solve it. The solution is certainly not the most perfect, but it has a place to be. If you don’t like something, or you know the solution better, please don’t beat me with big cucumbers, since I’m still small and green. Beat small with comments and teachings.



The task is as follows: we have a system in which there is a page on which some reporting is displayed. There you need to implement the formation of an Excel file and upload it to the user.



The page has the following approximate structure, which is displayed in the upper figure.

')

And the peculiarity is that the table is very large, and you need to upload many records to Excel.

And when you click on the line displays the panel to edit the record.

Code forming file:

public void generatePatientsExcel() { try{ log.info("Generating patients excel"); FacesContext facesContext = FacesContext.getCurrentInstance(); ExternalContext externalContext = facesContext.getExternalContext(); HttpServletResponse response = (HttpServletResponse) externalContext.getResponse(); //Create excel file Workbook wb = new HSSFWorkbook(); // // // // // // Header response.setHeader("Content-disposition", "attachment; filename=1.xls"); response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); response.setCharacterEncoding("UTF-8"); response.setContentType("application/vnd.ms-excel"); //Send Response ServletOutputStream responseOutputStream = response.getOutputStream(); wb.write(responseOutputStream); responseOutputStream.flush(); responseOutputStream.close(); facesContext.responseComplete(); log.info("Generating patients excel comlplete"); } catch (Exception ex) { ex.printStackTrace(); } } 


Well, actually the problem



The problem is that when uploading a file, its formation takes some time, and if at this moment you click on a line, you will get:

 org.jboss.seam.ConcurrentRequestTimeoutException: Concurrent call to conversation 




To avoid this, it is necessary to hang on onclick before generating the JavaScript file a function that displays the Loader. And after the action, hide it, too, with a javascript function hung on oncomplete. It seems simple, is not it?

Underwater rocks



Since we generate the file dynamically, we do not save it to disk, which could have made the task easier by not returning the HttpServletResponse, in which the file, but by clicking on the link where the file is saved on disk. But this, in turn, will be the server disk space, so dynamic file generation is what we need.



The hitch is that the h: commandButton button does not have oncomplete. In general, all the “h:” elements do not have this event. Thinking a little bit: “In general, why do we need this h: commandButton? After all, we have a magic a4j: commandButton. "



Implementing a file upload via a4j: commandButton, it looks like this:



 <a4j:commandButton onclick="showLoader();" image="exportExcel.png" action="#{importToExcelBean.getExcelFile()}" oncomplete="hideLoader();"/> 




And everything seems to be fine, but it is only at first glance. Since a4j: commandButton unloads HttpServletResponse into the current page.



The user uploads the file in Excel format, and a page opens with it. "Disorder" - the user said, punching the keyboard, swearing. And disappointed in our system for life.



You can try to hang a4j: support on h: commandButton, which will display a loader on onsubmit, form a file during the action, and hide a loader on oncomplete. But the problem is that a4j: support cannot return HttpServletResponse from the server. He does this too in the page. Since all a4j elements return HttpServletResponse to the page.



Bad luck turns out. What to do, no one knows, the Internet is silent, users are crying, and you yourself sit as ukakalsya. But such a simple event, but it is so lacking.



Solution, Crutches and jQuery



The decision occurred to a colleague. It's pretty simple.

  1. We divide the file generation procedure into two: generation and return of the request.
  2. Create a4j: commandButton, which is responsible for generating the file without returning it, displaying the loader and hiding it.



     <a4j:commandButton onclick="showLoader();" image="exportExcel.png" action="#{importToExcelBean.generateExcel()}" oncomplete="hideLoader()"/> 
  3. Create a hidden h: commandButton that returns the file, and also assign an id to it for later retrieval.



     <h:commandButton id="exelFileButton" style=" visibility: hidden;" action="#{importToExcelBean.returnResponse()}" /> 
  4. Create a JavaScript function that, with jQuery, finds the hidden h: commandButton by id and presses it.



     <script type="text/javascript" > function clickButtonGetExelFile(){jQuery("#exelFileButton").click();} </script> 


  5. We hang our JavaScript function after hiding the loader.



     <a4j:commandButton onclick="showLoader();" image="exportExcel.png" action="#{importToExcelBean.generatePatientsExcel()}" oncomplete="hideLoader();clickButtonGetExelFile();"/> 






Done, the user receives the file in the form in which it should receive. Critical situation resolved.



image

Source: https://habr.com/ru/post/146474/



All Articles