[JAVA] 04. J'ai fait un frontal avec SpringBoot + Thymeleaf

Aperçu

Cette fois, je vais essayer de créer un frontal (** Thymeleaf **) au lieu de l'API. Vous vous demandez peut-être: "Est-il possible de créer soudainement un front-end même s'il s'agissait d'une API jusqu'à la dernière fois?" De mon point de vue, ** l'implémentation API et front-end n'est pas si différente **.

Si vous suivez certaines règles (telles que l'emplacement des fichiers), Spring Boot fera ce que vous voulez. Les principaux changements sont la ** couche contrôleur ** et la ** couche vue y est ajoutée **. En d'autres termes, la couche ** Model (Service, Mapper) peut être configurée et implémentée de la même manière que l'API **.

Regardons réellement la source!

Sujet principal

J'ai utilisé le même projet jusqu'à la dernière fois, Cette fois, ce sera le front-end, donc je vais couper un nouveau projet. (Je vais omettre la procédure) En tant que faux, demandons simplement l'API de recherche de code postal comme auparavant et renvoyons le résultat au format html. Étant donné que l'essentiel de ce temps est l'implémentation de View by Thymeleaf, je vais principalement l'expliquer.

1. Ajouter une dépendance

Nous utiliserons le familier Spring Initializr. Cette fois, nous spécifierons «** Web », « MySQL », « My Batis », « Lombok » et « Thymeleaf **». 依存追加.png

Après avoir sélectionné ce qui précède, cliquez sur ** Générer le projet ** pour refléter ** build.gradle ** dans le zip téléchargé de votre projet. N'oubliez pas ** Reflesh **.

2. Faire un modèle

Dernière fois Copiez les GetAddressApiClient et ResponseHeaderInterceptor créés et apportez-les tels quels. Oh, n'oubliez pas d'apporter votre classe de données.

3. Créer un contrôleur et une vue

3-1. Contrôleur et vue qui affichent l'écran supérieur

C'est l'écran supérieur pour le moment. ** Redirect ** et ** Forward ** sont disponibles dans Spring Boot. Cette fois, j'utilise des redirections.

TopController.java


@Controller
public class TopController {
    @GetMapping("/top")
    public String top() {
        return "/top";
    }
    @GetMapping("/")
    public String index() {
        return "redirect:/top"; //Avec cette description/Vous pourrez rediriger vers le haut
    }
}

Vient ensuite le html, mais comme il ne suffit pas de le mettre, je vais l'omettre ici. Utilisez simplement une simple ancre pour accéder à l'écran de recherche.

3-2. Créer un contrôleur et une vue pour afficher la recherche et les résultats

Implémentons la validation à la fois. D'abord du contrôleur.

AddressSearchController.java


@Controller
@RequiredArgsConstructor
public class AddressSearchController {
    private final GetAddressApiClient client;

    @GetMapping("/address/search")
    public String search(@ModelAttribute SearchForm form) { // (1)
        return "/address/search";
    }

    @PostMapping("/address/confirm")
    public String confirm(@ModelAttribute @Valid SearchForm form,
                          BindingResult bindingResult,
                          Model model) {
        if (bindingResult.hasErrors()) { // (2)
            return "/address/search";
        }
        GetAddressApiResponse response = client.request(form.getPostalCode());
        model.addAttribute("addressList", response.getResults()); // (3)
        return "/address/confirm";
    }
}

Expliquons brièvement les principaux points. (1). Le formulaire est extrait de Model avec @ ModelAttribute comme argument. ** Puisque l'instance n'existe pas dans Model au moment de l'affichage initial, Spring new et passe cet objet **. C'est la même chose si vous explicitement new dans la méthode et model.addAttribute (), mais si vous écrivez cette description, c'est pratique car vous pouvez hériter de la valeur avec forward! (2) .Si le code postal saisi dans le familier bindingResult.hasErrors () est incorrect, l'écran sera renvoyé à l'écran de recherche. Au fait, l'annotation est la même que le ZipCode créé la dernière fois. (3) Si le code postal saisi est correct, récupérez les informations d'adresse via le "Client" créé précédemment et transmettez la valeur à View avec le nom ʻaddressList`.

Vient ensuite le html de l'écran de recherche.

search.html


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"> <!-- (1) -->
<head>
    <meta charset="UTF-8">
    <title>Sample Search</title>
</head>
<body>
<h2>Écran de recherche</h2>
<form th:action="@{/address/confirm}" th:method="post" th:object="${searchForm}">
    <label th:for="*{postalCode}">Code postal</label><input th:field="*{postalCode}">
    <span th:if="${#fields.hasErrors('postalCode')}" th:errors="*{postalCode}">error message</span><br/> <!-- (2) -->
    <button type="submit">Rechercher</button>
</form>
</body>
</html>

Tout d'abord, expliquons chaque balise th et méthode de description qui apparaissent dans ce html.

(1) Ceci est une description de l'utilisation de la balise «th» de la feuille de thym. Si vous ne l'incluez pas, vous ne pourrez pas utiliser thymeleaf, alors n'oubliez pas. (2). $ {# Fields.hasErrors ('postalCode')} renverra true si une violation de validation se produit avec la valeur de postalCode. Vous pouvez afficher des messages d'erreur pour un champ en spécifiant le nom du champ avec th: errors. En d'autres termes, ** Vous pouvez afficher un message d'erreur lorsqu'il y a une violation de validation avec cette phrase **.

Enfin, c'est le html de l'écran de confirmation.

confirm.html


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Sample Confirm</title>
</head>
<body>
<h2>Écran des résultats de la recherche</h2>
<table border="1">
    <tr>
        <th>Code postal</th>
        <th>Code préfecture</th>
        <th>Adresse 1</th>
        <th>Adresse 2</th>
        <th>Adresse 3</th>
        <th>Adresse Kana 1</th>
        <th>Adresse Kana 2</th>
        <th>Adresse Kana 3</th>
    </tr>
    <tr th:each="result : ${addressList}">
        <td th:text="${result.zipcode}"></td>
        <td th:text="${result.prefcode}"></td>
        <td th:text="${result.address1}"></td>
        <td th:text="${result.address2}"></td>
        <td th:text="${result.address3}"></td>
        <td th:text="${result.kana1}"></td>
        <td th:text="${result.kana2}"></td>
        <td th:text="${result.kana3}"></td>
    </tr>
</table>
<a th:href="@{/address/search}">Revenir à l'écran de recherche</a>
</body>
</html>

Cette fois, les résultats seront renvoyés sous forme de liste, donc je l'ai fait sortir dans un tableau. Les balises utilisées sur cet écran sont les suivantes.

--th: each… ** Ceci est une balise que vous utiliserez souvent. ** Je pense que ce sera plus facile à comprendre si vous pouvez imaginer la déclaration étendue for de java. Les valeurs sont extraites dans l'ordre de $ {addressList} afin que les valeurs puissent être utilisées avec le nom result. --th: text… ** Ceci est une balise que vous utiliserez souvent. ** Comme son nom l'indique, il est utilisé lorsque vous souhaitez l'afficher à l'écran, et la valeur est étendue à <td> </ td> après le rendu. De plus, il prend en charge XSS et échappe les méta-caractères, vous pouvez donc l'utiliser en toute confiance.

Est-ce un tel endroit? Enfin, frappons-le depuis le navigateur! !!

4. Essayez de le frapper

4-1. Écran supérieur

BootRun pour accéder à http: // localhost: 8080 /. トップ画面.png Cliquez sur ** Rechercher par code postal ** pour passer à l'écran de recherche.

4-2. Écran de recherche

検索画面.png

La source HTML après le rendu ressemble à ceci. 検索画面_html.png th: field est développé, ** ʻid et name sont des noms de variables et value` est vide **. Entrez maintenant la valeur correcte et cliquez sur ** Rechercher **.

4-3. Écran de résultat

Tout d'abord, lorsque le résultat est singulier. 結果画面.png

Puis quand il y a plusieurs résultats. 結果画面_複数.png th: each fonctionne correctement, et vous pouvez tous les voir même s'il y en a plusieurs.

Enfin, regardons le cas d'erreur de validation.

4-4. Erreur de validation

検索画面_不正値.png Si vous entrez une valeur non valide et cliquez sur ** Rechercher ** ...

検索画面_不正値_エラー.png Vous avez correctement affiché le message d'erreur. Au fait, ce message est une chaîne de caractères solide écrite dans la valeur par défaut de ZipCode.message.

finalement

C'était incroyablement simple, mais c'était une implémentation frontale. ** thymeleaf est profond, et les balises et les méthodes de description que je touche ne sont que la pointe de l'iceberg. ** ** Vous pouvez en faire de plus en plus, alors jetez-y un œil!

Je pense que css et javascript seront nécessaires après cela, mais récemment, j'ai eu l'occasion de toucher ** sémantique ui **. Il peut être utilisé avec CDN, et il sera décoré en spécifiant le nom de la classe. Si vous êtes intéressé, n'hésitez pas à nous contacter!

Merci d'avoir regardé jusqu'au bout! !!

Recommended Posts

04. J'ai fait un frontal avec SpringBoot + Thymeleaf
J'ai créé une interface graphique avec Swing
J'ai fait une mort risquée avec Ruby
J'ai créé une application Janken avec kotlin
J'ai créé une application Janken avec Android
J'ai fait de l'art de la mosaïque avec des images Pokemon
J'ai créé un robot LINE avec Rails + heroku
J'ai fait un portfolio avec Ruby On Rails
[Ruby] J'ai fait un robot avec de l'anémone et du nokogiri.
J'ai créé une application de chat.
J'ai écrit un test CRUD avec SpringBoot + MyBatis + DBUnit (Partie 1)
J'ai créé un environnement de développement avec rails6 + docker + postgreSQL + Materialise.
Créez un CRUD simple avec SpringBoot + JPA + Thymeleaf ③ ~ Ajouter une validation ~
J'ai créé un plug-in qui exécute jextract avec des tâches Gradle
Créez un CRUD simple avec SpringBoot + JPA + Thymeleaf ① ~ Hello World ~
J'ai créé un MOD qui appelle instantanément un véhicule avec Minecraft
Créez un CRUD simple avec SpringBoot + JPA + Thymeleaf ⑤ ~ Modèle commun ~
Dessiner un écran avec Thymeleaf dans SpringBoot
Implémenter le lien texte avec Springboot + Thymeleaf
J'ai créé une application shopify @java
J'ai fait une simple fonction de recommandation.
J'ai créé une application correspondante (application Android)
J'ai créé un outil de génération package.xml.
[Android] J'ai créé une application de podomètre.
J'ai créé une interface de ligne de commande avec WinMerge Plugin en utilisant JD-Core
[Rails] J'ai créé une mini-application de calendrier simple avec des spécifications personnalisées.
Créez un CRUD simple avec SpringBoot + JPA + Thymeleaf ④ ~ Personnaliser le message d'erreur ~
J'ai créé un formulaire de recherche simple avec Spring Boot + GitHub Search API.
[Ruby] J'ai créé un simple client Ping
Créez un CRUD simple avec SpringBoot + JPA + Thymeleaf ② ~ Création d'écran et de fonctions ~
J'ai créé un serveur écologique avec scala
J'ai essayé d'utiliser OnlineConverter avec SpringBoot + JODConverter
J'ai essayé de jouer un peu avec BottomNavigationView ①
J'ai créé un plug-in pour IntelliJ IDEA
J'ai créé une application de calculatrice sur Android
Désérialiser XML dans une collection avec spring-boot
J'ai créé un nouvel outil de déploiement Java
[LINE BOT] J'ai créé un Ramen BOT avec Java (Maven) + Heroku + Spring Boot (1)
J'ai créé un site qui résume les informations sur la restriction du sucre avec Vue.js
Apprendre Java avec Progate → Je vais vous expliquer parce que j'ai moi-même créé un jeu de base
J'ai créé un outil Diff pour les fichiers Java
J'ai créé un programme de jugement des nombres premiers en Java
J'ai fait un blackjack avec Ruby (j'ai essayé d'utiliser minitest)
J'ai créé un jeu Janken en Java (CLI)
J'ai créé une application de visualisation qui affiche le PDF
J'ai créé un conteneur Docker pour exécuter Maven
J'ai créé une bibliothèque d'extension Ruby en C
[Rails] J'ai créé une fonction de brouillon en utilisant enum
J'ai créé Code Pipeline avec AWS CDK.
Afficher un simple Hello World avec SpringBoot + IntelliJ
J'ai essayé de casser le bloc avec java (1)
J'ai créé StringUtils.isBlank
J'ai essayé de déployer une page créée avec l'antique Middleman sur Azure Static Web Apps
J'ai créé un schéma de verrouillage à l'aide de la touche de volume avec l'application Android. Édition fragmentée
J'ai créé une fonction pour enregistrer des images avec l'API dans Spring Framework. Partie 1 (édition API)
J'ai créé une image Docker pour la version japonaise de SDAPS