基于Spring Boot生成PNG/JPG格式发票并发送至手机号的技术方案咨询
基于Spring Boot实现发票图片生成与短信发送方案
一、发票图片生成的可行方案
1. 直接基于模板图片填充文字(最适配现有模板)
这种方式通过Java原生的BufferedImage API操作现有模板图片,在指定坐标位置绘制发票字段内容,无需额外依赖,开发成本低,适合固定格式的简单模板。
核心步骤:
- 用图片工具(如Photoshop、系统画图工具)定位每个发票字段的坐标(x,y)。
- 读取模板图片,通过
Graphics2D对象绘制文字,设置字体、颜色、对齐方式。 - 保存生成后的图片为PNG/JPG格式。
示例代码:
import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; public class TemplateBasedInvoiceGenerator { public static void generate(String templatePath, String outputPath) throws IOException { // 加载发票模板图片 BufferedImage templateImg = ImageIO.read(new File(templatePath)); Graphics2D g2d = templateImg.createGraphics(); // 配置字体(确保支持中文,避免乱码) Font textFont = new Font("SimSun", Font.PLAIN, 14); g2d.setFont(textFont); g2d.setColor(Color.BLACK); // 开启抗锯齿,让文字更清晰 g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); // 填充发票字段(坐标需根据实际模板调整) g2d.drawString("发票编号:INV20240520001", 160, 90); g2d.drawString("客户名称:某某科技有限公司", 160, 135); g2d.drawString("开票日期:2024-05-20", 480, 135); g2d.drawString("合计金额:¥1,200.00", 480, 380); // 释放绘图资源 g2d.dispose(); // 保存为PNG格式 ImageIO.write(templateImg, "PNG", new File(outputPath)); } }
2. HTML模板引擎转图片(灵活适配复杂模板)
如果发票样式需要频繁调整,或者包含复杂排版(如表格、动态样式),推荐用Thymeleaf/Freemarker生成HTML发票页面,再通过工具将HTML转为图片。这种方式通过CSS控制样式,维护成本低,扩展性强。
核心依赖:
- Thymeleaf:用于生成动态HTML
- Flying Saucer:将HTML/CSS渲染为图片
示例步骤:
- 引入Maven依赖:
<dependencies> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring6</artifactId> <version>3.1.2.RELEASE</version> </dependency> <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-core</artifactId> <version>9.1.22</version> </dependency> </dependencies>
- 编写Thymeleaf模板(
templates/invoice.html):
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <style> .invoice-container { width: 800px; padding: 20px; border: 1px solid #ccc; } .invoice-header { text-align: center; margin-bottom: 30px; } .invoice-info { display: flex; justify-content: space-between; margin-bottom: 20px; } .amount { font-size: 18px; font-weight: bold; color: #e63946; } </style> </head> <body> <div class="invoice-container"> <div class="invoice-header"> <h2>增值税普通发票</h2> </div> <div class="invoice-info"> <div> <p>发票编号:<span th:text="${invoiceNo}"></span></p> <p>客户名称:<span th:text="${customerName}"></span></p> </div> <div> <p>开票日期:<span th:text="${invoiceDate}"></span></p> </div> </div> <div class="amount">合计金额:¥<span th:text="${totalAmount}"></span></div> </div> </body> </html>
- 生成HTML并转图片:
import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; import org.xhtmlrenderer.swing.Java2DRenderer; import java.awt.image.BufferedImage; import java.io.FileOutputStream; import javax.imageio.ImageIO; public class HtmlToInvoiceImageGenerator { public static void generate(TemplateEngine templateEngine, String outputPath) throws Exception { Context context = new Context(); context.setVariable("invoiceNo", "INV20240520001"); context.setVariable("customerName", "某某科技有限公司"); context.setVariable("invoiceDate", "2024-05-20"); context.setVariable("totalAmount", "1,200.00"); // 渲染生成HTML字符串 String htmlContent = templateEngine.process("invoice", context); // 将HTML转为图片(设置宽高适配发票尺寸) Java2DRenderer renderer = new Java2DRenderer(htmlContent, 800, 1100); BufferedImage invoiceImage = renderer.getImage(); // 保存图片 ImageIO.write(invoiceImage, "PNG", new FileOutputStream(outputPath)); } }
3. PDF转图片(兼顾多格式输出)
如果业务需要同时生成PDF版和图片版发票,可先通过iText生成PDF发票,再用Apache PDFBox将PDF转为图片。这种方式适合需要多格式存档的场景。
核心依赖:
- iText:生成PDF
- Apache PDFBox:PDF转图片
二、图片发票的短信发送实现
由于直接通过短信发送图片受运营商限制,推荐先将生成的发票图片上传至云存储(如阿里云OSS、腾讯云COS),再发送图片访问链接到指定手机号。
以阿里云短信为例,核心代码示例:
import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; import com.aliyuncs.profile.DefaultProfile; public class InvoiceSmsSender { public static void sendInvoiceLink(String phoneNumber, String imageUrl) throws Exception { // 初始化短信客户端 DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "你的AccessKeyId", "你的AccessKeySecret"); IAcsClient client = new DefaultAcsClient(profile); // 构建短信请求 SendSmsRequest request = new SendSmsRequest(); request.setPhoneNumbers(phoneNumber); request.setSignName("你的短信签名"); request.setTemplateCode("你的短信模板ID"); request.setTemplateParam("{\"invoiceUrl\":\"" + imageUrl + "\"}"); // 发送短信 SendSmsResponse response = client.getAcsResponse(request); // 根据response处理发送结果(如判断是否发送成功) } }
三、最优方案选择
- 固定简单模板:优先选择「模板图片填充文字」方案,依赖少、开发快、性能高。
- 复杂/动态样式模板:优先选择「HTML模板引擎转图片」方案,通过CSS控制样式,维护成本低。
- 需要多格式输出:选择「PDF转图片」方案,兼顾PDF存档和图片发送需求。
内容的提问来源于stack exchange,提问作者Beksultan
相关产品推荐
相关产品推荐

