Spring Framework tiene integración incorporada para usar Spring MVC con JSP y JSTL.

View Resolvers

Al desarrollar JSP, es común declarar un InternalResourceViewResolver bean.

InternalResourceViewResolver se puede utilizar para enviar a cualquier recurso de servlet, pero especialmente a JSP. Como práctica recomendada, recomendamos encarecidamente colocar los archivos JSP en un directorio bajo el directorio "WEB-INF" para que los clientes no puedan acceder a ellos directamente.


<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>

JSP frente a JSTL

Cuando utilice la biblioteca de etiquetas estándar JSP (JSTL), debe utilizar un clase de vista especial JstlView, ya que JSTL requiere cierta preparación para que funcionen cosas como las funciones I18N.

Biblioteca de etiquetas JSP para Spring

Spring proporciona enlace del parámetro de solicitud comandos de datos a objetos como se describe en capítulos anteriores. Para facilitar el desarrollo de páginas JSP junto con estas funciones de enlace de datos, Spring proporciona varias etiquetas que facilitan aún más las cosas. Todas las etiquetas Spring tienen funciones de escape HTML que se pueden habilitar o deshabilitar para escapar de caracteres.

El descriptor de la biblioteca de etiquetas (TLD) spring.tld se incluye en spring-webmvc.jar. Para obtener información completa sobre etiquetas individuales, consulte Referencia de API o consulte la descripción de la biblioteca de etiquetas.

Biblioteca de etiquetas de formulario Spring

Desde la versión 2.0, Spring proporciona un conjunto completo de etiquetas que admiten el enlace de datos para trabajar con elementos de formulario cuando se utiliza JSP y Spring Web MVC. Cada etiqueta proporciona soporte para un conjunto de atributos de la etiqueta HTML correspondiente, lo que hace que el uso de las etiquetas sea familiar e intuitivo. El HTML generado por las etiquetas cumple con los estándares HTML 4.01/XHTML 1.0.

A diferencia de otras bibliotecas de etiquetas de formulario/entrada, la biblioteca de etiquetas de formulario para Spring está integrada con Spring Web MVC, lo que permite que las etiquetas tengan acceso a comandos. datos de objeto y de referencia con los que trabaja su responsable del tratamiento. Como se muestra en los siguientes ejemplos, las etiquetas de formulario hacen que los JSP sean más fáciles de desarrollar, leer y mantener.

Recorreremos las etiquetas de formulario y veremos un ejemplo de cómo usar cada etiqueta. Hemos incluido fragmentos HTML generados donde ciertas etiquetas requieren comentarios adicionales.

Configuración

Biblioteca de etiquetas de formulario incluida desde spring-webmvc.jar. El descriptor de la biblioteca se llama spring-form.tld.

Para usar etiquetas de esta biblioteca, agregue la siguiente directiva en la parte superior de su página JSP:

<%@ taglib prefix="form" uri= "http://www.springframework.org/tags/form" %>

donde form es el prefijo de el nombre de la etiqueta que desea utilizar para las etiquetas de esta biblioteca.

Etiqueta de formulario

Esta etiqueta representa el "formulario" HTML "elemento y expone la ruta de enlace a etiquetas internas para el anclaje. Coloca el objeto de comando en un PageContext para que se pueda acceder al objeto de comando mediante etiquetas internas. Todas las demás etiquetas de esta biblioteca son subetiquetas de la etiqueta form.

Supongamos que tenemos un objeto de dominio llamado User. Es un JavaBean con propiedades como firstName y lastName. Podemos usarlo como objeto de formulario base de nuestro controlador de formulario, que devuelve un archivo form.jsp. El siguiente ejemplo muestra cómo podría verse form.jsp:


<form:form>
    <table>
        <tr>
            <td>First Name:</td>
            <td><form:input path="firstName"/></td>
        </tr>
        <tr>
            <td>Last Name:</td>
            <td><form:input path="lastName"/></td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="Save Changes"/>
            </td>
        </tr>
    </table>
</form:form>

