2011-09-30 5 views
2

現在、Grailsを使用してWebベースのデータロードアプリケーションを作成しています。これは、要するに任意の行のExcelシートを取得し、テスター用のデータ。Grails/Dojoコントローラ/サービスからプログレスバーを取得する

すべてがうまくいきますが、最後に必要なのは、処理したデータの行数をユーザー(特にLARGEデータファイル)に通知する方法です。 200行以上がある場合、アプリはまだそれを見ていてもタイムアウトします(表示されます)。これは、ユーザーがファイルを再読み込みして処理を混乱させる可能性が高いため、問題です。テストデータ行が重複すると、一連の下流の問題が発生します。

私はコードhereで遊んでいます。

<g:actionSubmit action="${appContext}/FileUploader.processFile" value="Upload File" onclick="download()"></g:actionSubmit> 

    <script type="text/javascript"> 
    dojo.require("dijit.ProgressBar"); 
    dojo.require("dojo.parser"); 

    var i = 0; 
    function download() { 
     jsProgress.update({ 
      maximum: 10, 
      progress: ++i 
     }); 
     if (i < 10) { 
      setTimeout(download, 100 + Math.floor(Math.random() * 100)); 
     } 
    } 
</script> 

は、現在、私のコントローラで、私はこれを行う小規模な方法があります:私は把握することができないよう何

def updateStatus = { 
    render uploaderService.rowsLoaded/uploaderService.listToSend.size() 
} 

をリンクにパーセンテージを取得するメソッドを呼び出すための正しい方法でありますプログレスバーに移動します。 (ボイラープレートprogressのコードを置き換えます)

私はJavaを十分に理解していますが、を取得すると、このはちょっと不思議そうです。

私は、技術的にベストプラクティスであるかどうかにかかわらず進歩を遂げるという考えを楽しんでいます...私はこの情報を表示するにはちょっと必要です。それは道場である必要はありません、それは私が最初の成功を収めた方向です。

答えて

1

まず、あなたがバックグラウンドジョブの処理をキックオフし、ユーザー

に処理メッセージを返すようにしたいことがここでjprogressとエグゼキュータのプラグインを使用してこれを行う方法の例です。残念ながら、これはポーリングソリューションを使用します。私は、JMSを使ってアップデートを起動する方法を理解していません。あなたはまた、トピックにメッセージをパブリッシュするCometDプラグインを使用して、あなたのプログレスバーは、そのトピックにサブスクライブする可能性があり

ドメイン

package jprogressdemo 

class Event { 

    String name 
    Integer duration = 100 
    String status = "New" 
    Integer percentComplete = 0 

    static mapping = { 
     cache false 
    } 

    static constraints = { 
     name(size:1..45, unique:true) 
     duration() 
     status(size:1..5) 
     percentComplete() 
    } 
} 

コントローラ

package jprogressdemo 

class EventController { 

    //static allowedMethods = [save: "POST", update: "POST", delete: "POST"] 
    def progressService 
    def jmsService 


    static exposes = ['jms'] 
    static destination = "queue.notification" 


    def executeAction = { 

     println "executeAction" 

     def theEvent = Event.get(params.id) 

     def duration = theEvent?.duration ?: 10 
     def name  = theEvent?.name.trim() ?: "none" 
     def startAt  = theEvent?.percentComplete ?: 0 

     toEvent(name,duration,startAt,true) 

     render "the progress is done" 
    } 

    /* 
    * Start the backgorund task then 
    * while %complete < 100, query db and update progressbar. 
    */ 

    //the progress bar id needs to the same value that's passed into .setProgressBarValue 
    def backgroundAction = { 

     println "backgroundAction" 

     println "isDisabled():${jmsService.isDisabled()}" 

     def theEvent = Event.get(params.id) 

     def duration = theEvent?.duration ?: 10 
     def name  = theEvent?.name ?: "none" 
     def barName  = "${name}b" 
     def percentComplete  = theEvent?.percentComplete ?: 0 
     def lastPct    = -1 

     runAsync { 
      toEvent(name,duration,percentComplete,false) 
     } 

     if (percentComplete > 100) {progressService.setProgressBarValue(barName, 100)} 
     //can't be factored out because it's this function that 
     // gets called from the client ???? 
     while(percentComplete <= 100) { 
      println "percentComplete:${percentComplete}" 
      if (percentComplete != lastPct) { 
       progressService.setProgressBarValue(barName, percentComplete) 
       lastPct = percentComplete 
      } 
      def newEvent = Event.get(params.id) 
      newEvent.refresh() 
      percentComplete = theEvent.percentComplete 
     } 


     render "the progress is done" 
    } 


