diff --git a/pom.xml b/pom.xml index 8332589..3ce10da 100644 --- a/pom.xml +++ b/pom.xml @@ -148,6 +148,13 @@ 8.0.16 + + + com.alibaba + fastjson + 1.2.79 + + diff --git a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/AbstractFormItemConverter.java b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/AbstractFormItemConverter.java new file mode 100644 index 0000000..81eaa8c --- /dev/null +++ b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/AbstractFormItemConverter.java @@ -0,0 +1,109 @@ +package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after; + +import org.apache.commons.lang3.StringUtils; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * 表单项转换的操作流程,即如下的 convert 方法(使用 final 修饰,确保子类不可修改操作流程) + * + * @author F嘉阳 + * @date 2022/1/26 09:50 + */ +public abstract class AbstractFormItemConverter { + /** + * 子类可处理的表单项类型 + */ + public abstract ComponentTypeEnum getType(); + + /** + * 将输入的配置转变为表单项的操作流程 + * + * @param config 前端输入的配置 + * @return 表单项 + */ + public final FormItem convert(FormItemConfig config) { + FormItem item = createItem(config); + // 表单项创建完成之后,子类如果需要特殊处理,可覆写该方法 + afterItemCreate(item, config); + + FormComponentProps props = createComponentProps(config); + item.setComponentProps(props); + // 组件属性创建完成之后,子类如果需要特殊处理,可覆写该方法 + afterPropsCreate(props, config); + + List rules = createRules(config); + item.setRules(rules); + // 约束规则创建完成之后,子类如果需要特殊处理,可覆写该方法 + afterRulesCreate(rules, config); + + return item; + } + + /** + * 共用逻辑:创建表单项、设置通用的表单项属性 + */ + private FormItem createItem(FormItemConfig config) { + FormItem formItem = new FormItem(); + + formItem.setCode(config.getCode()); + formItem.setTitle(config.getTitle()); + formItem.setComponent(config.getComponent()); + + return formItem; + } + + /** + * 表单项创建完成之后,子类如果需要特殊处理,可覆写该方法 + */ + protected void afterItemCreate(FormItem item, FormItemConfig config) { + } + + /** + * 共用逻辑:创建组件属性、设置通用的组件属性 + */ + private FormComponentProps createComponentProps(FormItemConfig config) { + FormComponentProps props = new FormComponentProps(); + + if (config.isReadOnly()) { + props.setReadOnly(true); + } + + if (StringUtils.isNotBlank(config.getPlaceholder())) { + props.setPlaceholder(config.getPlaceholder()); + } + + return props; + } + + /** + * 组件属性创建完成之后,子类如果需要特殊处理,可覆写该方法 + */ + protected void afterPropsCreate(FormComponentProps props, FormItemConfig config) { + } + + /** + * 共用逻辑:创建约束规则、设置通用的约束规则 + */ + private List createRules(FormItemConfig config) { + List rules = new ArrayList<>(4); + + if (config.isRequired()) { + FormItemRule requiredRule = new FormItemRule(); + requiredRule.setRequired(true); + requiredRule.setMessage("请输入" + config.getTitle()); + + rules.add(requiredRule); + } + + return rules; + } + + /** + * 约束规则创建完成之后,子类如果需要特殊处理,可覆写该方法 + */ + protected void afterRulesCreate(List rules, FormItemConfig config) { + } +} \ No newline at end of file diff --git a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/AbstractTextConverter.java b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/AbstractTextConverter.java new file mode 100644 index 0000000..837ab42 --- /dev/null +++ b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/AbstractTextConverter.java @@ -0,0 +1,46 @@ +package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after; + +import org.springframework.stereotype.Component; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemConfig; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemRule; + +import java.util.List; + +/** + * 通用文本类转换器 + * + * @author F嘉阳 + * @date 2022/1/26 09:54 + */ +@Component +public abstract class AbstractTextConverter extends AbstractFormItemConverter { + + /** + * 约束规则创建完成之后,子类如果需要特殊处理,可覆写该方法 + * + * @param rules + * @param config + */ + @Override + protected void afterRulesCreate(List rules, FormItemConfig config) { + Integer minLength = config.getMinLength(); + + if (minLength != null && minLength > 0) { + FormItemRule minRule = new FormItemRule(); + minRule.setMin(minLength); + minRule.setMessage("请至少输入 " + minLength + " 个字"); + + rules.add(minRule); + } + + Integer maxLength = config.getMaxLength(); + + if (maxLength != null && maxLength > 0) { + FormItemRule maxRule = new FormItemRule(); + maxRule.setMax(maxLength); + maxRule.setMessage("请最多输入 " + maxLength + " 个字"); + + rules.add(maxRule); + } + } +} diff --git a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/DropdownSelectConverter.java b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/DropdownSelectConverter.java new file mode 100644 index 0000000..55b6885 --- /dev/null +++ b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/DropdownSelectConverter.java @@ -0,0 +1,38 @@ +package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after; + +import org.springframework.stereotype.Component; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.ComponentTypeEnum; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormComponentProps; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemConfig; + +/** + * 下拉选择框的转换器 + * + * @author F嘉阳 + * @date 2022/1/26 09:51 + */ +@Component +public class DropdownSelectConverter extends AbstractFormItemConverter { + /** + * 子类可处理的表单项类型 + */ + @Override + public ComponentTypeEnum getType() { + return ComponentTypeEnum.DROPDOWN_SELECT; + } + + /** + * 组件属性创建完成之后,子类如果需要特殊处理,可覆写该方法 + * + * @param props + * @param config + */ + @Override + protected void afterPropsCreate(FormComponentProps props, FormItemConfig config) { + props.setAutoWidth(false); + + if (config.isMultiple()) { + props.setMode("multiple"); + } + } +} diff --git a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/FormItemConverterFactory.java b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/FormItemConverterFactory.java new file mode 100644 index 0000000..4a8105e --- /dev/null +++ b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/FormItemConverterFactory.java @@ -0,0 +1,37 @@ +package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.ComponentTypeEnum; + +import java.util.EnumMap; +import java.util.List; + +/** + * 简单工厂 + * + * @author F嘉阳 + * @date 2022/1/26 09:56 + */ +@Component +public class FormItemConverterFactory { + + private static final EnumMap CONVERTER_MAP = new EnumMap<>(ComponentTypeEnum.class); + + /** + * 根据表单项类型获得对应的转换器 + * + * @param type 表单项类型 + * @return 表单项转换器 + */ + public AbstractFormItemConverter getConverter(ComponentTypeEnum type) { + return CONVERTER_MAP.get(type); + } + + @Autowired + public void setConverters(List converters) { + for (final AbstractFormItemConverter converter : converters) { + CONVERTER_MAP.put(converter.getType(), converter); + } + } +} diff --git a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/FuzzySearchConverter.java b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/FuzzySearchConverter.java new file mode 100644 index 0000000..1f70936 --- /dev/null +++ b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/FuzzySearchConverter.java @@ -0,0 +1,46 @@ +package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after; + +import org.springframework.stereotype.Component; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.ComponentTypeEnum; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormComponentProps; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItem; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemConfig; + +/** + * 模糊搜索框的转换器 + * + * @author F嘉阳 + * @date 2022/1/26 09:53 + */ +@Component +public class FuzzySearchConverter extends AbstractFormItemConverter { + /** + * 子类可处理的表单项类型 + */ + @Override + public ComponentTypeEnum getType() { + return ComponentTypeEnum.FUZZY_SEARCH; + } + + /** + * 表单项创建完成之后,子类如果需要特殊处理,可覆写该方法 + * + * @param item + * @param config + */ + @Override + protected void afterItemCreate(FormItem item, FormItemConfig config) { + item.setFuzzySearch(true); + } + + /** + * 组件属性创建完成之后,子类如果需要特殊处理,可覆写该方法 + * + * @param props + * @param config + */ + @Override + protected void afterPropsCreate(FormComponentProps props, FormItemConfig config) { + props.setAutoWidth(false); + } +} diff --git a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/TextAreaConvertor.java b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/TextAreaConvertor.java new file mode 100644 index 0000000..1dfb199 --- /dev/null +++ b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/TextAreaConvertor.java @@ -0,0 +1,22 @@ +package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after; + +import org.springframework.stereotype.Component; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.ComponentTypeEnum; + +/** + * 多行文本框的转换器 + * + * @author F嘉阳 + * @date 2022/1/26 09:56 + */ +@Component +public class TextAreaConvertor extends AbstractTextConverter { + + /** + * 子类可处理的表单项类型 + */ + @Override + public ComponentTypeEnum getType() { + return ComponentTypeEnum.TEXT_AREA; + } +} diff --git a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/TextInputConverter.java b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/TextInputConverter.java new file mode 100644 index 0000000..2c800c5 --- /dev/null +++ b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/TextInputConverter.java @@ -0,0 +1,22 @@ +package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after; + +import org.springframework.stereotype.Component; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.ComponentTypeEnum; + +/** + * 单行文本框的转换器 + * + * @author F嘉阳 + * @date 2022/1/26 09:55 + */ +@Component +public class TextInputConverter extends AbstractTextConverter { + + /** + * 子类可处理的表单项类型 + */ + @Override + public ComponentTypeEnum getType() { + return ComponentTypeEnum.TEXT_INPUT; + } +} diff --git a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/bean/FormComponentProps.java b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/bean/FormComponentProps.java index 164a15c..be8c020 100644 --- a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/bean/FormComponentProps.java +++ b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/bean/FormComponentProps.java @@ -16,4 +16,6 @@ public class FormComponentProps { private boolean autoWidth; private String mode; + + private String placeholder; } diff --git a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/bean/FormItemConfig.java b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/bean/FormItemConfig.java index 5518243..38ce904 100644 --- a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/bean/FormItemConfig.java +++ b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/bean/FormItemConfig.java @@ -28,4 +28,6 @@ public class FormItemConfig { private Integer minLength; private Integer maxLength; + + private String placeholder; } diff --git a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/bean/FormItemTypeEnum.java b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/bean/FormItemTypeEnum.java deleted file mode 100644 index a308200..0000000 --- a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/bean/FormItemTypeEnum.java +++ /dev/null @@ -1,17 +0,0 @@ -package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * TODO: - * - * @author F嘉阳 - * @date 2022/1/26 09:41 - */ -@Getter -@AllArgsConstructor -public enum FormItemTypeEnum { - ; - -} diff --git a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/FormItemConverter.java b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/before/FormItemConverter.java similarity index 77% rename from src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/FormItemConverter.java rename to src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/before/FormItemConverter.java index 3c037a9..34fd553 100644 --- a/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/FormItemConverter.java +++ b/src/main/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/before/FormItemConverter.java @@ -1,4 +1,4 @@ -package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring; +package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.before; import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.*; @@ -7,6 +7,13 @@ import java.util.List; /** * 原始逻辑 + *

+ * 代码违反了 开闭原则(对扩展开放,对修改关闭):如果此时需要添加一种新的表单项(包含特殊的组件属性),那么不可避免的要修改 convert 方法来进行新表单项的特殊处理。 + *

+ * 观察上面的代码,将配置转变为表单项 这个操作,满足以下流程: + * 创建表单项,并设置通用的表单项属性,然后再对不同表单项的特殊属性进行处理 + * 创建组件属性,处理通用的组件属性,然后再对不同组件的特殊属性进行处理 + * 创建约束规则,处理通用的约束规则,然后再对不同表单项的特性约束规则进行处理 * * @author F嘉阳 * @date 2022/1/26 09:38 diff --git a/src/test/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/FormItemConverterFactoryTest.java b/src/test/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/FormItemConverterFactoryTest.java new file mode 100644 index 0000000..8bda993 --- /dev/null +++ b/src/test/java/top/fjy8018/designpattern/pattern/behavior/templatemethod/spring/after/FormItemConverterFactoryTest.java @@ -0,0 +1,38 @@ +package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItem; +import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemConfig; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +@Component +class FormItemConverterFactoryTest { + + @Autowired + private FormItemConverterFactory factory; + + public List convertFormItems(JSONArray inputConfigs) { + return IntStream.range(0, inputConfigs.size()) + .mapToObj(inputConfigs::getJSONObject) + .map(this::convertFormItem) + .collect(Collectors.toList()); + } + + private FormItem convertFormItem(JSONObject inputConfig) { + FormItemConfig itemConfig = inputConfig.toJavaObject(FormItemConfig.class); + AbstractFormItemConverter converter = factory.getConverter(itemConfig.getType()); + + if (converter == null) { + throw new IllegalArgumentException("不存在转换器:" + itemConfig.getType()); + } + + return converter.convert(itemConfig); + } + +} \ No newline at end of file