2016-04-24 127 views
0

我试图实现JSF 2.3文件上传:JSF 2.3文件上传速度太慢

<context-param> 
    <param-name>javax.faces.ENABLE_WEBSOCKET_ENDPOINT</param-name> 
    <param-value>true</param-value> 
</context-param> 

XHTML页面:

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html lang="en" 
     xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" 
     xmlns:h="http://java.sun.com/jsf/html" 
     xmlns:f="http://xmlns.jcp.org/jsf/core"> 
    <h:head> 
     <title>About</title> 
     <script type="text/javascript"> 
      function progressBar(data) { 
       if (data.status == "begin") { 
        document.getElementById("progressBarId").style.display = "block"; 
       } 
       else if (data.status == "complete") { 
        document.getElementById("progressBarId").style.display = "none"; 
       } 
      } 

      function updateProgressBar(percent) { 
       var emptyColor = "#cccccc"; 
       var progressColor = "#3333cc"; 
       document.getElementById("progressBarId").style.background = "linear-gradient(to right, " + progressColor + " 0%, " + progressColor + " " + percent + "%, " + emptyColor + " " + percent + "%, " + emptyColor + " 100%)"; 
      } 
     </script> 
    </h:head> 
    <h:body> 
     <f:websocket channel="uploadProgress" scope="view" onmessage="updateProgressBar" /> 

     <h:messages id="uploadMsgId" globalOnly="true" showDetail="false" showSummary="true" style="color:red"/> 
     <h:form id="uploadFormId" enctype="multipart/form-data"> 
      <h:inputFile id="fileToUpload" required="true" requiredMessage="No file selected ..." value="#{uploadBean.file}"/> 
      <h:message showDetail="false" showSummary="true" for="fileToUpload" style="color:red"/> 
      <h:commandButton value="Upload" action="#{uploadBean.upload()}"> 
       <f:ajax execute="fileToUpload" onevent="progressBar" render=":uploadMsgId @form"/> 
      </h:commandButton> 
     </h:form> 
     <div> 
      <div id="progressBarId" style="display: none; width: 250px; height: 23px; border: 1px solid black;" width="250px;" height="23"/> 
     </div> 

    </h:body> 
</html> 

豆:

@Named 
@RequestScoped 
public class UploadBean 
{ 
    @Inject 
    @Push 
    private PushContext uploadProgress; 

    private static final Logger logger = Logger.getLogger(UploadBean.class.getName()); 
    private Part file; 

    public Part getFile() 
    { 
     return file; 
    } 

    public void setFile(Part file) 
    { 
     this.file = file; 
    } 

    public void upload() 
    { 

     if (file != null) 
     { 

      logger.info("File Details:"); 
      logger.log(Level.INFO, "File name:{0}", file.getName()); 
      logger.log(Level.INFO, "Content type:{0}", file.getContentType()); 
      logger.log(Level.INFO, "Submitted file name:{0}", file.getSubmittedFileName()); 
      logger.log(Level.INFO, "File size:{0}", file.getSize()); 

      try (InputStream inputStream = file.getInputStream(); FileOutputStream outputStream = new FileOutputStream("C:" + File.separator + "jsf_files_test_for_delete" + File.separator + file.getSubmittedFileName())) 
      { 

       long lastTimestamp = System.currentTimeMillis(); 
       int pushInterval = 1000; 
       long totalRead = 0; 
       long size = file.getSize(); 

       int bytesRead = 0; 
       final byte[] chunck = new byte[1024]; 
       while ((bytesRead = inputStream.read(chunck)) != -1) 
       { 
        outputStream.write(chunck, 0, bytesRead); 
        totalRead += bytesRead; 

        if (System.currentTimeMillis() > lastTimestamp + pushInterval) 
        { 
         lastTimestamp = System.currentTimeMillis(); 
         uploadProgress.send(100.0 * totalRead/size); // Make sure this isn't sent more often than once per second. 
        } 
       } 

       FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Upload successfully ended!")); 
      } 
      catch (IOException e) 
      { 
       FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Upload failed!")); 
      } 
     } 
    } 
} 

后我按上传我等待一段时间来上传过程。看起来像是我无法找到的代码存在问题。你能否介绍一下如何解决这个问题?

回答

0

文件上传的工作原理如下:

  1. 客户端发送文件到服务器。
  2. 服务器检索文件并保存在内存或tempdisk中。
  3. JSF bean方法将文件保存/移动到永久位置。

此代码仅计算步骤3的进步,而不是步骤1和2没有与<h:inputFile>不幸没有办法来计算前两个步骤的进行,因为:

  • <h:inputFile>不使用HTML5+XHR file upload,但iframe trick与旧版浏览器向后兼容。没有办法挂钩iframe在JavaScript中提交进度。
  • Servlet 3.0 Part<h:inputFile>使用的API不使用流式处理,而是在JSF支持bean方法被命中之前先保存在内存或临时磁盘中。使用本地Servlet API无法挂接服务器端上载请求解析进度。

所以,在点击JSF方法之前,通过网络从浏览器发送文件到服务器的进度仍然未知。也就是说,当你依赖标准的API。理论上的解决方案是创建一个使用HTML5 + XHR文件上传API的自定义组件。

在JSF backing bean方法中保存上传文件的进度可以用例如基于websocket的推送,但在服务器端保存文件的速度比将文件发送到服务器的速度快得多,但仅显示这部分进度毫无意义。

不幸的是,它就是这样。考虑使用<p:fileUpload>