[JAVA] La signification du champ th: dans Thymeleaf et le mécanisme de passage des valeurs de Spring Framework

introduction

Dans Thymeleaf, j'avais l'habitude d'utiliser th: field comme si je me souvenais d'un des idiots, mais j'ai l'impression que j'ai récemment échappé à ce niveau de compréhension, alors j'aimerais résumer le contenu.

En résumé, l'accent sera mis sur la classe Form, qui est responsable de la transmission des valeurs dans Spring Framework. En fin de compte, la valeur est transmise sans utiliser du tout la classe Form.

Le but est le suivant.

C'est une histoire de comprendre, donc ** ce n'est pas très pratique. ** **

supposition

Vous avez besoin d'un projet Web créé avec Spring Framework. Le moteur de modèle est basé sur Thymeleaf.

Mise en œuvre générale

Tout d'abord, considérons une implémentation générale utilisant Form. De là, vous pouvez modifier le code et éventuellement supprimer la classe Form.

BookForm.java

public class BookForm {

	private String title;
	private int price;
	private String summary;
	//	Getter,Setter omis
}

SampleController.java

@Controller
public class SampleController {

	//écran de saisie
	@GetMapping("/input")
	public String input(@ModelAttribute("bookForm") BookForm bookForm) {
		return "input";
	}

	//Écran d'informations sur le livre
	@PostMapping("/bookinfo")
	public String toBookInfo(@ModelAttribute("bookForm") BookForm bookForm) {
		return "bookinfo";
	}
}

input.html

	<!--Seulement à l'intérieur de l'onglet du corps-->
	<h3>Implémentation à l'aide de la classe Form</h3>
	<form th:action="@{/bookinfo}" method="post" th:object="${bookForm}">
	<label>Titre</label><br>
	<input type="text" th:field="*{title}"><br>
	<label>prix</label><br>
	<input type="text" th:field="*{price}"><br>
	<label>Aperçu</label><br>
	<input type="text" th:field="*{summary}"><br>
	<button>Envoyer</button>
	</form>

bookinfo.html

	<!--Seulement à l'intérieur de l'onglet du corps-->
	<h3>Implémentation à l'aide de la classe Form</h3>
	<div th:object="${bookForm}">
	<label>Titre</label><br>
	<span th:text="*{title}"></span><br>
	<label>prix</label><br>
	<span th:text="*{price}"></span><br>
	<label>Note</label><br>
	<span th:text="*{summary}"></span><br>
	</div>

La valeur d'entrée est sortie, ce qui est une implémentation très simple.

スクリーンショット 2018-11-06 22.23.08.png スクリーンショット 2018-11-06 22.28.54.png

Supprimer th: field et th: object dans input.html

Tout d'abord, envisagez de supprimer th: field '' et th: object '' de input.html. Maintenant, pour savoir ce que sont th: field '' et th: object '', utilisez les outils de développement de Chrome pour voir à quoi ressemble le fichier input.html écrit en Thymeleaf. Faisons le.

スクリーンショット 2018-11-06 22.49.40.png

th: object disparaît de la balise form, et la zone de texte pour saisir le titre décrit dans th: field devient <input type =" text "id =" title "name =" title "value> Vous pouvez voir qu'il y en a. En termes simples, vous pouvez effacer th: field et th: object en écrivant exactement comme il apparaît dans les outils de développement. Si vous n'écrivez que la description nécessaire, ce sera comme suit.

input.html

	<!--Seulement à l'intérieur de l'onglet du corps-->
	<h3>th:Implémentation avec objet supprimé</h3>
	<form th:action="@{/bookinfo}" method="post">
	<label>Titre</label><br>
	<input type="text" name="title"><br>
	<label>prix</label><br>
	<input type="text" name="price"><br>
	<label>Aperçu</label><br>
	<input type="text" name="summary"><br>
	<button>Envoyer</button>
	</form>

