一旦发出请求,就停止控制器再次执行

时间:2016-03-09 16:35:40

标签: pdf grails

我是grails的新手,所以希望有人耐心地帮助我。我有一个创建PDF的控制器。如果用户在创建PDF之前单击多次,则会出现以下错误。以下是创建PDF的代码。

2016-03-09 09:32:11,549 ERROR errors.GrailsExceptionResolver  - SocketException occurred when processing request: [GET] /wetlands-form/assessment/f3458c91-3435-4714-a0e0-3b24de238671/assessment/pdf
Connection reset by peer: socket write error. Stacktrace follows:
java.net.SocketException: Connection reset by peer: socket write error
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:159)
    at mdt.wetlands.AssessmentController$_closure11$$EPeyAg3t.doCall(AssessmentController.groovy:300)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    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:744)
2016-03-09 09:32:11,549 ERROR errors.GrailsExceptionResolver  - IllegalStateException occurred when processing request: [GET] /wetlands-form/assessment/f3458c91-3435-4714-a0e0-3b24de238671/assessment/pdf
getOutputStream() has already been called for this response. Stacktrace follows:
org.codehaus.groovy.grails.web.pages.exceptions.GroovyPagesException: Error processing GroovyPageView: getOutputStream() has already been called for this response
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    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:744)
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
    at C__MDTDATA_gg_workspace_new_wetlands_grails_app_views_error_gsp.run(error.gsp:1)
    ... 5 more
2016-03-09 09:32:11,549 ERROR [/wetlands-form].[grails]  - Servlet.service() for servlet grails threw exception
java.lang.IllegalStateException: getOutputStream() has already been called for this response

PDF代码通过渲染插件

def pdf = {
        def assessment = lookupAssessment()
        if (!assessment){
            return
        }
        // Trac 219 Jasper report for PDF output

        Map reportParams = [:]

        def report = params.report
        def printType = params.printType
        def mitigationType = params.mitigationType
        def fileName
        def fileType

        fileType = 'PDF'

        def reportDir =
        grailsApplication.mainContext.servletContext.getRealPath(""+File.separatorChar+"reports"+File.separatorChar)
        def resolver = new SimpleFileResolver(new File(reportDir))

        reportParams.put("ASSESS_ID", assessment.id)
        reportParams.put("RUN_DIR", reportDir+File.separatorChar)
        reportParams.put("JRParameter.REPORT_FILE_RESOLVER", resolver)       
        reportParams.put("_format", fileType)
        reportParams.put("_file", "assessment")

        println params

        def reportDef = jasperService.buildReportDefinition(reportParams, request.getLocale(), [])

        def file = jasperService.generateReport(reportDef).toByteArray()



        // Non-inline reports (e.g. PDF)
        if (!reportDef.fileFormat.inline && !reportDef.parameters._inline)
        {
            response.setContentType("APPLICATION/OCTET-STREAM")
            response.setHeader("Content-disposition", "attachment; filename=" + assessment.name + "." + reportDef.fileFormat.extension);
            response.contentType = reportDef.fileFormat.mimeTyp
            response.characterEncoding = "UTF-8"
            response.outputStream << reportDef.contentStream.toByteArray()

        }
        else
        {
            // Inline report (e.g. HTML)
            render(text: reportDef.contentStream, contentType: reportDef.fileFormat.mimeTyp, encoding: reportDef.parameters.encoding ? reportDef.parameters.encoding : 'UTF-8');

        }

    }

这是WORD代码。

