refactor(puzzle): 重构元素DTO及新增元素基类

- 将ElementCreateRequest和PuzzleElementDTO中的elementType从Integer改为String
- 删除所有类型特定字段,新增config和configMap支持JSON配置
- 新增BaseElement抽象基类定义元素通用行为
- 添加ElementConfig接口和具体实现类ImageConfig、TextConfig
- 创建ElementFactory工厂类和ElementRegistrar注册器
- 新增ElementType枚举和ElementValidationException异常类
- 实现ImageElement和TextElement具体元素类
- 添加Position位置信息封装类
This commit is contained in:
2025-11-18 08:13:38 +08:00
parent 5c49a5af9e
commit 3d361200b0
28 changed files with 2988 additions and 615 deletions

View File

@@ -0,0 +1,99 @@
package com.ycwl.basic.puzzle.element;
import com.ycwl.basic.puzzle.element.base.BaseElement;
import com.ycwl.basic.puzzle.element.base.ElementFactory;
import com.ycwl.basic.puzzle.element.enums.ElementType;
import com.ycwl.basic.puzzle.element.impl.ImageElement;
import com.ycwl.basic.puzzle.element.impl.TextElement;
import com.ycwl.basic.puzzle.entity.PuzzleElementEntity;
import com.ycwl.basic.puzzle.test.PuzzleTestDataBuilder;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
/**
* ElementFactory 单元测试
*
* @author Claude
* @since 2025-01-18
*/
@SpringBootTest
class ElementFactoryTest {
@BeforeAll
static void setUp() {
// 确保Element已注册(Spring会自动调用ElementRegistrar)
ElementFactory.register(ElementType.TEXT, TextElement.class);
ElementFactory.register(ElementType.IMAGE, ImageElement.class);
}
@Test
void testCreateTextElement_Success() {
// Given
PuzzleElementEntity entity = PuzzleTestDataBuilder.createTextElement(
1L, "userName", 100, 200, 300, 50, 10,
"测试文字", 24, "#333333"
);
// When
BaseElement element = ElementFactory.create(entity);
// Then
assertNotNull(element);
assertInstanceOf(TextElement.class, element);
assertEquals(ElementType.TEXT, element.getElementType());
assertEquals("userName", element.getElementKey());
assertEquals(100, element.getPosition().getX());
assertEquals(200, element.getPosition().getY());
assertEquals(300, element.getPosition().getWidth());
assertEquals(50, element.getPosition().getHeight());
}
@Test
void testCreateImageElement_Success() {
// Given
PuzzleElementEntity entity = PuzzleTestDataBuilder.createImageElement(
1L, "userAvatar", 50, 100, 100, 100, 5,
"https://example.com/avatar.jpg"
);
// When
BaseElement element = ElementFactory.create(entity);
// Then
assertNotNull(element);
assertInstanceOf(ImageElement.class, element);
assertEquals(ElementType.IMAGE, element.getElementType());
assertEquals("userAvatar", element.getElementKey());
}
@Test
void testCreateElement_InvalidType() {
// Given
PuzzleElementEntity entity = new PuzzleElementEntity();
entity.setElementType("INVALID_TYPE");
entity.setElementKey("test");
entity.setConfig("{}");
// When & Then
assertThrows(IllegalArgumentException.class, () -> ElementFactory.create(entity));
}
@Test
void testCreateElement_NullConfig() {
// Given
PuzzleElementEntity entity = new PuzzleElementEntity();
entity.setElementType("TEXT");
entity.setElementKey("test");
entity.setConfig(null);
entity.setXPosition(0);
entity.setYPosition(0);
entity.setWidth(100);
entity.setHeight(50);
// When & Then
assertThrows(IllegalArgumentException.class, () -> ElementFactory.create(entity));
}
}

View File

