From 038b52c64d1ff53ca8580e34c99988bc630bef36 Mon Sep 17 00:00:00 2001 From: lml <1297555865@qq.com> Date: Mon, 19 Oct 2026 15:43:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(botp):=20=E4=BF=9D=E5=AD=98=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E8=A7=84=E5=88=99=E6=97=B6=E6=A0=A1=E9=AA=8C=E5=8F=96?= =?UTF-8?q?=E5=80=BC=E6=96=B9=E5=BC=8F=E4=B8=8E=E5=88=86=E5=8D=95=E7=AD=96?= =?UTF-8?q?=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 ValueMethodEnum 与 SplitMergeStrategyEnum 承载字段可选值,消除魔法值, 并为二者补充 parse/validOptions 方法供保存校验使用。 保存入口(addAll/editAll)统一增加 validateBeforeSave 前置校验, 校验不通过抛 MyRuntimeException 阻止保存,且早于任何写库操作,避免脏数据。 - 取值方式:为空或未知时阻止保存,错误信息定位到分录行号、源字段、 目标字段、非法值、合法选项及分录id - 分单策略:未配置按默认「一对一」放行;非法值阻止保存;选择「按规则分组合并」 但未配置分单字段时阻止保存 - 事务:addAll/editAll 涉及主表与分录的多次独立写库(editAll 为先删后插), 此前无事务边界,中途失败会造成主表已改、分录残缺或产生无分录的空规则。 现补充 @Transactional(rollbackFor = Exception.class),removeChild 一并补充 files: common/common-botp/src/main/java/apelet/common/botp/model/constant/ValueMethodEnum.java common/common-botp/src/main/java/apelet/common/botp/model/constant/SplitMergeStrategyEnum.java common/common-botp/src/main/java/apelet/common/botp/service/impl/ConvertRuleServiceImpl.java --- .../model/constant/SplitMergeStrategyEnum.java | 99 +++++++++++++++++++ .../botp/model/constant/ValueMethodEnum.java | 105 ++++++++++++++++++++ .../botp/service/impl/ConvertRuleServiceImpl.java | 107 ++++++++++++++++++++- 3 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 common/common-botp/src/main/java/apelet/common/botp/model/constant/SplitMergeStrategyEnum.java create mode 100644 common/common-botp/src/main/java/apelet/common/botp/model/constant/ValueMethodEnum.java diff --git a/common/common-botp/src/main/java/apelet/common/botp/model/constant/SplitMergeStrategyEnum.java b/common/common-botp/src/main/java/apelet/common/botp/model/constant/SplitMergeStrategyEnum.java new file mode 100644 index 0000000..2fc86d9 --- /dev/null +++ b/common/common-botp/src/main/java/apelet/common/botp/model/constant/SplitMergeStrategyEnum.java @@ -0,0 +1,99 @@ +package apelet.common.botp.model.constant; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * 分单/合并策略枚举。 + * + *
对应 convert_rule.split_merge_strategy,落库为 varchar 的 "1"/"2"/"3",默认按「一对一」处理。
+ * + * @author admin + * @since 2024-01-18 + */ +public enum SplitMergeStrategyEnum { + + /** + * 一对一:一条源单对应一条目标单。 + */ + ONE_TO_ONE("1", "一对一"), + + /** + * 多对一:多条源单合并为一条目标单。 + */ + MANY_TO_ONE("2", "多对一"), + + /** + * 按规则分组合并:按分单字段分组后分别合并。 + */ + GROUP_BY_RULE("3", "按规则分组合并"); + + @Getter + private final String code; + + @Getter + private final String description; + + private static final Map供保存校验等场景使用:需要区分「未配置」与「配置了非法值」时,用本方法。
+ * + * @param code 分单策略编码。 + * @return 枚举对象;不是已知编码时返回 null。 + */ + public static SplitMergeStrategyEnum parse(String code) { + return StringUtils.isBlank(code) ? null : ENUM_MAP.get(code.trim()); + } + + /** + * 生成可选值说明,用于错误提示。 + * + * @return 形如「1-一对一 2-多对一 3-按规则分组合并」。 + */ + public static String validOptions() { + return Arrays.stream(values()) + .map(e -> e.getCode() + "-" + e.getDescription()) + .collect(Collectors.joining(" ")); + } +} diff --git a/common/common-botp/src/main/java/apelet/common/botp/model/constant/ValueMethodEnum.java b/common/common-botp/src/main/java/apelet/common/botp/model/constant/ValueMethodEnum.java new file mode 100644 index 0000000..2695141 --- /dev/null +++ b/common/common-botp/src/main/java/apelet/common/botp/model/constant/ValueMethodEnum.java @@ -0,0 +1,105 @@ +package apelet.common.botp.model.constant; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * 字段取值方式枚举。 + * + *对应 convert_fieldmapping_entry.value_method,落库为 varchar 的 "1"/"2"/"3"/"4"。
+ * + * @author admin + * @since 2024-01-18 + */ +public enum ValueMethodEnum { + + /** + * 映射:取源单同名字段的值。 + */ + MAPPING("1", "映射"), + + /** + * 常量:直接使用配置的固定值。 + */ + CONSTANT("2", "常量"), + + /** + * 计算公式:按配置的公式表达式计算。 + */ + EXPRESSION("3", "计算公式"), + + /** + * 按条件取值 + */ + CONDITION("4", "按条件取值") + ; + + @Getter + private final String code; + + @Getter + private final String description; + + private static final Map供保存校验等场景使用:需要区分「未配置」与「配置了非法值」时,用本方法。
+ * + * @param code 取值方式编码。 + * @return 枚举对象;不是已知编码时返回 null。 + */ + public static ValueMethodEnum parse(String code) { + return StringUtils.isBlank(code) ? null : ENUM_MAP.get(code.trim()); + } + + /** + * 生成可选值说明,用于错误提示。 + * + * @return 形如「1-映射 2-常量 3-计算公式 4-按条件取值」。 + */ + public static String validOptions() { + return Arrays.stream(values()) + .map(e -> e.getCode() + "-" + e.getDescription()) + .collect(Collectors.joining(" ")); + } +} diff --git a/common/common-botp/src/main/java/apelet/common/botp/service/impl/ConvertRuleServiceImpl.java b/common/common-botp/src/main/java/apelet/common/botp/service/impl/ConvertRuleServiceImpl.java index 9deb952..a1c93b4 100644 --- a/common/common-botp/src/main/java/apelet/common/botp/service/impl/ConvertRuleServiceImpl.java +++ b/common/common-botp/src/main/java/apelet/common/botp/service/impl/ConvertRuleServiceImpl.java @@ -5,6 +5,8 @@ import apelet.common.botp.dao.ConvertPluginEntryMapper; import apelet.common.botp.dao.ConvertRuleMapper; import apelet.common.botp.dto.*; import apelet.common.botp.model.*; +import apelet.common.botp.model.constant.SplitMergeStrategyEnum; +import apelet.common.botp.model.constant.ValueMethodEnum; import apelet.common.botp.service.*; import apelet.common.botp.service.execute.BotpService; import apelet.common.botp.service.execute.entity.BillData; @@ -13,6 +15,7 @@ import apelet.common.botp.util.Constant; import apelet.common.core.base.dao.BaseDaoMapper; import apelet.common.core.base.service.BaseService; import apelet.common.core.constant.GlobalDeletedFlag; +import apelet.common.core.exception.MyRuntimeException; import apelet.common.core.object.*; import apelet.common.generator.dao.OnlFormHeadMapper; import apelet.common.generator.model.OnlFormField; @@ -31,6 +34,7 @@ import org.jetbrains.annotations.NotNull; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.*; import java.util.stream.Collectors; @@ -99,11 +103,14 @@ public class ConvertRuleServiceImpl extends BaseService集中校验转换规则本身与其字段映射分录,任一不通过即抛出 {@link MyRuntimeException} 阻止保存。
+ * + * @param convertRule 待保存的转换规则。 + */ + private void validateBeforeSave(ConvertRule convertRule) { + validateSplitMergeStrategy(convertRule); + validateFieldmappingValueMethod(convertRule); + } + + /** + * 校验分单策略配置。 + * + *分单策略为空时按「一对一」处理(与字段默认值一致);配置了非法值时阻止保存; + * 选择「按规则分组合并」时必须配置分单字段。
+ * + * @param convertRule 待保存的转换规则。 + */ + private void validateSplitMergeStrategy(ConvertRule convertRule) { + String splitMergeStrategy = convertRule.getSplitMergeStrategy(); + if (StringUtils.isBlank(splitMergeStrategy)) { + // 未配置按默认值「一对一」处理,与 SplitMergeStrategyEnum.ofNullable 保持一致 + return; + } + SplitMergeStrategyEnum strategy = SplitMergeStrategyEnum.parse(splitMergeStrategy); + if (strategy == null) { + throw new MyRuntimeException("分单策略未知:" + splitMergeStrategy + + ",可选值为 " + SplitMergeStrategyEnum.validOptions()); + } + if (strategy == SplitMergeStrategyEnum.GROUP_BY_RULE + && StringUtils.isBlank(convertRule.getGroupByField())) { + throw new MyRuntimeException("分单策略为「" + SplitMergeStrategyEnum.GROUP_BY_RULE.getDescription() + + "」时必须配置分单字段,可选值为 " + SplitMergeStrategyEnum.validOptions()); + } + } + + /** + * 校验字段映射分录的取值方式。 + * + *取值方式为空或不在 {@link ValueMethodEnum} 允许范围内时,直接抛出异常阻止保存, + * 并在异常信息中定位到具体的分录行(第几行、源字段、目标字段),便于前端定位问题。
+ * + * @param convertRule 待保存的转换规则,含字段映射分录。 + */ + private void validateFieldmappingValueMethod(ConvertRule convertRule) { + List