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

关于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,你也可以用别的,原理都差不多。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
您可以使用 iTextPDF 库将文本(或其他内容)换为 PDF 文件。iTextPDF 是一个开源的 Java 库,它提供了丰富的 API 用于创建和操作 PDF 文件。 下面是一个简单的示例代码,演示如何使用 iTextPDF 将文本换为 PDF 文件: ```java import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfWriter; import com.itextpdf.layout.Document; import com.itextpdf.layout.element.Paragraph; public class TextToPdfConverter { public static void main(String[] args) { String text = "Hello, world!"; // 要换为 PDF 的文本 try { // 创建一个新的 PDF 文档 PdfDocument pdfDoc = new PdfDocument(new PdfWriter("output.pdf")); // 创建一个新的文档对象,并将 PDF 文档绑定到它上面 Document doc = new Document(pdfDoc); // 向文档添加一个段落 doc.add(new Paragraph(text)); // 关闭文档 doc.close(); System.out.println("PDF 文件已创建成功!"); } catch (Exception e) { e.printStackTrace(); } } } ``` 在上面的示例中,我们创建了一个新的 PDF 文档,并将其绑定到一个新的文档对象上。然后,我们向文档对象添加了一个段落,内容为 "Hello, world!"。最后,我们关闭了文档,将其保存为名为 "output.pdf" 的文件。 请注意,您需要在项目中引入 iTextPDF 库,以便能够编译和运行上述代码。您可以从 iTextPDF 的官方网站(https://itextpdf.com/)下载并获取该库的相关信息。 希望这对您有所帮助!如有任何疑问,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值