Extend business block definition protocol
This commit is contained in:
@@ -0,0 +1,50 @@
|
|||||||
|
package com.ruoyi.generator.domain.front.dto.block;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class BusinessBlockDefinition
|
||||||
|
{
|
||||||
|
private String code;
|
||||||
|
private String name;
|
||||||
|
private String category;
|
||||||
|
private String description;
|
||||||
|
private String placement;
|
||||||
|
private String kind;
|
||||||
|
private List<String> surfaces;
|
||||||
|
private List<String> placements;
|
||||||
|
private String chartType;
|
||||||
|
private String datasetSchema;
|
||||||
|
private Integer defaultSpan;
|
||||||
|
private Integer version;
|
||||||
|
private List<BusinessBlockConfigField> configs;
|
||||||
|
private List<BusinessBlockTemplateFile> templates;
|
||||||
|
|
||||||
|
public String getCode() { return code; }
|
||||||
|
public void setCode(String code) { this.code = code; }
|
||||||
|
public String getName() { return name; }
|
||||||
|
public void setName(String name) { this.name = name; }
|
||||||
|
public String getCategory() { return category; }
|
||||||
|
public void setCategory(String category) { this.category = category; }
|
||||||
|
public String getDescription() { return description; }
|
||||||
|
public void setDescription(String description) { this.description = description; }
|
||||||
|
public String getPlacement() { return placement; }
|
||||||
|
public void setPlacement(String placement) { this.placement = placement; }
|
||||||
|
public String getKind() { return kind; }
|
||||||
|
public void setKind(String kind) { this.kind = kind; }
|
||||||
|
public List<String> getSurfaces() { return surfaces; }
|
||||||
|
public void setSurfaces(List<String> surfaces) { this.surfaces = surfaces; }
|
||||||
|
public List<String> getPlacements() { return placements; }
|
||||||
|
public void setPlacements(List<String> placements) { this.placements = placements; }
|
||||||
|
public String getChartType() { return chartType; }
|
||||||
|
public void setChartType(String chartType) { this.chartType = chartType; }
|
||||||
|
public String getDatasetSchema() { return datasetSchema; }
|
||||||
|
public void setDatasetSchema(String datasetSchema) { this.datasetSchema = datasetSchema; }
|
||||||
|
public Integer getDefaultSpan() { return defaultSpan; }
|
||||||
|
public void setDefaultSpan(Integer defaultSpan) { this.defaultSpan = defaultSpan; }
|
||||||
|
public Integer getVersion() { return version; }
|
||||||
|
public void setVersion(Integer version) { this.version = version; }
|
||||||
|
public List<BusinessBlockConfigField> getConfigs() { return configs; }
|
||||||
|
public void setConfigs(List<BusinessBlockConfigField> configs) { this.configs = configs; }
|
||||||
|
public List<BusinessBlockTemplateFile> getTemplates() { return templates; }
|
||||||
|
public void setTemplates(List<BusinessBlockTemplateFile> templates) { this.templates = templates; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,346 @@
|
|||||||
|
package com.ruoyi.generator.service.front;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import com.ruoyi.generator.domain.GenTable;
|
||||||
|
import com.ruoyi.generator.domain.GenTableColumn;
|
||||||
|
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockConfigField;
|
||||||
|
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockDefinition;
|
||||||
|
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockInstance;
|
||||||
|
import com.ruoyi.generator.domain.front.dto.block.PageBusinessBlockLayout;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class BusinessBlockRegistryService
|
||||||
|
{
|
||||||
|
public static final String BUSINESS_BLOCK_CANVAS = "business-blocks-v1";
|
||||||
|
public static final String PLACEMENT_PAGE = "page";
|
||||||
|
public static final String PLACEMENT_EMBEDDED = "embedded";
|
||||||
|
|
||||||
|
private volatile List<BusinessBlockDefinition> cachedDefinitions;
|
||||||
|
|
||||||
|
public List<BusinessBlockDefinition> listDefinitions()
|
||||||
|
{
|
||||||
|
if (cachedDefinitions == null)
|
||||||
|
{
|
||||||
|
cachedDefinitions = loadDefinitions();
|
||||||
|
}
|
||||||
|
return cachedDefinitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BusinessBlockDefinition> listDefinitions(String surface)
|
||||||
|
{
|
||||||
|
String normalizedSurface = "admin".equals(surface) ? "admin" : "frontend";
|
||||||
|
List<BusinessBlockDefinition> definitions = new ArrayList<BusinessBlockDefinition>();
|
||||||
|
for (BusinessBlockDefinition definition : listDefinitions())
|
||||||
|
{
|
||||||
|
if (definition != null && definition.getSurfaces().contains(normalizedSurface))
|
||||||
|
{
|
||||||
|
definitions.add(definition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList(definitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessBlockDefinition findDefinition(String code)
|
||||||
|
{
|
||||||
|
for (BusinessBlockDefinition definition : listDefinitions())
|
||||||
|
{
|
||||||
|
if (definition != null && StringUtils.equals(definition.getCode(), code))
|
||||||
|
{
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ServiceException("未知业务块:" + code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageBusinessBlockLayout parseLayout(String layoutJson)
|
||||||
|
{
|
||||||
|
if (StringUtils.isEmpty(layoutJson))
|
||||||
|
{
|
||||||
|
PageBusinessBlockLayout layout = new PageBusinessBlockLayout();
|
||||||
|
layout.setCanvas(BUSINESS_BLOCK_CANVAS);
|
||||||
|
layout.setBlocks(Collections.<BusinessBlockInstance>emptyList());
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PageBusinessBlockLayout layout = JSON.parseObject(layoutJson, PageBusinessBlockLayout.class);
|
||||||
|
if (layout.getBlocks() == null)
|
||||||
|
{
|
||||||
|
layout.setBlocks(Collections.<BusinessBlockInstance>emptyList());
|
||||||
|
}
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
catch (RuntimeException e)
|
||||||
|
{
|
||||||
|
throw new ServiceException("业务块布局JSON格式错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateLayout(String layoutJson, List<GenTable> tables)
|
||||||
|
{
|
||||||
|
PageBusinessBlockLayout layout = parseLayout(layoutJson);
|
||||||
|
if (!BUSINESS_BLOCK_CANVAS.equals(layout.getCanvas()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (BusinessBlockInstance instance : layout.getBlocks())
|
||||||
|
{
|
||||||
|
if (instance == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BusinessBlockDefinition definition = findDefinition(instance.getBlockCode());
|
||||||
|
validateInstanceConfig(definition, instance, tables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, List<BusinessBlockInstance>> parseEmbeddedBlockZones(String layoutJson)
|
||||||
|
{
|
||||||
|
Map<String, List<BusinessBlockInstance>> zones = new LinkedHashMap<String, List<BusinessBlockInstance>>();
|
||||||
|
zones.put("top", new ArrayList<BusinessBlockInstance>());
|
||||||
|
zones.put("bottom", new ArrayList<BusinessBlockInstance>());
|
||||||
|
if (StringUtils.isEmpty(layoutJson))
|
||||||
|
{
|
||||||
|
return zones;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> layout = JSON.parseObject(layoutJson, Map.class);
|
||||||
|
if (layout == null)
|
||||||
|
{
|
||||||
|
return zones;
|
||||||
|
}
|
||||||
|
Object embeddedBlocks = layout.get("embeddedBlocks");
|
||||||
|
if (!(embeddedBlocks instanceof Map))
|
||||||
|
{
|
||||||
|
return zones;
|
||||||
|
}
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<Object, Object> embeddedMap = (Map<Object, Object>) embeddedBlocks;
|
||||||
|
for (Map.Entry<Object, Object> entry : embeddedMap.entrySet())
|
||||||
|
{
|
||||||
|
String zone = String.valueOf(entry.getKey());
|
||||||
|
zones.put(zone, parseBlockList(entry.getValue()));
|
||||||
|
}
|
||||||
|
return zones;
|
||||||
|
}
|
||||||
|
catch (RuntimeException e)
|
||||||
|
{
|
||||||
|
throw new ServiceException("嵌入业务块JSON格式错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateEmbeddedBlocks(String layoutJson, List<GenTable> tables)
|
||||||
|
{
|
||||||
|
Map<String, List<BusinessBlockInstance>> zones = parseEmbeddedBlockZones(layoutJson);
|
||||||
|
for (List<BusinessBlockInstance> blocks : zones.values())
|
||||||
|
{
|
||||||
|
if (blocks == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (BusinessBlockInstance instance : blocks)
|
||||||
|
{
|
||||||
|
if (instance == null || StringUtils.isEmpty(instance.getBlockCode()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BusinessBlockDefinition definition = findDefinition(instance.getBlockCode());
|
||||||
|
if (!isEmbeddedDefinition(definition))
|
||||||
|
{
|
||||||
|
throw new ServiceException("业务块只能放在业务块页面:" + instance.getBlockCode());
|
||||||
|
}
|
||||||
|
validateInstanceConfig(definition, instance, tables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmbeddedDefinition(BusinessBlockDefinition definition)
|
||||||
|
{
|
||||||
|
return supportsPlacement(definition, PLACEMENT_EMBEDDED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supportsPlacement(BusinessBlockDefinition definition, String placement)
|
||||||
|
{
|
||||||
|
return definition != null && definition.getPlacements() != null
|
||||||
|
&& definition.getPlacements().contains(placement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateInstanceConfig(BusinessBlockDefinition definition, BusinessBlockInstance instance,
|
||||||
|
List<GenTable> tables)
|
||||||
|
{
|
||||||
|
if (definition == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException("未知业务块:" + (instance == null ? "" : instance.getBlockCode()));
|
||||||
|
}
|
||||||
|
Map<String, String> config = instance == null || instance.getConfig() == null
|
||||||
|
? Collections.<String, String>emptyMap() : instance.getConfig();
|
||||||
|
Map<String, GenTable> tableMap = buildTableMap(tables);
|
||||||
|
List<BusinessBlockConfigField> fields = definition.getConfigs() == null
|
||||||
|
? Collections.<BusinessBlockConfigField>emptyList() : definition.getConfigs();
|
||||||
|
for (BusinessBlockConfigField field : fields)
|
||||||
|
{
|
||||||
|
String value = StringUtils.defaultString(config.get(field.getKey()));
|
||||||
|
if (Boolean.TRUE.equals(field.getRequired()) && StringUtils.isEmpty(value))
|
||||||
|
{
|
||||||
|
throw new ServiceException("业务块配置缺失:" + field.getKey());
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(value))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ("table".equals(field.getType()))
|
||||||
|
{
|
||||||
|
requireTable(tableMap, value);
|
||||||
|
}
|
||||||
|
if ("field".equals(field.getType()))
|
||||||
|
{
|
||||||
|
String tableName = config.get(field.getTable());
|
||||||
|
GenTable table = requireTable(tableMap, tableName);
|
||||||
|
requireField(table, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BusinessBlockDefinition> loadDefinitions()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Resource[] resources = new PathMatchingResourcePatternResolver()
|
||||||
|
.getResources("classpath*:business-blocks/*/block.json");
|
||||||
|
List<BusinessBlockDefinition> definitions = new ArrayList<BusinessBlockDefinition>();
|
||||||
|
for (Resource resource : resources)
|
||||||
|
{
|
||||||
|
BusinessBlockDefinition definition = JSON.parseObject(readResource(resource), BusinessBlockDefinition.class);
|
||||||
|
if (definition != null && StringUtils.isNotEmpty(definition.getCode()))
|
||||||
|
{
|
||||||
|
definitions.add(normalizeDefinition(definition));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(definitions, new Comparator<BusinessBlockDefinition>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public int compare(BusinessBlockDefinition left, BusinessBlockDefinition right)
|
||||||
|
{
|
||||||
|
return StringUtils.defaultString(left.getCode()).compareTo(StringUtils.defaultString(right.getCode()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Collections.unmodifiableList(definitions);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
throw new ServiceException("读取业务块定义失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BusinessBlockDefinition normalizeDefinition(BusinessBlockDefinition definition)
|
||||||
|
{
|
||||||
|
if (StringUtils.isEmpty(definition.getKind()))
|
||||||
|
{
|
||||||
|
definition.setKind("business");
|
||||||
|
}
|
||||||
|
if (definition.getSurfaces() == null || definition.getSurfaces().isEmpty())
|
||||||
|
{
|
||||||
|
definition.setSurfaces(Collections.singletonList("frontend"));
|
||||||
|
}
|
||||||
|
if (definition.getPlacements() == null || definition.getPlacements().isEmpty())
|
||||||
|
{
|
||||||
|
String placement = StringUtils.defaultIfEmpty(definition.getPlacement(), PLACEMENT_PAGE);
|
||||||
|
definition.setPlacements(Collections.singletonList(placement));
|
||||||
|
}
|
||||||
|
if (definition.getDefaultSpan() == null)
|
||||||
|
{
|
||||||
|
definition.setDefaultSpan(Integer.valueOf(12));
|
||||||
|
}
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BusinessBlockInstance> parseBlockList(Object value)
|
||||||
|
{
|
||||||
|
if (!(value instanceof List))
|
||||||
|
{
|
||||||
|
return new ArrayList<BusinessBlockInstance>();
|
||||||
|
}
|
||||||
|
return JSON.parseArray(JSON.toJSONString(value), BusinessBlockInstance.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readResource(Resource resource) throws IOException
|
||||||
|
{
|
||||||
|
InputStream inputStream = resource.getInputStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int length;
|
||||||
|
while ((length = inputStream.read(buffer)) != -1)
|
||||||
|
{
|
||||||
|
outputStream.write(buffer, 0, length);
|
||||||
|
}
|
||||||
|
return new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
inputStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, GenTable> buildTableMap(List<GenTable> tables)
|
||||||
|
{
|
||||||
|
Map<String, GenTable> tableMap = new LinkedHashMap<String, GenTable>();
|
||||||
|
if (tables == null)
|
||||||
|
{
|
||||||
|
return tableMap;
|
||||||
|
}
|
||||||
|
for (GenTable table : tables)
|
||||||
|
{
|
||||||
|
if (table != null && StringUtils.isNotEmpty(table.getTableName()))
|
||||||
|
{
|
||||||
|
tableMap.put(table.getTableName(), table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tableMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GenTable requireTable(Map<String, GenTable> tableMap, String tableName)
|
||||||
|
{
|
||||||
|
if (StringUtils.isEmpty(tableName) || !tableMap.containsKey(tableName))
|
||||||
|
{
|
||||||
|
throw new ServiceException("业务块表不存在:" + StringUtils.defaultString(tableName));
|
||||||
|
}
|
||||||
|
return tableMap.get(tableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requireField(GenTable table, String fieldName)
|
||||||
|
{
|
||||||
|
List<GenTableColumn> columns = table.getColumns() == null
|
||||||
|
? Collections.<GenTableColumn>emptyList() : table.getColumns();
|
||||||
|
for (GenTableColumn column : columns)
|
||||||
|
{
|
||||||
|
if (column == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (StringUtils.equals(fieldName, column.getColumnName()) || StringUtils.equals(fieldName, column.getJavaField()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ServiceException("业务块字段不存在:" + table.getTableName() + "." + fieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
package com.ruoyi.generator.service.front;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import org.junit.Test;
|
||||||
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
|
import com.ruoyi.generator.domain.GenTable;
|
||||||
|
import com.ruoyi.generator.domain.GenTableColumn;
|
||||||
|
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockDefinition;
|
||||||
|
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockInstance;
|
||||||
|
import com.ruoyi.generator.domain.front.dto.block.PageBusinessBlockLayout;
|
||||||
|
|
||||||
|
public class BusinessBlockRegistryServiceTest
|
||||||
|
{
|
||||||
|
private final BusinessBlockRegistryService service = new BusinessBlockRegistryService();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void listDefinitionsReturnsBundledCartBlock()
|
||||||
|
{
|
||||||
|
BusinessBlockDefinition definition = service.findDefinition("cart");
|
||||||
|
|
||||||
|
assertNotNull(definition);
|
||||||
|
assertEquals("cart", definition.getCode());
|
||||||
|
assertTrue(definition.getConfigs().size() >= 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void listDefinitionsReturnsBundledBusinessBlocks()
|
||||||
|
{
|
||||||
|
assertEquals("notice", service.findDefinition("notice").getCode());
|
||||||
|
assertEquals("carousel", service.findDefinition("carousel").getCode());
|
||||||
|
assertEquals("order", service.findDefinition("order").getCode());
|
||||||
|
assertEquals("master_detail", service.findDefinition("master_detail").getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void bundledDefinitionsDeclarePageOrEmbeddedPlacement()
|
||||||
|
{
|
||||||
|
assertEquals("embedded", service.findDefinition("notice").getPlacement());
|
||||||
|
assertEquals("embedded", service.findDefinition("carousel").getPlacement());
|
||||||
|
assertEquals("page", service.findDefinition("cart").getPlacement());
|
||||||
|
assertEquals("page", service.findDefinition("order").getPlacement());
|
||||||
|
assertEquals("page", service.findDefinition("master_detail").getPlacement());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void legacyDefinitionsDefaultToFrontendBusinessBlocks()
|
||||||
|
{
|
||||||
|
BusinessBlockDefinition definition = service.findDefinition("cart");
|
||||||
|
|
||||||
|
assertEquals("business", definition.getKind());
|
||||||
|
assertEquals(Collections.singletonList("frontend"), definition.getSurfaces());
|
||||||
|
assertEquals(Collections.singletonList("page"), definition.getPlacements());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void listDefinitionsFiltersBySurface()
|
||||||
|
{
|
||||||
|
for (BusinessBlockDefinition definition : service.listDefinitions("frontend"))
|
||||||
|
{
|
||||||
|
assertTrue(definition.getSurfaces().contains("frontend"));
|
||||||
|
}
|
||||||
|
for (BusinessBlockDefinition definition : service.listDefinitions("admin"))
|
||||||
|
{
|
||||||
|
assertTrue(definition.getSurfaces().contains("admin"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseLayoutReadsBusinessBlockInstances()
|
||||||
|
{
|
||||||
|
PageBusinessBlockLayout layout = service.parseLayout("{\"canvas\":\"business-blocks-v1\",\"blocks\":[{\"id\":\"cart_001\",\"blockCode\":\"cart\",\"config\":{\"cartTable\":\"shop_cart\"}}]}");
|
||||||
|
|
||||||
|
assertEquals("business-blocks-v1", layout.getCanvas());
|
||||||
|
assertEquals(1, layout.getBlocks().size());
|
||||||
|
assertEquals("cart_001", layout.getBlocks().get(0).getId());
|
||||||
|
assertEquals("cart", layout.getBlocks().get(0).getBlockCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validateInstanceConfigRejectsMissingRequiredConfig()
|
||||||
|
{
|
||||||
|
BusinessBlockDefinition definition = service.findDefinition("cart");
|
||||||
|
BusinessBlockInstance instance = new BusinessBlockInstance();
|
||||||
|
instance.setBlockCode("cart");
|
||||||
|
instance.setConfig(Collections.singletonMap("productTable", "shop_product"));
|
||||||
|
|
||||||
|
ServiceException exception = expectServiceException(new ThrowingRunnable()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
service.validateInstanceConfig(definition, instance, tables());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrue(exception.getMessage().contains("cartTable"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validateInstanceConfigRejectsUnknownTable()
|
||||||
|
{
|
||||||
|
BusinessBlockDefinition definition = service.findDefinition("cart");
|
||||||
|
BusinessBlockInstance instance = validCartInstance();
|
||||||
|
instance.getConfig().put("cartTable", "missing_cart");
|
||||||
|
|
||||||
|
ServiceException exception = expectServiceException(new ThrowingRunnable()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
service.validateInstanceConfig(definition, instance, tables());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrue(exception.getMessage().contains("missing_cart"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validateInstanceConfigRejectsUnknownField()
|
||||||
|
{
|
||||||
|
BusinessBlockDefinition definition = service.findDefinition("cart");
|
||||||
|
BusinessBlockInstance instance = validCartInstance();
|
||||||
|
instance.getConfig().put("productName", "missing_name");
|
||||||
|
|
||||||
|
ServiceException exception = expectServiceException(new ThrowingRunnable()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
service.validateInstanceConfig(definition, instance, tables());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrue(exception.getMessage().contains("missing_name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validateLayoutIgnoresNonBusinessBlockLayout()
|
||||||
|
{
|
||||||
|
service.validateLayout("{\"canvas\":\"frontend-list-v1\",\"regions\":[]}", tables());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validateEmbeddedBlocksAcceptsEmbeddedDefinitions()
|
||||||
|
{
|
||||||
|
service.validateEmbeddedBlocks("{\"canvas\":\"frontend-list-v1\",\"regions\":[],\"embeddedBlocks\":{\"top\":["
|
||||||
|
+ "{\"id\":\"notice_001\",\"blockCode\":\"notice\",\"config\":{"
|
||||||
|
+ "\"noticeTable\":\"sys_notice\",\"title\":\"noticeTitle\",\"content\":\"noticeContent\"}}"
|
||||||
|
+ "]}}", contentTables());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validateEmbeddedBlocksRejectsPageOnlyDefinitions()
|
||||||
|
{
|
||||||
|
ServiceException exception = expectServiceException(new ThrowingRunnable()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
service.validateEmbeddedBlocks("{\"canvas\":\"frontend-list-v1\",\"regions\":[],\"embeddedBlocks\":{\"top\":["
|
||||||
|
+ "{\"id\":\"cart_001\",\"blockCode\":\"cart\",\"config\":{"
|
||||||
|
+ "\"cartTable\":\"shop_cart\",\"productTable\":\"shop_product\",\"cartProductId\":\"product_id\","
|
||||||
|
+ "\"productId\":\"id\",\"productName\":\"name\",\"price\":\"price\",\"quantity\":\"quantity\","
|
||||||
|
+ "\"userId\":\"user_id\"}}"
|
||||||
|
+ "]}}", contentTables());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrue(exception.getMessage().contains("cart"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private BusinessBlockInstance validCartInstance()
|
||||||
|
{
|
||||||
|
BusinessBlockInstance instance = new BusinessBlockInstance();
|
||||||
|
instance.setId("cart_001");
|
||||||
|
instance.setBlockCode("cart");
|
||||||
|
java.util.Map<String, String> config = new java.util.LinkedHashMap<String, String>();
|
||||||
|
config.put("cartTable", "shop_cart");
|
||||||
|
config.put("productTable", "shop_product");
|
||||||
|
config.put("cartProductId", "product_id");
|
||||||
|
config.put("productId", "id");
|
||||||
|
config.put("productName", "name");
|
||||||
|
config.put("price", "price");
|
||||||
|
config.put("quantity", "quantity");
|
||||||
|
config.put("userId", "user_id");
|
||||||
|
instance.setConfig(config);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private java.util.List<GenTable> tables()
|
||||||
|
{
|
||||||
|
return Arrays.asList(
|
||||||
|
table("shop_cart", column("id", "id"), column("product_id", "productId"), column("quantity", "quantity"), column("user_id", "userId")),
|
||||||
|
table("shop_product", column("id", "id"), column("name", "name"), column("price", "price"), column("stock", "stock")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private java.util.List<GenTable> contentTables()
|
||||||
|
{
|
||||||
|
return Arrays.asList(
|
||||||
|
table("sys_notice", column("id", "id"), column("notice_title", "noticeTitle"),
|
||||||
|
column("notice_content", "noticeContent")),
|
||||||
|
table("shop_cart", column("id", "id"), column("product_id", "productId"),
|
||||||
|
column("quantity", "quantity"), column("user_id", "userId")),
|
||||||
|
table("shop_product", column("id", "id"), column("name", "name"),
|
||||||
|
column("price", "price")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private GenTable table(String tableName, GenTableColumn... columns)
|
||||||
|
{
|
||||||
|
GenTable table = new GenTable();
|
||||||
|
table.setTableName(tableName);
|
||||||
|
table.setColumns(Arrays.asList(columns));
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GenTableColumn column(String columnName, String javaField)
|
||||||
|
{
|
||||||
|
GenTableColumn column = new GenTableColumn();
|
||||||
|
column.setColumnName(columnName);
|
||||||
|
column.setJavaField(javaField);
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServiceException expectServiceException(ThrowingRunnable runnable)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
catch (ServiceException e)
|
||||||
|
{
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
throw new AssertionError("Expected ServiceException");
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface ThrowingRunnable
|
||||||
|
{
|
||||||
|
void run();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user