    //the progress bar id needs to the same value that's passed into .setProgressBarValue 
    def backgroundProgress = { 

     def theEvent = Event.get(params.id) 

     def duration = theEvent?.duration ?: 10 
     def name  = theEvent?.name ?: "none" 
     def barName  = "${name}p" 
     def percentComplete  = theEvent?.percentComplete ?: 0 
     def lastPct    = -1 

     if (percentComplete > 100) {progressService.setProgressBarValue(barName, 100)} 

     while(percentComplete <= 100) { 
      println "percentComplete:${percentComplete}" 
      if (percentComplete != lastPct) { 
       progressService.setProgressBarValue(barName, percentComplete) 
       lastPct = percentComplete 
      } 
      def newEvent = Event.get(params.id) 
      newEvent.refresh() 
      percentComplete = theEvent.percentComplete 
     } 

    } 
    /* 

    % complete needs to get to 101 to avoid infinit loop in polling logic 
    And you can't go from 0-99 because the progress bar doesn't register a 0 

    */ 

    def toEvent(name,duration,startAt,updateBar) { 

     println "duration:${duration}" 
     println "name:${name}" 
     println "startat:${startAt}" 

     for (int i = startAt; i < 102; i++) { 

      println "i:${i}" 

      def theEvent = Event.findByName(name) 
      theEvent.percentComplete = i 
      theEvent.save(flush:true) 
      println "theEvent.percentComplete:${theEvent.percentComplete}" 

      if(updateBar){ 
       progressService.setProgressBarValue(name, i) 
      } else { 
       sendJMSMessage("queue.notification", "${i}") 
      } 

      //let's waste some time 
      for (int a = 0; a < duration; a++) { 

       for (int b = 0; b < 1000; b++) { 

       } 
      } 
     } 
    } 



    def index = { 
     redirect(action: "list", params: params) 
    } 

    def list = { 
     params.max = Math.min(params.max ? params.int('max') : 10, 100) 
     [eventInstanceList: Event.list(params), eventInstanceTotal: Event.count()] 
    } 

    def create = { 
     def eventInstance = new Event() 
     eventInstance.properties = params 
     return [eventInstance: eventInstance] 
    } 

    def save = { 
     def eventInstance = new Event(params) 
     if (eventInstance.save(flush: true)) { 
      flash.message = "${message(code: 'default.created.message', args: [message(code: 'event.label', default: 'Event'), eventInstance.id])}" 
      redirect(action: "show", id: eventInstance.id) 
     } 
     else { 
      render(view: "create", model: [eventInstance: eventInstance]) 
     } 
    } 

    def show = { 
     def eventInstance = Event.get(params.id) 
     if (!eventInstance) { 
      flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'event.label', default: 'Event'), params.id])}" 
      redirect(action: "list") 
     } 
     else { 
      [eventInstance: eventInstance] 
     } 
    } 

    def edit = { 
     def eventInstance = Event.get(params.id) 
     if (!eventInstance) { 
      flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'event.label', default: 'Event'), params.id])}" 
      redirect(action: "list") 
     } 
     else { 
      return [eventInstance: eventInstance] 
     } 
    } 

    def update = { 
     def eventInstance = Event.get(params.id) 
     if (eventInstance) { 
      if (params.version) { 
       def version = params.version.toLong() 
       if (eventInstance.version > version) { 

        eventInstance.errors.rejectValue("version", "default.optimistic.locking.failure", [message(code: 'event.label', default: 'Event')] as Object[], "Another user has updated this Event while you were editing") 
        render(view: "edit", model: [eventInstance: eventInstance]) 
        return 
       } 
      } 
      eventInstance.properties = params 
      if (!eventInstance.hasErrors() && eventInstance.save(flush: true)) { 
       flash.message = "${message(code: 'default.updated.message', args: [message(code: 'event.label', default: 'Event'), eventInstance.id])}" 
       redirect(action: "show", id: eventInstance.id) 
      } 
      else { 
       render(view: "edit", model: [eventInstance: eventInstance]) 
      } 
     } 
     else { 
      flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'event.label', default: 'Event'), params.id])}" 
      redirect(action: "list") 
     } 
    } 

    def delete = { 
     def eventInstance = Event.get(params.id) 
     if (eventInstance) { 
      try { 
       eventInstance.delete(flush: true) 
       flash.message = "${message(code: 'default.deleted.message', args: [message(code: 'event.label', default: 'Event'), params.id])}" 
       redirect(action: "list") 
      } 
      catch (org.springframework.dao.DataIntegrityViolationException e) { 
       flash.message = "${message(code: 'default.not.deleted.message', args: [message(code: 'event.label', default: 'Event'), params.id])}" 
       redirect(action: "show", id: params.id) 
      } 
     } 
     else { 
      flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'event.label', default: 'Event'), params.id])}" 
      redirect(action: "list") 
     } 
    } 
} 

