需求: 公司多年来使用K3 ERP,存在大量二次开发的内容,其中就有一部分是K3中开发的大文本控件内容存入数据库中的情形,现在想在FR中呈现这一内容。看起来需求很简单,但在解决过程中碰到很多坑,本着共享的精神,提供出来,给有类似需求的人一点提示。
思路: 1、K3中存放于数据库中的大文本内容是经过KDZIP.DLL这个32位组件(强调这个32位是因为至今我也没能解决的坑)加密过的,必须要解密方能读取,首先就是解决Java调用dll组件问题。 2、正确解密后会生成一个RTF格式的文本文件,如何正确解析RTF格式成HTML的问题。
3、如果仅需要HTML中的部分内容,如何根据标签提取HTML文本的问题。
解决方法:
1、JAVA调用32位DLL组件网上有很多方法供使用,我采用的是JaCob组件,网上下载jocab 1.18的版本,取得2个文件,这里调用的是32位DLL,因此要使用32位的jacob-1.18-x86.dll,而且必须要使用32位的JDK,这几个必须保持一致,否则调用会失败。 2、将jacob.jar包放到项目的lib目录下,jacob-1.18-x86.dll放到JDK的BIN目录下,拷贝K3中的KDZIP.dll到System32目录下,并通过regsvr32注册。第一步的准备工作就完成了。 2、涉及到HTML处理的问题,无非是使用JEditorPane控件处理。 3、抽取HTML操作,使用了jsoup-1.11.3.jar包
getK3ZipRTF.java - package com.fr.function;
- import java.io.BufferedOutputStream;
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.FileReader;
- import java.io.IOException;
- import java.io.Reader;
- import java.io.StringWriter;
- import java.io.UnsupportedEncodingException;
- import java.io.Writer;
- import com.fr.data.core.db.*;
- import com.fr.script.AbstractFunction;
- import com.fr.stable.ArrayUtils;
- import com.fr.stable.Primitive;
- import com.jacob.activeX.ActiveXComponent;
- import com.jacob.com.ComThread;
- import com.jacob.com.Dispatch;
- import javax.swing.JEditorPane;
- import javax.swing.text.BadLocationException;
- import javax.swing.text.EditorKit;
- import org.jsoup.Jsoup;
- import org.jsoup.nodes.Document;
- import org.jsoup.nodes.Element;
- import org.jsoup.select.Elements;
- public class getK3ZipRTF extends AbstractFunction {
- @Override
- public Object run(Object[] args) {
- // TODO Auto-generated method stub
- if(ArrayUtils.getLength(args)!=1) {
- return Primitive.ERROR_VALUE;
- }
- return getK3Rtf2Html((BinaryObject)args[0]);
- }
- private static boolean readDb(BinaryObject ins) {
- byte[] bt=ins.getBytes();//
- return byte2File(bt,"c:\\","tmp.tmp"); //二进制内容临时保存成一个文件
- }
- /**
- * 调用KDZIP组件中的DeCompress方法进行解密
- * @param sFile 源文件
- * @param tFile 解密后的文件
- * @return 成功返回TRUE
- */
- private static boolean DeCompress(String sFile,String tFile)
- {
- boolean returnV=false;
- ComThread.InitSTA();
- try {
- ActiveXComponent com =new ActiveXComponent("KDZIP.ZIP");
- //ActiveXComponent com =new ActiveXComponent("Word.Application");
- Dispatch disp=(Dispatch) com.getObject();
- Dispatch.call(disp,"DeCompress",sFile,tFile);
- returnV=true;
- }
- catch(Exception e) {
- e.printStackTrace();
- }
- ComThread.Release();
- return returnV;
- }
- /**
- * 将解密后的RTF转换成HTML格式
- * @param ins
- * @return
- */
- private static String getK3Rtf2Html(BinaryObject ins)
- {
- String insNew=null;
- //byte[] nbt=null;
- boolean isok= readDb(ins); // 获得数据库中的IMAGE类型转成文 件
- if(isok) {
- if(DeCompress("c:\\tmp.tmp","c:\\newTemp.RTF")) {
- //将目标文件转成相应文件文件流
- //nbt=file2Byte("c:\\newTemp"+"."+fileType);
- try {
- insNew= rtfToHtml(new FileReader(new File("c:\\newTemp.RTF")));
- } catch (FileNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- //System.out.println(insNew);
- try {
- insNew= new String(insNew.getBytes("Cp1252"), "GB2312");//重要:错误的编码格式转换会造成读取乱码
- insNew=convertText(insNew); //提取HTML中的指定标签中的内容
- } catch (UnsupportedEncodingException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return insNew;
- }
- /**
- * 将字节流转存为文件
- * @param bfile
- * @param fPath
- * @param fName
- * @return
- */
- private static boolean byte2File(byte[] bfile,String fPath,String fName){
- boolean b=false;
- BufferedOutputStream bos=null;
- FileOutputStream fos=null;
- File file=null;
- try {
- File dir=new File(fPath);
- if(!dir.exists()&&!dir.isDirectory()) {
- dir.mkdirs();
- }
- file=new File(fPath+fName);
- fos=new FileOutputStream(file);
- bos=new BufferedOutputStream(fos);
- bos.write(bfile);
- b=true;
- }
- catch(Exception e) {
- e.printStackTrace();
- }
- finally {
- try {
- if(bos!=null) {
- bos.close();
- }
- if(fos!=null) {
- fos.close();
- }
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- return b;
- }
-
- /**
- *
- * @param rtf RTF格式文件
- * @return 返回转换成字符串格式的HTML文本
- * @throws IOException
- */
- private static String rtfToHtml(Reader rtf) throws IOException {
- JEditorPane p = new JEditorPane();
- p.setContentType("text/rtf");
-
- EditorKit kitRtf = p.getEditorKitForContentType("text/rtf");
- try {
- kitRtf.read(rtf, p.getDocument(), 0);
- kitRtf = null;
- EditorKit kitHtml = p.getEditorKitForContentType("text/html");
- Writer writer = new StringWriter();
- kitHtml.write(writer, p.getDocument(), 0, p.getDocument().getLength());
- return writer.toString();
- } catch (BadLocationException e) {
- e.printStackTrace();
- }
- return null;
- }
- /**
- *
- * @param Text HTML格式文件
- * @return 抽取出的格式文本
- */
- private static String convertText(String text) {
- if(text!=null) {
- Document doc=Jsoup.parse(text); //
- Elements links=doc.getElementsByTag("span"); //根据标签取得内容
- StringBuffer buffer=new StringBuffer(); //写入缓冲
- for(Element link:links) {
- buffer.append(link.text().trim()+"<br />");//对文本进行分段
- }
- return buffer.toString().trim();
- }
- return null;
- }
- }
复制代码将生成的class放入项目下的classes\com\fr\function文件夹中,在通过设计器的函数管理器中添加相应的函数。 涂颜色的地方都是直接读取数据库中加密IMAGE文件后,使用getK3ZipRTF($$$)进行数据转换,然后使用HTML方式查看内容。 实际显示效果:
不足:报表已正常运行了几周,但因为使用32位JDK,内存上面的先天限制,造成报表性能较低,后续正在查找64位的DLL来代替,或者可以用什么方法可以使用64位去封装32位的DLL,现在还没有头绪,也顺请大神能提供方法,感谢!
编辑于 2018-8-15 14:16
|