Java 设置 Word 文档编辑限制并允许指定区域编辑

在合同、申请表、报告模板等 Word 文档中,经常需要限制用户修改某些内容。例如,可以将整份文档设为只读,只允许添加批注或修订,也可以锁定大部分正文,仅保留指定区域供用户填写。

这类限制不同于文档打开密码。打开密码用于控制谁可以打开文件,而编辑限制是在文档已经打开的情况下控制允许执行的编辑操作。

下面介绍如何使用 Java 设置 Word 文档的编辑限制,以及如何在受保护的文档中保留指定区域可编辑。

添加依赖

下面的示例通过 Spire.Doc for Java 处理 Word 文档。使用 Maven 时,可在 ​​pom.xml​​ 中添加其 Maven 仓库和依赖:

xml
 代码解读
复制代码
<repositories>
    <repository>
        <id>com.e-iceblue</id>
        <name>e-iceblue</name>
        <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>e-iceblue</groupId>
        <artifactId>spire.doc</artifactId>
        <version>14.7.4</version>
    </dependency>
</dependencies>

使用 Java 设置 Word 文档编辑限制

可以通过 ​​Document.protect()​​ 为 Word 文档设置编辑限制,并使用 ​​ProtectionType​​ 指定允许的操作。

常用的限制类型包括:

ProtectionType允许的操作
​Allow_Only_Reading​仅查看,不允许修改
​Allow_Only_Revisions​可以修改,但修改内容以修订形式记录
​Allow_Only_Comments​只允许添加或修改批注
​Allow_Only_Form_Fields​只允许填写表单域
​No_Protection​不设置编辑限制

下面的示例将 Word 文档设置为只读:

typescript
 代码解读
复制代码
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.ProtectionType;

public class RestrictWordEditing {
    public static void main(String[] args) {

        // 加载 Word 文档
        Document doc = new Document();
        doc.loadFromFile("合同.docx");

        // 设置为只读,并设置解除限制所需的密码
        doc.protect(
                ProtectionType.Allow_Only_Reading,
                "123456"
        );

        // 保存文档
        doc.saveToFile("合同_限制编辑.docx", FileFormat.Docx_2019);
        doc.close();
    }
}

如果需要更换限制方式,只需修改传入的 ​​ProtectionType​​。例如,仅允许用户添加批注:

arduino
 代码解读
复制代码
doc.protect(
        ProtectionType.Allow_Only_Comments,
        "123456"
);

如果文档需要由多人审核,​​Allow_Only_Revisions​​ 会更合适。用户仍然可以修改正文,但这些修改会作为修订保留下来,便于后续接受或拒绝。

对于包含文本表单域、复选框等可填写控件的模板,可以使用 ​​Allow_Only_Form_Fields​​,限制用户只能操作这些表单域。

需要注意,​​protect()​​ 中的密码用于解除编辑限制,并不是打开文档所需的密码。如果需要用户输入密码才能打开文件,应使用文档加密功能,而不是编辑限制。

使用 Java 设置 Word 文档指定区域可编辑

整篇文档设为只读并不总是够用。更常见的一种情况是:合同条款、说明文字等内容不能修改,但需要保留部分位置供用户填写。

Spire.Doc 可以通过 ​​PermissionStart​​ 和 ​​PermissionEnd​​ 标记一个不受编辑限制影响的区域。

下面的示例将文档设置为只读,同时允许第 1 到第 6 个段落继续编辑:

java
 代码解读
复制代码
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.PermissionEnd;
import com.spire.doc.PermissionStart;
import com.spire.doc.ProtectionType;
import com.spire.doc.Section;

public class AllowEditingInSpecifiedRange {
    public static void main(String[] args) {

        // 加载 Word 文档
        Document doc = new Document();
        doc.loadFromFile("合同模板.docx");

        // 创建一对权限区域标记
        PermissionStart start =
                new PermissionStart(doc, "EditableRange1");
        PermissionEnd end =
                new PermissionEnd(doc, "EditableRange1");

        // 获取目标节
        Section section = doc.getSections().get(0);

        // 在第一个段落开头插入起始标记
        section.getParagraphs()
                .get(0)
                .getChildObjects()
                .insert(0, start);

        // 在第六个段落末尾插入结束标记
        section.getParagraphs()
                .get(5)
                .getChildObjects()
                .add(end);

        // 将其他内容设置为只读
        doc.protect(
                ProtectionType.Allow_Only_Reading,
                "123456"
        );

        // 保存结果
        doc.saveToFile(
                "合同模板_限制编辑.docx",
                FileFormat.Docx_2019
        );

        doc.close();
    }
}

​PermissionStart​​ 和 ​​PermissionEnd​​ 需要使用相同的权限 ID:

arduino
 代码解读
复制代码
new PermissionStart(doc, "EditableRange1");
new PermissionEnd(doc, "EditableRange1");

这样 Word 才能把两个标记之间的内容识别为同一个可编辑区域。

上面的代码把起始标记放在第一个段落的第一个子对象之前,把结束标记放在第六个段落的末尾,因此这几个段落之间的内容都属于例外区域。

如果只需要开放段落中的一部分内容,也可以把标记插入到具体的 ​​TextRange​​ 前后,而不是直接以整个段落作为边界。实际项目中,最好根据模板中稳定的书签、占位文本或其他可识别对象定位编辑区域,而不是长期依赖固定的段落索引。

设置多个可编辑区域时注意权限 ID

