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

WebRequest, NativeWebRequest

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.

javax.servlet.ServletRequest, javax.servlet.ServletResponse

Destinado a seleccionar cualquier tipo específico de solicitud o respuesta, por ejemplo, ServletRequest, HttpServletRequest o MultipartRequest, MultipartHttpServletRequest de Spring.

javax.servlet.http.HttpSession

Asegura que existe una sesión. Como consecuencia, dicho argumento nunca es null. Tenga en cuenta que el acceso a la sesión no es seguro para subprocesos. Considere establecer el indicador synchronizeOnSession de la instancia RequestMappingHandlerAdapter en true si se permite que varias solicitudes accedan a la sesión simultáneamente.

javax.servlet.http.PushBuilder

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 PushBuilder inyectada puede estar vacía si el cliente no admite esta característica HTTP/2.

java.security.Principal

El usuario autenticado actual - posiblemente una clase de implementación concreta de Principal, si se conoce.

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 HttpServletRequest#getUserPrincipal. Por ejemplo, Authentication de Spring Security implementa Principal y se inyectará como tal a través de HttpServletRequest#getUserPrincipal a menos que también esté anotado con @AuthenticationPrincipal; de lo contrario, en este caso lo resolverá el solucionador personalizado de Spring Security a través de Authentication#getPrincipal.

HttpMethod

Método de solicitud HTTP.

java.util.Locale

La configuración regional actual de la solicitud, determinada por el LocaleResolver más específico disponible (esencialmente el configurado LocaleResolver o LocaleContextResolver).

java.util.TimeZone + java.time.ZoneId

La zona horaria asociada con la solicitud actual, según lo determinado por LocaleContextResolver.

java.io.InputStream, java.io.Reader

Diseñado para proporcionar acceso al cuerpo de la solicitud sin formato tal como se presenta en la API de Servlet.

java.io.OutputStream, java.io.Writer

Diseñado para proporcionar acceso al cuerpo de respuesta sin procesar expuesto por la API de Servlet.

@PathVariable

Diseñado para proporcionar acceso a variables de patrón URI.

@MatrixVariable

Diseñado para proporcionar acceso a pares "nombre-valor" en segmentos de ruta URI.

@RequestParam

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 @RequestParam es opcional para valores de parámetros simples. Consulte "Cualquier otro argumento" al final de esta tabla.

@RequestHeader

Diseñado para proporcionar acceso a los encabezados de solicitud. Los valores del encabezado se convierten al tipo declarado de argumento del método.

@CookieValue

Diseñado para proporcionar acceso a las cookies . Los valores de las cookies se convierten al tipo de argumento del método declarado.

@RequestBody

Para acceder al cuerpo de la solicitud HTTP. El contenido del cuerpo se convierte al tipo de argumento del método declarado mediante implementaciones HttpMessageConverter.

HttpEntity<B>

Diseñado para proporcionar acceso a los encabezados y al cuerpo de la solicitud. El cuerpo se convierte usando HttpMessageConverter.

@RequestPart

Diseñado para proporcionar acceso a un componente en una solicitud multipart/form-data mediante la conversión del cuerpo de ese componente usando HttpMessageConverter.

java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMap

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.

RedirectAttributes

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.

@ModelAttribute

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 @ModelAttribute es opcional (por ejemplo, para establecer sus atributos). Consulte "Cualquier otro argumento" al final de esta tabla.

Errores, BindingResult

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 @ModelAttribute) o argumento errores de validación con anotaciones @RequestBody o @RequestPart. El argumento Errors o BindingResult debe declararse inmediatamente después del argumento del método validado.

SessionStatus + nivel de clase @SessionAttributes

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á @SessionAttributes en el nivel de clase.

UriComponentsBuilder

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.

@SessionAttribute

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 @SessionAttributes a nivel de clase.

@RequestAttribute

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 @RequestParam. De lo contrario, se resuelve en @ModelAttribute.

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

@ResponseBody

El valor de retorno se convierte a través de la implementación HttpMessageConverter y se escribe en la respuesta.

HttpEntity<B>, ResponseEntity<B>

Especificación del valor de retorno la respuesta completa (incluidos los encabezados y el cuerpo HTTP), convertida a través de la implementación HttpMessageConverter y escrita en la respuesta.

HttpHeaders

Diseñado para devolver una respuesta con encabezados y sin cuerpo.

String

El nombre de la vista que las implementaciones de ViewResolver reconocerán y utilizarán junto con la modelo implícito: definido a través de objetos de comando y métodos anotados @ModelAttribute. El método controlador también puede personalizar el modelo mediante programación declarando un argumento Model.

View

Una instancia de View destinada a ser representada junto con un modelo implícito, definido a través de objetos y métodos de comando con @ModelAttribute anotación. Un método de controlador también puede personalizar un modelo mediante programación declarando un argumento Model.

