Freemarker 中的管道流问题

发布于 2024-09-16 15:05:27 字数 450 浏览 6 评论 0原文

我需要在 freemarker 中加载和处理模板。我正在使用管道流来读回 freemarker 生成的结果。

示例代码:

PipedInputStream pi = new PipedInputStream();
PipedOutputStream po = new PipedOutputStream(pi);
Writer writer = new OutputStreamWriter(po);
configuration.getTemplate("xx").process(rootMap, writer);

问题是有时它会在 freemarker process 方法中冻结。 没有错误,没有异常,但它没有从 process 方法返回。

如果我将管道流转换为 ByteArray 流,它就可以正常工作。

我是否以正确的方式使用管道流?

I need to load and process a template in freemarker. I am using a piped stream to read back the generated result by freemarker.

Sample code:

PipedInputStream pi = new PipedInputStream();
PipedOutputStream po = new PipedOutputStream(pi);
Writer writer = new OutputStreamWriter(po);
configuration.getTemplate("xx").process(rootMap, writer);

The issue is that sometimes it's freezing inside freemarker procsss method.
No Error, no Exception, but it's not returning back from the process method.

If I convert the piped stream to a ByteArray stream, it works fine.

Am I using piped stream in correct way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

东京女 2024-09-23 15:05:27

不,管道流旨在在两个线程之间传递数据。管道两端之间只有一个小的缓冲区。如果写入管道输出流,则如果缓冲区已满,您的线程将被阻塞,直到另一个线程从相应的管道输入流中读取数据。这不适用于仅一个线程。

来自 Javadoc:

通常,数据是从
PipedInputStream 对象减一
线程和数据被写入
相应的 PipedOutputStream 通过
其他一些线程。

因此,对于小型模板,只需使用 StringWriter,对于大型模板,您可以在由 File.createTempFile() 创建的临时文件上使用 FileWriter

No, piped streams are designed to pass data between two threads. There is only a small buffer between the ends of the pipe. If you write into the piped output stream, your thread will be blocked if the buffer is full until another thread will read from the corresponding piped input stream. This will not work with just one thread.

From the Javadoc:

Typically, data is read from a
PipedInputStream object by one
thread and data is written to the
corresponding PipedOutputStream by
some other thread.

So for small templates just use a StringWriter, for large ones you may use a FileWriter on a temp file created by File.createTempFile().

少女净妖师 2024-09-23 15:05:27

正如 Arne 所写,管道流中的缓冲区空间量相当小。如果您无法使用可以容纳所有数据(无论是在内存中还是在磁盘上)的缓冲区,那么您可以尝试的一件事是看看是否可以在另一个线程中运行模板处理,并使用管道流将结果发送回到你正在执行此操作的主线程。

PipedInputStream pi = new PipedInputStream();
final Writer writer = new OutputStreamWriter(new PipedOutputStream(pi));
Thread worker = new Thread(new Runnable() {
    public void run() {
        configuration.getTemplate("xx").process(rootMap, writer);
    }
});
worker.start();

您可能需要将 final 关键字添加到其他变量中,以使其在实际代码中发挥作用。这取决于变量 configurationgetTemplate 的参数或 rootMap 变量是局部变量还是实例(或类)变量。

(当然,在指定线程的行为时,我可以对 Thread 进行子类化,但我更喜欢实例化一个接口 - 在本例中是 Runnable - 用于此类事情。)

As Arne writes, the amount of buffer space in a piped stream is fairly small. If you can't use a buffer that can hold all of the data (whether in memory or on disk) then one thing you could try is to see if you can run the template processing in another thread with a piped stream sending the results back to the main thread where you're doing this.

PipedInputStream pi = new PipedInputStream();
final Writer writer = new OutputStreamWriter(new PipedOutputStream(pi));
Thread worker = new Thread(new Runnable() {
    public void run() {
        configuration.getTemplate("xx").process(rootMap, writer);
    }
});
worker.start();

You might need to add final keywords to other variables to make this work in your real code. It depends on whether the variable configuration, the argument to getTemplate or the rootMap variable are local variables or instance (or class) variables.

(I could have subclassed Thread when specifying the thread's behavior of course, but I prefer to instantiate an interface – Runnable in this case – for such things.)

愛放△進行李 2024-09-23 15:05:27

这就是我让它发挥作用的方法。

final String uploadReportAsCsv = FreeMarkerTemplateUtils.processTemplateIntoString(
                        fileUploadReportTemplate, modelMap);

message.addAttachment("fileUploadProcessedReport.csv",
    new InputStreamSource() {
        //InputStreamResource from Spring is always returning an open stream,
        // thus we need to create this anonymous class.
        @Override
        public InputStream getInputStream() throws IOException {
            return new StringInputStream(uploadReportAsCsv);
        }
    }
);

This is how I made it work.

final String uploadReportAsCsv = FreeMarkerTemplateUtils.processTemplateIntoString(
                        fileUploadReportTemplate, modelMap);

message.addAttachment("fileUploadProcessedReport.csv",
    new InputStreamSource() {
        //InputStreamResource from Spring is always returning an open stream,
        // thus we need to create this anonymous class.
        @Override
        public InputStream getInputStream() throws IOException {
            return new StringInputStream(uploadReportAsCsv);
        }
    }
);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文