2013-06-26 13 views
7

Sto usando Spring MVC 3.2.2Primavera HandlerMethodArgumentResolver non esecuzione

Ho definito una classe HandlerMethodArgumentResolver personalizzato come questo

public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver { 

    public CurrentUserArgumentResolver() { 
    System.out.println("Ready"); 
    } 

    @Override 
    public boolean supportsParameter(MethodParameter parameter) { 
    return parameter.hasParameterAnnotation(CurrentUser.class); 
    } 

    @Override 
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, 
     NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { 

     Principal principal = webRequest.getUserPrincipal(); 
     System.out.println("*** Principal ***: " + principal); 
     return principal; 
    } 
} 

E aggiunto il seguente alla mia app-servlet.xml

<mvc:annotation-driven> 
    <mvc:argument-resolvers> 
    <beans:bean class="my.package.CurrentUserArgumentResolver" lazy-init="false"/> 
    </mvc:argument-resolvers> 
</mvc:annotation-driven> 

e creato un'annotazione per CurrentUser

@Target(ElementType.PARAMETER) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface CurrentUser { 

} 

Quando avvio l'applicazione, la classe è costruita in quanto posso vedere il messaggio di registro "Pronto" ma il resolver non viene eseguito quando annoto un metodo controller in quanto tale (in una classe che ha annotazione @Controller)

@RequestMapping(method = RequestMethod.POST, value = "/update") 
public ModelAndView update(@RequestParam MultipartFile background, @CurrentUser Principal principal) { 
... 
} 

Se inserisco punti di interruzione su uno dei due metodi nella classe CurrentUserArgumentResolver, nessuno dei due funziona. Quindi non sono sicuro di ciò che mi manca?

+0

apparire esattamente come la mia risposta a questa domanda: http://stackoverflow.com/questions/8764545/best-practice-for-getting-active-users-userdetails/8769670#8769670 - Non riesco a vedere alcun errore nel codice postato. Quindi forse il problema è da qualche altra parte: controlla che tutto sia conforme e sia distribuito correttamente. Verifica che ci sia solo un MVC: anotationdriven. Verificare che il raggio del controller venga rilevato solo dalla scansione del componente dall'app-servlet.xml – Ralph

+0

Sì, il mio codice era basato su una combinazione di risposta e documenti Spring. Tutto il codice viene compilato e il metodo del controller è chiamato correttamente, è solo che il principale è nullo. Mi aspetto almeno che venga chiamato il punto di interruzione su "supportsParameter". –

+0

Qual è il valore del parametro del metodo controller (principal)? È nulla? – Ralph

risposta

3

OK Ho capito che Spring stava già risolvendo l'oggetto Principal nel mio esempio precedente e quindi il mio risolutore di argomenti non stava dando il calcio d'inizio. Ero stato pigro e ho aggiunto l'annotazione @CurrentUser a un parametro esistente.

Così ho cambiato il mio esempio

@RequestMapping(method = RequestMethod.POST, value = "/update") 
public ModelAndView update(@RequestParam MultipartFile background, @CurrentUser Principal principal) { 
    ... 
} 

di usare il mio utente classe del modello

@RequestMapping(method = RequestMethod.POST, value = "/update") 
public ModelAndView update(@RequestParam MultipartFile background, @CurrentUser User user) { 
    ... 
} 

e ora funziona!

+1

Grazie per questa risposta, mi ha indirizzato nella giusta direzione. Uno dei miei corsi che volevo risolvere era estendere AbstractAuthenticationToken e come tale, è stato risolto anche da Spring senza che io nemmeno lo sapessi. La mia soluzione era creare un'interfaccia, usarla come parametro di metodo e risolvere l'interfaccia. –

+0

@ PetrDvořák Ho avuto lo stesso identico problema. L'ho riparato anche collegandolo a un'interfaccia. –

12

Se qualcuno vuole mai di dare la priorità gestori personalizzati oltre gestori predefiniti aggiunti entro la primavera, ecco un frammento che fa per me, lo faccio in un file @Configuration

private @Inject RequestMappingHandlerAdapter adapter; 

@PostConstruct 
public void prioritizeCustomArgumentMethodHandlers() { 
    List<HandlerMethodArgumentResolver> argumentResolvers = 
     new ArrayList<> (adapter.getArgumentResolvers()); 
    List<HandlerMethodArgumentResolver> customResolvers = 
     adapter.getCustomArgumentResolvers(); 
    argumentResolvers.removeAll (customResolvers); 
    argumentResolvers.addAll (0, customResolvers); 
    adapter.setArgumentResolvers (argumentResolvers); 
} 
+0

Come può essere ottenuto utilizzando la configurazione XML? – Andy

+0

Non deve essere un '@ Configuration' puoi metterlo su qualsiasi bean singleton, ma quello è un hack.Non devi modificare l'intero progetto in java config, puoi avere una classe con '@ Configuration' nel tuo percorso di individuazione automatica che fa esattamente questo. Tutta la tua altra configurazione sarebbe in XML. In alternativa, è possibile estendere il 'RequestMappingHandlerAdapter', inserire questo codice lì (non si dovrebbe iniettare se stesso ovviamente) e creare il bean adattatore in XML, tuttavia considererei l'approccio di configurazione più pulito poiché si sta infatti configurando il adattatore,

+0

Potrebbe essere necessario eseguire altre configurazioni non disponibili tramite XML e sarà necessario inserirle nella classe derivata che diventerà un punto in cui raccogliere un mucchio di cose che non hanno nulla a che fare l'una con l'altra. –

0

Io uso la proprietà customArgumentResolvers per caricare fagioli , in questo modo:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> 
     <property name="messageConverters"> 
      <list> 
       <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 
        <property name="supportedMediaTypes"> 
         <list> 
          <value>text/html;charset=UTF-8</value> 
          <value>text/plain;charset=UTF-8</value> 
          <value>application/json;charset=UTF-8</value> 
         </list> 
        </property> 
       </bean> 
      </list> 
     </property> 
     <property name="customArgumentResolvers"> 
     <list> 
      <bean id="MyTestMethodArgumentResolver" class="com.gst.authorization.resolvers.MyTestMethodArgumentResolver"></bean>   
      <bean id="currentUserMethodArgumentResolver" class="com.gst.authorization.resolvers.CurrentUserMethodArgumentResolver"> 
          <property name="userModelClass" value="com.gst.model.appuser.AppUser" /> 
        <property name="userModelRepository" ref="userRepository" /> 
       </bean> 
     </list>   
     </property> 
    </bean> 
    <mvc:annotation-driven /> 
Problemi correlati