2012-03-16 23 views
32

que tiene un controlador simple que se parece a esto: -comprensión de cómo funciona @RequestMapping POST del Spring MVC

@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) { 
     ... 
    } 
} 

Básicamente, esta página tiene las siguientes funcionalidades: -

  • usuario visita la página principal (/groups GET).
  • El usuario crea un nuevo grupo (/groups POST) o selecciona un grupo específico (/groups/1 GET).
  • El usuario edita un grupo existente (/groups/1 POST).

Entiendo cómo funcionan las dos asignaciones de solicitudes GET aquí. Se define el mapeo n. ° 2, de lo contrario (/groups/1 GET) se producirá la excepción "No se encontró el mapeo".

Lo que trato de entender aquí es ¿por qué el mapeo # 3 maneja tanto (/groups POST) como (/groups/1 POST)? Tiene sentido que se controle aquí (/groups POST) ya que la asignación de solicitudes coincide con el URI. ¿Por qué (/groups/1 POST) no se está produciendo una excepción de "No se encontró el mapeo" aquí? De hecho, casi parece que cualquier POST con URI que comience con/groups (por ejemplo, /groups/bla/1 POST) también se manejará mediante el mapeo # 3.

¿Alguien me puede dar una explicación clara de esto? Muchas gracias.

CLARIFICACION

entiendo el hecho de que puedo utilizar métodos más apropiados (como GET, POST, PUT o DELETE) ... o puede crear una nueva asignación de solicitud de manejar /groups/{id} POST.

Sin embargo, lo que realmente quiero saber es ...

.... "¿Por qué la asignación # 3 mango /groups/1 POST también?"

El razonamiento de "coincidencia más cercana" no parece ser cierto porque si elimino el mapeo n. ° 2, entonces pensaría que el mapeo n. ° 1 manejará /groups/1 GET, pero no lo hace y causa un error. "excepción"

Estoy un poco perplejo aquí.

+0

¿Por qué no utilizar PUT para la actualización de un recurso? Ese sería el protocolo HTTP adecuado. –

+0

El envío del formulario web solo admite GET y POST, y no estoy haciendo una llamada AJAX aquí, así que no puedo confiar en PUT y DELETE en este punto. – limc

+0

@limc, eso no es realmente cierto, los POST se pueden modificar (en el lado del servidor) a otro tipo de Solicitud con la ayuda de 'org.springframework.web.filter.HiddenHttpMethodFilter' – Ralph

Respuesta

19

Esto es complicado, creo que es mejor leer el código.

En Spring 3.0 La magia se realiza por el método public Method resolveHandlerMethod(HttpServletRequest request) de la clase interna ServletHandlerMethodResolver de org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.

Existe una instancia de esta clase para cada Clase de controlador de solicitudes, y tiene un campo handlerMethods que contiene una lista de todos los métodos de solicitud.

Pero permítanme resumir como yo lo entiendo

  • primavera primero comprueba si al menos un método de control de los partidos (esta puede contener falsos negativos)
  • Entonces se crea un mapa de todos los métodos de controlador realmente emparejan
  • continuación, ordena el mapa ruta de solicitud: RequestSpecificMappingInfoComparator
  • y toma la primera

La clasificación funciona de esta manera: el RequestSpecificMappingInfoComparator primero compara la ruta con la ayuda de un AntPathMatcher, si dos métodos son iguales de acuerdo con esto, entonces se toman en cuenta otras métricas (como el número de parámetros, número de encabezados, etc.) respecto a la solicitud.

+4

Vaya ... miro a través de 'resolveHandlerMethod (...)', hablo del código de complejidad ciclomática súper alta, me perdí después de enésimas declaraciones anidadas. Leí el javadoc en 'RequestSpecificMappingInfoComparator' que habla de la lista de pedidos. Tengo curiosidad por qué no se comportan igual para los métodos GET y POST. En otra palabra, si elimino el mapeo # 2, ¿por qué el mapeo # 1 no está manejando '/ groups/1 GET' pero en su lugar, Spring arroja una excepción ... – limc

+0

@Ralph - buena explicación de las partes internas – raddykrish

2

Spring intenta encontrar el mapeo que coincida con el más cercano.
Por lo tanto, en su caso de cualquier solicitud POST, el único mapa encontrado para el tipo de solicitud es Mapping # 3. Ni Mapping 1 ni Mapping 2 coincide con su tipo de solicitud, y por lo tanto se ignoran. ¡Puede tratar de eliminar el Mapping # 3 y ver que Spring arroja un error de tiempo de ejecución ya que no encuentra coincidencias!

+1

Inicialmente pensé lo mismo también que Spring está encontrando la coincidencia más cercana. Sin embargo, me di cuenta de que no es totalmente cierto porque si ese es el caso, debería poder eliminar el mapeo n. ° 2, y '/ grupos/1 OBTENER" debe manejarse con el mapeo n. ° 1 ya que es la coincidencia más cercana. ... pero obtengo una excepción "No se encontró un mapa" aquí. No pude encontrar ninguna documentación de Spring que explique más sobre esta situación. – limc

-2

añadir a @PathVariable el parámetro id largo en la cartografía # 2

1

Me gustaría agregar una asignación de puestos a/grupos/{id}. Supongo que POST también funcionaría, pero no sería estrictamente correcto desde una perspectiva HTTP.

añadiendo @RequestMapping ("/ {id}", POST) debería cubrirlo?

+0

¿Cómo envío el formulario web usando PUT, sin usar las llamadas AJAX? Todavía estoy interesado en saber por qué Spring se comporta de esta manera con mi situación actual. – limc

+0

Quizás también vea cómo simular una PUT con spring.http: //stackoverflow.com/questions/4362791/can-spring-mvc-handle-requests-from-html-forms-other-then-post-and-get –

+0

No tiene un controlador definido para la asignación de grupos/{id}. También lo consideraría un error porque me sería difícil ver el caso de uso para el comportamiento que estás viendo. –

Cuestiones relacionadas