복붙노트

[SPRING] Hibernate Validator로 어떻게 메시지 파라미터를 동적으로 해결하나요?

SPRING

Hibernate Validator로 어떻게 메시지 파라미터를 동적으로 해결하나요?

저는 Hibernate Validator를 사용하고 있으며 에러 메시지에서 카테고리의 이름을 해결하고 싶습니다. 다음과 같은 간단한 시나리오를 고려하십시오.

public class Category {
    private String name;
}

public class Product {
    @HazardousCategoryConstraint(message = "{haz.cat.error}")
    private Category category;
    private String name;
}

public class InventoryReport {
    @Valid
    private List<Product> products;
}


ValidationMessages.properties
haz.cat.error={name} is a product in the hazardous category list.

HazardousCategoryConstraint의 작동 구현이 있다고 가정합니다. 유효성 검사기는 각 범주의 이름을 제한된 이름의 목록과 비교하여 검사합니다. 유효성 검사 (InventoryReport)를 호출하면 동일한 문자열을 제외하고 예상되는 오류 수가 발생합니다. 카테고리의 이름이 각 메시지로 해석되는 것을보고 싶습니다. 누군가가 동적으로 매개 변수를 해결하는 방법에 대한 예를 가르쳐 주거나 나를 보여 줄 수 있습니까?

해결법

  1. ==============================

    1.IMO, 간단한 솔루션은 javax.validation.MessageInterpolator의 사용자 정의 구현을 작성하는 것입니다. 주요 작업을 Hibernate Validator의 ResourceBundleMessageInterpolator에게 위임하고 CustomMessageInterpolator에서 필요한 대체 작업을 수행하십시오.

    IMO, 간단한 솔루션은 javax.validation.MessageInterpolator의 사용자 정의 구현을 작성하는 것입니다. 주요 작업을 Hibernate Validator의 ResourceBundleMessageInterpolator에게 위임하고 CustomMessageInterpolator에서 필요한 대체 작업을 수행하십시오.

    public class CustomMessageInterpolator extends org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator {
    
        private static final Pattern MESSAGE_PARAMETER_PATTERN = Pattern.compile( "(\\{[^\\}]+?\\})" );
    
        @Override
        public String interpolate(String message, Context context) {
            String resolvedMessage = super.interpolate(message, context);
            resolvedMessage = replacePropertyNameWithPropertyValues(resolvedMessage, context.getValidatedValue());
            return resolvedMessage;
        }
    
        private String replacePropertyNameWithPropertyValues(String resolvedMessage, Object validatedValue) {
            Matcher matcher = MESSAGE_PARAMETER_PATTERN.matcher( resolvedMessage );
            StringBuffer sb = new StringBuffer();
    
            while ( matcher.find() ) {
                String parameter = matcher.group( 1 );
    
                String propertyName = parameter.replace("{", "");
                propertyName = propertyName.replace("}", "");
    
                PropertyDescriptor desc = null;
                try {
                    desc = new PropertyDescriptor(propertyName, validatedValue.getClass());
                } catch (IntrospectionException ignore) {
                    matcher.appendReplacement( sb, parameter );
                    continue;
                }
    
                try {
                    Object propertyValue = desc.getReadMethod().invoke(validatedValue);
                    matcher.appendReplacement( sb, propertyValue.toString() );
                } catch (Exception ignore) {
                    matcher.appendReplacement( sb, parameter );
                }
            }
            matcher.appendTail( sb );
            return sb.toString();
        }
    
    }
    

    @테스트

    public void validate() {
            Configuration<?> configuration = Validation.byDefaultProvider().configure();
            ValidatorFactory validatorFactory = configuration.messageInterpolator(new CustomMessageInterpolator()).buildValidatorFactory();
            Validator validator = validatorFactory.getValidator();
    
            Product p = new Product();
            Category cat = new Category();
            cat.setName("s"); //assume specified name is invalid
            p.setCategory(cat);
    
            Set<ConstraintViolation<Product>> violations = validator.validate(p);
            for(ConstraintViolation<Product> violation : violations) {
                System.out.println(violation.getMessage());
            }
        }
    

    산출

    s is a product in the hazardous category list.
    
  2. from https://stackoverflow.com/questions/4765127/how-do-i-dynamically-resolve-message-parameters-with-hibernate-validator by cc-by-sa and MIT license