Java 在JSF中读取和显示加密的PDF文件

Java 在JSF中读取和显示加密的PDF文件,java,jsf,pdf,encryption,primefaces,Java,Jsf,Pdf,Encryption,Primefaces,据我所知,我实现了函数downloadPDF(),它从文件系统读取PDF文件并在浏览器中显示。此功能按预期工作 此外,我还有一个类EncryptionService,它允许我加密和/或解密给定的文件。这也可以按预期工作 不幸的是,似乎无法读取PDF文件、解密并在浏览器中显示。最后,浏览器试图反复加载文件,但没有显示任何内容 下面的代码显示了我对BalusC的PDF处理程序的简单修改 public void showDocument(String path, boolean decrypt) th

据我所知,我实现了函数
downloadPDF()
,它从文件系统读取PDF文件并在浏览器中显示。此功能按预期工作

此外,我还有一个类
EncryptionService
,它允许我加密和/或解密给定的文件。这也可以按预期工作

不幸的是,似乎无法读取PDF文件、解密并在浏览器中显示。最后,浏览器试图反复加载文件,但没有显示任何内容

下面的代码显示了我对BalusC的PDF处理程序的简单修改

public void showDocument(String path, boolean decrypt) throws IOException, InvalidKeyException {

    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();

    File file = new File(path);
    BufferedInputStream input = null;
    BufferedOutputStream output = null;

    try {
        if(!decrypt)
            input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);
        else {
            // update MessageDigets, return Key
            cipher.init(Cipher.DECRYPT_MODE, genKey(passphrase));

            input = new BufferedInputStream(new CipherInputStream(new FileInputStream(file), cipher), DEFAULT_BUFFER_SIZE);
        }

        response.reset();
        response.setHeader("Content-Type", "application/pdf");
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setHeader("Content-Disposition", "inline; filename=\"" + path + "\"");

        output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);

        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        int length;
        while ((length = input.read(buffer)) > 0) {
            output.write(buffer, 0, length);
        }

        output.flush();
    } finally {
        try {
            input.close();
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    facesContext.responseComplete();
}

发生了什么事

就像控制台错误所说的那样

网络::错误内容长度不匹配

这表明响应正文中返回的内容的实际大小与响应的
内容长度
标题中指示的大小不匹配

为什么会这样

差异的原因包括两个因素:

  • 加密通常会增加加密内容的大小。加密过程需要使用密码对内容进行模糊处理,这通常意味着加入一些东西,否则内容将无法使用。另一方面,解密将使内容恢复到原始大小

  • 浏览器易于缓存。如果您提供不同文件的次数足够多(使用相同的文件名),您的浏览器可能只会确定它是具有相同内容的同一文件,而只提供文件的缓存版本。在您的例子中,您声明了对加密文件的引用,访问该文件,对其进行解密,然后将解密的内容写回到加密版本的同一文件句柄中

  • 基于磁盘的I/O与RAM或CPU不是100%同步的。写入磁盘和从磁盘读取仍然以RAM等待磁盘的形式带来开销

修复

  • 为操作中涉及的每个文件生成随机/不同的文件名。这意味着加密内容有一个单独的文件名,解密表单有一个单独的文件名

  • 如上所述,使用不同的
    File
    access变量,将不同的输出流打开到不同的文件

相关:


具体是在什么点发生循环?
showDocument
是否完成执行?返回浏览器的内容是什么?在浏览器的“网络”选项卡中查看响应代码、标题和响应正文package@kolossus,
showDocument
未正确完成。在新选项卡中加载内容时,“网络”选项卡不会显示任何内容。当尝试在同一选项卡中加载时,它显示system.jsf(当前站点)。几秒钟后,这将导致错误
net::ERR\u CONTENT\u LENGTH\u MISMATCH
。因此,您可以这样做:设置为
CONTENT LENGTH的内容
!=现实中发生了什么。你能给我一个提示,这个值应该是多少吗?我真的不明白如果文件的长度变长,内容的长度应该是多少。首先,加密可能会增大文件的大小,而解密则会逆转这种效果。也就是说,您通常不希望为文件的两个变体重用相同的变量:缓存和一般I/O不可靠性可能会导致问题。因此,为了进行实验,对pdf的加密和解密形式使用单独的
文件
s;不要同时重复使用
文件