Browse Source

选择系统字体

master
han\hanst 1 year ago
parent
commit
0c6f6effd5
  1. 108
      src/main/java/com/gaotao/modules/base/controller/FontController.java
  2. 10
      src/main/java/com/gaotao/modules/base/entity/ReportLabelList.java
  3. 30
      src/main/java/com/gaotao/modules/base/service/FontService.java
  4. 267
      src/main/java/com/gaotao/modules/base/service/Impl/FontServiceImpl.java
  5. 147
      src/main/java/com/gaotao/modules/base/service/Impl/LabelDataProcessorServiceImpl.java
  6. 15
      src/main/java/com/gaotao/modules/base/service/LabelDataProcessorService.java
  7. 172
      src/main/java/com/gaotao/modules/base/utils/ZplGenerator.java

108
src/main/java/com/gaotao/modules/base/controller/FontController.java

@ -0,0 +1,108 @@
package com.gaotao.modules.base.controller;
import com.gaotao.modules.base.service.FontService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 字体管理控制器
*/
@Slf4j
@RestController
@RequestMapping("/font")
public class FontController {
@Autowired
private FontService fontService;
/**
* 获取系统可用字体列表
*/
@RequestMapping("/available")
public Map<String, Object> getAvailableFonts() {
Map<String, Object> result = new HashMap<>();
try {
List<Map<String, String>> fonts = fontService.getAvailableFonts();
result.put("success", true);
result.put("data", fonts);
result.put("total", fonts.size());
result.put("message", "获取字体列表成功");
log.info("返回字体列表,共 {} 个字体", fonts.size());
} catch (Exception e) {
log.error("获取字体列表失败", e);
result.put("success", false);
result.put("data", null);
result.put("message", "获取字体列表失败: " + e.getMessage());
}
return result;
}
/**
* 检查字体是否可用
*/
@GetMapping("/check/{fontName}")
public Map<String, Object> checkFont(@PathVariable String fontName) {
Map<String, Object> result = new HashMap<>();
try {
boolean available = fontService.isFontAvailable(fontName);
String fontFile = fontService.getFontFilePath(fontName);
result.put("success", true);
result.put("fontName", fontName);
result.put("available", available);
result.put("fontFile", fontFile);
result.put("supported", fontFile != null);
} catch (Exception e) {
log.error("检查字体失败: {}", fontName, e);
result.put("success", false);
result.put("message", "检查字体失败: " + e.getMessage());
}
return result;
}
/**
* 获取字体分类
*/
@GetMapping("/categories")
public Map<String, Object> getFontCategories() {
Map<String, Object> result = new HashMap<>();
try {
List<Map<String, String>> fonts = fontService.getAvailableFonts();
// 按类别分组
Map<String, Integer> categories = new HashMap<>();
for (Map<String, String> font : fonts) {
String category = font.get("category");
categories.put(category, categories.getOrDefault(category, 0) + 1);
}
result.put("success", true);
result.put("categories", categories);
result.put("message", "获取字体分类成功");
} catch (Exception e) {
log.error("获取字体分类失败", e);
result.put("success", false);
result.put("message", "获取字体分类失败: " + e.getMessage());
}
return result;
}
}

10
src/main/java/com/gaotao/modules/base/entity/ReportLabelList.java

@ -56,4 +56,14 @@ public class ReportLabelList {
private String replaceFrom;
private String replaceTo;
// 字体相关字段
private String fontFamily; // 字体族名称
private String fontStyle; // 字体样式normal, italic
private String fontWeight; // 字体粗细normal, bold
private String textAlign; // 文本对齐left, center, right
private Integer letterSpacing; // 字符间距
private Integer lineHeight; // 行高
private Boolean fontItalic; // 斜体
private Boolean fontUnderline; // 下划线
}

30
src/main/java/com/gaotao/modules/base/service/FontService.java

@ -0,0 +1,30 @@
package com.gaotao.modules.base.service;
import java.util.List;
import java.util.Map;
/**
* 字体服务接口
*/
public interface FontService {
/**
* 获取系统可用字体列表
* @return 字体列表
*/
List<Map<String, String>> getAvailableFonts();
/**
* 获取字体文件路径
* @param fontName 字体名称
* @return 字体文件路径如果不存在返回null
*/
String getFontFilePath(String fontName);
/**
* 检查字体是否可用
* @param fontName 字体名称
* @return 是否可用
*/
boolean isFontAvailable(String fontName);
}

267
src/main/java/com/gaotao/modules/base/service/Impl/FontServiceImpl.java

