itext转PDF,富文本编辑器解决方案

来源:互联网 发布:linux idle process 编辑:程序博客网 时间:2024/06/05 16:44

关于itext转PDF的实现,大家可以看以下地址,如果不涉及富文本,上面的方案是非常棒,而且非常全的。我之前遇到的一些问题,在这个博客上都找到解决办法了。


直通车


上面那篇 博客,也没有实现富文本内容转PDF。他说得不错,富文本对于itext转PDF来说,就是一场灾难。包括我的解决办法,也只是让富文本,在更多的情况下,PDF能下载成功,而且能正常打开,正常显示。


虽然他博客上说了一些要注意的,我还是再备注一下,itext转PDF需要注意的地方:

1.所有标签必须闭合,如<input /> <img /> <br />  (有时候html内容非常非常多,其实很难找到哪里没闭合,这时候要头疼死,没关系,有解决办法的,firefox下载一个叫html validator的插件,配置一下,只看没有闭合的错误,其它的一些如该标签没有什么什么属性这些错误,不用管)

2.页面中不能出现&nbsp;  这是下载不成功的,把所有的 &nbsp; 改成 &#160;

3.如果你页面中,有table代码,你的table记得在style中加一个属性:table-layout:fixed; word-break:break-strict;

4.上面博客中,说是<html>标签上面要加一个dtd,我个人试了下,加跟没加,没区别,反正我没加

5.你的页面中,可以引入css文件,可以写style标签,但一定要记得,<style></style>这个必须是放在head里,不然不能渲染你的样式。

6.你的标签属性,属性值必须以引号包含,如width="50",如不包含,会报错。

7.标签名称,如<td>,不能写成<TD>,大写的,在IE下载时,不兼容,会报错。


好了,只相得到这么多,纯手打,有别的问题,也欢迎沟通交流。


说下富文本吧


上面说的几条,基本上富文本都不会遵守,也就是说,即使你自己写的html没有问题,但富文本编辑器插入的html,还是会这样。

1.富文本不会帮你闭合你的标签,它只管显示正常,如<img /> <br/>,它会是<img >  <br>更有甚者,比如说tinymce,<br中间还会有很多一些它定义的东西。

2.富文本对于空格或者一些空白,会帮你转成&nbsp; 这是灾难的开始

3.用富文本拉出来的table,会帮你加各种样式,加各种宽度高度,即使能下载成功,也不能完全展示(当然,这个问题,一般的编辑器都支持你引入自己的css,我没试过,但应该可以控制)

4.

5.

6.这个问题就很严重了,说的是IE浏览器,它并非所有的属性值都不用引号包含,但有很多属性值都会直接width=50这样,很残忍(fuck ie)(我用的是IE8测的)

7.再说这个问题,也非常扯淡,富文本的内容,在IE上,输入完成,保存,保存时居然被转成大写了。


好吧,扯了这么多,现在说下富文本的解决方案吧。

我用的方案很简单,也很蠢,就是一个个地转,以下是我将html代码转成适合下载的html用到的,完全是发现一个问题,解决一个,也许还不全 ,后面应该还需要做些完善。