Los valores firstName y lastName se recuperan de el objeto de comando colocado en PageContext por el controlador de página. Continúe leyendo para ver ejemplos más avanzados del uso de etiquetas internas con la etiqueta form.

La siguiente lista muestra el HTML generado, que parece un formulario estándar:


<form method="POST">
    <table>
        <tr>
            <td>First Name:</td>
            <td><input name="firstName" type="text" value="Harry"/></td>
        </tr>
        <tr>
            <td>Last Name:</td>
            <td><input name="lastName" type="text" value="Potter"/></td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="Save Changes"/>
            </td>
        </tr>
    </table>
</form>

El JSP anterior supone que el nombre de la variable del objeto de formulario subyacente es command. Si colocó el objeto de formulario subyacente en el modelo con un nombre diferente (definitivamente la mejor opción), puede vincular el formulario a una variable con nombre, como se muestra en el siguiente ejemplo:


<form:form modelAttribute="user">
    <table>
        <tr>
            <td>First Name:</td>
            <td><form:input path="firstName"/></td>
        </tr>
        <tr>
            <td>Last Name:</td>
            <td><form:input path="lastName"/></td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="Save Changes"/>
            </td>
        </tr>
    </table>
</form:form>

La etiqueta input

Esta etiqueta representa el elemento HTML input con un valor enlazado y type='text' de forma predeterminada. También puede utilizar tipos específicos de HTML5 como email, tel, date y otros.

La etiqueta checkbox

Esta etiqueta representa una etiqueta HTML input con type establecido en checkbox.

Supongamos que nuestro User tiene parámetros de usuario personales, como una suscripción al boletín y una lista de pasatiempos. El siguiente ejemplo muestra la clase Preferences:

Java

public class Preferences {
    private boolean receiveNewsletter;
    private String[] interests;
    private String favouriteWord;
    public boolean isReceiveNewsletter() {
        return receiveNewsletter;
    }
    public void setReceiveNewsletter(boolean receiveNewsletter) {
        this.receiveNewsletter = receiveNewsletter;
    }
    public String[] getInterests() {
        return interests;
    }
    public void setInterests(String[] interests) {
        this.interests = interests;
    }
    public String getFavouriteWord() {
        return favouriteWord;
    }
    public void setFavouriteWord(String favouriteWord) {
        this.favouriteWord = favouriteWord;
    }
}
Kotlin

class Preferences(
        var receiveNewsletter: Boolean,
        var interests: StringArray,
        var favouriteWord: String
)

El archivo form.jsp correspondiente podría verse así:


<form:form>
    <table>
        <tr>
            <td>Subscribe to newsletter?:</td>
            <%-- Approach 1: The property is of type java.lang.Boolean --%>
            <td><form:checkbox path="preferences.receiveNewsletter"/></td>
        </tr>
        <tr>
            <td>Interests:</td>
             <%-- Approach 2: The property is an array or has type java.util.Collection --%>
            <td>
                Quidditch: <form:checkbox path="preferences.interests" value="Quidditch"/>
                Herbology: <form:checkbox path="preferences.interests" value="Herbology"/>
                Defence Against the Dark Arts: <form:checkbox path="preferences.interests" value="Defence Against the Dark Arts"/>
            </td>
        </tr>
        <tr>
            <td>Favourite Word:</td>
             <%-- Approach 3: The property is of type java.lang.Object --%>
            <td>
                Magic: <form:checkbox path="preferences.favouriteWord" value="Magic"/>
            </td>
        </tr>
    </table>
</form:form>

Existen tres enfoques para la etiqueta checkbox que deberían satisfacer todas sus necesidades de casillas de verificación.

  • Enfoque uno: si el valor asociado es de tipo java.lang.Boolean, input(checkbox) se marca como checked si el valor asociado es true. El atributo value corresponde al valor permitido de la propiedad de valor setValue(Object).

  • Enfoque dos: si el valor asociado es de tipo array o java.util.Collection, input(checkbox) se marca como checked si el valor configurado es setValue( Object) y está presente en la Collection asociada.

  • Enfoque tres: en caso de cualquier otro tipo de valor asociado input(checkbox) se marca como checked si el setValue(Object) configurado es igual al valor asociado.