java.util.Map, org.springframework.ui.Model

Atributos agregados al modelo implícito, con el nombre de la vista definido implícitamente mediante RequestToViewNameTranslator.

@ModelAttribute

Atributo, agregado al modelo cuyo nombre de vista se especifica implícitamente mediante RequestToViewNameTranslator.

Tenga en cuenta que la anotación @ModelAttribute es opcional. Consulte la sección "Cualquier otro valor de retorno" al final de esta tabla.

ModelAndView objeto

Los atributos de vista y modelo a utilizar y, si es necesario, el estado de la respuesta.

void

Se considera que un método con un tipo de retorno void (o un valor de retorno null) habrá procesado completamente la respuesta si también tiene ServletResponse, el argumento OutputStream o la anotación @ResponseStatus. Lo mismo ocurre si el controlador ha realizado una verificación positiva de la marca de tiempo ETag o lastModified.

Si ninguno de los valores anteriores es verdadero, el tipo de retorno es void y también puede indicar "sin cuerpo de respuesta" para controladores REST o una opción de nombre de vista predeterminada para controladores HTML.

DeferredResult<V>

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.

Invocable<V>

Produce cualquiera de los valores devueltos anteriormente de forma asincrónica en un hilo administrado por Spring MVC.

ListenableFuture<V>, java.util.concurrent .CompletionStage<V>, java.util.concurrent.CompletableFuture<V>

Una alternativa más conveniente a DeferredResult (por ejemplo, si el servicio principal devuelve uno de ellos).

ResponseBodyEmitter, SseEmitter

Genera asincrónicamente un flujo de objetos para escribir en la respuesta usando HttpMessageConverter implementaciones. También se admite como cuerpo para ResponseEntity.

StreamingResponseBody

Escritura asincrónica en OutputStream de la respuesta. También se admite como cuerpo para ResponseEntity.

Tipos reactivos: Reactor, RxJava u otros a través de ReactiveAdapterRegistry

Alternativa a DeferredResult con secuencias de valores múltiples (por ejemplo, Flux, Observable), recopilados en List.

En escenarios de transmisión (por ejemplo, text/event-stream, application/json+stream ) en su lugar, se utilizan SseEmitter y ResponseBodyEmitter, donde la E/S de bloqueo ServletOutputStream se ejecuta en un subproceso administrado por Spring MVC. y la devolución de llamada se produce al completar cada registro.

Cualquier otro valor de retorno

Cualquiera valor de retorno que no coincide con ninguno de los valores anteriores en esta tabla y es un String o void, tratado como el nombre de la vista (la selección predeterminada del nombre de la vista a través de Se aplica RequestToViewNameTranslator) si no es un tipo simple como se define en BeanUtils#isSimpleProperty. Los valores que son tipos simples permanecen sin resolver.

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:

Java

// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
    // petId == 42
    // q == 11
}
Kotlin

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

Java

// 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
}
Kotlin

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

Java

// GET /pets/42
@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {
    // q == 1
}
Kotlin

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

Java

// 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]
}
Kotlin

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

Java

@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";
    }
    // ...
}
  1. Usando la anotación @RequestParam para enlaces petId.
Kotlin

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"
    }
    // ...
}
  1. Usar la anotación @RequestParam para vincular el petId.

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:

Java

@GetMapping("/demo")
public void handle(
        @RequestHeader(" Accept-Encoding") String encoding, 
        @RequestHeader("Keep-Alive") long keepAlive) { 
    //...
}
  1. Obtenemos los valores del encabezado Accept-Encoding.
  2. Obtenemos los valores del Keep-Alive encabezado.
Kotlin

@GetMapping("/demo")
fun handle(
        @RequestHeader("Accept-Encoding") encoding: String, 
        @RequestHeader("Keep-Alive") keepAlive: Long) { 
    //...
}
  1. Obtener los valores del encabezado Accept-Encoding.
  2. 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.

Hay soporte integrado para convertir una cadena separada por comas en una matriz o colección de cadenas u otros tipos conocidos por la conversión de tipos. sistema . Por ejemplo, un parámetro de método anotado con @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:

Java
 
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) { 
    //. ..
}
  1. Obteniendo el JSESSIONID valor de la cookie.
Kotlin

@GetMapping("/demo")
fun handle(@CookieValue("JSESSIONID") cookie: String) { 
    //...
}
  1. 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:

Java

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) {
    // method logic...
}
Kotlin

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

Java

@PutMapping("/accounts/{account}")
public String save( @ModelAttribute("account") Account account) {
    // ...
}
Kotlin

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

Java

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { 
    if (result.hasErrors()) {
        return "petForm";
    }
    // ...
}
  1. Agregando BindingResult junto al anotación @ModelAttribute.
Kotlin

