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
相关产品推荐
相关产品推荐

