[JAVA] Spring 4.2 vs 4.3: Différence de valeur de liaison au type de collection lors de la soumission case à cocher vide

Cette fois, le chèque généré à l'aide du composant qui prend en charge l'implémentation View fournie par Spring (bibliothèque de balises JSP, macro Freemarker, etc.) et le composant de coopération réalisé par le tiers (Dialect for Spring coopération de Thymeleaf, etc.) Lors de la soumission d'un formulaire avec la boîte vide (= non sélectionnée), la valeur définie pour le type Collection ( List, Set, etc.) défini dans l'objet de formulaire change entre Spring 4.2 et Spring 4.3. J'en parlerai.

Note:

Au fait ... Si vous utilisez un tableau au lieu du type Collection, le comportement ne changera pas. (Un tableau d'éléments vides est défini)

Quelle est la différence entre Spring 4.2 et Spring 4.3?

Soudainement de la conclusion ... Dans Spring 4.2, null est lié, mais à partir de Spring 4.3, un objet Collection élément vide est lié.

Note:

Les spécifications de fonctionnement ont été modifiées par rapport à Spring 4.3 en raison des demandes d'amélioration des utilisateurs de Spring (SPR-13502).

Quand je le vérifie réellement ...

Voyons un exemple concret utilisant Thymeleaf (Thymeleaf-Spring). Ici, nous allons simplement créer un contrôleur et une classe de formulaire dans l'application Spring Boot.

package com.example;

import java.util.List;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@SpringBootApplication
public class CheckboxDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(CheckboxDemoApplication.class, args);
	}

	@RequestMapping("/sample")
	@Controller
	static class SampleController {

		@ModelAttribute //Méthode de stockage du formulaire dans le modèle
		SampleForm setUpForm() {
			return new SampleForm();
		}

		@RequestMapping //Méthode du gestionnaire pour afficher l'écran du formulaire
		String form() {
			return "sample/form";
		}

		@RequestMapping(method = RequestMethod.POST) //Méthode de gestion pour recevoir des soumissions à partir de l'écran de formulaire
		String submit(SampleForm form) {
			System.out.println("-----------------------");
			System.out.println("list :" + form.getList());
			return "sample/form";
		}
	}

	static class SampleForm {

		private List<String> list; //Propriétés pour conserver la valeur de la case à cocher

		public List<String> getList() {
			return list;
		}

		public void setList(List<String> list) {
			this.list = list;
		}

	}

}
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>Sample</title>
</head>

<body>

<div class="container">

    <form method="post" th:object="${sampleForm}">
        <div class="form-group">
            <label>List</label> <!--Deux valeurs de sélection de case à cocher sont disponibles-->
            <ul>
                <li>
                    <input type="checkbox" th:field="*{list}" value="1"/>
                    <label th:for="${#ids.prev('list')}">A</label>
                </li>
                <li>
                    <input type="checkbox" th:field="*{list}" value="2"/>
                    <label th:for="${#ids.prev('list')}">B</label>
                </li>
            </ul>
        </div>
        <button class="btn btn-default">Submit</button>
    </form>

</div>
</body>

</html>

Lorsque vous démarrez l'application Spring Boot et accédez à "[http: // localhost: 8080 / sample](http: // localhost: 8080 / sample)", l'écran (shoboi w) suivant s'affiche.

checkbox-form.png

Au printemps 4.2?

Lorsque vous appuyez sur le bouton «Soumettre» dans Spring Boot 1.3.8.RELEASE (dernière version de la série Spring 4.2), sur la console ...

...
2016-12-23 19:40:42.727  INFO 38839 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 13 ms
-----------------------
list :null

Il sera affiché. En d'autres termes ... «null» est lié.

Au printemps 4.3?

D'autre part ... Lorsque vous appuyez sur le bouton "Soumettre" dans Spring Boot 1.4.3.RELEASE (dernière version de la série Spring 4.3), sur la console ...

...
2016-12-23 19:40:42.727  INFO 38839 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 13 ms
-----------------------
list :[]

Il sera affiché. Cela signifie qu'une liste vide est liée au lieu de «null».

Quelque chose ne va pas ou a un impact?

Que "null" devienne ou non une collection d'éléments vides est un problème ou a un effet dépend de la création de votre application. Par exemple ... Je pense qu'il n'y a pas de problème (= pas d'effet) dans les applications qui traitent à l'origine les éléments «nuls» et vides comme la même chose. Cependant, les applications qui traitent les éléments «null» et vides comme des choses différentes peuvent avoir besoin de faire quelque chose à ce sujet.

Par exemple ... Si la vérification requise pour l'élément de la case à cocher est effectuée selon qu'elle est «nulle» ou non comme indiqué ci-dessous, le processus se dirigera vers la couche logique en contournant la vérification d'entrée.

static class SampleForm {

	@NotNull // Bad ...Un élément vide est lié, donc une vérification nulle est NG! !!
	private List<String> list;

	// ...

}

Dans ce cas, le standard de validation de bean @ Size doit utiliser @ NotEmpty fourni par Hibernate Validator.

