2012-03-16 17 views
32

Ho un semplice controller che assomiglia a questo: -Capire come di Spring MVC @RequestMapping Post Works

@Controller 
@RequestMapping(value = "/groups") 
public class GroupsController { 
    // mapping #1 
    @RequestMapping(method = RequestMethod.GET) 
    public String main(@ModelAttribute GroupForm groupForm, Model model) { 
     ... 
    } 

    // mapping #2 
    @RequestMapping(value = "/{id}", method = RequestMethod.GET) 
    public String changeGroup(@PathVariable Long id, @ModelAttribute GroupForm groupForm, Model model) { 
     ... 
    } 

    // mapping #3 
    @RequestMapping(method = RequestMethod.POST) 
    public String save(@Valid @ModelAttribute GroupForm groupForm, BindingResult bindingResult, Model model) { 
     ... 
    } 
} 

In sostanza, questa pagina ha le seguenti funzionalità: -

  • utente visita la pagina principale (/groups GET).
  • L'utente crea un nuovo gruppo (/groups POST) o seleziona un gruppo specifico (/groups/1 GET).
  • L'utente modifica un gruppo esistente (/groups/1 POST).

Capisco come funzionano entrambi i mapping delle richieste GET. La mappatura n. 2 è definita, altrimenti (/groups/1 GET) causerà un'eccezione "Nessuna associazione trovata".

Quello che sto cercando di capire qui è il motivo per la mappatura # 3 gestisce sia (/groups POST) e (/groups/1 POST)? Ha senso che dovrebbe gestire (/groups POST) qui poiché il mapping della richiesta corrisponde all'URI. Perché (/groups/1 POST) non sta generando un'eccezione "Nessuna associazione trovata" che viene lanciata qui? In effetti, sembra quasi che qualsiasi POST con URI che inizia con/gruppi (es: /groups/bla/1 POST) venga gestito anche dalla mappatura # 3.

Qualcuno può fornirmi una spiegazione chiara? Grazie mille.

CHIARIMENTO

Capisco il fatto che posso usare metodi più appropriati (come GET, POST, PUT o DELETE) ... o io in grado di creare l'ennesimo mappatura richiesta per gestire /groups/{id} POST.

Tuttavia, quello che voglio sapere davvero è ...

.... "Perché mappatura # 3 maniglia /groups/1 POST anche tu?"

Il ragionamento "più vicino match" non sembrano tenere vero, perché se tolgo la mappatura # 2, quindi penserei mappatura # 1 si occuperà /groups/1 GET, ma non è così e che provoca un "alcun mapping trovato " eccezione.

Sono solo un po 'perplesso qui.

+0

Perché non utilizzare PUT per l'aggiornamento di una risorsa? Quello sarebbe il protocollo HTTP corretto. –

+0

L'invio del modulo web supporta solo GET e POST, e non sto facendo call AJAX qui, quindi non posso contare su PUT e DELETE a questo punto. – limc

+0

@limc, questo non è proprio vero, i POST possono essere modificati (sul lato server) in un altro tipo di richiesta con l'aiuto di 'org.springframework.web.filter.HiddenHttpMethodFilter' – Ralph

risposta

19

Questo è complicato, penso che sia meglio leggere il codice.

In primavera 3.0 La magia viene eseguita con il metodo public Method resolveHandlerMethod(HttpServletRequest request) della classe interna ServletHandlerMethodResolver di org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.

Un'istanza di questa classe esiste per ogni classe di controller richiesta e ha un campo handlerMethods che contiene un elenco di tutti i metodi di richiesta.

Ma lasciatemi riassumere quanto ho capito

  • primavera prima controlla se almeno un metodo del gestore corrisponde (questo può contenere falsi negativi)
  • Poi si crea una mappa con tutti realmente corrispondenti metodi del gestore
  • Poi ordina la mappa richiesta di traccia: RequestSpecificMappingInfoComparator
  • e prende il primo

L'ordinamento funziona in questo modo: il RequestSpecificMappingInfoComparator confronta prima il percorso con l'aiuto di uno AntPathMatcher, se due metodi sono uguali in base a questo, quindi altre metriche (come il numero di parametri, il numero di intestazioni, ecc.) Sono prese in considerazione con rispetto alla richiesta.

+4

Wow ... Guardo attraverso 'resolveHandlerMethod (...)', parlo del super alto numero di complessità ciclomatica, mi sono perso dopo le ennesime dichiarazioni if ​​annidate. Ho letto javadoc su 'RequestSpecificMappingInfoComparator' che parla della lista degli ordini. Sono curioso del perché non si comportano allo stesso modo per i metodi GET e POST. In un'altra parola, se rimuovo la mappatura # 2, perché la mappatura # 1 non sta gestendo '/ groups/1 GET', ma invece, Spring lancia un'eccezione ... – limc

+0

@Ralph - bella spiegazione degli interni – raddykrish

2

Spring tenta di trovare la mappatura che corrisponde al più vicino.
Quindi, nel caso di qualsiasi richiesta POST, l'unica mappa trovata per il tipo di richiesta è Mappatura n. 3. Né di Mapping 1 o Mapping 2 corrisponde al tipo di richiesta, e quindi vengono ignorati. Potrebbe essere possibile provare a rimuovere il Mapping # 3, e vedere che Spring genera un errore di runtime dal momento che non trova una corrispondenza!

+1

Inizialmente pensavo lo stesso anche che la primavera sta trovando la corrispondenza più vicina. Tuttavia, mi sono reso conto che non è del tutto vero perché, se così fosse, dovrei essere in grado di rimuovere la mappatura # 2, e '/ groups/1 GET' dovrebbe essere gestita dalla mappatura # 1, poiché è la corrispondenza più vicina. .. ma sto ricevendo un'eccezione "Nessuna mappatura trovata" qui. Non sono riuscito a trovare alcuna documentazione Spring che spieghi di più su questa situazione. – limc

-2

aggiungere @PathVariable al parametro lungo id nella mappatura # 2

1

vorrei aggiungere una mappatura PUT per/gruppi/{id}. Immagino che il POST funzionerebbe anche se non strettamente corretto da una prospettiva HTTP.

aggiungendo @RequestMapping ("/ {id}", POST) dovrebbe coprirlo?

+0

Come si invia il modulo Web utilizzando PUT, senza utilizzare le chiamate AJAX? Sono ancora interessato a sapere perché Spring si comporta in questo modo con la mia situazione attuale. – limc

+0

Forse anche controllare come prendere in giro un PUT con spring.http: //stackoverflow.com/questions/4362791/can-spring-mvc-handle-requests-from-html-forms-other-then-post-and-get –

+0

Non è stato definito un gestore per il mapping dei gruppi/{id}. Lo considererei anche un bug perché mi sarebbe difficile vedere il caso d'uso per il comportamento che stai vedendo. –

Problemi correlati