@@ -0,0 +1,124 @@
package com.ycwl.basic.puzzle.element;
import com.ycwl.basic.puzzle.element.base.BaseElement;
import com.ycwl.basic.puzzle.element.base.ElementFactory;
import com.ycwl.basic.puzzle.element.exception.ElementValidationException;
import com.ycwl.basic.puzzle.element.renderer.RenderContext;
import com.ycwl.basic.puzzle.entity.PuzzleElementEntity;
import com.ycwl.basic.puzzle.test.PuzzleTestDataBuilder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
/**
* ImageElement 单元测试
*
* @author Claude
* @since 2025-01-18
*/
class ImageElementTest {
private Graphics2D graphics;
private RenderContext context;
@BeforeEach
void setUp() {
BufferedImage canvas = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
graphics = canvas.createGraphics();
Map<String, String> dynamicData = new HashMap<>();
context = new RenderContext(graphics, dynamicData, 800, 600);
}
@Test
void testImageElement_Creation_Success() {
// Given
PuzzleElementEntity entity = PuzzleTestDataBuilder.createImageElement(
1L, "userAvatar", 50, 100, 100, 100, 5,
"https://example.com/avatar.jpg"
);
// When
BaseElement element = ElementFactory.create(entity);
// Then
assertNotNull(element);
assertEquals("userAvatar", element.getElementKey());
}
@Test
void testImageElement_RoundedImage_Success() {
// Given
PuzzleElementEntity entity = PuzzleTestDataBuilder.createRoundedImageElement(
1L, "userAvatar", 50, 100, 100, 100, 5,
"https://example.com/avatar.jpg", 50
);
// When
BaseElement element = ElementFactory.create(entity);
// Then
assertNotNull(element);
// 验证配置包含圆角信息
String schema = element.getConfigSchema();
assertTrue(schema.contains("borderRadius"));
}
@Test
void testImageElement_InvalidConfig_MissingDefaultImageUrl() {
// Given
PuzzleElementEntity entity = new PuzzleElementEntity();
entity.setElementType("IMAGE");
entity.setElementKey("testKey");
entity.setConfig("{\"imageFitMode\":\"FILL\"}"); // 缺少 defaultImageUrl
entity.setXPosition(0);
entity.setYPosition(0);
entity.setWidth(100);
entity.setHeight(100);
// When & Then
assertThrows(ElementValidationException.class, () -> ElementFactory.create(entity));
}
@Test
void testImageElement_InvalidConfig_InvalidBorderRadius() {
// Given
PuzzleElementEntity entity = new PuzzleElementEntity();
entity.setElementType("IMAGE");
entity.setElementKey("testKey");
entity.setConfig("{\"defaultImageUrl\":\"test.jpg\",\"borderRadius\":-1}"); // 非法圆角
entity.setXPosition(0);
entity.setYPosition(0);
entity.setWidth(100);
entity.setHeight(100);
// When & Then
assertThrows(ElementValidationException.class, () -> ElementFactory.create(entity));
}
@Test
void testImageElement_GetConfigSchema() {
// Given
PuzzleElementEntity entity = PuzzleTestDataBuilder.createImageElement(
1L, "userAvatar", 50, 100, 100, 100, 5,
"https://example.com/avatar.jpg"
);
BaseElement element = ElementFactory.create(entity);
// When
String schema = element.getConfigSchema();
// Then
assertNotNull(schema);
assertTrue(schema.contains("defaultImageUrl"));
assertTrue(schema.contains("imageFitMode"));
assertTrue(schema.contains("borderRadius"));
}
}

View File