@ -0,0 +1,267 @@
package com.gaotao.modules.base.service.Impl;
import com.gaotao.modules.base.service.FontService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.awt.*;
import java.util.*;
import java.util.List;
/**
* 字体服务实现类
*/
@Slf4j
@Service
public class FontServiceImpl implements FontService {
// 字体名称到ZPL字体文件的映射
private static final Map<String, String> FONT_FILE_MAPPING = new HashMap<>();
static {
// 中文字体映射
FONT_FILE_MAPPING.put("Microsoft YaHei", "MSYH.TTF");
FONT_FILE_MAPPING.put("微软雅黑", "MSYH.TTF");
FONT_FILE_MAPPING.put("SimSun", "SIMSUN.TTC");
FONT_FILE_MAPPING.put("宋体", "SIMSUN.TTC");
FONT_FILE_MAPPING.put("SimHei", "SIMHEI.TTF");
FONT_FILE_MAPPING.put("黑体", "SIMHEI.TTF");
FONT_FILE_MAPPING.put("KaiTi", "KAITI.TTF");
FONT_FILE_MAPPING.put("楷体", "KAITI.TTF");
FONT_FILE_MAPPING.put("FangSong", "SIMFANG.TTF");
FONT_FILE_MAPPING.put("仿宋", "SIMFANG.TTF");
// 英文字体映射
FONT_FILE_MAPPING.put("Arial", "ARIAL.TTF");
FONT_FILE_MAPPING.put("Times New Roman", "TIMES.TTF");
FONT_FILE_MAPPING.put("Courier New", "COUR.TTF");
FONT_FILE_MAPPING.put("Helvetica", "HELV.TTF");
FONT_FILE_MAPPING.put("Verdana", "VERDANA.TTF");
FONT_FILE_MAPPING.put("Georgia", "GEORGIA.TTF");
FONT_FILE_MAPPING.put("Tahoma", "TAHOMA.TTF");
FONT_FILE_MAPPING.put("Trebuchet MS", "TREBUC.TTF");
FONT_FILE_MAPPING.put("Lucida Console", "LUCON.TTF");
FONT_FILE_MAPPING.put("Impact", "IMPACT.TTF");
FONT_FILE_MAPPING.put("Comic Sans MS", "COMIC.TTF");
FONT_FILE_MAPPING.put("Palatino", "PALA.TTF");
FONT_FILE_MAPPING.put("Garamond", "GARA.TTF");
FONT_FILE_MAPPING.put("Bookman", "BOOKOS.TTF");
}
@Override
public List<Map<String, String>> getAvailableFonts() {
List<Map<String, String>> fontList = new ArrayList<>();
try {
// 获取系统图形环境
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
// 获取所有可用字体的名字
String[] fontNames = ge.getAvailableFontFamilyNames();
log.info("系统检测到 {} 个可用字体", fontNames.length);
// 处理系统字体
Set<String> processedFonts = new HashSet<>();
for (String fontName : fontNames) {
// 避免重复添加
if (processedFonts.contains(fontName)) {
continue;
}
processedFonts.add(fontName);
Map<String, String> fontInfo = new HashMap<>();
fontInfo.put("name", fontName);
fontInfo.put("value", fontName);
fontInfo.put("category", getFontCategory(fontName));
fontInfo.put("description", getFontDescription(fontName));
// 检查是否有对应的ZPL字体文件
String fontFile = getFontFilePath(fontName);
if (fontFile != null) {
fontInfo.put("zplFile", fontFile);
fontInfo.put("supported", "true");
} else {
fontInfo.put("supported", "false");
}
fontList.add(fontInfo);
}
// 按类别和名称排序
fontList.sort((f1, f2) -> {
// 默认字体排在最前面
if ("default".equals(f1.get("value"))) return -1;
if ("default".equals(f2.get("value"))) return 1;
// 按类别排序
int categoryCompare = f1.get("category").compareTo(f2.get("category"));
if (categoryCompare != 0) {
return categoryCompare;
}
// 同类别按名称排序
return f1.get("name").compareTo(f2.get("name"));
});
log.info("处理后可用字体数量: {}", fontList.size());
} catch (Exception e) {
log.error("获取系统字体失败", e);
// 如果获取系统字体失败返回基本字体列表
fontList = getBasicFontList();
}
return fontList;
}
@Override
public String getFontFilePath(String fontName) {
if (fontName == null || fontName.isEmpty()) {
return null;
}
// 直接查找映射
String fontFile = FONT_FILE_MAPPING.get(fontName);
if (fontFile != null) {
return fontFile;
}
// 尝试模糊匹配
for (Map.Entry<String, String> entry : FONT_FILE_MAPPING.entrySet()) {
if (fontName.toLowerCase().contains(entry.getKey().toLowerCase()) ||
entry.getKey().toLowerCase().contains(fontName.toLowerCase())) {
return entry.getValue();
}
}
return null;
}
@Override
public boolean isFontAvailable(String fontName) {
if (fontName == null || fontName.isEmpty() || "default".equals(fontName)) {
return true;
}
try {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
String[] fontNames = ge.getAvailableFontFamilyNames();
for (String availableFont : fontNames) {
if (availableFont.equals(fontName)) {
return true;
}
}
} catch (Exception e) {
log.warn("检查字体可用性失败: {}", fontName, e);
}
return false;
}
/**
* 获取字体类别
*/
private String getFontCategory(String fontName) {
if (fontName == null) {
return "other";
}
String lowerName = fontName.toLowerCase();
// 中文字体
if (lowerName.contains("微软雅黑") || lowerName.contains("microsoft yahei") ||
lowerName.contains("宋体") || lowerName.contains("simsun") ||
lowerName.contains("黑体") || lowerName.contains("simhei") ||
lowerName.contains("楷体") || lowerName.contains("kaiti") ||
lowerName.contains("仿宋") || lowerName.contains("fangsong")) {
return "chinese";
}
// 常用英文字体
if (lowerName.contains("arial") || lowerName.contains("times") ||
lowerName.contains("courier") || lowerName.contains("helvetica") ||
lowerName.contains("verdana") || lowerName.contains("georgia") ||
lowerName.contains("tahoma") || lowerName.contains("calibri")) {
return "english";
}
// 等宽字体
if (lowerName.contains("mono") || lowerName.contains("courier") ||
lowerName.contains("consolas") || lowerName.contains("lucida console")) {
return "monospace";
}
// 装饰字体
if (lowerName.contains("comic") || lowerName.contains("impact") ||
lowerName.contains("brush") || lowerName.contains("script")) {
return "decorative";
}
return "other";
}
/**
* 获取字体描述
*/
private String getFontDescription(String fontName) {
if (fontName == null) {
return "";
}
String category = getFontCategory(fontName);
switch (category) {
case "chinese":
return "中文字体";
case "english":
return "英文字体";
case "monospace":
return "等宽字体";
case "decorative":
return "装饰字体";
default:
return "系统字体";
}
}
/**
* 获取基本字体列表备用方案
*/
private List<Map<String, String>> getBasicFontList() {
List<Map<String, String>> basicFonts = new ArrayList<>();
// 基本字体配置
String[][] basicFontConfig = {
{"默认字体", "default", "system", "系统默认字体"},
{"微软雅黑", "Microsoft YaHei", "chinese", "现代中文字体"},
{"宋体", "SimSun", "chinese", "传统中文字体"},
{"黑体", "SimHei", "chinese", "粗体中文字体"},
{"Arial", "Arial", "english", "无衬线英文字体"},
{"Times New Roman", "Times New Roman", "english", "衬线英文字体"},
{"Courier New", "Courier New", "monospace", "等宽英文字体"}
};
for (String[] config : basicFontConfig) {
Map<String, String> fontInfo = new HashMap<>();
fontInfo.put("name", config[0]);
fontInfo.put("value", config[1]);
fontInfo.put("category", config[2]);
fontInfo.put("description", config[3]);
String fontFile = getFontFilePath(config[1]);
if (fontFile != null) {
fontInfo.put("zplFile", fontFile);
fontInfo.put("supported", "true");
} else {
fontInfo.put("supported", "false");
}
basicFonts.add(fontInfo);
}
return basicFonts;
}
}

