pdf - 发出请求后,停止 Controller 再次执行

标签 pdf grails

我不熟悉Grails,所以希望有人耐心并帮我忙。我有一个创建PDF的 Controller 。如果用户在创建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 CODE VIA渲染插件
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]
    }

最佳答案

您需要捕获该异常,如果您不希望对其执行任何操作,则如下所示,在捕获中什么也没有做..在该异常经过尝试并捕获之后,如果仍然没有文件,我们知道出了点问题,因此我们渲染另一个或这次有错误的相同 View 。在此之后,它会返回,因此不会再继续检查报告类型(例如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
...

现在,最后的提示try / catches很昂贵,不应在所有地方使用。如果您期望有什么需要处理的数据。在通常这种第三方api这样的场景中,您无法控制(即做出意想不到的期望),那么您将退回到这些方法

关于pdf - 发出请求后,停止 Controller 再次执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35897356/

相关文章:

node.js - 带有html-pdf的AWS Lambda上的“ERROR Error: write EPIPE”

json - Grails:使用executeQuery呈现JSON

grails - Groovy:参数链接标签

grails - Grails GORM有条件的左外部联接

ruby-on-rails - wicked_pdf : footer height/styling

java - 在 java 应用程序中运行 jar ( pdfbox )

android - 在 Android App 中打开 PDF

javascript - 页面分割在 jsPDF 中不起作用

grails - 如何在 grails 3.3.9 中为禁止的 url 访问显示自定义错误页面

unit-testing - 我为什么还要再次验证