如何在Spring MVC Web应用程序中以速度使用Apache FOP?

问题描述 投票:1回答:2

我在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>
spring-mvc velocity apache-fop
2个回答
6
投票

我是这样做的,但是我认为这肯定是一个更优雅的解决方案(testpdf.vmtestpdf.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);
        }
    }

}

3
投票

我完全像腌鱼一样。后来,当我们有很多用户同时进行PDF对话时,在大型Web应用程序中出现了问题(内存不足),因为VelocityEngine和Apache FOP都需要一些(很多)内存,并且当您有许多并发用户时,总和。

我们更改了流式传输方法。 Velocity现在将XSL-FO流传输到Apache FOP。 FOP将结果流式传输到客户端。我们使用PipedReader / PipedWriter进行了此操作。请注意,此解决方案需要一个额外的线程。我无法像我们为我们的客户所做的那样共享此代码。

同时,我找到了一种现有的网络流解决方案,请参阅archive。但是请注意,此解决方案通过new Thread(worker).start();创建了一个额外的线程在应用程序服务器中,您应该改为使用WorkManager。另请参见http://www.devx.com/java/Article/28815/1954

© www.soinside.com 2019 - 2024. All rights reserved.