使用Struts2 + Freemarker生成大文件

时间:2017-02-28 09:28:15

标签: java tomcat struts2 freemarker flush

我需要使用Struts2Freemarker将数据转储为大型xml(50~500 Mb):

<?xml version="1.0" encoding="UTF-8"?>
<documents>
    <#list collection as document>
        <document>
        ...
        </document>
        <#if document_index % 100 == 0> 
           <#flush/>
        </#if>
    </#list>
</document>

由于collection可能很大,它已经实现了一个内部逻辑来获取部分数据,只要有可用的数据就消耗它并再次获取。

问题似乎与XML的缓冲区有关:偶尔应用程序崩溃(java.lang.OutOfMemoryError)。

每100个文档调用一个Freemarker flush,但我不知道是否实际发生了刷新,根据documentation它只是嵌入软件的指示({{1} }} + Strut2)。

有关如何强行冲洗的任何建议吗?

JVM处理大约1~2 Gb的堆内存,可能只是内存问题?

为此目的,可以正确调整Tomcat7吗?

2 个答案:

答案 0 :(得分:1)

在此用例中不需要调用#flush。当缓存Writer(或其背后的OutputStream)以进行性能时,缓冲区的大小限制相当低(十几千字节等),之后它将自动刷新。如果输出由于某些功能原因而被缓冲,例如,为了确保输出可以在任何时候完全回滚,或者输出可以作为单个String返回,那么你应该修复无论如何(那也是#flush可能被忽略的地方)。因此,尝试在freemarker.template.Template.createProcessingEnvironment上设置一个断点并检查调试器中的out Writer参数(以及Writer / OutputStream Writer写入等等)。也许某处会有StringWriter

答案 1 :(得分:1)

我找到了解决方案。

问题在于Struts2 FreemarkerResult以及这个类如何让你处理输出编写器的刷新。

基本上,如果您使用TemplateExceptionHandler.RETHROW_HANDLER作为异常处理程序(就像我一样),则在执行任何刷新之前处理整个模板。 (这是所需的行为,因为如果存在任何模板错误,您希望在将任何输出发送到响应之前抛出并处理更高级别的异常)

但是TemplateExceptionHandlerFreemarkerManager中嵌入的固定配置,无法根据给定请求的需要进行切换。

我决定扩展FreemarkerResult重写方法doExecute(...)以包含一个参数,该参数强制执行单个请求的标准 flushing-during-template-process ,即使全局配置为TemplateExceptionHandler.RETHROW_HANDLER