@@ -0,0 +1,107 @@
package com.ycwl.basic.puzzle.element;
import com.ycwl.basic.puzzle.element.base.BaseElement;
import com.ycwl.basic.puzzle.element.base.ElementFactory;
import com.ycwl.basic.puzzle.element.exception.ElementValidationException;
import com.ycwl.basic.puzzle.element.renderer.RenderContext;
import com.ycwl.basic.puzzle.entity.PuzzleElementEntity;
import com.ycwl.basic.puzzle.test.PuzzleTestDataBuilder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
/**
* TextElement 单元测试
*
* @author Claude
* @since 2025-01-18
*/
class TextElementTest {
private Graphics2D graphics;
private RenderContext context;
@BeforeEach
void setUp() {
BufferedImage canvas = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
graphics = canvas.createGraphics();
Map<String, String> dynamicData = new HashMap<>();
context = new RenderContext(graphics, dynamicData, 800, 600);
}
@Test
void testTextElement_Render_Success() {
// Given
PuzzleElementEntity entity = PuzzleTestDataBuilder.createTextElement(
1L, "userName", 100, 200, 300, 50, 10,
"默认文字", 24, "#333333"
);
BaseElement element = ElementFactory.create(entity);
// 添加动态数据
context.getDynamicData().put("userName", "张三");
// When & Then (不抛出异常即为成功)
assertDoesNotThrow(() -> element.render(context));
}
@Test
void testTextElement_InvalidConfig_MissingDefaultText() {
// Given
PuzzleElementEntity entity = new PuzzleElementEntity();
entity.setElementType("TEXT");
entity.setElementKey("testKey");
entity.setConfig("{\"fontSize\":14,\"fontColor\":\"#000000\"}"); // 缺少 defaultText
entity.setXPosition(0);
entity.setYPosition(0);
entity.setWidth(100);
entity.setHeight(50);
// When & Then
assertThrows(ElementValidationException.class, () -> ElementFactory.create(entity));
}
@Test
void testTextElement_InvalidConfig_InvalidFontSize() {
// Given
PuzzleElementEntity entity = new PuzzleElementEntity();
entity.setElementType("TEXT");
entity.setElementKey("testKey");
entity.setConfig("{\"defaultText\":\"test\",\"fontSize\":0,\"fontColor\":\"#000000\"}"); // 非法字号
entity.setXPosition(0);
entity.setYPosition(0);
entity.setWidth(100);
entity.setHeight(50);
// When & Then
assertThrows(ElementValidationException.class, () -> ElementFactory.create(entity));
}
@Test
void testTextElement_GetConfigSchema() {
// Given
PuzzleElementEntity entity = PuzzleTestDataBuilder.createTextElement(
1L, "userName", 100, 200, 300, 50, 10,
"测试文字", 24, "#333333"
);
BaseElement element = ElementFactory.create(entity);
// When
String schema = element.getConfigSchema();
// Then
assertNotNull(schema);
assertTrue(schema.contains("defaultText"));
assertTrue(schema.contains("fontSize"));
assertTrue(schema.contains("fontColor"));
}
}

View File

