diff --git a/cf-framework/cf-spring-boot-starter-excel/src/main/java/com/cf/imes/framework/dict/core/util/DictFrameworkUtils.java b/cf-framework/cf-spring-boot-starter-excel/src/main/java/com/cf/imes/framework/dict/core/util/DictFrameworkUtils.java index 1fcd18cdf..9d3b946e3 100644 --- a/cf-framework/cf-spring-boot-starter-excel/src/main/java/com/cf/imes/framework/dict/core/util/DictFrameworkUtils.java +++ b/cf-framework/cf-spring-boot-starter-excel/src/main/java/com/cf/imes/framework/dict/core/util/DictFrameworkUtils.java @@ -3,6 +3,7 @@ package com.cf.imes.framework.dict.core.util; import cn.hutool.core.lang.Pair; import cn.hutool.core.util.ObjectUtil; import com.cf.imes.framework.common.util.cache.CacheUtils; +import com.cf.imes.framework.common.enums.CommonStatusEnum; import com.cf.imes.module.system.api.dict.DictDataApi; import com.cf.imes.module.system.api.dict.dto.DictDataRespDTO; import com.google.common.cache.CacheLoader; @@ -102,4 +103,19 @@ public class DictFrameworkUtils { return PARSE_DICT_DATA_CACHE.get(new Pair<>(dictType, label)).getValue(); } + /** + * 判断指定字典值是否存在且已启用。 + * + * @param dictType 字典类型 + * @param value 字典值 + * @return 是否为有效字典值 + */ + @SneakyThrows + public static boolean isDictDataValid(String dictType, String value) { + DictDataRespDTO dictData = GET_DICT_DATA_CACHE.get(new Pair<>(dictType, value)); + return dictData != DICT_DATA_NULL + && dictData.getValue() != null + && CommonStatusEnum.ENABLE.getStatus().equals(dictData.getStatus()); + } + } diff --git a/cf-framework/cf-spring-boot-starter-excel/src/main/java/com/cf/imes/framework/dict/core/validation/InDict.java b/cf-framework/cf-spring-boot-starter-excel/src/main/java/com/cf/imes/framework/dict/core/validation/InDict.java new file mode 100644 index 000000000..96d63ce12 --- /dev/null +++ b/cf-framework/cf-spring-boot-starter-excel/src/main/java/com/cf/imes/framework/dict/core/validation/InDict.java @@ -0,0 +1,32 @@ +package com.cf.imes.framework.dict.core.validation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 校验字段值是否为指定类型下存在且启用的字典值。 + */ +@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE_USE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Constraint(validatedBy = InDictValidator.class) +public @interface InDict { + + /** + * 字典类型。 + */ + String value(); + + String message() default "inDict.message"; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/cf-framework/cf-spring-boot-starter-excel/src/main/java/com/cf/imes/framework/dict/core/validation/InDictValidator.java b/cf-framework/cf-spring-boot-starter-excel/src/main/java/com/cf/imes/framework/dict/core/validation/InDictValidator.java new file mode 100644 index 000000000..9ffeffc67 --- /dev/null +++ b/cf-framework/cf-spring-boot-starter-excel/src/main/java/com/cf/imes/framework/dict/core/validation/InDictValidator.java @@ -0,0 +1,43 @@ +package com.cf.imes.framework.dict.core.validation; + +import com.cf.imes.framework.common.constants.ResourceBundleConstants; +import com.cf.imes.framework.common.util.i18n.core.util.ResourceBundleUtils; +import com.cf.imes.framework.dict.core.util.DictFrameworkUtils; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import org.springframework.context.i18n.LocaleContextHolder; + +import java.util.Locale; + +/** + * 字典值校验器。 + */ +public class InDictValidator implements ConstraintValidator { + + private String dictType; + + @Override + public void initialize(InDict annotation) { + this.dictType = annotation.value(); + } + + @Override + public boolean isValid(Object value, ConstraintValidatorContext context) { + // 是否必填由 @NotNull、@NotBlank 等注解负责。 + if (value == null) { + return true; + } + if (DictFrameworkUtils.isDictDataValid(dictType, String.valueOf(value))) { + return true; + } + + String messageKey = context.getDefaultConstraintMessageTemplate(); + Locale locale = LocaleContextHolder.getLocale(); + String message = ResourceBundleUtils.getMessage( + ResourceBundleConstants.MESSAGE_ENUM_PATH, messageKey, messageKey, locale, value); + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(message).addConstraintViolation(); + return false; + } + +} diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/DictTypeConstants.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/DictTypeConstants.java index a6db84f83..51001f2f3 100644 --- a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/DictTypeConstants.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/DictTypeConstants.java @@ -32,4 +32,6 @@ public class DictTypeConstants { public static final String PLATE_TEXTURE_TYPE = "plate_texture_type";// 板材纹路:0有 1无 + public static final String LABEL_TYPE = "labelType"; // 标签类型 + } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/label/vo/LabelSaveReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/label/vo/LabelSaveReqVO.java index 16e00808a..0e550799d 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/label/vo/LabelSaveReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/label/vo/LabelSaveReqVO.java @@ -1,5 +1,7 @@ package com.cf.imes.module.system.controller.admin.label.vo; +import com.cf.imes.framework.dict.core.validation.InDict; +import com.cf.imes.module.system.enums.DictTypeConstants; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -17,6 +19,7 @@ public class LabelSaveReqVO { @Schema(description = "标签类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @NotNull(message = "标签类型不能为空") @Size(max = 32, message = "标签类型长度不能超过32个字符") + @InDict(DictTypeConstants.LABEL_TYPE) private String type; @Schema(description = "标签名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") @@ -43,4 +46,4 @@ public class LabelSaveReqVO { @Schema(description = "组织ID") private Long organId; -} \ No newline at end of file +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/labeltemplate/vo/LabelTemplateSaveReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/labeltemplate/vo/LabelTemplateSaveReqVO.java index 22c38c9fe..5abc3473a 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/labeltemplate/vo/LabelTemplateSaveReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/labeltemplate/vo/LabelTemplateSaveReqVO.java @@ -1,5 +1,7 @@ package com.cf.imes.module.system.controller.admin.labeltemplate.vo; +import com.cf.imes.framework.dict.core.validation.InDict; +import com.cf.imes.module.system.enums.DictTypeConstants; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import jakarta.validation.constraints.NotEmpty; @@ -16,6 +18,7 @@ public class LabelTemplateSaveReqVO { @Schema(description = "标签类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @NotNull(message = "标签类型不能为空") @Size(max = 50, message = "标签类型长度不能超过50个字符") + @InDict(DictTypeConstants.LABEL_TYPE) private String type; @Schema(description = "标签名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") @@ -41,4 +44,4 @@ public class LabelTemplateSaveReqVO { @Schema(description = "配置") private String template; -} \ No newline at end of file +} diff --git a/cf-module-system/cf-module-system-biz/src/main/resources/message_enum_cht.properties b/cf-module-system/cf-module-system-biz/src/main/resources/message_enum_cht.properties index 8199371d3..0cf0a81d8 100644 --- a/cf-module-system/cf-module-system-biz/src/main/resources/message_enum_cht.properties +++ b/cf-module-system/cf-module-system-biz/src/main/resources/message_enum_cht.properties @@ -1,4 +1,5 @@ inEnum.message=必須在指定範圍 {0} +inDict.message=字典值 {0} 不存在或已停用 inScope.message={0}不合法 inScope.adPosition=廣告位置 @@ -103,4 +104,4 @@ excel.export.head.sms.log.templateContent=短信內容 excel.export.head.sms.log.sendStatus=發送狀態 excel.export.head.sms.log.templateId=模板編號 excel.export.head.sms.log.templateCode=模板編碼 -excel.export.head.sms.log.templateType=短信類型 \ No newline at end of file +excel.export.head.sms.log.templateType=短信類型 diff --git a/cf-module-system/cf-module-system-biz/src/main/resources/message_enum_en.properties b/cf-module-system/cf-module-system-biz/src/main/resources/message_enum_en.properties index f412889ad..c2aa0437b 100644 --- a/cf-module-system/cf-module-system-biz/src/main/resources/message_enum_en.properties +++ b/cf-module-system/cf-module-system-biz/src/main/resources/message_enum_en.properties @@ -1,4 +1,5 @@ inEnum.message=Must be within the specified range {0} +inDict.message=Dictionary value {0} does not exist or is disabled inScope.message={0} is illegal inScope.adPosition=Advertising position @@ -103,4 +104,4 @@ excel.export.head.sms.log.templateContent=SMS Content excel.export.head.sms.log.sendStatus=Send Status excel.export.head.sms.log.templateId=Template ID excel.export.head.sms.log.templateCode=Template Code -excel.export.head.sms.log.templateType=SMS Type \ No newline at end of file +excel.export.head.sms.log.templateType=SMS Type diff --git a/cf-module-system/cf-module-system-biz/src/main/resources/message_enum_zh.properties b/cf-module-system/cf-module-system-biz/src/main/resources/message_enum_zh.properties index 48f0946be..ef4aa40f4 100644 --- a/cf-module-system/cf-module-system-biz/src/main/resources/message_enum_zh.properties +++ b/cf-module-system/cf-module-system-biz/src/main/resources/message_enum_zh.properties @@ -1,4 +1,5 @@ inEnum.message=必须在指定范围 {0} +inDict.message=字典值 {0} 不存在或已停用 inScope.message={0}不合法 inScope.adPosition=广告位置 @@ -103,4 +104,4 @@ excel.export.head.sms.log.templateContent=短信内容 excel.export.head.sms.log.sendStatus=发送状态 excel.export.head.sms.log.templateId=模板编号 excel.export.head.sms.log.templateCode=模板编码 -excel.export.head.sms.log.templateType=短信类型 \ No newline at end of file +excel.export.head.sms.log.templateType=短信类型