2016-04-26 20 views
5

yay servlet.xml neden olur Benim önleyicim, herhangi bir İlkbahardan önce çağrıldı Validator ek açıklamasının ek açıklamalı denetleyici yöntemi. Amaç, doğrulama başarısız olursa, isteği doğrulamaktır, isteği farklı bir görünüme iletin. Bu genellikle çalışıyor. (!valid) numaralı bir hata varsa, RequestDispatcher.forward çağrılır. Bu, en sonunda hata görünümünü gösteren başka bir Spring denetleyici yönteminin çağrılmasına neden olur. Bu normal çalışır.Spring AOP yinelemeli aramaları

Sorun: Bazı Bahar denetleyicileri için

, benim RequestDispatcher en errorView istek (invoke() üzerinde adlandırılan ve üzeri alır) geri sonsuz döngü neden aynı yöntemle iletilir neden olur. Bunun nedeni, yay denetleyicisinin istek eşlemelerinin (aşağıya bakınız) nasıl ayarlandığından kaynaklanmaktadır.

Hata görünümü: @RequestMapping(value = URL, params="error")

Normal görünüm: İlk istek o istek parametreleri içinde 'devam' var yönlendirilir Yani @RequestMapping(value = URL, params="proceed")

. Sonra bir hata ve RequestDispatcher sorgu dizesinde 'error' parametresiyle görünümüne iletildiğinde, yukarıdaki "Hata görünümü" yöntemini iletmesi gerekir, ancak olmaz. Her zaman, MethodInterceptor invoke()'da sonsuz bir döngüye neden olan 'devam' yöntemine doğru ilerler. Bunun nedeni, 'devam' parametresinin HttpServletRequest'de kalmasıdır. Ancak bu, sabitlenmesi kolay değildir çünkü önleyicinin tüm noktası, yay denetleyicisinin kendisinin hiçbir bilgisi olmadığıdır - yalnızca bir hatanın oluşup oluşmadığını ve bir hata oluştuğunda hata görünümüne yönlendirmesi gerektiğini bilir.

Çözüm: Aşağıdaki istek eşleştirmeleri kullanma

, bu sorunu giderir. Bunun nedeni büyük olasılıkla, anahtar = değer gösterimi kullanılırken HttpServletRequest parametresinin üzerine yazılmasıdır.

Hata görünümü: @RequestMapping(value = URL, params="view=error")

Normal görünüm: @RequestMapping(value = URL, params="view=proceed")

Soru

nasıl "düzgün" Yukarıda gösterilen geçici çözüm başvurmadan sorunu çözebilirsiniz? Doğru yay denetleyicisine iletmek için daha standart bir yol var mı?

+0

Tüm kaynak kodlarını github veya ** MethodInterceptor invoke() ** ile daha ayrıntılı olarak paylaşabilir misiniz? – CrawlingKid

cevap

1

Çözüm # 1:

aşağıdaki olarak yapılandırılmış olması:

MethodInterceptor çağırma işlemi():

if (!valid){ 

// RequestDispatcher rd = request.getRequestDispatcher(errorView); 
// rd.forward(request, response); 
    response.sendRedirect(errorView); 
} 
şöyle

Error view: @RequestMapping(value = URL, params="error") 

Normal view: @RequestMapping(value = URL, params="proceed") 

Sen yönlendirme için deneyebilirsiniz

Geri Çekme: tarayıcı ikinci bir istekte bulunacaktır, bu nedenle eski yöntem parametreleri artık httpservletrequest'de değildir.

WorkArround: Dezavantajları önlemek için, Spring MVC Flash Attribute'u kullanabilirsiniz. Flash Attribute'un nasıl çalıştığını öğrenmek için bu eğiticiyi takip edebilirsiniz.

Refs: FlashAttributesExample

Çözüm # 2:

nasıl "düzgün" Yukarıda gösterilen geçici çözüm başvurmadan sorunu çözebilirsiniz? Doğru yay denetleyicisine iletmenin daha standart bir yolu var mı? Sizi uygulayarak dahil olabilir

RequestMappingHandlerAdapterkendi.

3. Çözüm: yalnızca tüm kontrolörleri tek doğrulayıcı uygulayabileceğiniz bu-etrafında çalışma ile

