csdn不能上传附件,相关的代码包附带不上来,悲剧
html导出到pdf和word
导出到pdf
a) 解决问题:1、保留html的样式处理;2、解决中文问题
b) 处理描述:
对应html的处理,利用开源的包,flyingsaucer来进行处理,里面有所依赖的其他包
InputStream input = new ByteArrayInputStream(out.toByteArray());
Document doc = builder.parse(input);
ITextRenderer renderer = new ITextRenderer();
renderer.setDocument(doc, null);
renderer.layout();
renderer.createPDF(os);
这里的input输入流要标准的xhtml,如果传如的html标签会有没有闭合或者属性上面的值没有““标注,需要进行格式化处理,继续利用开源的包jtidy.jar来处理:
Tidy tidy = new Tidy();
tidy.setXmlOut(true);
tidy.setXmlPi(true); // 添加 <?xml?> 标签 为输出的 XML 文件, 这些参数是可选的。
tidy.setXmlSpace(true);
tidy.setInputEncoding("utf-8");
tidy.setOutputEncoding("utf-8");
try {
// 文件转换
tidy.parse(inputStream, outStream);
}catch (Exception e) {
e.printStackTrace();
}
样式的处理问题,如果在处理html标签的时候,没有找到相关的样式,renderer会有异常抛出,我的处理办法是直接将文档中的样式抽取出来,下面是我做的一个样式抽取处理,但是感觉不是很好,当每个控件上都有同样的样式时,就会做很多重复的工作,还有就是这里只抽取了class的样式:
function getStyleNode(htmlobj)
{
var link = document.getElementsByTagName("link");
var style = document.getElementsByTagName("style");
var htmlStr = [];
htmlStr.push("<style>")
getNodeStyles(link,htmlobj,htmlStr);
htmlStr.push("</style>")
return htmlStr.join(“”);
}
获取节点样式
getNodeStyles=function(link_files,htmlobj,returnArray)
{
var className = htmlobj.className;
if(!Ext.isEmpty(className))
{
var classNames = className.split(//s/);
for(var c = 0 ; c < classNames.length ; c++)
{
var cls = "."+classNames[c].trim();
if(cls.indexOf("selected")>=0)
continue;
returnArray.push(cls+"{")
returnArray.push(dframe.getStyleValue(link_files,cls));
returnArray.push("}");
}
}
var chidlNodes = htmlobj.childNodes;
for(var i = 0 ; i < chidlNodes.length ; i++)
{
getNodeStyles(link_files,chidlNodes[i],returnArray);
}
}
获取样式值
getStyleValue=function(link_files,labname)
{
var tar;
var rss;
var style;
var value ="";
tar = link_files;
var queryFlag = false;
for(var f = 0; f < link_files.length ; f++)
{
rss = tar[f].styleSheet.cssRules?tar[f].styleSheet.cssRules:tar[f].styleSheet.rules
for(var i=0;i<rss.length;i++)
{
style = rss[i];
if(style.selectorText.toLowerCase() == labname.toLowerCase())
{
value = style;
queryFlag== true;
break;
}
}
if(queryFlag)
break;
}
if(value != "")
return value.style.cssText;
return value;
}
最后的重头戏,解决中文问题:
处理办法一、
flyingsaucer的帮助文档中的解说是在setDocument()之前来执行下面的代码,这样来处理UTF-8的编码问题:
import com.lowagie.text.pdf.BaseFont;
ITextRenderer renderer = new ITextRenderer();
FontResolver resolver = renderer.getFontResolver();
resolver.addFont (
"C://WINNT//Fonts//ARIALUNI.TTF",
BaseFont.IDENTITY_H,
BaseFont.NOT_EMBEDDED
);
这个不知道在其他人的机器上能不能解决中文问题,我电脑上的jdk的没有执行成功;
处理办法二、
这里需要另一个itext中文字体的包:iTextAsian.jar,可以打开看看,里面就是一些字体。
修改flyingsaucer中的源码:
找ITextFontOutputDevice中的
cb.setFontAndSize(_font.getFontDescription().getFont(), _font.getSize2D() / _dotsPerPoint);
修改成:
try {
cb.setFontAndSize(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",
BaseFont.NOT_EMBEDDED), _font.getSize2D()/_dotsPerPoint);
} catch (Exception e) {
e.printStackTrace();
}
ok,重新编译,测试,中文正常显示。
遗留问题:
导出的文字不能自动换行,希望有深入研究的人相互交流。
利用poi导出word,这里不用做太多的处理,因为word就有打开html页面的功能,把输入的流出入即可:
ByteArrayInputStream bais = new ByteArrayInputStream(b);
POIFSFileSystem poifs = new POIFSFileSystem();
DirectoryEntry directory = poifs.getRoot();
directory.createDocument("WordDocument", bais);
poifs.writeFilesystem(os);
bais.close();