报表中呈现金蝶K3存放于数据库中经加密过的大文本内容
需求: 公司多年来使用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,这几个必须保持一致,否则调用会失败。1139002、将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.javapackage 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);
}
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()+"");//对文本进行分段
}
return buffer.toString().trim();
}
return null;
}
}将生成的class放入项目下的classes\com\fr\function文件夹中,在通过设计器的函数管理器中添加相应的函数。113902涂颜色的地方都是直接读取数据库中加密IMAGE文件后,使用getK3ZipRTF($$$)进行数据转换,然后使用HTML方式查看内容。实际显示效果:113904
不足:报表已正常运行了几周,但因为使用32位JDK,内存上面的先天限制,造成报表性能较低,后续正在查找64位的DLL来代替,或者可以用什么方法可以使用64位去封装32位的DLL,现在还没有头绪,也顺请大神能提供方法,感谢!
编辑于 2018-8-15 14:16