Tenga en cuenta que, independientemente del enfoque, se genera la misma estructura HTML. El siguiente fragmento de HTML define varias casillas de verificación:


<tr>
    <td>Interests:</td>
    <td>
        Quidditch: <input name="preferences.interests" type="checkbox" value="Quidditch"/>
        <input type="hidden" value="1" name="_preferences.interests"/>
        Herbology: <input name="preferences.interests" type="checkbox" value="Herbology"/>
        <input type="hidden" value="1" name="_preferences.interests"/>
        Defence Against the Dark Arts: <input name="preferences.interests" type="checkbox" value="Defence Against the Dark Arts"/>
        <input type="hidden" value="1" name="_preferences.interests"/>
    </td>
</tr>

Es posible que no esperes ver un campo oculto adicional después de cada casilla de verificación. Si una casilla de verificación en una página HTML no está marcada, su valor no se envía al servidor como parte de los parámetros de solicitud HTTP después de enviar el formulario, por lo que se necesita una solución alternativa para esta característica HTML para que funcione el enlace de datos del formulario Spring. . La etiqueta checkbox sigue la convención existente de Spring de incluir un parámetro oculto con el prefijo de guión bajo (_) para cada casilla de verificación. Al hacer esto, efectivamente le estás diciendo a Spring que "la casilla de verificación estaba visible en el formulario y quiero que el objeto al que están vinculados los datos del formulario refleje el estado de la casilla de verificación, sin importar qué".

La etiqueta casillas de verificación

Esta etiqueta representa múltiples etiquetas HTML input con tipo establecido en casilla de checkbox.

Esta sección se basa en el ejemplo de la sección anterior sobre la etiqueta checkbox. A veces es preferible no enumerar todos los posibles pasatiempos en una página JSP. Es mejor especificar una lista de opciones disponibles en tiempo de ejecución y pasarla a la etiqueta. Este es el propósito de la etiqueta checkboxes. Puede pasar un Array, List o Map que contenga las opciones disponibles en la propiedad items. Normalmente, la propiedad vinculada es una colección, por lo que puede contener varios valores seleccionados por el usuario. El siguiente ejemplo muestra una página JSP que utiliza esta etiqueta:


<form:form>
    <table>
        <tr>
            <td>Interests:</td>
            <td>
                <%-- La propiedad es una matriz o es de tipo java.util.Collection --%>
                <form:checkboxes path="preferences.interests" items="${interestList}"/>
            </td>
        </tr>
    </table>
</form:form>

Este ejemplo supone que interestList es una List , disponible como un atributo de modelo que contiene cadenas de valores para seleccionar. Si usa Map, la clave de la entrada del Mapa se usa como valor y el valor de la entrada del Mapa se usa como etiqueta para mostrar. También puede usar un objeto personalizado en el que puede especificar nombres de propiedad para el valor usando itemValue y la etiqueta usando itemLabel.

El etiqueta botón de radio

Esta etiqueta representa un elemento HTML input con type establecido en radio.

Un uso típico implica múltiples instancias de etiquetas vinculadas a la misma propiedad pero con diferentes valores, como se muestra en el siguiente ejemplo:


<tr>
    <td>Sex:</td>
    <td>
        Male: <form:radiobutton path="sex" value="M"/> <br/>
        Female: <form:radiobutton path="sex" value="F"/>
    </td>
</tr>

La etiqueta radiobuttons

Esta etiqueta representa varios elementos HTML input con type establecido en radio.

Al igual que con la etiqueta checkboxes, puedes pasar la etiqueta disponible. opciones como una variable de tiempo de ejecución. Para hacer esto, puede usar la etiqueta radiobuttons. Pasa un Array, List o Map que contiene las opciones disponibles en la propiedad items. Si usa Mapa, la clave de la entrada del Mapa se usa como valor y el valor de la entrada del Mapa se usa como etiqueta para mostrar. También puede usar un objeto personalizado donde puede especificar nombres de propiedad para un valor usando itemValue y una etiqueta usando itemLabel, como se muestra en el siguiente ejemplo:


