2016-07-15 154 views
2

我有一個用於輸入日期的Spring MVC表單,輸入被髮送到Controller並通過標準Spring MVC驗證進行驗證。將@Future和LocalDate的自定義ConstraintValidator添加到Spring Boot項目

型號:

public class InvoiceForm { 
    @Future 
    private LocalDate invoicedate; 
} 

控制器:

public String postAdd(@Valid @ModelAttribute InvoiceForm invoiceForm, BindingResult result) { 
    .... 
} 

當提交我得到以下錯誤的形式:

javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 'javax.validation.constraints.Future' validating type 'java.time.LocalDate'. Check configuration for 'invoicedate' 
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.throwExceptionForNullValidator(ConstraintTree.java:229) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getConstraintValidatorNoUnwrapping(ConstraintTree.java:310) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getConstraintValidatorInstanceForAutomaticUnwrapping(ConstraintTree.java:244) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getInitializedConstraintValidator(ConstraintTree.java:163) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:116) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:87) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:73) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidatorImpl.java:617) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:580) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForSingleDefaultGroupElement(ValidatorImpl.java:524) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:492) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:457) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:407) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:205) ~[hibernate-validator-5.2.4.Final.jar:5.2.4.Final] 
at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:108) ~[spring-context-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.validation.DataBinder.validate(DataBinder.java:866) ~[spring-context-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.validateIfApplicable(ModelAttributeMethodProcessor.java:164) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:111) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:99) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) ~[spring-webmvc-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:832) ~[spring-webmvc-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:743) ~[spring-webmvc-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:961) ~[spring-webmvc-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:895) ~[spring-webmvc-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967) ~[spring-webmvc-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869) ~[spring-webmvc-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) ~[spring-webmvc-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:316) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at com.balticfinance.jwt.StatelessAuthenticationFilter.doFilter(StatelessAuthenticationFilter.java:46) ~[classes/:na] 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE] 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) ~[tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:676) [tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) [tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528) [tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099) [tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:670) [tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520) [tomcat-embed-core-8.0.36.jar:8.0.36] 
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476) [tomcat-embed-core-8.0.36.jar:8.0.36] 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_91] 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_91] 
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.36.jar:8.0.36] 
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_91] 

我實現我自己的ConstraintValidator這種情況。但不知怎麼的,Spring Boot並沒有選擇它進行驗證。

@Component 
public class LocalDateFutureValidator implements ConstraintValidator<Future, LocalDate> { 

    @Override 
    public void initialize(Future future) { 
    } 

    @Override 
    public boolean isValid(LocalDate localDate, ConstraintValidatorContext constraintValidatorContext) { 
     LocalDate today = LocalDate.now(); 
     return localDate.isEqual(today) || localDate.isAfter(today); 
    } 
} 

我知道我可以簡單地寫我自己的註釋並在那裏指定驗證器,但是沒有更簡潔更簡單的方法嗎?

+1

'@ Component'是非常沒用的,因爲驗證器不是由Spring管理的。你的'@ Future'應該指定使用哪個驗證器。如果您使用的是最新版本的hibernate驗證器,那麼您可以立即使用它,並且根本不需要自定義驗證器。 –

+1

謝謝,通過https://hibernate.atlassian.net/browse/HV-874判斷@自從使用hibernate-validator 5.2以後,應該支持LocalDate。我實際上使用休眠驗證5.2.4.Final(自動拉動spring-boot-starter-data-jpa我猜)。我正在使用spring-boot-starter-parent 1.3.6.RELEASE –

+0

LocalDate的驗證器已被刪除,可能我應該使用另一種類型的?! https://hibernate.atlassian.net/browse/HV-981 –

回答

2

你需要自己的驗證添加到META-INF/validation.xml文件,像這樣:

<constraint-mappings 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.1.xsd" 
    xmlns="http://jboss.org/xml/ns/javax/validation/mapping" version="1.1"> 

    <constraint-definition annotation="javax.validation.constraints.Future"> 
     <validated-by include-existing-validators="true"> 
      <value>package.to.LocalDateFutureValidator</value> 
     </validated-by> 
    </constraint-definition> 
</constraint-mappings> 

有關詳細信息,refer to the official documentation.

+1

您不必排除現有的驗證器,但通常使用XML添加新的ConstraintValidator是正確的。如果你很樂意使用非標準化的方法,你也可以看看ConstraintDefinitionContributor。在這種情況下,您可以使用Java ServiceLoader方法添加新的約束驗證程序。這就是說,爲什麼LocalDate沒有@Future實現是有原因的。根據定義,無法確定LocalDate是否將來,因爲它不包含時區信息。這可能是你的情況,但.. – Hardy

+0

他們不排除,但事實上,包括:) –

+0

我有一個春季啓動應用程序,我試圖基本上做同樣的事情。我如何告訴Spring我的自定義驗證器?儘管有一個validation.xml文件(在我的Resources文件夾中),我仍然不斷收到UnexpectedTypeException –

0

我與米洛什同意在使用META-INF/validation.xml可能是最乾淨和最簡單的方法,但如果你真的想在類中設置它,那麼這是可能的,這是你可以做到的一種方法。

Spring Boot的美妙之處在於,它代表了您的許多配置,因此您不必擔心。但是,當你想自己專門配置某些東西時,這也會導致問題,而且怎麼做也不是非常明顯。

所以昨天我開始嘗試添加CustomerValidator@PastLocalDate使用ConstraintDefinitionContributor機制,哈迪建議(和Hibernate文檔中提及)的。

簡單的位是寫的實現類做了驗證,這對我非常具體的用途包括了:

public class PastValidator implements ConstraintValidator<Past, LocalDate> { 

