Tú Puede usar la anotación @RequestMapping
para asignar solicitudes a métodos de controlador. Tiene
varios atributos para hacer coincidir por URL, método HTTP, parámetros de solicitud, encabezados, encabezados y
tipos de datos. Puede usarlo a nivel de clase para expresar asignaciones generales o a nivel de método para
limitarlo a una asignación de punto final específica.
También hay opciones específicas del método HTTP para acortar el
@RequestMapping
anotación:
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
Las abreviaturas son anotaciones personalizadas que se
especifican porque, quizás, la mayoría de los métodos del controlador deben asignarse a un método HTTP específico en
lugar de utilizar la anotación @RequestMapping
, que se asigna a todos los métodos HTTP de forma
predeterminada. Para expresar asignaciones comunes a nivel de clase aún se requiere @RequestMapping
.
El siguiente ejemplo tiene asignaciones a nivel de tipo y método:
@RestController
@RequestMapping("/persons")
class PersonController {
@GetMapping("/{id}")
public Person getPerson(@PathVariable Long id) {
// ...
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void add(@RequestBody Person person) {
// ...
}
}
@RestController
@RequestMapping("/persons")
class PersonController {
@GetMapping("/{id}")
fun getPerson(@PathVariable id: Long): Person {
// ...
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
fun add(@RequestBody person: Person) {
// ...
}
}
Patrones URI
Métodos anotado con @RequestMapping
se puede asignar utilizando patrones
de URL. Hay dos alternativas:
PathPattern
: un patrón previamente analizado asignado a una ruta URL, también analizado previamente como unPathContainer
. Diseñada para su uso en el entorno de Internet, esta solución funciona eficientemente con codificación y parámetros de ruta y proporciona una coincidencia eficiente.AntPathMatcher
- plantillas de coincidencia de cadenas con cadena camino. Esta solución original también se utiliza en la configuración de Spring para seleccionar recursos en el classpath, en el sistema de archivos y otros lugares. Es menos eficiente y ingresar una ruta de cadena dificulta el manejo efectivo de la codificación y otros problemas de URL.
PathPattern
es la solución recomendada para las aplicaciones web, y esta es la única opción cuando
se trabaja en Spring WebFlux. Antes de la versión 5.3, AntPathMatcher
era la única opción cuando se
trabajaba en Spring MVC y sigue siendo la predeterminada. Sin embargo, PathPattern
se puede activar en
una configuración MVC.
PathPattern
admite la misma sintaxis de patrón que
AntPathMatcher
. Además, también admite un patrón de captura como {*spring}
para hacer
coincidir 0 o más segmentos de ruta al final de una ruta. PathPattern
también restringe el uso del
carácter **
para que coincida con múltiples segmentos de ruta, de modo que solo se permita al final del
patrón. Esto evita la ambigüedad al elegir el mejor patrón de coincidencia para una consulta determinada. La
sintaxis completa del patrón se proporciona en las secciones en PathPattern y AntPathMatcher.
Algunos ejemplos de plantillas:
"/resources/ima?e.png "
- coincide con un carácter en el segmento de ruta"/resources/*.png"
- coincide con cero o más caracteres en segmento de ruta"/resources/**"
– coincide con múltiples segmentos de ruta"/projects/{project}/versions"
– coincide con el segmento de ruta y lo escribe como una variable"/projects/{ proyecto:[a-z]+}/versions"
– emparejar y capturar una variable usando una expresión regular
Se puede acceder a las variables URI capturadas usando una anotación @PathVariable
. Por ejemplo:
@GetMapping("/owners/{ownerId}/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
// ...
}
@GetMapping("/owners/{ownerId}/pets/{petId}")
fun findPet(@PathVariable ownerId: Long, @PathVariable petId: Long): Pet {
// ...
}
Puede declarar variables URI a nivel de clase y método, como se muestra en el siguiente ejemplo:
@Controller
@RequestMapping("/owners/{ownerId}")
public class OwnerController {
@GetMapping("/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
// ...
}
}
@Controller
@RequestMapping("/owners/{ownerId}")
class OwnerController {
@GetMapping("/pets/{petId}")
fun findPet(@PathVariable ownerId: Long, @PathVariable petId: Long): Pet {
// ...
}
}
Las variables URI son se convierte automáticamente al tipo apropiado o se lanza una TypeMismatchException
.
Los tipos simples (int
, long
, Date
, etc.) se admiten de forma predeterminada,
pero se puede registrar compatibilidad con cualquier otro tipo de datos. Consulte Conversión de tipos y DataBinder
.
Puede nombrar explícitamente variables URI (por ejemplo, @PathVariable("customId")
), pero también
puede omita esta información si los nombres son los mismos y su código se compila utilizando información de
depuración o con el indicador del compilador -parameters
en Java 8.
Sintaxis {varName:regex}
declara una variable URI usando una expresión regular, que tiene la sintaxis {varName:regex}
.
Por ejemplo, si se proporciona la URL "/spring-web-3.0.5.jar"
, el siguiente método recupera el nombre
del archivo, la versión y la extensión:
@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
public void handle(@PathVariable String name, @PathVariable String version, @PathVariable String ext) {
// ...
}
@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
fun handle(@PathVariable name: String, @PathVariable version: String, @PathVariable ext: String) {
// ...
}
Las plantillas de ruta de URI también pueden contener marcadores de posición integrados ${...}
,
que se reconocen cuando se ejecutan usando PropertySourcesPlaceholderConfigurer
en el sistema local.
fuentes de propiedades, entorno de fuentes de propiedades, etc. Puede utilizar esto, por ejemplo, para parametrizar
una URL base en función de alguna configuración externa.
Comparación de plantillas
Si varios patrones coinciden con una URL, es necesario seleccionar el más adecuado. Esto se hace de una de las
siguientes maneras, dependiendo de si se permite o no el uso del PathPattern
analizado
sintácticamente:
Ambos ayudan a ordenar las plantillas, con las más específicas en la parte superior. Un patrón es menos específico si tiene menos URI variables (cuenta como 1), comodines simples (cuenta como 1) y comodines dobles (cuenta como 2). Si los indicadores son iguales, se selecciona la plantilla más larga. Dadas las mismas métricas y longitud, se selecciona el patrón que tiene más URI variables que comodines.
El patrón de visualización predeterminado (/**
) se excluye del recuento y siempre se ordenado al
final. Además, los patrones con prefijos (como /public/**
) se consideran menos específicos que
otros patrones que no contienen comodines dobles.
Para obtener información completa, siga estos Consulte el enlaces anteriores para obtener descripciones de comparadores de patrones.
Coincidencia de sufijos
A partir de la versión 5.3, Spring MVC ya no utiliza de forma predeterminada la coincidencia de patrones con los
sufijos .*
si El controlador asignado a /person
también está implícitamente asignado a
/person.*
. Como consecuencia, las extensiones de ruta ya no se utilizan para interpretar el tipo de
contenido solicitado para la respuesta; por ejemplo, /person.pdf
, /person.xml
, etc. .
El uso de extensiones de archivo de esta manera era necesario cuando los navegadores enviaban encabezados
Aceptar
que eran difíciles de interpretar de manera consistente. Esto ya no es necesario hoy en día, y
usar el encabezado Aceptar
debería ser la opción preferida.
Con el tiempo, el uso de extensiones de nombre de archivo ha resultado problemático por diversas razones. Esto puede causar ambigüedad al superponer usando URI variables, parámetros de ruta y codificación de URI. Defender la autorización y la seguridad basadas en URL (consulte la siguiente sección para obtener más detalles) también se vuelve más complejo.
Para deshabilitar completamente el uso de extensiones de ruta en versiones anteriores a la 5.3, configure lo siguiente:
useSuffixPatternMatching(false)
favorPathExtension(false)
Tener una forma de solicitar tipos de contenido distintos del encabezado "Aceptar"
puede ser útil,
por ejemplo, al ingresar una URL en un navegador. Una alternativa segura a la expansión de rutas es utilizar la
estrategia de parámetros de consulta. Si debe utilizar extensiones de archivo, considere restringirlas a una
lista de extensiones registradas explícitamente a través de la propiedad mediaTypes
de
ContentNegotiationConfigurer.
Coincidencia de sufijos y RFD
Los ataques de descarga de archivos reflejados por vectores (RFD) son similares a XSS en que se basan en que la entrada de la solicitud (como un parámetro de solicitud y una variable URI) se refleja en la respuesta. Sin embargo, en lugar de insertar JavaScript en HTML, el vector de ataque RFD se basa en cambiar el navegador para realizar la descarga y tratar la respuesta como un script ejecutable cuando luego hace doble clic en él.
En Spring MVC, los métodos marcados con la anotación @ResponseBody
y ResponseEntity
están en riesgo porque pueden representar diferentes tipos de contenido que los clientes pueden solicitar a
través de extensiones de ruta URL. Deshabilitar la coincidencia de patrones de sufijos y usar extensiones de
ruta para hacer coincidir el contenido reduce el riesgo, pero no es suficiente para prevenir ataques RFD.
Para evitar ataques RFD, Spring MVC agrega un encabezado Content-Disposition:inline;filename=f.txt
antes
de representar el cuerpo
de respuesta para ofrecer un archivo de descarga fijo y seguro. Esto solo se hace
si la ruta URL contiene una extensión de archivo que no se considera segura y no se ha registrado explícitamente
para la negociación de contenido. Sin embargo, esto puede tener efectos secundarios si las URL se ingresan
directamente en el navegador.
Muchas extensiones de ruta comunes se permiten como seguras de forma predeterminada. Las aplicaciones con
implementaciones personalizadas de HttpMessageConverter
pueden registrar explícitamente extensiones
de archivos para la negociación de contenido para evitar agregar un encabezado Content-Disposition
para estas extensiones.
Consideraciones adicionales relacionadas con RFD, consulte "CVE-2015-5211".
Consumido Tipos de datos
Puede limitar la visualización de la consulta según la consulta Content-Type
, como se muestra en el
siguiente ejemplo:
@PostMapping(path = "/pets", consumes = "application/json")
public void addPet( @RequestBody Pet pet) {
// ...
}
- Usando atributo
consume
para limitar el rango de visualización por tipo de contenido.
@PostMapping("/pets", consumes = ["application/json" ])
fun addPet(@RequestBody pet: Pet) {
// ...
}
- Utilice el atributo
consume
para limitar el rango de visualización por tipo de contenido.
El atributo consume
también admite expresiones de negación; por ejemplo, !text/plain
significa cualquier tipo de contenido que no sea text/plain
.
Puedes declarar el atributo
general consume
a nivel de clase. Sin embargo, a diferencia de la mayoría de los otros atributos de
mapeo de solicitudes, cuando se usa a nivel de clase, el atributo consume
a nivel de método anula en
lugar de extender la declaración a nivel de clase.
MediaType
proporciona constantes para los tipos de medios
utilizados habitualmente, como APPLICATION_JSON_VALUE
y APPLICATION_XML_VALUE
.
Tipos de datos producidos
Puede limitar el rango de solicitudes que se muestran según el encabezado
de solicitud Aceptar
y la lista de tipos de contenido que produce el método del controlador, como se
muestra en el siguiente ejemplo:
@GetMapping(path = "/pets/{petId}", produces = "application/json")
@ResponseBody
public Pet getPet(@PathVariable String petId) {
// ...
}
- Utilice el atributo
produce
para limitar el rango de visualización por tipo de contenido.
@GetMapping("/pets/{petId}", produces = ["application/json"])
@ResponseBody
fun getPet( @PathVariable petId: String): Pet {
// ...
}
- El uso del atributo
produce
para limitar el rango de visualización por tipo de contenido.
El tipo de medio puede determinar el conjunto de caracteres. Se admiten expresiones negables; por ejemplo,
!text/plain
significa cualquier tipo de contenido que no sea "texto/plain".
Puedes declarar un
genérico
produce
atributo a nivel de clase. Sin embargo, a diferencia de la mayoría de los otros
atributos de mapeo de solicitudes, cuando se usa a nivel de clase, el atributo produce
a nivel de
método anula en lugar de extender la declaración a nivel de clase.
MediaType
proporciona constantes para los tipos de medios utilizados habitualmente, como APPLICATION_JSON_VALUE
y
APPLICATION_XML_VALUE
.
Parámetros, encabezados
Puede limitar el rango de visualización
de consultas según las condiciones de los parámetros de consulta. Puede comprobar la presencia de un parámetro de
consulta(myParam
), su ausencia (!myParam
) o un valor
específico(myParam=myValue
). El siguiente ejemplo muestra cómo verificar la presencia de un valor
específico:
@GetMapping(path = "/pets/{petId}", params = "myParam=myValue ")
public void findPet(@PathVariable String petId) {
// ...
}
- Comprueba si
myParam
es igual amyValue
.
@GetMapping("/pets/{petId}", params = ["myParam=myValue"])
fun findPet(@PathVariable petId: String) {
// ...
}
- Comprueba si
myParam
es igual al valor demyValue
.
Se puede utilizar lo mismo con condiciones de encabezado de solicitud, como se muestra en el siguiente ejemplo:
@GetMapping(path = "/pets", headers = "myHeader=myValue")
public void findPet(@PathVariable String petId) {
// ...
}
- Comprueba si
myHeader
es igual amyValue
.
@GetMapping("/pets", headers = ["myHeader=myValue"])
fun findPet( @PathVariable petId: String) {
// ...
}
Content-Type
y Aceptar
con la condición de los encabezados, pero es mejor usar consume y produce en su lugar.
Métodos HTTP HEAD, OPTIONS
@GetMapping
(y
@RequestMapping(method=HttpMethod.GET)
) admiten de forma transparente el método HTTP HEAD para
solicitudes de mapeo. No es necesario cambiar los métodos del controlador. La función contenedora de respuesta
utilizada en javax.servlet.http.HttpServlet
garantiza que el encabezado Content-Length
esté establecido en el número de bytes escritos (sin escribir realmente en la respuesta) .
@GetMapping
(y @RequestMapping(method=HttpMethod.GET)
) se asignan implícitamente y
admiten el método HEAD HTTP. Una solicitud que utiliza el método HTTP HEAD se procesa de la misma manera que
un método HTTP GET, excepto que en lugar de escribir un cuerpo, se cuenta el número de bytes y se establece
el encabezado Content-Length
.
De forma predeterminada, el método OPCIONES HTTP se maneja configurando el encabezado de respuesta
Allow
en la lista de métodos HTTP enumerados en todos los métodos marcados con @RequestMapping
.
anotación que tiene patrones de URL coincidentes.
En el caso de la anotación @RequestMapping
sin declarar métodos HTTP, el encabezado
Allow
se establece en GET, HEAD, POST, PUT, PATCH, DELETE , OPTIONS
.
Los métodos del controlador siempre deben declarar métodos HTTP admitidos (por ejemplo, utilizando variantes
específicas del método HTTP: @GetMapping
, @PostMapping
y otros).
Puede
asignar explícitamente un método anotado con @RequestMapping
al método HEAD HTTP y al método
OPTIONS HTTP, pero en casos normales esto no es necesario.
Anotaciones personalizadas
Spring
MVC admite el uso de anotaciones compuestas para mostrar consultas. Estas son anotaciones que son en sí
mismas metanotaciones @RequestMapping
y están compuestas para volver a declarar un subconjunto
(o todos) de los atributos marcados con la anotación @RequestMapping
para un alcance más
limitado. , propósito más específico.
@GetMapping
, @PostMapping
, @PutMapping
, @DeleteMapping
y
@PatchMapping
son ejemplos de anotaciones compuestas. Se proporcionan porque es probable que
la mayoría de los métodos del controlador deban asignarse a un método HTTP específico en lugar de utilizar
la anotación @RequestMapping
, que se asigna a todos los métodos HTTP de forma predeterminada.
Si necesita un ejemplo de anotaciones compuestas, observe cómo se declaran.
Spring MVC también admite atributos de mapeo de consultas personalizados con lógica de mapeo de consultas
personalizada. Esta es una opción más avanzada que requiere subclasificar
RequestMappingHandlerMapping
y anular el método getCustomMethodCondition
en el que
puede verificar el atributo personalizado y devolver su propia RequestCondition
.
Registro explícito
Puede registrar mediante programación métodos de controlador, que se pueden usar para registro dinámico o en casos más complejos, como si hay diferentes instancias del mismo controlador en URL diferentes. El siguiente ejemplo registra un método de controlador:
@Configuration
public class MyConfig {
@Autowired
public void setHandlerMapping(RequestMappingHandlerMapping mapping, UserHandler handler)
throws NoSuchMethodException {
RequestMappingInfo info = RequestMappingInfo
.paths("/user/{id}").methods(RequestMethod.GET).build();
Method method = UserHandler.class.getMethod("getUser", Long.class);
mapping.registerMapping(info, handler, method);
}
}
- Inyectar el controlador de destino y la asignación de controladores para los controladores.
- Preparar los metadatos de asignación de la solicitud.
- Obtener el método del controlador.
- Agregar registro.
@Configuration
class MyConfig {
@Autowired
fun setHandlerMapping(mapping: RequestMappingHandlerMapping, handler: UserHandler) {
val info = RequestMappingInfo.paths("/user/{id}").methods(RequestMethod.GET).build()
val method = UserHandler::class.java.getMethod("getUser", Long::class.java)
mapping.registerMapping(info, handler, method)
}
}
- Inyectar el controlador de destino y la asignación del controlador para los controladores.
- Preparar los metadatos de asignación de la solicitud.
- Obtener el método de controlador.
- Agregar registro.