签入版本

This commit is contained in:
2026-09-10 21:41:50 +08:00
commit 717116a605
2693 changed files with 355025 additions and 0 deletions
@@ -0,0 +1,434 @@
// +======================================================================
// | 小蚂蚁云·企业数字化开发平台 [ 加速数字化转型,构建智能未来 ]
// +----------------------------------------------------------------------
// | 核心价值:赋能开发者 · 服务企业 · 共建生态
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2026 小蚂蚁云团队 版权所有
// +----------------------------------------------------------------------
// | 官方平台: https://www.xiaomayicloud.com
// +======================================================================
// | 【知识产权声明】
// | 1. 权属声明:本软件是受《中华人民共和国著作权法》
// | 保护的专有财产,完整版权归小蚂蚁云团队所有
// | 2. 权利范围:所有知识产权(商标、专利、著作权、
// | 商业秘密等)均归小蚂蚁云团队所有,受法律保护
// | 3. 授权性质:用户仅可获得有限的、非独占的使用许可
// | 4. 禁止行为:未经书面授权,禁止对本软件本身
// | 申请任何知识产权
// | 5. 权利保留:未在本协议中明示授予的一切权利
// | 均由小蚂蚁云团队保留
// +======================================================================
// | 【授权状态说明】
// | 1. 未授权状态:用户未购买有效的商业许可证
// | 2. 商业授权:已购买正式商业许可证的用户
// +======================================================================
// | 【绝对禁止条款】
// | 无论授权状态如何,任何用户均严格禁止以下行为:
// | 1. 逆向工程:对软件进行反编译、反汇编、技术破解或任何形式的逆向分析
// | 2. 版权破坏:移除、修改、遮挡软件中的版权标识、许可控制或技术保护措施
// | 3. 非法传播:复制、分发、出租、出借、转售、再许可本软件或其许可权利
// | 4. 竞争性使用:利用本软件的代码、架构、设计开发直接竞争的产品或服务
// | 5. 侵权使用:将软件用于侵犯第三方知识产权或其他合法权益的用途
// +======================================================================
// | 【商业授权许可范围】
// | 购买有效商业许可证的用户,在遵守上述禁止条款的前提下,获得:
// | 1. 使用权利:在许可证约定的项目数量、开发者数量范围内使用本软件
// | 2. 技术支持:商业授权用户可以获取本地开发部署的技术支持服务
// | 3. 版本更新:在许可证有效期内获取软件更新、安全补丁和功能增强
// | 4. 商业部署:将基于本软件开发的应用程序用于商业运营和生产环境
// +======================================================================
// | 【许可证获取】
// | 1. 获取途径:仅通过小蚂蚁云官方渠道购买(官网、授权代理商),购买记录凭证
// | 2. 转让限制:许可证与购买主体绑定,未经书面同意不得转让
// | 3. 终止情形:许可证到期、违反协议、破产清算等情况下自动终止
// +======================================================================
// | 【合法使用要求】
// | 1. 仅限用于合法合规的软件研发
// | 2. 严禁用于任何违法、侵权或恶意行为
// | 3. 严禁违反我国法律法规和政策
// +======================================================================
// | 【免责声明】
// | 因使用本框架导致的以下情况,我们概不负责:
// | 1. 项目研发中的意外、疏忽、违约等风险
// | 2. 侵犯第三方知识产权或其他合法权益
// | 3. 任何直接、间接、附带或衍生一切损失
// | 4. 用户违规违法行为的一切法律后果
// +======================================================================
// | 【协议重要提示】
// | 1. 本声明是《小蚂蚁云最终用户许可协议》的摘要版本
// | 2. 下载、安装或使用本软件即表示您接受全部协议条款
// | 3. 我们保留单方面修改本声明的权利,修改后的版本在官网公布即生效
// | 4. 用户有义务定期查看最新版本,继续使用视为接受修改
// +======================================================================
// | 【侵权举报与合规】
// | 1. 知识产权侵权举报:请联系官方客服
// | 2. 许可证合规咨询:xiaomayicloud@163.com
// | 3. 违规使用将终止授权并追究责任
// | 4. 无条件配合司法机关调查取证
// | 5. 保留一切法律追诉权利
// | 6. 对有效举报和合规建议,我们将给予感谢和奖励
// +======================================================================
package com.xiaomayi.pdf.utils;
import com.aspose.cells.FontConfigs;
import com.aspose.cells.License;
import com.aspose.cells.PdfSaveOptions;
import com.aspose.cells.Workbook;
import com.itextpdf.text.*;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.*;
import com.xiaomayi.core.config.AppConfig;
import com.xiaomayi.core.exception.BizException;
import com.xiaomayi.core.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
/**
* <p>
* PDF文件处理工具类
* </p>
*
* @author 小蚂蚁云团队
* @since 2024-05-30
*/
@Slf4j
public class PdfUtils {
/**
* 合并pdf文档
*
* @param fileNameList 要合并的pdf文档列表
* @param destFile 要保存的文件名
*/
public static void mergePdf(List<String> fileNameList, String destFile) {
try {
File f = new File(destFile);
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
Document document = new Document();
OutputStream bos = Files.newOutputStream(Paths.get(destFile));
PdfCopy copy = new PdfCopy(document, bos);
document.open();
for (String fileName : fileNameList) {
PdfReader reader = new PdfReader(fileName);
copy.addDocument(reader);
copy.freeReader(reader);
reader.close();
}
document.close();
bos.close();
} catch (Exception e) {
log.error("PDF文件合并异常:{}", e.getMessage());
e.printStackTrace();
}
}
/**
* 从模板文件中替换表单域,并生成新的pdf文件
*
* @param fontFile 字体文件
* @param templateFile 模板文件
* @param fileTypeName 文件名称
* @param dataMap 数据源
*/
public static String createPdfFromTemplateFile(String fontFile, String templateFile, String fileTypeName, Map<String, String> dataMap) {
// 生成的新文件路径
String datePath = DateUtils.datePath();
String pathPrefix = "temp/" + datePath + "/";
String tempPath = AppConfig.getProfile() + pathPrefix;
File tempPathFile = new File(tempPath);
if (!tempPathFile.exists()) {
tempPathFile.mkdirs();
}
String nameBase = fileTypeName + "-" + System.currentTimeMillis();
String name = nameBase + ".pdf";
String newFile = tempPath + name;
BaseFont bf;
FileOutputStream out;
PdfReader reader;
ByteArrayOutputStream bos;
PdfStamper stamper;
try {
bf = BaseFont.createFont(fontFile, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
Font font = new Font(bf, 14, Font.NORMAL);
BaseFont baseFont = font.getBaseFont();
out = new FileOutputStream(newFile);
reader = new PdfReader(templateFile);
bos = new ByteArrayOutputStream();
stamper = new PdfStamper(reader, bos);
AcroFields form = stamper.getAcroFields();
// 文字类的内容处理
form.addSubstitutionFont(baseFont);
for (String key : dataMap.keySet()) {
String value = dataMap.get(key);
if ("Yes".equals(value)) {
form.setField(key, value, true);
} else {
form.setField(key, value);
}
}
form.setGenerateAppearances(true);
// 如果为false,生成的PDF文件可以编辑,如果为true,生成的PDF文件不可以编辑
stamper.setFormFlattening(true);
stamper.close();
Document doc = new Document();
// Font font = new Font(bf, 32);
PdfCopy copy = new PdfCopy(doc, out);
doc.open();
PdfReader pdfReader = new PdfReader(bos.toByteArray());
int pages = pdfReader.getNumberOfPages();
for (int i = 1; i <= pages; i++) {
PdfImportedPage importPage = copy.getImportedPage(pdfReader, i);
copy.addPage(importPage);
}
doc.close();
bos.close();
} catch (DocumentException | IOException e) {
e.printStackTrace();
}
return newFile;
}
/**
* 设置水印
*
* @param srcPath 文件地址
* @param markText 水印文字
* @return 返回结果
*/
public static String setWaterMark(String srcPath, String markText) {
String uploadPath = AppConfig.getProfile();
String newFile = srcPath.replace(".pdf", "-water.pdf");
File file = new File(newFile);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
BufferedOutputStream bos = null;
PdfReader reader = null;
PdfStamper stamper = null;
try {
bos = new BufferedOutputStream(Files.newOutputStream(file.toPath()));
reader = new PdfReader(srcPath);
stamper = new PdfStamper(reader, bos);
// 获取总页数 +1, 下面从1开始遍历
int total = reader.getNumberOfPages() + 1;
// 使用classpath下面的字体库
BaseFont base = null;
try {
String fontFile = uploadPath + "/simyou.ttf";
base = BaseFont.createFont(fontFile, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
} catch (Exception e) {
// 日志处理
e.printStackTrace();
}
// 间隔
int interval = -5;
// 获取水印文字的高度和宽度
int textH, textW;
JLabel label = new JLabel();
label.setText(markText);
FontMetrics metrics = label.getFontMetrics(label.getFont());
textH = metrics.getHeight();
textW = metrics.stringWidth(label.getText());
// 设置水印透明度
PdfGState gs = new PdfGState();
gs.setFillOpacity(0.1f);
gs.setStrokeOpacity(0.1f);
com.itextpdf.text.Rectangle pageSizeWithRotation;
PdfContentByte content;
for (int i = 1; i < total; i++) {
// 在内容上方加水印
content = stamper.getOverContent(i);
// 在内容下方加水印
content.saveState();
content.setGState(gs);
// 设置字体和字体大小
content.beginText();
content.setFontAndSize(base, 20);
// 获取每一页的高度、宽度
pageSizeWithRotation = reader.getPageSizeWithRotation(i);
float pageHeight = pageSizeWithRotation.getHeight();
float pageWidth = pageSizeWithRotation.getWidth();
// 根据纸张大小多次添加, 水印文字成30度角倾斜
for (int height = interval + textH; height < pageHeight; height = height + textH * 10) {
for (int width = interval + textW; width < pageWidth + textW; width = width + textW * 3) {
content.showTextAligned(Element.ALIGN_LEFT, markText, width - textW, height - textH, 30);
}
}
content.endText();
}
// 关流
stamper.close();
reader.close();
bos.close();
} catch (DocumentException | IOException e) {
e.printStackTrace();
return e.getMessage();
} finally {
try {
if (stamper != null) {
stamper.close();
}
if (reader != null) {
reader.close();
}
if (bos != null) {
bos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return newFile;
}
/**
* 生成单元格内容
*
* @param text 展示内容
* @param font 字体
* @param isAlignCenter 水平居中:1-居中
* @param isAlignMiddle 垂直居中:1-居中
* @param colspan 合并单元格数量
* @return 返回结果
*/
private static PdfPCell pdfCellStyle(String text, Font font, boolean isAlignCenter, boolean isAlignMiddle, int colspan) {
PdfPCell pdfPCell = new PdfPCell(new Paragraph(text, font));
pdfPCell.setUseAscender(true); // 设置可以居中
pdfPCell.setMinimumHeight(20);
if (isAlignCenter) {
pdfPCell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); // 设置水平居中
}
if (isAlignMiddle) {
pdfPCell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE); // 设置垂直居中
}
if (colspan > 1) {
pdfPCell.setColspan(colspan);
}
return pdfPCell;
}
/**
* 创建PDF表格
*
* @param columns 列数
* @param widths 列宽度数组
* @return PdfPTable
* @throws DocumentException 抛出文档异常
*/
private static PdfPTable pdfTableStyle(int columns, float[] widths) throws DocumentException {
PdfPTable table = new PdfPTable(columns);
table.setTotalWidth(900);
table.setWidths(widths);
table.setSplitLate(false);
table.setSplitRows(true);
return table;
}
/**
* 检查是否存在文件夹并创建
*
* @param path 文件路径
* @throws IOException 抛出IO异常
*/
public static void creatNewFile(String path) throws IOException {
File file = new File(path);
File fileParent = file.getParentFile();
if (!fileParent.exists()) {
fileParent.mkdirs();
}
file.createNewFile();
}
/**
* excel文件转换为PDF文件
*
* @param excelName 需要转化的Excel文件地址,
* @param pdfName 转换后的pdf文件地址
* @return 返回结果
*/
public static Boolean excel2pdf(String excelName, String pdfName) {
if (com.xiaomayi.core.utils.StringUtils.isNull(excelName) || com.xiaomayi.core.utils.StringUtils.isNull(pdfName)) {
throw new SecurityException("参数错误");
}
// 验证License 若不验证则转化出的pdf文档会有水印产生
boolean license = getLicense();
if (!license) {
throw new SecurityException("获取证书失败");
}
try {
File pdfFile = new File(pdfName);
FileInputStream excelStream = new FileInputStream(excelName);
Workbook wb = new Workbook(excelStream);
FileOutputStream fileOS = new FileOutputStream(pdfFile);
String fontPath = AppConfig.getProfile();
FontConfigs.setFontFolder(fontPath, true);
PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
pdfSaveOptions.setOnePagePerSheet(true);
wb.save(fileOS, pdfSaveOptions);
fileOS.close();
} catch (Exception e) {
e.printStackTrace();
throw new BizException(e.getMessage());
}
return true;
}
/**
* 获取认证、去除水印
*
* @return 返回结果
*/
private static Boolean getLicense() {
InputStream is = null;
try {
String path = AppConfig.getProfile();
// 这个文件应该是类似于密码验证(证书),用于获得去除水印的权限
String licenseFile = path + "license.xml";
File file = new File(licenseFile);
if (!file.exists()) {
throw new BizException("证书文件不存在");
}
is = Files.newInputStream(Paths.get(licenseFile));
License license = new License();
license.setLicense(is);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
}