    @Override 
    public void initialize(Past constraintAnnotation) {} 

    @Override 
    public boolean isValid(LocalDate value, ConstraintValidatorContext context) { 
     return null != value && value.isBefore(LocalDate.now()); 
    } 
} 

然後我懶惰,只是在我的配置實例化一個@Bean,剛上那麼Spring的自動配置類中的一個只會選擇它並將其連接到Hibernate驗證器。考慮到可用的文件(或缺少文件)以及哈代和其他人說過的話,這是相當長的一個鏡頭,並沒有得到回報。

因此,我啓動了一個調試器,並從org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree中拋出的異常後退,它告訴我它找不到@PastLocalDate的驗證器。

望着ConstraintValidatorFactory的類型層次,我發現有兩個實現類在我的Spring MVC應用程序:SpringConstraintValidatorFactorySpringWebConstraintValidatorFactory這兩者只是嘗試,並從正確的類的情況下得到的bean。這告訴我,我必須讓我的驗證器在Spring的BeanFactory上註冊,但是當我在這個上面插入一個斷點時,它並沒有碰到我的PastValidator,這意味着Hibernate不知道它應該甚至請求這個類。

這是有道理的:沒有任何地方可以告訴Hibernate它需要向Spring詢問一個PastValidator的實例。在 http://docs.jboss.org/hibernate/validator/5.2/reference/en-US/html_single/#section-constraint-definition-contributor 的文檔中的例子表明我需要訪問HibernateValidatorConfiguration,所以我只需要找到Spring在配置的位置。

經過一點挖掘之後,我發現這一切都發生在Spring的LocalValidatorFactoryBean類中,特別是在其afterPropertiesSet()方法中。從它的javadoc:

/* 
* This is the central class for {@code javax.validation} (JSR-303) setup in a Spring 
* application context: It bootstraps a {@code javax.validation.ValidationFactory} and 
* exposes it through the Spring {@link org.springframework.validation.Validator} interface 
* as well as through the JSR-303 {@link javax.validation.Validator} interface and the 
* {@link javax.validation.ValidatorFactory} interface itself. 
*/ 

基本上,如果你不設置並配置自己的驗證那麼這就是春天試圖爲你做它,而在真正的春天風格它提供了一個方便的擴展方法,使你可以讓它做它的配置,然後加入你自己的組合。

所以我的解決辦法是隻延長LocalValidatorFactoryBean,這樣我可以註冊自己的ConstraintDefinitionContributor實例:

import java.util.ArrayList; 
import java.util.List; 
import javax.validation.Configuration; 
import org.hibernate.validator.internal.engine.ConfigurationImpl; 
import org.hibernate.validator.spi.constraintdefinition.ConstraintDefinitionContributor; 
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; 

public class ConstraintContributingValidatorFactoryBean extends LocalValidatorFactoryBean { 

    private List<ConstraintDefinitionContributor> contributors = new ArrayList<>(); 

    public void addConstraintDefinitionContributor(ConstraintDefinitionContributor contributor) { 
     contributors.add(contributor); 
    } 

    @Override 
    protected void postProcessConfiguration(Configuration<?> configuration) { 
     if(configuration instanceof ConfigurationImpl) { 
      ConfigurationImpl config = ConfigurationImpl.class.cast(configuration); 
      for(ConstraintDefinitionContributor contributor : contributors) 
       config.addConstraintDefinitionContributor(contributor); 
     } 
    } 
} 

然後實例,在我的Spring配置配置此:

@Bean 
    public ConstraintContributingValidatorFactoryBean validatorFactory() { 
     ConstraintContributingValidatorFactoryBean validatorFactory = new ConstraintContributingValidatorFactoryBean(); 
     validatorFactory.addConstraintDefinitionContributor(new ConstraintDefinitionContributor() { 
      @Override 
      public void collectConstraintDefinitions(ConstraintDefinitionBuilder builder) { 
        builder.constraint(Past.class) 
          .includeExistingValidators(true) 
          .validatedBy(PastValidator.class); 
      } 
     }); 
     return validatorFactory; 
    } 

爲了完整性,這裏也是我通過PastValidator bean實例化的地方:

@Bean 
    public PastValidator pastValidator() { 
     return new PastValidator(); 
    } 

其他彈性,一樣的東西

我在調試注意到,因爲我已經有了相當大的Spring MVC應用程序中,我看到的SpringConstraintValidatorFactory兩個實例和SpringWebConstraintValidatorFactory之一。我發現後者 從未在驗證過程中使用過,因此我暫時忽略了它。

春天也有一個機制來決定哪些執行ValidatorFactory使用,因此有可能它不使用你的ConstraintContributingValidatorFactoryBean,而使用 別的東西(對不起,我發現在它該昨天做了類,但couldn」今天再次找到它,雖然我只花了大約2分鐘看)。如果你在任何種類的那麼不平凡的路 使用Spring MVC機會是你已經有了寫自己的配置類,如這一個,它實現WebMvcConfigurer在那裏你可以在你的Validator豆明確絲:

public static class MvcConfigurer implements WebMvcConfigurer { 

    @Autowired 
    private ConstraintContributingValidatorFactoryBean validatorFactory; 

    @Override 
    public Validator getValidator() { 
     return validatorFactory; 
    } 

    // ... 
    // <snip>lots of other overridden methods</snip> 
    // ... 
} 

這是錯誤

正如已經指出的那樣,你應該警惕應用@Past驗證到LocalDate因爲沒有時區信息的。但是,如果您使用的是LocalDate,因爲所有內容都會在同一時區運行,或者您故意忽略時區,或者您不在意,那麼這對您而言就沒有問題。

相關問題