我在Spring上下文中有简单的Velocity配置(根据官方Spring documentation)并且正常工作。如何使用Apache FOP配置/集成它并生成pdf文档?我会很感激一些例子。
<!-- velocity -->
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/WEB-INF/velocity/"/>
</bean>
<bean id="velocityViewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value=""/>
<property name="suffix" value=".vm"/>
</bean>
测试控制器:
@Controller
@RequestMapping("/doc")
public class DocumentController {
@RequestMapping("/test")
public ModelAndView velocityTest() {
List<String> xmens = new ArrayList<String>();
xmens.add("Professor X");
xmens.add("Cyclops");
xmens.add("Iceman");
xmens.add("Archangel");
xmens.add("Beast");
xmens.add("Phoenix");
Map<String, List<String>> model = new HashMap<String, List<String>>();
model.put("xmens", xmens);
return new ModelAndView("testdoc", model);
}
}
/WEB-INF/velocity/test.vm
<html>
<body>
<ul>
#foreach ($xmen in $xmens)
<li>$xmen</li>
#end
</ul>
</body>
</html>
答案 0 :(得分:6)
我是这样做的,但我认为这肯定是一个更优雅的解决方案(testpdf.vm
和testpdf.xsl
位于/WEB-INF/velocity
)。
@Controller
@RequestMapping("/doc")
public class DocumentController {
@Autowired
private PdfReportService pdfReportService;
@RequestMapping("/pdf")
public void testPdf(HttpServletResponse response) throws IOException {
Map<String, Object> model = new HashMap<String,Object>();
model.put("message", "Hello World!");
pdfReportService.generatePdf("testpdf", model, response.getOutputStream());
}
}
PdfReportService:
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.apache.log4j.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.view.velocity.VelocityConfigurer;
@Service("pdfReportService")
public class PdfReportService {
private final Logger log = Logger.getLogger(getClass());
@Autowired
private VelocityConfigurer velocityConfig;
@Autowired
private ServletContext servletContext;
public void generatePdf(String templateName, Map<String,Object>model, OutputStream out) {
// get an engine
final VelocityEngine engine = velocityConfig.getVelocityEngine();
// get the Template
Template template = engine.getTemplate(templateName+".vm");
// create a context and add data
VelocityContext context = new VelocityContext();
context.put("model", model);
// render the template into a StringWriter
StringWriter writer = new StringWriter();
template.merge(context, writer);
FopFactory fopFactory = FopFactory.newInstance();
try {
//Setup FOP
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);
//Setup Transformer
InputStream xstlIn = servletContext.getResourceAsStream("/WEB-INF/velocity/"+templateName+".xsl");
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer(new StreamSource(xstlIn));
//Make sure the XSL transformation's result is piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
//Setup input
byte[] bytes = writer.toString().getBytes("UTF-8");
Source src = new StreamSource(new ByteArrayInputStream(bytes));
//Start XSLT transformation and FOP processing
transformer.transform(src, res);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
答案 1 :(得分:2)
我完全像marioosh那样做了。后来我们在一个大型Web应用程序中遇到了问题(OutOfMemory ecxeptions)当我们有很多用户同时进行PDF对话时,因为VelocityEngine和Apache FOP都需要一些(很多)内存以及当你有很多并发用户时这总结了。
我们改变了流媒体的方法。 Velocity现在将XSL-FO流式传输到Apache FOP。 FOP将结果流式传输到客户端。我们使用PipedReader / PipedWriter完成了此操作。请注意,此解决方案需要额外的线程。我不能像我们为我们的客户那样分享这些代码。
与此同时,我找到了一个现有的网络流媒体解决方案,请参阅http://www.ibstaff.net/fmartinez/?p=15
但请注意,此解决方案通过new Thread(worker).start();
创建了一个额外的线程
在应用程序服务器中,您应该使用WorkManager代替。另请参阅http://www.devx.com/java/Article/28815/1954