4

我为每个模块(项目、产品……)使用相同的代码来导出 PDF。所有地方都工作正常,但在一个地方,PDF文件创建和下载成功,但在控制台中它给出了这样的错误。

getOutputStream() has already been called for this response. Stacktrace follows:
java.lang.IllegalStateException: getOutputStream() has already been called for this response
    at net.bull.javamelody.FilterServletResponseWrapper.getWriter(FilterServletResponseWrapper.java:121)
    at grails.converters.JSON.value(JSON.java:199)
    at grails.converters.JSON.render(JSON.java:134)
    at grails.converters.JSON.render(JSON.java:150)
    at com.****.***.RoomController$_closure2.doCall(RoomController.groovy:78)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:233)
    at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:197)
    at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:171)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:722)
2013-05-06 17:38:54,381 ERROR [http-bio-8080-exec-5] GrailsExceptionResolver                            IllegalStateException occurred when processing request: [GET] /****/room/listByCompanyJSON - parameters:
extension: pdf
format: pdf

代码:

package com.company.pro

import grails.converters.JSON
import grails.plugins.springsecurity.Secured

import java.sql.Timestamp

import com.company.pro.constants.CommonSearchParams
import com.company.pro.constants.TicketType
import com.company.pro.decorator.JQGridDecorator
import com.company.pro.search.RoomSearch


class RoomController extends BaseController
{
    def debugOn = log.isDebugEnabled()

    static defaultAction = "list"

    def userService
    def inventoryJMSService
    def filterUtilService
    def accountJMSService
    def ticketingJMSService
    def minutesUntilStale =  5 //TODO: make this configurable?
    def millisUntilStale = minutesUntilStale * 60 * 1000

    def proExportService


    @Secured(['ROLE_TelePresenceReportUser'])
    def list(){
        def colNames="'${g.message( code:'common.status' )}','${g.message( code:'rooms.label' )}','${g.message( code:'user.details.site' )}','${g.message( code:'device.city' )}','${g.message( code:'common.stateProvince' )}','${g.message( code:'common.country' )}'"
        def colModel="{name:'status', editable: false, fixed: true, width:'60px'},{name:'room', editable: false, fixed: false, width:'200px'},{name:'siteName', editable: false, fixed: false, width:'350px'},{name:'city', editable: false, fixed:true, width:'125px'},{name:'state', editable: false, fixed: true, width:'150px'},{name:'country', editable: false, fixed: true, width:'150px'}"

        [colNames:colNames, colModel:colModel]
    }

    @Secured(['ROLE_TelePresenceReportUser'])
    def listJSON = {
        chain(action: 'listByCompanyJSON', params: params)
    }

    @Secured(['ROLE_TelePresenceReportUser'])
    def listByCompanyJSON = {
        params.companyId= filterUtilService.getCurrentCustomer()?.id
        params.monitoringStatus = CommonSearchParams.MONITORING

        if(params.format!=null && params.format != "html"){
                downloadList(session, params)

        }
        session.setAttribute("lastSearchParams", params)

        def findRoomsResponse = inventoryJMSService.findRooms(params)
        def search = new RoomSearch()
        search.params = params
        search.doSearch()
        session.setAttribute("lastRoomsSearch", search.data?.collect {it.room})
        def decorator = new JQGridDecorator(search)

        def data = decorator.asRoomsListGrid()

        def up = message(code:"status.up")
        def down = message(code:"status.down")
        data.rows.each {row -> row.cell[0] = row.cell[0] ? up : down }

        render data as JSON
    }