147
src/main/java/com/gaotao/modules/base/service/Impl/LabelDataProcessorServiceImpl.java

@ -40,6 +40,9 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
@Autowired
private com.gaotao.modules.base.service.BaseService baseService;
@Autowired
private com.gaotao.modules.base.service.FontService fontService;
@Override
public List<ReportLabelList> processLabelData(List<ReportLabelList> elements, Map<String, Object> dataMap) {
if (elements == null || elements.isEmpty()) {
@ -47,18 +50,18 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
}
List<ReportLabelList> processedElements = new ArrayList<>();
// 第一轮处理处理基本数据替换不包含元素组合
List<ReportLabelList> firstPassElements = new ArrayList<>();
for (ReportLabelList element : elements) {
ReportLabelList processedElement = processElementData(element, dataMap);
ReportLabelList processedElement = processElementData(element, dataMap,true);
firstPassElements.add(processedElement);
}
// 第二轮处理处理元素组合引用
for (ReportLabelList element : firstPassElements) {
ReportLabelList finalElement = processElementCombinations(element, dataMap, firstPassElements);
// 如果元素被设置为不显示则跳过该元素
if (("onecode".equals(element.getType()) || "qrcode".equals(element.getType())
|| "text".equals(element.getType()) || "pic".equals(element.getType()))
@ -76,14 +79,14 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
/**
* 处理元素组合引用
*/
private ReportLabelList processElementCombinations(ReportLabelList element, Map<String, Object> dataMap,
private ReportLabelList processElementCombinations(ReportLabelList element, Map<String, Object> dataMap,
List<ReportLabelList> allElements) {
if (element == null || element.getData() == null || element.getData().isEmpty()) {
return element;
}
String originalData = element.getData();
// 检查是否包含元素引用
if (containsElementReferences(originalData)) {
ReportLabelList processedElement = copyElement(element);
@ -103,14 +106,14 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
if (data == null || data.isEmpty()) {
return false;
}
// 检查是否包含 {元素类型} 格式的引用排除 #{字段名} 格式
Pattern pattern = Pattern.compile("\\{(?!#)[^}]+\\}");
return pattern.matcher(data).find() || data.startsWith("CUSTOM:");
}
@Override
public ReportLabelList processElementData(ReportLabelList element, Map<String, Object> dataMap) {
public ReportLabelList processElementData(ReportLabelList element, Map<String, Object> dataMap,Boolean nextSeqNotExist) {
if (element == null || element.getData() == null || element.getData().isEmpty()) {
return element;
}
@ -152,7 +155,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
break;
case "serialNumber":
// 处理流水号元素生成真实的流水号
processedElement.setData(processSerialNumberElement(element, dataMap));
processedElement.setData(processSerialNumberElement(element, dataMap,nextSeqNotExist));
break;
case "pic":
break;
@ -178,7 +181,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
String orientation = labelSetting.getPaperOrientation() != null ? labelSetting.getPaperOrientation() : "portrait";
Integer dpi = labelSetting.getDpi() != null ? labelSetting.getDpi() : 203;
ZplGenerator generator = new ZplGenerator(orientation, dpi, canvasSize);
ZplGenerator generator = new ZplGenerator(orientation, dpi, canvasSize, fontService);
// 4. 生成ZPL代码
String zplCode = generator.generate(processedElements);
@ -211,7 +214,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
* 处理元素组合数据
* 支持将多个元素的内容按特定格式组合
*/
private String processElementCombination(String originalData, Map<String, Object> dataMap,
private String processElementCombination(String originalData, Map<String, Object> dataMap,
List<ReportLabelList> allElements, ReportLabelList currentElement) {
if (originalData == null || originalData.isEmpty()) {
return originalData;
@ -224,7 +227,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
// 处理模板模式的元素引用 {元素类型} {元素类型(内容)}
String processedData = originalData;
// 创建元素映射便于查找
Map<String, ReportLabelList> elementMap = new HashMap<>();
for (ReportLabelList element : allElements) {
@ -253,7 +256,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
ReportLabelList referencedElement = findElementByReference(reference, elementMap);
if (referencedElement != null) {
// 递归处理引用的元素数据
replacement = processElementData(referencedElement, dataMap).getData();
replacement = processElementData(referencedElement, dataMap,false).getData();
if (replacement == null) {
replacement = "";
}
@ -273,19 +276,19 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
/**
* 处理自定义组合表达式
*/
private String processCustomCombination(String expression, Map<String, Object> dataMap,
private String processCustomCombination(String expression, Map<String, Object> dataMap,
List<ReportLabelList> allElements) {
try {
// 这里可以实现简单的表达式处理
// 为了安全起见只支持有限的操作
// 示例支持简单的字符串拼接和条件判断
if (expression.contains("elements.filter")) {
return processElementsFilter(expression, allElements, dataMap);
} else if (expression.contains("dataMap.")) {
return processDataMapAccess(expression, dataMap);
}
// 默认返回表达式本身
return expression;
} catch (Exception e) {
@ -297,7 +300,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
/**
* 处理元素过滤表达式
*/
private String processElementsFilter(String expression, List<ReportLabelList> allElements,
private String processElementsFilter(String expression, List<ReportLabelList> allElements,
Map<String, Object> dataMap) {
// 简单实现elements.filter(e => e.type === 'text').map(e => e.data).join('-')
if (expression.contains("e.type === 'text'")) {
@ -305,7 +308,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
.filter(e -> "text".equals(e.getType()))
.map(e -> e.getData() != null ? e.getData() : "")
.collect(Collectors.toList());
String separator = "-";
if (expression.contains(".join('")) {
int start = expression.indexOf(".join('") + 7;
@ -314,10 +317,10 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
separator = expression.substring(start, end);
}
}
return String.join(separator, textData);
}
return expression;
}
@ -329,7 +332,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
Pattern pattern = Pattern.compile("dataMap\\.([a-zA-Z_][a-zA-Z0-9_]*)");
Matcher matcher = pattern.matcher(expression);
StringBuffer result = new StringBuffer();
while (matcher.find()) {
String fieldName = matcher.group(1);
Object value = dataMap.get(fieldName);
@ -337,7 +340,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
matcher.appendReplacement(result, Matcher.quoteReplacement(replacement));
}
matcher.appendTail(result);
return result.toString();
}
@ -353,29 +356,29 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
// 检查是否是带内容的引用格式文本(内容) 类型(内容)
Pattern contentPattern = Pattern.compile("^(文本|一维码|二维码|图片|流水号)\\((.+)\\)$");
Matcher contentMatcher = contentPattern.matcher(reference);
if (contentMatcher.matches()) {
String typeName = contentMatcher.group(1);
String expectedContent = contentMatcher.group(2);
// 根据类型名称获取对应的类型键
String targetType = getTypeKeyByName(typeName);
if (targetType != null) {
// 精确匹配同时匹配类型和内容
for (ReportLabelList element : elementMap.values()) {
if (targetType.equals(element.getType()) &&
if (targetType.equals(element.getType()) &&
expectedContent.equals(element.getData())) {
log.debug("精确匹配到元素: type={}, data={}", element.getType(), element.getData());
return element;
}
}
// 如果精确匹配失败尝试部分内容匹配
for (ReportLabelList element : elementMap.values()) {
if (targetType.equals(element.getType()) &&
element.getData() != null &&
if (targetType.equals(element.getType()) &&
element.getData() != null &&
element.getData().contains(expectedContent)) {
log.debug("部分匹配到元素: type={}, data={}, expected={}",
log.debug("部分匹配到元素: type={}, data={}, expected={}",
element.getType(), element.getData(), expectedContent);
return element;
}
@ -386,7 +389,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
// 模糊匹配按类型- 只有在没有内容指定时才使用
String[] typeNames = {"文本", "一维码", "二维码", "图片", "流水号"};
String[] typeKeys = {"text", "onecode", "qrcode", "pic", "serialNumber"};
for (int i = 0; i < typeNames.length; i++) {
if (reference.equals(typeNames[i])) { // 改为精确匹配类型名称
// 返回该类型的第一个元素保持向后兼容
@ -402,7 +405,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
log.warn("未找到匹配的元素引用: {}", reference);
return null;
}
/**
* 根据类型名称获取类型键
*/
@ -429,12 +432,12 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
typeNames.put("serialNumber", "流水号");
String typeName = typeNames.getOrDefault(element.getType(), element.getType());
String content = element.getData() != null && !element.getData().isEmpty()
? "(" + (element.getData().length() > 10
? element.getData().substring(0, 10) + "..."
String content = element.getData() != null && !element.getData().isEmpty()
? "(" + (element.getData().length() > 10
? element.getData().substring(0, 10) + "..."
: element.getData()) + ")"
: "";
return typeName + content;
}
@ -948,6 +951,15 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
copy.setReplaceFrom(original.getReplaceFrom());
copy.setReplaceTo(original.getReplaceTo());
copy.setFontFamily(original.getFontFamily());
copy.setFontStyle(original.getFontStyle());
copy.setFontWeight(original.getFontWeight());
copy.setTextAlign(original.getTextAlign());
copy.setLetterSpacing(original.getLetterSpacing());
copy.setLineHeight(original.getLineHeight());
copy.setFontItalic(original.getFontItalic());
copy.setFontUnderline(original.getFontUnderline());
return copy;
}
@ -958,7 +970,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
* @param dataMap 数据源映射
* @return 生成的流水号字符串
*/
private String processSerialNumberElement(ReportLabelList element, Map<String, Object> dataMap) {
private String processSerialNumberElement(ReportLabelList element, Map<String, Object> dataMap,Boolean nextSeqNotExist) {
try {
log.debug("开始处理流水号元素: itemNo={}, data={}", element.getItemNo(), element.getData());
@ -986,7 +998,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
log.debug("生成的KeyInfo: {}", keyInfo);
// 3. 获取或生成下一个流水号
int nextSeqNo = getNextSerialNumber(element.getReportId(), element.getItemNo(), keyInfo, intervalValue);
int nextSeqNo = getNextSerialNumber(element.getReportId(), element.getItemNo(), keyInfo, intervalValue,nextSeqNotExist);
log.debug("获取的下一个流水号: {}", nextSeqNo);
// 4. 格式化流水号
@ -1067,7 +1079,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
* @param intervalValue 步长
* @return 下一个流水号
*/
private int getNextSerialNumber(String reportId, Integer itemNo, String keyInfo, int intervalValue) {
private int getNextSerialNumber(String reportId, Integer itemNo, String keyInfo, int intervalValue,Boolean nextSeqNotExist) {
try {
// 查询现有的流水号信息
com.gaotao.modules.base.entity.LabelContentData query = new com.gaotao.modules.base.entity.LabelContentData();
@ -1086,36 +1098,39 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
}
int nextSeqNo;
if (matchingInfo != null) {
// 存在记录递增流水号
nextSeqNo = matchingInfo.getLastSeqNo() + intervalValue;
// 更新数据库记录
com.gaotao.modules.base.entity.LabelContentSerialInfoData updateInfo = new com.gaotao.modules.base.entity.LabelContentSerialInfoData();
updateInfo.setLabelNo(reportId);
updateInfo.setItemNo(itemNo);
updateInfo.setKeyInfo(keyInfo);
updateInfo.setLastSeqNo(nextSeqNo);
updateInfo.setOriKeyInfo(keyInfo); // 用于WHERE条件
baseService.updateLabelSerialInfo(updateInfo);
log.debug("更新流水号记录: reportId={}, itemNo={}, keyInfo={}, lastSeqNo={}",
reportId, itemNo, keyInfo, nextSeqNo);
if (nextSeqNotExist) {
if (matchingInfo != null) {
// 存在记录递增流水号
nextSeqNo = matchingInfo.getLastSeqNo() + intervalValue;
// 更新数据库记录
com.gaotao.modules.base.entity.LabelContentSerialInfoData updateInfo = new com.gaotao.modules.base.entity.LabelContentSerialInfoData();
updateInfo.setLabelNo(reportId);
updateInfo.setItemNo(itemNo);
updateInfo.setKeyInfo(keyInfo);
updateInfo.setLastSeqNo(nextSeqNo);
updateInfo.setOriKeyInfo(keyInfo); // 用于WHERE条件
baseService.updateLabelSerialInfo(updateInfo);
log.debug("更新流水号记录: reportId={}, itemNo={}, keyInfo={}, lastSeqNo={}",
reportId, itemNo, keyInfo, nextSeqNo);
} else {
// 不存在记录创建新记录
nextSeqNo = intervalValue; // 从步长开始
com.gaotao.modules.base.entity.LabelContentSerialInfoData newInfo = new com.gaotao.modules.base.entity.LabelContentSerialInfoData();
newInfo.setLabelNo(reportId);
newInfo.setItemNo(itemNo);
newInfo.setKeyInfo(keyInfo);
newInfo.setLastSeqNo(nextSeqNo);
baseService.insertLabelSerialInfo(newInfo);
log.debug("创建流水号记录: reportId={}, itemNo={}, keyInfo={}, lastSeqNo={}",
reportId, itemNo, keyInfo, nextSeqNo);
}
} else {
// 不存在记录创建新记录
nextSeqNo = intervalValue; // 从步长开始
com.gaotao.modules.base.entity.LabelContentSerialInfoData newInfo = new com.gaotao.modules.base.entity.LabelContentSerialInfoData();
newInfo.setLabelNo(reportId);
newInfo.setItemNo(itemNo);
newInfo.setKeyInfo(keyInfo);
newInfo.setLastSeqNo(nextSeqNo);
baseService.insertLabelSerialInfo(newInfo);
log.debug("创建流水号记录: reportId={}, itemNo={}, keyInfo={}, lastSeqNo={}",
reportId, itemNo, keyInfo, nextSeqNo);
nextSeqNo = matchingInfo!=null?matchingInfo.getLastSeqNo(): intervalValue; // 如果不存在记录则使用步长作为初始值
}
return nextSeqNo;
} catch (Exception e) {

15
src/main/java/com/gaotao/modules/base/service/LabelDataProcessorService.java

@ -10,7 +10,7 @@ import java.util.Map;
* 负责将标签模板中的数据源字段替换成真实数据并进行格式化处理生成ZPL代码
*/
public interface LabelDataProcessorService {
/**
* 处理标签元素数据将数据源字段替换为真实数据
* @param elements 标签元素列表
@ -18,15 +18,16 @@ public interface LabelDataProcessorService {
* @return 处理后的标签元素列表
*/
List<ReportLabelList> processLabelData(List<ReportLabelList> elements, Map<String, Object> dataMap);
/**
* 处理单个标签元素的数据
* @param element 标签元素
* @param dataMap 数据源映射
* @param nextSeqNotExist 是否存在下一个序列号
* @return 处理后的标签元素
*/
ReportLabelList processElementData(ReportLabelList element, Map<String, Object> dataMap);
ReportLabelList processElementData(ReportLabelList element, Map<String, Object> dataMap,Boolean nextSeqNotExist);
/**
* 生成带真实数据的ZPL代码
* @param elements 标签元素列表
@ -35,7 +36,7 @@ public interface LabelDataProcessorService {
* @return ZPL代码
*/
String generateZplWithData(List<ReportLabelList> elements, Map<String, Object> dataMap, LabelSettingData labelSetting);
/**
* 格式化数字数据
* @param value 原始数值
@ -45,7 +46,7 @@ public interface LabelDataProcessorService {
* @return 格式化后的字符串
*/
String formatNumber(Object value, Integer decimalPlaces, Boolean showDecimalPlaces, Boolean thousandsSeparator);
/**
* 替换数据源字段
* @param text 包含数据源字段的文本
@ -62,4 +63,4 @@ public interface LabelDataProcessorService {
* @return 处理后的ZPL代码
*/
String generateZplWithRealData(String reportId, List<ReportLabelList> elements, LabelSettingData labelSetting);
}
}

172
src/main/java/com/gaotao/modules/base/utils/ZplGenerator.java

@ -19,6 +19,7 @@ public class ZplGenerator {
private Integer dpi;
private CoordinateTransformer transformer;
private ZplConfig config;
private com.gaotao.modules.base.service.FontService fontService;
public ZplGenerator(String orientation, Integer dpi, CoordinateTransformer.CanvasSize canvasSize) {
this.orientation = orientation != null ? orientation : "portrait";
@ -27,6 +28,12 @@ public class ZplGenerator {
this.config = getConfig();
}
public ZplGenerator(String orientation, Integer dpi, CoordinateTransformer.CanvasSize canvasSize,
com.gaotao.modules.base.service.FontService fontService) {
this(orientation, dpi, canvasSize);
this.fontService = fontService;
}
/**
* 获取ZPL配置参数
*/
@ -110,9 +117,10 @@ public class ZplGenerator {
private String generateTextZPL(ReportLabelList element, int x, int y) {
StringBuilder zpl = new StringBuilder();
// 设置中文字体
// 设置字体
Integer fontSize = element.getFontSize() != null ? element.getFontSize() : 30;
zpl.append("^CI28 ^CWJ,E:MSYH.TTF ^CFJ,").append(fontSize).append("\n");
String fontCommand = generateFontCommand(element, fontSize);
zpl.append(fontCommand).append("\n");
// 如果有复选框
if (Boolean.TRUE.equals(element.getIsChecked())) {
@ -123,6 +131,9 @@ public class ZplGenerator {
String data = element.getData() != null ? element.getData() : "";
// 处理文本对齐
String alignmentParam = getTextAlignmentParam(element.getTextAlign());
// 基础文本
if (Boolean.TRUE.equals(element.getNewline())) {
// 多行文本
@ -130,7 +141,7 @@ public class ZplGenerator {
int lineRows = element.getLineRows() != null ? element.getLineRows() : 2;
zpl.append("^FO").append(x).append(",").append(y)
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0^CFJ,").append(fontSize)
.append(",0,").append(alignmentParam).append("^CFJ,").append(fontSize)
.append("^FD").append(data).append("^FS");
} else {
// 单行文本
@ -145,15 +156,15 @@ public class ZplGenerator {
int lineRows = element.getLineRows() != null ? element.getLineRows() : 2;
zpl.append("\n^FO").append(x + 1).append(",").append(y)
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0^CFJ,").append(fontSize)
.append(",0,").append(alignmentParam).append("^CFJ,").append(fontSize)
.append("^FD").append(data).append("^FS");
zpl.append("\n^FO").append(x).append(",").append(y + 1)
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0^CFJ,").append(fontSize)
.append(",0,").append(alignmentParam).append("^CFJ,").append(fontSize)
.append("^FD").append(data).append("^FS");
zpl.append("\n^FO").append(x + 1).append(",").append(y + 1)
.append("^FB").append(lineWidth).append(",").append(lineRows)
.append(",0^CFJ,").append(fontSize)
.append(",0,").append(alignmentParam).append("^CFJ,").append(fontSize)
.append("^FD").append(data).append("^FS");
} else {
zpl.append("\n^FO").append(x + 1).append(",").append(y)
@ -165,9 +176,158 @@ public class ZplGenerator {
}
}
// 下划线效果通过线条实现
if (Boolean.TRUE.equals(element.getFontUnderline())) {
int textWidth = estimateTextWidth(data, fontSize);
int underlineY = y + fontSize + 2;
zpl.append("\n^FO").append(x).append(",").append(underlineY)
.append("^GB").append(textWidth).append(",2,2,B^FS");
}
return zpl.toString();
}
/**
* 生成字体命令
*/
private String generateFontCommand(ReportLabelList element, Integer fontSize) {
StringBuilder fontCmd = new StringBuilder();
// 设置字符编码
fontCmd.append("^CI28");
// 根据字体族选择字体
String fontFamily = element.getFontFamily();
String fontFile = null;
if (fontFamily != null && !"default".equals(fontFamily)) {
// 优先使用FontService获取字体文件
if (fontService != null) {
fontFile = fontService.getFontFilePath(fontFamily);
log.debug("通过FontService获取字体文件: {} -> {}", fontFamily, fontFile);
}
// 如果FontService没有找到使用静态映射
if (fontFile == null) {
fontFile = mapFontFamilyToFile(fontFamily);
log.debug("通过静态映射获取字体文件: {} -> {}", fontFamily, fontFile);
}
if (fontFile != null) {
fontCmd.append(" ^CWJ,E:").append(fontFile);
} else {
// 使用系统默认字体
fontCmd.append(" ^CWJ,E:MSYH.TTF");
log.warn("未找到字体文件映射,使用默认字体: {}", fontFamily);
}
} else {
// 默认使用微软雅黑
fontCmd.append(" ^CWJ,E:MSYH.TTF");
}
// 设置字体大小
fontCmd.append(" ^CFJ,").append(fontSize);
return fontCmd.toString();
}
/**
* 映射字体族到字体文件
* 注意这是一个静态方法在实际使用中应该通过FontService来获取
*/
private String mapFontFamilyToFile(String fontFamily) {
// 基本字体映射静态备用方案
switch (fontFamily) {
case "Microsoft YaHei":
case "微软雅黑":
return "MSYH.TTF";
case "SimSun":
case "宋体":
return "SIMSUN.TTC";
case "SimHei":
case "黑体":
return "SIMHEI.TTF";
case "KaiTi":
case "楷体":
return "KAITI.TTF";
case "FangSong":
case "仿宋":
return "SIMFANG.TTF";
case "Arial":
return "ARIAL.TTF";
case "Times New Roman":
return "TIMES.TTF";
case "Courier New":
return "COUR.TTF";
case "Helvetica":
return "HELV.TTF";
case "Verdana":
return "VERDANA.TTF";
case "Georgia":
return "GEORGIA.TTF";
case "Tahoma":
return "TAHOMA.TTF";
case "Trebuchet MS":
return "TREBUC.TTF";
case "Lucida Console":
return "LUCON.TTF";
case "Impact":
return "IMPACT.TTF";
case "Comic Sans MS":
return "COMIC.TTF";
case "Palatino":
return "PALA.TTF";
case "Garamond":
return "GARA.TTF";
case "Bookman":
return "BOOKOS.TTF";
default:
return null; // 使用默认字体
}
}
/**
* 获取文本对齐参数
*/
private String getTextAlignmentParam(String textAlign) {
if (textAlign == null) {
return "L"; // 默认左对齐
}
switch (textAlign) {
case "center":
return "C";
case "right":
return "R";
case "left":
default:
return "L";
}
}
/**
* 估算文本宽度用于下划线
*/
private int estimateTextWidth(String text, Integer fontSize) {
if (text == null || text.isEmpty()) {
return 0;
}
// 简单估算中文字符按字体大小计算英文字符按字体大小的0.6倍计算
int chineseCount = 0;
int englishCount = 0;
for (char c : text.toCharArray()) {
if (c >= 0x4e00 && c <= 0x9fff) {
chineseCount++;
} else {
englishCount++;
}
}
return (int) (chineseCount * fontSize + englishCount * fontSize * 0.6);
}
/**
* 生成一维码ZPL代码
*/

Loading…
Cancel
Save