@@ -0,0 +1,103 @@
package com.ycwl.basic.puzzle.integration;
import com.ycwl.basic.puzzle.element.base.BaseElement;
import com.ycwl.basic.puzzle.element.base.ElementFactory;
import com.ycwl.basic.puzzle.element.enums.ElementType;
import com.ycwl.basic.puzzle.element.impl.ImageElement;
import com.ycwl.basic.puzzle.element.impl.TextElement;
import com.ycwl.basic.puzzle.entity.PuzzleElementEntity;
import com.ycwl.basic.puzzle.test.PuzzleTestDataBuilder;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* Element 调试测试
* 用于验证 Element 创建和配置是否正确
*/
class ElementDebugTest {
@BeforeAll
static void registerElements() {
ElementFactory.register(ElementType.TEXT, TextElement.class);
ElementFactory.register(ElementType.IMAGE, ImageElement.class);
}
@Test
void testCreateTextElement() {
System.out.println("=== 测试创建 TEXT 元素 ===");
PuzzleElementEntity entity = PuzzleTestDataBuilder.createTextElement(
1L, "testText", 100, 200, 300, 50, 10,
"测试文字", 24, "#333333"
);
System.out.println("Entity elementType: " + entity.getElementType());
System.out.println("Entity config: " + entity.getConfig());
try {
BaseElement element = ElementFactory.create(entity);
System.out.println("✅ Element 创建成功");
System.out.println("Element type: " + element.getElementType());
System.out.println("Element key: " + element.getElementKey());
assertNotNull(element);
} catch (Exception e) {
System.err.println("❌ Element 创建失败: " + e.getMessage());
e.printStackTrace();
fail("Element 创建失败");
}
}
@Test
void testCreateImageElement() {
System.out.println("\n=== 测试创建 IMAGE 元素 ===");
PuzzleElementEntity entity = PuzzleTestDataBuilder.createImageElement(
1L, "testImage", 50, 100, 100, 100, 5,
"https://example.com/test.jpg"
);
System.out.println("Entity elementType: " + entity.getElementType());
System.out.println("Entity config: " + entity.getConfig());
try {
BaseElement element = ElementFactory.create(entity);
System.out.println("✅ Element 创建成功");
System.out.println("Element type: " + element.getElementType());
System.out.println("Element key: " + element.getElementKey());
assertNotNull(element);
} catch (Exception e) {
System.err.println("❌ Element 创建失败: " + e.getMessage());
e.printStackTrace();
fail("Element 创建失败");
}
}
@Test
void testRealScenarioElements() {
System.out.println("\n=== 测试现实场景元素创建 ===");
var elements = PuzzleTestDataBuilder.createRealScenarioElements(1L);
System.out.println("元素数量: " + elements.size());
int successCount = 0;
for (PuzzleElementEntity entity : elements) {
System.out.println("\n--- 测试元素: " + entity.getElementKey() + " ---");
System.out.println("Type: " + entity.getElementType());
System.out.println("Config: " + entity.getConfig());
try {
BaseElement element = ElementFactory.create(entity);
System.out.println("✅ 创建成功");
successCount++;
} catch (Exception e) {
System.err.println("❌ 创建失败: " + e.getMessage());
e.printStackTrace();
}
}
System.out.println("\n总结: " + successCount + "/" + elements.size() + " 个元素创建成功");
assertEquals(elements.size(), successCount, "所有元素都应该创建成功");
}
}

View File