static class SampleForm {
	@Size(min = 1) // Good
	private List<String> list;
	// ...
}

or

static class SampleForm {
	@NotEmpty // Good
	private List<String> list;
	// ...
}

Comment la valeur initiale (valeur par défaut) est-elle définie?

Générez des cases à cocher et sélectionnez des cases à l'aide de composants prenant en charge l'implémentation de View fournie par Spring (bibliothèque de balises JSP, macros Freemarker, etc.) et des composants de coopération tiers (Dialect for Spring, coopération de Thymeleaf, etc.) Ensuite, des paramètres spéciaux (paramètres commençant par _) pour initialiser les propriétés de l'objet de formulaire sont incorporés en tant qu'éléments cachés. (Dans cet article, ce paramètre spécial sera appelé ci-après "paramètre de réinitialisation")

Contenu HTML généré par Thymeleaf



<!DOCTYPE html>


<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Sample</title>
</head>

<body>

<div class="container">

    <form method="post">
        <div class="form-group">
            <label>List</label>
            <ul>
                <li>
                    <input type="checkbox" value="1" id="list1" name="list" /><input type="hidden" name="_list" value="on" />
                    <label for="list1">A</label>
                </li>
                <li>
                    <input type="checkbox" value="2" id="list2" name="list" /><input type="hidden" name="_list" value="on" />
                    <label for="list2">B</label>
                </li>
            </ul>
            
        </div>
        <button class="btn btn-default">Submit</button>
    </form>

</div>
</body>

</html>

Dans cet exemple, «_list» est le paramètre de réinitialisation. La valeur est "ʻon`", mais puisque ce paramètre de réinitialisation est un paramètre de marqueur, la valeur n'a aucune signification.

Alors, que fait Spring MVC lorsque vous envoyez un paramètre de réinitialisation? Lorsque vous envoyez un paramètre de réinitialisation ... Lorsqu'un paramètre de requête normal (list dans l'exemple ci-dessus) n'est pas envoyé en tant que paramètre de requête (= il n'est pas envoyé lorsque la case à cocher est vide), la valeur de propriété de l'objet de formulaire Va s'initialiser.

La valeur utilisée au moment de cette initialisation était «null» jusqu'au printemps 4.2, mais à partir du printemps 4.3, elle est devenue une collection d'éléments vides.

Note:

Plus précisément ... La méthode getEmptyValue de ʻOrg.springframework.web.bind.WebDataBinderdétermine la valeur à définir lors de l'initialisation. À partir de Spring 4.3, les valeurs initiales de la classe d'implémentationjava.util.Collection et de la classe d'implémentation java.util.Map` ont changé.

Pourquoi avez-vous besoin de réinitialiser les paramètres?

Avez-vous besoin de réinitialiser les paramètres? ?? ?? Peut-être que certaines personnes ont pensé cela. En conclusion ... c'est nécessaire.

Plus précisément ... Lorsque l'objet de formulaire est géré dans la portée de session à l'aide de @ SessionAttributes, les opérations suivantes ...

  1. Affichez l'écran du formulaire
  2. Cochez une case sur l'écran du formulaire et soumettez
  3. Revenez à l'écran du formulaire, décochez la case et soumettez

Si vous le faites, l'état sélectionné de la case à cocher reviendra à l'état d'origine (l'état où l'un est coché). La raison pour laquelle le statut retourne est ... Si toutes les cases à cocher ne sont pas cochées, le paramètre de requête de l'élément correspondant ne sera pas envoyé au moment de la soumission, donc le processus de mise à jour du statut de l'objet de formulaire géré sur la session sera exécuté. En conséquence, l'état précédent demeure.

Spring MVC fournit un paramètre spécial appelé «paramètre de réinitialisation» pour éviter la situation ci-dessus.

Note:

Si l'élément d'entrée est désactivé, le paramètre de demande ne sera pas envoyé au moment de la soumission, donc si l'interface utilisateur doit basculer entre actif et inactif par l'opération de l'utilisateur, le même phénomène se produira à moins que le paramètre de réinitialisation ne soit envoyé ensemble. Cela peut arriver.

Résumé

Cette fois, j'ai parlé de la valeur définie lors de l'application du paramètre de réinitialisation fourni par Spring MVC est différente entre Spring 4.2 et 4.3. Est-il relativement courant d'assimiler «null» à un élément vide? J'ai peur, mais qu'en est-il de votre candidature? Pour le moment, lors de la mise à jour vers Spring 4.3, il semble que vous deviez faire attention à la gestion des cases à cocher et des éléments de case à cocher.

Recommended Posts

Spring 4.2 vs 4.3: Différence de valeur de liaison au type de collection lors de la soumission case à cocher vide
Faites attention à la vérification des limites de la valeur d'entrée lors de l'utilisation du type float
Lorsque vous souhaitez lier InputStream dans JDBI3
Comment se lier avec un fichier de propriétés dans Spring Boot
[Type de chaîne vs Générateur de chaînes] Différence de vitesse de traitement dans la combinaison de chaînes