当前位置: 首页 > news >正文

springboot生成PDF,并且添加水印

/***  导出调查问卷*/@ApiLog("导出调查问卷")@PostMapping("/print/{id}")@ApiOperationSupport(order = 23)@ApiOperation(value = "导出报告", notes = "导出报告")public void print(@PathVariable Long id, HttpServletResponse response) {BackendGradeEntity record = backendGradeService.getById(id);//如果record为空,直接返回错误信息if(record == null){throw new RuntimeException("未找到该记录");}Map<String, Object> values = new HashMap<>();Field[] fields = BackendGradeEntity.class.getDeclaredFields();//通过反射拿到对象的属性名并且赋值给mapfor (Field field : fields) {field.setAccessible(true);try {Object value = field.get(record);values.put(field.getName(), value);} catch (IllegalAccessException e) {// 处理访问异常e.printStackTrace();}}//通过用户id查询用户信息BackendUserinformationEntity user = backendUserinformationService.getById(record.getUserId());//获取用户性别Integer sex = null;if (user!= null){sex = user.getSex();}//添加用户性别values.put("sex", sex==1?"男":"女");String totalTime = values.get("totalTime").toString();double timeInSeconds = Double.parseDouble(totalTime) * 60; // 将分钟转换为秒int minutes = (int) timeInSeconds / 60;int seconds = (int) timeInSeconds % 60;String formattedTime = minutes + "分钟" + seconds + "秒";values.put("totalTime", formattedTime);//增加打印日期为当前日期values.put("printDate", DateUtil.format(LocalDate.now(), "yyyy年MM月dd日"));//修改map中的startTime 和 endTime 格式由2023-09-19T15:34:25  为 2023-09-19 15:34:25String startTime = values.get("startTime").toString().replace("T", " ");String endTime = values.get("endTime").toString().replace("T", " ");values.put("startTime", startTime);values.put("endTime", endTime);//将 正确率 错误率 未答题率 乘100再填回,因为数据存的是小数values.put("errorRate", Double.parseDouble(values.get("errorRate").toString())*100);values.put("accuracy", Double.parseDouble(values.get("accuracy").toString())*100);values.put("unansweredRate", Double.parseDouble(values.get("unansweredRate").toString())*100);String fileName = null;String tplName = null;if(true){fileName = "报告";tplName = "intuitionReport.ftl";}fileName = fileName + "-" + (values.get("userName")==null?UUID.randomUUID():values.get("userName"));String file = printer.print(values, tplName, fileName);//下载文件InputStream inStream = null;try {inStream = new FileInputStream(file);response.reset();response.setContentType("application/pdf");response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(new File(file).getName(), "UTF-8"));response.setCharacterEncoding("UTF-8");IoUtil.copy(inStream, response.getOutputStream());} catch (Exception e) {e.printStackTrace();} finally {if (inStream != null) {try { inStream.close(); } catch (IOException e) { e.printStackTrace(); }}}}/***  批量导出报告*/@ApiLog("批量导出报告")@PostMapping("/print/batch")@ApiOperationSupport(order = 23)@ApiOperation(value = "批量导出", notes = "批量导出报告")public void printBatch(@RequestParam String ids, HttpServletResponse response) {List<BackendGradeEntity> records = backendGradeService.listByIds(Func.toLongList(ids));String uuid = UUID.randomUUID().toString();int size = records.size();DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");String zipName = LocalDateTime.now().format(formatter)+"-"+size+"records.zip";Path zipPath = Paths.get(pathProperties.getPdf(), zipName);File zipFile = zipPath.toFile();if(zipFile.exists()){zipFile.delete();//如果文件存在则先删除旧的文件}List<File> files = null;try{if(!zipFile.getParentFile().exists()){Files.createDirectories(zipPath.getParent());}files = records.stream()
//				.filter(j -> j.getStatus() == 4).map(record -> {Map<String, Object> values = new HashMap<>();Field[] fields = BackendGradeEntity.class.getDeclaredFields();//通过反射拿到对象的属性名并且赋值给mapfor (Field field : fields) {field.setAccessible(true);try {Object value = field.get(record);values.put(field.getName(), value);} catch (IllegalAccessException e) {// 处理访问异常e.printStackTrace();}}//通过用户id查询用户信息BackendUserinformationEntity user = backendUserinformationService.getById(record.getUserId());//获取用户性别Integer sex = null;if (user!= null){sex = user.getSex();}//添加用户性别values.put("sex", sex==1?"男":"女");//处理总时长String totalTime = values.get("totalTime").toString();double timeInSeconds = Double.parseDouble(totalTime) * 60; // 将分钟转换为秒int minutes = (int) timeInSeconds / 60;int seconds = (int) timeInSeconds % 60;String formattedTime = minutes + "分钟" + seconds + "秒";values.put("totalTime", formattedTime);//增加打印日期为当前日期values.put("printDate", DateUtil.format(LocalDate.now(), "yyyy年MM月dd日"));//修改map中的startTime 和 endTime 格式由2023-09-19T15:34:25  为 2023-09-19 15:34:25String startTime = values.get("startTime").toString().replace("T", " ");String endTime = values.get("endTime").toString().replace("T", " ");values.put("startTime", startTime);values.put("endTime", endTime);//将 正确率 错误率 未答题率 乘100再填回,因为数据存的是小数values.put("errorRate", Double.parseDouble(values.get("errorRate").toString())*100);values.put("accuracy", Double.parseDouble(values.get("accuracy").toString())*100);values.put("unansweredRate", Double.parseDouble(values.get("unansweredRate").toString())*100);String fileName = null;String tplName = null;if(true){fileName = "报告";tplName = "intuitionReport.ftl";}fileName = fileName + "-" + (values.get("userName")==null?UUID.randomUUID():values.get("userName")+UUID.randomUUID().toString());String f = printer.print(values, tplName, uuid+"/"+fileName);return new File(f);}).collect(Collectors.toList());//			Path tempDir = Files.createTempDirectory("temp");
//			List<File> copiedFiles = new ArrayList<>();
//			for (File file : files) {
//				Path source = Paths.get(file.getPath());
//				Path destination = tempDir.resolve(file.getName());
//				Files.copy(source, destination);
//				copiedFiles.add(destination.toFile());
//			}
//			// 在这里调用添加水印的方法
//			PDFWatermarkExample.addWatermarkExample(copiedFiles);
//
//			files = copiedFiles;
//			try {
//				// 删除临时文件夹及其所有文件
//				FileUtils.deleteDirectory(tempDir.toFile());
//			} catch (IOException e) {
//				// 处理删除错误
//				e.printStackTrace();
//			}ZipTool.zipFile(files, zipPath.toFile().getAbsolutePath());}catch(Exception e){e.printStackTrace();}finally {if(files != null){for(File f : files){if(f.exists()) f.delete();}}Path dirPath = Paths.get(pathProperties.getPdf(), uuid);if(dirPath.toFile().exists()){dirPath.toFile().delete();}}//下载文件InputStream inStream = null;try {if(!zipFile.exists()){return ;}inStream = new FileInputStream(zipFile);response.reset();response.setContentType("application/zip");response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(zipFile.getName(), "UTF-8"));response.setCharacterEncoding("UTF-8");IoUtil.copy(inStream, response.getOutputStream());} catch (Exception e) {e.printStackTrace();} finally {if (inStream != null) {try { inStream.close(); } catch (IOException e) { e.printStackTrace(); }}}//这里删除临时文件夹内的压缩包,因为存着也没什么用浪费空间//通过zipPath获取绝对路径String absolutePath = zipPath.toFile().getAbsolutePath();//删除absolutepath文件夹,以及所有文件deleteDirectoryRecursively(new File(absolutePath));}

下面是加水印

package org.springblade.common.tool;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;import java.io.File;
import java.io.FileOutputStream;
import java.util.List;public class PDFWatermarkExample {public static void addWatermark(String inputFile, String outputFile, String watermarkText) {try {PdfReader reader = new PdfReader(inputFile);PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputFile));int numberOfPages = reader.getNumberOfPages();for (int i = 1; i <= numberOfPages; i++) {PdfContentByte content = stamper.getUnderContent(i);PdfGState gs = new PdfGState();gs.setFillOpacity(0.5f); // 设置水印透明度content.setGState(gs);ColumnText.showTextAligned(content,Element.ALIGN_CENTER,new Phrase(watermarkText, new Font(Font.FontFamily.HELVETICA, 40)),reader.getPageSizeWithRotation(i).getWidth() / 2,reader.getPageSizeWithRotation(i).getHeight() / 2,45);}stamper.close();reader.close();} catch (Exception e) {e.printStackTrace();}}public static void addWatermarkMulti(String inputFile, String outputFile, String watermarkText) {try {PdfReader reader = new PdfReader(inputFile);PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputFile));int numberOfPages = reader.getNumberOfPages();for (int i = 1; i <= numberOfPages; i++) {PdfContentByte content = stamper.getOverContent(i);PdfGState gs = new PdfGState();gs.setFillOpacity(0.05f); // 设置水印透明度content.setGState(gs);Rectangle pageSize = reader.getPageSizeWithRotation(i);float pageWidth = pageSize.getWidth();float pageHeight = pageSize.getHeight();// 设置水印间隔float xInterval = 200; // X轴间隔float yInterval = 50; // Y轴间隔// 计算水印个数int xCount = (int) Math.ceil(pageWidth / xInterval);int yCount = (int) Math.ceil(pageHeight / yInterval);// 平铺水印for (int x = 0; x < xCount; x++) {for (int y = 0; y < yCount; y++) {float xPosition = x * xInterval;float yPosition = y * yInterval;ColumnText.showTextAligned(content,Element.ALIGN_CENTER,new Phrase(watermarkText, new Font(Font.FontFamily.HELVETICA, 40)),xPosition,yPosition,0);}}}stamper.close();reader.close();} catch (Exception e) {e.printStackTrace();}}public static void addWatermarkExample(List<File> files) {// 在这里编写添加水印的代码逻辑,使用上面提到的添加水印的示例代码for (File file : files) {addWatermark(file.getPath(), file.getPath(), "Watermark Text");}}public static void main(String[] args) {String inputFile = "C:\\Users\\admin\\Downloads\\123.pdf";String outputFile = "C:\\Users\\admin\\Downloads\\789.pdf";String watermarkText = "zhijue.com";addWatermarkMulti(inputFile, outputFile, watermarkText);}
}

相关文章:

springboot生成PDF,并且添加水印

/*** 导出调查问卷*/ApiLog("导出调查问卷")PostMapping("/print/{id}")ApiOperationSupport(order 23)ApiOperation(value "导出报告", notes "导出报告")public void print(PathVariable Long id, HttpServletResponse response…...

Tensorflow2.0:CNN、ResNet实现MNIST分类识别

以下仅是个人的学习笔记 &#xff0c;内容可能是错误 CNN&#xff1a; import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers# 导入数据 (x_train, y_train), (x_test, y_test) keras.datasets.mnist.load_data()# 数据预处理 x_tra…...

本地jar导入maven

一、通过dependency引入 1.1. jar包放置&#xff0c;建造lib目录 1.2. pom.xml文件 <dependency><groupId>zip4j</groupId><artifactId>zip4j</artifactId><version>1.3.2</version><!--system&#xff0c;类似provided&#x…...

数据结构与算法【堆】的Java实现

前言 之前已经说过堆的特点了&#xff0c;具体文章在数据结构与算法【队列】的Java实现-CSDN博客。因此直接实现堆的其他功能。 建堆 所谓建堆&#xff0c;就是将一个初始的堆变为大顶堆或是小顶堆。这里以大顶堆为例。展示如何建堆。 找到最后一个非叶子节点从后向前&…...

同创永益联合红帽打造一站式数字韧性解决方案

随着AI技术的快速兴起&#xff0c;IT技术已成为推动业务持续增长的重要驱动力&#xff0c;这要求企业不断尝试新事物&#xff0c;改变固有流程&#xff0c;加强IT技术与业务的合作&#xff0c;同时提升数字韧性能力&#xff0c;以实现业务目标。10月26日&#xff0c;红帽2023中…...

c++ call_once 使用详解

c call_once 使用详解 std::call_once 头文件 #include <mutex>。 函数原型&#xff1a; template<class Callable, class... Args> void call_once(std::once_flag& flag, Callable&& f, Args&&... args);flag&#xff1a;标志对象&#xf…...

【rosrun diagnostic_analysis】报错No module named rospkg | ubuntu 20.04

ubuntu20.04使用指令报错 现象 rosrun diagnostic_analysis export_csv.py my.bag -d ~/Desktop报错 Traceback (most recent call last): File "/opt/ros/noetic/lib/diagnostic_analysis/export_csv.py", line 40, in <module> import roslib; roslib.load_m…...

高防CDN有什么作用?

分布式拒绝服务攻击&#xff08;DDoS攻击&#xff09;是一种针对目标系统的恶意网络攻击行为&#xff0c;DDoS攻击经常会导致被攻击者的业务无法正常访问&#xff0c;也就是所谓的拒绝服务。 常见的DDoS攻击包括以下几类&#xff1a; 网络层攻击&#xff1a;比较典型的攻击类…...

盛元广通开放实训室管理系统2.0

开放实训室管理系统是一种基于网络和数据库的实训室信息管理系统&#xff0c;旨在提高实训室的管理水平&#xff0c;实现实训资源的优化配置和高效利用。该系统通常包括用户管理、设备管理、课程管理、考核管理等功能模块&#xff0c;能够实现实训室的预约、设备借用、课程安排…...

3D建模基础教程:编辑多边形功能命令快捷方式

一、打开3D软件并创建新模型 首先&#xff0c;打开你的3D建模软件&#xff0c;比如Blender、Maya或3ds Max。然后&#xff0c;创建一个新的3D模型。你可以使用基本几何体来创建模型&#xff0c;也可以导入现有的模型。 二、进入编辑多边形模式 在主工具栏中&#xff0c;找到并…...

SaleSmartly新增AI意图识别触发器!让客户享受更精准的自动化服务

AI意图识别技术是对话式AI中很重要的组成部分&#xff0c;通俗点来说就是一种可以识别用户在对话中表达的意图的技术。通过对大量数据的分析和学习&#xff0c;AI可以理解用户想要获得的信息&#xff0c;并根据这些信息来采取相应的行动或提供相应的响应。而在对话式AI中&#…...

计算机毕业设计选题推荐-个人博客微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…...

一篇详解,Postman设置token依赖步骤

前言 postman做接口测试时&#xff0c;大多数的接口必须在有token的情况下才能运行&#xff0c;我们可以获取token后设置一个环境变量供所在同一个集合中的所有接口使用。 一般是通过调用登录接口&#xff0c;获取到token的值 实战项目&#xff1a;jeecg boot项目 项目官网…...

音频录制实现 绘制频谱

思路 获取设备信息 获取录音的频谱数据 绘制频谱图 具体实现 封装 loadDevices.js /*** 是否支持录音*/ const recordingSupport () > {const scope navigator.mediaDevices || {};if (!scope.getUserMedia) {scope navigatorscope.getUserMedia || (scope.getUserM…...

nginx代理本地服务请求,避免跨域;前端图片压缩并上传

痛点 有时用vscode进行一些测试 请求不同端口服务、或者其他服务接口时时&#xff0c;老是会报跨域&#xff0c;非常的烦 所有就想用 nginx 进行请求代理&#xff0c;来解决这个痛点 nginx 下载地址&#xff1a;nginx: download 下载到某一目录&#xff1a; window下nginx相关…...

Vue3-readonly(深只读) 与 shallowReadonly(浅只读)

Vue3-readonly(深只读) 与 shallowReadonly&#xff08;浅只读&#xff09; readonly(深只读)&#xff1a;具有响应式对象中所有的属性&#xff0c;其所有值都是只读且不可修改的。shallowReadonly(浅只读)&#xff1a;具有响应式对象的第一层属性值是只读且不可修改的&#x…...

中小企业怎么实现数字化转型?有什么实用的工单管理系统?

当前&#xff0c;世界经济数字化转型已是大势所趋。在这个数字化转型的大潮中&#xff0c;如果企业仍然逆水而行&#xff0c;不随大流&#xff0c;那么&#xff0c;企业将有可能会被抛弃&#xff0c;被对手超越&#xff0c;甚至被市场边缘化&#xff0c;导致最终的结果是&#…...

vue3.x中父组件添加自定义参数后,如何获取子组件$emit传递过来的参数

之前写过一篇文章&#xff0c;vue中父组件添加自定义参数后&#xff0c;如何获取子组件$emit传递过来的参数 现在已经进入vue3.x开发的时代了&#xff0c;那么vue3.x中父组件添加自定义参数后&#xff0c;如何获取子组件$emit传递过来的参数&#xff1f; 1、子组件使用emit传…...

【Machine Learning in R - Next Generation • mlr3】

本篇主要介绍mlr3包的基本使用。 一个简单的机器学习流程在mlr3中可被分解为以下几个部分&#xff1a; 创建任务 比如回归、分裂、生存分析、降维、密度任务等等挑选学习器&#xff08;算法/模型&#xff09; 比如随机森林、决策树、SVM、KNN等等训练和预测 创建任务 本次示…...

CorelDraw2024(CDR)- 矢量图制作软件介绍

在当今数字化时代&#xff0c;平面设计已成为营销、品牌推广和创意表达中不可或缺的元素。平面设计必备三大软件Adebo PhotoShop、CorelDraw、Adobe illustrator, 今天小编就详细介绍其中之一的CorelDraw软件。为什么这款软件在设计界赢得了声誉&#xff0c;并成为了设计师的无…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...