@@ -1,11 +1,15 @@
package com.ycwl.basic.puzzle.integration;
import com.ycwl.basic.puzzle.element.enums.ElementType;
import com.ycwl.basic.puzzle.entity.PuzzleElementEntity;
import com.ycwl.basic.puzzle.entity.PuzzleTemplateEntity;
import com.ycwl.basic.puzzle.test.MockImageUtil;
import com.ycwl.basic.puzzle.test.PuzzleTestDataBuilder;
import com.ycwl.basic.puzzle.util.PuzzleImageRenderer;
import org.apache.commons.lang3.Strings;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@@ -18,6 +22,7 @@ import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.*;
@@ -102,6 +107,18 @@ class PuzzleRealScenarioIntegrationTest {
dynamicData.put("qrCode", mockImageFiles.get("qrCode").getAbsolutePath());
dynamicData.put("bottomText", "奇遇时光乐园\n2025.11.11");
// 打印调试信息
System.out.println("\n=== 调试信息 ===");
System.out.println("元素数量: " + elements.size());
for (PuzzleElementEntity element : elements) {
System.out.println("元素: " + element.getElementKey() +
" | 类型: " + element.getElementType() +
" | 配置: " + element.getConfig());
}
System.out.println("\n动态数据:");
dynamicData.forEach((k, v) -> System.out.println(" " + k + " = " + v));
System.out.println("=================\n");
// When: 渲染拼图
BufferedImage result = renderer.render(template, elements, dynamicData);
@@ -192,17 +209,6 @@ class PuzzleRealScenarioIntegrationTest {
List<PuzzleElementEntity> elements = PuzzleTestDataBuilder.createRealScenarioElements(template.getId());
// 设置默认图片路径
for (PuzzleElementEntity element : elements) {
if (element.getElementType() == 1) {
// 图片元素使用本地文件
String key = element.getElementKey();
if (mockImageFiles.containsKey(key)) {
element.setDefaultImageUrl(mockImageFiles.get(key).getAbsolutePath());
}
}
}
// When: 不传动态数据,使用默认值
Map<String, String> dynamicData = new HashMap<>();
BufferedImage result = renderer.render(template, elements, dynamicData);
@@ -297,4 +303,17 @@ class PuzzleRealScenarioIntegrationTest {
data.put("bottomText", "测试文字内容");
return data;
}
@BeforeAll
static void registerElements() {
// 注册 Element 类型(确保工厂可用)
com.ycwl.basic.puzzle.element.base.ElementFactory.register(
com.ycwl.basic.puzzle.element.enums.ElementType.TEXT,
com.ycwl.basic.puzzle.element.impl.TextElement.class
);
com.ycwl.basic.puzzle.element.base.ElementFactory.register(
com.ycwl.basic.puzzle.element.enums.ElementType.IMAGE,
com.ycwl.basic.puzzle.element.impl.ImageElement.class
);
}
}

View File

@@ -60,7 +60,7 @@ public class PuzzleTestDataBuilder {
PuzzleElementEntity element = new PuzzleElementEntity();
element.setId(System.currentTimeMillis());
element.setTemplateId(templateId);
element.setElementType(1); // 图片
element.setElementType("IMAGE"); // 修改为字符串类型
element.setElementKey(elementKey);
element.setElementName(elementKey);
element.setXPosition(x);
@@ -70,9 +70,11 @@ public class PuzzleTestDataBuilder {
element.setZIndex(zIndex);
element.setRotation(0);
element.setOpacity(100);
element.setDefaultImageUrl(imageUrl);
element.setImageFitMode("FILL"); // 使用FILL模式确保图片完全填充区域
element.setBorderRadius(0);
// 使用JSON配置
String config = String.format("{\"defaultImageUrl\":\"%s\",\"imageFitMode\":\"FILL\",\"borderRadius\":0}", imageUrl);
element.setConfig(config);
element.setCreateTime(new Date());
element.setUpdateTime(new Date());
element.setDeleted(0);
@@ -85,8 +87,28 @@ public class PuzzleTestDataBuilder {
public static PuzzleElementEntity createRoundedImageElement(Long templateId, String elementKey,
int x, int y, int width, int height,
int zIndex, String imageUrl, int borderRadius) {
PuzzleElementEntity element = createImageElement(templateId, elementKey, x, y, width, height, zIndex, imageUrl);
element.setBorderRadius(borderRadius);
PuzzleElementEntity element = new PuzzleElementEntity();
element.setId(System.currentTimeMillis());
element.setTemplateId(templateId);
element.setElementType("IMAGE");
element.setElementKey(elementKey);
element.setElementName(elementKey);
element.setXPosition(x);
element.setYPosition(y);
element.setWidth(width);
element.setHeight(height);
element.setZIndex(zIndex);
element.setRotation(0);
element.setOpacity(100);
// 使用JSON配置(包含圆角)
String config = String.format("{\"defaultImageUrl\":\"%s\",\"imageFitMode\":\"COVER\",\"borderRadius\":%d}",
imageUrl, borderRadius);
element.setConfig(config);
element.setCreateTime(new Date());
element.setUpdateTime(new Date());
element.setDeleted(0);
return element;
}
@@ -100,7 +122,7 @@ public class PuzzleTestDataBuilder {
PuzzleElementEntity element = new PuzzleElementEntity();
element.setId(System.currentTimeMillis());
element.setTemplateId(templateId);
element.setElementType(2); // 文字
element.setElementType("TEXT"); // 修改为字符串类型
element.setElementKey(elementKey);
element.setElementName(elementKey);
element.setXPosition(x);
@@ -110,16 +132,15 @@ public class PuzzleTestDataBuilder {
element.setZIndex(zIndex);
element.setRotation(0);
element.setOpacity(100);
element.setDefaultText(defaultText);
element.setFontFamily("微软雅黑");
element.setFontSize(fontSize);
element.setFontColor(fontColor);
element.setFontWeight("NORMAL");
element.setFontStyle("NORMAL");
element.setTextAlign("LEFT");
element.setLineHeight(BigDecimal.valueOf(1.5));
element.setMaxLines(null);
element.setTextDecoration("NONE");
// 使用JSON配置
String config = String.format(
"{\"defaultText\":\"%s\",\"fontFamily\":\"微软雅黑\",\"fontSize\":%d,\"fontColor\":\"%s\"," +
"\"fontWeight\":\"NORMAL\",\"fontStyle\":\"NORMAL\",\"textAlign\":\"LEFT\"," +
"\"lineHeight\":1.5,\"textDecoration\":\"NONE\"}",
defaultText, fontSize, fontColor);
element.setConfig(config);
element.setCreateTime(new Date());
element.setUpdateTime(new Date());
element.setDeleted(0);
@@ -133,9 +154,31 @@ public class PuzzleTestDataBuilder {
int x, int y, int width, int height,
int zIndex, String defaultText,
int fontSize, String fontColor, String textAlign) {
PuzzleElementEntity element = createTextElement(templateId, elementKey, x, y, width, height, zIndex, defaultText, fontSize, fontColor);
element.setFontWeight("BOLD");
element.setTextAlign(textAlign);
PuzzleElementEntity element = new PuzzleElementEntity();
element.setId(System.currentTimeMillis());
element.setTemplateId(templateId);
element.setElementType("TEXT");
element.setElementKey(elementKey);
element.setElementName(elementKey);
element.setXPosition(x);
element.setYPosition(y);
element.setWidth(width);
element.setHeight(height);
element.setZIndex(zIndex);
element.setRotation(0);
element.setOpacity(100);
// 使用JSON配置(粗体)
String config = String.format(
"{\"defaultText\":\"%s\",\"fontFamily\":\"微软雅黑\",\"fontSize\":%d,\"fontColor\":\"%s\"," +
"\"fontWeight\":\"BOLD\",\"fontStyle\":\"NORMAL\",\"textAlign\":\"%s\"," +
"\"lineHeight\":1.5,\"textDecoration\":\"NONE\"}",
defaultText, fontSize, fontColor, textAlign);
element.setConfig(config);
element.setCreateTime(new Date());
element.setUpdateTime(new Date());
element.setDeleted(0);
return element;
}
@@ -175,9 +218,9 @@ public class PuzzleTestDataBuilder {
public static List<PuzzleElementEntity> createRealScenarioElements(Long templateId) {
List<PuzzleElementEntity> elements = new ArrayList<>();
// 画布总高度1520,每张图片460高度
int imageHeight = 460;
int bottomHeight = 140; // 剩余高度:1520 - 460*3 = 140
// 画布总高度1520,每张图片470高度
int imageHeight = 470;
int bottomHeight = 110; // 剩余高度:1520 - 470*3 = 110
// 上方3张图片,每张470高度
elements.add(createImageElement(templateId, "image1", 0, 0, 1020, imageHeight, 1,
@@ -190,17 +233,50 @@ public class PuzzleTestDataBuilder {
"https://example.com/image3.jpg"));
// 底部区域起始Y坐标
int bottomY = imageHeight * 3; // 1380
int bottomY = imageHeight * 3; // 1410
// 底部二维码(左侧,占满底部高度)
elements.add(createImageElement(templateId, "qrCode", 20, bottomY + 10, 120, 120, 2,
"https://example.com/qrcode.png"));
PuzzleElementEntity qrElement = new PuzzleElementEntity();
qrElement.setId(System.currentTimeMillis());
qrElement.setTemplateId(templateId);
qrElement.setElementType("IMAGE");
qrElement.setElementKey("qrCode");
qrElement.setElementName("qrCode");
qrElement.setXPosition(20);
qrElement.setYPosition(bottomY + 5);
qrElement.setWidth(100);
qrElement.setHeight(100);
qrElement.setZIndex(2);
qrElement.setRotation(0);
qrElement.setOpacity(100);
qrElement.setConfig("{\"defaultImageUrl\":\"https://example.com/qrcode.png\",\"imageFitMode\":\"CONTAIN\",\"borderRadius\":0}");
qrElement.setCreateTime(new Date());
qrElement.setUpdateTime(new Date());
qrElement.setDeleted(0);
elements.add(qrElement);
// 底部文字(右侧,占满剩余宽度和高度)
int textX = 140; // 二维码右侧留20像素间距
int textWidth = 1020 - textX - 20; // 右侧留20像素边距
elements.add(createBoldTextElement(templateId, "bottomText", textX, bottomY + 20, textWidth, bottomHeight - 20, 2,
"扫码查看详情", 18, "#333333", "RIGHT"));
PuzzleElementEntity textElement = new PuzzleElementEntity();
textElement.setId(System.currentTimeMillis() + 1);
textElement.setTemplateId(templateId);
textElement.setElementType("TEXT");
textElement.setElementKey("bottomText");
textElement.setElementName("bottomText");
textElement.setXPosition(textX);
textElement.setYPosition(bottomY + 10);
textElement.setWidth(textWidth);
textElement.setHeight(bottomHeight - 10);
textElement.setZIndex(2);
textElement.setRotation(0);
textElement.setOpacity(100);
textElement.setConfig("{\"defaultText\":\"扫码查看详情\",\"fontFamily\":\"微软雅黑\",\"fontSize\":18,\"fontColor\":\"#333333\",\"fontWeight\":\"BOLD\",\"textAlign\":\"RIGHT\",\"lineHeight\":1.5,\"textDecoration\":\"NONE\"}");
textElement.setCreateTime(new Date());
textElement.setUpdateTime(new Date());
textElement.setDeleted(0);
elements.add(textElement);
return elements;
}

View File

@@ -1,5 +1,9 @@
package com.ycwl.basic.puzzle.test;
import com.ycwl.basic.puzzle.element.base.ElementFactory;
import com.ycwl.basic.puzzle.element.enums.ElementType;
import com.ycwl.basic.puzzle.element.impl.ImageElement;
import com.ycwl.basic.puzzle.element.impl.TextElement;
import com.ycwl.basic.puzzle.entity.PuzzleElementEntity;
import com.ycwl.basic.puzzle.entity.PuzzleTemplateEntity;
import com.ycwl.basic.puzzle.util.PuzzleImageRenderer;
@@ -56,7 +60,7 @@ public class RealScenarioTestHelper {
* 创建场景图片(1020x470)
*/
private void createSceneImage(String key, String text, Color bgColor) throws IOException {
BufferedImage image = MockImageUtil.createImageWithText(1020, 460, text, bgColor, Color.BLACK);
BufferedImage image = MockImageUtil.createImageWithText(1020, 470, text, bgColor, Color.BLACK);
File file = saveImage(image, key + ".jpg");
resourceFiles.put(key, file);
}
@@ -224,6 +228,10 @@ public class RealScenarioTestHelper {
* 快速测试方法(主方法,可直接运行)
*/
public static void main(String[] args) throws IOException {
// 【重要】注册 Element 类型(主方法运行必须先注册)
ElementFactory.register(ElementType.TEXT, TextElement.class);
ElementFactory.register(ElementType.IMAGE, ImageElement.class);
// 创建临时目录
Path tempDir = Files.createTempDirectory("puzzle_test_");
System.out.println("📂 测试目录: " + tempDir.toAbsolutePath());