    private downloadList(javax.servlet.http.HttpSession session, Map params) {
        String cname = filterUtilService.getCurrentCustomer()?.name
        cname = cname.replaceAll(" ","_")
        def arrRooms =session.getAttribute("lastRoomsSearch")
        def deviceArray = getAllDevices().findAll { device -> arrRooms.find({currRoom ->  device.room == currRoom})}
        def siteMap = getSiteMap(deviceArray)

        deviceArray.each( {
            it.siteName = it.siteName?.split(":")[1];
        })
        //populate device array with site map
        deviceArray.each( {
            it.metaClass.city =  siteMap[it.siteId]?.city
            it.metaClass.state =  siteMap[it.siteId]?.state
            it.metaClass.country =  siteMap[it.siteId]?.country
            it.metaClass.countryAbbrev =  siteMap[it.siteId]?.countryAbbrev
            it.metaClass.companyId =  siteMap[it.siteId]?.companyId
            it.metaClass.companyName =  siteMap[it.siteId]?.companyName

        })

        def idList = deviceArray.collect({ it.deviceId})
        def arrId = idList.toArray(new String[0])
        //get url information for all device id's and populate that in deviceArray
        params.deviceIds =arrId
        params.populateSoldServices = false
        def respo2  = inventoryJMSService.findDevicesByKeys(params)
        def deviceByKeysSO = respo2.getDevices()
        deviceArray.each({
            def parentRec = it
            def record = deviceByKeysSO.find {parentRec.deviceId == it.deviceHeaderMgmtSysSO.deviceId}
            it.metaClass.deviceURL = record.deviceURL
            it.metaClass.region = record.region
            it.metaClass.floor = record.floor
        })

        List fields = ["city","state","companyId","companyName","countryAbbrev","country",
            "productCategorization.tier1","productCategorization.tier2","productCategorization.tier3",
            "deviceId", "deviceName","siteId", "siteName",
            "mgmtSysAddIPSO.description","mgmtSysAddIPSO.ipAddress",
            "mgmtSysAddIPSO.deviceExternalSysRefKey","mgmtSysAddIPSO.ipAddressTypeId",
            "deviceURL",
            "productCategorization.manufacturer","productCategorization.productModelVersion",
            "region","floor","room"
        ]



        Map labels =    ["city" : message(code:"device.city"),
            "state" : message(code:"common.stateProvince"),
            "companyId" : message(code:"reports.telepresence.cdr.columns.COMPANYID"),
            "companyName": message(code:"reports.telepresence.cdr.columns.COMPANYNAME"),
            "countryAbbrev" : message(code:"common.country.abbrev"),
            "country":message(code:"common.country"),
            "deviceId": message(code:"device.label.id"),
            "deviceName": message(code:"device.label.name"),
            "siteId": message(code:"common.siteId"),
            "siteName": message(code:"site.name"),
            "deviceURL" : message(code:"device.url"),
            "productCategorization.manufacturer": message(code:"device.detail.manufacturer"),
            "productCategorization.productModelVersion": message(code:"device.detail.model.version"),
            "region": message(code:"site.region"),
            "floor":message(code:"site.floor"),
            "room": message(code:"site.room")]

        Map parameters
        def title =  message(code:"rooms.label.plural") + "             " + message(code:"common.downloadDateTime") + " "+new Date()
            if(params.extension == TicketType.EXPORT_EXCEL){
             parameters = [title: title, "column.widths": [0.1, 0.2, 0.1, 0.2, 0.2, 0.3, 0.3, 0.2, 0.3, 0.3, 0.3,0.3,0.3,0.3,0.3,0.3,0.3, 0.2, 0.2, 0.2,0.2,0.2]]
             labels <<    ["productCategorization.tier1": message(code:"device.product.categorization.tier1"),
                           "productCategorization.tier2": message(code:"device.product.categorization.tier2"),
                           "productCategorization.tier3": message(code:"device.product.categorization.tier3"),
                           "mgmtSysAddIPSO.description": message(code:"device.mgmt.system"),
                           "mgmtSysAddIPSO.ipAddress": message(code:"device.mgmt.system.address"),
                           "mgmtSysAddIPSO.deviceExternalSysRefKey": message(code:"device.mgmt.system.refc"),
                           "mgmtSysAddIPSO.ipAddressTypeId": message(code:"device.mgmt.system.ipAddress.typid")]

             } else{
              parameters = [title: title]
              labels <<    ["productCategorization.tier1": message(code:"device.product.categorization.pc.tier1"),
                           "productCategorization.tier2": message(code:"device.product.categorization.pc.tier2"),
                           "productCategorization.tier3": message(code:"device.product.categorization.pc.tier3"),
                           "mgmtSysAddIPSO.description": message(code:"device.mgmt.sys"),
                           "mgmtSysAddIPSO.ipAddress": message(code:"device.mgmt.sys.address"),
                           "mgmtSysAddIPSO.deviceExternalSysRefKey": message(code:"device.mgmt.sys.refc"),
                           "mgmtSysAddIPSO.ipAddressTypeId": message(code:"device.mgmt.sys.ipAddress.typid")]
            }
             downloadDataToFiles(params.format, params.extension, "Room_List_" + cname,deviceArray, fields, labels, null, parameters)
        return
    }