<tr>
    <td>Sex:</td>
    <td><form:radiobuttons path="sex" items="${sexOptions}"/></td>
</tr>

La etiqueta contraseña

Esta etiqueta representa la entrada HTML input con tipo establecido en password, con valor vinculado.


<tr>
    <td>Password:</td>
    <td>
        <form:password path="password"/>
    </td>
</tr>

Tenga en cuenta que, de forma predeterminada, no se muestra el valor de la contraseña. Si desea que se muestre el valor de la contraseña, puede establecer el valor del atributo showPassword en true, como se muestra en el siguiente ejemplo:


<tr>
    <td>Password:</td>
    <td>
        <form:password path="password" value="^76525bvHGq" showPassword="true"/>
    </td>
</tr>

La etiqueta select

Esta etiqueta representa el elemento HTML "select" . Admite el enlace de datos a la opción seleccionada, así como el uso de etiquetas anidadas option y options.

Supongamos que el User hay una lista de habilidades. El HTML correspondiente podría verse así:


<tr>
    <td>Skills:</td>
    <td><form:select path="skills" items="${skills}"/></td>
</tr>

Si User tiene habilidades en herbología, entonces la fuente HTML para la cadena "Habilidades" podría verse así esto:


<tr>
    <td>Skills:</td>
    <td>
        <select name="skills" multiple="true">
            <option value="Potions">Potions</option>
            <option value="Herbology" selected="selected">Herbology</option>
            <option value="Quidditch">Quidditch</option>
        </select>
    </td>
</tr>

La etiqueta de

opción

Esta etiqueta representa la HTML elementooption. Establece selected según el valor asociado. El siguiente HTML muestra un resultado típico:

 
<tr>
    <td>House:</td>
    <td>
        <form:select path="house">
            <form:option value="Gryffindor"/>
            <form:option value="Hufflepuff"/>
            <form:option value="Ravenclaw"/>
            <form:option value="Slytherin"/>
        </form:select>
    </td>
</tr>

Si la casa de User está en Gryffindor, entonces la fuente HTML para la cadena "Casa" se verá así:


<tr>
    <td>House:</td>
    <td>
        <select name="house">
            <option value="Gryffindor" selected="selected">Gryffindor</option> 
            <option value="Hufflepuff">Hufflepuff</option>
            <option value="Ravenclaw">Ravenclaw</option>
            <option value="Slytherin">Slytherin</option>
        </select>
    </td>
</tr>
  1. Tenga en cuenta la adición del atributo selected

La etiqueta options

Esta etiqueta muestra una lista de elementos HTML option. Establece el atributo selected en función del valor asociado. El siguiente HTML muestra un resultado típico:

 
<tr>
    <td>Country:</td>
    <td>
        <form:select path="country">
            <form:option value="-" label="--Please Select"/>
            <form:options items="${countryList}" itemValue="code" itemLabel="name"/>
        </form:select>
    </td>
</tr>

Si User viviera en el Reino Unido, la fuente HTML para la cadena "País" se vería así esto:


<tr>
    <td>Country:</td>
    <td>
        <select name="country">
            <option value="-">--Please Select</option>
            <option value="AT">Austria</option>
            <option value="UK" selected="selected">United Kingdom</option> 
            <option value="US">United States</option>
        </select>
    </td>
</tr>
  1. Tenga en cuenta la adición del atributo selected .

Como se muestra en el ejemplo anterior, combinar la etiqueta option con la etiqueta options produce el mismo HTML estándar, pero le permite para especificar explícitamente el valor en JSP, que está destinado únicamente a mostrarse (donde pertenece), como en el caso de la cadena predeterminada en el ejemplo: "-- Seleccione".

El items generalmente se completan con una colección o matriz de objetos de elementos de datos. itemValue y itemLabel se refieren a las propiedades de bean de estos objetos de elemento, si se especifican. De lo contrario, los propios objetos del elemento se convierten en cadenas. Alternativamente, puede especificar un Map de elementos, en cuyo caso las claves del Mapa se interpretarán como valores de opción y los valores del Mapa corresponderán a etiquetas de opción. Si también se especifican itemValue o itemLabel (o ambos), entonces la propiedad de valor del elemento de datos se aplicará a la clave Mapa y la propiedad de etiqueta del elemento de datos se aplicará a el valor del Mapa.