一份文档可以包含多个可编辑区域,例如分别开放“客户信息”“合同金额”和“备注”。

每个区域应使用自己的权限 ID:

 代码解读
复制代码
CustomerInfo
ContractAmount
Remarks

起始标记和结束标记必须一一对应。

如果多个区域误用了不匹配的 ID,或者只插入了 ​​PermissionStart​​ 而没有正确插入对应的 ​​PermissionEnd​​,生成的文档可能出现编辑范围与预期不一致的问题。

因此,如果编辑区域是根据业务配置动态生成的,建议为每组标记生成明确且唯一的 ID,而不要在所有位置都硬编码同一个名称。

使用 Java 移除 Word 文档编辑限制

如果需要恢复文档的正常编辑状态,可以将保护类型设置为 ​​No_Protection​​:

typescript
 代码解读
复制代码
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.ProtectionType;

public class RemoveEditingRestriction {
    public static void main(String[] args) {

        // 加载受限制的 Word 文档
        Document doc = new Document();
        doc.loadFromFile("合同_限制编辑.docx");

        // 移除编辑限制
        doc.protect(ProtectionType.No_Protection);

        // 保存结果
        doc.saveToFile(
                "合同_解除限制.docx",
                FileFormat.Docx_2019
        );

        doc.close();
    }
}

如果文档之前只设置了整体编辑限制,这样处理即可。

但如果文档中使用过 ​​PermissionStart​​ 和 ​​PermissionEnd​​ 创建例外区域,这些标记属于文档内容结构的一部分。取消保护并不会自动意味着程序后续不再需要这些标记。

如果希望输出一份完全清理后的普通文档,可以同时删除这些对象:

ini
 代码解读
复制代码
import com.spire.doc.Document;
import com.spire.doc.DocumentObject;
import com.spire.doc.FileFormat;
import com.spire.doc.PermissionEnd;
import com.spire.doc.PermissionStart;
import com.spire.doc.ProtectionType;
import com.spire.doc.Section;
import com.spire.doc.documents.Paragraph;

public class RemoveEditingRestrictionAndPermissions {
    public static void main(String[] args) {

        Document doc = new Document();
        doc.loadFromFile("合同模板_限制编辑.docx");

        // 移除编辑限制
        doc.protect(ProtectionType.No_Protection);

        // 删除权限区域标记
        for (int s = 0; s < doc.getSections().getCount(); s++) {
            Section section = doc.getSections().get(s);

            for (int p = 0; p < section.getParagraphs().getCount(); p++) {
                Paragraph paragraph = section.getParagraphs().get(p);

                for (int i = 0;
                     i < paragraph.getChildObjects().getCount();) {

                    DocumentObject obj =
                            paragraph.getChildObjects().get(i);

                    if (obj instanceof PermissionStart
                            || obj instanceof PermissionEnd) {

                        paragraph.getChildObjects().remove(obj);
                    } else {
                        i++;
                    }
                }
            }
        }

        doc.saveToFile(
                "合同模板_解除限制.docx",
                FileFormat.Docx_2019
        );

        doc.close();
    }
}

这里删除对象时没有在 ​​for​​ 循环末尾固定执行 ​​i++​​。原因是删除当前对象以后,后面的对象会移动到当前索引;如果此时继续递增索引,就可能跳过紧邻的下一个权限标记。

编辑限制和文档加密不要混用概念

编辑限制控制的是文档打开以后可以进行哪些操作:

arduino
 代码解读
复制代码
doc.protect(ProtectionType.Allow_Only_Reading, "123456");

而文档加密控制的是没有密码能否打开文件。

因此,“只能看不能改”和“没有密码不能打开”是两个不同的需求。项目中如果同时需要这两层控制,可以分别设置,但不应把 ​​protect()​​ 当作文件访问权限。

另外,Word 的编辑限制主要用于规范正常的文档编辑行为,并不适合作为高强度的数据安全机制。如果真正需要防止未经授权的人员访问内容,仍然应该使用加密、访问控制或其他安全措施。

使用时需要注意的几点

对于固定 Word 模板,可以直接根据段落、表格单元格等结构插入权限标记。但模板一旦经常调整,硬编码类似: https://0571fp.wordpress.com/ https://0571hyfp.wordpress.com/ https://0571clfp.wordpress.com/ https://0571lwfp.wordpress.com/ https://0571zlfp.wordpress.com/ https://0571zxfp.wordpress.com/ https://hzkfp.wordpress.com/ https://0571qcfp.wordpress.com/ https://hzjxfp.wordpress.com/ https://hzypfp.wordpress.com/

scss
 代码解读
复制代码
section.getParagraphs().get(5)

这样的索引会比较脆弱。新增一个标题或说明段落,就可能让原来的编辑区域落到错误位置。

更稳妥的做法是先通过书签、特定占位文本或其他稳定标识找到目标位置,再插入 ​​PermissionStart​​ 和 ​​PermissionEnd​​。

如果文档中已经存在编辑限制或权限区域,在重新设置保护前也应先检查原来的结构,避免重复加入权限标记。

结语

对于需要长期维护的 Word 模板,真正值得固定下来的不是段落序号,而是“哪些业务内容允许编辑”的定位规则。只要编辑区域能够通过稳定的书签、占位符或其他结构标识找到,后续模板增加说明文字或调整排版时,权限设置代码通常不需要跟着频繁修改。

0
0
0
0
评论
未登录
暂无评论