    /**
     * This behavior has been moved to the JQGridDecorator object.
     * Must remove this later, when there is time to test thoroughly
     */
    private formatPanelResults={ findRoomsResponse ->
        session.setAttribute("lastRoomsSearch", findRoomsResponse?.collect {it.room})
        def allRows = findRoomsResponse?.collect {
            [
                    cell: [
                        it.status,
                        it.room,
                        it.siteName,
                        it.city,
                        it.state,
                        it.country
                        ],
                    id : it.room
            ]

        }.unique()

        def totalRows = allRows.size()
        def maxRows = Integer.valueOf(params.rows?:1)
        def currentPage = Integer.valueOf(params.page?:1)
        def numberOfPages = Math.ceil(totalRows / maxRows).toInteger()
        def rowOffset = ((currentPage - 1) * maxRows)

        def maxIndex = rowOffset + maxRows
        if (maxIndex > totalRows ) { maxIndex = totalRows }

        [rows:allRows, records: totalRows, page: currentPage, total:numberOfPages]

    }
    @Secured(['ROLE_TelePresenceReportUser'])
    def listDevicesByRoomJSON() {
        if (params.room == null) {render ''}

        def devicesForRoom = getRoomDeviceList().findAll { it.room == params.room }

        if (debugOn) log.debug('devicesForRoom: ' + devicesForRoom)

        def totalRows = devicesForRoom.size()
        def maxRows = Integer.valueOf(params.rows?:1)
        def currentPage = Integer.valueOf(params.page?:1)
        def numberOfPages = Math.ceil(totalRows / maxRows).toInteger()
        def rowOffset = ((currentPage - 1) * maxRows)

        def maxIndex = rowOffset + maxRows
        if (maxIndex > totalRows ) {maxIndex = totalRows}
        if (debugOn) log.debug ("totalRows: $totalRows, maxRows: $maxRows, currentPage: $currentPage, numberOfPages: $numberOfPages, rowOffset: $rowOffset, maxIndex: $maxIndex")
        def roleArr = session.getAttribute("roles")
        def svcRole = roleArr.findAll{ it.name.equalsIgnoreCase('RequestServiceUser')}
        def validRoleExists = false
        if(svcRole.size == 1)
            validRoleExists = true

        def rows = devicesForRoom[rowOffset ..< maxIndex].collect() {
            [
                cell: [
                    it.deviceId,
                    it.deviceName,
                    it.status?'Up':'Down',
                    "<a href=" + createLink(controller:'requestService', action:'create',absolute:true, params:[thisDevice:it.deviceId, requestType:14, showDevSel:false]) + ">" + message(code:'default.button.create.label') + "</href>"
                ],
                id:it.deviceId
            ]
        }

        def jsonData = [rows:rows, records: totalRows, page: currentPage, total:numberOfPages,showSvcReq:validRoleExists]
        render jsonData as JSON
    }

    private uniqueRoomData() {
        def deviceList = getRoomDeviceList()
        def downRooms = deviceList.findAll { !it.status }.collect { it.room }
        if (debugOn) log.debug("downRooms: $downRooms")

        /* Added the below code for Download functionality */

            //for the room list, we do not want device data
            def temp = deviceList?.collect {
                [
                    'status' : downRooms.contains(it.room) ? 'Down' : 'Up' ,
                    'room' : it.room,
                    'siteName' : it.siteName,
                    'city' : it.city,
                    'state' : it.state,
                    'country' : it.country
                ]
            }

            temp = sortList(temp)

            //if more than one device in a room, there will be duplicate data. Remove it.
            def rows = temp.unique().collect {
                [
                    cell: [
                        it.status,
                        it.room,
                        it.siteName,
                        it.city,
                        it.state,
                        it.country
                        ],
                    id : it.room
                ]

            }

    }
    private sortList(list) {
        def asc = params['sord']=='asc'
        def idx = params['sidx']
        if (asc) {
            return list.sort { a, b ->
                a[idx].compareToIgnoreCase(b[idx])
            }
        }
        else {
            return list.sort { a, b ->
                b[idx].compareToIgnoreCase(a[idx])
            }
        }
    }

    private getRoomDeviceList() {
        def roomDeviceList = session.getAttribute("roomDeviceList")
        def roomDeviceListCreated = session.getAttribute("roomDeviceListCreated")
        def refreshNeeded = false
        //check for null or stale list
        if (roomDeviceList != null && roomDeviceListCreated != null) {
            def now = new Timestamp(System.currentTimeMillis())
            refreshNeeded = (now - roomDeviceListCreated > millisUntilStale)
        }
        else {
            //roomDeviceList or roomDeviceListCreated *is* null, generate new list
            refreshNeeded = true
        }
        if(debugOn) log.debug( "refreshNeeded: " + refreshNeeded)
        if (refreshNeeded) roomDeviceList = populateRoomDeviceListForSession()
        if(debugOn) log.debug('roomDeviceList: ' + roomDeviceList?:"<null>")
        return roomDeviceList
    }

