Add executable business blueprint workflow

This commit is contained in:
王鹏
2026-05-24 13:29:42 +08:00
parent ecdc015c2f
commit 6682a44a43
40 changed files with 4756 additions and 113 deletions

View File

@@ -280,6 +280,9 @@ public interface I${ClassName}Service
(910108, 9101, 'serviceImpl.java.vm', NULL, 'serviceImpl.java.vm',
'package ${packageName}.service.impl;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
@@ -374,6 +377,24 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
#foreach($field in $action.requestFields)
requireBusinessParam(params, "${field}");
#end
#end
#if($action.ruleChecks)
#foreach($rule in $action.ruleChecks)
#set($conditionFields = $rule.conditionFields)
#if($rule.type == "EXISTS")
assertExists(params, "${rule.targetTable}", new String[] {#foreach($field in $conditionFields)"${field}"#if($foreach.hasNext), #end#end}, "${rule.message}");
#elseif($rule.type == "NOT_EXISTS")
assertNotExists(params, "${rule.targetTable}", new String[] {#foreach($field in $conditionFields)"${field}"#if($foreach.hasNext), #end#end}, "${rule.message}");
#elseif($rule.type == "FIELD_EQUALS")
assertFieldEquals(params, "${rule.targetTable}", "${rule.targetField}", "${rule.expectedValue}", new String[] {#foreach($field in $conditionFields)"${field}"#if($foreach.hasNext), #end#end}, "${rule.message}");
#elseif($rule.type == "FIELD_NOT_EQUALS")
assertFieldNotEquals(params, "${rule.targetTable}", "${rule.targetField}", "${rule.expectedValue}", new String[] {#foreach($field in $conditionFields)"${field}"#if($foreach.hasNext), #end#end}, "${rule.message}");
#elseif($rule.type == "FIELD_IN")
assertFieldIn(params, "${rule.targetTable}", "${rule.targetField}", new String[] {#foreach($value in $rule.expectedValues)"${value}"#if($foreach.hasNext), #end#end}, new String[] {#foreach($field in $conditionFields)"${field}"#if($foreach.hasNext), #end#end}, "${rule.message}");
#elseif($rule.type == "NUMBER_GTE")
assertNumberGte(params, "${rule.targetTable}", "${rule.targetField}", "${rule.compareValue}", new String[] {#foreach($field in $conditionFields)"${field}"#if($foreach.hasNext), #end#end}, "${rule.message}");
#end
#end
#end
int rows = 0;
#if($action.effects)
@@ -384,6 +405,30 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
#set($conditionFields = $action.requestFields)
#end
rows += executeUpdateFieldEffect(params, "${effect.targetTable}", "${effect.targetField}", "${effect.value}", new String[] {#foreach($field in $conditionFields)"${field}"#if($foreach.hasNext), #end#end});
#elseif($effect.type == "INSERT_ROW")
#set($effectIndex = $foreach.index)
Map<String, Object> insertValues${effectIndex} = new java.util.LinkedHashMap<String, Object>();
#foreach($entry in $effect.values.entrySet())
insertValues${effectIndex}.put("${entry.key}", resolveBusinessValue(params, "${entry.value}"));
#end
rows += insertRow("${effect.targetTable}", insertValues${effectIndex});
#elseif($effect.type == "UPDATE_FIELDS")
#set($conditionFields = $effect.conditionFields)
#set($effectIndex = $foreach.index)
Map<String, Object> updateValues${effectIndex} = new java.util.LinkedHashMap<String, Object>();
#foreach($entry in $effect.values.entrySet())
updateValues${effectIndex}.put("${entry.key}", resolveBusinessValue(params, "${entry.value}"));
#end
rows += updateFields(params, "${effect.targetTable}", updateValues${effectIndex}, new String[] {#foreach($field in $conditionFields)"${field}"#if($foreach.hasNext), #end#end});
#elseif($effect.type == "SET_STATUS")
#set($conditionFields = $effect.conditionFields)
rows += setStatus(params, "${effect.targetTable}", "${effect.targetField}", resolveBusinessValue(params, "${effect.value}"), new String[] {#foreach($field in $conditionFields)"${field}"#if($foreach.hasNext), #end#end});
#elseif($effect.type == "INCREASE_NUMBER")
#set($conditionFields = $effect.conditionFields)
rows += increaseNumberField(params, "${effect.targetTable}", "${effect.targetField}", "${effect.amount}", new String[] {#foreach($field in $conditionFields)"${field}"#if($foreach.hasNext), #end#end});
#elseif($effect.type == "DECREASE_NUMBER")
#set($conditionFields = $effect.conditionFields)
rows += decreaseNumberField(params, "${effect.targetTable}", "${effect.targetField}", "${effect.amount}", "${effect.minValue}", new String[] {#foreach($field in $conditionFields)"${field}"#if($foreach.hasNext), #end#end}, "${effect.message}");
#else
// Unsupported effect type ${effect.type}: ${effect.description}
#end
@@ -400,6 +445,143 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
}
}
private void assertExists(Map<String, Object> params, String tableName, String[] conditionFields, String message)
{
if (countRows(params, tableName, conditionFields) <= 0) {
throw new ServiceException(defaultMessage(message, "Business record does not exist"));
}
}
private void assertNotExists(Map<String, Object> params, String tableName, String[] conditionFields, String message)
{
if (countRows(params, tableName, conditionFields) > 0) {
throw new ServiceException(defaultMessage(message, "Business record already exists"));
}
}
private void assertFieldEquals(Map<String, Object> params, String tableName, String targetField, String expectedValue,
String[] conditionFields, String message)
{
Object value = querySingleField(params, tableName, targetField, conditionFields);
if (value == null || !String.valueOf(resolveBusinessValue(params, expectedValue)).equals(String.valueOf(value))) {
throw new ServiceException(defaultMessage(message, "Business rule check failed"));
}
}
private void assertFieldNotEquals(Map<String, Object> params, String tableName, String targetField, String expectedValue,
String[] conditionFields, String message)
{
Object value = querySingleField(params, tableName, targetField, conditionFields);
if (value != null && String.valueOf(resolveBusinessValue(params, expectedValue)).equals(String.valueOf(value))) {
throw new ServiceException(defaultMessage(message, "Business rule check failed"));
}
}
private void assertFieldIn(Map<String, Object> params, String tableName, String targetField, String[] expectedValues,
String[] conditionFields, String message)
{
Object value = querySingleField(params, tableName, targetField, conditionFields);
String current = value == null ? "" : String.valueOf(value);
for (String expectedValue : expectedValues) {
if (String.valueOf(resolveBusinessValue(params, expectedValue)).equals(current)) {
return;
}
}
throw new ServiceException(defaultMessage(message, "Business rule check failed"));
}
private void assertNumberGte(Map<String, Object> params, String tableName, String targetField, String compareValue,
String[] conditionFields, String message)
{
Object value = querySingleField(params, tableName, targetField, conditionFields);
BigDecimal current = toBigDecimal(value, "Business numeric value is invalid");
BigDecimal expected = resolveBusinessNumber(params, compareValue);
if (current.compareTo(expected) < 0) {
throw new ServiceException(defaultMessage(message, "Business numeric rule check failed"));
}
}
private int insertRow(String tableName, Map<String, Object> values)
{
String safeTableName = requireSafeIdentifier(tableName, "Business effect target table is invalid");
if (values == null || values.isEmpty()) {
throw new ServiceException("Business insert values cannot be empty");
}
StringBuilder fields = new StringBuilder();
StringBuilder placeholders = new StringBuilder();
List<Object> args = new ArrayList<Object>();
for (Map.Entry<String, Object> entry : values.entrySet()) {
if (fields.length() > 0) {
fields.append(", ");
placeholders.append(", ");
}
fields.append(requireSafeIdentifier(entry.getKey(), "Business effect value field is invalid"));
placeholders.append("?");
args.add(entry.getValue());
}
return jdbcTemplate.update("insert into " + safeTableName + " (" + fields + ") values (" + placeholders + ")", args.toArray());
}
private int updateFields(Map<String, Object> params, String tableName, Map<String, Object> values, String[] conditionFields)
{
String safeTableName = requireSafeIdentifier(tableName, "Business effect target table is invalid");
if (values == null || values.isEmpty()) {
throw new ServiceException("Business update values cannot be empty");
}
StringBuilder sets = new StringBuilder();
List<Object> args = new ArrayList<Object>();
for (Map.Entry<String, Object> entry : values.entrySet()) {
if (sets.length() > 0) {
sets.append(", ");
}
sets.append(requireSafeIdentifier(entry.getKey(), "Business effect value field is invalid")).append(" = ?");
args.add(entry.getValue());
}
String whereClause = buildWhereClause(params, conditionFields);
appendConditionValues(args, params, conditionFields);
return jdbcTemplate.update("update " + safeTableName + " set " + sets + " where " + whereClause, args.toArray());
}
private int setStatus(Map<String, Object> params, String tableName, String targetField, Object value, String[] conditionFields)
{
Map<String, Object> values = new java.util.LinkedHashMap<String, Object>();
values.put(targetField, value);
return updateFields(params, tableName, values, conditionFields);
}
private int increaseNumberField(Map<String, Object> params, String tableName, String targetField, String amountExpression,
String[] conditionFields)
{
String safeTableName = requireSafeIdentifier(tableName, "Business effect target table is invalid");
String safeTargetField = requireSafeIdentifier(targetField, "Business effect target field is invalid");
BigDecimal amount = resolveBusinessNumber(params, amountExpression);
String whereClause = buildWhereClause(params, conditionFields);
List<Object> args = new ArrayList<Object>();
args.add(amount);
appendConditionValues(args, params, conditionFields);
return jdbcTemplate.update("update " + safeTableName + " set " + safeTargetField + " = " + safeTargetField + " + ? where " + whereClause, args.toArray());
}
private int decreaseNumberField(Map<String, Object> params, String tableName, String targetField, String amountExpression,
String minValueExpression, String[] conditionFields, String message)
{
String safeTableName = requireSafeIdentifier(tableName, "Business effect target table is invalid");
String safeTargetField = requireSafeIdentifier(targetField, "Business effect target field is invalid");
BigDecimal amount = resolveBusinessNumber(params, amountExpression);
BigDecimal minValue = resolveBusinessNumber(params, minValueExpression == null || minValueExpression.length() == 0 ? "0" : minValueExpression);
String whereClause = buildWhereClause(params, conditionFields);
List<Object> args = new ArrayList<Object>();
args.add(amount);
appendConditionValues(args, params, conditionFields);
args.add(amount);
args.add(minValue);
int rows = jdbcTemplate.update("update " + safeTableName + " set " + safeTargetField + " = " + safeTargetField + " - ? where " + whereClause + " and " + safeTargetField + " - ? >= ?", args.toArray());
if (rows == 0) {
throw new ServiceException(defaultMessage(message, "Business numeric decrease failed"));
}
return rows;
}
private int executeUpdateFieldEffect(Map<String, Object> params, String tableName, String targetField,
String valueExpression, String[] conditionFields)
{
@@ -438,6 +620,68 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
return values;
}
private int countRows(Map<String, Object> params, String tableName, String[] conditionFields)
{
String safeTableName = requireSafeIdentifier(tableName, "Business rule target table is invalid");
String whereClause = buildWhereClause(params, conditionFields);
Integer count = jdbcTemplate.queryForObject("select count(1) from " + safeTableName + " where " + whereClause, conditionValues(params, conditionFields), Integer.class);
return count == null ? 0 : count.intValue();
}
private Object querySingleField(Map<String, Object> params, String tableName, String targetField, String[] conditionFields)
{
String safeTableName = requireSafeIdentifier(tableName, "Business rule target table is invalid");
String safeTargetField = requireSafeIdentifier(targetField, "Business rule target field is invalid");
String whereClause = buildWhereClause(params, conditionFields);
List<Map<String, Object>> rows = jdbcTemplate.queryForList("select " + safeTargetField + " from " + safeTableName + " where " + whereClause + " limit 1", conditionValues(params, conditionFields));
if (rows.isEmpty()) {
return null;
}
return rows.get(0).get(safeTargetField);
}
private void appendConditionValues(List<Object> args, Map<String, Object> params, String[] conditionFields)
{
for (Object value : conditionValues(params, conditionFields)) {
args.add(value);
}
}
private Object resolveBusinessValue(Map<String, Object> params, String valueExpression)
{
if (valueExpression == null) {
return null;
}
if ("#[[${now}]]#".equals(valueExpression)) {
return new Date();
}
if (valueExpression.startsWith("#[[${param.]]#") && valueExpression.endsWith("}")) {
String field = valueExpression.substring(8, valueExpression.length() - 1);
requireBusinessParam(params, field);
return params.get(field);
}
return valueExpression;
}
private BigDecimal resolveBusinessNumber(Map<String, Object> params, String valueExpression)
{
return toBigDecimal(resolveBusinessValue(params, valueExpression), "Business numeric expression is invalid");
}
private BigDecimal toBigDecimal(Object value, String message)
{
try {
return new BigDecimal(String.valueOf(value));
} catch (RuntimeException e) {
throw new ServiceException(message);
}
}
private String defaultMessage(String message, String fallback)
{
return message == null || message.length() == 0 ? fallback : message;
}
private String requireSafeIdentifier(String value, String message)
{
if (value == null || !value.matches("[A-Za-z][A-Za-z0-9_]*")) {
@@ -793,7 +1037,7 @@ export default {
submitForm() {
const request = this.form.${pkColumn.javaField} ? ${className}Api.update${ClassName}(this.form) : ${className}Api.add${ClassName}(this.form)
request.then(() => {
this.$modal.msgSuccess("保存成功")
this.#[[$modal]]#.msgSuccess("保存成功")
this.open = false
this.getList()
})
@@ -801,14 +1045,14 @@ export default {
handleDelete(row) {
const id = row.${pkColumn.javaField}
${className}Api.del${ClassName}(id).then(() => {
this.$modal.msgSuccess("删除成功")
this.#[[$modal]]#.msgSuccess("删除成功")
this.getList()
})
},
handleBusinessAction(row, actionCode) {
const action = this.businessActions.find(item => item.code === actionCode)
${className}Api[actionCode]({ ...row }).then(() => {
this.$modal.msgSuccess((action ? action.name : "业务动作") + "成功")
this.#[[$modal]]#.msgSuccess((action ? action.name : "业务动作") + "成功")
this.getList()
})
},