我尝试做基于HTML模板生成pdf文件的简单servlet。我尝试使用Thymeleaf和FlyingSaucer,就像在example一样
在我的template.html中我有样式声明如下:
<link rel="stylesheet" type="text/css" media="all" href="style.css"/>
它永远不会被装载。没有错误,没有,只是导致.pdf缺少样式。如果我将样式文件的内容放入模板.HTML就像魅力一样。
如果我把这样的东西:
<link rel="stylesheet" type="text/css" media="all" href="http://localhost:8080/MY_APP/resources/style.css"/>
有用。
我所有的资源都在src/main/webapp/resources
下。
经过几个小时的研究问题,这就是我最终的结果。
对于CSS - 我发现的解决方案只是将CSS放在HTML模板中。不优雅,但做的工作(至少现在)。这不是一个大问题,因为我使用这些模板生成pdf文件。
但同样的问题是图像文件,但我能够以优雅的方式解决这个问题。就这个!
问题是在Web容器中Java无法找到.html模板中指向的文件。所以我不得不编写扩展ReplacedElementFactory的自定义Element Factory。这是代码:
public class B64ImgReplacedElementFactory implements ReplacedElementFactory {
public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box, UserAgentCallback uac, int cssWidth, int cssHeight) {
Element e = box.getElement();
if (e == null) {
return null;
}
String nodeName = e.getNodeName();
if (nodeName.equals("img")) {
String attribute = e.getAttribute("src");
FSImage fsImage;
try {
fsImage = buildImage(attribute);
} catch (BadElementException e1) {
fsImage = null;
} catch (IOException e1) {
fsImage = null;
}
if (fsImage != null) {
if (cssWidth != -1 || cssHeight != -1) {
fsImage.scale(cssWidth, cssHeight);
}
return new ITextImageElement(fsImage);
}
}
return null;
}
protected FSImage buildImage(String srcAttr) throws IOException, BadElementException {
URL res = getClass().getClassLoader().getResource(srcAttr);
if (res != null) {
return new ITextFSImage(Image.getInstance(res));
} else {
return null;
}
}
public void remove(Element e) {
}
public void reset() {
}
@Override
public void setFormSubmissionListener(FormSubmissionListener listener) {
}
}
和生成PDF文件的代码中的用例:
ITextRenderer renderer = new ITextRenderer();
SharedContext sharedContext = renderer.getSharedContext();
sharedContext.setReplacedElementFactory(new B64ImgReplacedElementFactory());
自定义元素替换捕获所有'img'节点,并使用ClasLoader获取资源路径,并根据返回的FSImage,这就是我们需要的。
希望有所帮助!