I have a Spring MVC web application that uses freemarker as the template language. I am currently working on the changes to flush the html head section rather than buffering the whole html and flushing at the end. I tried setting the auto_flush freemarker setting to false and used freemarker's builtin <#flush> directive as below, but that doesn't seem to work.
common-header.ftl
<head>
.......
</head>
<#flush>
page.ftl
<#include "common-header.ftl" />
<body>
.......
</body>
I would appreciate your help with this. Also, per the API documentation, autoFlush() seems to only work for pages which aren't composed with #include statements and require multiple Template.process() methods. If that's correct, should i write a custom template processor to handle the head and body sections in my page ? Any pointers would be helpful.
Update:
Tried using FreeMarkerView.java as the view class as it uses the default writer (PrinterWriter) of HttpServletResponse to process the writer. This doesn't work either though PrinterWriter does support flush() and the <#flush> freemarker directive in my template doesn't seem to be invoking this.
Tried extending the FreeMarkerView class to wrap the PrinterWriter inside a BufferedWriter, and that doesn't work as well.
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="suffix"><value>.ftl</value></property>
<property name="contentType"><value>text/html; charset=utf-8</value></property>
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>
<property name="exposeSpringMacroHelpers"><value>true</value></property>
</bean>
I would appreciate any help with this.
<#flush>
simply calls Writer.flush()
on the Writer
that was given to Template.process
. If, for example, that Writer
is a StringWriter
, the flush()
call will not do nothing of course. The thing that passes the Writer
to FreeMarker will have to ensure that that Writer
does the right thing when its flush()
method is called.
auto_flush
is unrelated to your problem. (But you misunderstand the API docs. auto_flush
is always supported. The docs describe the case when you want to set it to false
.)
Not an answer to the original question but to @soontobeared comment. I was never notified about your comment so sorry for the late response.
I'm using a buffered view during development so I can catch various exception and output debug etc.. This will give access to the Writer. I'm using Spring 3.2 and FreeMarker 2.3.
BufferedFreeMarkerView.java
package com.example.web;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Set;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.view.freemarker.FreeMarkerView;
import freemarker.core.InvalidReferenceException;
import freemarker.template.SimpleHash;
import freemarker.template.Template;
import freemarker.template.TemplateException;
public class BufferedFreeMarkerView extends FreeMarkerView {
@Override
protected void processTemplate(Template template, SimpleHash model,
HttpServletResponse response) throws IOException, TemplateException {
StringWriter buffer = new StringWriter(50000);
try {
template.process(model, buffer);
} catch (TemplateException e) {
logger.warn(e.getMessage() + "\n" + e.getFTLInstructionStack(), e);
throw new RuntimeException(e.getMessage() + "\n"
+ e.getFTLInstructionStack(), e);
} // ommited more catches
try (Writer out = response.getWriter()) {
out.write(buffer.toString());
}
}
}
BufferedFreeMarkerViewResolver.java
package com.example.web;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
public class BufferedFreeMarkerViewResolver extends FreeMarkerViewResolver {
/**
*
*/
public BufferedFreeMarkerViewResolver() {
setViewClass(requiredViewClass());
}
@SuppressWarnings("rawtypes")
@Override
protected Class requiredViewClass() {
return BufferedFreeMarkerView.class;
}
}
From spring dispatcher context
<bean id="viewResolver" class="com.example.web.BufferedFreeMarkerViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value=""/>
<property name="suffix" value=".ftl"/>
<property name="allowSessionOverride" value="true"/>
<property name="exposeSpringMacroHelpers" value="true"/>
<property name="exposeRequestAttributes" value="true"/>
<property name="exposeSessionAttributes" value="true"/>
<property name="requestContextAttribute" value="rc"/>
</bean>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With