使用SpringBoot + Thymeleaf + iText实现动态PDF导出
使用SpringBoot + Thymeleaf + iText实现动态PDF导出
1.前端模版代码,需要注意,iText有很多高级样式兼用性不好,需要自己试错:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"/><title>模版文件</title><style>* {padding: 0;margin: 0;box-sizing: border-box;}li {list-style: none;}@page {size: A4;margin: 0.5cm;}html, body {width: 100%; /* A4宽度 */font-family: SimSun, Arial, sans-serif;}/* 容器样式 */.home, .profile, .clazzHourCert, .records {width: 90%;margin: 0 auto;}.records {margin-top: 90px;}h1, h2 {font-weight: normal;}.studyProfileNo {text-align: right;width: 100%;margin-top: 70px;}.home h1 {margin-top: 380px;text-align: center;width: 100%;}.info-container {margin: 250px auto 0;width: 100%;position: relative;}.info-row {margin-bottom: 35px;text-align: left;position: relative;left: 35%;}.spacing {/*调整汉字间距*/letter-spacing: 2em;font-style: normal;}table {width: 100%;/*设置框线*/border-collapse: collapse;/*固定列宽*/table-layout: fixed;}.profile table {text-align: center;}.profile table caption {margin-bottom: 25px;margin-top: 70px;}.profile table tr {height: 25px;}td {border: 1px solid black;padding: 5px;}.clazzHourCert .title {font-size: 20px;text-align: center;margin-top: 90px;}.clazzHourCert .no {text-align: left;margin-top: 60px;}.clazzHourCert table {margin-top: 10px;text-align: left;}.clazzHourCert td {width: 40%;height: 40px;}/*最后一行的表格*/.clazzHourCert table tr:last-child {height: 220px;line-height: 2.5;/*垂直底部对齐*/vertical-align: bottom;}.studyRecords table, .faceRecords table {/* 强制列宽固定 */table-layout: fixed;text-align: center;}/*span转成块才能设置宽高*/.studyRecords .name {display: inline-block;width: 50%;margin-bottom: 15px;}.exam header {text-align: center;}.exam p {margin-top: 15px;}.exam .info {margin-top: 15px;}.exam td {border: 0;padding: 0;text-align: left;}.home {position: relative;}/*电子签章*/.home .seal {position: absolute;bottom: -50px;left: 120px;}.profile .seal {position: relative;left: 350px;top: 250px;}.clazzHourCert .seal {position: relative;right: 100px;top: 80px;}.faceRecords .seal {position: absolute;right: 150px;bottom: 0;}.studyRecords {position: relative;}.studyRecords .seal {position: absolute;left: 450px;top: 750px;}.exam {position: relative;}.exam .seal {position: absolute;left: 450px;top: 750px;}</style>
</head>
<body>
<!--首页-->
<div class="home"><p class="studyProfileNo">档案编号:<span th:text="${data.studyProfileNo}"></span></p><h1>学员学习档案</h1><div class="info-container"><div class="info-row"><span class="label"><em class="spacing">姓</em>名:</span><span class="content" th:text="${data.studentName}"></span></div><div class="info-row"><span class="label">身份证号:</span><span class="content" th:text="${data.idCard}"></span></div><div class="info-row"><span class="label">生成日期:</span><span class="content" th:text="${data.curDate}"></span></div><div class="info-row">平台名称(盖章):<img class="seal" src="" alt="电子签章" width="170"/></div></div>
</div><div style="page-break-before: always;"></div><!--学员学习档案-->
<div class="profile"><table><caption><h2>学员学习档案</h2></caption><colgroup><col style="width: 20%;"/><col style="width: 20%;"/><col style="width: 10%;"/><col style="width: 10%;"/><col style="width: 10%;"/><col style="width: 10%;"/><col style="width: 20%;"/></colgroup><tbody><tr><td colspan="7">注册信息</td></tr><tr><td>姓名</td><td th:text="${data.studentName}"></td><td>性别</td><td th:text="${data.sex}"></td><td>年龄</td><td th:text="${data.age}"></td><td rowspan="5"><img th:src="${data.personnelImg}" src="" alt="暂无图片" width="auto" height="125px"/></td></tr><tr><td>联系电话</td><td th:text="${data.phone}"></td><td colspan="2">身份证号</td><td colspan="2" style="font-size: 14px" th:text="${data.idCard}"></td></tr><tr><td>学历</td><td th:text="${data.education}"></td><td colspan="2">职务/职称</td><td colspan="2" th:text="${data.post}"></td></tr><tr><td>部门</td><td th:text="${data.department}"></td><td colspan="2">工种</td><td colspan="2" th:text="${data.craft}"></td></tr><tr><td>平台注册时间</td><td th:text="${data.registerTime}"></td><td colspan="2">累计课时</td><td colspan="2" th:text="${data.cumulativeClazzHour}"></td></tr><tr class="large-height" height="50px"><td height="50px">所属单位</td><td colspan="6" height="50px" th:text="${data.companyName}"></td></tr><tr><td colspan="7">班级信息</td></tr><tr><td>班级名称</td><td colspan="6" th:text="${data.clazzName}"></td></tr><tr><td>班级编号</td><td colspan="2" th:text="${data.clazzNo}"></td><td colspan="2">班级期次</td><td colspan="2" th:text="${data.clazzIssue}"></td></tr><tr><td>班级期限</td><td colspan="2" th:text="${data.clazzDeadline}"></td><td colspan="2">起止学习时间</td><td colspan="2" th:text="${data.studyDeadline}"></td></tr><tr><td>学习方式</td><td colspan="2" th:text="${data.studyWay}"></td><td colspan="2">课程形式</td><td colspan="2" th:text="${data.courseForm}"></td></tr></tbody></table><img class="seal" src="" alt="电子签章" width="170"/></div><div style="page-break-before: always;"></div><!--学时证明-->
<div class="clazzHourCert"><p class="title">安全教育职业培训平台学时证明</p><p class="no">证书编号: <span th:text="${data.clazzHourProve.clazzHourCertNo}"></span></p><table><tbody><tr><td>姓名</td><td><span th:text="${data.studentName}"></span></td></tr><tr><td>证件类型</td><td>身份证</td></tr><tr><td>证件编号</td><td><span th:text="${data.idCard}"></span></td></tr><tr><td>企业名称</td><td><span th:text="${data.companyName}"></span></td></tr><tr><td>班级名称</td><td><span th:text="${data.clazzName}"></span></td></tr><tr><td>培训日期</td><td><span th:text="${data.clazzHourProve.trainTime}"></span></td></tr><tr><td>培训类型</td><td><span th:text="${data.clazzHourProve.trainType}"></span></td></tr><tr><td>视频学习时长</td><td><span th:text="${data.clazzHourProve.videoLearningTime}"></span></td></tr><tr><td>合计在线学习时长</td><td><span th:text="${data.clazzHourProve.onlineLearningTotalTime}"></span></td></tr><tr><td>培训单位:(盖章)<br/>日期:<span th:text="${data.clazzHourProve.curDate}"></span></td><td>平台:(盖章)<img class="seal" src="" alt="电子签章" width="170px"/><br/>日期:<span th:text="${data.clazzHourProve.curDate}"></span></td></tr></tbody></table>
</div><div style="page-break-before: always;"></div><div class="records" th:each="item, stat : ${data.studyRecordsList}"><!--人脸验证记录--><div class="faceRecords"><table><colgroup><col style="width: 20%;"/><col style="width: 30%;"/><col style="width: 10%;"/><col style="width: 10%;"/><col style="width: 30%;"/></colgroup><tr><td colspan="5">学习记录</td></tr><tr><td>课程名称</td><td colspan="4" th:text="${item.studyRecords.courseName}"></td></tr><tr><td>要求课时</td><td th:text="${item.studyRecords.requireClazzHour}"></td><td colspan="2">已学课时</td><td th:text="${item.studyRecords.studyClazzHour}"></td></tr><tr><td>是否完成</td><td th:text="${item.studyRecords.completeStatus}"></td><td colspan="2">学时证明</td><td th:text="${item.studyRecords.clazzHourCertNo}"></td></tr><tr><td>到课率</td><td th:text="${item.studyRecords.clazzAttendance}"></td><td colspan="2">课程考试正确率</td><td th:text="${item.studyRecords.examCorrectAttendance}"></td></tr><tr><td>考试成绩</td><td th:text="${item.studyRecords.examScore}"></td><td colspan="2">是否合格</td><td th:text="${item.studyRecords.passStatus}"></td></tr><tr><td rowspan="6">人脸验证记录</td><td colspan="4">共进行<span th:text="${item.studyRecords.faceVerifyTotal}"></span>次人脸认证,成功<span th:text="${item.studyRecords.faceVerifySuccessCount}"></span>次,失败<span th:text="${item.studyRecords.faceVerifyFailCount}"></span>次。</td></tr><!--如果是第5行就增加相对定位,因为第五行第二列的签章设置相对定位了--><tr th:each="faceVerify, iterStat : ${item.studyRecords.faceVerifyList}" th:style="${iterStat.count == 5} ? 'position: relative;'"><td colspan="2"><span th:text="${faceVerify != null} ? '随机照片' + ${iterStat.count}"></span><br/><span th:text="${faceVerify != null} ? ${faceVerify.snapshotTime}"></span><br/><span th:text="${faceVerify != null} ? '课件:' + ${faceVerify.coursewareName}"></span></td><td colspan="2"><!--如果是第5行就增加这个图片,不是的话不加--><img th:if="${iterStat.count == 5}" class="seal" src="" alt="电子签章" width="170px"/><img th:src="${faceVerify != null} ? ${faceVerify.snapshotFile}" src="" alt="暂无图片" width="auto" height="125px"/></td></tr><tr><td>考试试卷名称</td><td colspan="4" th:text="${item.studentExamPaper.examPaperName}"></td></tr></table></div><div style="page-break-before: always;"></div><!--课程章节学习记录--><div class="studyRecords"><p><span class="name" th:text="'姓名:' + ${data.studentName}"></span><span class="idcardNo" th:text="'身份证号:' + ${data.idcard}"></span></p><table><!--每列的固定宽度--><colgroup><col style="width: 15%;"/><col style="width: 60%;"/><col style="width: 10%;"/><col style="width: 15%;"/></colgroup><tr><td>课程名称</td><td colspan="3" th:text="${item.courseCourseware.courseName}"></td></tr><tr><td>序号</td><td>课程内容</td><td>课时</td><td>讲师</td></tr><!--遍历课件列表--><tr th:each="courseware, iterStat : ${item.courseCourseware.coursewareList}"><td th:text="${iterStat.count}"></td><td th:text="${courseware.coursewareName}"></td><td th:text="${courseware.courseHour}"></td><td th:text="${courseware.teacherName}"></td></tr></table><img class="seal" src="" alt="电子签章" width="170"/></div><!--PDF手动分页--><div style="page-break-before: always;"></div><!--试卷--><div class="exam"><header><h1 th:text="${item.studentExamPaper.examPaperName}"></h1><p>(满分:<span th:text="${item.studentExamPaper.fullMark}"></span>分)</p><div class="info"><table><colgroup><col style="width: 40%;"/><col style="width: 40%;"/><col style="width: 20%;"/></colgroup><tr><td>班级名称:<span th:text="${data.clazzName}"></span></td><td>姓名:<span th:text="${data.studentName}"></span></td><td>成绩:<span th:text="${item.studentExamPaper.grade}"></span></td></tr><tr><td>考试时间:<span th:text="${item.studentExamPaper.examTime}"></span></td><td>判卷人:<span th:text="${item.studentExamPaper.judge}"></span></td></tr></table></div></header><main><section th:each="question, iterStat : ${item.studentExamPaper.examPaperItems}"><p><span th:text="${question.questionContent}"></span></p><ul><li th:each="option : ${question.options}" th:text="${option}"></li></ul></section></main><img class="seal" src="" alt="电子签章" width="170"/></div><!-- 判断是否为最后一个元素,避免最后一项后多余分页 --><div th:if="${!stat.last}" style="page-break-after: always;"></div>
</div></body>
</html>
2.maven依赖
<dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-pdf</artifactId><version>9.1.22</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13.3</version></dependency>
3.PDF工具类,将动态数据渲染到PDF模版中,并保存到磁盘
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;public class PDFUtil {private static final TemplateEngine templateEngine;static {ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();templateResolver.setPrefix("template/");templateResolver.setSuffix(".html");templateResolver.setTemplateMode(TemplateMode.HTML);templateResolver.setCharacterEncoding("UTF-8");templateResolver.setCacheable(true);templateEngine = new TemplateEngine();templateEngine.setTemplateResolver(templateResolver);}/*** 获取PDF总页数*/public static int getPdfPageCount(String pdfPath) throws IOException {PdfReader reader = new PdfReader(pdfPath);int pages = reader.getNumberOfPages();reader.close();return pages;}/*** 在 PDF 文档中插入骑缝章。** @param inputPdfPath 输入的 PDF 文件路径* @param outputPdfPath 输出的 PDF 文件路径* @param sealImages 骑缝章图片数组(每个元素对应一页)* @throws IOException 如果读取或写入文件时发生错误* @throws DocumentException 如果操作 PDF 时发生错误*/public static void addRidingSeal(String inputPdfPath, String outputPdfPath, BufferedImage[] sealImages)throws IOException, com.itextpdf.text.DocumentException {// 读取输入的 PDF 文件PdfReader reader = new PdfReader(inputPdfPath);int numberOfPages = reader.getNumberOfPages();// 确保骑缝章图片的数量与 PDF 页面数量一致if (sealImages.length != numberOfPages) {throw new IllegalArgumentException("骑缝章图片数量与 PDF 页面数量不匹配!");}// 创建输出的 PDF 文件PdfStamper stamper = new PdfStamper(reader, Files.newOutputStream(Paths.get(outputPdfPath)));// 循环每一页,将对应的骑缝章插入到页面中for (int i = 1; i <= numberOfPages; i++) {// 获取当前页的内容字节流PdfContentByte content = stamper.getOverContent(i);// 将 BufferedImage 转换为 iText 的 Image 对象File tempFile = File.createTempFile("sealPart", ".png");ImageIO.write(sealImages[i - 1], "png", tempFile);Image sealImage = Image.getInstance(tempFile.getAbsolutePath());float scaleDownFactor = 0.72f;// 电子签章缩放倍数// 获取原始 BufferedImage 的宽高(以像素为单位)float originalWidthPx = sealImages[i - 1].getWidth() * scaleDownFactor;float originalHeightPx = sealImages[i - 1].getHeight() * scaleDownFactor;// 设置骑缝章的实际宽高(保持比例不变)sealImage.scaleAbsolute(originalWidthPx, originalHeightPx);// 设置骑缝章的位置Rectangle pageSize = reader.getPageSize(i);float pageWidth = pageSize.getWidth();float pageHeight = pageSize.getHeight();// 计算骑缝章的位置(右侧边缘,垂直居中)float x = pageWidth - sealImage.getScaledWidth(); // 右侧边缘float y = (pageHeight - sealImage.getScaledHeight()) / 2; // 垂直居中// 添加骑缝章到当前页sealImage.setAbsolutePosition(x, y);content.addImage(sealImage);// 删除临时文件tempFile.deleteOnExit();}// 关闭资源stamper.close();reader.close();}/*** 将HTML转换为PDF* @param htmlContent HTML内容* @param outputPath 输出路径* @param fileName 文件名称* @throws IOException* @throws DocumentException*/public static void convertHtmlToPdf(String htmlContent, String outputPath, String fileName)throws IOException, DocumentException {ITextRenderer renderer = new ITextRenderer();// 加载中文字体try (InputStream fontStream = PDFUtil.class.getClassLoader().getResourceAsStream("fonts/simsun.ttc")) {if (fontStream == null) {throw new IOException("无法找到字体文件");}Path tempFontFile = Files.createTempFile("simsun", ".ttc");tempFontFile.toFile().deleteOnExit();Files.copy(fontStream, tempFontFile, StandardCopyOption.REPLACE_EXISTING);renderer.getFontResolver().addFont(tempFontFile.toString(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);}renderer.setDocumentFromString(htmlContent);renderer.layout();try (OutputStream os = Files.newOutputStream(Paths.get(outputPath + fileName))) {renderer.createPDF(os);}}public static String processTemplateWithData(Object dataModel, String templateName) throws IOException {Context context = new Context();context.setVariable("data", dataModel); // 将数据模型设置到Thymeleaf上下文中return templateEngine.process(templateName, context);}}
测试调用:
try {// 使用数据对象处理HTML模板,模版放到resources/template文件夹中,且必须是HTML文件String processedHtml = PDFUtil.processTemplateWithData(studentProfile, "study_profile");// 转换为PDFPDFUtil.convertHtmlToPdf(processedHtml, "/path/to/save/", "newfile.pdf");System.out.println("PDF生成成功!");} catch (Exception e) {e.printStackTrace();}
4.图片处理工具类,用于处理骑缝章
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;public class ImageUtil {/*** 调整图片大小以达到目标宽度,并保持宽高比。** @param inputFile 输入图片文件路径* @param outputFile 输出调整大小后的图片文件路径* @param targetWidth 目标宽度* @throws IOException 如果读取或写入图片时发生错误*/public static void resizeImage(String inputFile, String outputFile, int targetWidth) throws IOException {// 读取原始图片BufferedImage originalImage = ImageIO.read(new File(inputFile));if (originalImage == null) {throw new IOException("无法读取图片文件: " + inputFile);}// 获取原始尺寸int originalWidth = originalImage.getWidth();int originalHeight = originalImage.getHeight();// 计算新的高度,保持原始宽高比int targetHeight = (int) (targetWidth * ((double) originalHeight / originalWidth));// 创建一个新的空白图像,用于绘制调整大小后的图像BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, originalImage.getType());Graphics2D g2d = resizedImage.createGraphics();// 使用抗锯齿和高质量的缩放算法绘制调整大小后的图像g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);g2d.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null);// 释放资源g2d.dispose();// 写入输出文件String formatName = inputFile.substring(inputFile.lastIndexOf(".") + 1);ImageIO.write(resizedImage, formatName, new File(outputFile));}/*** 图片分割* @param imagePath 图片路径* @param parts 切割数量* @return 切割后的图片数组* @throws Exception*/public static BufferedImage[] splitImage2(String imagePath, int parts) throws Exception {// 加载图片BufferedImage originalImage = ImageIO.read(new File(imagePath));int totalWidth = originalImage.getWidth();int height = originalImage.getHeight();System.out.println(totalWidth + " : " + height);// 创建分割后的图片数组BufferedImage[] splitImages = new BufferedImage[parts];// 计算每段的基础宽度和剩余宽度int basePartWidth = totalWidth / parts; // 每段的基础宽度int remainder = totalWidth % parts; // 剩余的宽度for (int i = 0; i < parts; i++) {// 动态计算当前段的宽度int partWidth = basePartWidth + (i < remainder ? 1 : 0);// 计算当前段的起始位置int startX = i * basePartWidth + Math.min(i, remainder);// 截取当前段splitImages[i] = originalImage.getSubimage(startX, 0, partWidth, height);}return splitImages;}}
5.向PDF中插入骑缝章
String inputPdf = "/path/to/input/file.pdf";String outputPdf = "/path/to/out/newfile.pdf";String sealImage = "/path/to/seal/seal.png";int parts = PDFUtil.getPdfPageCount(inputPdf);BufferedImage[] bufferedImages = ImageUtil.splitImage(sealImage, parts);PDFUtil.addRidingSeal(inputPdf, outputPdf, bufferedImages);
6.效果展示
不知道为什么,PDF插入骑缝章的时候,即便是给骑缝章设置了固定宽高,到PDF后依然会失调,所以手动设置了宽高的缩放比为0.72。至此,使用SpringBoot + Thymeleaf + iText实现动态PDF导出完成。
相关文章:
使用SpringBoot + Thymeleaf + iText实现动态PDF导出
使用SpringBoot Thymeleaf iText实现动态PDF导出 1.前端模版代码,需要注意,iText有很多高级样式兼用性不好,需要自己试错: <!DOCTYPE html> <html lang"en" xmlns:th"http://www.thymeleaf.org"…...
Redis 源码硬核解析系列专题 - 扩展篇:Gossip协议的具体实现
1. 引言 Redis Cluster使用Gossip协议实现节点间的状态同步和一致性维护。Gossip协议是一种去中心化的通信机制,通过节点间的“谣言传播”方式交换信息,具有高容错性和扩展性。本篇将深入剖析Redis中Gossip协议的具体实现,包括消息格式、传播机制和故障检测逻辑。 2. Gossi…...
scGPT环境安装
scGPT环境安装 conda create -n scgpt_2 conda activate scgpt_2 conda install python3.10.11 cudatoolkit11.7 cudatoolkit-dev gxx>6.0.0,<12.0 cudnn -c conda-forge pip install torch1.13.0cu117 torchvision0.14.0cu117 torchaudio0.13.0 --extra-index-url https…...
linux服务器组建与管理
环境: DNSSamba服务器 ip:192.168.177.153 FTP服务器 ip:192.168.177.152 pc ip:192.168.177.151 这里先把DNS的ip及DNS固定给固定了,免得我关机了还会更改 网络配置:(前面的命令是DNS/Samba的后面的是FTP的,下面那张是示例图) sudo nmcli con mod ens33 ipv4.addres…...
vue3 生命周期函数(挂载、更新、销毁)
在这之前,相必用户也是用过vue2的经历,所以,在讲解之前先对vue2和vue3的生命周期进行对比: Option API组合APIbeforeCreate-setupcreated-setupbeforeMountonBeforeMountmountedonMountedbeforeUpdateonBeforeUpdateupdatedonUpd…...
树莓派超全系列教程文档--(20)树莓派配置自动息屏
树莓派配置自动息屏 配置自动息屏桌面Raspberry Pi 配置CLI 控制台设置控制台模式自动息屏查看当前自动息屏设置 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置自动息屏 您可以将 Raspberry Pi 配置为在一段时间不活动后自动息屏。默认情况…...
基于 Qt / HTTP/JSON 的智能天气预报系统测试报告
目录 一、项目概述 1.1项目背景 1.2项目目标 二、功能需求 2.1 用户界面功能 2.2 后台功能 三、技术选择 3.1 开发框架与工具 3.2 第三方 API 四、UI设计 4.1界面展示 4.2stylesheet样式 五、代码实现 1.构造函数 2.网络请求响应处理函数 3.处理json数据 4.更新…...
Oracle数据库数据编程SQL<3.7 PL/SQL 触发器(Trigger)>
触发器是Oracle数据库中的一种特殊存储过程,它会在特定数据库事件发生时自动执行。触发器通常用于实现复杂的业务规则、数据验证、审计跟踪等功能。 目录 一、触发器基本概念 1. 触发器特点 2. 触发器组成要素 二、触发器类型 1. DML触发器 2. DDL触发器 3.…...
反常积分和定积分的应用 1
网课 还是得跟上网课的进度。但是不要给自己太大的压力。看到数学题确实有点慌张。老师为什么说写对了不要打对号,我感觉打对号可以给自己充足的正反馈。关键问题就是能做对的题不多。这篇笔记主要整理网课的一些笔记。网课落下的比较多,大概还需要补好…...
Day49 | 11. 盛最多水的容器、16. 最接近的三数之和、33. 搜索旋转排序数组、36. 有效的数独
11. 盛最多水的容器 题目链接:11. 盛最多水的容器 - 力扣(LeetCode) 题目难度:中等 代码: class Solution {public int maxArea(int[] height) {int i0,jheight.length-1,res0;while(i<j){resheight[i]<heig…...
31天Python入门——第20天:魔法方法详解
你好,我是安然无虞。 文章目录 魔法方法1. __new__和__del__2. __repr__和__len__3. __enter__和__exit__4. 可迭代对象和迭代器5. 中括号[]数据操作6. __getattr__、__setattr__ 和 __delattr__7. 可调用的8. 运算符 魔法方法 魔法方法: Python中的魔法方法是一类…...
WPF 浅述IsHitTestVisible属性
WPF 浅述IsHitTestVisible属性 IsHitTestVisible 属性是 WPF 中一个非常重要的属性,它决定了一个控件是否可以作为 hit test 的一部分被检测到。理解这个属性对于处理交互事件(如鼠标点击、触摸等)非常重要。 IsHitTestVisible 属性的含义&am…...
WSN 经典定位算法
WSN 经典定位算法 包括: Centoid, Bounding_box, Grid_Scan, RSSI, DV_hop, MDS_MAP,APIT-WSN Localization/Amorphous/Amorphous.m , 3351 Localization/APIT/APIT.m , 4169 Localization/APIT/PPIT.m , 3889 Localization/Bounding Box/Bounding_Box.…...
LLM 优化技术(1)——Scaled-Dot-Product-Attention(SDPA)
在 Transformer 中抛弃了传统的 CNN 和 RNN,整个网络结构完全由Scaled Dot Product Attention 和Feed Forward Neural Network组成。一个基于 Transformer 的可训练的神经网络可以通过堆叠 Transformer 的形式进行搭建,Attention is All You Need论文中通…...
【深度学习】嘿马深度学习目标检测教程第1篇:商品目标检测要求、目标,1.1 项目演示【附代码文档】
教程总体简介:要求 目标 1.1 项目演示 学习目标 1.1 图像识别背景 1.2 什么是目标检测 1.2.1 目标检测定义 1.2.1.1 物体 1.3 目标检测应用场景 1.3.1 行业 1.3.2 应用类别 1.4 开发环境搭建 目标检测概述 3.1 目标检测任务描述 3.1.4 目标定位的简单实现 项目实现 …...
【蓝桥杯】单片机设计与开发,RTC实时时钟
一、RTC-DS1302概述 二、BCD码 三、三线协议概述 四、RTC的应用 五、DS1302的驱动函数 六、操作流程 七、三线协议驱动程序...
Java 各版本的新特性
Java 各版本的新特性主要集中在提升开发效率、性能优化、语言功能增强和模块化支持等方面。以下是 JDK 8 到 JDK 21(截至2023年)的主要新特性概览: JDK 8 (2014) - LTS Lambda 表达式:支持函数式编程,简化匿名内部类。…...
OpenGL中EBO的使用及原理
EBO 是什么? 在OpenGL中,EBO(Element Buffer Object),也称为索引缓冲对象 IBO(Index Buffer Object),是一种用于存储顶点索引数据的缓冲区对象。它的核心作用是通过复用顶点数据来减…...
应用分享 | AWG技术突破:操控钻石氮空位色心,开启量子计算新篇章!
利用AWG操作钻石中的氮空位色彩中心 金刚石中的颜色中心是晶格中的缺陷,其中碳原子被不同种类的原子取代,而相邻的晶格位点则是空的。由于色心具有明亮的单光子发射和光学可触及的自旋,因此有望成为未来量子信息处理和量子网络的固态量子发射…...
【Ultralytics YOLO COCO 评估脚本 | 获得COCO评价指标】
文章目录 Ultralytics YOLO COCO 评估脚本 (coco_evaluate.py)1. 描述2. 依赖项3. 使用方法4. 输入文件格式5. 输出6. 注意7. 完整代码 Ultralytics YOLO COCO 评估脚本 (coco_evaluate.py) 这是一个 Python 脚本,用于评估以 COCO JSON 格式提供的目标检测结果。它…...
聊一聊,元件封装知多少?
目录 01 | 简 介 02 | 常见的无源器件封装 03 | 集成(IC)类封装 04 | 功率器件类封装 05 | 连接器类封装 06 | 总 结 01 | 简 介 由于平时工作中,经常需要查看封装的样式,以便初步规划PCB布局;遂萌发对常用的元件封装进行一次总结。 …...
企业需要使用防病毒系统保障数据安全的原因
数据作为企业的重要资产,正面临勒索病毒等极大威胁。在复杂严峻的网络安全形势下,企业的业务运营、数据安全和声誉遭遇诸多来自网络的挑战。2023年,国内发生多起严重网络安全事件,例如数据库漏洞导致数据泄露、钓鱼邮件窃取信息、…...
使用无人机进行露天矿运输道路分析
使用无人机进行露天矿运输道路分析 无人机正在彻底改变采矿业,为露天矿场的运输道路收集数据和分析提供了一种新方法。通过使用 UAS 技术,采矿公司可以更全面地了解道路状况,确定磨损区域,并提高安全性和效率。 本文介绍了无人机用…...
基于Vue.js网页开发相关知识:Vue-router
一、基础知识 vue-router 是 Vue.js 官方的路由管理器,用于实现单页面应用(SPA)的路由功能。以下从几个方面对 vue-router 进行详细分析: 1. 核心概念 路由配置 vue-router 通过定义路由配置对象来管理应用的路由。每个路由配置…...
同时使用Telnet和SSH登录思科交换机
同时使用Telnet和SSH登录思科交换机 1. 配置管理IP地址 首先,为交换机配置一个管理IP地址,以便可以通过网络进行远程管理: Switch(config)# interface vlan [VLAN_ID] Switch(config-if)# ip address [IP地址] [子网掩码] Switch(config-i…...
presto行转列
presto的行列转换和spark、hive一样也是通过外链语句实现的,只不过语法和关键子有点不同,如下 with tmp1 as (select 1,2,3 as a1,4,5,6 as a2 ) select * from tmp1 cross join unnest(split(tmp1.a1, ,),split(tmp1.a2, ,) ) as b(a1s,a2s) 结果如下...
App Usage v5.57 Pro版 追踪手机及应用使用情况
手机使用监控神器:让你的手机使用情况一目了然 现代人的生活已经离不开手机——通讯、娱乐、支付、购物…每天我们花在手机上的时间越来越多。你是否好奇: 每天在各个应用上花费了多少时间?一天中查看了多少次手机?哪些应用在后…...
24.3 CogView3多模态生成实战:从API调优到1024高清图像生成全解析
CogView3多模态生成实战:从API调优到1024高清图像生成全解析 CogView3 & CharGLM:多模态生成技术深度解析 关键词:CogView3 API 调用,图像生成与编辑,多模态提示工程,GLM 技术栈集成,参数优化策略 1. 智谱清言平台演示 CogView-3 核心能力 1.1 CogView3 技术架构…...
操作系统高频(六)linux内核
操作系统高频(六)linux内核 1.内核态,用户态的区别⭐⭐⭐ 内核态和用户态的区别主要在于权限和安全性。 权限:内核态拥有最高的权限,可以访问和执行所有的系统指令和资源,而用户态的权限相对较低&#x…...
Ubuntu系统安装Cpolar 实现内网穿透教程
文章目录 方法 1:使用官方脚本快速安装(推荐)方法 2:手动下载安装包配置与使用常见问题 方法 1:使用官方脚本快速安装(推荐) 下载安装脚本 打开终端,执行以下命令下载并运行安装脚本…...
Trustworthy Machine Learning
1. 可信任机器学习的核心概念 1.1 可信任性的定义 稳健性(Robustness): 机器学习模型在面对数据噪声、分布变化或对抗性攻击时仍能维持其预测性能的能力。 公平性(Fairness): 避免 AI 决策对某些群体存在…...
Enovia许可管理系统的特点
在当今竞争激烈的市场环境中,企业对于产品生命周期管理(PLM)的需求日益增加。Enovia许可管理系统,作为一款先进的许可证管理工具,凭借其卓越的特点,助力企业实现资源的高效管理和最大化利用。本文将详细介绍…...
【CSS】样式与效果
个人主页:Guiat 归属专栏:HTML CSS JavaScript 文章目录 1. CSS盒模型1.1 盒模型基础1.2 盒模型类型1.2.1 标准盒模型1.2.2 IE盒模型 2. CSS选择器2.1 基本选择器2.2 组合选择器2.3 伪类和伪元素 3. CSS布局技术3.1 Flexbox布局3.2 Grid布局3.3 定位 4. …...
Python中常用网络编程模块
学习籽料在下方自拿 一、网络基础 网络由下往上分为:物理层、数据链路层、网络怪、传输层、会话层、表示层和应用层。 TCP/IP协议是传输层协议,主要解决数据如何在网络中传输;socket则是对TCP/IP协议的封装,它本身不是协议&…...
python-flask
1.定时任务的时候一定要加--preload,防止 --preload gunicorn --config gunicorn-conf.py --preload index:app 2.source /usr/local/nginx/html/prod/pypd/venv/bin/activate 启动linux的python环境 3.pip freeze > requirements.txt 生成所有依赖 4.p…...
OpenIPC开源FPV之Adaptive-Link信号干扰
OpenIPC开源FPV之Adaptive-Link信号干扰 1. 源由2. 现象3. 分析3.1 冲突弃包3.2 传输丢包 4. 逻辑4.1 可调整参数4.2 可监测参数4.3 逻辑思路 5. 总结6. 参考资料 1. 源由 虽然,OpenIPC作为FPV图传在延时方面使用广播wfb-ng,性能上已经非常棒了。 在权…...
C++ 结构体与函数
一.结构体 1.概念: 结构体(struct)是一种用户自定义复合数据类型,其中可以包含不同类型的不同成员 2.结构体的应用场景: 我们在使用多个变量描述一个对象时,虽然也可以做到,但是难免显得杂乱…...
【Java全栈】Java + Vue 项目框架与运行流程详解
文章目录 ⭐前言⭐一、框架介绍🌟1、后端框架(Java Spring Boot)🌟2、前端框架(Vue 3 Element Plus) ⭐二、项目结构🌟1、后端目录(Spring Boot)🌟2、前端目…...
JAVA:利用 JSONPath 操作JSON数据的技术指南
1、简述 JSONPath 是一种强大的工具,用于查询和操作 JSON 数据。类似于 SQL 的语法,它为处理复杂的 JSON 数据结构提供了简单且高效的解决方案。✨ 代码样例:https://gitee.com/lhdxhl/springboot-example.git 本文将介绍 JSONPath 的基本…...
5.2.1 WPF 通过ItemControl自己做柱状图
1. 最终效果如下图: 1.1 准备数据 ViewModel public class PrimaryItemModel{public double Value { get; set; }public string XLabel { get; set; }}public class MainViewModel{public ObservableCollection<PrimaryItemModel> PrimaryList { get; set; }…...
3.31 代码随想录第三十一天打卡
1049.最后一块石头的重量II (1)题目描述: (2)解题思路: class Solution { public:int lastStoneWeightII(vector<int>& stones) {vector<int> dp(15001, 0);int sum 0;for (int i 0; i < stones.size(); i) sum stones[i];int target sum / 2;for (in…...
基于网启PXE服务器的批量定制系统平台
一.项目背景 公司新购了一批服务器和台式机,需要为台式机和服务器安装系统,一部分需要安装国产OpenEuler,一部分要求安装CentOS 7.9,同时也要满足定制化需求,即按要求分区安装相应软件。 二.项目环境 安装win10/11 …...
Unity光线传播体积(LPV)技术实现详解
一、LPV技术概述 光线传播体积(Light Propagation Volumes)是一种实时全局光照技术,通过将场景中的间接光信息存储在3D网格中,实现动态物体的间接光照效果。 核心优势: 实时性能:相比传统光照贴图,支持动态场景 硬件…...
蓝桥杯备考---》贪心算法之矩阵消除游戏
我们第一次想到的贪心策略一定是找出和最大的行或者列来删除,每次都更新行和列 比如如图这种情况,这种情况就不如直接删除两行的多,所以本贪心策略有误 so我们可以枚举选的行的情况,然后再贪心的选择列和最大的列来做 #include …...
python+playwright 学习-93 结合pands 抓取网页表格数据
playwright 结合 pands 抓取网页表格数据 pandas 直接抓取网页表格数据 web 网页表格数据 """ 上海 202501 天气抓取 """ import pandas as pddf = pd.read_html(fhttp://www.tianqihoubao.com/lishi/shanghai/month/202501.html,encoding...
MVC编程
MVC基本概述 例子——显示本地文件系统结构 先分别拖入ListView,TableView,TreeView 然后在进行布局 在widget.cpp 结果 mock测试 1,先加入json测试对象 2.创建后端目录 3,在src添加新文件 在models文件夹里 在mybucket.h,添加测试用例的三个字段 4.在…...
51单片机总结
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.03.31 51单片机学习总结(有感而发) 一、总结结语 一、总结 一路…...
端到端语音识别案例
《DeepSeek大模型高性能核心技术与多模态融合开发(人工智能技术丛书)》(王晓华)【摘要 书评 试读】- 京东图书 语音识别这一技术正如其名,是通过精密地解析说话人的语音来识别并准确转写出其所说的内容。它不仅仅是一个简单的转录过程&#…...
iOS自定义collection view的page size(width/height)分页效果
前言 想必大家工作中或多或少会遇到下图样式的UI需求吧 像这种cell长度不固定,并且还能实现的分页效果UI还是很常见的 实现 我们这里实现主要采用collection view,实现的方式是自定义一个UICollectionViewFlowLayout的子类,在这个类里对…...
CI/CD基础知识
什么是CI/CD CI:持续集成,开发人员频繁地将代码集成到主干(主分支)中每次集成都通过自动化构建和测试来验证,从而尽早发现集成错误,常用的CI工具包括Jenkins、Travis CI、CircleCI、GitLab CI等 CD&#…...