/**     * 基本过滤,主要过滤特殊字符与下载时不规则字符,过滤table样式     * @param result     * @return     */    public static String reEscapeHtml(String result) {        String temp = result;      //匹配script整个标签的正则        final String scriptRegx = "(?i)(<SCRIPT)[\\s\\S]*?((</SCRIPT>)|(/>))";        //匹配换行的正则          final String brRegx = "(?i)(</*br.*?>)";        //空格        final String nbspRegx = "(&|&amp;)nbsp;";        //table        final String tableRegx = "(?i)(<table (?!ignore=\"true\").*?>)";        //img        final String imgRegx = "(?i)(<img\\s.*?>)";        temp = temp.replaceAll(scriptRegx, "")                .replaceAll("\r|\n|\\r|\\n|\r\n|\\r\\n|\t|\\t", "")                .replaceAll(imgRegx, "")                .replaceAll(brRegx, "<br />")                .replaceAll(nbspRegx, " ")                .replaceAll(" ", " ")                .replaceAll(tableRegx, "<table class=\"cm_tb\" style=\"width:100%;table-layout:fixed; word-break:break-strict;\">")                ;                return temp;    }          /**     * 标签转小写,转完小写,顺便补全引号     * @param temp     * @return     */    public static String tagToLowerCaseAndComplete(String temp) {        //标签开始的匹配        final String tagRegx = "<[A-Za-z].*?>";        Pattern p = null;        Matcher matcher = null;        p = Pattern.compile(tagRegx);        matcher = p.matcher(temp);        while (matcher.find()) {            String value = matcher.group(0);            if (null == value || "".equals(value))                continue;            String tmpValue = value.toLowerCase();          //自动补全引号,加这里而不加外面            tmpValue = reCompletionQuoat(tmpValue);            //tmpValue = removeWidthAndHeightInTag(tmpValue);            temp = replaceStr(temp, value, tmpValue);                    }        //结束标签的匹配        final String tagEndRegx = "</[A-Za-z]+>";        p = Pattern.compile(tagEndRegx);        matcher = p.matcher(temp);        while (matcher.find()) {            String value = matcher.group(0);            if (null == value || "".equals(value))                continue;            temp = replaceStr(temp, value, value.toLowerCase());        }        return temp;    }        /**     * 自动补全引号(接上一步的标签转小写)     * @param str     * @return     */    public static String reCompletionQuoat(String tag) {        final String tagRegx = "([A-Za-z]+)=([^\"|\']*?)(>|\\s)";        Pattern p = Pattern.compile(tagRegx);        Matcher m = p.matcher(tag);        while (m.find()) {            String tmp = m.group(0);            String key = m.group(1);            if (null == key || "".equals(key.trim()))                continue;            String value = "\"" + m.group(2) + "\"";            String end = m.group(3);            tag = replaceStr(tag, tmp, (key + "=" + value + end));        }        return tag;    }            /**     * width="1024px"|width='1024px'|width:1024px|width:1024px;     * 对于width,上面的example都可以过滤,height与width同样规则     * 对于width="50%"这样的,是不过滤的     * @param tag     * @return     */    public static String removeTableWidthAndHeight(String result) {        String widthAndHeightRegx = "(width|height)(=|:|\\s*?:\\s*?)(\"|\')*\\d+px(\"|\'|;)*";        //String tableRegx = "(?i)(<table (?!ignore=\"true\").*?>.*?</table>)";        return result.replaceAll(widthAndHeightRegx, "");    }        public static String replaceStr(String sourceStr, String targetStr, String insertStr) {        int index = sourceStr.indexOf(targetStr);        if (index == -1)            return sourceStr;        String preStr = sourceStr.substring(0, index);        String afterStr = sourceStr.substring(index + targetStr.length());                return preStr + insertStr + afterStr;    }

上面的removeTableWidthAndHeight这个方法我没有写全,因为后面富文本粘贴,换成了直接粘贴纯文本。这个方法,也只是在粘贴其它地方的富文本,贴到自己的编辑器的时候,会存在问题。


还有没完善的

如:富文本里,如style="width:'50'"这样的问题,还需要正则来做下过滤。


到了这个时候,如果你已经全部照做了,但是格式还是有问题,这个时候怎么办?我这个项目也没解决,但有一个方法是行得通的,就是你已经编辑好内容了,你就验证一下你的html是否能下载。


把下载PDF代码阉割一下,只要在render的时候异常,就说明你格式有问题。(大部分的操作,都是为了兼容IE浏览器)



------------------------分割线----------------------------


这个问题到此为止了。但事实上这不是我想要的解决方案。我相信很多人,包括我自已,都是这么说


replaceStr 上面我写了这个方法,很多人会说,我为什么不直接replaceFirst,原因就是因为我担心一些特殊字符,会被当成正则来匹配,导致匹配出问题,这时候直接限制了你前台的输入。我觉得这里写越多的方法,来解决这个问题,就会暴露越多问题。这不是我想要的,我曾经提过一个解决方案,但是没通过。


这里我说下我想的解决方案。


htmlcleaner这个html分析的jar,相信很多人都用过。我曾经用过一段时间,挺不错的。

htmlcleaner我记得有一个操作,你将一段html转成TagNode的时候,再去把html代码拿出来,这里面大多数标签,都会闭合,都会是一个很完整的标签,是一段比较完美的html代码。因为项目中考虑到第三方jar包的安全问题,我只提了出来,但没有去试过,我隐约记得以前做爬虫,htmlcleaner确实有这方面的操作的,感兴趣的朋友,可以去试一下。

而且,用htmlcleaner处理html元素,我相信,会比用正则处理字符串更好,不容易引发别的问题。有兴趣的朋友,可以试一下。


当然,我这里只是列举一个我用过的处理html的一个jar,你也可以用别的,原理都差不多。

0 0
原创粉丝点击