Spring Grails应用程序响应.outputStream<&书信电报;升级到Grails 3.3后失败

Spring Grails应用程序响应.outputStream<&书信电报;升级到Grails 3.3后失败,spring,servlets,grails,tomcat7,Spring,Servlets,Grails,Tomcat7,我有一个最近从2.5升级到3.3的Grails应用程序。总的来说,一切正常,但今天我们遇到了一个似乎是其他人共同面临的问题,但我找不到解决方案 在控制器中,我有一个将字符串附加到response.outputStream的方法 代码现在显示为 response.status = OK.value() response.contentType = 'text/csv;charset=UTF-8' response.setHeader "Content-disposition

我有一个最近从2.5升级到3.3的Grails应用程序。总的来说,一切正常,但今天我们遇到了一个似乎是其他人共同面临的问题,但我找不到解决方案

在控制器中,我有一个将字符串附加到response.outputStream的方法

代码现在显示为

    response.status = OK.value()
    response.contentType = 'text/csv;charset=UTF-8'
    response.setHeader "Content-disposition", "attachment; filename=rcCandidate.csv"
    response.outputStream << converted
    response.outputStream.flush()
    response.outputStream.close()
但在生产服务器上严重失败

$ java -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

$ apt list | grep tomcat
tomcat7/trusty-security,trusty-updates,now 7.0.52-1ubuntu0.13 all [installed]
故障报告从以下内容开始:

org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: javax/servlet/WriteListener
然后是堆栈跟踪,然后是

Caused by: java.lang.NoClassDefFoundError: javax/servlet/WriteListener
然后是关于WriteListener的更多堆栈跟踪和类似消息

我已经看到了替换这一行的建议

provided "org.springframework.boot:spring-boot-starter-tomcat"

但正如这里所指出的

这不是一个好主意,事实上,当我尝试它时,tomcat并没有启动

我相信我在某个地方读到过,用Tomcat8替换Tomcat7可能可以解决这个问题;然而,现在我在服务器上运行Ubuntu 14.04,而Tomcat8在存储库中不提供,所以测试它不是很简单


有人对我有什么建议吗?提前感谢。

您可以通过在方法中添加@CompileStatic来解决此问题,但这并不总是可行的。我们在应用程序中通过添加静态实用程序方法解决了此问题:

@CompileStatic
public static sendResponseData(ServletOutputStream outputStream, String s) { // but this could be byte[] s or InputStream s or whatever you need
    outputStream << s
}

为了方便起见,因为这一个也必须进行静态编译。

Daniel,对于这个非常有用的信息,我非常感谢。为了防止其他人遇到同样的问题,我必须
导入groovy.transform.CompileStatic
javax.servlet.ServletOutputStream
,以实现这一点。我还将这些方法输入为void(也许我还是太过挑剔了?)。非常感谢。我应该补充一点,我在另一个StackExchange post(可能是你的?)之后尝试过类似的方法,但直接将其应用于所讨论的控制器方法,基于所需的斗争量,这似乎不是正确的方法。这是好的,干净的,工作很好。再次感谢!我可能遇到过同一个帖子…我知道我们在这个帖子上工作了一段时间!我很高兴它对您有用,并感谢为其他需要此功能的人提供的附加信息!有没有一种方法可以编写一个集成测试,使它在本地框上失败,然后我们知道方法上的@CompileStatic可以工作
compile "org.springframework.boot:spring-boot-starter-tomcat"
@CompileStatic
public static sendResponseData(ServletOutputStream outputStream, String s) { // but this could be byte[] s or InputStream s or whatever you need
    outputStream << s
}
@CompileStatic
public static flushOutputStream(ServletOutputStream outputStream) {
    outputStream.flush()
}