環境介紹:
itext目前已經發展到itext7版本,目前系統裏面使用的itext2版本;
使用spring的freemaker結合itext,完成pdf的導出
需要進行pdf導出的html文件,可能包含下面這幾種情況,導致pdf導出失敗:
- 含有不閉合的html標籤,比如<br>
- html標籤中,含有非法的屬性,比如 v:data="xxx"
- img標籤不是引用的http,而是base64之類的
- 設置了特殊字體的,pdf導出雖然不失敗,但是內容看不到
- img圖片過大的時候,pdf導出會出現截圖的現象
針對上面的幾個問題,解決思路:
1,研究itext代碼,重寫html解析相關的類
2,使用html處理工具,對html文件進行合法性處理(比如:jsoup)
選第二種方案(第一個費時間,沒有太多的精力研究)
結合jsoup,對html文件進行處理,核心代碼:
對html文件進行合法性處理
/**
* 1,html標籤對齊
* 2,檢查所有的img標籤,如果爲base64編碼就去掉該圖片
* 3,過濾所有的html標籤,僅保留styles和class兩個屬性,其他的屬性去掉
* 4,檢查字體設置,如果有字體設置,但是沒有SimSun字體,增加SimSun
* @param bodyHtml
* @return
*/
public static String correctBody(String bodyHtml){
if(bodyHtml==null || "".equals(bodyHtml)) {
return "";
}
//1,html標籤對齊
Document doc = Jsoup.parseBodyFragment(bodyHtml);
//2,檢查所有的img標籤,如果爲base64編碼就去掉該圖片
Elements elements=doc.getElementsByTag("img");
for(Element element : elements) {
String imgSrc=element.attr("src"); //獲取src屬性的值
if(imgSrc.indexOf("data:image")>-1){
element.attr("alt","該圖片不支持導出");
element.attr("src"," ");
}else{
String width = element.attr("width");
int num = getNumber(width);
if(num==Integer.MAX_VALUE){
int realWidth = FileTool.imageWidth(imgSrc);
if(realWidth > 550){
element.attr("width","550");
}
}else if(num > 550){
element.attr("width","550");
}else{
//do nothing
}
}
}
//3,過濾所有的html標籤,僅保留styles和class兩個屬性,其他的屬性去掉
Whitelist wl = Whitelist.relaxed();
for(int i=0;i<htmlTags.length;i++){
wl.addTags(htmlTags[i]);
}
wl.addAttributes("input", "type","value");
wl.addAttributes(":all", "class","styles","style");
//4,檢查字體設置,如果有字體設置,但是沒有SimSun字體設置,增加SimSun
addFontFamliy(doc.getAllElements());
Cleaner cleaner = new Cleaner(wl);
Document clean = cleaner.clean(doc);
String str = clean.body().outerHtml();
return str;
}
關於圖片的處理,從本地環境,獲取圖片的寬度
/**
* 計算width對應的寬度
* 如果沒有寬度設置,設置爲Integer.MAX_VALUE
* 否則就是width對應的寬度
* @param str
* @return
*/
private static int getNumber(String str){
StringBuffer sbuf = new StringBuffer();
int num = Integer.MAX_VALUE;
if(str != null && !"".equals(str)){
for(int i=0;i<str.length();i++){
if(str.charAt(i)>=48 && str.charAt(i)<=57){
sbuf.append(str.charAt(i));
}
}
if(sbuf.length()>0){
num = Integer.valueOf(sbuf.toString());
}
}
return num;
}
最終的處理:
public static String correctHtml(String bodyHtml){
// 1,html標籤對齊
// 2,檢查所有的img標籤,如果爲base64編碼就去掉該圖片
// 3,過濾所有的html標籤,僅保留styles和class兩個屬性,其他的屬性去掉
// 4,檢查字體設置,如果有字體設置,但是沒有SimSun字體,增加SimSun
String str = JsStringUtils.correctBody(bodyHtml);
// 5,填空題
str = str.replaceAll("(<input)([^>]+)(>)", "__________");
// 6,pdf要求嚴格的html
str = str.replaceAll("<br>", "<br/>");
// str = str.replaceAll("(<img)([^>]+)(>)", "$1$2 />");
// str = str.replaceAll("(<input)([^>]+)(>)", "$1$2 />");
// 7,去掉多餘的body
str = str.replaceAll("<body>", "");
str = str.replaceAll("</body>", "");
// System.out.println("-----------------------------------");
// System.out.println(str);
return str;
}