ajax|js| Performance We will implement an AJAX-capable component that not only implements the actual process of uploading files to the server, but also "real-time" monitoring of file uploads. (iv) Progressmonitorfileitem class
public class Progressmonitorfileitem extends Diskfileitem { Private Progressobserver Observer; Private Long passedinfilesize; ... Private Boolean Isformfield; ... @Override Public OutputStream Getoutputstream () throws IOException { OutputStream baseoutputstream = super.g Etoutputstream (); if (Isformfield = = False) { return new Bytescountingoutputstream (Baseoutputstream); }else{return Baseoutputstream;} } ... Private class Bytescountingoutputstream extends outputstream{ Private long previousprogressupdate Private OutputStream base; Public Bytescountingoutputstream (OutputStream ous) {base = ous;} ... private void fireprogressevent (int b) { Bytesread + = b; ... Double progress = ((double) (bytesread)/passedinfilesize); Progress *= 100.0 Observer.setprogress (); } } } |
Progressmonitorfileitem wraps the default outputstream of Diskfileitem into a bytescountingoutputstream, This can update the associated progressobserver each time a certain number of bytes are read.
(v) AJAX-enabled JavaServer Faces (JSF) Upload components
This component is responsible for generating HTML file upload tags, displaying a progress bar to monitor file uploads, and generating components that need to be displayed once the file is uploaded successfully. One of the main advantages of using JavaServer faces to implement this component is that most of the complexity is hidden. Developers only need to add component tags to the JSP, and then the component will be responsible for all Ajax and related progress bars to monitor the details. The following JSP code fragment is used to add the upload component to the page.
Value= "#{uploadpagebean.uploadedfile}" uploadicon= "Images/upload.png" Styleclass= "Progressbardiv" Progressbarstyleclass= "ProgressBar" Cellstyleclass= "Progressbarcell" Activestyleclass= "Progressbaractivecell" > <%--below is the component that will become visible once the file upload is completed--%> Value= "file uploaded successfully."/> Image= "Images/reset.png"/> Image= "Images/continue.png"/> |
The Value property of the file upload component needs to be bound to a bean with an attribute with a fileitem. The component is displayed only if the file is successfully received by the server.
third, the realization of Ajax file upload components
Essentially, uploading a component or generating a complete self, or, in the case of an AJAX request, only generates part of the XML to update the status of the progress bar on the page. To prevent the JavaServer faces from generating the complete component tree (which can result in unnecessary load), We also need to implement a Phaselistener (Pagephaselistener) to cancel the other parts of the faces request processing-If an AJAX request is encountered. I've omitted all the discussion about standard configurations (Faces-config.xml and tag libraries) in this article because they are fairly straightforward and have been discussed before, and are all contained in the source code accompanying this article, which you can analyze in detail.
(i) Ajax file Upload Component Builder
The implementation of this component and tag class is simpler. A large number of logic is included in the builder, specifically, it is responsible for the following:
· Encode the entire upload component (and the full HTML file upload tag), the component to display when the file is uploaded, and the client JavaScript code that implements the AJAX request.
· Handle partially AJAX requests appropriately and send back the necessary XML.
· Decode a file upload and set it to a Fileitem instance.
(ii) encoding the entire upload component
As mentioned earlier, the file Upload component consists of three phases. During the entire encoding of the component, we will analyze the encoding for these three phases in detail. Note that the visualization of the component on the page (using CSS Display) attributes will be controlled by Ajax JavaScript.
(iii) Phase I
Figure 5 shows the first phase of the upload component.
Figure 5. Select File Upload |
In the first phase, we need to generate HTML file upload tags and click the upload button when the corresponding execution code. Once the user clicks on the Upload button, the form is submitted and initialized to the second phase by an IFRAME (to prevent the page from blocking). The following is part of the generated code:
File Upload Component Writer.startelement ("input", component); Writer.writeattribute ("type", "file", null); Writer.writeattribute ("Name", Component.getclientid (context), "id"); Writer.writeattribute ("id", Component.getclientid (context), "id"); if (Input.getvalue ()!= null) { If available, the file name is generated. Fileitem filedata = (fileitem) input.getvalue (); Writer.writeattribute ("Value", Filedata.getname (), Filedata.getname ()); } Writer.endelement ("input"); String Iconurl = Input.getuploadicon (); Generate images and attach JavaScript events to them. Writer.startelement ("div", component); Writer.writeattribute ("Style", "display:block;width:100%;text-align:center;", "style"); Writer.startelement ("img", component); Writer.writeattribute ("src", Iconurl, "src"); Writer.writeattribute ("type", "image", "type"); Writer.writeattribute ("Style", "cursor:hand;cursor:pointer;", "style"); UIForm form = Facesutils.getform (context,component); if (form!= null) { String Getformjs = "document.getElementById ('" + form.getclientid (context) + "')"; String Jsfriendlyclientid = Input.getclientid (context). Replace (":", "_"); Set the encoding of the form to multipart for file uploads, and pass an IFRAME To submit its contents. The second phase of the component is also initialized after 500 milliseconds. Writer.writeattribute ("onclick", Getformjs + ". encoding= ' Multipart/form-data ';" + Getformjs + ". target= '" + Iframename + "" + Getformjs + ". Submit ();" + Getformjs + ". encoding= ' application/x-www-form-urlencoded ';" + Getformjs + ". target= ' _self ';" + "SetTimeout (' refreshprogress" + Jsfriendlyclientid + "(); ';"; ", null); } ... Writer.endelement ("img"); Now implement the IFRAME we are going to submit the file/form to. Writer.startelement ("iframe", component); Writer.writeattribute ("id", iframename, NULL); Writer.writeattribute ("name", Iframename,null); Writer.writeattribute ("Style", "display:none;", null); Writer.endelement ("iframe"); Writer.endelement ("div"); Writer.endelement ("div"); Phase 1 over |
(iv) Phase II
The second stage is a progress bar and label showing the current percentage, as shown in Figure 6. The progress bar is implemented as a DIV tag with 100 inline span tags. These will be set by Ajax JavaScript based on the response from the server.
Figure 6. Uploading files to the server |
Writer.startelement ("div", component); Writer.writeattribute ("id", Input.getclientid (context) + "_stage2", "id"); ... Writer.writeattribute ("Style", "Display:none", "style"); String Progressbarid = Component.getclientid (context) + "_progressbar"; String Progressbarlabelid = Component.getclientid (context) + "_progressbarlabel"; Writer.startelement ("div", component); Writer.writeattribute ("id", Progressbarid, "id"); String Progressbarstyleclass = Input.getprogressbarstyleclass (); if (Progressbarstyleclass!= null) Writer.writeattribute ("Class", Progressbarstyleclass, "class"); for (int i=0;i<100;i++) { Writer.write (" "); } Writer.endelement ("div"); Writer.startelement ("div", component); Writer.writeattribute ("id", Progressbarlabelid, "id"); ... Writer.endelement ("div"); Writer.endelement ("div"); Phase 2 over |
(v) Phase three
Finally, as stage three, once the file is uploaded successfully, the component that needs to be displayed is generated, as shown in Figure 7. These are implemented in the Encodechildren method of the generator.
Figure 7. Upload Complete |
public void Encodechildren (Facescontext context, UIComponent component) throws IOException { Responsewriter writer = Context.getresponsewriter (); Uifileupload input = (uifileupload) component; Once the file is uploaded successfully, handle the child nodes that will be displayed Writer.startelement ("div", component); Writer.writeattribute ("id", Input.getclientid (context) + "_stage3", "id"); Stage 3. if (input.getvalue () = null) { Writer.writeattribute ("Style", "display:none;", null); }else{ Writer.writeattribute ("Style", "Display:block", null); } List children = Input.getchildren (); for (UIComponent Child:children) { Facesutils.encoderecursive (Context,child); } Writer.endelement ("div"); Phase 3 over } |