requestmapping pathvariable mvc español ejemplo java spring spring-mvc request-mapping

java - pathvariable - requestmapping spring boot



Comprender cómo funciona el POST @RequestMapping de Spring MVC (4)

Tengo un controlador simple que se ve así:

@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:

  • Página principal de visitas del usuario ( /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í. El mapeo # 2 está definido, de lo contrario ( /groups/1 GET ) causará una 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 maneje ( /groups POST ) aquí ya que el mapeo de solicitudes coincide con el URI. ¿Por qué ( /groups/1 POST ) no está provocando una excepción de "No se encontró una asignación" aquí? De hecho, casi parece que cualquier POST con URI que comience con / groups (ej: /groups/bla/1 POST ) también será manejado por el mapeo # 3.

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

ACLARACIÓN

Entiendo el hecho de que puedo usar métodos más apropiados (como GET, POST, PUT o DELETE) ... o puedo crear otra asignación de solicitud para manejar /groups/{id} POST .

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

.... "¿Por qué el mapeo # 3 maneja /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 es así y causa un "No se encontró mapeo" excepción.

Estoy un poco perplejo aquí.


Agregaría un mapeo PUT para / groups / {id}. Supongo que POST también funcionaría, pero no sería estrictamente correcto desde una perspectiva HTTP.

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


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

En Spring 3.0 La magia se realiza mediante 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 solicitud, y tiene un campo handlerMethods que contiene una lista de todos los métodos de solicitud.

Pero déjame resumir cómo lo entiendo

  • Spring primero comprueba si al menos un método de manejo coincide (esto puede contener falsos negativos)
  • A continuación, crea un mapa de todos los métodos de control realmente coincidentes
  • A continuación, ordena el mapa por ruta de solicitud: RequestSpecificMappingInfoComparator
  • y toma el primero

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


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 coinciden con su tipo de solicitud, y por lo tanto se ignoran. Puede ser que puedas intentar eliminar el Mapping # 3, y ver que Spring lanza un error de tiempo de ejecución ya que no encuentra una coincidencia.


agregue @PathVariable al parámetro Long id en la asignación n. ° 2