烦恼一般都是想太多了。

0%

利用poi对docx文档进行加密

事情的起因是,公司业务上对于某一类型的文书是在客户端生成,然后上传到服务器,openoffice转换成pdf文书,然后展示给用户。以避免用户对文书进行的修改。而,docx模板替换后生成的文书,转换成pdf后会丢失格式。最为明显的是,对于图片进行旋转后,docx显示正常,而openoffice无效果的问题。

解决方案

最终,协商出一个折衷的方法,就是对docx文档进行加密,这样展示的话就没有什么问题了。虽然这并不能避免进行复制后到其他地方进行操作,但也是最快捷的解决办法了。

加密级别

对文档的加密有好几个级别,

  • 文档的访问限制
  • 文档的修改限制
  • 文档内部分内容的修改限制

POI的实现

文档的修改限制

这个级别的加密,用户想要修改必须输入正确的密码才能继续修改,而且POI实现起来也比较简单:


try {
XWPFDocument document = new XWPFDocument();
document.createParagraph().createRun().setText("此文档禁止修改");
OutputStream os = new FileOutputStream("test.docx");
document.enforceReadonlyProtection("foobar", HashAlgorithm.md5);
document.write(os);

os.close();
} catch (Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}

这样加密了以后,文档打开阅览没有问题,但是一旦需要修改就要求输入密码了。

文档访问加密

这个级别的加密,打开文件都需要输入密码。密码错误则无法打开。
我们用上面的文档来进行加密。

        POIFSFileSystem fs = new POIFSFileSystem();
EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
// EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile, CipherAlgorithm.aes192, HashAlgorithm.sha384, -1, -1, null);

Encryptor enc = info.getEncryptor();
enc.confirmPassword("foobaa");

// Read in an existing OOXML file
try {
OPCPackage opc = OPCPackage.open(new File("test.docx"), PackageAccess.READ_WRITE);
OutputStream os = enc.getDataStream(fs);
opc.save(os);
opc.close();

// Write out the encrypted version
FileOutputStream fos = new FileOutputStream("docx_e.docx");
fs.writeFilesystem(fos);
fos.close();
} catch (Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}

这样操作过后,打开文档就需要输入密码,否则打开失败。

同时,我们可以看到,我们可以使用不同的密码来进行不同级别的加密限制。

部分内容的修改限制

这个级别的加密,可以使有的部分可以修改,有的内容禁止修改。我们使用对文件整体修改的例子上,对部分内容不加限制的代码如下:

                try {
XWPFDocument document = new XWPFDocument();
document.createParagraph().createRun().setText("此文档禁止修改");

// 注意这里
CTPermStart ctPermStart = document.getDocument().getBody().addNewPermStart();
ctPermStart.setEdGrp(STEdGrp.EVERYONE);
ctPermStart.setId("123456"); //note the Id
document.createParagraph().createRun().setText("此处可以修改");
document.getDocument().getBody().addNewPermEnd().setId("123456"); //note the same Id
// 注意 setId。
OutputStream os = new FileOutputStream("test.docx");
document.enforceReadonlyProtection("foobar", HashAlgorithm.md5);
document.write(os);

os.close();
} catch (Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}
}

如此之后,我们可以发现,后面的这句文字可以修改,而其他的都不能修改。