附件文件增加水印

运行效果

附件上传时,文件中没有水印,下载前,加上水印。

图 0

实现方法

  1. 获取附件中文件的 storeFileName,用于在服务中获取文件
  2. 调用自定义的服务,传入 storeFileName 参数,使用平台提供的 StorageClient 类下载文件
  3. 使用第三方工具给文件增加水印
  4. 返回文件流,浏览器预览或下载文件

后端开发

添加本地 pdf 水印依赖 jar 包

在服务上“设置依赖”,如下图所示

图 4

添加“本地 jar”(也可以添加 maven 配置),上传 jar 包

图 5

图 6

添加自定义服务

自定义服务 addWatermark,设置四个请求参数

  • storeFileName:用于获取文件
  • realFileName:用于返回文件名
  • operateType:用于设置响应头,是预览还是下载
  • watermark:自定义水印内容

图 3

点击“写代码”在系统自动生成的服务方法中实现增加水印并返回,代码如下:

public void addWatermark(String storeFileName,String realFileName,String operateType,String watermark) throws Exception {
    HttpServletResponse response = SpringWebUtil.getResponse();

    // 调用 service 获取加了水印的文件流
    try(InputStream fis = this.addWatermark(storeFileName, watermark)){
        response.reset();
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/octet-stream");
        // 参数为 attachment 代表下载,参数为 inline 代表预览,预览前提是文件支持预览的,并且 contentType 不为 application/octet-stream
        // 根据 operateType 参数值,确定是下载还是预览
        if ("download".equals(operateType)) {
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + new String(realFileName.getBytes("utf-8"), "ISO-8859-1"));
            response.setContentType("application/octet-stream");

        } else {
            response.setHeader("Content-Disposition",
                    "inline;filename=" + new String(realFileName.getBytes("utf-8"), "ISO-8859-1"));
            response.setContentType("application/pdf");

        }

        byte[] bytes = new byte[1024];
        int len;
        while ((len = fis.read(bytes)) != -1) {
            response.getOutputStream().write(bytes, 0, len);
        }
        response.flushBuffer();
        fis.close();
    }
}

增加水印

在 service 文件中添加增加水印的方法 addWatermark(String storeFileName, String watermark)

  • 用 storeFileName 获取文件流
  • 使用第三方工具给 pdf 文件的第一页增加水印(代码来自于网络)
  • 返回加了水印的文件流

增加水印方法的代码如下:

 //增加水印
public InputStream addWatermark(String storeFileName, String watermark) throws Exception {
    // 获取文档
    StorageApi instance = StorageClient.getInstance();
    Response response = instance.getFileAsFeignResponse(storeFileName, storeFileName);
    InputStream is=response.body().asInputStream();

    PdfDocument pdf = new PdfDocument();
    // 加载文档
    pdf.loadFromStream(is);
    PdfPageCollection pageList= pdf.getPages();
    //给每一页都新增水印,最多处理5页
    for(int i=0;i<pageList.getCount()&&i<5;i++) {
        PdfPageBase page = pdf.getPages().get(i);
        // 插入水印
        insertWatermark(page, watermark);
    }

    // 保存文档
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    pdf.saveToStream(os);
    byte[] buffer = os.toByteArray();
    InputStream sbs = new ByteArrayInputStream(buffer);
    pdf.close();

    // 返回已加水印的文件流
    return sbs;
}

//pdf 页面新增水印
static void insertWatermark(PdfPageBase page, String watermark) {
    Dimension2D dimension2D = new Dimension();
    dimension2D.setSize(page.getCanvas().getClientSize().getWidth() / 2,
            page.getCanvas().getClientSize().getHeight() / 3);
    PdfTilingBrush brush = new PdfTilingBrush(dimension2D);
    brush.getGraphics().setTransparency(0.3F);
    brush.getGraphics().save();
    brush.getGraphics().translateTransform((float) brush.getSize().getWidth() / 2,
            (float) brush.getSize().getHeight() / 2);
    brush.getGraphics().rotateTransform(-45);
    PdfTrueTypeFont font1 = new PdfTrueTypeFont(new Font("宋体", Font.PLAIN, 14), true);
    brush.getGraphics().drawString(watermark, font1, PdfBrushes.getViolet(), 0, 0,
            new PdfStringFormat(PdfTextAlignment.Center));
    brush.getGraphics().restore();
    brush.getGraphics().setTransparency(1);
    Rectangle2D loRect = new Rectangle2D.Float();
    loRect.setFrame(new Point2D.Float(0, 0), page.getCanvas().getClientSize());
    page.getCanvas().drawRectangle(brush, loRect);
}

前端开发

从附件中获取 storeFileName

附件上传后,存入数据库中的数据是一个 JSON 数组,代码如下。主要包括两项内容,一是存储文件名 storeFileName,二是真实文件名 realFileName。

[{
    "storeFileName":"anoy_CA30A885715000016616595C1A40134E外部应用导入说明.pdf",
    "realFileName":"外部应用导入说明.pdf"
}]

调用自定义服务下载或预览文件

在附件组件的“预览”事件中,给 event.detail.file._previewUrl 赋值为自定义服务的 url,从而替代了附件组件默认的预览 url,代码如下:

react 代码

onUpload10Preview = (event) => {
    let { detail: { file } } = event;  
    let {storeFileName,realFileName} = file;   
    let url = this.getServiceUrl("/main/dataservice/addwatermark?storeFileName="
        + storeFileName + "&realFileName=" + realFileName + "&operateType=preview&watermark="+(new Date()).getTime());
    //点击附件预览跳转到指定路径,可用于下载前给文件加水印
    event.detail.file._previewUrl = url;
}

vue 代码

let onUpload8Preview = (event) => {
    let {detail:{file}} = event;
    let {storeFileName,realFileName} = file;   
    let url = $page.getServiceUrl("/main/file/addwatermark?storeFileName="
        + storeFileName + "&realFileName=" + realFileName + "&operateType=preview&watermark="+(new Date()).getTime());
    //点击附件预览跳转到指定路径,可用于下载前给文件加水印
    event.detail.file._previewUrl = url;
}

在附件组件的“下载”事件中,给 event.detail.file.downloadUrl 赋值为自定义服务的 url,从而替代了附件组件默认的下载 url,代码如下:

react 代码

onUpload10Download = (event) => {
    let { detail: { file } } = event;

    let {storeFileName,realFileName} = file;   
    let url = this.getServiceUrl("/main/dataservice/addwatermark?storeFileName="
        + storeFileName + "&realFileName=" + realFileName + "&operateType=download&watermark="+(new Date()).getTime());
    //点击附件下载跳转到指定路径,可用于下载前给文件加水印
    event.detail.file.downloadUrl = url;
}

vue 代码

let onUpload8Download = (event) => {
    let {detail:{file}} = event;
    let {storeFileName,realFileName} = file;   
    let url = $page.getServiceUrl("/main/file/addwatermark?storeFileName="
        + storeFileName + "&realFileName=" + realFileName + "&operateType=download&watermark="+(new Date()).getTime());
    //点击附件下载跳转到指定路径,可用于下载前给文件加水印
    event.detail.file.downloadUrl = url;
}

关于字体

上面代码中,添加水印使用了“宋体”,平台本身不带字体,需上传字体后才能使用,参考《增加字体

results matching ""

    No results matching ""