Генерация ошибки проверки пружины - PullRequest
3 голосов
/ 19 ноября 2010

Я использую JSR-303 для проверки и Spring MVC 3. Проверка выполняется вручную через validator.validate(bean, errors) в контроллере.

Я аннотировал свойство name класса Foo с помощью@NotNull.Когда проверка завершилась неудачно, я заметил, что Spring MVC сгенерировал следующие коды ошибок в объекте Errors.

NotNull.form.foo.name
NotNull.name
NotNull.java.lang.String
NotNull

Способ работы тега <form:errors> состоит в том, что он пройдет через все коды ошибоки ищите пакет ресурсов по умолчанию, пока он не вернет ненулевое сообщение.Есть ли способ настроить эти коды ошибок или, по крайней мере, порядок их перечисления?

Причина в том, что у меня есть пользовательский объект ResourceBundle, который возвращает сообщение по умолчанию, полученное из данного кода сообщения, если ни один из них не являетсянайдено в текстовом файле пакета ресурсов.Поскольку тег работает вниз по списку кодов ошибок, он сначала будет искать NotNull.form.foo.name в этом примере.Текстовый файл, конечно, не имеет этой записи, поэтому пользовательский объект ResourceBundle вернет сообщение по умолчанию.Проблема в том, что у меня уже есть сообщение, определенное в текстовом файле для NotNull, но тег увидит его в таком виде.

Если бы я мог как-то сгенерировать только один код ошибки или изменить порядоккоды ошибок, это будет работать.

Есть идеи?Спасибо.

Ответы [ 2 ]

2 голосов
/ 19 ноября 2010

Не удалось найти более простое решение, чем это ...

my-servlet.xml

<bean id="handlerAdapter" class="org.opensource.web.StandardAnnotationMethodHandlerAdapter">
</bean>

StandardAnnotationMethodHandlerAdapter.java

public class StandardAnnotationMethodHandlerAdapter extends AnnotationMethodHandlerAdapter    {
    @Override
    protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object target, String objectName) throws Exception {
    MyServletRequestDataBinder dataBinder = new MyServletRequestDataBinder(target, objectName);
    return dataBinder;
   }
}

MyServletRequestDataBinder .java

public class MyServletRequestDataBinder extends ServletRequestDataBinder {

private MessageCodesResolver messageCodesResolver = new MyMessageCodesResolver();

@Override
public void initBeanPropertyAccess() {
   super.initBeanPropertyAccess();
   BindingResult bindingResult = super.getBindingResult();
   if(bindingResult instanceof AbstractBindingResult) {
       ((AbstractBindingResult)bindingResult).setMessageCodesResolver(messageCodesResolver);
   }
}

@Override
public void initDirectFieldAccess() {
  super.initDirectFieldAccess();
  BindingResult bindingResult = super.getBindingResult();
  if(bindingResult instanceof AbstractBindingResult) {
     ((AbstractBindingResult)bindingResult).setMessageCodesResolver(messageCodesResolver);
    }
 }
}

MyMessageCodesResolver .java

public class MyMessageCodesResolver extends DefaultMessageCodesResolver {

public static final String NOT_NULL_ERROR_CODE = "NotNull";

@Override
public String[] resolveMessageCodes(String errorCode, String objectName, String field, Class fieldType) {
   if(NOT_NULL_ERROR_CODE.equalsIgnoreCase(errorCode)) {
       String notNullErrorCode = errorCode + CODE_SEPARATOR + objectName + CODE_SEPARATOR + field;
       //notNullErrorCode = postProcessMessageCode(notNullErrorCode);
       return new String[] {notNullErrorCode};
    }
      return super.resolveMessageCodes(errorCode, objectName, field, fieldType);
}   
}
2 голосов
/ 19 ноября 2010

Я использую следующий класс, чтобы вручную выполнить проверку bean-компонента JSR-303 и HibernateValidator с помощью валидатора Spring.Возможно, это может быть полезно.

BeanValidator.java

import java.util.Locale;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;

public class BeanValidator implements org.springframework.validation.Validator, InitializingBean {

private static final Logger log = LoggerFactory.getLogger(BeanValidator.class.getName());

private Validator validator;

@Autowired
MessageSource messageSource;

@Override
public void afterPropertiesSet() throws Exception {
    ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
    validator = validatorFactory.usingContext().getValidator();
}

@Override
public boolean supports(Class clazz) {
    return true;
}

@Override
public void validate(Object target, Errors errors) {
    Set<ConstraintViolation<Object>> constraintViolations = validator.validate(target);
    for (ConstraintViolation<Object> constraintViolation : constraintViolations) {
        String propertyPath = constraintViolation.getPropertyPath().toString();
        String message;
        try {
            message = messageSource.getMessage(constraintViolation.getMessage(), new Object[]{}, Locale.getDefault());
        } catch (NoSuchMessageException e) {
            log.error(String.format("Could not interpolate message \"%s\" for validator. "
                    + e.getMessage(), constraintViolation.getMessage()), e);
            message = constraintViolation.getMessage();
        }
        errors.rejectValue(propertyPath, "", message);
    }
}
}

SpringMessageSourceMessageInterpolator.java

import javax.validation.MessageInterpolator;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.NoSuchMessageException;

public class SpringMessageSourceMessageInterpolator extends ResourceBundleMessageInterpolator implements MessageInterpolator, MessageSourceAware, InitializingBean {

@Autowired
private MessageSource messageSource;

@Override
public String interpolate(String messageTemplate, Context context) {
    try {
        return messageSource.getMessage(messageTemplate, new Object[]{}, Locale.getDefault());
    } catch (NoSuchMessageException e) {
        return super.interpolate(messageTemplate, context);
    }
}

@Override
public String interpolate(String messageTemplate, Context context, Locale locale) {
    try {
        return messageSource.getMessage(messageTemplate, new Object[]{}, locale);
    } catch (NoSuchMessageException e) {
        return super.interpolate(messageTemplate, context, locale);
    }
}

@Override
public void setMessageSource(MessageSource messageSource) {
    this.messageSource = messageSource;
}

@Override
public void afterPropertiesSet() throws Exception {
    if (messageSource == null) {
        throw new IllegalStateException("MessageSource was not injected, could not initialize "
                + this.getClass().getSimpleName());
    }
}
}

applicationContext.xml

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource" p:basename="messages"/>

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <property name="messageInterpolator">
        <bean class="com.company.utils.spring.SpringMessageSourceMessageInterpolator" />
    </property>
</bean>

Пример свойства компонента

@NotNull(message = "validation.mandatoryField")
private ClientGroup clientGroup;

Пример проверки

@Controller
public class MyController {

    @Autowired
    private BeanValidator validator;

    @RequestMapping("/foo", method=RequestMethod.POST)
    public void processFoo(ModelAttribute("foo") Foo foo, BindingResult result, Model model) {
        //...
        validator.validate(foo, result);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...