Micronaut自定义校验约束:如何为不同违规场景设置自定义消息
Absolutely! You can define unique, scenario-specific error messages for your CheckDecimal constraint in Micronaut. The ConstraintValidatorContext does have the tools you need—you just need to use its message-building methods to override the default annotation message for each violation case. Here's how to implement it:
Key API Methods to Use
You’ll rely on three critical methods from ConstraintValidatorContext to customize messages:
buildConstraintViolationWithTemplate(String message): Creates a custom violation message template (supports variable substitution with${}).disableDefaultConstraintViolation(): Turns off the default message defined in your@CheckDecimalannotation, so only your custom message is shown.addConstraintViolation(): Finalizes and adds the custom violation to the validation context.
Modified Validator Implementation
Here’s your updated checkDecimalValidator() with tailored messages for each violation scenario:
@Factory class ValidatorFactory { @Singleton ConstraintValidator<CheckDecimal, Double> checkDecimalValidator() { return { Double value, AnnotationValue<CheckDecimal> annotation, ConstraintValidatorContext context -> final parameters = annotation.convertibleValues.asMap() final keySet = parameters.keySet() if(value == null) { return true } // Validate minimum value if(keySet.contains('minimum')) { double minimumValidator = parameters.get('minimum') if(value < minimumValidator) { context.buildConstraintViolationWithTemplate("数值不能小于 ${minimumValidator}") .addConstraintViolation() context.disableDefaultConstraintViolation() return false } } // Validate maximum value if(keySet.contains('maximum')) { double maximumValidator = parameters.get('maximum') if(value > maximumValidator) { context.buildConstraintViolationWithTemplate("数值不能大于 ${maximumValidator}") .addConstraintViolation() context.disableDefaultConstraintViolation() return false } } // Validate integer part length if(keySet.contains('integerLength')) { final integerLengthValidator = parameters.get('integerLength') final integerLength = value.toString().split(/\./)[0].length() if(integerLength > integerLengthValidator) { context.buildConstraintViolationWithTemplate("整数部分长度不能超过 ${integerLengthValidator} 位") .addConstraintViolation() context.disableDefaultConstraintViolation() return false } } // Validate decimal part length if(keySet.contains('decimalLength')) { final decimalLengthValidator = parameters.get('decimalLength') final decimalLength = value.toString().split(/\./)[1].length() if(decimalLength > decimalLengthValidator) { context.buildConstraintViolationWithTemplate("小数部分长度不能超过 ${decimalLengthValidator} 位") .addConstraintViolation() context.disableDefaultConstraintViolation() return false } } return true } as ConstraintValidator<CheckDecimal, Double> } }
How It Works
- For each violation condition (e.g., value below the minimum), we first construct a custom message using the parameter value from your
@CheckDecimalannotation (like${minimumValidator}). - We add this custom violation to the validation context with
addConstraintViolation(). - We call
disableDefaultConstraintViolation()to ensure the default message from your annotation isn’t displayed alongside the custom one. - Return
falseto mark the field as invalid.
Optional: Internationalization (i18n)
If you need multi-language support, replace hardcoded messages with keys that map to properties files. For example:
// Use a message key instead of hardcoded text context.buildConstraintViolationWithTemplate("{checkdecimal.minimum.violation}") .addConstraintViolation()
Then define the key in your messages.properties file:
checkdecimal.minimum.violation=数值不能小于 {0}
Micronaut will automatically resolve the key and substitute parameter values (you can pass additional parameters via addParameter() if needed).
内容的提问来源于stack exchange,提问作者Nolyurn