Même avec cette description html, le processus de "sortie de la valeur d'entrée" montré dans [Implémentation générale](# Implémentation générale) peut être réalisé.

Le fait que la description de th: object ait disparu signifie que la classe Form de la méthode d'entrée de SampleController.java peut également être supprimée.

	//écran de saisie
	@GetMapping("/input")
	public String input() {
		return "input";
	}

La chose la plus importante est ** Si vous spécifiez un nom de champ de classe Form dans l'attribut neme de la balise d'entrée, la valeur saisie sera stockée dans ce champ ** à propos de ça.

Presque tout ce que je veux dire dans cet article réside dans ce fait. (Ce qui précède n'est pas exactement l'explication correcte du comportement de th: field. Pour plus de détails, voir Fonction de liaison de formulaire par th: field et th: object (balise d'entrée / système d'entrée de base) Je vous serais reconnaissant si vous pouviez vous référer à: //casual-tech-note.hatenablog.com/entry/2018/10/10/224250)

Swap Form classes

Avec le mécanisme ci-dessus à l'esprit, vous pouvez faire ceci: Par exemple, supposons que vous ayez la classe Form suivante appelée MovieForm, qui est différente de BookForm.

MovieForm.java

public class MovieForm {

	private String title;
	private String summary;
	//	Getter,Setter omis
}

(Désolé pour l'exemple non naturel) Supposons que vous souhaitiez traiter les informations de livre qui ont été créées dans un film à l'aide de cette classe MovieForm comme des informations de film. Dans bookinfo.html, préparez un bouton "Envoyer en tant qu'informations sur le film" et réécrivez-le pour que BookForm soit envoyé au dernier.

bookinfo.html (modifié de manière significative)

	<!--Seulement à l'intérieur de l'onglet du corps-->
	<h3>Échangez les valeurs de BookForm vers MoiveForm</h3>
	<form th:action="@{/movieinfo}" method="post" th:object="${bookForm}">
	<label>Titre</label><br>
	<input type="text" readonly th:field="*{title}"><br>
	<label>prix</label><br>
	<input type="text" readonly th:field="*{price}"><br>
	<label>Aperçu</label><br>
	<input type="text" readonly name="summary" th:value="*{summary}"><br>
	<button>Également envoyé en tant qu'informations sur le film</button>
	</form>

SampleController.java (note supplémentaire)

	//Écran de sortie des informations sur le film (informations supplémentaires)
	@PostMapping("/movieinfo")
	public String toMovieinfo(@ModelAttribute("movieForm") MovieForm movieForm) {
		return "movieinfo";
	}

movieinfo.html

	<!--Seulement à l'intérieur de l'onglet du corps-->
	<h3>Échangez les valeurs de BookForm vers MoiveForm</h3>
	<div th:object="${movieForm}">
	<label>Titre</label><br>
	<span th:text="*{title}"></span><br>
	<label>Aperçu</label><br>
	<span th:text="*{summary}"></span><br>
	</div>

Le résultat du traitement est le suivant. スクリーンショット 2018-11-11 19.18.16.png スクリーンショット 2018-11-11 19.18.31.png

La valeur envoyée en tant que classe BookForm de cette manière est stockée dans MovieForm et sortie dans movieinfo.html. C'est une implémentation légèrement tordue, donc certaines personnes peuvent avoir un sentiment étrange.

Le fait est que BookForm et MovieForm ont des champs avec le même nom tels que «titre» et «résumé». J'ai écrit deux types dans bookinfo.html, mais dans ce résultat de traitement

<input type="text" readonly th:field="*{title}"> Est <input type =" text "readonly name =" title "value =" AIUEO ">

<input type="text" readonly name="summary" th:value="*{summary}"> Est-ce que <input type =" text "readonly name =" summary "value =" test ">

A la même signification que. En d'autres termes, la valeur de l'attribut ** name est la même que le nom de champ de Form **, il y a donc un tsuji 褄.

Spécifiez une valeur pour bouton et recevez-la dans la classe Form

** N'est-il pas possible de l'implémenter sans utiliser th: field? ** ** N'est-ce pas sur le point de me venir à l'esprit?

Maintenant, considérons recevoir la valeur spécifiée pour button. Ajoutez un champ de catégorie comme celui-ci à MovieForm pour ajouter des boutons pour chaque catégorie dans bookinfo.html. Le texte sera affiché dans movieinfo.html en fonction du bouton sur lequel vous appuyez.

MovieForm.java

public class MovieForm {

	private String title;
	private String summary;
	//Champ de catégorie ajouté
	private String category;
	//	Getter,Setter omis
}

bookinfo.html (Ajouter plusieurs boutons avec des valeurs dans la catégorie)

	<!--Seulement à l'intérieur de l'onglet du corps-->
	<h3>Spécifiez une valeur pour bouton et recevez-la dans la classe Form</h3>
	<form th:action="@{/movieinfo}" method="post" th:object="${bookForm}">
	<label>Titre</label><br>
	<input type="text" readonly th:field="*{title}"><br>
	<label>prix</label><br>
	<input type="text" readonly th:field="*{price}"><br>
	<label>Aperçu</label><br>
	<input type="text" readonly name="summary" th:value="*{summary}"><br>
	<button name="category" value="action">action映画として送信</button>
	<button name="category" value="Fantaisie">Fantaisie映画として送信</button>
	<button name="category" value="SF">Envoyer comme film SF</button>
	</form>

movieinfo.html

	<!--Seulement à l'intérieur de l'onglet du corps-->
	<h3>Spécifiez une valeur pour bouton et recevez-la dans la classe Form</h3>
	<div th:object="${movieForm}">
	<label>Titre</label><br>
	<span th:text="*{title}"></span><br>
	<label>Aperçu</label><br>
	<span th:text="*{summary}"></span><br>
La catégorie est<span th:text="*{category}"></span>est.
	</div>

Le résultat est le suivant

Si vous utilisez uniquement th: field, il est difficile de modifier la valeur de la valeur de l'élément qui ne peut pas être saisie, mais lorsque vous savez que ** la valeur du nom et la valeur de la valeur sont liées **, comme ceci Il est également possible de modifier le traitement en fonction de la valeur de valeur du bouton.

Supprimer la classe Form

Dans une dernière étape, nous effacerons la classe Form. L'annotation `` @ RequestParam '' joue ici un rôle actif.

L'implémentation qui génère la valeur saisie est la suivante.

input.html → Voir [Effacer th: champ et th: objet dans input.html](Supprimer le champ et l'objet dans #inputhtml)

SampleController.java

@Controller
public class SampleController {

	//écran de saisie
	@GetMapping("/input")
	public String input() {
		return "input";
	}

	//Écran de sortie des informations sur le livre
	@PostMapping("/bookinfo")
	public String toBookInfo(@RequestParam Map<String, String> bookmap, Model model) {
		model.addAttribute("bookmap", bookmap);
		return "bookinfo";
	}
}

bookinfo.html

	<!--Seulement à l'intérieur de l'onglet du corps-->
	<h3>Supprimer la classe Form</h3>
	<label>Titre</label><br>
	<span th:text="${bookmap.title}"></span><br>
	<label>prix</label><br>
	<span th:text="${bookmap.price}"></span><br>
	<label>Note</label><br>
	<span th:text="${bookmap.summary}"></span><br>

Vous pouvez maintenant obtenir le même résultat que l'implémentation générale (#General Implementation) sans utiliser aucune classe Form. Lorsque la valeur saisie dans input.html avec @ RequestParam est reçue dans Map, la valeur est stockée dans bookinfo sous la forme {title = AIUEO, price = 1000, summary = test}. Vous pouvez bien voir que la ** valeur du nom et la valeur de la valeur ** que j'ai mentionnées à plusieurs reprises dans cet article sont envoyées en association l'une avec l'autre.

En outre, l'avantage de cette implémentation est que vous pouvez modifier la valeur à saisir.

Déclenchement et supplément

En premier lieu, j'ai pensé "Je veux effacer" th: field "" parce que je devais créer un écran de saisie variable.

À la suite de diverses conclusions, je pense que si vous pouvez utiliser th: field '', vous devez l'utiliser activement, et vous ne devez pas utiliser jusqu'à @ RequestParam '' pour supprimer la classe Form.

Dans l'implémentation où la valeur d'entrée est reçue par Map '' en utilisant @ RequestParam '', Traitement des valeurs lorsqu'il y a un bouton retour Gestion des erreurs (les annotations Spring Framework ne peuvent pas être utilisées, bien sûr) Etc.

Dans cet exemple également, il peut suffire de spécifier une valeur pour bouton et de la recevoir, mais je pense que si vous faites [Swap Form class](Swap #Form class), la lisibilité sera considérablement réduite. Je vais.

Résumé

** th: champ signifie les attributs de nom et de valeur (et id) en HTML ** ** La valeur de l'attribut value est envoyée en association avec la valeur spécifiée dans l'attribut name et le côté contrôleur la reçoit ** c'est tout!

référence

Spring MVC populate @RequestParam Map<String, String> Arguments du contrôleur Spring MVC

Comme mentionné dans les commentaires, cet article explique plus en détail le comportement de th: field. Fonction de liaison de formulaire par th: field et th: object (balise d'entrée / système d'entrée de base)

Recommended Posts

La signification du champ th: dans Thymeleaf et le mécanisme de passage des valeurs de Spring Framework
Play Framework étudiant la transmission de valeur