我没有权限将文件保存到文件系统。我可以在网上找到的所有例子都是使用文件系统。我想用Apache POI创建一个密码保护的excel文件,然后把它下载到Servlet.getOutputStream()
我想在内存中创建如下工作簿:
HSSFWorkbook workbook = new HSSFWorkbook();
将数据写入工作簿... 使工作簿密码保护?
然后写工作簿如下输出流:
workbook.write(servlet.getOutputStream());
我没有权限将文件保存到文件系统。我可以在网上找到的所有例子都是使用文件系统。我想用Apache POI创建一个密码保护的excel文件,然后把它下载到Servlet.getOutputStream()
我想在内存中创建如下工作簿:
HSSFWorkbook workbook = new HSSFWorkbook();
将数据写入工作簿... 使工作簿密码保护?
然后写工作簿如下输出流:
workbook.write(servlet.getOutputStream());
我能得到以下用的HttpServlet和HSSFWorkbook .xls文件的工作 - WorkbookServlet.java:
package com.joshden;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
@WebServlet("/workbook")
public class WorkbookServlet extends HttpServlet {
private static final long serialVersionUID = 4087954595439224462L;
private static final String password = "foobar1";
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.ms-excel");
response.addHeader("Content-Disposition", "attachment; filename=password_protected.xls");
createAndWriteEncryptedWorkbook(response.getOutputStream());
}
private void createAndWriteEncryptedWorkbook(OutputStream requestOutputStream) throws IOException {
HSSFWorkbook workbook = new HSSFWorkbook();
populateWorkbook(workbook);
Biff8EncryptionKey.setCurrentUserPassword(password);
workbook.write(requestOutputStream);
workbook.close();
}
private void populateWorkbook(Workbook workbook) {
workbook.createSheet("TestSheet");
// TODO create other sheets, populate cell values
}
}
通过对/ workbook的请求,servlet使用名为TestSheet的工作表在内存中创建HSSF工作簿。密码设置为“foobar1”。它会提示浏览器将其作为名称为password_protected.xls的文件下载。
另见Apache POI - Encryption support。二进制格式(HSSF)的加密仅在Apache POI 3.16后才可用。在写这篇文章的时候,3.16还没有发布,在我的例子中我使用了3.16-beta1。
encyprtion支持指南还提供了创建加密(密码保护).xlsx(XSSF)文件的信息。这是我创建的一个例子,它会提示文件被命名为password_protected.xlsx:
package com.joshden;
import java.io.IOException;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.crypt.EncryptionMode;
import org.apache.poi.poifs.crypt.Encryptor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
@WebServlet("/workbook")
public class WorkbookServlet extends HttpServlet {
private static final long serialVersionUID = 4087954595439224462L;
private static final String password = "foobar1";
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.addHeader("Content-Disposition", "attachment; filename=password_protected.xlsx");
createAndWriteEncryptedWorkbook(response.getOutputStream());
}
private void createAndWriteEncryptedWorkbook(OutputStream requestOutputStream) throws IOException {
XSSFWorkbook workbook = new XSSFWorkbook();
OPCPackage opc = workbook.getPackage();
populateWorkbook(workbook);
try {
POIFSFileSystem fileSystem = new POIFSFileSystem();
opc.save(getEncryptingOutputStream(fileSystem, password));
fileSystem.writeFilesystem(requestOutputStream);
}
finally {
workbook.close();
}
}
private void populateWorkbook(Workbook workbook) {
workbook.createSheet("TestSheet");
// TODO create other sheets, populate cell values
}
private OutputStream getEncryptingOutputStream(POIFSFileSystem fileSystem, String password) throws IOException {
EncryptionInfo encryptionInfo = new EncryptionInfo(EncryptionMode.agile);
Encryptor encryptor = encryptionInfo.getEncryptor();
encryptor.confirmPassword(password);
try {
return encryptor.getDataStream(fileSystem);
}
catch (GeneralSecurityException e) {
// TODO handle this better
throw new RuntimeException(e);
}
}
}
谢谢Joshden,我用apache3.15使用了XSSF第二个解决方案,它给了我下面的异常:我想我必须等待3.16 :) :javax.el.ELException:java.lang.NoSuchMethodError:org.apache.poi.poifs.crypt.EncryptionInfo。
您正在编写一个没有对文件系统的写入权限的Servlet吗? – EJP
截至目前,我已经实现了[ChunkedCipherOutputStream](https://svn.apache.org/repos/asf/poi/trunk/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java) ,它在加密过程中使用,以使用temp。文件,以便能够加密较大的文件而不会受到内存限制。如果你想单独留在内存中,你需要在本地修补该类。 – kiwiwings
...还有一些其他地方需要修补:(例如[AgileEncryptor](https://svn.apache.org/repos/asf/poi/trunk/src/ooxml/java/ org/apache/poi/poifs/crypt/agile/AgileEncryptor.java)类 – kiwiwings