java使用jacob操作word文档

本文深入探讨了使用Java与COM桥接技术(Jacob)操作Word文档的方法,包括准备工作、安装过程、使用示例及常见错误分析。详细介绍了如何利用Jacob访问Word文档的特性,并提供了具体代码实现,旨在帮助开发者高效地完成Office文档操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ava使用jacob操作word文档

java调用com组件操作word使用总结(jacob)


简单描述


   在此处输入简单摘要


特别声明:使用java-com技术可以完成任何VBA可以完成的office文档操作;


 一、准备工作


   先了解一下概念,JACOB 就是 JAVA-COM Bridge的缩写,提供自动化的访问com的功能,也是通过JNI功能访问windows平台下的com组件或者win32系统库的。这是一个开始于1999年的开源项目的成果,有很多使用者对该项目进行了修改,做出了自己的贡献。


   Jacob下载地址:


              http://sourceforge.net/project/showfiles.php?group_id=109543&package_id=118368


        我在这里下载了Jacob1.14.3和jacob1.9的版本两个版本


  这里下载的是目前最新的Jacob1.14.3的Release版。


      另外java操作word方式还有(个人认为通过jacob最好,自己可以扩展,网上除poi之外几乎全是java-com技术实现的):


      (1):Apache POI - Java API To Access Microsoft Format Files(http://poi.apache.org/);对word处理不够强处理Excel功能可以,但是全是通过java完成的,不需 要com组件支持;


     (2):java2word 是一个在java程序中调用 MS Office Word 文档的组件(类库)。该组件提供了一组简单的接口,以便java程序调用他的服务操作Word 文档。(好象也是用的java-com技术);


     (3)web开发语言操作word的功能最好还是用第三方的控件, 看看这个SOAOFFICE,还可以使用js 写VBA呢http://www.kehansoft.com/soaoffice/doclist.asp


二、安装Jacob


   Jacob的安装非常的简单,我们解开下载的jacob_1.9.zip,在文件夹中找到jacob.dll和jacob.jar两个文件,如果是Jacob1.14.3则是jacob-1.14.3-x86.dll(32位,机和jacob-1.14.3-x64.dll(64位)和jacob.jar两个文件。Jacob.dll直接放到系统的system32文件夹下就行了,连注册都不用的(或者拷贝到jdk或者jre的bin目录下也行,当前测试文件所在的目录也行,就是只要在java.library.path中就可以)。而jacob.jar设置到classpath中去就可以了,或者在IDE开发环境的工程中设置扩展库也一样的,我是这样使用的将jacob-1.14.3-x86.dll或复制到%Tomcat5%\bin目录下将jacob.jar复制到%Tomcot5%\Share\lib目录下,我使用过程中感觉放到这里是一个最终解决办法,当你放哪都有问题的时候。我这样用之后再没有出过因为系统不一样出现的各种各样的问题,当然你作的是web的项目。


       注意使用jacob一写要安装word,我装的word2003,如果是操作word2007就不用jacob了(好像这方面的API)。


对jacob.dll几种配置方法 (网上看到):


2008-07-31 11:59:49


1、把jacob.dll文件,复制到 windows\system32 目录下。(注:我用的时候这个方法不能运行)


2、 把jacob.dll放入 Java\jdk1.5.0_06\jre\bin目录下.把jacob.jar放入 Java\jdk1.5.0_0\jre\lib\ext  


   目录下.可以正常运行。


3、把jacob.dll放入 \glc\src目录下.把jacob.jar放入WEB-INF\lib目录下,也是可以正常运行。


三、使用(以下是我改写的一个word操作类,希望有兴趣的朋友完善,记得发给我一份)


0001//注意java操作word关键是定位操作对象;
0002 
0003import com.jacob.activeX.ActiveXComponent;
0004 
0005import com.jacob.com.Dispatch;
0006 
0007import com.jacob.com.Variant;
0008 
0009/**
0010 
0011* jacob操作MSword类
0012 
0013* @author
0014 
0015*/
0016 
0017public class WordBean {
0018 
0019// word文档
0020 
0021private Dispatch doc;
0022 
0023// word运行程序对象
0024 
0025private ActiveXComponent word;
0026 
0027// 所有word文档集合
0028 
0029private Dispatch documents;
0030 
0031// 选定的范围或插入点
0032 
0033private Dispatch selection;
0034 
0035private boolean saveOnExit = true;
0036 
0037public WordBean()throws Exception{
0038 
0039if (word == null) {
0040 
0041word = new ActiveXComponent("Word.Application");
0042 
0043word.setProperty("Visible"new Variant(false)); //不可见打开word
0044 
0045word.setProperty("AutomationSecurity"new Variant(3)); //禁用宏
0046 
0047}
0048 
0049if (documents == null)
0050 
0051documents = word.getProperty("Documents").toDispatch();
0052 
0053}
0054 
0055/**
0056 
0057* 设置退出时参数
0058 
0059*
0060 
0061* @param saveOnExit
0062 
0063*            boolean true-退出时保存文件,false-退出时不保存文件
0064 
0065*/
0066 
0067public void setSaveOnExit(boolean saveOnExit) {
0068 
0069this.saveOnExit = saveOnExit;
0070 
0071}
0072 
0073/**
0074 
0075* 创建一个新的word文档
0076 
0077*
0078 
0079*/
0080 
0081public void createNewDocument() {
0082 
0083doc = Dispatch.call(documents, "Add").toDispatch();
0084 
0085selection = Dispatch.get(word, "Selection").toDispatch();
0086 
0087}
0088 
0089/**
0090 
0091* 打开一个已存在的文档
0092 
0093*
0094 
0095* @param docPath
0096 
0097*/
0098 
0099public void openDocument(String docPath) {
0100 
0101closeDocument();
0102 
0103doc = Dispatch.call(documents, "Open", docPath).toDispatch();
0104 
0105selection = Dispatch.get(word, "Selection").toDispatch();
0106 
0107}
0108 
0109/**
0110 
0111*只读 打开一个保护文档,
0112 
0113* @param docPath-文件全名
0114 
0115* @param pwd-密码
0116 
0117*/
0118 
0119public void openDocumentOnlyRead(String docPath, String pwd)throws Exception {
0120 
0121closeDocument();
0122 
0123// doc = Dispatch.invoke(documents, "Open", Dispatch.Method,
0124 
0125// new Object[]{docPath, new Variant(false), new Variant(true), new Variant(true), pwd},
0126 
0127// new int[1]).toDispatch();//打开word文件
0128 
0129doc =  Dispatch.callN(documents, "Open"new Object[]{docPath, new Variant(false),
0130 
0131new Variant(true), new Variant(true), pwd, ""new Variant(false)}).toDispatch();
0132 
0133selection = Dispatch.get(word, "Selection").toDispatch();
0134 
0135}
0136 
0137public void openDocument(String docPath, String pwd)throws Exception {
0138 
0139closeDocument();
0140 
0141doc =  Dispatch.callN(documents, "Open"new Object[]{docPath, new Variant(false),
0142 
0143new Variant(false), new Variant(true), pwd}).toDispatch();
0144 
0145selection = Dispatch.get(word, "Selection").toDispatch();
0146 
0147}
0148 
0149/**
0150 
0151* 把选定的内容或插入点向上移动
0152 
0153*
0154 
0155* @param pos
0156 
0157*            移动的距离
0158 
0159*/
0160 
0161public void moveUp(int pos) {
0162 
0163if (selection == null)
0164 
0165selection = Dispatch.get(word, "Selection").toDispatch();
0166 
0167for (int i = 0; i < pos; i++)
0168 
0169Dispatch.call(selection, "MoveUp");
0170 
0171}
0172 
0173/**
0174 
0175* 把选定的内容或者插入点向下移动
0176 
0177*
0178 
0179* @param pos
0180 
0181*            移动的距离
0182 
0183*/
0184 
0185public void moveDown(int pos) {
0186 
0187if (selection == null)
0188 
0189selection = Dispatch.get(word, "Selection").toDispatch();
0190 
0191for (int i = 0; i < pos; i++)
0192 
0193Dispatch.call(selection, "MoveDown");
0194 
0195}
0196 
0197/**
0198 
0199* 把选定的内容或者插入点向左移动
0200 
0201*
0202 
0203* @param pos
0204 
0205*            移动的距离
0206 
0207*/
0208 
0209public void moveLeft(int pos) {
0210 
0211if (selection == null)
0212 
0213selection = Dispatch.get(word, "Selection").toDispatch();
0214 
0215for (int i = 0; i < pos; i++) {
0216 
0217Dispatch.call(selection, "MoveLeft");
0218 
0219}
0220 
0221}
0222 
0223/**
0224 
0225* 把选定的内容或者插入点向右移动
0226 
0227*
0228 
0229* @param pos
0230 
0231*            移动的距离
0232 
0233*/
0234 
0235public void moveRight(int pos) {
0236 
0237if (selection == null)
0238 
0239selection = Dispatch.get(word, "Selection").toDispatch();
0240 
0241for (int i = 0; i < pos; i++)
0242 
0243Dispatch.call(selection, "MoveRight");
0244 
0245}
0246 
0247/**
0248 
0249* 把插入点移动到文件首位置
0250 
0251*
0252 
0253*/
0254 
0255public void moveStart() {
0256 
0257if (selection == null)
0258 
0259selection = Dispatch.get(word, "Selection").toDispatch();
0260 
0261Dispatch.call(selection, "HomeKey"new Variant(6));
0262 
0263}
0264 
0265/**
0266 
0267* 从选定内容或插入点开始查找文本
0268 
0269*
0270 
0271* @param toFindText
0272 
0273*            要查找的文本
0274 
0275* @return boolean true-查找到并选中该文本,false-未查找到文本
0276 
0277*/
0278 
0279@SuppressWarnings("static-access")
0280 
0281public boolean find(String toFindText) {
0282 
0283if (toFindText == null || toFindText.equals(""))
0284 
0285return false;
0286 
0287// 从selection所在位置开始查询
0288 
0289Dispatch find = word.call(selection, "Find").toDispatch();
0290 
0291// 设置要查找的内容
0292 
0293Dispatch.put(find, "Text", toFindText);
0294 
0295// 向前查找
0296 
0297Dispatch.put(find, "Forward""True");
0298 
0299// 设置格式
0300 
0301Dispatch.put(find, "Format""True");
0302 
0303// 大小写匹配
0304 
0305Dispatch.put(find, "MatchCase""True");
0306 
0307// 全字匹配
0308 
0309Dispatch.put(find, "MatchWholeWord""True");
0310 
0311// 查找并选中
0312 
0313return Dispatch.call(find, "Execute").getBoolean();
0314 
0315}
0316 
0317/**
0318 
0319* 把选定选定内容设定为替换文本
0320 
0321*
0322 
0323* @param toFindText
0324 
0325*            查找字符串
0326 
0327* @param newText
0328 
0329*            要替换的内容
0330 
0331* @return
0332 
0333*/
0334 
0335public boolean replaceText(String toFindText, String newText) {
0336 
0337if (!find(toFindText))
0338 
0339return false;
0340 
0341Dispatch.put(selection, "Text", newText);
0342 
0343return true;
0344 
0345}
0346 
0347/**
0348 
0349* 全局替换文本
0350 
0351*
0352 
0353* @param toFindText
0354 
0355*            查找字符串
0356 
0357* @param newText
0358 
0359*            要替换的内容
0360 
0361*/
0362 
0363public void replaceAllText(String toFindText, String newText) {
0364 
0365while (find(toFindText)) {
0366 
0367Dispatch.put(selection, "Text", newText);
0368 
0369Dispatch.call(selection, "MoveRight");
0370 
0371}
0372 
0373}
0374 
0375/**
0376 
0377* 在当前插入点插入字符串
0378 
0379*
0380 
0381* @param newText
0382 
0383*            要插入的新字符串
0384 
0385*/
0386 
0387public void insertText(String newText) {
0388 
0389Dispatch.put(selection, "Text", newText);
0390 
0391}
0392 
0393/**
0394 
0395*
0396 
0397* @param toFindText
0398 
0399*            要查找的字符串
0400 
0401* @param imagePath
0402 
0403*            图片路径
0404 
0405* @return
0406 
0407*/
0408 
0409public boolean replaceImage(String toFindText, String imagePath) {
0410 
0411if (!find(toFindText))
0412 
0413return false;
0414 
0415Dispatch.call(Dispatch.get(selection, "InLineShapes").toDispatch(),
0416 
0417"AddPicture", imagePath);
0418 
0419return true;
0420 
0421}
0422 
0423/**
0424 
0425* 全局替换图片
0426 
0427*
0428 
0429* @param toFindText
0430 
0431*            查找字符串
0432 
0433* @param imagePath
0434 
0435*            图片路径
0436 
0437*/
0438 
0439public void replaceAllImage(String toFindText, String imagePath) {
0440 
0441while (find(toFindText)) {
0442 
0443Dispatch.call(Dispatch.get(selection, "InLineShapes").toDispatch(),
0444 
0445"AddPicture", imagePath);
0446 
0447Dispatch.call(selection, "MoveRight");
0448 
0449}
0450 
0451}
0452 
0453/**
0454 
0455* 在当前插入点插入图片
0456 
0457*
0458 
0459* @param imagePath
0460 
0461*            图片路径
0462 
0463*/
0464 
0465public void insertImage(String imagePath) {
0466 
0467Dispatch.call(Dispatch.get(selection, "InLineShapes").toDispatch(),
0468 
0469"AddPicture", imagePath);
0470 
0471}
0472 
0473/**
0474 
0475* 合并单元格
0476 
0477*
0478 
0479* @param tableIndex
0480 
0481* @param fstCellRowIdx
0482 
0483* @param fstCellColIdx
0484 
0485* @param secCellRowIdx
0486 
0487* @param secCellColIdx
0488 
0489*/
0490 
0491public void mergeCell(int tableIndex, int fstCellRowIdx, int fstCellColIdx,
0492 
0493int secCellRowIdx, int secCellColIdx) {
0494 
0495// 所有表格
0496 
0497Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
0498 
0499// 要填充的表格
0500 
0501Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
0502 
0503.toDispatch();
0504 
0505Dispatch fstCell = Dispatch.call(table, "Cell",
0506 
0507new Variant(fstCellRowIdx), new Variant(fstCellColIdx))
0508 
0509.toDispatch();
0510 
0511Dispatch secCell = Dispatch.call(table, "Cell",
0512 
0513new Variant(secCellRowIdx), new Variant(secCellColIdx))
0514 
0515.toDispatch();
0516 
0517Dispatch.call(fstCell, "Merge", secCell);
0518 
0519}
0520 
0521/**
0522 
0523* 在指定的单元格里填写数据
0524 
0525*
0526 
0527* @param tableIndex
0528 
0529* @param cellRowIdx
0530 
0531* @param cellColIdx
0532 
0533* @param txt
0534 
0535*/
0536 
0537public void putTxtToCell(int tableIndex, int cellRowIdx, int cellColIdx,
0538 
0539String txt) {
0540 
0541// 所有表格
0542 
0543Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
0544 
0545// 要填充的表格
0546 
0547Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
0548 
0549.toDispatch();
0550 
0551Dispatch cell = Dispatch.call(table, "Cell"new Variant(cellRowIdx),
0552 
0553new Variant(cellColIdx)).toDispatch();
0554 
0555Dispatch.call(cell, "Select");
0556 
0557Dispatch.put(selection, "Text", txt);
0558 
0559}
0560 
0561/**
0562 
0563* 获得指定的单元格里数据
0564 
0565*
0566 
0567* @param tableIndex
0568 
0569* @param cellRowIdx
0570 
0571* @param cellColIdx
0572 
0573* @return
0574 
0575*/
0576 
0577public String getTxtFromCell(int tableIndex, int cellRowIdx, int cellColIdx) {
0578 
0579// 所有表格
0580 
0581Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
0582 
0583// 要填充的表格
0584 
0585Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
0586 
0587.toDispatch();
0588 
0589Dispatch cell = Dispatch.call(table, "Cell"new Variant(cellRowIdx),
0590 
0591new Variant(cellColIdx)).toDispatch();
0592 
0593Dispatch.call(cell, "Select");
0594 
0595String ret = "";
0596 
0597ret = Dispatch.get(selection, "Text").toString();
0598 
0599ret = ret.substring(0, ret.length()-1); //去掉最后的回车符;
0600 
0601return ret;
0602 
0603}
0604 
0605/**
0606 
0607* 在当前文档拷贝剪贴板数据
0608 
0609* @param pos
0610 
0611*/
0612 
0613public void pasteExcelSheet(String pos) {
0614 
0615moveStart();
0616 
0617if (this.find(pos)) {
0618 
0619Dispatch textRange = Dispatch.get(selection, "Range").toDispatch();
0620 
0621Dispatch.call(textRange, "Paste");
0622 
0623}
0624 
0625}
0626 
0627/**
0628 
0629* 在当前文档指定的位置拷贝表格
0630 
0631*
0632 
0633* @param pos
0634 
0635*            当前文档指定的位置
0636 
0637* @param tableIndex
0638 
0639*            被拷贝的表格在word文档中所处的位置
0640 
0641*/
0642 
0643public void copyTable(String pos, int tableIndex) {
0644 
0645// 所有表格
0646 
0647Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
0648 
0649// 要填充的表格
0650 
0651Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
0652 
0653.toDispatch();
0654 
0655Dispatch range = Dispatch.get(table, "Range").toDispatch();
0656 
0657Dispatch.call(range, "Copy");
0658 
0659if (this.find(pos)) {
0660 
0661Dispatch textRange = Dispatch.get(selection, "Range").toDispatch();
0662 
0663Dispatch.call(textRange, "Paste");
0664 
0665}
0666 
0667}
0668 
0669/**
0670 
0671* 在当前文档指定的位置拷贝来自另一个文档中的表格
0672 
0673*
0674 
0675* @param anotherDocPath
0676 
0677*            另一个文档的磁盘路径
0678 
0679* @param tableIndex
0680 
0681*            被拷贝的表格在另一格文档中的位置
0682 
0683* @param pos
0684 
0685*            当前文档指定的位置
0686 
0687*/
0688 
0689public void copyTableFromAnotherDoc(String anotherDocPath, int tableIndex,
0690 
0691String pos) {
0692 
0693Dispatch doc2 = null;
0694 
0695try {
0696 
0697doc2 = Dispatch.call(documents, "Open", anotherDocPath)
0698 
0699.toDispatch();
0700 
0701// 所有表格
0702 
0703Dispatch tables = Dispatch.get(doc2, "Tables").toDispatch();
0704 
0705// 要填充的表格
0706 
0707Dispatch table = Dispatch.call(tables, "Item",
0708 
0709new Variant(tableIndex)).toDispatch();
0710 
0711Dispatch range = Dispatch.get(table, "Range").toDispatch();
0712 
0713Dispatch.call(range, "Copy");
0714 
0715if (this.find(pos)) {
0716 
0717Dispatch textRange = Dispatch.get(selection, "Range")
0718 
0719.toDispatch();
0720 
0721Dispatch.call(textRange, "Paste");
0722 
0723}
0724 
0725catch (Exception e) {
0726 
0727e.printStackTrace();
0728 
0729finally {
0730 
0731if (doc2 != null) {
0732 
0733Dispatch.call(doc2, "Close"new Variant(saveOnExit));
0734 
0735doc2 = null;
0736 
0737}
0738 
0739}
0740 
0741}
0742 
0743/**
0744 
0745* 在当前文档指定的位置拷贝来自另一个文档中的图片
0746 
0747*
0748 
0749* @param anotherDocPath 另一个文档的磁盘路径
0750 
0751* @param shapeIndex 被拷贝的图片在另一格文档中的位置
0752 
0753* @param pos 当前文档指定的位置
0754 
0755*/
0756 
0757public void copyImageFromAnotherDoc(String anotherDocPath, int shapeIndex,
0758 
0759String pos) {
0760 
0761Dispatch doc2 = null;
0762 
0763try {
0764 
0765doc2 = Dispatch.call(documents, "Open", anotherDocPath)
0766 
0767.toDispatch();
0768 
0769Dispatch shapes = Dispatch.get(doc2, "InLineShapes").toDispatch();
0770 
0771Dispatch shape = Dispatch.call(shapes, "Item",
0772 
0773new Variant(shapeIndex)).toDispatch();
0774 
0775Dispatch imageRange = Dispatch.get(shape, "Range").toDispatch();
0776 
0777Dispatch.call(imageRange, "Copy");
0778 
0779if (this.find(pos)) {
0780 
0781Dispatch textRange = Dispatch.get(selection, "Range")
0782 
0783.toDispatch();
0784 
0785Dispatch.call(textRange, "Paste");
0786 
0787}
0788 
0789catch (Exception e) {
0790 
0791e.printStackTrace();
0792 
0793finally {
0794 
0795if (doc2 != null) {
0796 
0797Dispatch.call(doc2, "Close"new Variant(saveOnExit));
0798 
0799doc2 = null;
0800 
0801}
0802 
0803}
0804 
0805}
0806 
0807/**
0808 
0809* 创建表格
0810 
0811*
0812 
0813* @param pos
0814 
0815*            位置
0816 
0817* @param cols
0818 
0819*            列数
0820 
0821* @param rows
0822 
0823*            行数
0824 
0825*/
0826 
0827public void createTable(String pos, int numCols, int numRows) {
0828 
0829if (find(pos)) {
0830 
0831Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
0832 
0833Dispatch range = Dispatch.get(selection, "Range").toDispatch();
0834 
0835@SuppressWarnings("unused")
0836 
0837Dispatch newTable = Dispatch.call(tables, "Add", range,
0838 
0839new Variant(numRows), new Variant(numCols)).toDispatch();
0840 
0841Dispatch.call(selection, "MoveRight");
0842 
0843else {
0844 
0845Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
0846 
0847Dispatch range = Dispatch.get(selection, "Range").toDispatch();
0848 
0849@SuppressWarnings("unused")
0850 
0851Dispatch newTable = Dispatch.call(tables, "Add", range,
0852 
0853new Variant(numRows), new Variant(numCols)).toDispatch();
0854 
0855Dispatch.call(selection, "MoveRight");
0856 
0857}
0858 
0859}
0860 
0861/**
0862 
0863* 在指定行前面增加行
0864 
0865*
0866 
0867* @param tableIndex
0868 
0869*            word文件中的第N张表(从1开始)
0870 
0871* @param rowIndex
0872 
0873*            指定行的序号(从1开始)
0874 
0875*/
0876 
0877public void addTableRow(int tableIndex, int rowIndex) {
0878 
0879// 所有表格
0880 
0881Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
0882 
0883// 要填充的表格
0884 
0885Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
0886 
0887.toDispatch();
0888 
0889// 表格的所有行
0890 
0891Dispatch rows = Dispatch.get(table, "Rows").toDispatch();
0892 
0893Dispatch row = Dispatch.call(rows, "Item"new Variant(rowIndex))
0894 
0895.toDispatch();
0896 
0897Dispatch.call(rows, "Add"new Variant(row));
0898 
0899}
0900 
0901/**
0902 
0903* 在第1行前增加一行
0904 
0905*
0906 
0907* @param tableIndex
0908 
0909*  word文档中的第N张表(从1开始)
0910 
0911*/
0912 
0913public void addFirstTableRow(int tableIndex) {
0914 
0915// 所有表格
0916 
0917Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
0918 
0919// 要填充的表格
0920 
0921Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
0922 
0923.toDispatch();
0924 
0925// 表格的所有行
0926 
0927Dispatch rows = Dispatch.get(table, "Rows").toDispatch();
0928 
0929Dispatch row = Dispatch.get(rows, "First").toDispatch();
0930 
0931Dispatch.call(rows, "Add"new Variant(row));
0932 
0933}
0934 
0935/**
0936 
0937* 在最后1行前增加一行
0938 
0939*
0940 
0941* @param tableIndex
0942 
0943*            word文档中的第N张表(从1开始)
0944 
0945*/
0946 
0947public void addLastTableRow(int tableIndex) {
0948 
0949// 所有表格
0950 
0951Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
0952 
0953// 要填充的表格
0954 
0955Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
0956 
0957.toDispatch();
0958 
0959// 表格的所有行
0960 
0961Dispatch rows = Dispatch.get(table, "Rows").toDispatch();
0962 
0963Dispatch row = Dispatch.get(rows, "Last").toDispatch();
0964 
0965Dispatch.call(rows, "Add"new Variant(row));
0966 
0967}
0968 
0969/**
0970 
0971* 增加一行
0972 
0973*
0974 
0975* @param tableIndex
0976 
0977*            word文档中的第N张表(从1开始)
0978 
0979*/
0980 
0981public void addRow(int tableIndex) {
0982 
0983Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
0984 
0985// 要填充的表格
0986 
0987Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
0988 
0989.toDispatch();
0990 
0991// 表格的所有行
0992 
0993Dispatch rows = Dispatch.get(table, "Rows").toDispatch();
0994 
0995Dispatch.call(rows, "Add");
0996 
0997}
0998 
0999/**
1000 
1001* 增加一列
1002 
1003*
1004 
1005* @param tableIndex
1006 
1007*            word文档中的第N张表(从1开始)
1008 
1009*/
1010 
1011public void addCol(int tableIndex) {
1012 
1013// 所有表格
1014 
1015Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
1016 
1017// 要填充的表格
1018 
1019Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
1020 
1021.toDispatch();
1022 
1023// 表格的所有行
1024 
1025Dispatch cols = Dispatch.get(table, "Columns").toDispatch();
1026 
1027Dispatch.call(cols, "Add").toDispatch();
1028 
1029Dispatch.call(cols, "AutoFit");
1030 
1031}
1032 
1033/**
1034 
1035* 在指定列前面增加表格的列
1036 
1037*
1038 
1039* @param tableIndex
1040 
1041*            word文档中的第N张表(从1开始)
1042 
1043* @param colIndex
1044 
1045*            制定列的序号 (从1开始)
1046 
1047*/
1048 
1049public void addTableCol(int tableIndex, int colIndex) {
1050 
1051// 所有表格
1052 
1053Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
1054 
1055// 要填充的表格
1056 
1057Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
1058 
1059.toDispatch();
1060 
1061// 表格的所有行
1062 
1063Dispatch cols = Dispatch.get(table, "Columns").toDispatch();
1064 
1065System.out.println(Dispatch.get(cols, "Count"));
1066 
1067Dispatch col = Dispatch.call(cols, "Item"new Variant(colIndex))
1068 
1069.toDispatch();
1070 
1071// Dispatch col = Dispatch.get(cols, "First").toDispatch();
1072 
1073Dispatch.call(cols, "Add", col).toDispatch();
1074 
1075Dispatch.call(cols, "AutoFit");
1076 
1077}
1078 
1079/**
1080 
1081* 在第1列前增加一列
1082 
1083*
1084 
1085* @param tableIndex
1086 
1087*            word文档中的第N张表(从1开始)
1088 
1089*/
1090 
1091public void addFirstTableCol(int tableIndex) {
1092 
1093Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
1094 
1095// 要填充的表格
1096 
1097Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
1098 
1099.toDispatch();
1100 
1101// 表格的所有行
1102 
1103Dispatch cols = Dispatch.get(table, "Columns").toDispatch();
1104 
1105Dispatch col = Dispatch.get(cols, "First").toDispatch();
1106 
1107Dispatch.call(cols, "Add", col).toDispatch();
1108 
1109Dispatch.call(cols, "AutoFit");
1110 
1111}
1112 
1113/**
1114 
1115* 在最后一列前增加一列
1116 
1117*
1118 
1119* @param tableIndex
1120 
1121*            word文档中的第N张表(从1开始)
1122 
1123*/
1124 
1125public void addLastTableCol(int tableIndex) {
1126 
1127Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
1128 
1129// 要填充的表格
1130 
1131Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
1132 
1133.toDispatch();
1134 
1135// 表格的所有行
1136 
1137Dispatch cols = Dispatch.get(table, "Columns").toDispatch();
1138 
1139Dispatch col = Dispatch.get(cols, "Last").toDispatch();
1140 
1141Dispatch.call(cols, "Add", col).toDispatch();
1142 
1143Dispatch.call(cols, "AutoFit");
1144 
1145}
1146 
1147/**
1148 
1149* 自动调整表格
1150 
1151*
1152 
1153*/
1154 
1155@SuppressWarnings("deprecation")
1156 
1157public void autoFitTable() {
1158 
1159Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
1160 
1161int count = Dispatch.get(tables, "Count").toInt();
1162 
1163for (int i = 0; i < count; i++) {
1164 
1165Dispatch table = Dispatch.call(tables, "Item"new Variant(i + 1))
1166 
1167.toDispatch();
1168 
1169Dispatch cols = Dispatch.get(table, "Columns").toDispatch();
1170 
1171Dispatch.call(cols, "AutoFit");
1172 
1173}
1174 
1175}
1176 
1177/**
1178 
1179* 调用word里的宏以调整表格的宽度,其中宏保存在document下
1180 
1181*
1182 
1183*/
1184 
1185@SuppressWarnings("deprecation")
1186 
1187public void callWordMacro() {
1188 
1189Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
1190 
1191int count = Dispatch.get(tables, "Count").toInt();
1192 
1193Variant vMacroName = new Variant("Normal.NewMacros.tableFit");
1194 
1195@SuppressWarnings("unused")
1196 
1197Variant vParam = new Variant("param1");
1198 
1199@SuppressWarnings("unused")
1200 
1201Variant para[] = new Variant[] { vMacroName };
1202 
1203for (int i = 0; i < count; i++) {
1204 
1205Dispatch table = Dispatch.call(tables, "Item"new Variant(i + 1))
1206 
1207.toDispatch();
1208 
1209Dispatch.call(table, "Select");
1210 
1211Dispatch.call(word, "Run""tableFitContent");
1212 
1213}
1214 
1215}
1216 
1217/**
1218 
1219* 设置当前选定内容的字体
1220 
1221*
1222 
1223* @param boldSize
1224 
1225* @param italicSize
1226 
1227* @param underLineSize
1228 
1229*            下划线
1230 
1231* @param colorSize
1232 
1233*            字体颜色
1234 
1235* @param size
1236 
1237*            字体大小
1238 
1239* @param name
1240 
1241*            字体名称
1242 
1243*/
1244 
1245public void setFont(boolean bold, boolean italic, boolean underLine,
1246 
1247String colorSize, String size, String name) {
1248 
1249Dispatch font = Dispatch.get(selection, "Font").toDispatch();
1250 
1251Dispatch.put(font, "Name"new Variant(name));
1252 
1253Dispatch.put(font, "Bold"new Variant(bold));
1254 
1255Dispatch.put(font, "Italic"new Variant(italic));
1256 
1257Dispatch.put(font, "Underline"new Variant(underLine));
1258 
1259Dispatch.put(font, "Color", colorSize);
1260 
1261Dispatch.put(font, "Size", size);
1262 
1263}
1264 
1265/**
1266 
1267* 设置单元格被选中
1268 
1269*
1270 
1271* @param tableIndex
1272 
1273* @param cellRowIdx
1274 
1275* @param cellColIdx
1276 
1277*/
1278 
1279public void setTableCellSelected(int tableIndex, int cellRowIdx, int cellColIdx){
1280 
1281Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
1282 
1283Dispatch table = Dispatch.call(tables, "Item"new Variant(tableIndex))
1284 
1285.toDispatch();
1286 
1287Dispatch cell = Dispatch.call(table, "Cell"new Variant(cellRowIdx),
1288 
1289new Variant(cellColIdx)).toDispatch();
1290 
1291Dispatch.call(cell, "Select");
1292 
1293}
1294 
1295/**
1296 
1297* 设置选定单元格的垂直对起方式, 请使用setTableCellSelected选中一个单元格
1298 
1299* @param align 0-顶端, 1-居中, 3-底端
1300 
1301*/
1302 
1303public void setCellVerticalAlign(int verticalAlign){
1304 
1305Dispatch cells = Dispatch.get(selection, "Cells").toDispatch();
1306 
1307Dispatch.put(cells, "VerticalAlignment"new Variant(verticalAlign));
1308 
1309}
1310 
1311/**
1312 
1313* 设置当前文档中所有表格水平居中方式及其它一些格式,用在将word文件转化为html中,针对申报表
1314 
1315*/
1316 
1317@SuppressWarnings("deprecation")
1318 
1319public void setApplyTableFormat(){
1320 
1321Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
1322 
1323int tabCount = Integer.valueOf(Dispatch.get(tables, "Count").toString()); //System.out.println(tabCount);
1324 
1325System.out.println("*******************************************************");
1326 
1327for(int i=1; i<=tabCount; i++){
1328 
1329Dispatch table = Dispatch.call(tables, "Item"new Variant(i)).toDispatch();
1330 
1331Dispatch rows = Dispatch.get(table, "Rows").toDispatch();
1332 
1333if(i==1){
1334 
1335Dispatch.put(rows, "Alignment"new Variant(2)); //1-居中,2-Right
1336 
1337continue ;
1338 
1339}
1340 
1341Dispatch.put(rows, "Alignment"new Variant(1)); //1-居中
1342 
1343Dispatch.call(table, "AutoFitBehavior"new Variant(1));//设置自动调整表格方式,1-根据窗口自动调整
1344 
1345Dispatch.put(table, "PreferredWidthType"new Variant(1));
1346 
1347Dispatch.put(table, "PreferredWidth"new Variant(700));
1348 
1349System.out.println(Dispatch.get(rows, "HeightRule").toString());
1350 
1351Dispatch.put(rows, "HeightRule"new Variant(1)); //0-自动wdRowHeightAuto,1-最小值wdRowHeightAtLeast, 2-固定wdRowHeightExactly
1352 
1353Dispatch.put(rows, "Height"new Variant(0.04*28.35));
1354 
1355//int oldAlign = Integer.valueOf(Dispatch.get(rows, "Alignment").toString());
1356 
1357//System.out.println("Algin:" + oldAlign);
1358 
1359}
1360 
1361}
1362 
1363/**
1364 
1365* 设置段落格式
1366 
1367*
1368 
1369* @param alignment
1370 
1371* 0-左对齐, 1-右对齐, 2-右对齐, 3-两端对齐, 4-分散对齐
1372 
1373* @param lineSpaceingRule
1374 
1375* @param lineUnitBefore
1376 
1377* @param lineUnitAfter
1378 
1379* @param characterUnitFirstLineIndent
1380 
1381*/
1382 
1383public void setParagraphsProperties(int alignment, int lineSpaceingRule,
1384 
1385int lineUnitBefore, int lineUnitAfter, int characterUnitFirstLineIndent){
1386 
1387Dispatch paragraphs = Dispatch.get(selection, "Paragraphs").toDispatch();
1388 
1389Dispatch.put(paragraphs, "Alignment"new Variant(alignment)); //对齐方式
1390 
1391Dispatch.put(paragraphs, "LineSpacingRule"new Variant(lineSpaceingRule)); //行距
1392 
1393Dispatch.put(paragraphs, "LineUnitBefore"new Variant(lineUnitBefore)); //段前
1394 
1395Dispatch.put(paragraphs, "LineUnitAfter"new Variant(lineUnitAfter)); //段后
1396 
1397Dispatch.put(paragraphs, "CharacterUnitFirstLineIndent",
1398 
1399new Variant(characterUnitFirstLineIndent)); //首行缩进字符数
1400 
1401}
1402 
1403/**
1404 
1405* 打印当前段落格式, 使用前,请先选中段落
1406 
1407*/
1408 
1409public void getParagraphsProperties(){
1410 
1411Dispatch paragraphs = Dispatch.get(selection, "Paragraphs").toDispatch();
1412 
1413String val = Dispatch.get(paragraphs, "LineSpacingRule").toString(); //行距
1414 
1415System.out.println("行距:" + val);
1416 
1417val = Dispatch.get(paragraphs, "Alignment").toString(); //对齐方式
1418 
1419System.out.println("对齐方式:" + val); //0-左对齐, 1-右对齐, 2-右对齐, 3-两端对齐, 4-分散对齐
1420 
1421val = Dispatch.get(paragraphs, "LineUnitBefore").toString(); //段前行数
1422 
1423System.out.println("段前行数:" + val);
1424 
1425val = Dispatch.get(paragraphs, "LineUnitAfter").toString(); //段后行数
1426 
1427System.out.println("段后行数:" + val);
1428 
1429val = Dispatch.get(paragraphs, "FirstLineIndent").toString(); //首行缩进
1430 
1431System.out.println("首行缩进:" + val);
1432 
1433val = Dispatch.get(paragraphs, "CharacterUnitFirstLineIndent").toString(); //首行缩进字符数
1434 
1435System.out.println("首行缩进字符数:" + val);
1436 
1437}
1438 
1439/**
1440 
1441* 文件保存或另存为
1442 
1443*
1444 
1445* @param savePath
1446 
1447*            保存或另存为路径
1448 
1449*/
1450 
1451public void save(String savePath) {
1452 
1453Dispatch.call(Dispatch.call(word, "WordBasic").getDispatch(),
1454 
1455"FileSaveAs", savePath);
1456 
1457}
1458 
1459/**
1460 
1461* 文件保存为html格式
1462 
1463*
1464 
1465* @param savePath
1466 
1467* @param htmlPath
1468 
1469*/
1470 
1471public void saveAsHtml(String htmlPath){
1472 
1473Dispatch.invoke(doc,"SaveAs", Dispatch.Method,
1474 
1475new Object[]{htmlPath, new Variant(8)}, new int[1]);
1476 
1477}
1478 
1479/**
1480 
1481* 关闭文档
1482 
1483*@param val 0不保存修改 -1 保存修改 -2 提示是否保存修改
1484 
1485*/
1486 
1487public void closeDocument(int val) {
1488 
1489Dispatch.call(doc, "Close"new Variant(val));
1490 
1491doc = null;
1492 
1493}
1494 
1495/**
1496 
1497* 关闭当前word文档
1498 
1499*
1500 
1501*/
1502 
1503public void closeDocument() {
1504 
1505if (doc != null) {
1506 
1507Dispatch.call(doc, "Save");
1508 
1509Dispatch.call(doc, "Close"new Variant(saveOnExit));
1510 
1511doc = null;
1512 
1513}
1514 
1515}
1516 
1517public void closeDocumentWithoutSave(){
1518 
1519if (doc != null) {
1520 
1521Dispatch.call(doc, "Close"new Variant(false));
1522 
1523doc = null;
1524 
1525}
1526 
1527}
1528 
1529/**
1530 
1531* 关闭全部应用
1532 
1533*
1534 
1535*/
1536 
1537public void close() {
1538 
1539//closeDocument();
1540 
1541if (word != null) {
1542 
1543Dispatch.call(word, "Quit");
1544 
1545word = null;
1546 
1547}
1548 
1549selection = null;
1550 
1551documents = null;
1552 
1553}
1554 
1555/**
1556 
1557* 打印当前word文档
1558 
1559*
1560 
1561*/
1562 
1563public void printFile() {
1564 
1565if (doc != null) {
1566 
1567Dispatch.call(doc, "PrintOut");
1568 
1569}
1570 
1571}
1572 
1573/**
1574 
1575* 保护当前档,如果不存在, 使用expression.Protect(Type, NoReset, Password)
1576 
1577*
1578 
1579* @param pwd
1580 
1581* WdProtectionType 可以是下列 WdProtectionType 常量之一:
1582 
1583* 1-wdAllowOnlyComments, 2-wdAllowOnlyFormFields, 0-wdAllowOnlyRevisions,
1584 
1585* -1-wdNoProtection, 3-wdAllowOnlyReading
1586 
1587*
1588 
1589*/
1590 
1591public void protectedWord(String pwd){
1592 
1593String protectionType = Dispatch.get(doc, "ProtectionType").toString();
1594 
1595if(protectionType.equals("-1")){
1596 
1597Dispatch.call(doc, "Protect"new Variant(3), new Variant(true), pwd);
1598 
1599}
1600 
1601}
1602 
1603/**
1604 
1605* 解除文档保护,如果存在
1606 
1607* @param pwd
1608 
1609* WdProtectionType 常量之一(Long 类型,只读):
1610 
1611* 1-wdAllowOnlyComments,2-wdAllowOnlyFormFields、
1612 
1613* 0-wdAllowOnlyRevisions,-1-wdNoProtection, 3-wdAllowOnlyReading
1614 
1615*
1616 
1617*/
1618 
1619public void unProtectedWord(String pwd){
1620 
1621String protectionType = Dispatch.get(doc, "ProtectionType").toString();
1622 
1623if(protectionType.equals("3")){
1624 
1625Dispatch.call(doc, "Unprotect", pwd);
1626 
1627}
1628 
1629}
1630 
1631/**
1632 
1633* 设置word文档安全级别
1634 
1635* @param value
1636 
1637* 1-msoAutomationSecurityByUI  使用“安全”对话框指定的安全设置。
1638 
1639* 2-msoAutomationSecurityForceDisable  在程序打开的所有文件中禁用所有宏,而不显示任何安全提醒。
1640 
1641* 3-msoAutomationSecurityLow  启用所有宏,这是启动应用程序时的默认值。
1642 
1643*/
1644 
1645public void setAutomationSecurity(int value){
1646 
1647word.setProperty("AutomationSecurity"new Variant(value));
1648 
1649}
1650 
1651/**
1652 
1653* 读取文档中第paragraphsIndex段文字的内容;
1654 
1655* @param paragraphsIndex
1656 
1657* @return
1658 
1659*/
1660 
1661public String getParagraphs(int paragraphsIndex){
1662 
1663String ret = "";
1664 
1665Dispatch paragraphs = Dispatch.get(doc, "Paragraphs").toDispatch(); // 所有段落
1666 
1667int paragraphCount = Dispatch.get(paragraphs, "Count").getInt(); // 一共的段落数
1668 
1669Dispatch paragraph = null;
1670 
1671Dispatch range = null;
1672 
1673if(paragraphCount > paragraphsIndex && 0 < paragraphsIndex){
1674 
1675paragraph = Dispatch.call(paragraphs, "Item"new Variant(paragraphsIndex)).toDispatch();
1676 
1677range = Dispatch.get(paragraph, "Range").toDispatch();
1678 
1679ret = Dispatch.get(range, "Text").toString();
1680 
1681}
1682 
1683return ret;
1684 
1685}
1686 
1687public static void main(String[] args)throws Exception{
1688 
1689WordBean word = new WordBean();
1690 
1691word.createNewDocument();
1692 
1693word.createTable(""55);
1694 
1695word.mergeCell(11115);
1696 
1697word.mergeCell(12125);
1698 
1699word.mergeCell(13135);
1700 
1701word.putTxtToCell(1,1,1,"主题");
1702 
1703word.putTxtToCell(1,2,1,"时间");
1704 
1705word.putTxtToCell(1,3,1,"人员");
1706 
1707word.putTxtToCell(1,4,2,"说话了");
1708 
1709word.save("c:\\jacobTest.doc");
1710 
1711System.out.print("请打开c:\\jacobTest.doc查看是否有写word成功!");
1712 
1713word.close();
1714 
1715}
1716 
1717}


四.使用错误分析:


1.由于应用程序配置不正确,不能启用dll文件;


解决:版本不对,换另一个版本试一下.


2. 

1ERROR [http-8080-Processor25] - Servlet.service() for servlet FileUploaded threw exception
2 
3   java.lang.UnsatisfiedLinkError: no jacob-1.14.3-x86 in java.library.path
4 
5   at java.lang.ClassLoader.loadLibrary(Unknown Source)
6 
7   at java.lang.Runtime.loadLibrary0(Unknown Source)
8 
9   at java.lang.System.loadLibrary(Unknown Source)


将dll文件复制到tomcat\bin目录下重新启动tomcat5.5


3.使用过程中(将项目发布到Tomcat5下运行时)提示


1java.lang.UnsatisfiedLinkError:
2 
3Native Library D:\Program Files\Apache Software Foundation\Tomcat 5.5\bin\jacob-1.14.3-x86.dll
4 
5already loaded in another classloader


解决:将%Tomcat 5.5%\webapps\XXXX\WEB-INF\lib\下的jacob.jar包剪切到%Tomcat 5.5%\shared\lib目录下(或删除).




五.自己改写WordBean类:


1.改写前你要知道VBA,熟悉怎样用VBA操作word;


2.将VBA操作改到java代码;要知道com.jacob.com.Dispatch可容纳任何VBA中的集合对象;


如:Dispatch paragraphs = Dispatch.get(doc, "Paragraphs").toDispatch(); // 将Paragraphs 集合对象赋给Dispatch对象;


3.使用VBA对象属性:


如:int paragraphCount = Dispatch.get(paragraphs, "Count").getInt(); //调用Dispatch.get()方法获取Paragraphs 集合对象的Count属性;


4.调用VBA对象方法:


在VBA帮助中我们找到Document 对象Close方法是这样声明的:


expression.Close(SaveChanges, OriginalFormat, RouteDocument)


expression   必需。该表达式返回以上的一个对象。


SaveChanges  Variant 类型,可选。指定保存文档的操作。可以是下列 WdSaveOptions 常量之一:wdDoNotSaveChanges、wdPromptToSaveChanges 或 wdSaveChanges。


OriginalFormat  Variant 类型,可选。指定保存文档的格式。可以是下列 WdOriginalFormat 常量之一:wdOriginalDocumentFormat、wdPromptUser 或 wdWordDocument。


RouteDocument  Variant 类型,可选。如果该属性值为 True,则将文档发送给下一个收件人。如果文档没有附加传送名单,则忽略该参数。


因些我们可在WordBean添加一个这样的方法关闭文档:


1public void closeDocument(int val) {
2 
3Dispatch doc = Dispatch.call(documents, "Open", docPath).toDispatch();  //doc是Document对象,调用
4 
5Dispatch.call(doc, "Close"new Variant(val));  // val 0不保存修改 -1 保存修改 -2 提示是否保存修改,对应VBA中Document 对象Close方法的SaveChanges参数
6 
7doc = null;
8 
9}


你会注意到Dispatch类重载了很多call方法,这与VBA中方法基本相似有很多参数是缺省的:


你可还会注意到Dispatch还有个invoke方法其实它和call差不多也是调用VBA对象方法的,只参数的形式不同(我目前这样认为)


Dispatch还有很多方法调用都是为配合调用VBA对象的方法,我还没有时间深入的看,等都明白再补上这部分说明;


参考(自己Gooogle一下):


JAVA 深度控制 WORD;


Aspose.Words for Java 发布-操作word的工具


Java/Office2007 以往java程序员要访问office文档,往往要借助各种各样的com组件,jni是难以避免的,因为office文档(word、excel、ppt)是二进制存储的。但是在许多系统中都要用到office文档,这个java程序员带来了一定的麻烦。  随着office2007的出现,文档存储支持OpenXML,使得java程序读写office文档不用必须借助第三方控件。以word2007为例,文档存储为*.docx文件,这实际上是一个压缩文件,通过java的ZIPjar包、TAR jar包,都可以访问,可以使用100%纯java代码完成对word2007文件的读取、写入操作。  比较详细的一个例子如下:http://www.infoq.com/articles/cracking-office-2007-with-java,有兴趣的可以去参考一下。  另外,office文档操作也有很多其他方法,比如POI、j-Interop等第三方工具包。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值