Ajax Grails/Dojo进度条从控制器/服务获取进度

Ajax Grails/Dojo进度条从控制器/服务获取进度,ajax,grails,dojo,Ajax,Grails,Dojo,目前,我正在使用Grails创建一个基于web的数据加载应用程序,简而言之,它获取任意行的excel工作表,并通过后端系统运行它们,为测试人员准备数据 一切正常,但我最不需要的是某种方法来通知用户(尤其是在大型数据文件上)它处理了多少行数据。如果有超过200行,应用程序将(显示)超时,即使它仍在运行。这是一个问题,因为用户很可能会重新加载文件并扰乱处理。。。重复的测试数据行将导致一系列下游问题 我在玩代码 我似乎不知道调用该方法以获取链接到进度条的百分比的正确方法。(更换样板文件progress

目前,我正在使用Grails创建一个基于web的数据加载应用程序,简而言之,它获取任意行的excel工作表,并通过后端系统运行它们,为测试人员准备数据

一切正常,但我最不需要的是某种方法来通知用户(尤其是在大型数据文件上)它处理了多少行数据。如果有超过200行,应用程序将(显示)超时,即使它仍在运行。这是一个问题,因为用户很可能会重新加载文件并扰乱处理。。。重复的测试数据行将导致一系列下游问题

我在玩代码

我似乎不知道调用该方法以获取链接到进度条的百分比的正确方法。(更换样板文件
progress
code.)

我对Java非常了解,但让它工作起来似乎有点神秘


我愿意接受任何取得进展的想法,无论其技术上是否是最佳实践。。。我已经到了需要一些东西来显示这些信息的地步。它不一定是dojo,它只是我最初最成功的方向

首先,您可能希望启动后台作业中的进程,并将处理消息返回给用户

下面是一个如何使用jprogress和executer插件实现这一点的示例。不幸的是,这使用了轮询解决方案。我还没有弄明白如何使用JMS来触发更新

领域

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")
        }
    }
}
包jprogressdemo
类事件控制器{
//静态allowedMethods=[保存:“发布”,更新:“发布”,删除:“发布”]
def progressService
def jmsService
静态公开=['jms']
static destination=“queue.notification”
def执行={
println“执行”
def theEvent=Event.get(params.id)
def持续时间=事件持续时间:10
def name=theEvent?.name.trim()?:“无”
def startAt=事件完成百分比:0
toEvent(名称、持续时间、起始时间、true)
呈现“进度已完成”
}
/*
*然后启动backgound任务
*当完成百分比<100时,查询数据库并更新progressbar。
*/
//进度条id需要与传递到.setProgressBarValue的值相同
def背景动作={
println“背景行动”
println“isDisabled():${jmsService.isDisabled()}”
def theEvent=Event.get(params.id)
def持续时间=事件持续时间:10
def name=theEvent?.name?:“无”
def barName=“${name}b”
def Percent Complete=theEvent?.Percent Complete?:0
def lastPct=-1
运行异步{
toEvent(名称、持续时间、完成百分比、false)
}
如果(完成百分比>100){progressService.setProgressBarValue(barName,100)}
//不能被分解,因为这个函数
//从客户端被调用????
while(完整版本百分比){
eventInstance.errors.rejectValue(“版本”,“默认值.乐观值.锁定.失败”,“消息(代码:'event.label',默认值:'event')”)作为对象[],“另一个用户在您编辑时更新了此事件”)
渲染(视图:“编辑”,模型:[eventInstance:eventInstance])
返回
}
}
eventInstance.properties=params
如果(!eventInstance.hasErrors()&&eventInstance.save(flush:true)){
flash.message=“${message(代码:'default.updated.message',args:[消息(代码:'event.label',默认值:'event'),eventInstance.id])”
重定向(操作:“显示”,id:eventInstance.id)
}
否则{
渲染(视图:“编辑”,模型:[eventInstance:eventInstance])
}
}
否则{
flash.message=“${message(代码:'default.not.found.message',args:[message(代码:'event.label',默认值:'event'),params.id])”
重定向(操作:“列表”)
}
}
def delete={
def eventInstance=Event.get(params.id)
if(eventInstance){
试一试{
eventInstance.delete(刷新:true)
flash.message=“${message(代码:'default.deleted.message',args:[消息(代码:'event.label',默认值:'event'),params.id])”
重定向(操作:“列表”)
}
catch(org.springframework.dao.DataIntegrityViolationException){
flash.message=“${message(代码:'default.not.deleted.message',args:[message(代码:'event.label',默认值:'event'),params.id])”
重定向(操作:“显示”,id:params.id)
}
}
否则{
flash.message=“${message(代码:'default.not.found.message',args:[message(代码:'event.label',默认值:'event'),params.id])”
重定向(操作:“列表”)
}
}
}
看法


${flash.message}
${fieldValue(bean:eventInstance,字段:“id”)}
${fieldValue(bean:eventInstance,field:“name”)}
${fieldValue(bean:eventInstance,字段:“duration”)}
${fieldValue(bean:eventInstance,字段:“status”)}
${fieldValue(bean:eventInstance,字段:“percentComplete”)}


您还可以使用Comed插件将消息发布到主题
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>