@PostMapping("/owners/{ownerId}/pets/{petId}/ edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { 
    if (result.hasErrors ()) {
        return "petForm"
    }
    // ...
}
  1. 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:

Java

@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) { 
    // ...
}
  1. Configuración @ModelAttribute(binding=false).
Kotlin

@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 { 
    // ...
}
  1. 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:

Java

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) { 
    if (result.hasErrors()) {
        return "petForm";
    }
    // ...
}
  1. Valide la instancia Pet.
Kotlin

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

Java

@Controller
@SessionAttributes("pet") 
public class EditPetForm {
    // ...
}
  1. Usando la anotación @SessionAttributes.
Kotlin

@Controller
@SessionAttributes("pet") 
class EditPetForm {
    // ...
}
  1. 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:

Java

@Controller
@SessionAttributes("pet") 
public class EditPetForm {
    // ...
    @PostMapping("/pets/{id }")
    public String handle(Pet pet, BindingResult errors, SessionStatus status) {
        if (errors.hasErrors) {
            // ...
        }
        status.setComplete(); 
        // ...
    }
}
  1. Almacenar el valor Pet en la sesión del servlet.
  2. Borrar el valor Pet de la sesión del servlet.
Kotlin

@Controller
@SessionAttributes("pet") 
class EditPetForm {
    // ...
    @PostMapping("/pets/{id}")
    fun handle(pet: Pet, errors: BindingResult, status: SessionStatus): String {
        if (errors.hasErrors()) {
            // ...
        }
        status.setComplete() 
        // ...
    }
}
  1. Almacenar el valor de Pet en la sesión del servlet.
  2. 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:

Java

@RequestMapping("/")
public String handle(@SessionAttribute User user) { 
    // ...
}
  1. Usando @SessionAttribute anotación.
Kotlin

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

Java

@GetMapping("/")
public String handle(@RequestAttribute Client client) { 
    // ...
}
  1. Usando la anotación @RequestAttribute.
Kotlin

@GetMapping("/")
fun handle(@RequestAttribute client: Client): String { 
    // ...
}
  1. 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:

Java

@PostMapping("/files/{path}")
public String upload(...) {
    // ...
    return "redirect:files/{path}";
}
Kotlin

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

Asignación de solicitudes a atributos flash

El concepto de atributos flash existe en muchos otros marcos web y, como resulta, a veces propenso a problemas de concurrencia. Esto se debe a que los atributos flash, por definición, deben almacenarse hasta la siguiente solicitud. Sin embargo, es posible que la "siguiente" solicitud en sí no provenga del destinatario previsto, sino de otra solicitud asincrónica (como una solicitud de sondeo o asignación de recursos), en cuyo caso los atributos flash se eliminarán demasiado pronto.

Para reducir la probabilidad de que se produzcan problemas como estos, RedirectView "etiqueta" automáticamente las instancias de FlashMap con la ruta y los parámetros de consulta de la URL de redireccionamiento de destino. A su vez, FlashMapManager de forma predeterminada compara esta información con las solicitudes entrantes cuando se busca un FlashMap de "entrada".

Esto no elimina por completo la posibilidad de El problema con el paralelismo, pero lo reduce significativamente cuando se utiliza información que ya está disponible en la URL de redireccionamiento. Por lo tanto, recomendamos utilizar atributos flash principalmente para escenarios de redirección.

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:

Java

@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";
    }
}
Kotlin

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

Al analizar varias partes en Servlet 3.0, también puede declarar 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:

Java

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";
    }
}
Kotlin

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:

Java

@PostMapping("/")
public String handle(@RequestPart("meta-data") MetaData metadata,
        @RequestPart("file-data") MultipartFile file) {
    // ...
}
Kotlin

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

Java

@PostMapping("/")
public String handle(@Valid @RequestPart("meta-data") MetaData metadata,
        BindingResult result) {
    // ...
}
Kotlin

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

Java

@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
    // ...
}
Kotlin

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

Java

@PostMapping("/accounts")
fun handle(@RequestBody account: Account) {
    // ...
}
Kotlin

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

Java

@PostMapping("/accounts")
public void handle(HttpEntity<Account> entity) {
    // ...
}
Kotlin

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

Java

@GetMapping("/accounts/{id}")
@ResponseBody
public Account handle() {
    // ...
}
Kotlin

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

Java

@GetMapping("/something")
public ResponseEntity<String> handle() {
    String body = ... ;
    String etag = ... ;
    return ResponseEntity.ok().eTag(etag).body(body);
}
Kotlin

@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>> o ResponseEntity<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. Utilice Mono si el cuerpo consta de 0..1 valores, o Flux 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:

Java

@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;
    }
}
Kotlin

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

Java

@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;
    }
}
Kotlin

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

Java

@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";
    }
}
Kotlin

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"
    }
}