La etiqueta textarea

Esta etiqueta representa el elemento HTML textarea. El siguiente HTML muestra el resultado típico:


<tr>
    <td>Notes:</td>
    <td><form:textarea path="notes" rows="3" cols="20"/></td>
    <td><form:errors path="notes"/></td>
</tr>

La etiqueta hidden

Esta etiqueta representa la entrada HTML input con type establecida en hidden, con un valor vinculado. Para enviar un valor oculto independiente, utilice la etiqueta HTML input con type establecido en hidden. El siguiente HTML muestra el resultado típico:

<form:hidden path="house"/>

Si decide pasar el valor de house como oculto, entonces el HTML se verá así:

 <input nombre="casa" tipo="hidden" valor="Gryffindor"/>

errores tag

Esta etiqueta muestra errores de campo en el elemento HTML span. Proporciona acceso a los errores generados en su controlador o a los errores generados por cualquier validador asociado con su controlador.

Supongamos que queremos mostrar todos los mensajes de error para los campos firstName y lastName después de enviar el formulario. Tenemos un validador para instancias de la clase User llamado UserValidator, como se muestra en el siguiente ejemplo:

Java

public class UserValidator implements Validator {
    public boolean supports(Class candidate) {
        return User.class.isAssignableFrom(candidate);
    }
    public void validate(Object obj, Errors errors) {
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "required", "Field is required.");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "required", "Field is required.");
    }
}
Kotlin

class UserValidator : Validator {
    override fun supports(candidate: Class<*>): Boolean {
        return User::class.java.isAssignableFrom(candidate)
    }
    override fun validate(obj: Any, errors: Errors) {
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "required", "Field is required.")
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "required", "Field is required.")
    }
}

form.jsp podría verse así:


<form:form>
    <table>
        <tr>
            <td>First Name:</td>
            <td><form:input path="firstName"/></td>
            <%-- Show errors for firstName field --%>
            <td><form:errors path="firstName"/></td>
        </tr>
        <tr>
            <td>Last Name:</td>
            <td><form:input path="lastName"/></td>
            <%-- Show errors for lastName field --%>
            <td><form:errors path="lastName"/></td>
        </tr>
        <tr>
            <td colspan="3">
                <input type="submit" value="Save Changes"/>
            </td>
        </tr>
    </table>
</form:form>

Si enviamos un formulario con valores vacíos en firstName y lastName código de campos>, entonces el HTML se verá así:


<form method="POST">
    <table>
        <tr>
            <td>First Name:</td>
            <td><input name="firstName" type="text" value=""/></td>
            <%-- Associated errors to firstName field displayed --%>
            <td><span name="firstName.errors">Field is required.</span></td>
        </tr>
        <tr>
            <td>Last Name:</td>
            <td><input name="lastName" type="text" value=""/></td>
            <%-- Associated errors to lastName field displayed --%>
            <td><span name="lastName.errors">Field is required.</span></td>
        </tr>
        <tr>
            <td colspan="3">
                <input type="submit" value="Save Changes"/>
            </td>
        </tr>
    </table>
</form>

¿Qué sucede si queremos mostrar la lista completa de errores de una página determinada? El siguiente ejemplo muestra que la etiqueta errors también admite algunas funciones de sustitución básicas.

  • path="*": Salidas a mostrar todos los errores.

  • path="lastName": muestra todos los errores asociados con el campo lastName.

  • Si se omite path, solo se imprimen los errores de objeto.

En el siguiente ejemplo, en La parte superior de la página muestra una lista de errores y junto a los campos hay errores específicos de cada campo:


<form:form>
    <form:errors path="*" cssClass="errorBox"/>
    <table>
        <tr>
            <td>First Name:</td>
            <td><form:input path="firstName"/></td>
            <td><form:errors path="firstName"/></td>
        </tr>
        <tr>
            <td>Last Name:</td>
            <td><form:input path="lastName"/></td>
            <td><form:errors path="lastName"/></td>
        </tr>
        <tr>
            <td colspan="3">
                <input type="submit" value="Save Changes"/>
            </td>
        </tr>
    </table>
