fix:优化小票打印逻辑

This commit is contained in:
石崇礼 2025-03-14 16:31:53 +08:00
parent 438d52da0c
commit ba18bf9558
4 changed files with 53 additions and 24 deletions

View File

@ -1,11 +1,14 @@
package com.dpkj.modules.autoReplyPrint.controller; package com.dpkj.modules.autoReplyPrint.controller;
import com.alibaba.fastjson.JSONObject;
import com.dpkj.common.exception.RRException;
import com.dpkj.common.vo.Result; import com.dpkj.common.vo.Result;
import com.dpkj.modules.autoReplyPrint.request.ReceiptPrintRequest; import com.dpkj.modules.autoReplyPrint.request.ReceiptPrintRequest;
import com.dpkj.modules.autoReplyPrint.service.ImagePrintService; import com.dpkj.modules.autoReplyPrint.service.ImagePrintService;
import com.dpkj.modules.autoReplyPrint.service.impl.TemplateService; import com.dpkj.modules.autoReplyPrint.service.impl.TemplateService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.thymeleaf.util.StringUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -23,13 +26,33 @@ public class ReceiptPrintController {
@Resource(name = "USBImagePrint") @Resource(name = "USBImagePrint")
private ImagePrintService usbImagePrintService; private ImagePrintService usbImagePrintService;
@Resource
private TemplateService templateService;
@PostMapping("/print") @PostMapping("/print")
private Result<Void> print(@Validated @RequestBody ReceiptPrintRequest request){ private Result<Void> print(@Validated @RequestBody ReceiptPrintRequest request){
String devName = "VID:0x0FE6,PID:0x811E"; // 采用默认的devName不进行入参传值了 String devName = "VID:0x0FE6,PID:0x811E"; // 采用默认的devName不进行入参传值了
StringBuilder filePath = new StringBuilder(request.getFileDir());
//
// 校验是否选中了模板,如果没选中模板的话则不需要另外生成了
if ( !StringUtils.isEmpty(request.getTemplateName()) && !StringUtils.isEmpty(request.getFileDir())){
String templateFillData = request.getTemplateFillData();
if ( !StringUtils.isEmpty(templateFillData)){
byte[] image = templateService.generateReceiptImage(
JSONObject.parseObject(request.getTemplateFillData()),
request.getTemplateName(),
request.getWidth(),
request.getHeight(),
filePath);
}
}else {
throw new RRException("模板渲染错误");
}
usbImagePrintService.imagePrintFromPath(devName, usbImagePrintService.imagePrintFromPath(devName,
request.getWidth(), request.getWidth(),
request.getHeight(), request.getHeight(),
request.getFileDir(), filePath.toString(),
1, 1,
0); 0);
return Result.ok(); return Result.ok();

View File

@ -28,7 +28,8 @@ public class TemplateController {
@RequestParam Integer height, @RequestParam Integer height,
@PathVariable String templateName, @PathVariable String templateName,
@RequestParam(defaultValue = "E:\\images") String saveDir) { @RequestParam(defaultValue = "E:\\images") String saveDir) {
this.templateService.generateReceiptImage(JSONObject.parseObject(jsonData), templateName, width, height, saveDir); StringBuilder fileDir = new StringBuilder(saveDir);
this.templateService.generateReceiptImage(JSONObject.parseObject(jsonData), templateName, width, height, fileDir);
return Result.ok("模板生成成功"); return Result.ok("模板生成成功");
} }
@ -44,7 +45,8 @@ public class TemplateController {
"<h2><span th:text='${name}'> </span></h2>\n" + "<h2><span th:text='${name}'> </span></h2>\n" +
"</body>\n" + "</body>\n" +
"</html>"; "</html>";
this.templateService.generateReceiptImage(JSONObject.parseObject(jsonData), html, width, height, saveDir); StringBuilder fileDir = new StringBuilder(saveDir);
this.templateService.generateReceiptImage(JSONObject.parseObject(jsonData), html, width, height, fileDir);
return Result.ok("模板生成成功"); return Result.ok("模板生成成功");
} }

View File

@ -32,12 +32,14 @@ public class ReceiptPrintRequest implements Serializable {
/** /**
* 模板名称也可以是自己写的html的字符串文件 * 模板名称也可以是自己写的html的字符串文件
*/ */
@NotBlank(message = "模板不能为空")
private String templateName = "receipt"; private String templateName = "receipt";
/** /**
* 填充模板的数据,必填也可以通过自己设置的模板名称进行设计部分设计规则 * 填充模板的数据,必填也可以通过自己设置的模板名称进行设计部分设计规则
* <p>1特殊字段(二维码图片)类型qrCodeBase64_2base64Type_120_120字段解析qrCodeBase64为字段名称 * <p>1特殊字段(二维码图片)类型qrCodeBase64_2base64Type_1_120_120字段解析qrCodeBase64为字段名称
* _2base64Type为将这个数据转换为图片类型的base64编码第一个_120图片的宽度第二个_120的为图片高度</p> * 第一个1为打印类型1为二维码2为条形码
* _2base64Type为将这个数据转换为图片类型的base64编码第二个_120图片的宽度第三个_120的为图片高度</p>
* <p>2需要对传入的JSON数据进行URI编码</p> * <p>2需要对传入的JSON数据进行URI编码</p>
* <p>3{"hospitalName":"澜沧县中医医院","registeTerminalName":"中国农业银行自助终端","registeType":"自助挂号","name":"刘博雅","gender":"","age":28,"birthDate":"1996-06-31","cardNumber":"6221**********0731","outpatientNumber":"2501150038","department":"普外科门诊","visitLevel":"普通号","doctor":"普通门诊","sequence":"1","registerDate":"2025-01-15","totalFee":4.00,"paymentMethod":"微信扫码支付","orderNumber":"","transactionNumber":"2025011513090412092794szztzzj","qrCodeBase64_2base64Type_120_120":"这里应是二维码的Base64编码数据如果有","terminalNumber":"12092794","printTime":"2025-01-15 13:10:08"}</p> * <p>3{"hospitalName":"澜沧县中医医院","registeTerminalName":"中国农业银行自助终端","registeType":"自助挂号","name":"刘博雅","gender":"","age":28,"birthDate":"1996-06-31","cardNumber":"6221**********0731","outpatientNumber":"2501150038","department":"普外科门诊","visitLevel":"普通号","doctor":"普通门诊","sequence":"1","registerDate":"2025-01-15","totalFee":4.00,"paymentMethod":"微信扫码支付","orderNumber":"","transactionNumber":"2025011513090412092794szztzzj","qrCodeBase64_2base64Type_120_120":"这里应是二维码的Base64编码数据如果有","terminalNumber":"12092794","printTime":"2025-01-15 13:10:08"}</p>
*/ */

View File

@ -12,6 +12,7 @@ import org.jsoup.Jsoup;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext; import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine; import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.templatemode.TemplateMode; import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.StringTemplateResolver; import org.thymeleaf.templateresolver.StringTemplateResolver;
@ -40,8 +41,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.thymeleaf.context.Context;
/** /**
* 模板服务类 * 模板服务类
* *
@ -64,7 +63,7 @@ public class TemplateService {
* @param saveDir 图片的保存路径如果为空那么不进行图片的保存 * @param saveDir 图片的保存路径如果为空那么不进行图片的保存
* @return 图片字节数组 * @return 图片字节数组
*/ */
public byte[] generateReceiptImage(JSONObject data, String template, int width, int height, String saveDir) { public byte[] generateReceiptImage(JSONObject data, String template, int width, int height, StringBuilder saveDir) {
try { try {
// 获取模板上下文 // 获取模板上下文
Context context = this.getContext(data); Context context = this.getContext(data);
@ -91,11 +90,12 @@ public class TemplateService {
BufferedImage image = this.generate(html, width, height); BufferedImage image = this.generate(html, width, height);
// 保存图片 // 保存图片
if (saveDir != null && !"".equals(saveDir)) { if (saveDir != null && !"".equals(saveDir.toString())) {
String outputPath = saveDir + "\\genera_image_" + System.currentTimeMillis() + ".png"; String outputPath = saveDir.toString() + "\\genera_image_" + System.currentTimeMillis() + ".png";
ImageIO.write(image, "PNG", new File(outputPath)); ImageIO.write(image, "PNG", new File(outputPath));
saveDir.reverse();
saveDir.append(outputPath);
} }
ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
ImageIO.write(image, "PNG", byteOutputStream); ImageIO.write(image, "PNG", byteOutputStream);
return byteOutputStream.toByteArray(); return byteOutputStream.toByteArray();
@ -135,19 +135,21 @@ public class TemplateService {
private Context getContext(JSONObject data) { private Context getContext(JSONObject data) {
// 创建Thymeleaf上下文 // 创建Thymeleaf上下文
Context context = new Context(); Context context = new Context();
Set<String> keys = data.keySet(); if ( data != null) {
for (String key : keys) { Set<String> keys = data.keySet();
// 判单是否有图片生成统一后面采用的是_2base64Type 例子 qrCodeBase64_2base64Type_120_120 for (String key : keys) {
String[] split = key.split("_"); // 判单是否有图片生成统一后面采用的是_2base64Type
if (split.length > 1 && split[1].equals("2base64Type")) { String[] split = key.split("_");
int width = split.length > 2 ? Integer.parseInt(split[2]) : 100; if (split.length > 1 && split[1].equals("2base64Type")) {
int height = split.length > 3 ? Integer.parseInt(split[3]) : 100; int width = split.length > 2 ? Integer.parseInt(split[2]) : 100;
// 如果是图片类型,需要进行base64转换 int height = split.length > 3 ? Integer.parseInt(split[3]) : 100;
String base64 = this.generateQRCode(String.valueOf(data.get(key)), width, height); // 如果是图片类型,需要进行base64转换
context.setVariable(split[0], "data:image/jpeg;base64," + base64); String base64 = this.generateQRCode(String.valueOf(data.get(key)), width, height);
} else { context.setVariable(split[0], "data:image/jpeg;base64," + base64);
// 普通字段直接设置 } else {
context.setVariable(key, data.get(key)); // 普通字段直接设置
context.setVariable(key, data.get(key));
}
} }
} }