项目需要,用户从系统里面下载word文档,该文档进行了填写限制和加密,用户只能在固定位置填写内容。现要求系统验证上传的附件是否从系统上下载下来的。
思路:系统上面的文档都加入一个固定书签,用户上传文档的时候,检验文档里是否包含这个书签。
采用jacob操作word文档
JACOB(java -com bridge)是一个 JAVA到微软的COM接口的桥梁。使用JACOB允许任何JVM访问COM对象,从而使JAVA应用程序能够调用COM对象。
下载地址:http://sourceforge.net/projects/jacob-project/
其中jacob-1.16.1-x64.dll 是用于64位机器上的,jacob-1.16.1-x86.dll用于32位的。
该dll放于 C:\Windows\system32 目录下。jacob.jar放于应用lib底下
测试代码
Java代码 收藏代码
ActiveXComponent word = null;
try {
word = new ActiveXComponent(“Word.Application”);
System.out.println(“jacob当前版本:”+word.getBuildVersion());
}catch(Exception e ){
e.printStackTrace();
}
下面再贴出网上常见的代码+自己整理的几个方法(模糊查询书签等)
注意插入书签+书签值的方法,要先插入书签值再选中书签值,之后插入书签。这样根据书签名才能取得书签值。否则根据网络上很多方法,都取不到书签值或者取到空。因为书签值可以是一个点也可以是一大段内容。
Java代码 收藏代码
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import com.gdcn.bpaf.common.helper.StringHelper;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
/**
* *
*
Description: {jacob操作word类}
*
*
Copyright: Copyright (c) 2011
*
*
CreateDate: 2012-6-28
*
* @author Beny
* @version 1.0
*/
public class JacobHelper {
// word文档
private Dispatch doc;
// word运行程序对象
private ActiveXComponent word;
// 所有word文档集合
private Dispatch documents;
// 选定的范围或插入点
private Dispatch selection;
private boolean saveOnExit = true;
public JacobHelper(boolean visible) throws Exception {
ComThread.InitSTA();//线程启动
if (word == null) {
word = new ActiveXComponent("Word.Application");
word.setProperty("Visible", new Variant(visible)); // 不可见打开word
word.setProperty("AutomationSecurity", new Variant(3)); // 禁用宏
}
if (documents == null)
documents = word.getProperty("Documents").toDispatch();
}
/**
* 设置退出时参数
*
* @param saveOnExit
* boolean true-退出时保存文件,false-退出时不保存文件
*/
public void setSaveOnExit(boolean saveOnExit) {
this.saveOnExit = saveOnExit;
}
/**
* 创建一个新的word文档
*
*/
public void createNewDocument() {
doc = Dispatch.call(documents, "Add").toDispatch();
selection = Dispatch.get(word, "Selection").toDispatch();
}
/**
* 打开一个已存在的文档
*
* @param docPath
*/
public void openDocument(String docPath) {
// closeDocument();
doc = Dispatch.call(documents, “Open”, docPath).toDispatch();
selection = Dispatch.get(word, “Selection”).toDispatch();
}
/**
* 只读方式打开一个加密的文档
*
* @param docPath-文件全名
* @param pwd-密码
*/
public void openDocumentOnlyRead(String docPath, String pwd)
throws Exception {
// closeDocument();
doc = Dispatch.callN(
documents,
“Open”,
new Object[] { docPath, new Variant(false), new Variant(true),
new Variant(true), pwd, “”, new Variant(false) })
.toDispatch();
selection = Dispatch.get(word, “Selection”).toDispatch();
}
/**
* 打开一个加密的文档
* @param docPath
* @param pwd
* @throws Exception
*/
public void openDocument(String docPath, String pwd) throws Exception {
// closeDocument();
doc = Dispatch.callN(
documents,
“Open”,
new Object[] { docPath, new Variant(false), new Variant(false),
new Variant(true), pwd }).toDispatch();
selection = Dispatch.get(word, “Selection”).toDispatch();
}
/**
* 从选定内容或插入点开始查找文本
*
* @param toFindText
* 要查找的文本
* @return boolean true-查找到并选中该文本,false-未查找到文本
*/
@SuppressWarnings("static-access")
public boolean find(String toFindText) {
if (toFindText == null || toFindText.equals(""))
return false;
// 从selection所在位置开始查询
Dispatch find = word.call(selection, "Find").toDispatch();
// 设置要查找的内容
Dispatch.put(find, "Text", toFindText);
// 向前查找
Dispatch.put(find, "Forward", "True");
// 设置格式
Dispatch.put(find, "Format", "True");
// 大小写匹配
Dispatch.put(find, "MatchCase", "True");
// 全字匹配
Dispatch.put(find, "MatchWholeWord", "false");
// 查找并选中
return Dispatch.call(find, "Execute").getBoolean();
}
/**
* 把选定选定内容设定为替换文本
*
* @param toFindText
* 查找字符串
* @param newText
* 要替换的内容
* @return
*/
public boolean replaceText(String toFindText, String newText) {
if (!find(toFindText))
return false;
Dispatch.put(selection, "Text", newText);
return true;
}
/**
* 全局替换文本
*
* @param toFindText
* 查找字符串
* @param newText
* 要替换的内容
*/
public void replaceAllText(String toFindText, String newText) {
while (find(toFindText)) {
Dispatch.put(selection, "Text", newText);
Dispatch.call(selection, "MoveRight");
}
}
/**
* 在当前插入点插入字符串
*
* @param newText
* 要插入的新字符串
*/
public void insertText(String newText) {
Dispatch.put(selection, "Text", newText);
}
/**
* 设置当前选定内容的字体
*
* @param boldSize
* @param italicSize
* @param underLineSize
* 下划线
* @param colorSize
* 字体颜色
* @param size
* 字体大小
* @param name
* 字体名称
* @param hidden
* 是否隐藏
*/
public void setFont(boolean bold, boolean italic, boolean underLine,
String colorSize, String size, String name,boolean hidden) {
Dispatch font = Dispatch.get(selection, "Font").toDispatch();
Dispatch.put(font, "Name", new Variant(name));
Dispatch.put(font, "Bold", new Variant(bold));
Dispatch.put(font, "Italic", new Variant(italic));
Dispatch.put(font, "Underline", new Variant(underLine));
Dispatch.put(font, "Color", colorSize);
Dispatch.put(font, "Size", size);
Dispatch.put(font, "Hidden", hidden);
}
/**
* 文件保存或另存为
*
* @param savePath
* 保存或另存为路径
*/
public void save(String savePath) {
Dispatch.call(Dispatch.call(word, "WordBasic").getDispatch(),
"FileSaveAs", savePath);
}
/**
* 文件保存为html格式
*
* @param savePath
* @param htmlPath
*/
public void saveAsHtml(String htmlPath) {
Dispatch.invoke(doc, "SaveAs", Dispatch.Method, new Object[] {
htmlPath, new Variant(8) }, new int[1]);
}
/**
* 关闭文档
*
* @param val
* 0不保存修改 -1 保存修改 -2 提示是否保存修改
*/
public void closeDocument(int val) {
Dispatch.call(doc, "Close", new Variant(val));//注 是documents而不是doc
documents = null;
doc = null;
}
/**
* 关闭当前word文档
*
*/
public void closeDocument() {
if (documents != null) {
Dispatch.call(documents, "Save");
Dispatch.call(documents, "Close", new Variant(saveOnExit));
documents = null;
doc = null;
}
}
public void closeDocumentWithoutSave() {
if (documents != null) {
Dispatch.call(documents, "Close", new Variant(false));
documents = null;
doc = null;
}
}
/**
* 保存并关闭全部应用
*
*/
public void close() {
closeDocument(-1);
if (word != null) {
// Dispatch.call(word, “Quit”);
word.invoke(“Quit”, new Variant[] {});
word = null;
}
selection = null;
documents = null;
ComThread.Release();//释放com线程。根据jacob的帮助文档,com的线程回收不由java的垃圾回收器处理
}
/**
* 打印当前word文档
*
*/
public void printFile() {
if (doc != null) {
Dispatch.call(doc, "PrintOut");
}
}
/**
* 保护当前档,如果不存在, 使用expression.Protect(Type, NoReset, Password)
*
* @param pwd
* @param type
* WdProtectionType 常量之一(int 类型,只读):
* 1-wdAllowOnlyComments 仅批注
* 2-wdAllowOnlyFormFields 仅填写窗体
* 0-wdAllowOnlyRevisions 仅修订
* -1-wdNoProtection 无保护,
* 3-wdAllowOnlyReading 只读
*
*/
public void protectedWord(String pwd,String type) {
String protectionType = Dispatch.get(doc, "ProtectionType").toString();
if (protectionType.equals("-1")) {
Dispatch.call(doc, "Protect", Integer.parseInt(type), new Variant(true),pwd);
}
}
/**
* 解除文档保护,如果存在
*
* @param pwd
* WdProtectionType 常量之一(int 类型,只读):
* 1-wdAllowOnlyComments 仅批注
* 2-wdAllowOnlyFormFields 仅填写窗体
* 0-wdAllowOnlyRevisions 仅修订
* -1-wdNoProtection 无保护,
* 3-wdAllowOnlyReading 只读
*
*/
public void unProtectedWord(String pwd) {
String protectionType = Dispatch.get(doc, "ProtectionType").toString();
if (!protectionType.equals("0")&&!protectionType.equals("-1")) {
Dispatch.call(doc, "Unprotect", pwd);
}
}
/**
* 返回文档的保护类型
* @return
*/
public String getProtectedType(){
return Dispatch.get(doc, "ProtectionType").toString();
}
/**
* 设置word文档安全级别
*
* @param value
* 1-msoAutomationSecurityByUI 使用“安全”对话框指定的安全设置。
* 2-msoAutomationSecurityForceDisable
* 在程序打开的所有文件中禁用所有宏,而不显示任何安全提醒。 3-msoAutomationSecurityLow
* 启用所有宏,这是启动应用程序时的默认值。
*/
public void setAutomationSecurity(int value) {
word.setProperty("AutomationSecurity", new Variant(value));
}
/**
* 在word中插入标签 labelName是标签名,labelValue是标签值
* @param labelName
* @param labelValue
*/
public void insertLabelValue(String labelName,String labelValue) {
Dispatch bookMarks = Dispatch.call(doc, "Bookmarks").toDispatch();
boolean isExist = Dispatch.call(bookMarks, "Exists", labelName).getBoolean();
if (isExist == true) {
Dispatch rangeItem1 = Dispatch.call(bookMarks, "Item", labelName).toDispatch();
Dispatch range1 = Dispatch.call(rangeItem1, "Range").toDispatch();
String bookMark1Value = Dispatch.get(range1, "Text").toString();
System.out.println("书签内容:"+bookMark1Value);
} else {
System.out.println("当前书签不存在,重新建立!");
//TODO 先插入文字,再查找选中文字,再插入标签
this.insertText(labelValue);
// this.find(labelValue);//查找文字,并选中
this.setFont(true, true,true,”102,92,38”, “20”, “”,true);
Dispatch.call(bookMarks, “Add”, labelName, selection);
Dispatch.call(bookMarks, “Hidden”, labelName);
}
}
/**
* 在word中插入标签 labelName是标签名
* @param labelName
*/
public void insertLabel(String labelName) {
Dispatch bookMarks = Dispatch.call(doc, "Bookmarks").toDispatch();
boolean isExist = Dispatch.call(bookMarks, "Exists", labelName).getBoolean();
if (isExist == true) {
System.out.println("书签已存在");
} else {
System.out.println("建立书签:"+labelName);
Dispatch.call(bookMarks, "Add", labelName, selection);
}
}
/**
* 查找书签
* @param labelName
* @return
*/
public boolean findLabel(String labelName) {
Dispatch bookMarks = Dispatch.call(doc, "Bookmarks").toDispatch();
boolean isExist = Dispatch.call(bookMarks, "Exists", labelName).getBoolean();
if (isExist == true) {
return true;
} else {
System.out.println("当前书签不存在!");
return false;
}
}
/**
* 模糊查找书签,并返回准确的书签名称
* @param labelName
* @return
*/
public String findLabelLike(String labelName) {
Dispatch bookMarks = Dispatch.call(doc, "Bookmarks").toDispatch();
int count = Dispatch.get(bookMarks, "Count").getInt(); // 书签数
Dispatch rangeItem = null;
String lname = "";
for(int i=1;i<=count;i++){
rangeItem = Dispatch.call(bookMarks, "Item", new Variant(i)).toDispatch();
lname = Dispatch.call(rangeItem, "Name").toString();//书签名称
if(lname.startsWith(labelName)){//前面匹配
// return lname.replaceFirst(labelName, “”);//返回后面值
return lname;
}
}
return “”;
}
/**
* 模糊删除书签
* @param labelName
*/
public void deleteLableLike(String labelName){
Dispatch bookMarks = Dispatch.call(doc, “Bookmarks”).toDispatch();
int count = Dispatch.get(bookMarks, “Count”).getInt(); // 书签数
Dispatch rangeItem = null;
String lname = “”;
for(int i=1;i<=count;i++){
rangeItem = Dispatch.call(bookMarks, “Item”, new Variant(i)).toDispatch();
lname = Dispatch.call(rangeItem, “Name”).toString();//书签名称
if(lname.startsWith(labelName)){//前面匹配
Dispatch.call(rangeItem, “Delete”);
count–;//书签已被删除,书签数目和当前书签都要相应减1,否则会报错:集合找不到
i–;
}
}
}
/**
* 获取书签内容
* @param labelName
* @return
*/
public String getLableValue(String labelName){
if(this.findLabel(labelName)){
Dispatch bookMarks = Dispatch.call(doc, “Bookmarks”).toDispatch();
Dispatch rangeItem1 = Dispatch.call(bookMarks, “Item”, labelName).toDispatch();
Dispatch range1 = Dispatch.call(rangeItem1, “Range”).toDispatch();
Dispatch font = Dispatch.get(range1, “Font”).toDispatch();
Dispatch.put(font, “Hidden”, new Variant(false)); //显示书签内容
String bookMark1Value = Dispatch.get(range1, “Text”).toString();
System.out.println(“书签内容:”+bookMark1Value);
// font = Dispatch.get(range1, “Font”).toDispatch();
// Dispatch.put(font, “Hidden”, new Variant(true)); //隐藏书签内容
return bookMark1Value;
}
return “”;
}
public static void main(String[] args) throws Exception {
}
}
采用jacob方式操作文档,经常会出现卡机的现象,所以最后采用poi方式来操作书签。若单纯的操作书签用poi方式还是比较简单的,但要操作表格、文档格式之类的还是用jacob功能比较强大。
Java代码 收藏代码
InputStream input = null;
File docFile = new File( fileName );
HWPFDocument document = null;
try{
input = new FileInputStream(docFile);//加载 doc 文档
document = new HWPFDocument(input);//文件流方式创建hwpf
Bookmarks bookmarks = document.getBookmarks();//文档书签
for(int i=0,length=bookmarks.getBookmarksCount();i