def word = {
        def assessment = lookupAssessment()
        if (!assessment){
            return
        }

        // get the assessment's data as xml
        def assessmentXml = g.render(template: 'word', model: [assessment:assessment]).toString()

        // open the Word template
        def loader = new LoadFromZipNG()
        def template = servletContext.getResourceAsStream('/word/template.docx')
        WordprocessingMLPackage wordMLPackage = (WordprocessingMLPackage)loader.get(template)

        // get custom xml piece from Word template
        String itemId = '{44f68b34-ffd4-4d43-b59d-c40f7b0a2880}' // have to pull up part by ID.  Watch out - this may change if you muck with the template!
        CustomXmlDataStoragePart customXmlDataStoragePart = wordMLPackage.getCustomXmlDataStorageParts().get(itemId)
        CustomXmlDataStorage data = customXmlDataStoragePart.getData()

        // and replace it with our assessment's xml
        ByteArrayInputStream bs = new ByteArrayInputStream(assessmentXml.getBytes())
        data.setDocument(bs) // needs java.io.InputStream
        // that's it!  the data is in the Word file
        // but in order to do the highlighting, we have to manipulate the Word doc directly

        // gather the list of cells to highlight
        def highlights = assessment.highlights()

        // get the main document from the Word file as xml
        MainDocumentPart mainDocPart = wordMLPackage.getMainDocumentPart()
        def xml = XmlUtils.marshaltoString(mainDocPart.getJaxbElement(), true)

        // use the standard Groovy tools to handle the xml
        def document = new XmlSlurper(keepWhitespace:true).parseText(xml)

        // for each value in highlight list - find node, shade cell and add bold element
        highlights.findAll{it != null}.each{highlight ->
            def tableCell = document.body.tbl.tr.tc.find{it.sdt.sdtPr.alias.'@w:val' == highlight}
            tableCell.tcPr.shd[0].replaceNode{
                'w:shd'('w:fill': 'D9D9D9') // shade the cell
            }
            def textNodes = tableCell.sdt.sdtContent.p.r.rPr
            textNodes.each{
                it.appendNode{
                    'w:b'()  // bold element
                }
            }
        }

        // here's a good way to print out xml for debugging     
        // System.out.println(new StreamingMarkupBuilder().bindNode(document.body.tbl.tr.tc.find{it.sdt.sdtPr.alias.@'w:val' == '12.1.1'}).toString())

        // or save xml to file for study
        // File testOut = new File("C:/MDTDATA/wetlands-trunk/xmlout.xml")
        // testOut.setText(new StreamingMarkupBuilder().bindNode(document).toString()) 

        // get the updated xml back in the Word doc
        Object obj = XmlUtils.unmarshallFromTemplate(new StreamingMarkupBuilder().bindNode(document).toString(), null);
        mainDocPart.setJaxbElement((Object)obj)

        File file = File.createTempFile('wordexport-', '.docx')
        wordMLPackage.save(file)

        response.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document;')
        response.setHeader('Content-Disposition', "attachment; filename=${assessment.name.encodeAsURL()}.docx")
        response.setHeader('Content-Length', "${file.size()}")

        response.outputStream << file.readBytes()
        response.outputStream.flush()
        file.delete()
    }

    // for checking XML during development
    def word2 = {
        def assessment = lookupAssessment()
        if (!assessment){
            return
        }
        render template: 'word', model: [assessment:assessment]
    }

3 个答案:

答案 0 :(得分:0)

你需要捕捉异常,如果你不想对它做任何事情然后如下所示在捕获没有任何事情...经过尝试后捕获如果仍然没有文件我们知道出了什么问题所以我们这次渲染另一个或相同的视图有错误。在此之后它返回,因此它不会继续检查报告类型的其他位,即pdf或html

..
//declare file (def means it could be any type of object)
def file
//Now when you expect unexpected behaviour capture it with a try/catch
try {
  file = jasperService.generateReport(reportDef).toByteArray()
}catch (Exception e) { 
   //log.warn (e)
   //println "${e} ${e.errors}"
}
//in your scenario or 2nd click the user will hit the catch segment
//and have no file produced that would be in the above try block
//this now says if file == null or if file == ''
// in groovy !file means capture if there nothing defined for file
if (!file) { 
  //render something else
  render 'a message or return to page with error that its in use or something gone wrong'
  //return tells your controller to stop what ever else from this point
  return
}
//so what ever else would occur will not occur since no file was produced
...

现在最后一点注意尝试/捕获是昂贵的,不应该在任何地方使用。如果您期待某些事情,那么处理数据。在通常像第三方api这样的情况下,你无法控制,即意外预期,那么你会回到这些方法

答案 1 :(得分:0)

1-客户端:最好是在第一次单击时禁用按钮并等待来自服务器的响应。

2- Catch Exception并且不执行任何操作或仅打印错误日志。

// get/set parameters     
    def file
     def reportDef 
    try{
       reportDef = jasperService.buildReportDefinition(reportParams, request.getLocale(), [])

       file = jasperService.generateReport(reportDef).toByteArray()
    }catch(Exception e){
      // print log or do nothing
    }


    if (file){
      // render file according to your conditions
    }
    else {
            // render , return appropriate message.
    }

答案 2 :(得分:0)

不是捕获Exception,而是捕获IOException。否则你也会吃掉所有其他的例外情况。以下是我处理它的方式。

     private def streamFile(File file) {
        def outputStream
        try {
            response.contentType = "application/pdf"
            response.setHeader "Content-disposition", "inline; filename=${file.name}"
            outputStream = response.outputStream
            file.withInputStream {
                response.contentLength = it.available()
                outputStream << it
            }
            outputStream.flush()
        } 
        catch (IOException e){
            log.info 'Probably User Cancelled the download!'
        } 
        finally {
            if (outputStream != null){
                try {
                    outputStream.close()
                } catch (IOException e) {
                    log.info 'Exception on close'
                }
            }
        }
    }