    private populateRoomDeviceListForSession() {
        //def devices = devicesInRooms(getAllDevices())
        def devices = getAllDevices().findAll { it.room }
        def alarmMap = getAlarmMap()
        def siteMap = getSiteMap (devices)

        def results = devices?.collect {            
            [
                room : it.room,
                deviceId : it.deviceId,
                deviceName : it.deviceName,
                siteName : it.siteName == null ? null: it.siteName.substring(it.siteName.indexOf(":")+1), //strip companyId & ':' from site name,
                city : siteMap[it.siteId].city,
                state : siteMap[it.siteId].state,
                country : siteMap[it.siteId].country,
                status:!(alarmMap?.values()?.contains(it.deviceId))
                //status: message(code:alarmMap.values().contains(it.deviceId)?'status.down':'status.up')
            ]       
        }

        session.setAttribute("roomDeviceList", results)
        session.setAttribute("roomDeviceListCreated",new Timestamp(System.currentTimeMillis()))
        return results
    }

    private getAllDevices() {
        //AuthenticatedUser usr = springSecurityService.getPrincipal()
        params.companyId= filterUtilService.getCurrentCustomer()?.id //usr.getCompanyId()
        params.totalDeviceCountNeeded=true
        params.monitoringStatus = CommonSearchParams.MONITORING
        def tempRowParam = params.rows //need to store this value - will restore it later
        params.rows = 9999 //we need all devices to find those with rooms...
        def resp = inventoryJMSService.searchDevices(params)
        params.rows = tempRowParam //restore original value so that pagination will work properly on first call
        log.info("getAllDevices params:$params")
        return resp?.getSearchDevices()

    }

    private getSiteMap(devices) {
        String[] siteIds = (devices*.siteId).unique()
        def siteMap = [:]
        if (!siteIds) {
            return siteMap
        }
        def resp = accountJMSService.findSitesByKeys([siteIds:siteIds])
        resp?.sites?.each {
                    siteMap.put(it.id, [
                        name: it.name == null ? null: it.name.substring(it.name.indexOf(":")+1), //strip companyId & ':' from site name, 
                        city:it.city, 
                        state:it.stateProvince, 
                        //country:it.countryAbbrev,//updated
                        countryAbbrev:it.countryAbbrev,
                        country:it.country,
                        companyId: it.companyId,
                        companyName:it.companyName
                    ]
                )
            }
            if (debugOn) log.debug(siteMap)


        return siteMap

    }

    private getAlarmMap() {
        def tempRowParam = params.rows //need to store this value - will restore it later
        params.rows = 9999
        if (debugOn) log.debug("getAlarmMap params: $params")

        def resp = ticketingJMSService.searchAlapro([companyId:params.companyId, monitoringStatus:CommonSearchParams.MONITORING, ticketState: 'OPEN'])
        def map = [:]
        params.rows = tempRowParam //restore original value so that pagination will work properly on first call
        log.info("getAlarmMap params:$params")
        resp?.alapro?.each {
                map.put(it.id, it.deviceId)
            }
            if (debugOn) log.debug("getAlarmMap map: $map")

        return map
    }

    def listAll = {
        def customer = filterUtilService.getCurrentCustomer()?.id
        def search = new RoomSearch(customer)
        render search.parseDataAsJSON() as JSON
    }

    def lastSearchFullDataset = {
        def params = session.getAttribute("lastSearchParams");
        params.loadonce = true
        def search = new RoomSearch()
        search.params = params
        search.doSearch()

        render search.data as JSON
    }

    def getRoomsByGroup = {

        def rooms = []
            def group = params.group=='Group 1'?'0':'1'
            getAllDevices().collect{
                if(group == it.group){
                    if(it.room !=null && it.room.trim() !="" && it.room.trim().length()>0){
                        rooms.add(it.room)
                    }
                }
            }
        render rooms as JSON
    }
}
4

3 回答 3

3

当您直接渲染事物时,让 grails 知道不要渲染视图。利用:

//outputStream - make sure you close it
OutputStream out
try {
    out = response.getOutputStream()
    out << bytes
} catch (IOException ioe) {
    //gulp - can't send to the browser
} finally {
    try {   
        out?.close()
    } catch (IOException ioe) {
        //gulp - can't close
    }
}
//or render input stream
    render ( file: <InputStream>, contentType: '<content/type>')
//or render byte array
    render ( file: <byte[]>, contentType: '<content/type>')
//or just tell Grails that you don't want the view rendered.
    GrailsWebRequest webRequest = 
             (GrailsWebRequest) RequestContextHolder.currentRequestAttributes()
    webRequest.setRenderView(false)

让我知道它是否适用于任何人。

于 2013-07-31T21:10:42.953 回答
0

看一下这个问题:用户在 Grails 中取消了文件下载,这可能会有所帮助,因为您可能会在第一个请求仍在服务时收到第二个请求并且抛出 ClientAbortException。

于 2013-07-12T12:45:26.077 回答
0

listByCompanyJSON有一个错误:您应该在调用后停止处理请求并做出新的响应downloadList

if(params.format!=null && params.format != "html"){
    downloadList(session, params)
    return // <-- like this
}
于 2013-05-06T15:17:23.097 回答