带有 Quartz 作业的 XSL 样式表路径

Posted

技术标签:

【中文标题】带有 Quartz 作业的 XSL 样式表路径【英文标题】:XSL Stylesheet Path with Quartz Job 【发布时间】:2021-07-01 13:23:57 【问题描述】:

我有一个将 XML 数据转换为基于 XSL 的报告的操作,该报告可以在网页上查看。用户调用的单独操作可用于将此报告转换为 PDF 并将其保存到某个位置。

我希望每天使用 Quartz Scheduler 来运行报告并将报告另存为 PDF。我已经确认 Quartz Scheduler 运行成功,但是当它尝试将数据转换为 PDF 报告时失败了。

public byte[] render(Action action, String location) throws Exception 

    // Transform the source XML to System.out.
    ByteArrayOutputStream out = new ByteArrayOutputStream();

    try 

        // configure fopFactory as desired
        FopFactory fopFactory = FopFactory.newInstance();

        // configure foUserAgent as desired
        FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

        // Create a transformer for the stylesheet.
        Templates templates = null;
        Transformer transformer;
        if (location != null) 
            templates = getTemplates(location);
            transformer = templates.newTransformer();
         else 
            transformer = TransformerFactory.newInstance().newTransformer();
        
        transformer.setURIResolver(getURIResolver());
        Object result = action;

        Source xmlSource = getDOMSourceForStack(result);

        // Construct fop with desired output format
        Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
        Result res = new SAXResult(fop.getDefaultHandler());
        transformer.transform(xmlSource, res);
        return out.toByteArray();

     catch (Exception e) 
        throw e;
     finally 
        out.close(); // ...and flush...
    


protected Templates getTemplates(String path) throws TransformerException, IOException 
    
    if (path == null) 
        throw new TransformerException("Stylesheet path is null");
    
    Templates templates = null;
    URL resource = ServletActionContext.getServletContext().getResource(path);

    if (resource == null) 
        throw new TransformerException("Stylesheet " + path + " not found in resources.");
    
    TransformerFactory factory = TransformerFactory.newInstance();
    templates = factory.newTemplates(new StreamSource(resource.openStream()));

    return templates;


protected Source getDOMSourceForStack(Object value)
        throws IllegalAccessException, InstantiationException 
    return new DOMSource(getAdapterFactory().adaptDocument("result", value));


protected AdapterFactory getAdapterFactory() 
    if (adapterFactory == null) 
        adapterFactory = new AdapterFactory();
    
    return adapterFactory;


protected void setAdapterFactory(AdapterFactory adapterFactory) 
    this.adapterFactory = adapterFactory;


protected URIResolver getURIResolver() 
         return new ServletURIResolver(
                 ServletActionContext.getServletContext());
     
 

action 参数是运行要转换的报告的操作,location 参数是格式化报告的 XSL 样式表的位置。此操作在用户调用时起作用,但是当 Quartz 尝试按计划调用它时,它会在

处抛出 NullPointerException 错误
    URL resource = ServletActionContext.getServletContext().getResource(path);

线。有没有办法让 Quartz 使用这个转换操作?

【问题讨论】:

【参考方案1】:

您的代码抛出 NPE,因为它是由 Quartz 在 Struts 操作之外执行的,因此 ServletActionContext.getServletContext() 返回 null。您需要找到一种不同的方式来获取ServletContext。最简单的方法是实现一个ServletContextListener,在调用contextInitialized 方法时将ServletContext 实例保存在私有静态字段中。然后在您的 Quartz 作业代码中,您将使用如下内容:

MyServletContextListener.getServletContext().getResource(path);

getServletContext 是一个静态方法,您需要将其添加到您的ServletContextListener 中,它只会返回保存的ServletContext 实例。

您需要确保在调用 ServletContextListener's contextInitialized 方法后启动 Quartz。最简单的方法是从 contextInitialized 方法启动 Quartz。这确保当 Quartz 执行任何作业时,ServletContext 字段将被初始化,MyServletContextListener.getServletContext() 不会返回 null。

【讨论】:

以上是关于带有 Quartz 作业的 XSL 样式表路径的主要内容,如果未能解决你的问题,请参考以下文章

有没有一种简单的方法来表示 xsl 样式表中的引号?

XSL 转换以输出许多嵌入式 XSL 样式表

预处理 XSL 样式表 - 包括外部文档

xsl 转换在 .net 环境中生成 xsl 样式表

为啥 XSL 样式表显示没有 XML(信息/值)的 html 表

使用 XSL 样式表进行 ADO XML 清理