</form:form>

HTML se verá así:


<form method="POST">
    <span name="*.errors" class="errorBox">Field is required.<br/>Field is required.</span>
    <table>
        <tr>
            <td>First Name:</td>
            <td><input name="firstName" type="text" value=""/></td>
            <td><span name="firstName.errors">Field is required.</span></td>
        </tr>
        <tr>
            <td>Last Name:</td>
            <td><input name="lastName" type="text" value=""/></td>
            <td><span name="lastName.errors">Field is required.</span></td>
        </tr>
        <tr>
            <td colspan="3">
                <input type="submit" value="Save Changes"/>
            </td>
        </tr>
    </table>
</form>

El descriptor de biblioteca de etiquetas (TLD) spring-form.tld está incluido en spring-webmvc.jar. Para obtener información completa sobre etiquetas individuales, consulte Referencia de API o consulte la descripción de la biblioteca de etiquetas.

Traducción de métodos HTTP

El principio clave REST es el uso de una "interfaz unificada". Esto significa que todos los recursos (URL) se pueden manipular utilizando los mismos cuatro métodos HTTP: GET, PUT, POST y DELETE. Para cada método, la especificación HTTP define la semántica exacta. Por ejemplo, GET siempre debe ser una operación segura, lo que significa que no tiene efectos secundarios, y PUT o DELETE deben ser idempotentes, lo que significa que puedes repetir estas operaciones una y otra vez, pero el resultado final debe ser el mismo. Aunque HTTP define estos cuatro métodos, HTML sólo admite dos de ellos: GET y POST. Afortunadamente, existen dos posibles soluciones: puede usar JavaScript para realizar PUT o DELETE, o puede realizar un POST con un método "real" como parámetro adicional (muy parecido a un campo de entrada oculto en un formulario HTML). El HiddenHttpMethodFilter de Spring aprovecha este último truco. Este filtro es un filtro de servlet normal, por lo que se puede utilizar junto con cualquier marco web (no solo Spring MVC). Agregue este filtro a su web.xml y una POST con un parámetro method oculto se convertirá en una solicitud para el método HTTP correspondiente.

Para convertir métodos HTTP, el la etiqueta de formulario Spring MVC se ha actualizado para brindar soporte para configurar el método HTTP. Por ejemplo, el siguiente fragmento está tomado del ejemplo de Pet Clinic:


<form:form method="delete">
    <p class="submit"><input type="submit" value="Delete Pet"/></p>
</form:form>

El ejemplo anterior ejecuta el método HTTP POST, mientras que el método DELETE "real" está oculto detrás de un parámetro de solicitud. Lo recoge HiddenHttpMethodFilter, que se define en web.xml, como se muestra en el siguiente ejemplo:


<filter>
    <filter-name>httpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>httpMethodFilter</filter-name>
    <servlet-name>petclinic</servlet-name>
</filter-mapping>

El siguiente ejemplo muestra el método correspondiente con la anotación @Controller:

Java
@RequestMapping(method =
        RequestMethod.DELETE) public String eliminarPet(@PathVariable intownerId, @PathVariable int petId) {
        this.clinic.deletePet(petId); devolver "redireccionamiento:/propietarios/" + ID de propietario; }
Kotlin

@RequestMapping(method = RequestMethod.DELETE)
public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
    this.clinic.deletePet(petId);
    return "redirect:/owners/" + ownerId;
}

Etiquetas HTML5

La biblioteca de etiquetas de formulario Spring permite la entrada de atributos dinámicos, lo que significa que puede ingresar cualquier atributo específico de HTML5.

La etiqueta de formulario input admite la entrada de atributos de tipo. diferente de text. Esto le permite visualizar nuevos tipos de entrada específicos de HTML5, como email, date, range y otros. Tenga en cuenta que ingresar type='text' no es obligatorio porque text es el tipo predeterminado.