public class RequestBodyValidatorAspect { 
    private Validator validator; 

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)") 
    private void controllerInvocation() { 
    } 

    @Around("controllerInvocation()") 
    public Object aroundController(ProceedingJoinPoint joinPoint) throws Throwable { 

    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); 
    Method method = methodSignature.getMethod(); 
    Annotation[][] argAnnotations = method.getParameterAnnotations(); 
    String[] argNames = methodSignature.getParameterNames(); 
    Object[] args = joinPoint.getArgs(); 

    for (int i = 0; i < args.length; i++) { 
     if (hasRequestBodyAndValidAnnotations(argAnnotations[i])) { 
     validateArg(args[i], argNames[i]); 
     } 
    } 

    return joinPoint.proceed(args); 
    } 

    private boolean hasRequestBodyAndValidAnnotations(Annotation[] annotations) { 
    if (annotations.length < 2) 
     return false; 

    boolean hasValid = false; 
    boolean hasRequestBody = false; 

    for (Annotation annotation : annotations) { 
     if (Valid.class.isInstance(annotation)) 
     hasValid = true; 
     else if (RequestBody.class.isInstance(annotation)) 
     hasRequestBody = true; 

     if (hasValid &amp;&amp; hasRequestBody) 
     return true; 
    } 
    return false; 
    } 

    @SuppressWarnings({"ThrowableInstanceNeverThrown"}) 
    private void validateArg(Object arg, String argName) { 
    BindingResult result = getBindingResult(arg, argName); 
    validator.validate(arg, result); 
    if (result.hasErrors()) { 
     throw new HttpMessageConversionException("Validation of controller input parameter failed", 
       new BindException(result)); 
    } 
    } 

    private BindingResult getBindingResult(Object target, String targetName) { 
    return new BeanPropertyBindingResult(target, targetName); 
    } 

    @Required 
    public void setValidator(Validator validator) { 
    this.validator = validator; 
    } 
} 

Bir sınırlama: Burada

yönü için kodudur. Bunu da önleyebilirsiniz. doğrulayıcı yönü ve birlikte meta doğrulayıcı kullanarak

public class TypeMatchingValidator implements Validator, InitializingBean, ApplicationContextAware { 
    private ApplicationContext context; 
    private Collection<Validator> validators; 

    public void afterPropertiesSet() throws Exception { 
    findAllValidatorBeans(); 
    } 

    public boolean supports(Class clazz) { 
    for (Validator validator : validators) { 
     if (validator.supports(clazz)) { 
     return true; 
     } 
    } 

    return false; 
    } 

    public void validate(Object target, Errors errors) { 
    for (Validator validator : validators) { 
     if (validator.supports(target.getClass())) { 
     validator.validate(target, errors); 
     } 
    } 
    } 

    private void findAllValidatorBeans() { 
    Map<String, Validator> validatorBeans = 
      BeanFactoryUtils.beansOfTypeIncludingAncestors(context, Validator.class, true, false); 
    validators = validatorBeans.values(); 
    validators.remove(this); 
    } 

    public void setApplicationContext(ApplicationContext context) throws BeansException { 
    this.context = context; 
    } 
} 

Bahar XML yapılandırma dosyası:

<!-- enable Spring AOP support --> 
    <aop:aspectj-autoproxy proxy-target-class="true"/> 

    <!-- declare the validator aspect and inject the validator into it --> 
    <bean id="validatorAspect" class="com.something.RequestBodyValidatorAspect"> 
    <property name="validator" ref="validator"/> 
    </bean> 

    <!-- inject the validator into the DataBinder framework --> 
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> 
    <property name="webBindingInitializer"> 
     <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer" p:validator-ref="validator"/> 
    </property> 
    </bean> 

    <!-- declare the meta-validator bean --> 
    <bean id="validator" class="com.something.TypeMatchingValidator"/> 

    <!-- declare all Validator beans, these will be discovered by TypeMatchingValidator --> 
    <bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/> 
    <bean class="com.something.PersonValidator"/> 
    <bean class="com.something.AccountValidator"/> 

Kaynaklar Refs: scottfrederick:pring-3-Validation-Aspect

Çözüm # 4:

Henüz başka çözüm aop kullanarak form doğrulama için blogu kontrol edebilirsiniz: form-validation-using-aspect-oriented-programming-aop-in-spring-framework

+0

Teknik olarak, bu sorun tarayıcıyı ikinci bir istekte bulunacağı için düzeltecektir, bu nedenle eski yöntem parametreleri artık httpservletrequest'de bulunmamaktadır. Bununla birlikte, temel olarak, Bahar yaşam döngüsüne nasıl bağlanacağını ve talebi bir Bahar kontrolörüne doğru bir şekilde iletmeyi gerektiren sorulardan kaçınmaktadır. – KyleM