Manejador Los métodos con la anotación @RequestMapping
tienen una firma flexible y pueden elegir entre
una variedad de argumentos de método de controlador admitidos y valores de retorno.
Argumentos de método
Los siguientes La tabla describe los argumentos del método del controlador admitidos. Los tipos reactivos no son compatibles con ningún argumento.
El argumento java.util.Optional
de JDK 8 se
admite como argumento de método en combinación con anotaciones que tienen el required
atributo (por
ejemplo, @RequestParam
, @RequestHeader
y otros), y es equivalente a
required=false
.
Argumento del método controlador | Descripción |
---|---|
|
Proporciona acceso escrito a los parámetros de solicitud y a los atributos de solicitud y sesión, sin utilizar directamente la API de Servlet. |
|
Destinado a seleccionar cualquier tipo específico de solicitud o respuesta, por ejemplo, |
|
Asegura que existe una sesión. Como consecuencia, dicho argumento nunca es |
|
API de impulsor de compilación de Servlet 4.0 para inserción programática ) Recursos HTTP/2. Tenga en
cuenta que, según la especificación del servlet, la instancia |
|
El usuario autenticado actual - posiblemente una clase de implementación concreta de
Tenga en cuenta que este argumento no se reconoce aceleradamente si tiene una anotación diseñada para
permitir que un solucionador personalizado lo reconozca antes de recurrir al reconocimiento
predeterminado a través de |
|
Método de solicitud HTTP. |
|
La configuración regional actual de la solicitud, determinada por el |
|
La zona horaria asociada con la solicitud actual, según lo determinado por
|
|
Diseñado para proporcionar acceso al cuerpo de la solicitud sin formato tal como se presenta en la API de Servlet. |
|
Diseñado para proporcionar acceso al cuerpo de respuesta sin procesar expuesto por la API de Servlet. |
|
Diseñado para proporcionar acceso a variables de patrón URI. |
|
Diseñado para proporcionar acceso a pares "nombre-valor" en segmentos de ruta URI. |
|
Diseñado para proporcionar acceso a los parámetros de solicitud de servlet, incluidos archivos de varias partes. Los valores de los parámetros se convierten al tipo declarado de los argumentos del método. Tenga en cuenta que el uso de la anotación |
|
Diseñado para proporcionar acceso a los encabezados de solicitud. Los valores del encabezado se convierten al tipo declarado de argumento del método. |
|
Diseñado para proporcionar acceso a las cookies . Los valores de las cookies se convierten al tipo de argumento del método declarado. |
|
Para acceder al cuerpo de la solicitud HTTP. El contenido del cuerpo se convierte al tipo de argumento
del método declarado mediante implementaciones |
|
Diseñado para proporcionar acceso a los encabezados y al cuerpo de la solicitud. El cuerpo se convierte
usando |
|
Diseñado para proporcionar acceso a un componente en una solicitud |
|
Diseñado para proporcionar acceso a un modelo que se utiliza en controladores HTML y se expone en plantillas como parte de la representación de la vista. |
|
Especifica los atributos que se utilizarán en el evento de una redirección (es decir, se agregará a la línea de solicitud), atributos flash que se almacenarán temporalmente hasta que llegue la solicitud después de una redirección. |
|
Para acceder a un atributo existente en el modelo (del cual se crea una instancia si falta) con enlace de datos y validación. Tenga en cuenta que el uso de la anotación |
|
Diseñado para proporcionar acceso a errores de validación y enlace de datos para un objeto de comando (es
decir, un argumento con la anotación |
|
Destinado a marcar la finalización del procesamiento del formulario, lo que provoca que se declaren los
atributos de sesión a través de la anotación de código que se borrará
|
|
Diseñado para preparar una URL asociada con el host, puerto, esquema, ruta de contexto de la solicitud actual y componente literal de mapeo de servlet. |
|
Diseñado para proporcionar acceso a cualquier atributo de sesión, a diferencia de los atributos del
modelo, almacenados en la sesión como resultado de declarar la anotación |
|
Diseñado para proporcionar acceso a los atributos de la solicitud. |
Cualquier otro argumento |
Si el método del argumento no coincide con ninguno de los valores anteriores en esta tabla y es un tipo
simple (como se define en BeanUtils#isSimpleProperty ), se resuelve en |
Valores devueltos
En lo siguiente La tabla describe los valores de retorno admitidos del método del controlador. Los tipos reactivos son compatibles con todos los valores de retorno.
Valor de retorno del método del controlador | Descripción |
---|---|
|
El valor de retorno se convierte a través de la implementación |
|
Especificación del valor de retorno la respuesta completa (incluidos los encabezados y el cuerpo HTTP),
convertida a través de la implementación |
|
Diseñado para devolver una respuesta con encabezados y sin cuerpo. |
|
El nombre de la vista que las implementaciones de |
|
Una instancia de |
|
Atributos agregados al modelo implícito, con el nombre de la vista definido implícitamente mediante
|
|
Atributo, agregado al modelo cuyo nombre de vista se especifica implícitamente mediante Tenga en cuenta que la anotación |
|
Los atributos de vista y modelo a utilizar y, si es necesario, el estado de la respuesta. |
|
Se considera que un método con un tipo de retorno Si ninguno de los valores anteriores es verdadero, el tipo de retorno es |
|
Produce cualquiera de los valores de retorno anteriores de forma asincrónica desde cualquier subproceso, por ejemplo, como resultado de un evento o devolución de llamada. |
|
Produce cualquiera de los valores devueltos anteriormente de forma asincrónica en un hilo administrado por Spring MVC. |
|
Una alternativa más conveniente a |
|
Genera asincrónicamente un flujo de objetos para escribir en la respuesta usando |
|
Escritura asincrónica en |
Tipos reactivos: Reactor, RxJava u otros a través de |
Alternativa a En escenarios de transmisión (por ejemplo, |
Cualquier otro valor de retorno |
Cualquiera valor de retorno que no coincide con ninguno de los valores anteriores en esta tabla y es un
|
Conversión de tipo
Algunos argumentos anotados del método del controlador que representan la
entrada de la solicitud basado en String
(como @RequestParam
, @RequestHeader
,
@PathVariable
, @MatrixVariable
y @CookieValue
) pueden requerir una
conversión de tipo si el argumento no se declara como String
.
En tales casos, la conversión de
tipo es se aplica automáticamente en función de los convertidores configurados. De forma predeterminada, se admiten
tipos simples (int
, long
, Date
y otros). Puede configurar la conversión de
tipos a través de WebDataBinder
o registrando Formatters
con FormattingConversionService
.
Un problema práctico con la conversión de tipos es manejando vaciar el valor original de la cadena. Dicho valor
se considera faltante si se vuelve null
como resultado de una conversión de tipo. Esto puede ser cierto
para Long
, UUID
y otros tipos de destino. Si necesita permitir la inyección
null
, utilice el indicador required
en la anotación del argumento o declare el argumento
como @Nullable
.
A partir de la versión 5.3, los argumentos no nulos se respetarán incluso después de la conversión de tipos. Si
se espera que el método del controlador acepte un valor nulo, entonces declare el argumento como
@Nullable
o márquelo como required=false
en el anotación @RequestParam
apropiado etc. Esta es la mejor práctica y la solución recomendada para las regresiones encontradas al
actualizar a la versión 5.3.
Además, puede manejar especialmente, por ejemplo, la excepción MissingPathVariableException
que se
genera si el Se requiere la anotación @PathVariable
. Un valor nulo después de la conversión se
tratará como un valor original vacío, por lo que se generará la excepción Missing...Exception
correspondiente.
Variables de matriz
En RFC 3986 se describen pares nombre-valor en segmentos de ruta. En Spring MVC las llamamos "variables de matriz", según la "publicación anterior" de Tim Berners -Lee, pero también pueden denominarse parámetros de ruta URI.
Las variables de matriz pueden aparecer
en cualquier segmento de ruta, con cada variable separada por un punto y coma y múltiples valores separados por una
coma (por ejemplo, /cars;color=rojo,verde;año=2012
). También se pueden especificar múltiples
valores a través de nombres de variables repetidos (por ejemplo, color=red;color=green;color=blue
).
Si se espera que la URL contenga variables de matriz, entonces el mapeo de solicitudes para un método de controlador debe usar una variable URI para enmascarar el contenido de dicha variable de matriz y garantizar un mapeo de solicitudes exitoso independientemente del orden o la presencia de las variables de matriz. El siguiente ejemplo utiliza una variable de matriz:
// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
// petId == 42
// q == 11
}
// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
fun findPet(@PathVariable petId: String, @MatrixVariable q: Int) {
// petId == 42
// q == 11
}
Dado que todos los segmentos de ruta pueden contener variables matriciales, a veces ¿Necesitará determinar en qué variable de ruta debe estar la variable de matriz? El siguiente ejemplo muestra cómo hacer esto:
// GET /owners/42;q=11/pets/21;q=22
@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
@MatrixVariable(name="q", pathVar="ownerId") int q1,
@MatrixVariable(name="q", pathVar="petId") int q2) {
// q1 == 11
// q2 == 22
}
// GET /owners/42;q=11/pets/21;q=22
@GetMapping("/owners/{ownerId}/pets/{petId}")
fun findPet(
@MatrixVariable(name = "q", pathVar = "ownerId") q1: Int,
@MatrixVariable(name = "q", pathVar = "petId") q2: Int) {
// q1 == 11
// q2 == 22
}
Una variable de matriz se puede definir como opcional y tener un valor predeterminado, como se muestra en el siguiente ejemplo:
// GET /pets/42
@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {
// q == 1
}
// GET /pets/42
@GetMapping("/pets/{petId}")
fun findPet(@MatrixVariable(required = false, defaultValue = "1") q: Int) {
// q == 1
}
Para obtener todas las matrices variables, puede utilizar MultiValueMap
como se muestra en el
siguiente ejemplo:
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
@MatrixVariable MultiValueMap<String, String> matrixVars,
@MatrixVariable(pathVar="petId") MultiValueMap<String, String> petMatrixVars) {
// matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
// petMatrixVars: ["q" : 22, "s" : 23]
}
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
@GetMapping("/owners/{ownerId}/pets/{petId}")
fun findPet(
@MatrixVariable matrixVars: MultiValueMap<String, String>,
@MatrixVariable(pathVar="petId") petMatrixVars: MultiValueMap<String, String>) {
// matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
// petMatrixVars: ["q" : 22, "s" : 23]
}
Tenga en cuenta que el uso de variables matriciales debe estar habilitado. En la configuración de MVC en Java,
debe configurar UrlPathHelper
cuando removeSemicolonContent=false
mediante Path Matching.
En el espacio de nombres MVC en XML puede configurar <mvc:annotation-driven enable-matrix-variables="true"/>
.
@RequestParam
La anotación @RequestParam
se puede utilizar para vincular los
parámetros de solicitud del servlet (es decir, parámetros de solicitud o datos de formulario) a un argumento de
método en el controlador.
En el siguiente ejemplo se muestra cómo hacer esto:
@Controller
@RequestMapping("/pets")
public class EditPetForm {
// ...
@GetMapping
public String setupForm( @RequestParam("petId") int petId, Model model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet);
return "petForm";
}
// ...
}
- Usando la anotación
@RequestParam
para enlacespetId
.
import org.springframework.ui.set
@Controller
@RequestMapping("/pets" )
class EditPetForm {
// ...
@GetMapping
fun setupForm(@RequestParam("petId") petId: Int, model: Model): String {
val pet = this.clinic.loadPet(petId);
model["pet"] = pet
return "petForm"
}
// ...
}
- Usar la anotación
@RequestParam
para vincular elpetId
.
De forma predeterminada, los parámetros del método que usan esta anotación son obligatorios, pero usted puede
especifique que el parámetro del método es opcional estableciendo el indicador required
de la
anotación @RequestParam
en false
o declarando el argumento usando el Función
contenedora java.util.Optional
.
La conversión de tipo se aplica automáticamente si el tipo de parámetro del método de destino no es
String
.
Declaración del El tipo de argumento como matriz o lista permite múltiples valores de parámetros para el mismo nombre de parámetro.
Si la anotación @RequestParam
se declara como Map<String, String>
o MultiValueMap<String,
String>
sin especificar un nombre de parámetro en la anotación, el mapa se completa con los valores
de parámetro de solicitud para cada nombre de parámetro dado.
Tenga en cuenta que usar la anotación
@RequestParam
es opcional (por ejemplo, para establecer atributos). De forma predeterminada,
cualquier
argumento que sea un tipo de valor simple (como se define en BeanUtils#isSimpleProperty) y no se resuelve mediante ningún otro solucionador de
argumentos, se trata como si estuviera anotado con @RequestParam
.
@RequestHeader
Puede utilizar la anotación @RequestHeader
para vincular el encabezado de la solicitud a un
argumento de método en el controlador.
Considere la siguiente solicitud con encabezados:
Host localhost:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9 Accept-Language fr,en-gb;q=0.7,en;q=0.3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive 300
El siguiente ejemplo muestra cómo obtenga el valor de encabezados Accept-Encoding
y
Keep-Alive
:
@GetMapping("/demo")
public void handle(
@RequestHeader(" Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive") long keepAlive) {
//...
}
- Obtenemos los valores del encabezado
Accept-Encoding
. - Obtenemos los valores del
Keep-Alive
encabezado.
@GetMapping("/demo")
fun handle(
@RequestHeader("Accept-Encoding") encoding: String,
@RequestHeader("Keep-Alive") keepAlive: Long) {
//...
}
- Obtener los valores del encabezado
Accept-Encoding
. - Obtener los valores del encabezado
Keep-Alive
.
Si el tipo de parámetro del método de destino no es String
, la conversión de tipo se aplica
automáticamente.
Si la anotación @RequestHeader
se utiliza en un argumento Map<String, String>
,
MultiValueMap<String, String>
o HttpHeaders
. El mapa se completa con todos
los encabezados valores.
@RequestHeader("Accept")
puede ser de tipo String
,
así
como String[]
o List<String>
.
@CookieValue
La anotación @CookieValue
se puede utilizar para vincular El tipo de datos HTTP valora la cookie
como un argumento de método en el controlador.
Considere una solicitud con la siguiente cookie:
JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
El siguiente ejemplo muestra cómo obtener el valor de la cookie:
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) {
//. ..
}
- Obteniendo el
JSESSIONID
valor de la cookie.
@GetMapping("/demo")
fun handle(@CookieValue("JSESSIONID") cookie: String) {
//...
}
- Obtenga el valor de la cookie
JSESSIONID
.
Si el tipo de parámetro del método de destino no es String
, la conversión de tipos se aplica
automáticamente.
@ModelAttribute
La anotación @ModelAttribute
se puede utilizar en un método argumento para acceder al atributo desde
el modelo o crear una instancia del mismo si falta. El atributo del modelo también se superpone con valores de
los parámetros de solicitud del servlet a través de HTTP, cuyos nombres coinciden con los nombres de los campos.
Esto se denomina enlace de datos y elimina la necesidad de analizar y transformar parámetros de consulta y
campos de formulario individuales. El siguiente ejemplo muestra cómo hacer esto:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) {
// method logic...
}
@PostMapping( "/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String {
// method logic...
}
La instancia Pet
anterior se obtiene de una de las siguientes maneras:
Recuperada del modelo donde pudo haber sido agregada por un método con la anotación @ModelAttribute.
Recuperado de la sesión HTTP si el atributo del modelo se especificó en la anotación
@SessionAttributes
a nivel de clase.Recibido a través de algún tipo de
Convertidor
, donde el nombre del atributo del modelo es el mismo que el nombre del valor de la solicitud, por ejemplo, un variable de ruta o parámetro de solicitud (ver. siguiente ejemplo).Creado usando el constructor predeterminado.
Creado a través del "constructor primario" con argumentos correspondientes al Solicitud de servlet de parámetros. Los nombres de los argumentos se especifican mediante la anotación
@ConstructorProperties
de las clases JavaBeans o mediante nombres de parámetros almacenados en código de bytes en tiempo de ejecución.
Una alternativa al uso de un El método con la anotación @ModelAttribute para proporcionarlo, o para llamar al
marco para crear un atributo de modelo, es usar Converter<String, T>
para proporcionar
una instancia. Esto es aplicable si el nombre del atributo del modelo es el mismo que el nombre de un valor
de consulta, como una variable de ruta o un parámetro de consulta, y hay un Converter
de
String
a el tipo de atributo del modelo. En el siguiente ejemplo, el nombre del atributo del
modelo es account
, que corresponde a la variable de ruta URI account
, y también
hay un Converter<String, Account>
que puede cargar Account
desde el almacén
de datos:
@PutMapping("/accounts/{account}")
public String save( @ModelAttribute("account") Account account) {
// ...
}
@PutMapping ("/accounts/{account}")
fun save(@ModelAttribute("account") account: Account): String {
// ...
}
Después de recibir la instancia del atributo del modelo, se aplica el enlace de datos. La clase
WebDataBinder
asigna nombres de parámetros de solicitud de servlet (parámetros de consulta y campos de formulario) a nombres
de campos de objetos de destino. Los campos coincidentes se completan después de aplicar la conversión de tipo
cuando sea necesario.
El enlace de datos puede causar errores. De forma predeterminada, se lanza una
excepción BindException
. Sin embargo, para comprobar dichos errores en un método de controlador,
puede agregar un argumento BindingResult
directamente al lado de la anotación
@ModelAttribute
, como se muestra en el siguiente ejemplo:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
- Agregando
BindingResult
junto al anotación@ModelAttribute
.
@PostMapping("/owners/{ownerId}/pets/{petId}/ edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String {
if (result.hasErrors ()) {
return "petForm"
}
// ...
}
- Agregando
BindingResult
junto a la anotación@ModelAttribute
.
En algunos casos, es posible que necesite acceder a un atributo de modelo sin enlace de datos. Para tales
casos, puede inyectar un Model
en el controlador y acceder a él directamente, o
alternativamente establecer @ModelAttribute(binding=false)
, como se muestra en el siguiente
ejemplo:
@ModelAttribute
public AccountForm setUpForm() {
return new AccountForm();
}
@ModelAttribute
public Account findAccount(@PathVariable String accountId) {
return accountRepository.findOne(accountId);
}
@PostMapping("update")
public String update(@Valid AccountForm form, BindingResult result,
@ModelAttribute(binding=false) Account account) {
// ...
}
- Configuración
@ModelAttribute(binding=false)
.
@ModelAttribute
fun setUpForm(): AccountForm {
return AccountForm()
}
@ModelAttribute
fun findAccount(@PathVariable accountId : String): Account {
return accountRepository.findOne(accountId)
}
@PostMapping("update")
fun update(@Valid form: AccountForm, result: BindingResult,
@ModelAttribute(binding = false) account: Account): String {
// ...
}
- Configuración de
@ModelAttribute(binding=false)
.
Puedes aplicar la validación automáticamente después del enlace de datos agregando
javax.validation.Valid
anotación o la anotación @Validated
de Spring. El siguiente ejemplo
muestra cómo
hacer esto:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
- Valide la instancia
Pet
.
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute( "pet") pet: Pet, result: BindingResult): String {
if (result.hasErrors()) {
return "petForm"
}
// ...
}
Tenga en cuenta que usar la anotación @ModelAttribute
es opcional (por ejemplo, para
establecer atributos). De forma predeterminada, cualquier argumento que no sea un tipo de valor simple (como se
define en BeanUtils#isSimpleProperty) y no se resuelve mediante ningún otro solucionador de
argumentos, se trata como si estuviera anotado con @ModelAttribute
.
@SessionAttributes
La @SessionAttributes
anotación se utiliza para almacenar atributos de modelo en un servlet HTTP
sesión entre solicitudes. Esta es una anotación de nivel de tipo que declara los atributos de sesión utilizados
por un controlador en particular. Normalmente, esto enumera los nombres de atributos del modelo o los tipos de
atributos del modelo que deben almacenarse de forma transparente en la sesión para solicitudes de acceso
posteriores.
El siguiente ejemplo utiliza la anotación @SessionAttributes
:
@Controller
@SessionAttributes("pet")
public class EditPetForm {
// ...
}
- Usando la anotación
@SessionAttributes
.
@Controller
@SessionAttributes("pet")
class EditPetForm {
// ...
}
- Usando el
@SessionAttributes
anotación.
En la primera solicitud, cuando se agrega un atributo de modelo llamado pet
al modelo, se promueve y
almacena automáticamente en la sesión HTTP del servlet. Permanece allí hasta que otro método de controlador
utiliza el argumento del método SessionStatus
para borrar el almacenamiento, como se muestra en el
siguiente ejemplo:
@Controller
@SessionAttributes("pet")
public class EditPetForm {
// ...
@PostMapping("/pets/{id }")
public String handle(Pet pet, BindingResult errors, SessionStatus status) {
if (errors.hasErrors) {
// ...
}
status.setComplete();
// ...
}
}
- Almacenar el valor
Pet
en la sesión del servlet. - Borrar el valor
Pet
de la sesión del servlet.
@Controller
@SessionAttributes("pet")
class EditPetForm {
// ...
@PostMapping("/pets/{id}")
fun handle(pet: Pet, errors: BindingResult, status: SessionStatus): String {
if (errors.hasErrors()) {
// ...
}
status.setComplete()
// ...
}
}
- Almacenar el valor de
Pet
en la sesión del servlet. - Borrar el
Pet
valor de la sesión del servlet.
@SessionAttribute
Si necesita acceso a atributos de sesión preexistentes que se administran globalmente ( es decir, fuera del
controlador (por ejemplo, mediante un filtro) y puede estar presente o ausente, puede usar la anotación @SessionAttribute
en el parámetro del método, como se muestra en el siguiente ejemplo:
@RequestMapping("/")
public String handle(@SessionAttribute User user) {
// ...
}
- Usando
@SessionAttribute
anotación.
@RequestMapping("/")
fun handle(@SessionAttribute user: User): String {
// ..
}
Para casos de uso que requieren agregar o eliminar atributos de sesión, considere implementar org.springframework.web.context.request.WebRequest
o javax.servlet.http.HttpSession
en un método de controlador.
Para temporalmente almacene los atributos del modelo en una sesión como parte del flujo de trabajo del
controlador, considere usar la anotación @SessionAttributes
.
@RequestAttribute
De manera similar a la anotación @SessionAttribute
, puede usar la anotación annotation @RequestAttribute
para proporcionar acceso a los atributos de solicitud existentes creados anteriormente (por ejemplo,
Filter
o servlets HandlerInterceptor
):
@GetMapping("/")
public String handle(@RequestAttribute Client client) {
// ...
}
- Usando la anotación
@RequestAttribute
.
@GetMapping("/")
fun handle(@RequestAttribute client: Client): String {
// ...
}
- Usando el
@RequestAttribute
anotación.
Atributos de redirección
De forma predeterminada, se considera que todos los atributos del modelo tienen la forma de un patrón URI en la URL de redireccionamiento. De los atributos restantes, aquellos que son tipos primitivos o colecciones o matrices de tipos primitivos se agregan automáticamente como parámetros de consulta.
Agregar atributos de tipos primitivos como parámetros de consulta puede ser el resultado deseado si la instancia
del modelo se preparó específicamente para redirección Sin embargo, en los controladores anotados, el modelo
puede contener atributos adicionales agregados con fines de visualización (por ejemplo, valores de campos
desplegables). Para evitar que dichos atributos aparezcan en la URL, un método marcado con la anotación @RequestMapping
puede declarar un argumento de tipo RedirectAttributes
y usarlo para especificar los atributos
exactos que deberían estar disponibles.
RedirectView
. Si el método realiza una redirección, se utiliza el contenido de RedirectAttributes
. En caso
contrario, se utiliza el contenido del modelo.
RequestMappingHandlerAdapter
proporciona un indicador ignoreDefaultModelOnRedirect
que
se puede usar para indicar que el contenido del Model
predeterminado nunca debe usarse en un
controlador de redireccionamiento método. En su lugar, el método del controlador debe declarar un atributo de
tipo RedirectAttributes
o, si no lo hace, no se debe pasar ningún atributo a
RedirectView
. Tanto en el espacio de nombres MVC como en la configuración de Java MVC, este
indicador se establece en false
para mantener la compatibilidad con versiones anteriores. Sin
embargo, para aplicaciones nuevas, recomendamos establecer esto en true
.
Tenga en cuenta que las variables de plantilla de URI de esta solicitud están disponibles automáticamente cuando
se expande la URL de redireccionamiento, así que agréguelas explícitamente a través de Model
o
RedirectAttributes
no es necesario. El siguiente ejemplo muestra cómo definir una redirección:
@PostMapping("/files/{path}")
public String upload(...) {
// ...
return "redirect:files/{path}";
}
@PostMapping("/files/{path}")
fun upload(... ): String {
// ...
return "redirect:files/{path}"
}
Otra forma de pasar datos al destino de redireccionamiento es utilizar atributos flash. A diferencia de otros atributos de redireccionamiento, los atributos Flash se almacenan temporalmente en la sesión HTTP (y por lo tanto no se muestran en la URL).
Atributos Flash
Los atributos Flash brindan la capacidad de almacenar atributos uno solicitud, destinada a ser utilizada en otra solicitud. En la mayoría de los casos, esto es necesario al redireccionar, por ejemplo, el patrón Post-Redirect-Get. Los atributos Flash se almacenan temporalmente antes de una redirección (generalmente en una sesión) para que estén disponibles para su solicitud después de la redirección y luego se eliminan inmediatamente.
Spring MVC tiene dos abstracciones principales para admitir atributos flash. FlashMap
se usa para
almacenar atributos flash y FlashMapManager
se usa para almacenar, recuperar y administrar
instancias de FlashMap
.
La compatibilidad con atributos flash siempre está "activada" y no requiere activación explícita. Sin embargo, si
no se utiliza, nunca creará una sesión HTTP. Con cada solicitud, hay un FlashMap
de "entrada" con
los atributos pasados desde la solicitud anterior (si corresponde) y un FlashMap
de "salida" con
los atributos que se necesitan. para ser guardado para la solicitud posterior. Se puede acceder a ambas
instancias de FlashMap
desde cualquier lugar en Spring MVC a través de métodos estáticos en RequestContextUtils
.
Los controladores anotados generalmente no necesitan trabajar directamente con FlashMap
. En
cambio, un método anotado con @RequestMapping
puede tomar un argumento de tipo
RedirectAttributes
y usarlo para agregar atributos flash para el script de redirección. Los atributos Flash agregados mediante
RedirectAttributes
se propagan automáticamente al FlashMap de "salida". Del mismo modo, después de
una redirección, los atributos de la "entrada" FlashMap
se agregan automáticamente al
Model
del controlador que sirve la URL de destino.
Multipart
Después de activar MultipartResolver
, el contenido de POST Las solicitudes con
multipart/form-data
se analizan y quedan disponibles como parámetros de solicitud normales. El siguiente ejemplo accede a un campo
de formulario normal y a un archivo cargado:
@Controller
public class FileUploadController {
@PostMapping("/form")
public String handleFormUpload(@RequestParam("name") String name,
@RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
byte[] bytes = file.getBytes();
// almacena los bytes en algún lugar
return "redirect:uploadSuccess";
}
return "redirect:uploadFailure";
}
}
@Controller
class FileUploadController {
@PostMapping("/form")
fun handleFormUpload(@RequestParam("name") name: String,
@RequestParam("file") file: MultipartFile): String {
if (!file.isEmpty) {
val bytes = file.bytes
// almacena los bytes en algún lugar
return "redirect:uploadSuccess"
}
return "redirect:uploadFailure"
}
}
Declarar el tipo de argumento como List<MultipartFile>
le permite permitir múltiples archivos
para un mismo nombre de parámetro.
Si la anotación @RequestParam
se declara como Map<String, MultipartFile>
o MultiValueMap<String,
MultipartFile>
sin un nombre de parámetro especificado en la anotación, entonces el mapa se llena con
archivos de varias partes para cada nombre de parámetro dado.
javax.servlet.http.Part
en lugar de MultipartFile
de Spring como argumento de método o tipo de valor de colección.
También puede utilizar contenido de varias partes como elemento de enlace de datos al objeto de comando. Por ejemplo, el campo de formulario y el archivo del ejemplo anterior podrían ser campos de objeto de formulario, como se muestra en el siguiente ejemplo:
class MyForm {
private String name;
private MultipartFile file;
// ...
}
@Controller
public class FileUploadController {
@PostMapping("/form")
public String handleFormUpload(MyForm form, BindingResult errors) {
if (!form.getFile().isEmpty()) {
byte[] bytes = form.getFile().getBytes();
// store the bytes somewhere
return "redirect:uploadSuccess";
}
return "redirect:uploadFailure";
}
}
class MyForm(val name: String, val file: MultipartFile, ...)
@Controller
class FileUploadController {
@PostMapping("/form")
fun handleFormUpload(form: MyForm, errors: BindingResult): String {
if (!form.file.isEmpty) {
val bytes = form.file.bytes
// almacena los bytes en algún lugar
return "redirect:uploadSuccess"
}
return "redirect:uploadFailure"
}
}
Las solicitudes de varias partes también se pueden enviar desde clientes sin navegador en un Escenario de servicio RESTful. El siguiente ejemplo muestra un archivo JSON:
POST /someUrl Content-Type: multipart/mixed --edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp Content-Disposition: form-data; name="meta-data" Content-Type: application/json; charset=UTF-8 Content-Transfer-Encoding: 8bit { "name": "value" } --edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp Content-Disposition: form-data; name="file-data"; filename="file.properties" Content-Type: text/xml Content-Transfer-Encoding: 8bit ... File Data ...
Puedes acceder a los "metadatos" con la anotación @RequestParam
como String
, pero
probablemente querrás que se deserialice desde JSON (similar a la anotación @RequestBody
).
Utilice la anotación @RequestPart
para acceder a un archivo de varias partes después de haberlo
convertido mediante HttpMessageConverter:
@PostMapping("/")
public String handle(@RequestPart("meta-data") MetaData metadata,
@RequestPart("file-data") MultipartFile file) {
// ...
}
@PostMapping("/")
fun handle(@RequestPart("meta-data") metadata: MetaData,
@RequestPart("file-data") file: MultipartFile): String {
// ...
}
Puede utilizar la anotación @RequestPart
en combinación con javax.validation.Valid
o
utilice la anotación @Validated
de Spring, que hace que se aplique la validación de Bean estándar.
De forma predeterminada, los errores de validación dan como resultado una excepción MethodArgumentNotValidException
,
que se convierte en una respuesta 400 (BAD_REQUEST). Alternativamente, puede manejar los errores de validación
localmente en el controlador mediante el argumento Errors
o BindingResult
, como se
muestra en el siguiente ejemplo:
@PostMapping("/")
public String handle(@Valid @RequestPart("meta-data") MetaData metadata,
BindingResult result) {
// ...
}
@PostMapping("/")
fun handle(@Valid @RequestPart("meta-data") metadata: MetaData,
result: BindingResult): String {
// ...
}
@RequestBody
Anotación @RequestBody
se puede utilizar para que el cuerpo de la solicitud pueda leerse y
deserializarse en un Object
mediante HttpMessageConverter
. El siguiente ejemplo
utiliza un argumento con la anotación @RequestBody
:
@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
// ...
}
@PostMapping("/accounts")
fun handle(@RequestBody account: Account) {
// ...
}
La opción Convertidores de mensajes en la configuración de MVC se puede utilizar para configurar o configurar la conversión de mensajes.
Puede utilizar la anotación @RequestBody
en combinación con javax.validation.Valid
o
@Validated
anotación de Spring, que activa la validación de frijol estándar de la aplicación. De
forma predeterminada, los errores de validación dan como resultado una excepción MethodArgumentNotValidException
,
que se convierte en una respuesta 400 (BAD_REQUEST). Alternativamente, puede manejar los errores de validación
localmente en el controlador mediante el argumento Errors
o BindingResult
, como se
muestra en el siguiente ejemplo:
@PostMapping("/accounts")
fun handle(@RequestBody account: Account) {
// ...
}
@PostMapping("/accounts")
fun handle(@Valid @RequestBody account: Account, result: BindingResult) {
// ...
}
HttpEntity
La clase HttpEntity
es más o menos idéntica en términos de uso de @RequestBody
, pero
se basa en un objeto contenedor que expone los encabezados y el cuerpo de la solicitud. El siguiente listado es
un ejemplo:
@PostMapping("/accounts")
public void handle(HttpEntity<Account> entity) {
// ...
}
@PostMapping("/accounts")
fun handle(entity: HttpEntity<Account>) {
// ...
}
@ResponseBody
El
Anotación @ResponseBody
se puede utilizar como método para serializar la devolución en el
cuerpo de la respuesta a través de HttpMessageConverter. El siguiente listado es un ejemplo:
@GetMapping("/accounts/{id}")
@ResponseBody
public Account handle() {
// ...
}
@GetMapping("/accounts/{id}")
@ResponseBody
fun handle(): Account {
// ...
}
@ResponseBody
también se admite a nivel de clase, en cuyo caso Es heredado por todos los métodos del
controlador. Este es el efecto de la anotación @RestController
, que no es más que una metaanotación
marcada con las anotaciones @Controller
y @ResponseBody.
Tú puede usar @ResponseBody
con tipos reactivos.
Puede usar la opción Convertidores de mensajes en la configuración de MVC para configurar o personalizar la conversión de mensajes.
Puede combinar métodos marcados con la anotación @ResponseBody
, con representaciones de
serialización en formato JSON.
ResponseEntity
La clase ResponseEntity
es similar a la anotación @ResponseBody
, pero con estado y
encabezados. Por ejemplo:
@GetMapping("/something")
public ResponseEntity<String> handle() {
String body = ... ;
String etag = ... ;
return ResponseEntity.ok().eTag(etag).body(body);
}
@GetMapping("/something")
fun handle(): ResponseEntity<String> {
val body = ...
val etag = ...
return ResponseEntity.ok().eTag(etag).build(body)
}
Primavera MVC admite el uso de un tipo reactivo de valor único para crear de forma asincrónica una ResponseEntity
y/o tipos reactivos de valor único y múltiple para el cuerpo. Esto permite los siguientes tipos de respuestas
asincrónicas:
ResponseEntity<Mono<T>>
oResponseEntity<Flux<T>>
informa el estado de la respuesta y los encabezados inmediatamente, mientras que el cuerpo de la respuesta se proporciona de forma asincrónica en un momento posterior. UtiliceMono
si el cuerpo consta de 0..1 valores, oFlux
si puede crear múltiples valores.Mono<ResponseEntity<T>>
proporciona los tres parámetros (estado de respuesta, encabezados y cuerpo) de forma asíncrona en un momento posterior. Esto le permite cambiar el estado de la respuesta y los encabezados según los resultados del procesamiento de solicitudes asincrónicas.
Jackson JSON
Spring proporciona soporte para Jackson JSON biblioteca.
Vistas JSON
Spring MVC proporciona soporte nativo para la serialización de vistas Vistas de serialización de
Jackson, que le permite mostrar solo un subconjunto de todos los campos de un objeto. Para usarlo con
métodos de controlador anotados con @ResponseBody
, o con la clase ResponseEntity
,
puede aprovechar la anotación @JsonView
de Jackson para activar el clase de vista de serialización,
como se muestra en el siguiente ejemplo:
@RestController
public class UserController {
@GetMapping("/user")
@JsonView(User.WithoutPasswordView.class)
public User getUser() {
return new User("eric", "7!jd#h23");
}
}
public class User {
public interface WithoutPasswordView {};
public interface WithPasswordView extends WithoutPasswordView {};
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
@JsonView(WithoutPasswordView.class)
public String getUsername() {
return this.username;
}
@JsonView(WithPasswordView.class)
public String getPassword() {
return this.password;
}
}
@RestController
class UserController {
@GetMapping("/user")
@JsonView(User.WithoutPasswordView::class)
fun getUser() = User("eric", "7!jd#h23")
}
class User(
@JsonView(WithoutPasswordView::class) val username: String,
@JsonView(WithPasswordView::class) val password: String) {
interface WithoutPasswordView
interface WithPasswordView : WithoutPasswordView
}
@JsonView
le permite usar una variedad de clases de vista,
pero solo puede especificar una por método de controlador. Si necesita activar varias vistas, puede usar una
interfaz compuesta.
Si desea haga lo anterior mediante programación, en lugar de declarar de anotación
@JsonView
ajuste el valor de retorno con MappingJacksonValue
y utilícelo para proporcionar una vista de
serialización:
@RestController
public class UserController {
@GetMapping("/user")
public MappingJacksonValue getUser() {
User user = new User("eric", "7!jd#h23");
MappingJacksonValue value = new MappingJacksonValue(user);
value.setSerializationView(User.WithoutPasswordView.class);
return value;
}
}
@RestController
class UserController {
@GetMapping("/user")
fun getUser(): MappingJacksonValue {
val value = MappingJacksonValue(User("eric", "7!jd#h23"))
value.serializationView = User.WithoutPasswordView::class.java
return value
}
}
Para los controladores que usan reconocimiento de vista, puede agregar una clase de vista de serialización al modelo, como se muestra en el siguiente ejemplo:
@Controller
public class UserController extends AbstractController {
@GetMapping("/user")
public String getUser(Model model) {
model.addAttribute("user", new User("eric", "7!jd#h23"));
model.addAttribute(JsonView.class.getName(), User.WithoutPasswordView.class);
return "userView";
}
}
import org.springframework.ui.set
@Controller
class UserController : AbstractController() {
@GetMapping("/user")
fun getUser(model: Model): String {
model["user"] = User("eric", "7!jd#h23")
model[JsonView::class.qualifiedName] = User.WithoutPasswordView::class.java
return "userView"
}
}