ビュー

<%@ page import="jprogressdemo.Event" %> 
<html> 
    <head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
    <meta name="layout" content="main" /> 
    <g:javascript library="jquery" plugin="jquery"/> 
    <jqui:resources/> 
    <g:set var="entityName" value="${message(code: 'event.label', default: 'Event')}" /> 
    <title><g:message code="default.show.label" args="[entityName]" /></title> 
</head> 
<body> 
    <div class="nav"> 
    <span class="menuButton"><a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a></span> 
    <span class="menuButton"><g:link class="list" action="list"><g:message code="default.list.label" args="[entityName]" /></g:link></span> 
    <span class="menuButton"><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></span> 
    </div> 
    <div class="body"> 
    <h1><g:message code="default.show.label" args="[entityName]" /></h1> 
    <g:if test="${flash.message}"> 
     <div class="message">${flash.message}</div> 
    </g:if> 
    <div class="dialog"> 
     <table> 
     <tbody> 

      <tr class="prop"> 
      <td valign="top" class="name"><g:message code="event.id.label" default="Id" /></td> 

     <td valign="top" class="value">${fieldValue(bean: eventInstance, field: "id")}</td> 

     </tr> 

     <tr class="prop"> 
      <td valign="top" class="name"><g:message code="event.name.label" default="Name" /></td> 

     <td valign="top" class="value">${fieldValue(bean: eventInstance, field: "name")}</td> 

     </tr> 

     <tr class="prop"> 
      <td valign="top" class="name"><g:message code="event.duration.label" default="Duration" /></td> 

     <td valign="top" class="value">${fieldValue(bean: eventInstance, field: "duration")}</td> 

     </tr> 

     <tr class="prop"> 
      <td valign="top" class="name"><g:message code="event.status.label" default="Status" /></td> 

     <td valign="top" class="value">${fieldValue(bean: eventInstance, field: "status")}</td> 

     </tr> 

     <tr class="prop"> 
      <td valign="top" class="name"><g:message code="event.percentComplete.label" default="Percent Complete" /></td> 

     <td valign="top" class="value">${fieldValue(bean: eventInstance, field: "percentComplete")}</td> 

     </tr> 

     </tbody> 
     </table> 
    </div> 
    <div class="buttons"> 
     <g:form> 
     <g:hiddenField name="id" value="${eventInstance?.id}" /> 
     <span class="button"><g:actionSubmit class="edit" action="edit" value="${message(code: 'default.button.edit.label', default: 'Edit')}" /></span> 
     <span class="button"><g:actionSubmit class="delete" action="delete" value="${message(code: 'default.button.delete.label', default: 'Delete')}" onclick="return confirm('${message(code: 'default.button.delete.confirm.message', default: 'Are you sure?')}');" /></span> 
     </g:form> 
    </div> 
    <p> 
    <HR WIDTH="75%" COLOR="#FF0000" SIZE="4"/> 
    <g:form> 
     <g:hiddenField name="id" value="${eventInstance?.id}"/> 
     <g:submitToRemote action="executeAction" name="startButton" value="start...."/> 
     <g:submitToRemote action="backgroundAction" name="backgroundButton" value="background...."/> 
     <g:submitToRemote action="backgroundProgress" name="progressButton" value="progress...."/> 
    </g:form> 

    <g:jprogress progressId="${eventInstance?.name}" trigger="startButton"/> 
    <g:jprogress progressId="${eventInstance?.name}b" trigger="backgroundButton"/> 
    <g:jprogress progressId="${eventInstance?.name}p" trigger="progressButton"/> 

    </div> 
</body> 
</html> 
+0

私は、SSTSに奇妙な依存関係の問題がありましたが、これは必要な結果を得ています。 – avgvstvs

関連する問題