需求:点击下载---》弹窗加入水印(可加可不加,加上就有水印,没有不加水印),点击之后下载文件
处理思路及流程
前端:
用户点击下载 → 收集水印参数 → 调用后端API → 处理响应为Blob → 触发文件下载
后端:
接收请求 → 验证权限 → 从Minio获取文件 → 判断文件类型 → 添加水印 → 返回处理后的文件流
前端
<template><button @click="downloadFileWithWatermark">下载文件并添加水印</button>
</template><script setup>
import axios from 'axios';const downloadFileWithWatermark = async () => {const watermarkText = '飞天小女警'; // 自定义水印内容const fileUrl = 'your_minio_file_url'; // MinIO 上文件的 URLtry {const response = await axios.get('/api/download', {params: {fileUrl,watermarkText},responseType: 'blob'});const url = window.URL.createObjectURL(new Blob([response]));const link = document.createElement('a');link.href = url;link.setAttribute('download', 'file_with_watermark.pdf'); // 根据文件类型修改文件名document.body.appendChild(link);link.click();document.body.removeChild(link);} catch (error) {console.error('下载失败:', error);}
};
</script>
Java
加jar包
<!-- Apache PDFBox 用于处理 PDF --><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.24</version></dependency>
import io.minio.MinioClient;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;@RestController
public class FileDownloadController {@Autowiredprivate MinioClient minioClient;@GetMapping("/api/download")public byte[] downloadFileWithWatermark(@RequestParam String fileUrl, @RequestParam String watermarkText) throws Exception {// 解析 MinIO 存储桶和对象名称String[] parts = fileUrl.split("/");String bucketName = parts[parts.length - 2];String objectName = parts[parts.length - 1];// 获取字节InputStream inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());byte[] content = inputStreamToByteArray(inputStream);inputStream.close();byte[] fileBytes;if (objectName.toLowerCase().endsWith(".pdf")) {fileBytes = addWatermarkToPdf(content, watermarkText);} else if (objectName.toLowerCase().endsWith(".jpg") || objectName.toLowerCase().endsWith(".png")) {fileBytes = addWatermarkToImage(content, watermarkText);} else {throw new IllegalArgumentException("不支持的文件类型");}// 设置响应头HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);headers.setContentDispositionFormData("attachment", URLEncoder.encode(objectName, StandardCharsets.UTF_8));return fileBytes}private byte[] inputStreamToByteArray(InputStream inputStream) throws IOException {ByteArrayOutputStream buffer = new ByteArrayOutputStream();int nRead;byte[] data = new byte[16384];while ((nRead = inputStream.read(data, 0, data.length)) != -1) {buffer.write(data, 0, nRead);}buffer.flush();return buffer.toByteArray();}private byte[] addWatermarkToPdf(byte[] content, String watermarkText) throws IOException {try (PDDocument document = PDDocument.load(content)) {for (PDPage page : document.getPages()) {try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {contentStream.setFont(PDType1Font.HELVETICA_BOLD, 20);contentStream.setNonStrokingColor(Color.LIGHT_GRAY);contentStream.beginText();contentStream.newLineAtOffset(100, 100);contentStream.showText(watermarkText);contentStream.endText();}}ByteArrayOutputStream outputStream = new ByteArrayOutputStream();document.save(outputStream);return outputStream.toByteArray();}}private byte[] addWatermarkToImage(byte[] content, String watermarkText) throws IOException {java.io.ByteArrayInputStream bis = new java.io.ByteArrayInputStream(content);BufferedImage image = ImageIO.read(bis);Graphics2D g2d = image.createGraphics();g2d.setColor(Color.LIGHT_GRAY);g2d.setFont(new Font("Arial", Font.BOLD, 20));g2d.drawString(watermarkText, 100, 100);g2d.dispose();ByteArrayOutputStream bos = new ByteArrayOutputStream();ImageIO.write(image, "png", bos);return bos.toByteArray();}
}
修改pdf加水印,因为没有对应的字体没输入文字水印之后pdf文件会打不开
所以现在改进方法:
从网站下载对应字体的ttf,我是从c:/windows/fonts/ 下找到对应的 “simhei.ttf”文件复制在“ssrc/main/resources/fonts
”文件夹下;
修改对应加水印的代码,如下:
private byte[] addWatermarkToPdf(byte[] content, String watermarkText) throws IOException {try (PDDocument document = PDDocument.load(content)) {// 使用try-with-resources确保字体流关闭try (InputStream fontStream = getClass().getResourceAsStream("/fonts/simhei.ttf")) {//PDTrueTypeFont font = PDTrueTypeFont.loadTTF(document, fontStream);注意这是个大坑!PDTType0Font font = PDTType0Font.load(document, fontStream);for (PDPage page : document.getPages()) {try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {contentStream.setFont(font, 20);contentStream.setNonStrokingColor(Color.LIGHT_GRAY);contentStream.beginText();contentStream.newLineAtOffset(100, 100);contentStream.showText(watermarkText);contentStream.endText();}}}ByteArrayOutputStream outputStream = new ByteArrayOutputStream();document.save(outputStream);return outputStream.toByteArray();}
}
这样就基本都可以出来了,样式什么的需要后续自己调节。