You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java上传PDF添加密码保护报错,输出文件损坏或未加密如何解决?

问题排查

代码中存在几个核心错误直接导致功能异常:

  • 逻辑判断写反:刚通过copy方法把上传文件写入fileStorage路径,文件必然是存在的,但你的判断条件是if(!f.exists() && !f.isDirectory()),只有文件不存在时才触发加密逻辑,加密代码根本不会执行,这是输出未加密PDF的核心原因。
  • 加密文件输出路径错误:给PdfWriter传入的输出流是new FileOutputStream("Protected_"+DIRECTORY),DIRECTORY是存储目录,直接拼接字符串会把内容写到和目录同级、名为Protected_+目录名的错误路径,要么写失败要么生成损坏的非PDF文件。
  • 流资源未主动关闭:FileInputStream、PdfReader等资源使用完未关闭,会导致文件句柄占用,内容无法完全写入磁盘,最终生成损坏文件。
  • 接口返回值不符合需求:当前仅返回原文件名,前端无法拿到加密后的文件路径,无法提供下载入口。

修正后的代码

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public ResponseEntity<List<String>> uploadFiles(@RequestParam("files")List<MultipartFile> multipartFiles) throws IOException, DocumentException {
    List<String> protectedFilenames = new ArrayList<>();
    // 请替换为你实际使用的密码常量和存储目录
    final String OWNER_PASSWORD = "自定义管理员密码";
    final String USER_PASSWORD = "自定义用户打开密码";
    final String DIRECTORY = "你的文件存储目录绝对路径";

    for (MultipartFile file : multipartFiles){
        String originalFilename = StringUtils.cleanPath(file.getOriginalFilename());
        Path originalFileStorage = Paths.get(DIRECTORY, originalFilename).toAbsolutePath().normalize();
        Files.copy(file.getInputStream(), originalFileStorage, StandardCopyOption.REPLACE_EXISTING);

        File originalFile = originalFileStorage.toFile();
        // 修正判断条件:原文件存在且不是目录才执行加密
        if(originalFile.exists() && !originalFile.isDirectory()) {
            // try-with-resources自动关闭所有流资源,避免资源泄漏
            try (FileInputStream fis = new FileInputStream(originalFile);
                 PdfReader pdfReader = new PdfReader(fis);){
                pdfReader.setUnethicalReading(true);
                WriterProperties writerProperties = new WriterProperties();
                writerProperties.setStandardEncryption(OWNER_PASSWORD.getBytes(StandardCharsets.UTF_8),
                        USER_PASSWORD.getBytes(StandardCharsets.UTF_8), 
                        EncryptionConstants.ALLOW_PRINTING,
                        EncryptionConstants.ENCRYPTION_AES_128);
                // 修正输出路径:加密后的文件存在同一目录,加Protected_前缀
                String protectedFilename = "Protected_" + originalFilename;
                Path protectedFilePath = Paths.get(DIRECTORY, protectedFilename).toAbsolutePath().normalize();
                try (PdfWriter pdfWriter = new PdfWriter(new FileOutputStream(protectedFilePath.toFile()), writerProperties);
                     PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter)){
                }
                protectedFilenames.add(protectedFilename);
            } catch (Exception e) {
                e.printStackTrace();
                protectedFilenames.add(originalFilename + "_加密失败");
            }
        }
    }
    return ResponseEntity.ok().body(protectedFilenames);
}

可选优化

如果需要用户上传后直接触发下载,可以调整接口返回值为ResponseEntity<byte[]>,把加密后的文件流直接写入响应体,设置响应头Content-Disposition为attachment; filename=加密后的文件名即可。

内容的提问来源于stack exchange,提问作者Sanele Cele

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 21:54:04